agp.c revision 238172
161452Sdfr/*-
261452Sdfr * Copyright (c) 2000 Doug Rabson
361452Sdfr * All rights reserved.
461452Sdfr *
561452Sdfr * Redistribution and use in source and binary forms, with or without
661452Sdfr * modification, are permitted provided that the following conditions
761452Sdfr * are met:
861452Sdfr * 1. Redistributions of source code must retain the above copyright
961452Sdfr *    notice, this list of conditions and the following disclaimer.
1061452Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1161452Sdfr *    notice, this list of conditions and the following disclaimer in the
1261452Sdfr *    documentation and/or other materials provided with the distribution.
1361452Sdfr *
1461452Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1561452Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1661452Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1761452Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1861452Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1961452Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2061452Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2161452Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2261452Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2361452Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2461452Sdfr * SUCH DAMAGE.
2561452Sdfr */
2661452Sdfr
27116192Sobrien#include <sys/cdefs.h>
28116192Sobrien__FBSDID("$FreeBSD: head/sys/dev/agp/agp.c 238172 2012-07-06 15:57:03Z marcel $");
29116192Sobrien
30188247Swkoszek#include "opt_agp.h"
3161452Sdfr#include "opt_bus.h"
3261452Sdfr
3361452Sdfr#include <sys/param.h>
3461452Sdfr#include <sys/systm.h>
3561452Sdfr#include <sys/malloc.h>
3661452Sdfr#include <sys/kernel.h>
37129878Sphk#include <sys/module.h>
3861452Sdfr#include <sys/bus.h>
3961452Sdfr#include <sys/conf.h>
4061452Sdfr#include <sys/ioccom.h>
4161452Sdfr#include <sys/agpio.h>
4261452Sdfr#include <sys/lock.h>
4376827Salfred#include <sys/mutex.h>
4469927Sjhb#include <sys/proc.h>
4561452Sdfr
46173573Sjhb#include <dev/agp/agppriv.h>
47173573Sjhb#include <dev/agp/agpvar.h>
48173573Sjhb#include <dev/agp/agpreg.h>
49119288Simp#include <dev/pci/pcivar.h>
50119288Simp#include <dev/pci/pcireg.h>
5161452Sdfr
5261452Sdfr#include <vm/vm.h>
5361452Sdfr#include <vm/vm_object.h>
5461452Sdfr#include <vm/vm_page.h>
5561452Sdfr#include <vm/vm_pageout.h>
5661452Sdfr#include <vm/pmap.h>
5761452Sdfr
5861452Sdfr#include <machine/bus.h>
5961452Sdfr#include <machine/resource.h>
6061452Sdfr#include <sys/rman.h>
6161452Sdfr
6261452SdfrMODULE_VERSION(agp, 1);
6361452Sdfr
6470185SassarMALLOC_DEFINE(M_AGP, "agp", "AGP data structures");
6561452Sdfr
6661452Sdfr				/* agp_drv.c */
6761452Sdfrstatic d_open_t agp_open;
6861452Sdfrstatic d_close_t agp_close;
6961452Sdfrstatic d_ioctl_t agp_ioctl;
7061452Sdfrstatic d_mmap_t agp_mmap;
7161452Sdfr
7261452Sdfrstatic struct cdevsw agp_cdevsw = {
73126080Sphk	.d_version =	D_VERSION,
74126080Sphk	.d_flags =	D_NEEDGIANT,
75111815Sphk	.d_open =	agp_open,
76111815Sphk	.d_close =	agp_close,
77111815Sphk	.d_ioctl =	agp_ioctl,
78111815Sphk	.d_mmap =	agp_mmap,
79111815Sphk	.d_name =	"agp",
8061452Sdfr};
8161452Sdfr
8261452Sdfrstatic devclass_t agp_devclass;
8361452Sdfr
8461452Sdfr/* Helper functions for implementing chipset mini drivers. */
8561452Sdfr
8661501Sdfrvoid
8761501Sdfragp_flush_cache()
8861501Sdfr{
89133852Sobrien#if defined(__i386__) || defined(__amd64__)
9061501Sdfr	wbinvd();
9161452Sdfr#endif
9261501Sdfr}
9361452Sdfr
9461452Sdfru_int8_t
9561452Sdfragp_find_caps(device_t dev)
9661452Sdfr{
97153561Sjhb	int capreg;
9861452Sdfr
9961452Sdfr
100219902Sjhb	if (pci_find_cap(dev, PCIY_AGP, &capreg) != 0)
101153561Sjhb		capreg = 0;
102153561Sjhb	return (capreg);
10361452Sdfr}
10461452Sdfr
10561452Sdfr/*
10661452Sdfr * Find an AGP display device (if any).
10761452Sdfr */
10861452Sdfrstatic device_t
10961452Sdfragp_find_display(void)
11061452Sdfr{
11161452Sdfr	devclass_t pci = devclass_find("pci");
11261452Sdfr	device_t bus, dev = 0;
11361452Sdfr	device_t *kids;
11461452Sdfr	int busnum, numkids, i;
11561452Sdfr
11661452Sdfr	for (busnum = 0; busnum < devclass_get_maxunit(pci); busnum++) {
11761452Sdfr		bus = devclass_get_device(pci, busnum);
11861452Sdfr		if (!bus)
11961452Sdfr			continue;
120182068Simp		if (device_get_children(bus, &kids, &numkids) != 0)
121182068Simp			continue;
12261452Sdfr		for (i = 0; i < numkids; i++) {
12361452Sdfr			dev = kids[i];
12461452Sdfr			if (pci_get_class(dev) == PCIC_DISPLAY
12561452Sdfr			    && pci_get_subclass(dev) == PCIS_DISPLAY_VGA)
12661452Sdfr				if (agp_find_caps(dev)) {
12761452Sdfr					free(kids, M_TEMP);
12861452Sdfr					return dev;
12961452Sdfr				}
13061452Sdfr
13161452Sdfr		}
13261452Sdfr		free(kids, M_TEMP);
13361452Sdfr	}
13461452Sdfr
13561452Sdfr	return 0;
13661452Sdfr}
13761452Sdfr
13861452Sdfrstruct agp_gatt *
13961452Sdfragp_alloc_gatt(device_t dev)
14061452Sdfr{
14161452Sdfr	u_int32_t apsize = AGP_GET_APERTURE(dev);
14261452Sdfr	u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
14361452Sdfr	struct agp_gatt *gatt;
14461452Sdfr
14561452Sdfr	if (bootverbose)
14661452Sdfr		device_printf(dev,
14761452Sdfr			      "allocating GATT for aperture of size %dM\n",
14861452Sdfr			      apsize / (1024*1024));
14961452Sdfr
150122513Sanholt	if (entries == 0) {
151122513Sanholt		device_printf(dev, "bad aperture size\n");
152122513Sanholt		return NULL;
153122513Sanholt	}
154122513Sanholt
15561452Sdfr	gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
15661452Sdfr	if (!gatt)
15761452Sdfr		return 0;
15861452Sdfr
15961452Sdfr	gatt->ag_entries = entries;
16061452Sdfr	gatt->ag_virtual = contigmalloc(entries * sizeof(u_int32_t), M_AGP, 0,
16161452Sdfr					0, ~0, PAGE_SIZE, 0);
16261452Sdfr	if (!gatt->ag_virtual) {
16361452Sdfr		if (bootverbose)
16461452Sdfr			device_printf(dev, "contiguous allocation failed\n");
16561452Sdfr		free(gatt, M_AGP);
16661452Sdfr		return 0;
16761452Sdfr	}
16861452Sdfr	bzero(gatt->ag_virtual, entries * sizeof(u_int32_t));
16961452Sdfr	gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
17061452Sdfr	agp_flush_cache();
17161452Sdfr
17261452Sdfr	return gatt;
17361452Sdfr}
17461452Sdfr
17561452Sdfrvoid
17661452Sdfragp_free_gatt(struct agp_gatt *gatt)
17761452Sdfr{
17861452Sdfr	contigfree(gatt->ag_virtual,
17961452Sdfr		   gatt->ag_entries * sizeof(u_int32_t), M_AGP);
18061452Sdfr	free(gatt, M_AGP);
18161452Sdfr}
18261452Sdfr
183163362Stanimurastatic u_int agp_max[][2] = {
18461452Sdfr	{0,	0},
18561452Sdfr	{32,	4},
18661452Sdfr	{64,	28},
18761452Sdfr	{128,	96},
18861452Sdfr	{256,	204},
18961452Sdfr	{512,	440},
19061452Sdfr	{1024,	942},
19161452Sdfr	{2048,	1920},
19261452Sdfr	{4096,	3932}
19361452Sdfr};
19461452Sdfr#define agp_max_size	(sizeof(agp_max) / sizeof(agp_max[0]))
19561452Sdfr
196171433Sanholt/**
197171433Sanholt * Sets the PCI resource which represents the AGP aperture.
198171433Sanholt *
199171433Sanholt * If not called, the default AGP aperture resource of AGP_APBASE will
200171433Sanholt * be used.  Must be called before agp_generic_attach().
201171433Sanholt */
202171433Sanholtvoid
203171433Sanholtagp_set_aperture_resource(device_t dev, int rid)
204171433Sanholt{
205171433Sanholt	struct agp_softc *sc = device_get_softc(dev);
206171433Sanholt
207171433Sanholt	sc->as_aperture_rid = rid;
208171433Sanholt}
209171433Sanholt
21061452Sdfrint
21161452Sdfragp_generic_attach(device_t dev)
21261452Sdfr{
21361452Sdfr	struct agp_softc *sc = device_get_softc(dev);
214171433Sanholt	int i;
215163362Stanimura	u_int memsize;
21661452Sdfr
21761452Sdfr	/*
218171433Sanholt	 * Find and map the aperture, RF_SHAREABLE for DRM but not RF_ACTIVE
219171433Sanholt	 * because the kernel doesn't need to map it.
22061452Sdfr	 */
221171433Sanholt
222214603Snwhitehorn	if (sc->as_aperture_rid != -1) {
223214603Snwhitehorn		if (sc->as_aperture_rid == 0)
224214603Snwhitehorn			sc->as_aperture_rid = AGP_APBASE;
22561452Sdfr
226214603Snwhitehorn		sc->as_aperture = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
227214603Snwhitehorn		    &sc->as_aperture_rid, RF_SHAREABLE);
228214603Snwhitehorn		if (!sc->as_aperture)
229214603Snwhitehorn			return ENOMEM;
230214603Snwhitehorn	}
231214603Snwhitehorn
23261452Sdfr	/*
23361452Sdfr	 * Work out an upper bound for agp memory allocation. This
23461452Sdfr	 * uses a heurisitc table from the Linux driver.
23561452Sdfr	 */
236238172Smarcel	memsize = ptoa(realmem) >> 20;
23761452Sdfr	for (i = 0; i < agp_max_size; i++) {
23861452Sdfr		if (memsize <= agp_max[i][0])
23961452Sdfr			break;
24061452Sdfr	}
241235782Skib	if (i == agp_max_size)
242235782Skib		i = agp_max_size - 1;
24361452Sdfr	sc->as_maxmem = agp_max[i][1] << 20U;
24461452Sdfr
24561452Sdfr	/*
24661452Sdfr	 * The lock is used to prevent re-entry to
24761452Sdfr	 * agp_generic_bind_memory() since that function can sleep.
24861452Sdfr	 */
249129579Smux	mtx_init(&sc->as_lock, "agp lock", NULL, MTX_DEF);
25061452Sdfr
25161452Sdfr	/*
25261452Sdfr	 * Initialise stuff for the userland device.
25361452Sdfr	 */
25461452Sdfr	agp_devclass = devclass_find("agp");
25561452Sdfr	TAILQ_INIT(&sc->as_memory);
25661452Sdfr	sc->as_nextid = 1;
25761452Sdfr
25861452Sdfr	sc->as_devnode = make_dev(&agp_cdevsw,
259191057Sed	    0, UID_ROOT, GID_WHEEL, 0600, "agpgart");
260191057Sed	sc->as_devnode->si_drv1 = dev;
26161452Sdfr
26261452Sdfr	return 0;
26361452Sdfr}
26461452Sdfr
265173203Sjhbvoid
266173203Sjhbagp_free_cdev(device_t dev)
26761452Sdfr{
26861452Sdfr	struct agp_softc *sc = device_get_softc(dev);
269153562Sjhb
270153562Sjhb	destroy_dev(sc->as_devnode);
271173203Sjhb}
272173203Sjhb
273173203Sjhbvoid
274173203Sjhbagp_free_res(device_t dev)
275173203Sjhb{
276173203Sjhb	struct agp_softc *sc = device_get_softc(dev);
277173203Sjhb
278214603Snwhitehorn	if (sc->as_aperture != NULL)
279214603Snwhitehorn		bus_release_resource(dev, SYS_RES_MEMORY, sc->as_aperture_rid,
280214603Snwhitehorn		    sc->as_aperture);
281129579Smux	mtx_destroy(&sc->as_lock);
28261452Sdfr	agp_flush_cache();
283173203Sjhb}
284173203Sjhb
285173203Sjhbint
286173203Sjhbagp_generic_detach(device_t dev)
287173203Sjhb{
288173203Sjhb
289173203Sjhb	agp_free_cdev(dev);
290173203Sjhb	agp_free_res(dev);
29161452Sdfr	return 0;
29261452Sdfr}
29361452Sdfr
294171433Sanholt/**
295171433Sanholt * Default AGP aperture size detection which simply returns the size of
296171433Sanholt * the aperture's PCI resource.
297171433Sanholt */
298189578Simpu_int32_t
299171433Sanholtagp_generic_get_aperture(device_t dev)
300171433Sanholt{
301171433Sanholt	struct agp_softc *sc = device_get_softc(dev);
302171433Sanholt
303171433Sanholt	return rman_get_size(sc->as_aperture);
304171433Sanholt}
305171433Sanholt
306171433Sanholt/**
307171433Sanholt * Default AGP aperture size setting function, which simply doesn't allow
308171433Sanholt * changes to resource size.
309171433Sanholt */
310171433Sanholtint
311171433Sanholtagp_generic_set_aperture(device_t dev, u_int32_t aperture)
312171433Sanholt{
313171433Sanholt	u_int32_t current_aperture;
314171433Sanholt
315171433Sanholt	current_aperture = AGP_GET_APERTURE(dev);
316171433Sanholt	if (current_aperture != aperture)
317171433Sanholt		return EINVAL;
318171433Sanholt	else
319171433Sanholt		return 0;
320171433Sanholt}
321171433Sanholt
322121440Sjhb/*
323121440Sjhb * This does the enable logic for v3, with the same topology
324121440Sjhb * restrictions as in place for v2 -- one bus, one device on the bus.
325121440Sjhb */
326121440Sjhbstatic int
327121440Sjhbagp_v3_enable(device_t dev, device_t mdev, u_int32_t mode)
32861452Sdfr{
32961452Sdfr	u_int32_t tstatus, mstatus;
33061452Sdfr	u_int32_t command;
331121440Sjhb	int rq, sba, fw, rate, arqsz, cal;
33261452Sdfr
333121440Sjhb	tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
334121440Sjhb	mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
33561452Sdfr
336121440Sjhb	/* Set RQ to the min of mode, tstatus and mstatus */
337121440Sjhb	rq = AGP_MODE_GET_RQ(mode);
338121440Sjhb	if (AGP_MODE_GET_RQ(tstatus) < rq)
339121440Sjhb		rq = AGP_MODE_GET_RQ(tstatus);
340121440Sjhb	if (AGP_MODE_GET_RQ(mstatus) < rq)
341121440Sjhb		rq = AGP_MODE_GET_RQ(mstatus);
342121440Sjhb
343121440Sjhb	/*
344121440Sjhb	 * ARQSZ - Set the value to the maximum one.
345121440Sjhb	 * Don't allow the mode register to override values.
346121440Sjhb	 */
347121440Sjhb	arqsz = AGP_MODE_GET_ARQSZ(mode);
348121440Sjhb	if (AGP_MODE_GET_ARQSZ(tstatus) > rq)
349121440Sjhb		rq = AGP_MODE_GET_ARQSZ(tstatus);
350121440Sjhb	if (AGP_MODE_GET_ARQSZ(mstatus) > rq)
351121440Sjhb		rq = AGP_MODE_GET_ARQSZ(mstatus);
352121440Sjhb
353121440Sjhb	/* Calibration cycle - don't allow override by mode register */
354121440Sjhb	cal = AGP_MODE_GET_CAL(tstatus);
355121440Sjhb	if (AGP_MODE_GET_CAL(mstatus) < cal)
356121440Sjhb		cal = AGP_MODE_GET_CAL(mstatus);
357121440Sjhb
358121440Sjhb	/* SBA must be supported for AGP v3. */
359121440Sjhb	sba = 1;
360121440Sjhb
361121440Sjhb	/* Set FW if all three support it. */
362121440Sjhb	fw = (AGP_MODE_GET_FW(tstatus)
363121440Sjhb	       & AGP_MODE_GET_FW(mstatus)
364121440Sjhb	       & AGP_MODE_GET_FW(mode));
365121440Sjhb
366121440Sjhb	/* Figure out the max rate */
367121440Sjhb	rate = (AGP_MODE_GET_RATE(tstatus)
368121440Sjhb		& AGP_MODE_GET_RATE(mstatus)
369121440Sjhb		& AGP_MODE_GET_RATE(mode));
370121440Sjhb	if (rate & AGP_MODE_V3_RATE_8x)
371121440Sjhb		rate = AGP_MODE_V3_RATE_8x;
372121440Sjhb	else
373121440Sjhb		rate = AGP_MODE_V3_RATE_4x;
374121440Sjhb	if (bootverbose)
375121440Sjhb		device_printf(dev, "Setting AGP v3 mode %d\n", rate * 4);
376121440Sjhb
377121440Sjhb	pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, 0, 4);
378121440Sjhb
379121440Sjhb	/* Construct the new mode word and tell the hardware */
380161222Sjkim	command = 0;
381121440Sjhb	command = AGP_MODE_SET_RQ(0, rq);
382121440Sjhb	command = AGP_MODE_SET_ARQSZ(command, arqsz);
383121440Sjhb	command = AGP_MODE_SET_CAL(command, cal);
384121440Sjhb	command = AGP_MODE_SET_SBA(command, sba);
385121440Sjhb	command = AGP_MODE_SET_FW(command, fw);
386121440Sjhb	command = AGP_MODE_SET_RATE(command, rate);
387161222Sjkim	command = AGP_MODE_SET_MODE_3(command, 1);
388121440Sjhb	command = AGP_MODE_SET_AGP(command, 1);
389121440Sjhb	pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4);
390121440Sjhb	pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
391121440Sjhb
392121440Sjhb	return 0;
393121440Sjhb}
394121440Sjhb
395121440Sjhbstatic int
396121440Sjhbagp_v2_enable(device_t dev, device_t mdev, u_int32_t mode)
397121440Sjhb{
398121440Sjhb	u_int32_t tstatus, mstatus;
399121440Sjhb	u_int32_t command;
400121440Sjhb	int rq, sba, fw, rate;
401121440Sjhb
40261452Sdfr	tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
40361452Sdfr	mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
40461452Sdfr
40561452Sdfr	/* Set RQ to the min of mode, tstatus and mstatus */
40661452Sdfr	rq = AGP_MODE_GET_RQ(mode);
40761452Sdfr	if (AGP_MODE_GET_RQ(tstatus) < rq)
40861452Sdfr		rq = AGP_MODE_GET_RQ(tstatus);
40961452Sdfr	if (AGP_MODE_GET_RQ(mstatus) < rq)
41061452Sdfr		rq = AGP_MODE_GET_RQ(mstatus);
41161452Sdfr
41261452Sdfr	/* Set SBA if all three can deal with SBA */
41361452Sdfr	sba = (AGP_MODE_GET_SBA(tstatus)
41461452Sdfr	       & AGP_MODE_GET_SBA(mstatus)
41561452Sdfr	       & AGP_MODE_GET_SBA(mode));
41661452Sdfr
41761452Sdfr	/* Similar for FW */
41861452Sdfr	fw = (AGP_MODE_GET_FW(tstatus)
41961452Sdfr	       & AGP_MODE_GET_FW(mstatus)
42061452Sdfr	       & AGP_MODE_GET_FW(mode));
42161452Sdfr
42261452Sdfr	/* Figure out the max rate */
42361452Sdfr	rate = (AGP_MODE_GET_RATE(tstatus)
42461452Sdfr		& AGP_MODE_GET_RATE(mstatus)
42561452Sdfr		& AGP_MODE_GET_RATE(mode));
426121440Sjhb	if (rate & AGP_MODE_V2_RATE_4x)
427121440Sjhb		rate = AGP_MODE_V2_RATE_4x;
428121440Sjhb	else if (rate & AGP_MODE_V2_RATE_2x)
429121440Sjhb		rate = AGP_MODE_V2_RATE_2x;
43061452Sdfr	else
431121440Sjhb		rate = AGP_MODE_V2_RATE_1x;
432121440Sjhb	if (bootverbose)
433121440Sjhb		device_printf(dev, "Setting AGP v2 mode %d\n", rate);
43461452Sdfr
43561452Sdfr	/* Construct the new mode word and tell the hardware */
436161222Sjkim	command = 0;
43761452Sdfr	command = AGP_MODE_SET_RQ(0, rq);
43861452Sdfr	command = AGP_MODE_SET_SBA(command, sba);
43961452Sdfr	command = AGP_MODE_SET_FW(command, fw);
44061452Sdfr	command = AGP_MODE_SET_RATE(command, rate);
44161452Sdfr	command = AGP_MODE_SET_AGP(command, 1);
44261452Sdfr	pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4);
44361452Sdfr	pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
44461452Sdfr
44561452Sdfr	return 0;
44661452Sdfr}
44761452Sdfr
448121440Sjhbint
449121440Sjhbagp_generic_enable(device_t dev, u_int32_t mode)
450121440Sjhb{
451121440Sjhb	device_t mdev = agp_find_display();
452121440Sjhb	u_int32_t tstatus, mstatus;
453121440Sjhb
454121440Sjhb	if (!mdev) {
455121440Sjhb		AGP_DPF("can't find display\n");
456121440Sjhb		return ENXIO;
457121440Sjhb	}
458121440Sjhb
459121440Sjhb	tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
460121440Sjhb	mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
461121440Sjhb
462121440Sjhb	/*
463121440Sjhb	 * Check display and bridge for AGP v3 support.  AGP v3 allows
464121440Sjhb	 * more variety in topology than v2, e.g. multiple AGP devices
465121440Sjhb	 * attached to one bridge, or multiple AGP bridges in one
466121440Sjhb	 * system.  This doesn't attempt to address those situations,
467121440Sjhb	 * but should work fine for a classic single AGP slot system
468121440Sjhb	 * with AGP v3.
469121440Sjhb	 */
470161222Sjkim	if (AGP_MODE_GET_MODE_3(mode) &&
471161222Sjkim	    AGP_MODE_GET_MODE_3(tstatus) &&
472161222Sjkim	    AGP_MODE_GET_MODE_3(mstatus))
473121440Sjhb		return (agp_v3_enable(dev, mdev, mode));
474121440Sjhb	else
475121440Sjhb		return (agp_v2_enable(dev, mdev, mode));
476121440Sjhb}
477121440Sjhb
47861452Sdfrstruct agp_memory *
47961452Sdfragp_generic_alloc_memory(device_t dev, int type, vm_size_t size)
48061452Sdfr{
48161452Sdfr	struct agp_softc *sc = device_get_softc(dev);
48261452Sdfr	struct agp_memory *mem;
48361452Sdfr
48461452Sdfr	if ((size & (AGP_PAGE_SIZE - 1)) != 0)
48561452Sdfr		return 0;
48661452Sdfr
48761452Sdfr	if (sc->as_allocated + size > sc->as_maxmem)
48861452Sdfr		return 0;
48961452Sdfr
49063010Sdfr	if (type != 0) {
49163010Sdfr		printf("agp_generic_alloc_memory: unsupported type %d\n",
49263010Sdfr		       type);
49363010Sdfr		return 0;
49463010Sdfr	}
49563010Sdfr
496111119Simp	mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
49761452Sdfr	mem->am_id = sc->as_nextid++;
49861452Sdfr	mem->am_size = size;
49963010Sdfr	mem->am_type = 0;
50061452Sdfr	mem->am_obj = vm_object_allocate(OBJT_DEFAULT, atop(round_page(size)));
50161452Sdfr	mem->am_physical = 0;
50261452Sdfr	mem->am_offset = 0;
50361452Sdfr	mem->am_is_bound = 0;
50461452Sdfr	TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link);
50561452Sdfr	sc->as_allocated += size;
50661452Sdfr
50761452Sdfr	return mem;
50861452Sdfr}
50961452Sdfr
51061452Sdfrint
51161452Sdfragp_generic_free_memory(device_t dev, struct agp_memory *mem)
51261452Sdfr{
51361452Sdfr	struct agp_softc *sc = device_get_softc(dev);
51461452Sdfr
51561452Sdfr	if (mem->am_is_bound)
51661452Sdfr		return EBUSY;
51761452Sdfr
51861452Sdfr	sc->as_allocated -= mem->am_size;
51961452Sdfr	TAILQ_REMOVE(&sc->as_memory, mem, am_link);
52061452Sdfr	vm_object_deallocate(mem->am_obj);
52161452Sdfr	free(mem, M_AGP);
52261452Sdfr	return 0;
52361452Sdfr}
52461452Sdfr
52561452Sdfrint
52661452Sdfragp_generic_bind_memory(device_t dev, struct agp_memory *mem,
52761452Sdfr			vm_offset_t offset)
52861452Sdfr{
52961452Sdfr	struct agp_softc *sc = device_get_softc(dev);
53061452Sdfr	vm_offset_t i, j, k;
53161452Sdfr	vm_page_t m;
53261452Sdfr	int error;
53361452Sdfr
534129601Smux	/* Do some sanity checks first. */
535190169Srnoland	if ((offset & (AGP_PAGE_SIZE - 1)) != 0 ||
536129601Smux	    offset + mem->am_size > AGP_GET_APERTURE(dev)) {
53761452Sdfr		device_printf(dev, "binding memory at bad offset %#x\n",
538129601Smux		    (int)offset);
53961452Sdfr		return EINVAL;
54061452Sdfr	}
54161452Sdfr
54261452Sdfr	/*
543129601Smux	 * Allocate the pages early, before acquiring the lock,
544209793Skib	 * because vm_page_grab() may sleep and we can't hold a mutex
545209793Skib	 * while sleeping.
54661452Sdfr	 */
547136852Salc	VM_OBJECT_LOCK(mem->am_obj);
54861452Sdfr	for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
54961452Sdfr		/*
55061452Sdfr		 * Find a page from the object and wire it
55161452Sdfr		 * down. This page will be mapped using one or more
55261452Sdfr		 * entries in the GATT (assuming that PAGE_SIZE >=
55361452Sdfr		 * AGP_PAGE_SIZE. If this is the first call to bind,
55461452Sdfr		 * the pages will be allocated and zeroed.
55561452Sdfr		 */
55661452Sdfr		m = vm_page_grab(mem->am_obj, OFF_TO_IDX(i),
557101647Salc		    VM_ALLOC_WIRED | VM_ALLOC_ZERO | VM_ALLOC_RETRY);
558188247Swkoszek		AGP_DPF("found page pa=%#jx\n", (uintmax_t)VM_PAGE_TO_PHYS(m));
559129601Smux	}
560136852Salc	VM_OBJECT_UNLOCK(mem->am_obj);
56161452Sdfr
562129601Smux	mtx_lock(&sc->as_lock);
563129601Smux
564129601Smux	if (mem->am_is_bound) {
565129601Smux		device_printf(dev, "memory already bound\n");
566129601Smux		error = EINVAL;
567136852Salc		VM_OBJECT_LOCK(mem->am_obj);
568186433Skib		i = 0;
569129601Smux		goto bad;
570129601Smux	}
571129601Smux
572129601Smux	/*
573129601Smux	 * Bind the individual pages and flush the chipset's
574129601Smux	 * TLB.
575129601Smux	 */
576136852Salc	VM_OBJECT_LOCK(mem->am_obj);
577129601Smux	for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
578129601Smux		m = vm_page_lookup(mem->am_obj, OFF_TO_IDX(i));
579129601Smux
58061452Sdfr		/*
58161452Sdfr		 * Install entries in the GATT, making sure that if
58261452Sdfr		 * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not
58361452Sdfr		 * aligned to PAGE_SIZE, we don't modify too many GATT
58461452Sdfr		 * entries.
58561452Sdfr		 */
58661452Sdfr		for (j = 0; j < PAGE_SIZE && i + j < mem->am_size;
58761452Sdfr		     j += AGP_PAGE_SIZE) {
58861452Sdfr			vm_offset_t pa = VM_PAGE_TO_PHYS(m) + j;
589188247Swkoszek			AGP_DPF("binding offset %#jx to pa %#jx\n",
590188247Swkoszek				(uintmax_t)offset + i + j, (uintmax_t)pa);
59161452Sdfr			error = AGP_BIND_PAGE(dev, offset + i + j, pa);
59261452Sdfr			if (error) {
59361452Sdfr				/*
59461452Sdfr				 * Bail out. Reverse all the mappings
59561452Sdfr				 * and unwire the pages.
59661452Sdfr				 */
59761452Sdfr				for (k = 0; k < i + j; k += AGP_PAGE_SIZE)
59861452Sdfr					AGP_UNBIND_PAGE(dev, offset + k);
599129601Smux				goto bad;
60061452Sdfr			}
60161452Sdfr		}
60261452Sdfr		vm_page_wakeup(m);
60361452Sdfr	}
604136852Salc	VM_OBJECT_UNLOCK(mem->am_obj);
60561452Sdfr
60661452Sdfr	/*
60761452Sdfr	 * Flush the cpu cache since we are providing a new mapping
60861452Sdfr	 * for these pages.
60961452Sdfr	 */
61061452Sdfr	agp_flush_cache();
61161452Sdfr
61261452Sdfr	/*
61361452Sdfr	 * Make sure the chipset gets the new mappings.
61461452Sdfr	 */
61561452Sdfr	AGP_FLUSH_TLB(dev);
61661452Sdfr
61761452Sdfr	mem->am_offset = offset;
61861452Sdfr	mem->am_is_bound = 1;
61961452Sdfr
620129579Smux	mtx_unlock(&sc->as_lock);
62161452Sdfr
62261452Sdfr	return 0;
623129601Smuxbad:
624129601Smux	mtx_unlock(&sc->as_lock);
625136852Salc	VM_OBJECT_LOCK_ASSERT(mem->am_obj, MA_OWNED);
626186433Skib	for (k = 0; k < mem->am_size; k += PAGE_SIZE) {
627186433Skib		m = vm_page_lookup(mem->am_obj, OFF_TO_IDX(k));
628186433Skib		if (k >= i)
629186433Skib			vm_page_wakeup(m);
630207574Salc		vm_page_lock(m);
631129601Smux		vm_page_unwire(m, 0);
632207574Salc		vm_page_unlock(m);
633129601Smux	}
634129601Smux	VM_OBJECT_UNLOCK(mem->am_obj);
635129601Smux
636129601Smux	return error;
63761452Sdfr}
63861452Sdfr
63961452Sdfrint
64061452Sdfragp_generic_unbind_memory(device_t dev, struct agp_memory *mem)
64161452Sdfr{
64261452Sdfr	struct agp_softc *sc = device_get_softc(dev);
64361452Sdfr	vm_page_t m;
64461452Sdfr	int i;
64561452Sdfr
646129579Smux	mtx_lock(&sc->as_lock);
64761452Sdfr
64861452Sdfr	if (!mem->am_is_bound) {
64961452Sdfr		device_printf(dev, "memory is not bound\n");
650129579Smux		mtx_unlock(&sc->as_lock);
65161452Sdfr		return EINVAL;
65261452Sdfr	}
65361452Sdfr
65461452Sdfr
65561452Sdfr	/*
65661452Sdfr	 * Unbind the individual pages and flush the chipset's
65761452Sdfr	 * TLB. Unwire the pages so they can be swapped.
65861452Sdfr	 */
65961452Sdfr	for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
66061452Sdfr		AGP_UNBIND_PAGE(dev, mem->am_offset + i);
661116555Salc	VM_OBJECT_LOCK(mem->am_obj);
66261452Sdfr	for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
66361452Sdfr		m = vm_page_lookup(mem->am_obj, atop(i));
664207574Salc		vm_page_lock(m);
66561452Sdfr		vm_page_unwire(m, 0);
666207574Salc		vm_page_unlock(m);
66761452Sdfr	}
668116555Salc	VM_OBJECT_UNLOCK(mem->am_obj);
66961452Sdfr
67061452Sdfr	agp_flush_cache();
67161452Sdfr	AGP_FLUSH_TLB(dev);
67261452Sdfr
67361452Sdfr	mem->am_offset = 0;
67461452Sdfr	mem->am_is_bound = 0;
67561452Sdfr
676129579Smux	mtx_unlock(&sc->as_lock);
67761452Sdfr
67861452Sdfr	return 0;
67961452Sdfr}
68061452Sdfr
68161452Sdfr/* Helper functions for implementing user/kernel api */
68261452Sdfr
68361452Sdfrstatic int
68461452Sdfragp_acquire_helper(device_t dev, enum agp_acquire_state state)
68561452Sdfr{
68661452Sdfr	struct agp_softc *sc = device_get_softc(dev);
68761452Sdfr
68861452Sdfr	if (sc->as_state != AGP_ACQUIRE_FREE)
68961452Sdfr		return EBUSY;
69061452Sdfr	sc->as_state = state;
69161452Sdfr
69261452Sdfr	return 0;
69361452Sdfr}
69461452Sdfr
69561452Sdfrstatic int
69661452Sdfragp_release_helper(device_t dev, enum agp_acquire_state state)
69761452Sdfr{
69861452Sdfr	struct agp_softc *sc = device_get_softc(dev);
69961452Sdfr
70061452Sdfr	if (sc->as_state == AGP_ACQUIRE_FREE)
70161452Sdfr		return 0;
70261452Sdfr
70361452Sdfr	if (sc->as_state != state)
70461452Sdfr		return EBUSY;
70561452Sdfr
70661452Sdfr	sc->as_state = AGP_ACQUIRE_FREE;
70761452Sdfr	return 0;
70861452Sdfr}
70961452Sdfr
71061452Sdfrstatic struct agp_memory *
71161452Sdfragp_find_memory(device_t dev, int id)
71261452Sdfr{
71361452Sdfr	struct agp_softc *sc = device_get_softc(dev);
71461452Sdfr	struct agp_memory *mem;
71561452Sdfr
71661452Sdfr	AGP_DPF("searching for memory block %d\n", id);
71761452Sdfr	TAILQ_FOREACH(mem, &sc->as_memory, am_link) {
71861452Sdfr		AGP_DPF("considering memory block %d\n", mem->am_id);
71961452Sdfr		if (mem->am_id == id)
72061452Sdfr			return mem;
72161452Sdfr	}
72261452Sdfr	return 0;
72361452Sdfr}
72461452Sdfr
72561452Sdfr/* Implementation of the userland ioctl api */
72661452Sdfr
72761452Sdfrstatic int
72861452Sdfragp_info_user(device_t dev, agp_info *info)
72961452Sdfr{
73061452Sdfr	struct agp_softc *sc = device_get_softc(dev);
73161452Sdfr
73261452Sdfr	bzero(info, sizeof *info);
73361452Sdfr	info->bridge_id = pci_get_devid(dev);
73461452Sdfr	info->agp_mode =
73561452Sdfr	    pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
736214603Snwhitehorn	if (sc->as_aperture)
737214603Snwhitehorn		info->aper_base = rman_get_start(sc->as_aperture);
738214603Snwhitehorn	else
739214603Snwhitehorn		info->aper_base = 0;
74061452Sdfr	info->aper_size = AGP_GET_APERTURE(dev) >> 20;
74161452Sdfr	info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT;
74261452Sdfr	info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT;
74361452Sdfr
74461452Sdfr	return 0;
74561452Sdfr}
74661452Sdfr
74761452Sdfrstatic int
74861452Sdfragp_setup_user(device_t dev, agp_setup *setup)
74961452Sdfr{
75061452Sdfr	return AGP_ENABLE(dev, setup->agp_mode);
75161452Sdfr}
75261452Sdfr
75361452Sdfrstatic int
75461452Sdfragp_allocate_user(device_t dev, agp_allocate *alloc)
75561452Sdfr{
75661452Sdfr	struct agp_memory *mem;
75761452Sdfr
75861452Sdfr	mem = AGP_ALLOC_MEMORY(dev,
75961452Sdfr			       alloc->type,
76061452Sdfr			       alloc->pg_count << AGP_PAGE_SHIFT);
76163010Sdfr	if (mem) {
76263010Sdfr		alloc->key = mem->am_id;
76363010Sdfr		alloc->physical = mem->am_physical;
76463010Sdfr		return 0;
76563010Sdfr	} else {
76663010Sdfr		return ENOMEM;
76763010Sdfr	}
76861452Sdfr}
76961452Sdfr
77061452Sdfrstatic int
77161452Sdfragp_deallocate_user(device_t dev, int id)
77261452Sdfr{
773201758Smbr	struct agp_memory *mem = agp_find_memory(dev, id);
77461452Sdfr
77561452Sdfr	if (mem) {
77661452Sdfr		AGP_FREE_MEMORY(dev, mem);
77761452Sdfr		return 0;
77861452Sdfr	} else {
77961452Sdfr		return ENOENT;
78061452Sdfr	}
78161452Sdfr}
78261452Sdfr
78361452Sdfrstatic int
78461452Sdfragp_bind_user(device_t dev, agp_bind *bind)
78561452Sdfr{
78661452Sdfr	struct agp_memory *mem = agp_find_memory(dev, bind->key);
78761452Sdfr
78861452Sdfr	if (!mem)
78961452Sdfr		return ENOENT;
79061452Sdfr
79161452Sdfr	return AGP_BIND_MEMORY(dev, mem, bind->pg_start << AGP_PAGE_SHIFT);
79261452Sdfr}
79361452Sdfr
79461452Sdfrstatic int
79561452Sdfragp_unbind_user(device_t dev, agp_unbind *unbind)
79661452Sdfr{
79761452Sdfr	struct agp_memory *mem = agp_find_memory(dev, unbind->key);
79861452Sdfr
79961452Sdfr	if (!mem)
80061452Sdfr		return ENOENT;
80161452Sdfr
80261452Sdfr	return AGP_UNBIND_MEMORY(dev, mem);
80361452Sdfr}
80461452Sdfr
80561452Sdfrstatic int
806235782Skibagp_chipset_flush(device_t dev)
807235782Skib{
808235782Skib
809235782Skib	return (AGP_CHIPSET_FLUSH(dev));
810235782Skib}
811235782Skib
812235782Skibstatic int
813130585Sphkagp_open(struct cdev *kdev, int oflags, int devtype, struct thread *td)
81461452Sdfr{
815191057Sed	device_t dev = kdev->si_drv1;
81661452Sdfr	struct agp_softc *sc = device_get_softc(dev);
81761452Sdfr
81861452Sdfr	if (!sc->as_isopen) {
81961452Sdfr		sc->as_isopen = 1;
82061452Sdfr		device_busy(dev);
82161452Sdfr	}
82261452Sdfr
82361452Sdfr	return 0;
82461452Sdfr}
82561452Sdfr
82661452Sdfrstatic int
827130585Sphkagp_close(struct cdev *kdev, int fflag, int devtype, struct thread *td)
82861452Sdfr{
829191057Sed	device_t dev = kdev->si_drv1;
83061452Sdfr	struct agp_softc *sc = device_get_softc(dev);
83186976Sru	struct agp_memory *mem;
83261452Sdfr
83361452Sdfr	/*
83461452Sdfr	 * Clear the GATT and force release on last close
83561452Sdfr	 */
83686976Sru	while ((mem = TAILQ_FIRST(&sc->as_memory)) != 0) {
83786976Sru		if (mem->am_is_bound)
83886976Sru			AGP_UNBIND_MEMORY(dev, mem);
83986976Sru		AGP_FREE_MEMORY(dev, mem);
84086976Sru	}
84161452Sdfr	if (sc->as_state == AGP_ACQUIRE_USER)
84261452Sdfr		agp_release_helper(dev, AGP_ACQUIRE_USER);
84361452Sdfr	sc->as_isopen = 0;
84461452Sdfr	device_unbusy(dev);
84561452Sdfr
84661452Sdfr	return 0;
84761452Sdfr}
84861452Sdfr
84961452Sdfrstatic int
850130585Sphkagp_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int fflag, struct thread *td)
85161452Sdfr{
852191057Sed	device_t dev = kdev->si_drv1;
85361452Sdfr
85461452Sdfr	switch (cmd) {
85561452Sdfr	case AGPIOC_INFO:
85661452Sdfr		return agp_info_user(dev, (agp_info *) data);
85761452Sdfr
85861452Sdfr	case AGPIOC_ACQUIRE:
85961452Sdfr		return agp_acquire_helper(dev, AGP_ACQUIRE_USER);
86061452Sdfr
86161452Sdfr	case AGPIOC_RELEASE:
86261452Sdfr		return agp_release_helper(dev, AGP_ACQUIRE_USER);
86361452Sdfr
86461452Sdfr	case AGPIOC_SETUP:
86561452Sdfr		return agp_setup_user(dev, (agp_setup *)data);
86661452Sdfr
86761452Sdfr	case AGPIOC_ALLOCATE:
86861452Sdfr		return agp_allocate_user(dev, (agp_allocate *)data);
86961452Sdfr
87061452Sdfr	case AGPIOC_DEALLOCATE:
87161452Sdfr		return agp_deallocate_user(dev, *(int *) data);
87261452Sdfr
87361452Sdfr	case AGPIOC_BIND:
87461452Sdfr		return agp_bind_user(dev, (agp_bind *)data);
87561452Sdfr
87661452Sdfr	case AGPIOC_UNBIND:
87761452Sdfr		return agp_unbind_user(dev, (agp_unbind *)data);
87861452Sdfr
879235782Skib	case AGPIOC_CHIPSET_FLUSH:
880235782Skib		return agp_chipset_flush(dev);
88161452Sdfr	}
88261452Sdfr
88361452Sdfr	return EINVAL;
88461452Sdfr}
88561452Sdfr
88661452Sdfrstatic int
887201223Srnolandagp_mmap(struct cdev *kdev, vm_ooffset_t offset, vm_paddr_t *paddr,
888201223Srnoland    int prot, vm_memattr_t *memattr)
88961452Sdfr{
890191057Sed	device_t dev = kdev->si_drv1;
89161452Sdfr	struct agp_softc *sc = device_get_softc(dev);
89261452Sdfr
89361452Sdfr	if (offset > AGP_GET_APERTURE(dev))
89461452Sdfr		return -1;
895214603Snwhitehorn	if (sc->as_aperture == NULL)
896214603Snwhitehorn		return -1;
897111462Smux	*paddr = rman_get_start(sc->as_aperture) + offset;
898111462Smux	return 0;
89961452Sdfr}
90061452Sdfr
90161452Sdfr/* Implementation of the kernel api */
90261452Sdfr
90361452Sdfrdevice_t
90461452Sdfragp_find_device()
90561452Sdfr{
906154486Sjhb	device_t *children, child;
907153568Sjhb	int i, count;
908153568Sjhb
90961452Sdfr	if (!agp_devclass)
910153568Sjhb		return NULL;
911153568Sjhb	if (devclass_get_devices(agp_devclass, &children, &count) != 0)
912153568Sjhb		return NULL;
913154486Sjhb	child = NULL;
914153568Sjhb	for (i = 0; i < count; i++) {
915154486Sjhb		if (device_is_attached(children[i])) {
916154486Sjhb			child = children[i];
917154486Sjhb			break;
918154486Sjhb		}
919153568Sjhb	}
920154486Sjhb	free(children, M_TEMP);
921154486Sjhb	return child;
92261452Sdfr}
92361452Sdfr
92461452Sdfrenum agp_acquire_state
92561452Sdfragp_state(device_t dev)
92661452Sdfr{
92761452Sdfr	struct agp_softc *sc = device_get_softc(dev);
92861452Sdfr	return sc->as_state;
92961452Sdfr}
93061452Sdfr
93161452Sdfrvoid
93261452Sdfragp_get_info(device_t dev, struct agp_info *info)
93361452Sdfr{
93461452Sdfr	struct agp_softc *sc = device_get_softc(dev);
93561452Sdfr
93661452Sdfr	info->ai_mode =
93761452Sdfr		pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
938214603Snwhitehorn	if (sc->as_aperture != NULL)
939214603Snwhitehorn		info->ai_aperture_base = rman_get_start(sc->as_aperture);
940214603Snwhitehorn	else
941214603Snwhitehorn		info->ai_aperture_base = 0;
942214603Snwhitehorn	info->ai_aperture_size = AGP_GET_APERTURE(dev);
94361452Sdfr	info->ai_memory_allowed = sc->as_maxmem;
94461452Sdfr	info->ai_memory_used = sc->as_allocated;
94561452Sdfr}
94661452Sdfr
94761452Sdfrint
94861452Sdfragp_acquire(device_t dev)
94961452Sdfr{
95061452Sdfr	return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL);
95161452Sdfr}
95261452Sdfr
95361452Sdfrint
95461452Sdfragp_release(device_t dev)
95561452Sdfr{
95661452Sdfr	return agp_release_helper(dev, AGP_ACQUIRE_KERNEL);
95761452Sdfr}
95861452Sdfr
95961452Sdfrint
96061452Sdfragp_enable(device_t dev, u_int32_t mode)
96161452Sdfr{
96261452Sdfr	return AGP_ENABLE(dev, mode);
96361452Sdfr}
96461452Sdfr
96561452Sdfrvoid *agp_alloc_memory(device_t dev, int type, vm_size_t bytes)
96661452Sdfr{
96761452Sdfr	return  (void *) AGP_ALLOC_MEMORY(dev, type, bytes);
96861452Sdfr}
96961452Sdfr
97061452Sdfrvoid agp_free_memory(device_t dev, void *handle)
97161452Sdfr{
97261452Sdfr	struct agp_memory *mem = (struct agp_memory *) handle;
97361452Sdfr	AGP_FREE_MEMORY(dev, mem);
97461452Sdfr}
97561452Sdfr
97661452Sdfrint agp_bind_memory(device_t dev, void *handle, vm_offset_t offset)
97761452Sdfr{
97861452Sdfr	struct agp_memory *mem = (struct agp_memory *) handle;
97961452Sdfr	return AGP_BIND_MEMORY(dev, mem, offset);
98061452Sdfr}
98161452Sdfr
98261452Sdfrint agp_unbind_memory(device_t dev, void *handle)
98361452Sdfr{
98461452Sdfr	struct agp_memory *mem = (struct agp_memory *) handle;
98561452Sdfr	return AGP_UNBIND_MEMORY(dev, mem);
98661452Sdfr}
98761452Sdfr
98861452Sdfrvoid agp_memory_info(device_t dev, void *handle, struct
98961452Sdfr		     agp_memory_info *mi)
99061452Sdfr{
99161452Sdfr	struct agp_memory *mem = (struct agp_memory *) handle;
99261452Sdfr
99361452Sdfr	mi->ami_size = mem->am_size;
99461452Sdfr	mi->ami_physical = mem->am_physical;
99561452Sdfr	mi->ami_offset = mem->am_offset;
99661452Sdfr	mi->ami_is_bound = mem->am_is_bound;
99761452Sdfr}
998