File:  [DragonFly] / src / sys / dev / agp / agp.c
Revision 1.7: download - view: text, annotated - select for diffs
Thu Aug 7 21:16:48 2003 UTC (11 years, 1 month ago) by dillon
Branches: MAIN
CVS tags: HEAD
kernel tree reorganization stage 1: Major cvs repository work (not logged as
commits) plus a major reworking of the #include's to accomodate the
relocations.

    * CVS repository files manually moved.  Old directories left intact
      and empty (temporary).

    * Reorganize all filesystems into vfs/, most devices into dev/,
      sub-divide devices by function.

    * Begin to move device-specific architecture files to the device
      subdirs rather then throwing them all into, e.g. i386/include

    * Reorganize files related to system busses, placing the related code
      in a new bus/ directory.  Also move cam to bus/cam though this may
      not have been the best idea in retrospect.

    * Reorganize emulation code and place it in a new emulation/ directory.

    * Remove the -I- compiler option in order to allow #include file
      localization, rename all config generated X.h files to use_X.h to
      clean up the conflicts.

    * Remove /usr/src/include (or /usr/include) dependancies during the
      kernel build, beyond what is normally needed to compile helper
      programs.

    * Make config create 'machine' softlinks for architecture specific
      directories outside of the standard <arch>/include.

    * Bump the config rev.

    WARNING! after this commit /usr/include and /usr/src/sys/compile/*
    should be regenerated from scratch.

    1: /*-
    2:  * Copyright (c) 2000 Doug Rabson
    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:  *	$FreeBSD: src/sys/pci/agp.c,v 1.3.2.4 2002/08/11 19:58:12 alc Exp $
   27:  *	$DragonFly: src/sys/dev/agp/agp.c,v 1.7 2003/08/07 21:16:48 dillon Exp $
   28:  */
   29: 
   30: #include "opt_bus.h"
   31: #include "opt_pci.h"
   32: 
   33: #include <sys/param.h>
   34: #include <sys/systm.h>
   35: #include <sys/malloc.h>
   36: #include <sys/kernel.h>
   37: #include <sys/bus.h>
   38: #include <sys/conf.h>
   39: #include <sys/ioccom.h>
   40: #include <sys/agpio.h>
   41: #include <sys/lock.h>
   42: #include <sys/proc.h>
   43: 
   44: #include <bus/pci/pcivar.h>
   45: #include <bus/pci/pcireg.h>
   46: #include "agppriv.h"
   47: #include "agpvar.h"
   48: #include "agpreg.h"
   49: 
   50: #include <vm/vm.h>
   51: #include <vm/vm_object.h>
   52: #include <vm/vm_page.h>
   53: #include <vm/vm_pageout.h>
   54: #include <vm/pmap.h>
   55: 
   56: #include <machine/md_var.h>
   57: #include <machine/bus.h>
   58: #include <machine/resource.h>
   59: #include <sys/rman.h>
   60: 
   61: MODULE_VERSION(agp, 1);
   62: 
   63: MALLOC_DEFINE(M_AGP, "agp", "AGP data structures");
   64: 
   65: #define CDEV_MAJOR	148
   66: 				/* agp_drv.c */
   67: static d_open_t agp_open;
   68: static d_close_t agp_close;
   69: static d_ioctl_t agp_ioctl;
   70: static d_mmap_t agp_mmap;
   71: 
   72: static struct cdevsw agp_cdevsw = {
   73: 	/* name */	"agp",
   74: 	/* maj */	CDEV_MAJOR,
   75: 	/* flags */	D_TTY,
   76: 	/* port */	NULL,
   77: 	/* autoq */	0,
   78: 
   79: 	/* open */	agp_open,
   80: 	/* close */	agp_close,
   81: 	/* read */	noread,
   82: 	/* write */	nowrite,
   83: 	/* ioctl */	agp_ioctl,
   84: 	/* poll */	nopoll,
   85: 	/* mmap */	agp_mmap,
   86: 	/* strategy */	nostrategy,
   87: 	/* dump */	nodump,
   88: 	/* psize */	nopsize
   89: };
   90: 
   91: static devclass_t agp_devclass;
   92: #define KDEV2DEV(kdev)	devclass_get_device(agp_devclass, minor(kdev))
   93: 
   94: /* Helper functions for implementing chipset mini drivers. */
   95: 
   96: void
   97: agp_flush_cache()
   98: {
   99: #ifdef __i386__
  100: 	wbinvd();
  101: #endif
  102: }
  103: 
  104: u_int8_t
  105: agp_find_caps(device_t dev)
  106: {
  107: 	u_int32_t status;
  108: 	u_int8_t ptr, next;
  109: 
  110: 	/*
  111: 	 * Check the CAP_LIST bit of the PCI status register first.
  112: 	 */
  113: 	status = pci_read_config(dev, PCIR_STATUS, 2);
  114: 	if (!(status & 0x10))
  115: 		return 0;
  116: 
  117: 	/*
  118: 	 * Traverse the capabilities list.
  119: 	 */
  120: 	for (ptr = pci_read_config(dev, AGP_CAPPTR, 1);
  121: 	     ptr != 0;
  122: 	     ptr = next) {
  123: 		u_int32_t capid = pci_read_config(dev, ptr, 4);
  124: 		next = AGP_CAPID_GET_NEXT_PTR(capid);
  125: 
  126: 		/*
  127: 		 * If this capability entry ID is 2, then we are done.
  128: 		 */
  129: 		if (AGP_CAPID_GET_CAP_ID(capid) == 2)
  130: 			return ptr;
  131: 	}
  132: 
  133: 	return 0;
  134: }
  135: 
  136: /*
  137:  * Find an AGP display device (if any).
  138:  */
  139: static device_t
  140: agp_find_display(void)
  141: {
  142: 	devclass_t pci = devclass_find("pci");
  143: 	device_t bus, dev = 0;
  144: 	device_t *kids;
  145: 	int busnum, numkids, i;
  146: 
  147: 	for (busnum = 0; busnum < devclass_get_maxunit(pci); busnum++) {
  148: 		bus = devclass_get_device(pci, busnum);
  149: 		if (!bus)
  150: 			continue;
  151: 		device_get_children(bus, &kids, &numkids);
  152: 		for (i = 0; i < numkids; i++) {
  153: 			dev = kids[i];
  154: 			if (pci_get_class(dev) == PCIC_DISPLAY
  155: 			    && pci_get_subclass(dev) == PCIS_DISPLAY_VGA)
  156: 				if (agp_find_caps(dev)) {
  157: 					free(kids, M_TEMP);
  158: 					return dev;
  159: 				}
  160: 					
  161: 		}
  162: 		free(kids, M_TEMP);
  163: 	}
  164: 
  165: 	return 0;
  166: }
  167: 
  168: struct agp_gatt *
  169: agp_alloc_gatt(device_t dev)
  170: {
  171: 	u_int32_t apsize = AGP_GET_APERTURE(dev);
  172: 	u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
  173: 	struct agp_gatt *gatt;
  174: 
  175: 	if (bootverbose)
  176: 		device_printf(dev,
  177: 			      "allocating GATT for aperture of size %dM\n",
  178: 			      apsize / (1024*1024));
  179: 
  180: 	gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
  181: 	if (!gatt)
  182: 		return 0;
  183: 
  184: 	gatt->ag_entries = entries;
  185: 	gatt->ag_virtual = contigmalloc(entries * sizeof(u_int32_t), M_AGP, 0,
  186: 					0, ~0, PAGE_SIZE, 0);
  187: 	if (!gatt->ag_virtual) {
  188: 		if (bootverbose)
  189: 			device_printf(dev, "contiguous allocation failed\n");
  190: 		free(gatt, M_AGP);
  191: 		return 0;
  192: 	}
  193: 	bzero(gatt->ag_virtual, entries * sizeof(u_int32_t));
  194: 	gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
  195: 	agp_flush_cache();
  196: 
  197: 	return gatt;
  198: }
  199: 
  200: void
  201: agp_free_gatt(struct agp_gatt *gatt)
  202: {
  203: 	contigfree(gatt->ag_virtual,
  204: 		   gatt->ag_entries * sizeof(u_int32_t), M_AGP);
  205: 	free(gatt, M_AGP);
  206: }
  207: 
  208: static int agp_max[][2] = {
  209: 	{0,	0},
  210: 	{32,	4},
  211: 	{64,	28},
  212: 	{128,	96},
  213: 	{256,	204},
  214: 	{512,	440},
  215: 	{1024,	942},
  216: 	{2048,	1920},
  217: 	{4096,	3932}
  218: };
  219: #define agp_max_size	(sizeof(agp_max) / sizeof(agp_max[0]))
  220: 
  221: int
  222: agp_generic_attach(device_t dev)
  223: {
  224: 	struct agp_softc *sc = device_get_softc(dev);
  225: 	int rid, memsize, i;
  226: 
  227: 	/*
  228: 	 * Find and map the aperture.
  229: 	 */
  230: 	rid = AGP_APBASE;
  231: 	sc->as_aperture = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
  232: 					     0, ~0, 1, RF_ACTIVE);
  233: 	if (!sc->as_aperture)
  234: 		return ENOMEM;
  235: 
  236: 	/*
  237: 	 * Work out an upper bound for agp memory allocation. This
  238: 	 * uses a heurisitc table from the Linux driver.
  239: 	 */
  240: 	memsize = ptoa(Maxmem) >> 20;
  241: 	for (i = 0; i < agp_max_size; i++) {
  242: 		if (memsize <= agp_max[i][0])
  243: 			break;
  244: 	}
  245: 	if (i == agp_max_size) i = agp_max_size - 1;
  246: 	sc->as_maxmem = agp_max[i][1] << 20U;
  247: 
  248: 	/*
  249: 	 * The lock is used to prevent re-entry to
  250: 	 * agp_generic_bind_memory() since that function can sleep.
  251: 	 */
  252: 	lockinit(&sc->as_lock, PCATCH, "agplk", 0, 0);
  253: 
  254: 	/*
  255: 	 * Initialise stuff for the userland device.
  256: 	 */
  257: 	agp_devclass = devclass_find("agp");
  258: 	TAILQ_INIT(&sc->as_memory);
  259: 	sc->as_nextid = 1;
  260: 
  261: 	sc->as_devnode = make_dev(&agp_cdevsw,
  262: 				  device_get_unit(dev),
  263: 				  UID_ROOT,
  264: 				  GID_WHEEL,
  265: 				  0600,
  266: 				  "agpgart");
  267: 
  268: 	return 0;
  269: }
  270: 
  271: int
  272: agp_generic_detach(device_t dev)
  273: {
  274: 	struct agp_softc *sc = device_get_softc(dev);
  275: 	bus_release_resource(dev, SYS_RES_MEMORY, AGP_APBASE, sc->as_aperture);
  276: 	lockmgr(&sc->as_lock, LK_DRAIN, 0, curthread); /* XXX */
  277: 	destroy_dev(sc->as_devnode);
  278: 	agp_flush_cache();
  279: 	return 0;
  280: }
  281: 
  282: int
  283: agp_generic_enable(device_t dev, u_int32_t mode)
  284: {
  285: 	device_t mdev = agp_find_display();
  286: 	u_int32_t tstatus, mstatus;
  287: 	u_int32_t command;
  288: 	int rq, sba, fw, rate;;
  289: 
  290: 	if (!mdev) {
  291: 		AGP_DPF("can't find display\n");
  292: 		return ENXIO;
  293: 	}
  294: 
  295: 	tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
  296: 	mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
  297: 
  298: 	/* Set RQ to the min of mode, tstatus and mstatus */
  299: 	rq = AGP_MODE_GET_RQ(mode);
  300: 	if (AGP_MODE_GET_RQ(tstatus) < rq)
  301: 		rq = AGP_MODE_GET_RQ(tstatus);
  302: 	if (AGP_MODE_GET_RQ(mstatus) < rq)
  303: 		rq = AGP_MODE_GET_RQ(mstatus);
  304: 
  305: 	/* Set SBA if all three can deal with SBA */
  306: 	sba = (AGP_MODE_GET_SBA(tstatus)
  307: 	       & AGP_MODE_GET_SBA(mstatus)
  308: 	       & AGP_MODE_GET_SBA(mode));
  309: 
  310: 	/* Similar for FW */
  311: 	fw = (AGP_MODE_GET_FW(tstatus)
  312: 	       & AGP_MODE_GET_FW(mstatus)
  313: 	       & AGP_MODE_GET_FW(mode));
  314: 
  315: 	/* Figure out the max rate */
  316: 	rate = (AGP_MODE_GET_RATE(tstatus)
  317: 		& AGP_MODE_GET_RATE(mstatus)
  318: 		& AGP_MODE_GET_RATE(mode));
  319: 	if (rate & AGP_MODE_RATE_4x)
  320: 		rate = AGP_MODE_RATE_4x;
  321: 	else if (rate & AGP_MODE_RATE_2x)
  322: 		rate = AGP_MODE_RATE_2x;
  323: 	else
  324: 		rate = AGP_MODE_RATE_1x;
  325: 
  326: 	/* Construct the new mode word and tell the hardware */
  327: 	command = AGP_MODE_SET_RQ(0, rq);
  328: 	command = AGP_MODE_SET_SBA(command, sba);
  329: 	command = AGP_MODE_SET_FW(command, fw);
  330: 	command = AGP_MODE_SET_RATE(command, rate);
  331: 	command = AGP_MODE_SET_AGP(command, 1);
  332: 	pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4);
  333: 	pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
  334: 
  335: 	return 0;
  336: }
  337: 
  338: struct agp_memory *
  339: agp_generic_alloc_memory(device_t dev, int type, vm_size_t size)
  340: {
  341: 	struct agp_softc *sc = device_get_softc(dev);
  342: 	struct agp_memory *mem;
  343: 
  344: 	if ((size & (AGP_PAGE_SIZE - 1)) != 0)
  345: 		return 0;
  346: 
  347: 	if (sc->as_allocated + size > sc->as_maxmem)
  348: 		return 0;
  349: 
  350: 	if (type != 0) {
  351: 		printf("agp_generic_alloc_memory: unsupported type %d\n",
  352: 		       type);
  353: 		return 0;
  354: 	}
  355: 
  356: 	mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
  357: 	mem->am_id = sc->as_nextid++;
  358: 	mem->am_size = size;
  359: 	mem->am_type = 0;
  360: 	mem->am_obj = vm_object_allocate(OBJT_DEFAULT, atop(round_page(size)));
  361: 	mem->am_physical = 0;
  362: 	mem->am_offset = 0;
  363: 	mem->am_is_bound = 0;
  364: 	TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link);
  365: 	sc->as_allocated += size;
  366: 
  367: 	return mem;
  368: }
  369: 
  370: int
  371: agp_generic_free_memory(device_t dev, struct agp_memory *mem)
  372: {
  373: 	struct agp_softc *sc = device_get_softc(dev);
  374: 
  375: 	if (mem->am_is_bound)
  376: 		return EBUSY;
  377: 
  378: 	sc->as_allocated -= mem->am_size;
  379: 	TAILQ_REMOVE(&sc->as_memory, mem, am_link);
  380: 	vm_object_deallocate(mem->am_obj);
  381: 	free(mem, M_AGP);
  382: 	return 0;
  383: }
  384: 
  385: int
  386: agp_generic_bind_memory(device_t dev, struct agp_memory *mem,
  387: 			vm_offset_t offset)
  388: {
  389: 	struct agp_softc *sc = device_get_softc(dev);
  390: 	vm_offset_t i, j, k;
  391: 	vm_page_t m;
  392: 	int error;
  393: 
  394: 	lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curthread); /* XXX */
  395: 
  396: 	if (mem->am_is_bound) {
  397: 		device_printf(dev, "memory already bound\n");
  398: 		return EINVAL;
  399: 	}
  400: 	
  401: 	if (offset < 0
  402: 	    || (offset & (AGP_PAGE_SIZE - 1)) != 0
  403: 	    || offset + mem->am_size > AGP_GET_APERTURE(dev)) {
  404: 		device_printf(dev, "binding memory at bad offset %#x\n",
  405: 			      (int) offset);
  406: 		return EINVAL;
  407: 	}
  408: 
  409: 	/*
  410: 	 * Bind the individual pages and flush the chipset's
  411: 	 * TLB.
  412: 	 *
  413: 	 * XXX Presumably, this needs to be the pci address on alpha
  414: 	 * (i.e. use alpha_XXX_dmamap()). I don't have access to any
  415: 	 * alpha AGP hardware to check.
  416: 	 */
  417: 	for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
  418: 		/*
  419: 		 * Find a page from the object and wire it
  420: 		 * down. This page will be mapped using one or more
  421: 		 * entries in the GATT (assuming that PAGE_SIZE >=
  422: 		 * AGP_PAGE_SIZE. If this is the first call to bind,
  423: 		 * the pages will be allocated and zeroed.
  424: 		 */
  425: 		m = vm_page_grab(mem->am_obj, OFF_TO_IDX(i),
  426: 				 VM_ALLOC_ZERO | VM_ALLOC_RETRY);
  427: 		if ((m->flags & PG_ZERO) == 0)
  428: 			vm_page_zero_fill(m);
  429: 		AGP_DPF("found page pa=%#x\n", VM_PAGE_TO_PHYS(m));
  430: 		vm_page_wire(m);
  431: 
  432: 		/*
  433: 		 * Install entries in the GATT, making sure that if
  434: 		 * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not
  435: 		 * aligned to PAGE_SIZE, we don't modify too many GATT 
  436: 		 * entries.
  437: 		 */
  438: 		for (j = 0; j < PAGE_SIZE && i + j < mem->am_size;
  439: 		     j += AGP_PAGE_SIZE) {
  440: 			vm_offset_t pa = VM_PAGE_TO_PHYS(m) + j;
  441: 			AGP_DPF("binding offset %#x to pa %#x\n",
  442: 				offset + i + j, pa);
  443: 			error = AGP_BIND_PAGE(dev, offset + i + j, pa);
  444: 			if (error) {
  445: 				/*
  446: 				 * Bail out. Reverse all the mappings
  447: 				 * and unwire the pages.
  448: 				 */
  449: 				vm_page_wakeup(m);
  450: 				for (k = 0; k < i + j; k += AGP_PAGE_SIZE)
  451: 					AGP_UNBIND_PAGE(dev, offset + k);
  452: 				for (k = 0; k <= i; k += PAGE_SIZE) {
  453: 					m = vm_page_lookup(mem->am_obj,
  454: 							   OFF_TO_IDX(k));
  455: 					vm_page_unwire(m, 0);
  456: 				}
  457: 				lockmgr(&sc->as_lock, LK_RELEASE, 0, curthread); /* XXX */
  458: 				return error;
  459: 			}
  460: 		}
  461: 		vm_page_wakeup(m);
  462: 	}
  463: 
  464: 	/*
  465: 	 * Flush the cpu cache since we are providing a new mapping
  466: 	 * for these pages.
  467: 	 */
  468: 	agp_flush_cache();
  469: 
  470: 	/*
  471: 	 * Make sure the chipset gets the new mappings.
  472: 	 */
  473: 	AGP_FLUSH_TLB(dev);
  474: 
  475: 	mem->am_offset = offset;
  476: 	mem->am_is_bound = 1;
  477: 
  478: 	lockmgr(&sc->as_lock, LK_RELEASE, 0, curthread); /* XXX */
  479: 
  480: 	return 0;
  481: }
  482: 
  483: int
  484: agp_generic_unbind_memory(device_t dev, struct agp_memory *mem)
  485: {
  486: 	struct agp_softc *sc = device_get_softc(dev);
  487: 	vm_page_t m;
  488: 	int i;
  489: 
  490: 	lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curthread); /* XXX */
  491: 
  492: 	if (!mem->am_is_bound) {
  493: 		device_printf(dev, "memory is not bound\n");
  494: 		return EINVAL;
  495: 	}
  496: 
  497: 
  498: 	/*
  499: 	 * Unbind the individual pages and flush the chipset's
  500: 	 * TLB. Unwire the pages so they can be swapped.
  501: 	 */
  502: 	for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
  503: 		AGP_UNBIND_PAGE(dev, mem->am_offset + i);
  504: 	for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
  505: 		m = vm_page_lookup(mem->am_obj, atop(i));
  506: 		vm_page_unwire(m, 0);
  507: 	}
  508: 		
  509: 	agp_flush_cache();
  510: 	AGP_FLUSH_TLB(dev);
  511: 
  512: 	mem->am_offset = 0;
  513: 	mem->am_is_bound = 0;
  514: 
  515: 	lockmgr(&sc->as_lock, LK_RELEASE, 0, curthread); /* XXX */
  516: 
  517: 	return 0;
  518: }
  519: 
  520: /* Helper functions for implementing user/kernel api */
  521: 
  522: static int
  523: agp_acquire_helper(device_t dev, enum agp_acquire_state state)
  524: {
  525: 	struct agp_softc *sc = device_get_softc(dev);
  526: 
  527: 	if (sc->as_state != AGP_ACQUIRE_FREE)
  528: 		return EBUSY;
  529: 	sc->as_state = state;
  530: 
  531: 	return 0;
  532: }
  533: 
  534: static int
  535: agp_release_helper(device_t dev, enum agp_acquire_state state)
  536: {
  537: 	struct agp_softc *sc = device_get_softc(dev);
  538: 
  539: 	if (sc->as_state == AGP_ACQUIRE_FREE)
  540: 		return 0;
  541: 
  542: 	if (sc->as_state != state)
  543: 		return EBUSY;
  544: 
  545: 	sc->as_state = AGP_ACQUIRE_FREE;
  546: 	return 0;
  547: }
  548: 
  549: static struct agp_memory *
  550: agp_find_memory(device_t dev, int id)
  551: {
  552: 	struct agp_softc *sc = device_get_softc(dev);
  553: 	struct agp_memory *mem;
  554: 
  555: 	AGP_DPF("searching for memory block %d\n", id);
  556: 	TAILQ_FOREACH(mem, &sc->as_memory, am_link) {
  557: 		AGP_DPF("considering memory block %d\n", mem->am_id);
  558: 		if (mem->am_id == id)
  559: 			return mem;
  560: 	}
  561: 	return 0;
  562: }
  563: 
  564: /* Implementation of the userland ioctl api */
  565: 
  566: static int
  567: agp_info_user(device_t dev, agp_info *info)
  568: {
  569: 	struct agp_softc *sc = device_get_softc(dev);
  570: 
  571: 	bzero(info, sizeof *info);
  572: 	info->bridge_id = pci_get_devid(dev);
  573: 	info->agp_mode = 
  574: 	    pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
  575: 	info->aper_base = rman_get_start(sc->as_aperture);
  576: 	info->aper_size = AGP_GET_APERTURE(dev) >> 20;
  577: 	info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT;
  578: 	info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT;
  579: 
  580: 	return 0;
  581: }
  582: 
  583: static int
  584: agp_setup_user(device_t dev, agp_setup *setup)
  585: {
  586: 	return AGP_ENABLE(dev, setup->agp_mode);
  587: }
  588: 
  589: static int
  590: agp_allocate_user(device_t dev, agp_allocate *alloc)
  591: {
  592: 	struct agp_memory *mem;
  593: 
  594: 	mem = AGP_ALLOC_MEMORY(dev,
  595: 			       alloc->type,
  596: 			       alloc->pg_count << AGP_PAGE_SHIFT);
  597: 	if (mem) {
  598: 		alloc->key = mem->am_id;
  599: 		alloc->physical = mem->am_physical;
  600: 		return 0;
  601: 	} else {
  602: 		return ENOMEM;
  603: 	}
  604: }
  605: 
  606: static int
  607: agp_deallocate_user(device_t dev, int id)
  608: {
  609: 	struct agp_memory *mem = agp_find_memory(dev, id);;
  610: 
  611: 	if (mem) {
  612: 		AGP_FREE_MEMORY(dev, mem);
  613: 		return 0;
  614: 	} else {
  615: 		return ENOENT;
  616: 	}
  617: }
  618: 
  619: static int
  620: agp_bind_user(device_t dev, agp_bind *bind)
  621: {
  622: 	struct agp_memory *mem = agp_find_memory(dev, bind->key);
  623: 
  624: 	if (!mem)
  625: 		return ENOENT;
  626: 
  627: 	return AGP_BIND_MEMORY(dev, mem, bind->pg_start << AGP_PAGE_SHIFT);
  628: }
  629: 
  630: static int
  631: agp_unbind_user(device_t dev, agp_unbind *unbind)
  632: {
  633: 	struct agp_memory *mem = agp_find_memory(dev, unbind->key);
  634: 
  635: 	if (!mem)
  636: 		return ENOENT;
  637: 
  638: 	return AGP_UNBIND_MEMORY(dev, mem);
  639: }
  640: 
  641: static int
  642: agp_open(dev_t kdev, int oflags, int devtype, struct thread *td)
  643: {
  644: 	device_t dev = KDEV2DEV(kdev);
  645: 	struct agp_softc *sc = device_get_softc(dev);
  646: 
  647: 	if (!sc->as_isopen) {
  648: 		sc->as_isopen = 1;
  649: 		device_busy(dev);
  650: 	}
  651: 
  652: 	return 0;
  653: }
  654: 
  655: static int
  656: agp_close(dev_t kdev, int fflag, int devtype, struct thread *td)
  657: {
  658: 	device_t dev = KDEV2DEV(kdev);
  659: 	struct agp_softc *sc = device_get_softc(dev);
  660: 	struct agp_memory *mem;
  661: 
  662: 	/*
  663: 	 * Clear the GATT and force release on last close
  664: 	 */
  665: 	while ((mem = TAILQ_FIRST(&sc->as_memory)) != 0) {
  666: 		if (mem->am_is_bound)
  667: 			AGP_UNBIND_MEMORY(dev, mem);
  668: 		AGP_FREE_MEMORY(dev, mem);
  669: 	}
  670: 	if (sc->as_state == AGP_ACQUIRE_USER)
  671: 		agp_release_helper(dev, AGP_ACQUIRE_USER);
  672: 	sc->as_isopen = 0;
  673: 	device_unbusy(dev);
  674: 
  675: 	return 0;
  676: }
  677: 
  678: static int
  679: agp_ioctl(dev_t kdev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  680: {
  681: 	device_t dev = KDEV2DEV(kdev);
  682: 
  683: 	switch (cmd) {
  684: 	case AGPIOC_INFO:
  685: 		return agp_info_user(dev, (agp_info *) data);
  686: 
  687: 	case AGPIOC_ACQUIRE:
  688: 		return agp_acquire_helper(dev, AGP_ACQUIRE_USER);
  689: 
  690: 	case AGPIOC_RELEASE:
  691: 		return agp_release_helper(dev, AGP_ACQUIRE_USER);
  692: 
  693: 	case AGPIOC_SETUP:
  694: 		return agp_setup_user(dev, (agp_setup *)data);
  695: 
  696: 	case AGPIOC_ALLOCATE:
  697: 		return agp_allocate_user(dev, (agp_allocate *)data);
  698: 
  699: 	case AGPIOC_DEALLOCATE:
  700: 		return agp_deallocate_user(dev, *(int *) data);
  701: 
  702: 	case AGPIOC_BIND:
  703: 		return agp_bind_user(dev, (agp_bind *)data);
  704: 
  705: 	case AGPIOC_UNBIND:
  706: 		return agp_unbind_user(dev, (agp_unbind *)data);
  707: 
  708: 	}
  709: 
  710: 	return EINVAL;
  711: }
  712: 
  713: static int
  714: agp_mmap(dev_t kdev, vm_offset_t offset, int prot)
  715: {
  716: 	device_t dev = KDEV2DEV(kdev);
  717: 	struct agp_softc *sc = device_get_softc(dev);
  718: 
  719: 	if (offset > AGP_GET_APERTURE(dev))
  720: 		return -1;
  721: 	return atop(rman_get_start(sc->as_aperture) + offset);
  722: }
  723: 
  724: /* Implementation of the kernel api */
  725: 
  726: device_t
  727: agp_find_device()
  728: {
  729: 	if (!agp_devclass)
  730: 		return 0;
  731: 	return devclass_get_device(agp_devclass, 0);
  732: }
  733: 
  734: enum agp_acquire_state
  735: agp_state(device_t dev)
  736: {
  737: 	struct agp_softc *sc = device_get_softc(dev);
  738: 	return sc->as_state;
  739: }
  740: 
  741: void
  742: agp_get_info(device_t dev, struct agp_info *info)
  743: {
  744: 	struct agp_softc *sc = device_get_softc(dev);
  745: 
  746: 	info->ai_mode =
  747: 		pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
  748: 	info->ai_aperture_base = rman_get_start(sc->as_aperture);
  749: 	info->ai_aperture_size = (rman_get_end(sc->as_aperture)
  750: 				  - rman_get_start(sc->as_aperture)) + 1;
  751: 	info->ai_aperture_va = (vm_offset_t) rman_get_virtual(sc->as_aperture);
  752: 	info->ai_memory_allowed = sc->as_maxmem;
  753: 	info->ai_memory_used = sc->as_allocated;
  754: }
  755: 
  756: int
  757: agp_acquire(device_t dev)
  758: {
  759: 	return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL);
  760: }
  761: 
  762: int
  763: agp_release(device_t dev)
  764: {
  765: 	return agp_release_helper(dev, AGP_ACQUIRE_KERNEL);
  766: }
  767: 
  768: int
  769: agp_enable(device_t dev, u_int32_t mode)
  770: {
  771: 	return AGP_ENABLE(dev, mode);
  772: }
  773: 
  774: void *agp_alloc_memory(device_t dev, int type, vm_size_t bytes)
  775: {
  776: 	return  (void *) AGP_ALLOC_MEMORY(dev, type, bytes);
  777: }
  778: 
  779: void agp_free_memory(device_t dev, void *handle)
  780: {
  781: 	struct agp_memory *mem = (struct agp_memory *) handle;
  782: 	AGP_FREE_MEMORY(dev, mem);
  783: }
  784: 
  785: int agp_bind_memory(device_t dev, void *handle, vm_offset_t offset)
  786: {
  787: 	struct agp_memory *mem = (struct agp_memory *) handle;
  788: 	return AGP_BIND_MEMORY(dev, mem, offset);
  789: }
  790: 
  791: int agp_unbind_memory(device_t dev, void *handle)
  792: {
  793: 	struct agp_memory *mem = (struct agp_memory *) handle;
  794: 	return AGP_UNBIND_MEMORY(dev, mem);
  795: }
  796: 
  797: void agp_memory_info(device_t dev, void *handle, struct
  798: 		     agp_memory_info *mi)
  799: {
  800: 	struct agp_memory *mem = (struct agp_memory *) handle;
  801: 
  802: 	mi->ami_size = mem->am_size;
  803: 	mi->ami_physical = mem->am_physical;
  804: 	mi->ami_offset = mem->am_offset;
  805: 	mi->ami_is_bound = mem->am_is_bound;
  806: }