xref: /freebsd/sys/dev/agp/agp.c (revision a163d034fadcfb4a25ca34a2ba5f491c47b6ff69)
159747216SDoug Rabson /*-
259747216SDoug Rabson  * Copyright (c) 2000 Doug Rabson
359747216SDoug Rabson  * All rights reserved.
459747216SDoug Rabson  *
559747216SDoug Rabson  * Redistribution and use in source and binary forms, with or without
659747216SDoug Rabson  * modification, are permitted provided that the following conditions
759747216SDoug Rabson  * are met:
859747216SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
959747216SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
1059747216SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
1159747216SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
1259747216SDoug Rabson  *    documentation and/or other materials provided with the distribution.
1359747216SDoug Rabson  *
1459747216SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1559747216SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1659747216SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1759747216SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1859747216SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1959747216SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2059747216SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2159747216SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2259747216SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2359747216SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2459747216SDoug Rabson  * SUCH DAMAGE.
2559747216SDoug Rabson  *
2659747216SDoug Rabson  *	$FreeBSD$
2759747216SDoug Rabson  */
2859747216SDoug Rabson 
2959747216SDoug Rabson #include "opt_bus.h"
3059747216SDoug Rabson 
3159747216SDoug Rabson #include <sys/param.h>
3259747216SDoug Rabson #include <sys/systm.h>
3359747216SDoug Rabson #include <sys/malloc.h>
3459747216SDoug Rabson #include <sys/kernel.h>
3559747216SDoug Rabson #include <sys/bus.h>
3659747216SDoug Rabson #include <sys/conf.h>
3759747216SDoug Rabson #include <sys/ioccom.h>
3859747216SDoug Rabson #include <sys/agpio.h>
3959747216SDoug Rabson #include <sys/lock.h>
407e9e7dc4SBruce Evans #include <sys/lockmgr.h>
4123955314SAlfred Perlstein #include <sys/mutex.h>
421639f08bSJohn Baldwin #include <sys/proc.h>
4359747216SDoug Rabson 
4459747216SDoug Rabson #include <pci/pcivar.h>
4559747216SDoug Rabson #include <pci/pcireg.h>
4659747216SDoug Rabson #include <pci/agppriv.h>
4759747216SDoug Rabson #include <pci/agpvar.h>
4859747216SDoug Rabson #include <pci/agpreg.h>
4959747216SDoug Rabson 
5059747216SDoug Rabson #include <vm/vm.h>
5159747216SDoug Rabson #include <vm/vm_object.h>
5259747216SDoug Rabson #include <vm/vm_page.h>
5359747216SDoug Rabson #include <vm/vm_pageout.h>
5459747216SDoug Rabson #include <vm/pmap.h>
5559747216SDoug Rabson 
5659747216SDoug Rabson #include <machine/md_var.h>
5759747216SDoug Rabson #include <machine/bus.h>
5859747216SDoug Rabson #include <machine/resource.h>
5959747216SDoug Rabson #include <sys/rman.h>
6059747216SDoug Rabson 
6159747216SDoug Rabson MODULE_VERSION(agp, 1);
6259747216SDoug Rabson 
63315a1645SAssar Westerlund MALLOC_DEFINE(M_AGP, "agp", "AGP data structures");
6459747216SDoug Rabson 
6559747216SDoug Rabson #define CDEV_MAJOR	148
6659747216SDoug Rabson 				/* agp_drv.c */
6759747216SDoug Rabson static d_open_t agp_open;
6859747216SDoug Rabson static d_close_t agp_close;
6959747216SDoug Rabson static d_ioctl_t agp_ioctl;
7059747216SDoug Rabson static d_mmap_t agp_mmap;
7159747216SDoug Rabson 
7259747216SDoug Rabson static struct cdevsw agp_cdevsw = {
7359747216SDoug Rabson 	/* open */	agp_open,
7459747216SDoug Rabson 	/* close */	agp_close,
7559747216SDoug Rabson 	/* read */	noread,
7659747216SDoug Rabson 	/* write */	nowrite,
7759747216SDoug Rabson 	/* ioctl */	agp_ioctl,
7859747216SDoug Rabson 	/* poll */	nopoll,
7959747216SDoug Rabson 	/* mmap */	agp_mmap,
8059747216SDoug Rabson 	/* strategy */	nostrategy,
8159747216SDoug Rabson 	/* name */	"agp",
8259747216SDoug Rabson 	/* maj */	CDEV_MAJOR,
8359747216SDoug Rabson 	/* dump */	nodump,
8459747216SDoug Rabson 	/* psize */	nopsize,
8559747216SDoug Rabson 	/* flags */	D_TTY,
8659747216SDoug Rabson };
8759747216SDoug Rabson 
8859747216SDoug Rabson static devclass_t agp_devclass;
8959747216SDoug Rabson #define KDEV2DEV(kdev)	devclass_get_device(agp_devclass, minor(kdev))
9059747216SDoug Rabson 
9159747216SDoug Rabson /* Helper functions for implementing chipset mini drivers. */
9259747216SDoug Rabson 
93111618cbSDoug Rabson void
94111618cbSDoug Rabson agp_flush_cache()
95111618cbSDoug Rabson {
9659747216SDoug Rabson #ifdef __i386__
97111618cbSDoug Rabson 	wbinvd();
9859747216SDoug Rabson #endif
9905d1e23aSEric Anholt #ifdef __alpha__
10005d1e23aSEric Anholt 	/* FIXME: This is most likely not correct as it doesn't flush CPU
10105d1e23aSEric Anholt 	 * write caches, but we don't have a facility to do that and
10205d1e23aSEric Anholt 	 * this is all linux does, too */
10305d1e23aSEric Anholt 	alpha_mb();
10405d1e23aSEric Anholt #endif
105111618cbSDoug Rabson }
10659747216SDoug Rabson 
10759747216SDoug Rabson u_int8_t
10859747216SDoug Rabson agp_find_caps(device_t dev)
10959747216SDoug Rabson {
11059747216SDoug Rabson 	u_int32_t status;
11159747216SDoug Rabson 	u_int8_t ptr, next;
11259747216SDoug Rabson 
11359747216SDoug Rabson 	/*
11459747216SDoug Rabson 	 * Check the CAP_LIST bit of the PCI status register first.
11559747216SDoug Rabson 	 */
11659747216SDoug Rabson 	status = pci_read_config(dev, PCIR_STATUS, 2);
11759747216SDoug Rabson 	if (!(status & 0x10))
11859747216SDoug Rabson 		return 0;
11959747216SDoug Rabson 
12059747216SDoug Rabson 	/*
12159747216SDoug Rabson 	 * Traverse the capabilities list.
12259747216SDoug Rabson 	 */
12359747216SDoug Rabson 	for (ptr = pci_read_config(dev, AGP_CAPPTR, 1);
12459747216SDoug Rabson 	     ptr != 0;
12559747216SDoug Rabson 	     ptr = next) {
12659747216SDoug Rabson 		u_int32_t capid = pci_read_config(dev, ptr, 4);
12759747216SDoug Rabson 		next = AGP_CAPID_GET_NEXT_PTR(capid);
12859747216SDoug Rabson 
12959747216SDoug Rabson 		/*
13059747216SDoug Rabson 		 * If this capability entry ID is 2, then we are done.
13159747216SDoug Rabson 		 */
13259747216SDoug Rabson 		if (AGP_CAPID_GET_CAP_ID(capid) == 2)
13359747216SDoug Rabson 			return ptr;
13459747216SDoug Rabson 	}
13559747216SDoug Rabson 
13659747216SDoug Rabson 	return 0;
13759747216SDoug Rabson }
13859747216SDoug Rabson 
13959747216SDoug Rabson /*
14059747216SDoug Rabson  * Find an AGP display device (if any).
14159747216SDoug Rabson  */
14259747216SDoug Rabson static device_t
14359747216SDoug Rabson agp_find_display(void)
14459747216SDoug Rabson {
14559747216SDoug Rabson 	devclass_t pci = devclass_find("pci");
14659747216SDoug Rabson 	device_t bus, dev = 0;
14759747216SDoug Rabson 	device_t *kids;
14859747216SDoug Rabson 	int busnum, numkids, i;
14959747216SDoug Rabson 
15059747216SDoug Rabson 	for (busnum = 0; busnum < devclass_get_maxunit(pci); busnum++) {
15159747216SDoug Rabson 		bus = devclass_get_device(pci, busnum);
15259747216SDoug Rabson 		if (!bus)
15359747216SDoug Rabson 			continue;
15459747216SDoug Rabson 		device_get_children(bus, &kids, &numkids);
15559747216SDoug Rabson 		for (i = 0; i < numkids; i++) {
15659747216SDoug Rabson 			dev = kids[i];
15759747216SDoug Rabson 			if (pci_get_class(dev) == PCIC_DISPLAY
15859747216SDoug Rabson 			    && pci_get_subclass(dev) == PCIS_DISPLAY_VGA)
15959747216SDoug Rabson 				if (agp_find_caps(dev)) {
16059747216SDoug Rabson 					free(kids, M_TEMP);
16159747216SDoug Rabson 					return dev;
16259747216SDoug Rabson 				}
16359747216SDoug Rabson 
16459747216SDoug Rabson 		}
16559747216SDoug Rabson 		free(kids, M_TEMP);
16659747216SDoug Rabson 	}
16759747216SDoug Rabson 
16859747216SDoug Rabson 	return 0;
16959747216SDoug Rabson }
17059747216SDoug Rabson 
17159747216SDoug Rabson struct agp_gatt *
17259747216SDoug Rabson agp_alloc_gatt(device_t dev)
17359747216SDoug Rabson {
17459747216SDoug Rabson 	u_int32_t apsize = AGP_GET_APERTURE(dev);
17559747216SDoug Rabson 	u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
17659747216SDoug Rabson 	struct agp_gatt *gatt;
17759747216SDoug Rabson 
17859747216SDoug Rabson 	if (bootverbose)
17959747216SDoug Rabson 		device_printf(dev,
18059747216SDoug Rabson 			      "allocating GATT for aperture of size %dM\n",
18159747216SDoug Rabson 			      apsize / (1024*1024));
18259747216SDoug Rabson 
18359747216SDoug Rabson 	gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
18459747216SDoug Rabson 	if (!gatt)
18559747216SDoug Rabson 		return 0;
18659747216SDoug Rabson 
18759747216SDoug Rabson 	gatt->ag_entries = entries;
18859747216SDoug Rabson 	gatt->ag_virtual = contigmalloc(entries * sizeof(u_int32_t), M_AGP, 0,
18959747216SDoug Rabson 					0, ~0, PAGE_SIZE, 0);
19059747216SDoug Rabson 	if (!gatt->ag_virtual) {
19159747216SDoug Rabson 		if (bootverbose)
19259747216SDoug Rabson 			device_printf(dev, "contiguous allocation failed\n");
19359747216SDoug Rabson 		free(gatt, M_AGP);
19459747216SDoug Rabson 		return 0;
19559747216SDoug Rabson 	}
19659747216SDoug Rabson 	bzero(gatt->ag_virtual, entries * sizeof(u_int32_t));
19759747216SDoug Rabson 	gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
19859747216SDoug Rabson 	agp_flush_cache();
19959747216SDoug Rabson 
20059747216SDoug Rabson 	return gatt;
20159747216SDoug Rabson }
20259747216SDoug Rabson 
20359747216SDoug Rabson void
20459747216SDoug Rabson agp_free_gatt(struct agp_gatt *gatt)
20559747216SDoug Rabson {
20659747216SDoug Rabson 	contigfree(gatt->ag_virtual,
20759747216SDoug Rabson 		   gatt->ag_entries * sizeof(u_int32_t), M_AGP);
20859747216SDoug Rabson 	free(gatt, M_AGP);
20959747216SDoug Rabson }
21059747216SDoug Rabson 
21159747216SDoug Rabson static int agp_max[][2] = {
21259747216SDoug Rabson 	{0,	0},
21359747216SDoug Rabson 	{32,	4},
21459747216SDoug Rabson 	{64,	28},
21559747216SDoug Rabson 	{128,	96},
21659747216SDoug Rabson 	{256,	204},
21759747216SDoug Rabson 	{512,	440},
21859747216SDoug Rabson 	{1024,	942},
21959747216SDoug Rabson 	{2048,	1920},
22059747216SDoug Rabson 	{4096,	3932}
22159747216SDoug Rabson };
22259747216SDoug Rabson #define agp_max_size	(sizeof(agp_max) / sizeof(agp_max[0]))
22359747216SDoug Rabson 
22459747216SDoug Rabson int
22559747216SDoug Rabson agp_generic_attach(device_t dev)
22659747216SDoug Rabson {
22759747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
22859747216SDoug Rabson 	int rid, memsize, i;
22959747216SDoug Rabson 
23059747216SDoug Rabson 	/*
23159747216SDoug Rabson 	 * Find and map the aperture.
23259747216SDoug Rabson 	 */
23359747216SDoug Rabson 	rid = AGP_APBASE;
23459747216SDoug Rabson 	sc->as_aperture = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
23559747216SDoug Rabson 					     0, ~0, 1, RF_ACTIVE);
23659747216SDoug Rabson 	if (!sc->as_aperture)
23759747216SDoug Rabson 		return ENOMEM;
23859747216SDoug Rabson 
23959747216SDoug Rabson 	/*
24059747216SDoug Rabson 	 * Work out an upper bound for agp memory allocation. This
24159747216SDoug Rabson 	 * uses a heurisitc table from the Linux driver.
24259747216SDoug Rabson 	 */
24359747216SDoug Rabson 	memsize = ptoa(Maxmem) >> 20;
24459747216SDoug Rabson 	for (i = 0; i < agp_max_size; i++) {
24559747216SDoug Rabson 		if (memsize <= agp_max[i][0])
24659747216SDoug Rabson 			break;
24759747216SDoug Rabson 	}
24859747216SDoug Rabson 	if (i == agp_max_size) i = agp_max_size - 1;
24959747216SDoug Rabson 	sc->as_maxmem = agp_max[i][1] << 20U;
25059747216SDoug Rabson 
25159747216SDoug Rabson 	/*
25259747216SDoug Rabson 	 * The lock is used to prevent re-entry to
25359747216SDoug Rabson 	 * agp_generic_bind_memory() since that function can sleep.
25459747216SDoug Rabson 	 */
25559747216SDoug Rabson 	lockinit(&sc->as_lock, PZERO|PCATCH, "agplk", 0, 0);
25659747216SDoug Rabson 
25759747216SDoug Rabson 	/*
25859747216SDoug Rabson 	 * Initialise stuff for the userland device.
25959747216SDoug Rabson 	 */
26059747216SDoug Rabson 	agp_devclass = devclass_find("agp");
26159747216SDoug Rabson 	TAILQ_INIT(&sc->as_memory);
26259747216SDoug Rabson 	sc->as_nextid = 1;
26359747216SDoug Rabson 
26459747216SDoug Rabson 	sc->as_devnode = make_dev(&agp_cdevsw,
26559747216SDoug Rabson 				  device_get_unit(dev),
26659747216SDoug Rabson 				  UID_ROOT,
26759747216SDoug Rabson 				  GID_WHEEL,
26859747216SDoug Rabson 				  0600,
26959747216SDoug Rabson 				  "agpgart");
27059747216SDoug Rabson 
27159747216SDoug Rabson 	return 0;
27259747216SDoug Rabson }
27359747216SDoug Rabson 
27459747216SDoug Rabson int
27559747216SDoug Rabson agp_generic_detach(device_t dev)
27659747216SDoug Rabson {
27759747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
27859747216SDoug Rabson 	bus_release_resource(dev, SYS_RES_MEMORY, AGP_APBASE, sc->as_aperture);
279b40ce416SJulian Elischer 	lockmgr(&sc->as_lock, LK_DRAIN, 0, curthread);
280a18b1f1dSJason Evans 	lockdestroy(&sc->as_lock);
28159747216SDoug Rabson 	destroy_dev(sc->as_devnode);
28259747216SDoug Rabson 	agp_flush_cache();
28359747216SDoug Rabson 	return 0;
28459747216SDoug Rabson }
28559747216SDoug Rabson 
28659747216SDoug Rabson int
28759747216SDoug Rabson agp_generic_enable(device_t dev, u_int32_t mode)
28859747216SDoug Rabson {
28959747216SDoug Rabson 	device_t mdev = agp_find_display();
29059747216SDoug Rabson 	u_int32_t tstatus, mstatus;
29159747216SDoug Rabson 	u_int32_t command;
29259747216SDoug Rabson 	int rq, sba, fw, rate;;
29359747216SDoug Rabson 
29459747216SDoug Rabson 	if (!mdev) {
29559747216SDoug Rabson 		AGP_DPF("can't find display\n");
29659747216SDoug Rabson 		return ENXIO;
29759747216SDoug Rabson 	}
29859747216SDoug Rabson 
29959747216SDoug Rabson 	tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
30059747216SDoug Rabson 	mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
30159747216SDoug Rabson 
30259747216SDoug Rabson 	/* Set RQ to the min of mode, tstatus and mstatus */
30359747216SDoug Rabson 	rq = AGP_MODE_GET_RQ(mode);
30459747216SDoug Rabson 	if (AGP_MODE_GET_RQ(tstatus) < rq)
30559747216SDoug Rabson 		rq = AGP_MODE_GET_RQ(tstatus);
30659747216SDoug Rabson 	if (AGP_MODE_GET_RQ(mstatus) < rq)
30759747216SDoug Rabson 		rq = AGP_MODE_GET_RQ(mstatus);
30859747216SDoug Rabson 
30959747216SDoug Rabson 	/* Set SBA if all three can deal with SBA */
31059747216SDoug Rabson 	sba = (AGP_MODE_GET_SBA(tstatus)
31159747216SDoug Rabson 	       & AGP_MODE_GET_SBA(mstatus)
31259747216SDoug Rabson 	       & AGP_MODE_GET_SBA(mode));
31359747216SDoug Rabson 
31459747216SDoug Rabson 	/* Similar for FW */
31559747216SDoug Rabson 	fw = (AGP_MODE_GET_FW(tstatus)
31659747216SDoug Rabson 	       & AGP_MODE_GET_FW(mstatus)
31759747216SDoug Rabson 	       & AGP_MODE_GET_FW(mode));
31859747216SDoug Rabson 
31959747216SDoug Rabson 	/* Figure out the max rate */
32059747216SDoug Rabson 	rate = (AGP_MODE_GET_RATE(tstatus)
32159747216SDoug Rabson 		& AGP_MODE_GET_RATE(mstatus)
32259747216SDoug Rabson 		& AGP_MODE_GET_RATE(mode));
32359747216SDoug Rabson 	if (rate & AGP_MODE_RATE_4x)
32459747216SDoug Rabson 		rate = AGP_MODE_RATE_4x;
32559747216SDoug Rabson 	else if (rate & AGP_MODE_RATE_2x)
32659747216SDoug Rabson 		rate = AGP_MODE_RATE_2x;
32759747216SDoug Rabson 	else
32859747216SDoug Rabson 		rate = AGP_MODE_RATE_1x;
32959747216SDoug Rabson 
33059747216SDoug Rabson 	/* Construct the new mode word and tell the hardware */
33159747216SDoug Rabson 	command = AGP_MODE_SET_RQ(0, rq);
33259747216SDoug Rabson 	command = AGP_MODE_SET_SBA(command, sba);
33359747216SDoug Rabson 	command = AGP_MODE_SET_FW(command, fw);
33459747216SDoug Rabson 	command = AGP_MODE_SET_RATE(command, rate);
33559747216SDoug Rabson 	command = AGP_MODE_SET_AGP(command, 1);
33659747216SDoug Rabson 	pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4);
33759747216SDoug Rabson 	pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
33859747216SDoug Rabson 
33959747216SDoug Rabson 	return 0;
34059747216SDoug Rabson }
34159747216SDoug Rabson 
34259747216SDoug Rabson struct agp_memory *
34359747216SDoug Rabson agp_generic_alloc_memory(device_t dev, int type, vm_size_t size)
34459747216SDoug Rabson {
34559747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
34659747216SDoug Rabson 	struct agp_memory *mem;
34759747216SDoug Rabson 
34859747216SDoug Rabson 	if ((size & (AGP_PAGE_SIZE - 1)) != 0)
34959747216SDoug Rabson 		return 0;
35059747216SDoug Rabson 
35159747216SDoug Rabson 	if (sc->as_allocated + size > sc->as_maxmem)
35259747216SDoug Rabson 		return 0;
35359747216SDoug Rabson 
354e547d6fdSDoug Rabson 	if (type != 0) {
355e547d6fdSDoug Rabson 		printf("agp_generic_alloc_memory: unsupported type %d\n",
356e547d6fdSDoug Rabson 		       type);
357e547d6fdSDoug Rabson 		return 0;
358e547d6fdSDoug Rabson 	}
359e547d6fdSDoug Rabson 
360a163d034SWarner Losh 	mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
36159747216SDoug Rabson 	mem->am_id = sc->as_nextid++;
36259747216SDoug Rabson 	mem->am_size = size;
363e547d6fdSDoug Rabson 	mem->am_type = 0;
36459747216SDoug Rabson 	mem->am_obj = vm_object_allocate(OBJT_DEFAULT, atop(round_page(size)));
36559747216SDoug Rabson 	mem->am_physical = 0;
36659747216SDoug Rabson 	mem->am_offset = 0;
36759747216SDoug Rabson 	mem->am_is_bound = 0;
36859747216SDoug Rabson 	TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link);
36959747216SDoug Rabson 	sc->as_allocated += size;
37059747216SDoug Rabson 
37159747216SDoug Rabson 	return mem;
37259747216SDoug Rabson }
37359747216SDoug Rabson 
37459747216SDoug Rabson int
37559747216SDoug Rabson agp_generic_free_memory(device_t dev, struct agp_memory *mem)
37659747216SDoug Rabson {
37759747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
37859747216SDoug Rabson 
37959747216SDoug Rabson 	if (mem->am_is_bound)
38059747216SDoug Rabson 		return EBUSY;
38159747216SDoug Rabson 
38259747216SDoug Rabson 	sc->as_allocated -= mem->am_size;
38359747216SDoug Rabson 	TAILQ_REMOVE(&sc->as_memory, mem, am_link);
38459747216SDoug Rabson 	vm_object_deallocate(mem->am_obj);
38559747216SDoug Rabson 	free(mem, M_AGP);
38659747216SDoug Rabson 	return 0;
38759747216SDoug Rabson }
38859747216SDoug Rabson 
38959747216SDoug Rabson int
39059747216SDoug Rabson agp_generic_bind_memory(device_t dev, struct agp_memory *mem,
39159747216SDoug Rabson 			vm_offset_t offset)
39259747216SDoug Rabson {
39359747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
39459747216SDoug Rabson 	vm_offset_t i, j, k;
39559747216SDoug Rabson 	vm_page_t m;
39659747216SDoug Rabson 	int error;
39759747216SDoug Rabson 
398b40ce416SJulian Elischer 	lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curthread);
39959747216SDoug Rabson 
40059747216SDoug Rabson 	if (mem->am_is_bound) {
40159747216SDoug Rabson 		device_printf(dev, "memory already bound\n");
40259747216SDoug Rabson 		return EINVAL;
40359747216SDoug Rabson 	}
40459747216SDoug Rabson 
40559747216SDoug Rabson 	if (offset < 0
40659747216SDoug Rabson 	    || (offset & (AGP_PAGE_SIZE - 1)) != 0
40759747216SDoug Rabson 	    || offset + mem->am_size > AGP_GET_APERTURE(dev)) {
40859747216SDoug Rabson 		device_printf(dev, "binding memory at bad offset %#x\n",
40959747216SDoug Rabson 			      (int) offset);
41059747216SDoug Rabson 		return EINVAL;
41159747216SDoug Rabson 	}
41259747216SDoug Rabson 
41359747216SDoug Rabson 	/*
41459747216SDoug Rabson 	 * Bind the individual pages and flush the chipset's
41559747216SDoug Rabson 	 * TLB.
41659747216SDoug Rabson 	 *
41759747216SDoug Rabson 	 * XXX Presumably, this needs to be the pci address on alpha
41859747216SDoug Rabson 	 * (i.e. use alpha_XXX_dmamap()). I don't have access to any
41959747216SDoug Rabson 	 * alpha AGP hardware to check.
42059747216SDoug Rabson 	 */
42159747216SDoug Rabson 	for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
42259747216SDoug Rabson 		/*
42359747216SDoug Rabson 		 * Find a page from the object and wire it
42459747216SDoug Rabson 		 * down. This page will be mapped using one or more
42559747216SDoug Rabson 		 * entries in the GATT (assuming that PAGE_SIZE >=
42659747216SDoug Rabson 		 * AGP_PAGE_SIZE. If this is the first call to bind,
42759747216SDoug Rabson 		 * the pages will be allocated and zeroed.
42859747216SDoug Rabson 		 */
42959747216SDoug Rabson 		m = vm_page_grab(mem->am_obj, OFF_TO_IDX(i),
430fab965bfSAlan Cox 		    VM_ALLOC_WIRED | VM_ALLOC_ZERO | VM_ALLOC_RETRY);
4315ec699cdSAlan Cox 		if ((m->flags & PG_ZERO) == 0)
432fff6062aSAlan Cox 			pmap_zero_page(m);
43359747216SDoug Rabson 		AGP_DPF("found page pa=%#x\n", VM_PAGE_TO_PHYS(m));
43459747216SDoug Rabson 
43559747216SDoug Rabson 		/*
43659747216SDoug Rabson 		 * Install entries in the GATT, making sure that if
43759747216SDoug Rabson 		 * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not
43859747216SDoug Rabson 		 * aligned to PAGE_SIZE, we don't modify too many GATT
43959747216SDoug Rabson 		 * entries.
44059747216SDoug Rabson 		 */
44159747216SDoug Rabson 		for (j = 0; j < PAGE_SIZE && i + j < mem->am_size;
44259747216SDoug Rabson 		     j += AGP_PAGE_SIZE) {
44359747216SDoug Rabson 			vm_offset_t pa = VM_PAGE_TO_PHYS(m) + j;
44459747216SDoug Rabson 			AGP_DPF("binding offset %#x to pa %#x\n",
44559747216SDoug Rabson 				offset + i + j, pa);
44659747216SDoug Rabson 			error = AGP_BIND_PAGE(dev, offset + i + j, pa);
44759747216SDoug Rabson 			if (error) {
44859747216SDoug Rabson 				/*
44959747216SDoug Rabson 				 * Bail out. Reverse all the mappings
45059747216SDoug Rabson 				 * and unwire the pages.
45159747216SDoug Rabson 				 */
452e7863f18SAlan Cox 				vm_page_lock_queues();
45359747216SDoug Rabson 				vm_page_wakeup(m);
454e7863f18SAlan Cox 				vm_page_unlock_queues();
45559747216SDoug Rabson 				for (k = 0; k < i + j; k += AGP_PAGE_SIZE)
45659747216SDoug Rabson 					AGP_UNBIND_PAGE(dev, offset + k);
45759747216SDoug Rabson 				for (k = 0; k <= i; k += PAGE_SIZE) {
45859747216SDoug Rabson 					m = vm_page_lookup(mem->am_obj,
45959747216SDoug Rabson 							   OFF_TO_IDX(k));
4601f545269SAlan Cox 					vm_page_lock_queues();
46159747216SDoug Rabson 					vm_page_unwire(m, 0);
4621f545269SAlan Cox 					vm_page_unlock_queues();
46359747216SDoug Rabson 				}
464b40ce416SJulian Elischer 				lockmgr(&sc->as_lock, LK_RELEASE, 0, curthread);
46559747216SDoug Rabson 				return error;
46659747216SDoug Rabson 			}
46759747216SDoug Rabson 		}
468e7863f18SAlan Cox 		vm_page_lock_queues();
46959747216SDoug Rabson 		vm_page_wakeup(m);
470e7863f18SAlan Cox 		vm_page_unlock_queues();
47159747216SDoug Rabson 	}
47259747216SDoug Rabson 
47359747216SDoug Rabson 	/*
47459747216SDoug Rabson 	 * Flush the cpu cache since we are providing a new mapping
47559747216SDoug Rabson 	 * for these pages.
47659747216SDoug Rabson 	 */
47759747216SDoug Rabson 	agp_flush_cache();
47859747216SDoug Rabson 
47959747216SDoug Rabson 	/*
48059747216SDoug Rabson 	 * Make sure the chipset gets the new mappings.
48159747216SDoug Rabson 	 */
48259747216SDoug Rabson 	AGP_FLUSH_TLB(dev);
48359747216SDoug Rabson 
48459747216SDoug Rabson 	mem->am_offset = offset;
48559747216SDoug Rabson 	mem->am_is_bound = 1;
48659747216SDoug Rabson 
487b40ce416SJulian Elischer 	lockmgr(&sc->as_lock, LK_RELEASE, 0, curthread);
48859747216SDoug Rabson 
48959747216SDoug Rabson 	return 0;
49059747216SDoug Rabson }
49159747216SDoug Rabson 
49259747216SDoug Rabson int
49359747216SDoug Rabson agp_generic_unbind_memory(device_t dev, struct agp_memory *mem)
49459747216SDoug Rabson {
49559747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
49659747216SDoug Rabson 	vm_page_t m;
49759747216SDoug Rabson 	int i;
49859747216SDoug Rabson 
499b40ce416SJulian Elischer 	lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curthread);
50059747216SDoug Rabson 
50159747216SDoug Rabson 	if (!mem->am_is_bound) {
50259747216SDoug Rabson 		device_printf(dev, "memory is not bound\n");
50359747216SDoug Rabson 		return EINVAL;
50459747216SDoug Rabson 	}
50559747216SDoug Rabson 
50659747216SDoug Rabson 
50759747216SDoug Rabson 	/*
50859747216SDoug Rabson 	 * Unbind the individual pages and flush the chipset's
50959747216SDoug Rabson 	 * TLB. Unwire the pages so they can be swapped.
51059747216SDoug Rabson 	 */
51159747216SDoug Rabson 	for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
51259747216SDoug Rabson 		AGP_UNBIND_PAGE(dev, mem->am_offset + i);
51359747216SDoug Rabson 	for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
51459747216SDoug Rabson 		m = vm_page_lookup(mem->am_obj, atop(i));
5151f545269SAlan Cox 		vm_page_lock_queues();
51659747216SDoug Rabson 		vm_page_unwire(m, 0);
5171f545269SAlan Cox 		vm_page_unlock_queues();
51859747216SDoug Rabson 	}
51959747216SDoug Rabson 
52059747216SDoug Rabson 	agp_flush_cache();
52159747216SDoug Rabson 	AGP_FLUSH_TLB(dev);
52259747216SDoug Rabson 
52359747216SDoug Rabson 	mem->am_offset = 0;
52459747216SDoug Rabson 	mem->am_is_bound = 0;
52559747216SDoug Rabson 
526b40ce416SJulian Elischer 	lockmgr(&sc->as_lock, LK_RELEASE, 0, curthread);
52759747216SDoug Rabson 
52859747216SDoug Rabson 	return 0;
52959747216SDoug Rabson }
53059747216SDoug Rabson 
53159747216SDoug Rabson /* Helper functions for implementing user/kernel api */
53259747216SDoug Rabson 
53359747216SDoug Rabson static int
53459747216SDoug Rabson agp_acquire_helper(device_t dev, enum agp_acquire_state state)
53559747216SDoug Rabson {
53659747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
53759747216SDoug Rabson 
53859747216SDoug Rabson 	if (sc->as_state != AGP_ACQUIRE_FREE)
53959747216SDoug Rabson 		return EBUSY;
54059747216SDoug Rabson 	sc->as_state = state;
54159747216SDoug Rabson 
54259747216SDoug Rabson 	return 0;
54359747216SDoug Rabson }
54459747216SDoug Rabson 
54559747216SDoug Rabson static int
54659747216SDoug Rabson agp_release_helper(device_t dev, enum agp_acquire_state state)
54759747216SDoug Rabson {
54859747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
54959747216SDoug Rabson 
55059747216SDoug Rabson 	if (sc->as_state == AGP_ACQUIRE_FREE)
55159747216SDoug Rabson 		return 0;
55259747216SDoug Rabson 
55359747216SDoug Rabson 	if (sc->as_state != state)
55459747216SDoug Rabson 		return EBUSY;
55559747216SDoug Rabson 
55659747216SDoug Rabson 	sc->as_state = AGP_ACQUIRE_FREE;
55759747216SDoug Rabson 	return 0;
55859747216SDoug Rabson }
55959747216SDoug Rabson 
56059747216SDoug Rabson static struct agp_memory *
56159747216SDoug Rabson agp_find_memory(device_t dev, int id)
56259747216SDoug Rabson {
56359747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
56459747216SDoug Rabson 	struct agp_memory *mem;
56559747216SDoug Rabson 
56659747216SDoug Rabson 	AGP_DPF("searching for memory block %d\n", id);
56759747216SDoug Rabson 	TAILQ_FOREACH(mem, &sc->as_memory, am_link) {
56859747216SDoug Rabson 		AGP_DPF("considering memory block %d\n", mem->am_id);
56959747216SDoug Rabson 		if (mem->am_id == id)
57059747216SDoug Rabson 			return mem;
57159747216SDoug Rabson 	}
57259747216SDoug Rabson 	return 0;
57359747216SDoug Rabson }
57459747216SDoug Rabson 
57559747216SDoug Rabson /* Implementation of the userland ioctl api */
57659747216SDoug Rabson 
57759747216SDoug Rabson static int
57859747216SDoug Rabson agp_info_user(device_t dev, agp_info *info)
57959747216SDoug Rabson {
58059747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
58159747216SDoug Rabson 
58259747216SDoug Rabson 	bzero(info, sizeof *info);
58359747216SDoug Rabson 	info->bridge_id = pci_get_devid(dev);
58459747216SDoug Rabson 	info->agp_mode =
58559747216SDoug Rabson 	    pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
58659747216SDoug Rabson 	info->aper_base = rman_get_start(sc->as_aperture);
58759747216SDoug Rabson 	info->aper_size = AGP_GET_APERTURE(dev) >> 20;
58859747216SDoug Rabson 	info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT;
58959747216SDoug Rabson 	info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT;
59059747216SDoug Rabson 
59159747216SDoug Rabson 	return 0;
59259747216SDoug Rabson }
59359747216SDoug Rabson 
59459747216SDoug Rabson static int
59559747216SDoug Rabson agp_setup_user(device_t dev, agp_setup *setup)
59659747216SDoug Rabson {
59759747216SDoug Rabson 	return AGP_ENABLE(dev, setup->agp_mode);
59859747216SDoug Rabson }
59959747216SDoug Rabson 
60059747216SDoug Rabson static int
60159747216SDoug Rabson agp_allocate_user(device_t dev, agp_allocate *alloc)
60259747216SDoug Rabson {
60359747216SDoug Rabson 	struct agp_memory *mem;
60459747216SDoug Rabson 
60559747216SDoug Rabson 	mem = AGP_ALLOC_MEMORY(dev,
60659747216SDoug Rabson 			       alloc->type,
60759747216SDoug Rabson 			       alloc->pg_count << AGP_PAGE_SHIFT);
608e547d6fdSDoug Rabson 	if (mem) {
60959747216SDoug Rabson 		alloc->key = mem->am_id;
61059747216SDoug Rabson 		alloc->physical = mem->am_physical;
61159747216SDoug Rabson 		return 0;
612e547d6fdSDoug Rabson 	} else {
613e547d6fdSDoug Rabson 		return ENOMEM;
614e547d6fdSDoug Rabson 	}
61559747216SDoug Rabson }
61659747216SDoug Rabson 
61759747216SDoug Rabson static int
61859747216SDoug Rabson agp_deallocate_user(device_t dev, int id)
61959747216SDoug Rabson {
62059747216SDoug Rabson 	struct agp_memory *mem = agp_find_memory(dev, id);;
62159747216SDoug Rabson 
62259747216SDoug Rabson 	if (mem) {
62359747216SDoug Rabson 		AGP_FREE_MEMORY(dev, mem);
62459747216SDoug Rabson 		return 0;
62559747216SDoug Rabson 	} else {
62659747216SDoug Rabson 		return ENOENT;
62759747216SDoug Rabson 	}
62859747216SDoug Rabson }
62959747216SDoug Rabson 
63059747216SDoug Rabson static int
63159747216SDoug Rabson agp_bind_user(device_t dev, agp_bind *bind)
63259747216SDoug Rabson {
63359747216SDoug Rabson 	struct agp_memory *mem = agp_find_memory(dev, bind->key);
63459747216SDoug Rabson 
63559747216SDoug Rabson 	if (!mem)
63659747216SDoug Rabson 		return ENOENT;
63759747216SDoug Rabson 
63859747216SDoug Rabson 	return AGP_BIND_MEMORY(dev, mem, bind->pg_start << AGP_PAGE_SHIFT);
63959747216SDoug Rabson }
64059747216SDoug Rabson 
64159747216SDoug Rabson static int
64259747216SDoug Rabson agp_unbind_user(device_t dev, agp_unbind *unbind)
64359747216SDoug Rabson {
64459747216SDoug Rabson 	struct agp_memory *mem = agp_find_memory(dev, unbind->key);
64559747216SDoug Rabson 
64659747216SDoug Rabson 	if (!mem)
64759747216SDoug Rabson 		return ENOENT;
64859747216SDoug Rabson 
64959747216SDoug Rabson 	return AGP_UNBIND_MEMORY(dev, mem);
65059747216SDoug Rabson }
65159747216SDoug Rabson 
65259747216SDoug Rabson static int
653b40ce416SJulian Elischer agp_open(dev_t kdev, int oflags, int devtype, struct thread *td)
65459747216SDoug Rabson {
65559747216SDoug Rabson 	device_t dev = KDEV2DEV(kdev);
65659747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
65759747216SDoug Rabson 
65859747216SDoug Rabson 	if (!sc->as_isopen) {
65959747216SDoug Rabson 		sc->as_isopen = 1;
66059747216SDoug Rabson 		device_busy(dev);
66159747216SDoug Rabson 	}
66259747216SDoug Rabson 
66359747216SDoug Rabson 	return 0;
66459747216SDoug Rabson }
66559747216SDoug Rabson 
66659747216SDoug Rabson static int
667b40ce416SJulian Elischer agp_close(dev_t kdev, int fflag, int devtype, struct thread *td)
66859747216SDoug Rabson {
66959747216SDoug Rabson 	device_t dev = KDEV2DEV(kdev);
67059747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
6713e0cee70SRuslan Ermilov 	struct agp_memory *mem;
67259747216SDoug Rabson 
67359747216SDoug Rabson 	/*
67459747216SDoug Rabson 	 * Clear the GATT and force release on last close
67559747216SDoug Rabson 	 */
6763e0cee70SRuslan Ermilov 	while ((mem = TAILQ_FIRST(&sc->as_memory)) != 0) {
6773e0cee70SRuslan Ermilov 		if (mem->am_is_bound)
6783e0cee70SRuslan Ermilov 			AGP_UNBIND_MEMORY(dev, mem);
6793e0cee70SRuslan Ermilov 		AGP_FREE_MEMORY(dev, mem);
6803e0cee70SRuslan Ermilov 	}
68159747216SDoug Rabson 	if (sc->as_state == AGP_ACQUIRE_USER)
68259747216SDoug Rabson 		agp_release_helper(dev, AGP_ACQUIRE_USER);
68359747216SDoug Rabson 	sc->as_isopen = 0;
68459747216SDoug Rabson 	device_unbusy(dev);
68559747216SDoug Rabson 
68659747216SDoug Rabson 	return 0;
68759747216SDoug Rabson }
68859747216SDoug Rabson 
68959747216SDoug Rabson static int
690b40ce416SJulian Elischer agp_ioctl(dev_t kdev, u_long cmd, caddr_t data, int fflag, struct thread *td)
69159747216SDoug Rabson {
69259747216SDoug Rabson 	device_t dev = KDEV2DEV(kdev);
69359747216SDoug Rabson 
69459747216SDoug Rabson 	switch (cmd) {
69559747216SDoug Rabson 	case AGPIOC_INFO:
69659747216SDoug Rabson 		return agp_info_user(dev, (agp_info *) data);
69759747216SDoug Rabson 
69859747216SDoug Rabson 	case AGPIOC_ACQUIRE:
69959747216SDoug Rabson 		return agp_acquire_helper(dev, AGP_ACQUIRE_USER);
70059747216SDoug Rabson 
70159747216SDoug Rabson 	case AGPIOC_RELEASE:
70259747216SDoug Rabson 		return agp_release_helper(dev, AGP_ACQUIRE_USER);
70359747216SDoug Rabson 
70459747216SDoug Rabson 	case AGPIOC_SETUP:
70559747216SDoug Rabson 		return agp_setup_user(dev, (agp_setup *)data);
70659747216SDoug Rabson 
70759747216SDoug Rabson 	case AGPIOC_ALLOCATE:
70859747216SDoug Rabson 		return agp_allocate_user(dev, (agp_allocate *)data);
70959747216SDoug Rabson 
71059747216SDoug Rabson 	case AGPIOC_DEALLOCATE:
71159747216SDoug Rabson 		return agp_deallocate_user(dev, *(int *) data);
71259747216SDoug Rabson 
71359747216SDoug Rabson 	case AGPIOC_BIND:
71459747216SDoug Rabson 		return agp_bind_user(dev, (agp_bind *)data);
71559747216SDoug Rabson 
71659747216SDoug Rabson 	case AGPIOC_UNBIND:
71759747216SDoug Rabson 		return agp_unbind_user(dev, (agp_unbind *)data);
71859747216SDoug Rabson 
71959747216SDoug Rabson 	}
72059747216SDoug Rabson 
72159747216SDoug Rabson 	return EINVAL;
72259747216SDoug Rabson }
72359747216SDoug Rabson 
72459747216SDoug Rabson static int
72559747216SDoug Rabson agp_mmap(dev_t kdev, vm_offset_t offset, int prot)
72659747216SDoug Rabson {
72759747216SDoug Rabson 	device_t dev = KDEV2DEV(kdev);
72859747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
72959747216SDoug Rabson 
73059747216SDoug Rabson 	if (offset > AGP_GET_APERTURE(dev))
73159747216SDoug Rabson 		return -1;
73259747216SDoug Rabson 	return atop(rman_get_start(sc->as_aperture) + offset);
73359747216SDoug Rabson }
73459747216SDoug Rabson 
73559747216SDoug Rabson /* Implementation of the kernel api */
73659747216SDoug Rabson 
73759747216SDoug Rabson device_t
73859747216SDoug Rabson agp_find_device()
73959747216SDoug Rabson {
74059747216SDoug Rabson 	if (!agp_devclass)
74159747216SDoug Rabson 		return 0;
74259747216SDoug Rabson 	return devclass_get_device(agp_devclass, 0);
74359747216SDoug Rabson }
74459747216SDoug Rabson 
74559747216SDoug Rabson enum agp_acquire_state
74659747216SDoug Rabson agp_state(device_t dev)
74759747216SDoug Rabson {
74859747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
74959747216SDoug Rabson 	return sc->as_state;
75059747216SDoug Rabson }
75159747216SDoug Rabson 
75259747216SDoug Rabson void
75359747216SDoug Rabson agp_get_info(device_t dev, struct agp_info *info)
75459747216SDoug Rabson {
75559747216SDoug Rabson 	struct agp_softc *sc = device_get_softc(dev);
75659747216SDoug Rabson 
75759747216SDoug Rabson 	info->ai_mode =
75859747216SDoug Rabson 		pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
75959747216SDoug Rabson 	info->ai_aperture_base = rman_get_start(sc->as_aperture);
760df585170SPeter Wemm 	info->ai_aperture_size = rman_get_size(sc->as_aperture);
761fe707548SMatthew N. Dodd 	info->ai_aperture_va = (vm_offset_t) rman_get_virtual(sc->as_aperture);
76259747216SDoug Rabson 	info->ai_memory_allowed = sc->as_maxmem;
76359747216SDoug Rabson 	info->ai_memory_used = sc->as_allocated;
76459747216SDoug Rabson }
76559747216SDoug Rabson 
76659747216SDoug Rabson int
76759747216SDoug Rabson agp_acquire(device_t dev)
76859747216SDoug Rabson {
76959747216SDoug Rabson 	return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL);
77059747216SDoug Rabson }
77159747216SDoug Rabson 
77259747216SDoug Rabson int
77359747216SDoug Rabson agp_release(device_t dev)
77459747216SDoug Rabson {
77559747216SDoug Rabson 	return agp_release_helper(dev, AGP_ACQUIRE_KERNEL);
77659747216SDoug Rabson }
77759747216SDoug Rabson 
77859747216SDoug Rabson int
77959747216SDoug Rabson agp_enable(device_t dev, u_int32_t mode)
78059747216SDoug Rabson {
78159747216SDoug Rabson 	return AGP_ENABLE(dev, mode);
78259747216SDoug Rabson }
78359747216SDoug Rabson 
78459747216SDoug Rabson void *agp_alloc_memory(device_t dev, int type, vm_size_t bytes)
78559747216SDoug Rabson {
78659747216SDoug Rabson 	return  (void *) AGP_ALLOC_MEMORY(dev, type, bytes);
78759747216SDoug Rabson }
78859747216SDoug Rabson 
78959747216SDoug Rabson void agp_free_memory(device_t dev, void *handle)
79059747216SDoug Rabson {
79159747216SDoug Rabson 	struct agp_memory *mem = (struct agp_memory *) handle;
79259747216SDoug Rabson 	AGP_FREE_MEMORY(dev, mem);
79359747216SDoug Rabson }
79459747216SDoug Rabson 
79559747216SDoug Rabson int agp_bind_memory(device_t dev, void *handle, vm_offset_t offset)
79659747216SDoug Rabson {
79759747216SDoug Rabson 	struct agp_memory *mem = (struct agp_memory *) handle;
79859747216SDoug Rabson 	return AGP_BIND_MEMORY(dev, mem, offset);
79959747216SDoug Rabson }
80059747216SDoug Rabson 
80159747216SDoug Rabson int agp_unbind_memory(device_t dev, void *handle)
80259747216SDoug Rabson {
80359747216SDoug Rabson 	struct agp_memory *mem = (struct agp_memory *) handle;
80459747216SDoug Rabson 	return AGP_UNBIND_MEMORY(dev, mem);
80559747216SDoug Rabson }
80659747216SDoug Rabson 
80759747216SDoug Rabson void agp_memory_info(device_t dev, void *handle, struct
80859747216SDoug Rabson 		     agp_memory_info *mi)
80959747216SDoug Rabson {
81059747216SDoug Rabson 	struct agp_memory *mem = (struct agp_memory *) handle;
81159747216SDoug Rabson 
81259747216SDoug Rabson 	mi->ami_size = mem->am_size;
81359747216SDoug Rabson 	mi->ami_physical = mem->am_physical;
81459747216SDoug Rabson 	mi->ami_offset = mem->am_offset;
81559747216SDoug Rabson 	mi->ami_is_bound = mem->am_is_bound;
81659747216SDoug Rabson }
817