File:  [DragonFly] / src / sys / dev / agp / agp_nvidia.c
Revision 1.1: download - view: text, annotated - select for diffs
Fri Oct 31 21:49:23 2003 UTC (10 years, 9 months ago) by asmodai
Branches: MAIN
CVS tags: HEAD
Add nForce AGP support, taken from FreeBSD with some minor changes to get
it to work with DragonFly.

    1: /*-
    2:  * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net>
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  *
   14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24:  * SUCH DAMAGE.
   25:  *
   26:  * Based on FreeBSD v1.2.
   27:  * $DragonFly: src/sys/dev/agp/agp_nvidia.c,v 1.1 2003/10/31 21:49:23 asmodai Exp $
   28:  */
   29: 
   30: /*
   31:  * Written using information gleaned from the
   32:  * NVIDIA nForce/nForce2 AGPGART Linux Kernel Patch.
   33:  */
   34: 
   35: #include "opt_bus.h"
   36: #include "opt_pci.h"
   37: 
   38: #include <sys/param.h>
   39: #include <sys/systm.h>
   40: #include <sys/malloc.h>
   41: #include <sys/kernel.h>
   42: #include <sys/bus.h>
   43: #include <sys/lock.h>
   44: 
   45: #include <bus/pci/pcivar.h>
   46: #include <bus/pci/pcireg.h>
   47: #include "agppriv.h"
   48: #include "agpreg.h"
   49: 
   50: #include <vm/vm.h>
   51: #include <vm/vm_object.h>
   52: #include <vm/pmap.h>
   53: 
   54: #include <machine/bus.h>
   55: #include <machine/resource.h>
   56: #include <sys/rman.h>
   57: 
   58: #define	NVIDIA_VENDORID		0x10de
   59: #define	NVIDIA_DEVICEID_NFORCE	0x01a4
   60: #define	NVIDIA_DEVICEID_NFORCE2	0x01e0
   61: 
   62: struct agp_nvidia_softc {
   63: 	struct agp_softc	agp;
   64: 	u_int32_t		initial_aperture; /* aperture size at startup */
   65: 	struct agp_gatt *	gatt;
   66: 
   67: 	device_t		dev;		/* AGP Controller */
   68: 	device_t		mc1_dev;	/* Memory Controller */
   69: 	device_t		mc2_dev;	/* Memory Controller */
   70: 	device_t		bdev;		/* Bridge */
   71: 
   72: 	u_int32_t		wbc_mask;
   73: 	int			num_dirs;
   74: 	int			num_active_entries;
   75: 	off_t			pg_offset;
   76: };
   77: 
   78: static const char *	agp_nvidia_match	(device_t dev);
   79: static int		agp_nvidia_probe	(device_t);
   80: static int		agp_nvidia_attach	(device_t);
   81: static int		agp_nvidia_detach	(device_t);
   82: static u_int32_t	agp_nvidia_get_aperture	(device_t);
   83: static int		agp_nvidia_set_aperture	(device_t, u_int32_t);
   84: static int		agp_nvidia_bind_page	(device_t, int, vm_offset_t);
   85: static int		agp_nvidia_unbind_page	(device_t, int);
   86: 
   87: static int		nvidia_init_iorr	(u_int32_t, u_int32_t);
   88: 
   89: static const char *
   90: agp_nvidia_match (device_t dev)
   91: {
   92: 	if (pci_get_class(dev) != PCIC_BRIDGE ||
   93: 	    pci_get_subclass(dev) != PCIS_BRIDGE_HOST ||
   94: 	    pci_get_vendor(dev) != NVIDIA_VENDORID)
   95: 		return (NULL);
   96: 
   97: 	switch (pci_get_device(dev)) {
   98: 	case NVIDIA_DEVICEID_NFORCE:
   99: 		return ("NVIDIA nForce AGP Controller");
  100: 	case NVIDIA_DEVICEID_NFORCE2:
  101: 		return ("NVIDIA nForce2 AGP Controller");
  102: 	}
  103: 	return ("NVIDIA Generic AGP Controller");
  104: }
  105: 
  106: static int
  107: agp_nvidia_probe (device_t dev)
  108: {
  109: 	const char *desc;
  110: 
  111: 	desc = agp_nvidia_match(dev);
  112: 	if (desc) {
  113: 		device_verbose(dev);
  114: 		device_set_desc(dev, desc);
  115: 		return (0);
  116: 	}
  117: 	return (ENXIO);
  118: }
  119: 
  120: static int
  121: agp_nvidia_attach (device_t dev)
  122: {
  123: 	struct agp_nvidia_softc *sc = device_get_softc(dev);
  124: 	struct agp_gatt *gatt;
  125: 	u_int32_t apbase;
  126: 	u_int32_t aplimit;
  127: 	u_int32_t temp;
  128: 	int size;
  129: 	int i;
  130: 	int error;
  131: 
  132: 	switch (pci_get_device(dev)) {
  133: 	case NVIDIA_DEVICEID_NFORCE:
  134: 		sc->wbc_mask = 0x00010000;
  135: 		break;
  136: 	case NVIDIA_DEVICEID_NFORCE2:
  137: 		sc->wbc_mask = 0x80000000;
  138: 		break;
  139: 	default:
  140: 		sc->wbc_mask = 0;
  141: 		break;
  142: 	}
  143: 
  144: 	/* AGP Controller */
  145: 	sc->dev = dev;
  146: 
  147: 	/* Memory Controller 1 */
  148: 	sc->mc1_dev = pci_find_bsf(pci_get_bus(dev), 0, 1);
  149: 	if (sc->mc1_dev == NULL) {
  150: 		device_printf(dev,
  151: 			"Unable to find NVIDIA Memory Controller 1.\n");
  152: 		return (ENODEV);
  153: 	}
  154: 
  155: 	/* Memory Controller 2 */
  156: 	sc->mc2_dev = pci_find_bsf(pci_get_bus(dev), 0, 2);
  157: 	if (sc->mc2_dev == NULL) {
  158: 		device_printf(dev,
  159: 			"Unable to find NVIDIA Memory Controller 2.\n");
  160: 		return (ENODEV);
  161: 	}
  162: 
  163: 	/* AGP Host to PCI Bridge */
  164: 	sc->bdev = pci_find_bsf(pci_get_bus(dev), 30, 0);
  165: 	if (sc->bdev == NULL) {
  166: 		device_printf(dev,
  167: 			"Unable to find NVIDIA AGP Host to PCI Bridge.\n");
  168: 		return (ENODEV);
  169: 	}
  170: 
  171: 	error = agp_generic_attach(dev);
  172: 	if (error)
  173: 		return (error);
  174: 
  175: 	sc->initial_aperture = AGP_GET_APERTURE(dev);
  176: 
  177: 	for (;;) {
  178: 		gatt = agp_alloc_gatt(dev);
  179: 		if (gatt)
  180: 			break;
  181: 		/*
  182: 		 * Probably contigmalloc failure. Try reducing the
  183: 		 * aperture so that the gatt size reduces.
  184: 		 */
  185: 		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2))
  186: 			goto fail;
  187: 	}
  188: 	sc->gatt = gatt;
  189: 
  190: 	apbase = rman_get_start(sc->agp.as_aperture);
  191: 	aplimit = apbase + AGP_GET_APERTURE(dev) - 1;
  192: 	pci_write_config(sc->mc2_dev, AGP_NVIDIA_2_APBASE, apbase, 4);
  193: 	pci_write_config(sc->mc2_dev, AGP_NVIDIA_2_APLIMIT, aplimit, 4);
  194: 	pci_write_config(sc->bdev, AGP_NVIDIA_3_APBASE, apbase, 4);
  195: 	pci_write_config(sc->bdev, AGP_NVIDIA_3_APLIMIT, aplimit, 4);
  196: 
  197: 	error = nvidia_init_iorr(apbase, AGP_GET_APERTURE(dev));
  198: 	if (error) {
  199: 		device_printf(dev, "Failed to setup IORRs\n");
  200: 		goto fail;
  201: 	}
  202: 
  203: 	/* directory size is 64k */
  204: 	size = AGP_GET_APERTURE(dev) / 1024 / 1024;
  205: 	sc->num_dirs = size / 64;
  206: 	sc->num_active_entries = (size == 32) ? 16384 : ((size * 1024) / 4);
  207: 	sc->pg_offset = 0;
  208: 	if (sc->num_dirs == 0) {
  209: 		sc->num_dirs = 1;
  210: 		sc->num_active_entries /= (64 / size);
  211: 		sc->pg_offset = (apbase & (64 * 1024 * 1024 - 1) &
  212: 				 ~(AGP_GET_APERTURE(dev) - 1)) / PAGE_SIZE;
  213: 	}
  214: 
  215: 	/* (G)ATT Base Address */
  216: 	for (i = 0; i < 8; i++) {
  217: 		pci_write_config(sc->mc2_dev, AGP_NVIDIA_2_ATTBASE(i),
  218: 				 (sc->gatt->ag_physical +
  219: 				   (i % sc->num_dirs) * 64 * 1024),
  220: 				 4);
  221: 	}
  222: 
  223: 	/* GTLB Control */
  224: 	temp = pci_read_config(sc->mc2_dev, AGP_NVIDIA_2_GARTCTRL, 4);
  225: 	pci_write_config(sc->mc2_dev, AGP_NVIDIA_2_GARTCTRL, temp | 0x11, 4);
  226: 
  227: 	/* GART Control */
  228: 	temp = pci_read_config(sc->dev, AGP_NVIDIA_0_APSIZE, 4);
  229: 	pci_write_config(sc->dev, AGP_NVIDIA_0_APSIZE, temp | 0x100, 4);
  230: 
  231: 	return (0);
  232: fail:
  233: 	agp_generic_detach(dev);
  234: 	return (ENOMEM);
  235: }
  236: 
  237: static int
  238: agp_nvidia_detach (device_t dev)
  239: {
  240: 	struct agp_nvidia_softc *sc = device_get_softc(dev);
  241: 	int error;
  242: 	u_int32_t temp;
  243: 
  244: 	error = agp_generic_detach(dev);
  245: 	if (error)
  246: 		return (error);
  247: 
  248: 	/* GART Control */
  249: 	temp = pci_read_config(sc->dev, AGP_NVIDIA_0_APSIZE, 4);
  250: 	pci_write_config(sc->dev, AGP_NVIDIA_0_APSIZE, temp & ~(0x100), 4);
  251: 
  252: 	/* GTLB Control */
  253: 	temp = pci_read_config(sc->mc2_dev, AGP_NVIDIA_2_GARTCTRL, 4);
  254: 	pci_write_config(sc->mc2_dev, AGP_NVIDIA_2_GARTCTRL, temp & ~(0x11), 4);
  255: 
  256: 	/* Put the aperture back the way it started. */
  257: 	AGP_SET_APERTURE(dev, sc->initial_aperture);
  258: 
  259: 	/* restore iorr for previous aperture size */
  260: 	nvidia_init_iorr(rman_get_start(sc->agp.as_aperture),
  261: 			 sc->initial_aperture);
  262: 
  263: 	agp_free_gatt(sc->gatt);
  264: 
  265: 	return (0);
  266: }
  267: 
  268: static u_int32_t
  269: agp_nvidia_get_aperture(device_t dev)
  270: {
  271: 	u_int8_t	key;
  272: 
  273: 	key = ffs(pci_read_config(dev, AGP_NVIDIA_0_APSIZE, 1) & 0x0f);
  274: 	return (1 << (24 + (key ? key : 5)));
  275: }
  276: 
  277: static int
  278: agp_nvidia_set_aperture(device_t dev, u_int32_t aperture)
  279: {
  280: 	u_int8_t val;
  281: 	u_int8_t key;
  282: 
  283: 	switch (aperture) {
  284: 	case (512 * 1024 * 1024): key = 0; break;
  285: 	case (256 * 1024 * 1024): key = 8; break;
  286: 	case (128 * 1024 * 1024): key = 12; break;
  287: 	case (64 * 1024 * 1024): key = 14; break;
  288: 	case (32 * 1024 * 1024): key = 15; break;
  289: 	default:
  290: 		device_printf(dev, "Invalid aperture size (%dMb)\n",
  291: 				aperture / 1024 / 1024);
  292: 		return (EINVAL);
  293: 	}
  294: 	val = pci_read_config(dev, AGP_NVIDIA_0_APSIZE, 1);
  295: 	pci_write_config(dev, AGP_NVIDIA_0_APSIZE, ((val & ~0x0f) | key), 1);
  296: 
  297: 	return (0);
  298: }
  299: 
  300: static int
  301: agp_nvidia_bind_page(device_t dev, int offset, vm_offset_t physical)
  302: {
  303: 	struct agp_nvidia_softc *sc = device_get_softc(dev);
  304: 	u_int32_t index;
  305: 
  306: 	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
  307: 		return (EINVAL);
  308: 
  309: 	index = (sc->pg_offset + offset) >> AGP_PAGE_SHIFT;
  310: 	sc->gatt->ag_virtual[index] = physical;
  311: 
  312: 	return (0);
  313: }
  314: 
  315: static int
  316: agp_nvidia_unbind_page(device_t dev, int offset)
  317: {
  318: 	struct agp_nvidia_softc *sc = device_get_softc(dev);
  319: 	u_int32_t index;
  320: 
  321: 	if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
  322: 		return (EINVAL);
  323: 
  324: 	index = (sc->pg_offset + offset) >> AGP_PAGE_SHIFT;
  325: 	sc->gatt->ag_virtual[index] = 0;
  326: 
  327: 	return (0);
  328: }
  329: 
  330: static int
  331: agp_nvidia_flush_tlb (device_t dev, int offset)
  332: {
  333: 	struct agp_nvidia_softc *sc;
  334: 	u_int32_t wbc_reg, temp;
  335: 	int i;
  336: 
  337: 	sc = (struct agp_nvidia_softc *)device_get_softc(dev);
  338: 
  339: 	if (sc->wbc_mask) {
  340: 		wbc_reg = pci_read_config(sc->mc1_dev, AGP_NVIDIA_1_WBC, 4);
  341: 		wbc_reg |= sc->wbc_mask;
  342: 		pci_write_config(sc->mc1_dev, AGP_NVIDIA_1_WBC, wbc_reg, 4);
  343: 
  344: 		/* Wait no more than 3 seconds. */
  345: 		for (i = 0; i < 3000; i++) {
  346: 			wbc_reg = pci_read_config(sc->mc1_dev,
  347: 						  AGP_NVIDIA_1_WBC, 4);
  348: 			if ((sc->wbc_mask & wbc_reg) == 0)
  349: 				break;
  350: 			else
  351: 				DELAY(1000);
  352: 		}
  353: 		if (i == 3000)
  354: 			device_printf(dev,
  355: 				"TLB flush took more than 3 seconds.\n");
  356: 	}
  357: 
  358: 	/* Flush TLB entries. */
  359: 	for(i = 0; i < 32 + 1; i++)
  360: 		temp = sc->gatt->ag_virtual[i * PAGE_SIZE / sizeof(u_int32_t)];
  361: 	for(i = 0; i < 32 + 1; i++)
  362: 		temp = sc->gatt->ag_virtual[i * PAGE_SIZE / sizeof(u_int32_t)];
  363: 
  364: 	return (0);
  365: }
  366: 
  367: #define	SYSCFG		0xC0010010
  368: #define	IORR_BASE0	0xC0010016
  369: #define	IORR_MASK0	0xC0010017
  370: #define	AMD_K7_NUM_IORR	2
  371: 
  372: static int
  373: nvidia_init_iorr(u_int32_t addr, u_int32_t size)
  374: {
  375: 	quad_t base, mask, sys;
  376: 	u_int32_t iorr_addr, free_iorr_addr;
  377: 
  378: 	/* Find the iorr that is already used for the addr */
  379: 	/* If not found, determine the uppermost available iorr */
  380: 	free_iorr_addr = AMD_K7_NUM_IORR;
  381: 	for(iorr_addr = 0; iorr_addr < AMD_K7_NUM_IORR; iorr_addr++) {
  382: 		base = rdmsr(IORR_BASE0 + 2 * iorr_addr);
  383: 		mask = rdmsr(IORR_MASK0 + 2 * iorr_addr);
  384: 
  385: 		if ((base & 0xfffff000ULL) == (addr & 0xfffff000))
  386: 			break;
  387: 
  388: 		if ((mask & 0x00000800ULL) == 0)
  389: 			free_iorr_addr = iorr_addr;
  390: 	}
  391: 
  392: 	if (iorr_addr >= AMD_K7_NUM_IORR) {
  393: 		iorr_addr = free_iorr_addr;
  394: 		if (iorr_addr >= AMD_K7_NUM_IORR)
  395: 			return (EINVAL);
  396: 	}
  397: 
  398: 	base = (addr & ~0xfff) | 0x18;
  399: 	mask = (0xfULL << 32) | ((~(size - 1)) & 0xfffff000) | 0x800;
  400: 	wrmsr(IORR_BASE0 + 2 * iorr_addr, base);
  401: 	wrmsr(IORR_MASK0 + 2 * iorr_addr, mask);
  402: 
  403: 	sys = rdmsr(SYSCFG);
  404: 	sys |= 0x00100000ULL;
  405: 	wrmsr(SYSCFG, sys);
  406: 
  407: 	return (0);
  408: }
  409: 
  410: static device_method_t agp_nvidia_methods[] = {
  411: 	/* Device interface */
  412: 	DEVMETHOD(device_probe,		agp_nvidia_probe),
  413: 	DEVMETHOD(device_attach,	agp_nvidia_attach),
  414: 	DEVMETHOD(device_detach,	agp_nvidia_detach),
  415: 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
  416: 	DEVMETHOD(device_suspend,	bus_generic_suspend),
  417: 	DEVMETHOD(device_resume,	bus_generic_resume),
  418: 
  419: 	/* AGP interface */
  420: 	DEVMETHOD(agp_get_aperture,	agp_nvidia_get_aperture),
  421: 	DEVMETHOD(agp_set_aperture,	agp_nvidia_set_aperture),
  422: 	DEVMETHOD(agp_bind_page,	agp_nvidia_bind_page),
  423: 	DEVMETHOD(agp_unbind_page,	agp_nvidia_unbind_page),
  424: 	DEVMETHOD(agp_flush_tlb,	agp_nvidia_flush_tlb),
  425: 
  426: 	DEVMETHOD(agp_enable,		agp_generic_enable),
  427: 	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
  428: 	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
  429: 	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
  430: 	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
  431: 
  432: 	{ 0, 0 }
  433: };
  434: 
  435: static driver_t agp_nvidia_driver = {
  436: 	"agp",
  437: 	agp_nvidia_methods,
  438: 	sizeof(struct agp_nvidia_softc),
  439: };
  440: 
  441: static devclass_t agp_devclass;
  442: 
  443: DRIVER_MODULE(agp_nvidia, pci, agp_nvidia_driver, agp_devclass, 0, 0);
  444: MODULE_DEPEND(agp_nvidia, agp, 1, 1, 1);
  445: MODULE_DEPEND(agp_nvidia, pci, 1, 1, 1);