xref: /openbsd/sys/dev/pci/agp.c (revision 371e2336)
1*371e2336Sjsg /* $OpenBSD: agp.c,v 1.41 2014/03/17 04:10:59 jsg Exp $ */
20139788eSmatthieu /*-
30139788eSmatthieu  * Copyright (c) 2000 Doug Rabson
40139788eSmatthieu  * All rights reserved.
50139788eSmatthieu  *
60139788eSmatthieu  * Redistribution and use in source and binary forms, with or without
70139788eSmatthieu  * modification, are permitted provided that the following conditions
80139788eSmatthieu  * are met:
90139788eSmatthieu  * 1. Redistributions of source code must retain the above copyright
100139788eSmatthieu  *    notice, this list of conditions and the following disclaimer.
110139788eSmatthieu  * 2. Redistributions in binary form must reproduce the above copyright
120139788eSmatthieu  *    notice, this list of conditions and the following disclaimer in the
130139788eSmatthieu  *    documentation and/or other materials provided with the distribution.
140139788eSmatthieu  *
150139788eSmatthieu  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
160139788eSmatthieu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
170139788eSmatthieu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
180139788eSmatthieu  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
190139788eSmatthieu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
200139788eSmatthieu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
210139788eSmatthieu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
220139788eSmatthieu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
230139788eSmatthieu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
240139788eSmatthieu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
250139788eSmatthieu  * SUCH DAMAGE.
260139788eSmatthieu  *
270139788eSmatthieu  *	$FreeBSD: src/sys/pci/agp.c,v 1.12 2001/05/19 01:28:07 alfred Exp $
280139788eSmatthieu  */
290139788eSmatthieu 
300139788eSmatthieu #include <sys/param.h>
310139788eSmatthieu #include <sys/malloc.h>
320139788eSmatthieu #include <sys/agpio.h>
330139788eSmatthieu #include <sys/fcntl.h>
340139788eSmatthieu #include <sys/ioctl.h>
350139788eSmatthieu 
360139788eSmatthieu #include <uvm/uvm.h>
370139788eSmatthieu 
380139788eSmatthieu #include <dev/pci/pcivar.h>
3940d7c10bSoga #include <dev/pci/pcidevs.h>
400139788eSmatthieu 
410139788eSmatthieu #include <dev/ic/mc6845reg.h>
420139788eSmatthieu #include <dev/ic/pcdisplayvar.h>
430139788eSmatthieu #include <dev/ic/vgareg.h>
440139788eSmatthieu #include <dev/ic/vgavar.h>
450139788eSmatthieu 
460139788eSmatthieu #include <dev/pci/agpvar.h>
470139788eSmatthieu #include <dev/pci/agpreg.h>
480139788eSmatthieu 
498f6e6e82Soga /*
508f6e6e82Soga  * the enable and {alloc, free, bind, unbind} memory routines have default
518f6e6e82Soga  * fallbacks, these macros do the right thing. The callbacks with no fallback
528f6e6e82Soga  * are called directly. These are mostly hacks around the weirdness of intel
538f6e6e82Soga  * integrated graphics, since they are not technically a true agp chipset,
548f6e6e82Soga  * but provide an almost identical interface.
558f6e6e82Soga  */
568f6e6e82Soga int	agp_generic_enable(struct agp_softc *, u_int32_t);
578f6e6e82Soga struct agp_memory *
588f6e6e82Soga 	agp_generic_alloc_memory(struct agp_softc *, int, vsize_t size);
598f6e6e82Soga int	agp_generic_free_memory(struct agp_softc *, struct agp_memory *);
608f6e6e82Soga void	agp_attach(struct device *, struct device *, void *);
618f6e6e82Soga int	agp_probe(struct device *, void *, void *);
620139788eSmatthieu 
634ad474a9Smpi struct agp_memory *agp_find_memory(struct agp_softc *, int);
644ad474a9Smpi struct agp_memory *agp_lookup_memory(struct agp_softc *, off_t);
654ad474a9Smpi 
668f6e6e82Soga int	agpvga_match(struct pci_attach_args *);
6770456743Soga int	agp_acquire_helper(void *dev, enum agp_acquire_state state);
6870456743Soga int	agp_release_helper(void *dev, enum agp_acquire_state state);
6940d7c10bSoga 
708f6e6e82Soga int
718f6e6e82Soga agpdev_print(void *aux, const char *pnp)
728f6e6e82Soga {
738f6e6e82Soga 	if (pnp) {
748f6e6e82Soga 		printf("agp at %s", pnp);
758f6e6e82Soga 	}
768f6e6e82Soga 	return (UNCONF);
778f6e6e82Soga }
7840d7c10bSoga 
798f6e6e82Soga int
808f6e6e82Soga agpbus_probe(struct agp_attach_args *aa)
818f6e6e82Soga {
828f6e6e82Soga 	struct pci_attach_args	*pa = aa->aa_pa;
838f6e6e82Soga 
848f6e6e82Soga 	if (strncmp(aa->aa_busname, "agp", 3) == 0 &&
858f6e6e82Soga 	    PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
868f6e6e82Soga 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
878f6e6e82Soga 		return (1);
888f6e6e82Soga 	return (0);
898f6e6e82Soga }
908f6e6e82Soga 
918f6e6e82Soga /*
928f6e6e82Soga  * Find the video card hanging off the agp bus XXX assumes only one bus
938f6e6e82Soga  */
948f6e6e82Soga int
958f6e6e82Soga agpvga_match(struct pci_attach_args *pa)
968f6e6e82Soga {
978f6e6e82Soga 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY &&
988f6e6e82Soga 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_DISPLAY_VGA) {
998f6e6e82Soga 		if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
1008f6e6e82Soga 		    NULL, NULL))
1018f6e6e82Soga 			return (1);
1028f6e6e82Soga 	}
1038f6e6e82Soga 	return (0);
1048f6e6e82Soga }
1058f6e6e82Soga 
1068f6e6e82Soga struct device *
1078f6e6e82Soga agp_attach_bus(struct pci_attach_args *pa, const struct agp_methods *methods,
108b113917fSoga     bus_addr_t apaddr, bus_size_t apsize, struct device *dev)
1098f6e6e82Soga {
1108f6e6e82Soga 	struct agpbus_attach_args arg;
1118f6e6e82Soga 
1128f6e6e82Soga 	arg.aa_methods = methods;
1138f6e6e82Soga 	arg.aa_pa = pa;
114d8cdf4a2Soga 	arg.aa_apaddr = apaddr;
115b113917fSoga 	arg.aa_apsize = apsize;
1168f6e6e82Soga 
1178f6e6e82Soga 	printf("\n"); /* newline from the driver that called us */
1188f6e6e82Soga 	return (config_found(dev, &arg, agpdev_print));
1198f6e6e82Soga }
12040d7c10bSoga 
12170456743Soga int
12240d7c10bSoga agp_probe(struct device *parent, void *match, void *aux)
12340d7c10bSoga {
1248f6e6e82Soga 	/*
1258f6e6e82Soga 	 * we don't do any checking here, driver we're attaching this
1268f6e6e82Soga 	 * interface to should have already done it.
1278f6e6e82Soga 	 */
12840d7c10bSoga 	return (1);
12940d7c10bSoga }
1300139788eSmatthieu 
1310139788eSmatthieu void
1320139788eSmatthieu agp_attach(struct device *parent, struct device *self, void *aux)
1330139788eSmatthieu {
1348f6e6e82Soga 	struct agpbus_attach_args *aa = aux;
1358f6e6e82Soga 	struct pci_attach_args *pa = aa->aa_pa;
13640d7c10bSoga 	struct agp_softc *sc = (struct agp_softc *)self;
1370139788eSmatthieu 	u_int memsize;
1388f6e6e82Soga 	int i;
1390139788eSmatthieu 
1408f6e6e82Soga 	sc->sc_chipc = parent;
1418f6e6e82Soga 	sc->sc_methods = aa->aa_methods;
142d8cdf4a2Soga 	sc->sc_apaddr = aa->aa_apaddr;
143b113917fSoga 	sc->sc_apsize = aa->aa_apsize;
1448f6e6e82Soga 
1450139788eSmatthieu 	static const int agp_max[][2] = {
1460139788eSmatthieu 		{0,		0},
1470139788eSmatthieu 		{32,		4},
1480139788eSmatthieu 		{64,		28},
1490139788eSmatthieu 		{128,		96},
1500139788eSmatthieu 		{256,		204},
1510139788eSmatthieu 		{512,		440},
1520139788eSmatthieu 		{1024,		942},
1530139788eSmatthieu 		{2048,		1920},
1540139788eSmatthieu 		{4096,		3932}
1550139788eSmatthieu 	};
1560139788eSmatthieu 
1570139788eSmatthieu 	/*
1580139788eSmatthieu 	 * Work out an upper bound for agp memory allocation. This
1590139788eSmatthieu 	 * uses a heuristic table from the Linux driver.
1600139788eSmatthieu 	 */
1610139788eSmatthieu 	memsize = ptoa(physmem) >> 20;
1620139788eSmatthieu 
1639aa97624Sjasper 	for (i = 0; i < nitems(agp_max) && memsize > agp_max[i][0]; i++)
1640139788eSmatthieu 		;
1659aa97624Sjasper 	if (i == nitems(agp_max))
1669aa97624Sjasper 		i = nitems(agp_max) - 1;
1670139788eSmatthieu 	sc->sc_maxmem = agp_max[i][1] << 20;
1680139788eSmatthieu 
1690139788eSmatthieu 	/*
1700139788eSmatthieu 	 * The lock is used to prevent re-entry to
1710139788eSmatthieu 	 * agp_generic_bind_memory() since that function can sleep.
1720139788eSmatthieu 	 */
173f0c692fcSoga 	rw_init(&sc->sc_lock, "agplk");
1740139788eSmatthieu 
1750139788eSmatthieu 	TAILQ_INIT(&sc->sc_memory);
1760139788eSmatthieu 
1770139788eSmatthieu 	sc->sc_pcitag = pa->pa_tag;
1780139788eSmatthieu 	sc->sc_pc = pa->pa_pc;
1790139788eSmatthieu 	sc->sc_id = pa->pa_id;
1800139788eSmatthieu 	sc->sc_dmat = pa->pa_dmat;
1814ad474a9Smpi 	sc->sc_memt = pa->pa_memt;
1820139788eSmatthieu 
1830139788eSmatthieu 	pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP,
1840139788eSmatthieu 	    &sc->sc_capoff, NULL);
1850139788eSmatthieu 
186d8cdf4a2Soga 	printf(": aperture at 0x%lx, size 0x%lx\n", (u_long)sc->sc_apaddr,
187b113917fSoga 	    (u_long)sc->sc_apsize);
1880139788eSmatthieu }
1890139788eSmatthieu 
19040d7c10bSoga struct cfattach agp_ca = {
19140d7c10bSoga 	sizeof(struct agp_softc), agp_probe, agp_attach,
19240d7c10bSoga 	NULL, NULL
19340d7c10bSoga };
19440d7c10bSoga 
19540d7c10bSoga struct cfdriver agp_cd = {
19640d7c10bSoga 	NULL, "agp", DV_DULL
19740d7c10bSoga };
19840d7c10bSoga 
1990139788eSmatthieu struct agp_memory *
20040d7c10bSoga agp_find_memory(struct agp_softc *sc, int id)
2010139788eSmatthieu {
2020139788eSmatthieu 	struct agp_memory *mem;
2030139788eSmatthieu 
2040139788eSmatthieu 	AGP_DPF("searching for memory block %d\n", id);
2050139788eSmatthieu 	TAILQ_FOREACH(mem, &sc->sc_memory, am_link) {
2060139788eSmatthieu 		AGP_DPF("considering memory block %d\n", mem->am_id);
2070139788eSmatthieu 		if (mem->am_id == id)
2080139788eSmatthieu 			return (mem);
2090139788eSmatthieu 	}
2104ad474a9Smpi 	return (NULL);
2114ad474a9Smpi }
2124ad474a9Smpi 
2134ad474a9Smpi 
2144ad474a9Smpi struct agp_memory *
2154ad474a9Smpi agp_lookup_memory(struct agp_softc *sc, off_t off)
2164ad474a9Smpi {
2174ad474a9Smpi 	struct agp_memory* mem;
2184ad474a9Smpi 
2194ad474a9Smpi 	AGP_DPF("searching for memory offset 0x%lx\n", (unsigned long)off);
2204ad474a9Smpi 	TAILQ_FOREACH(mem, &sc->sc_memory, am_link) {
2214ad474a9Smpi 		if (mem->am_is_bound == 0)
2224ad474a9Smpi 			continue;
2234ad474a9Smpi 		if (off >= mem->am_offset &&
2244ad474a9Smpi 		    off < (mem->am_offset + mem->am_size))
2254ad474a9Smpi 			return (mem);
2264ad474a9Smpi 	}
2274ad474a9Smpi 	return (NULL);
2280139788eSmatthieu }
2290139788eSmatthieu 
2300139788eSmatthieu struct agp_gatt *
2318f6e6e82Soga agp_alloc_gatt(bus_dma_tag_t dmat, u_int32_t apsize)
2320139788eSmatthieu {
2330139788eSmatthieu 	struct agp_gatt		*gatt;
2348f6e6e82Soga 	u_int32_t	 	 entries = apsize >> AGP_PAGE_SHIFT;
2350139788eSmatthieu 
23640d7c10bSoga 	gatt = malloc(sizeof(*gatt), M_AGP, M_NOWAIT | M_ZERO);
2370139788eSmatthieu 	if (!gatt)
2380139788eSmatthieu 		return (NULL);
2390139788eSmatthieu 	gatt->ag_entries = entries;
240d4ab52b1Soga 	gatt->ag_size = entries * sizeof(u_int32_t);
2410139788eSmatthieu 
242d4ab52b1Soga 	if (agp_alloc_dmamem(dmat, gatt->ag_size, &gatt->ag_dmamap,
243*371e2336Sjsg 	    &gatt->ag_physical, &gatt->ag_dmaseg) != 0) {
244*371e2336Sjsg 		free(gatt, M_AGP);
24540d7c10bSoga 		return (NULL);
246*371e2336Sjsg 	}
2470139788eSmatthieu 
248d4ab52b1Soga 	if (bus_dmamem_map(dmat, &gatt->ag_dmaseg, 1, gatt->ag_size,
249d4ab52b1Soga 	    (caddr_t *)&gatt->ag_virtual, BUS_DMA_NOWAIT) != 0) {
250d4ab52b1Soga 		agp_free_dmamem(dmat, gatt->ag_size, gatt->ag_dmamap,
251d4ab52b1Soga 		    &gatt->ag_dmaseg);
252*371e2336Sjsg 		free(gatt, M_AGP);
253d4ab52b1Soga 		return (NULL);
254d4ab52b1Soga 	}
255d4ab52b1Soga 
2560139788eSmatthieu 	agp_flush_cache();
2570139788eSmatthieu 
25840d7c10bSoga 	return (gatt);
2590139788eSmatthieu }
2600139788eSmatthieu 
2610139788eSmatthieu void
2628f6e6e82Soga agp_free_gatt(bus_dma_tag_t dmat, struct agp_gatt *gatt)
2630139788eSmatthieu {
264d4ab52b1Soga 	bus_dmamem_unmap(dmat, (caddr_t)gatt->ag_virtual, gatt->ag_size);
265d4ab52b1Soga 	agp_free_dmamem(dmat, gatt->ag_size, gatt->ag_dmamap, &gatt->ag_dmaseg);
26640d7c10bSoga 	free(gatt, M_AGP);
2670139788eSmatthieu }
2680139788eSmatthieu 
2690139788eSmatthieu int
27040d7c10bSoga agp_generic_enable(struct agp_softc *sc, u_int32_t mode)
2710139788eSmatthieu {
2728f6e6e82Soga 	struct pci_attach_args	pa;
2738f6e6e82Soga 	pcireg_t		tstatus, mstatus, command;
2740139788eSmatthieu 	int			rq, sba, fw, rate, capoff;
2750139788eSmatthieu 
2768f6e6e82Soga 	if (pci_find_device(&pa, agpvga_match) == 0 ||
2778f6e6e82Soga 	    pci_get_capability(pa.pa_pc, pa.pa_tag, PCI_CAP_AGP,
2780139788eSmatthieu 	    &capoff, NULL) == 0) {
2790139788eSmatthieu 		printf("agp_generic_enable: not an AGP capable device\n");
28040d7c10bSoga 		return (-1);
2810139788eSmatthieu 	}
2820139788eSmatthieu 
2830139788eSmatthieu 	tstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
2840139788eSmatthieu 	    sc->sc_capoff + AGP_STATUS);
28560d13d3bSoga 	/* display agp mode */
2868f6e6e82Soga 	mstatus = pci_conf_read(pa.pa_pc, pa.pa_tag,
2870139788eSmatthieu 	    capoff + AGP_STATUS);
2880139788eSmatthieu 
2890139788eSmatthieu 	/* Set RQ to the min of mode, tstatus and mstatus */
2900139788eSmatthieu 	rq = AGP_MODE_GET_RQ(mode);
2910139788eSmatthieu 	if (AGP_MODE_GET_RQ(tstatus) < rq)
2920139788eSmatthieu 		rq = AGP_MODE_GET_RQ(tstatus);
2930139788eSmatthieu 	if (AGP_MODE_GET_RQ(mstatus) < rq)
2940139788eSmatthieu 		rq = AGP_MODE_GET_RQ(mstatus);
2950139788eSmatthieu 
2960139788eSmatthieu 	/* Set SBA if all three can deal with SBA */
2970139788eSmatthieu 	sba = (AGP_MODE_GET_SBA(tstatus)
2980139788eSmatthieu 	    & AGP_MODE_GET_SBA(mstatus)
2990139788eSmatthieu 	    & AGP_MODE_GET_SBA(mode));
3000139788eSmatthieu 
3010139788eSmatthieu 	/* Similar for FW */
3020139788eSmatthieu 	fw = (AGP_MODE_GET_FW(tstatus)
3030139788eSmatthieu 	    & AGP_MODE_GET_FW(mstatus)
3040139788eSmatthieu 	    & AGP_MODE_GET_FW(mode));
3050139788eSmatthieu 
3060139788eSmatthieu 	/* Figure out the max rate */
3070139788eSmatthieu 	rate = (AGP_MODE_GET_RATE(tstatus)
3080139788eSmatthieu 	    & AGP_MODE_GET_RATE(mstatus)
3090139788eSmatthieu 	    & AGP_MODE_GET_RATE(mode));
3100139788eSmatthieu 	if (rate & AGP_MODE_RATE_4x)
3110139788eSmatthieu 		rate = AGP_MODE_RATE_4x;
3120139788eSmatthieu 	else if (rate & AGP_MODE_RATE_2x)
3130139788eSmatthieu 		rate = AGP_MODE_RATE_2x;
3140139788eSmatthieu 	else
3150139788eSmatthieu 		rate = AGP_MODE_RATE_1x;
3160139788eSmatthieu 
3170139788eSmatthieu 	/* Construct the new mode word and tell the hardware  */
3180139788eSmatthieu 	command = AGP_MODE_SET_RQ(0, rq);
3190139788eSmatthieu 	command = AGP_MODE_SET_SBA(command, sba);
3200139788eSmatthieu 	command = AGP_MODE_SET_FW(command, fw);
3210139788eSmatthieu 	command = AGP_MODE_SET_RATE(command, rate);
3220139788eSmatthieu 	command = AGP_MODE_SET_AGP(command, 1);
32360d13d3bSoga 
3240139788eSmatthieu 	pci_conf_write(sc->sc_pc, sc->sc_pcitag,
3250139788eSmatthieu 	    sc->sc_capoff + AGP_COMMAND, command);
3268f6e6e82Soga 	pci_conf_write(pa.pa_pc, pa.pa_tag, capoff + AGP_COMMAND, command);
32740d7c10bSoga 	return (0);
3280139788eSmatthieu }
3290139788eSmatthieu 
3300139788eSmatthieu struct agp_memory *
33140d7c10bSoga agp_generic_alloc_memory(struct agp_softc *sc, int type, vsize_t size)
3320139788eSmatthieu {
3330139788eSmatthieu 	struct agp_memory *mem;
3340139788eSmatthieu 
3350139788eSmatthieu 	if (type != 0) {
3360139788eSmatthieu 		printf("agp_generic_alloc_memory: unsupported type %d\n", type);
33740d7c10bSoga 		return (0);
3380139788eSmatthieu 	}
3390139788eSmatthieu 
34040d7c10bSoga 	mem = malloc(sizeof *mem, M_AGP, M_WAITOK | M_ZERO);
3410139788eSmatthieu 
3420139788eSmatthieu 	if (bus_dmamap_create(sc->sc_dmat, size, size / PAGE_SIZE + 1,
3430139788eSmatthieu 	    size, 0, BUS_DMA_NOWAIT, &mem->am_dmamap) != 0) {
34440d7c10bSoga 		free(mem, M_AGP);
34540d7c10bSoga 		return (NULL);
3460139788eSmatthieu 	}
3470139788eSmatthieu 
3480139788eSmatthieu 	mem->am_id = sc->sc_nextid++;
3490139788eSmatthieu 	mem->am_size = size;
3500139788eSmatthieu 	TAILQ_INSERT_TAIL(&sc->sc_memory, mem, am_link);
3510139788eSmatthieu 	sc->sc_allocated += size;
3520139788eSmatthieu 
35340d7c10bSoga 	return (mem);
3540139788eSmatthieu }
3550139788eSmatthieu 
3560139788eSmatthieu int
35740d7c10bSoga agp_generic_free_memory(struct agp_softc *sc, struct agp_memory *mem)
3580139788eSmatthieu {
3590139788eSmatthieu 	if (mem->am_is_bound)
36040d7c10bSoga 		return (EBUSY);
3610139788eSmatthieu 
3620139788eSmatthieu 	sc->sc_allocated -= mem->am_size;
3630139788eSmatthieu 	TAILQ_REMOVE(&sc->sc_memory, mem, am_link);
3640139788eSmatthieu 	bus_dmamap_destroy(sc->sc_dmat, mem->am_dmamap);
36540d7c10bSoga 	free(mem, M_AGP);
36640d7c10bSoga 	return (0);
3670139788eSmatthieu }
3680139788eSmatthieu 
3690139788eSmatthieu int
37040d7c10bSoga agp_generic_bind_memory(struct agp_softc *sc, struct agp_memory *mem,
37107fa6f2aSoga     bus_size_t offset)
3720139788eSmatthieu {
3730139788eSmatthieu 	bus_dma_segment_t	*segs, *seg;
37407fa6f2aSoga 	bus_addr_t		 apaddr = sc->sc_apaddr + offset;
37507fa6f2aSoga 	bus_size_t		 done, i, j;
376eabb5cdaSdim 	int			 nseg, error;
3770139788eSmatthieu 
378f0c692fcSoga 	rw_enter_write(&sc->sc_lock);
3790139788eSmatthieu 
3800139788eSmatthieu 	if (mem->am_is_bound) {
3810139788eSmatthieu 		printf("AGP: memory already bound\n");
382f0c692fcSoga 		rw_exit_write(&sc->sc_lock);
38340d7c10bSoga 		return (EINVAL);
3840139788eSmatthieu 	}
3850139788eSmatthieu 
386b3d58ac7Sbrad 	if ((offset & (AGP_PAGE_SIZE - 1)) != 0 ||
387b113917fSoga 	    offset + mem->am_size > sc->sc_apsize) {
3880139788eSmatthieu 		printf("AGP: binding memory at bad offset %#lx\n",
3890139788eSmatthieu 		    (unsigned long) offset);
390f0c692fcSoga 		rw_exit_write(&sc->sc_lock);
39140d7c10bSoga 		return (EINVAL);
3920139788eSmatthieu 	}
3930139788eSmatthieu 
3940139788eSmatthieu 	/*
3950139788eSmatthieu 	 * The memory here needs to be directly accessable from the
3960139788eSmatthieu 	 * AGP video card, so it should be allocated using bus_dma.
3970139788eSmatthieu 	 * However, it need not be contiguous, since individual pages
3980139788eSmatthieu 	 * are translated using the GATT.
3990139788eSmatthieu 	 */
4000139788eSmatthieu 
401eabb5cdaSdim 	nseg = (mem->am_size + PAGE_SIZE - 1) / PAGE_SIZE;
40240d7c10bSoga 	segs = malloc(nseg * sizeof *segs, M_AGP, M_WAITOK);
4030139788eSmatthieu 	if ((error = bus_dmamem_alloc(sc->sc_dmat, mem->am_size, PAGE_SIZE, 0,
404d4ab52b1Soga 	    segs, nseg, &mem->am_nseg, BUS_DMA_ZERO | BUS_DMA_WAITOK)) != 0) {
40540d7c10bSoga 		free(segs, M_AGP);
406f0c692fcSoga 		rw_exit_write(&sc->sc_lock);
4070139788eSmatthieu 		AGP_DPF("bus_dmamem_alloc failed %d\n", error);
40840d7c10bSoga 		return (error);
4090139788eSmatthieu 	}
410d4ab52b1Soga 	if ((error = bus_dmamap_load_raw(sc->sc_dmat, mem->am_dmamap, segs,
411d4ab52b1Soga 	    mem->am_nseg, mem->am_size, BUS_DMA_WAITOK)) != 0) {
4120139788eSmatthieu 		bus_dmamem_free(sc->sc_dmat, segs, mem->am_nseg);
41340d7c10bSoga 		free(segs, M_AGP);
414f0c692fcSoga 		rw_exit_write(&sc->sc_lock);
4150139788eSmatthieu 		AGP_DPF("bus_dmamap_load failed %d\n", error);
41640d7c10bSoga 		return (error);
4170139788eSmatthieu 	}
4180139788eSmatthieu 	mem->am_dmaseg = segs;
4190139788eSmatthieu 
4200139788eSmatthieu 	/*
42107fa6f2aSoga 	 * Install entries in the GATT, making sure that if
42207fa6f2aSoga 	 * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not
42307fa6f2aSoga 	 * aligned to PAGE_SIZE, we don't modify too many GATT
42407fa6f2aSoga 	 * entries. Flush chipset tlb when done.
4250139788eSmatthieu 	 */
4260139788eSmatthieu 	done = 0;
4270139788eSmatthieu 	for (i = 0; i < mem->am_dmamap->dm_nsegs; i++) {
4280139788eSmatthieu 		seg = &mem->am_dmamap->dm_segs[i];
4290139788eSmatthieu 		for (j = 0; j < seg->ds_len && (done + j) < mem->am_size;
4300139788eSmatthieu 		    j += AGP_PAGE_SIZE) {
4310139788eSmatthieu 			AGP_DPF("binding offset %#lx to pa %#lx\n",
4320139788eSmatthieu 			    (unsigned long)(offset + done + j),
43307fa6f2aSoga 			    (unsigned long)seg->ds_addr + j);
43407fa6f2aSoga 			sc->sc_methods->bind_page(sc->sc_chipc,
43507fa6f2aSoga 			    apaddr + done + j, seg->ds_addr + j, 0);
4360139788eSmatthieu 		}
4370139788eSmatthieu 		done += seg->ds_len;
4380139788eSmatthieu 	}
4390139788eSmatthieu 
4400139788eSmatthieu 	/*
4410139788eSmatthieu 	 * Flush the cpu cache since we are providing a new mapping
4420139788eSmatthieu 	 * for these pages.
4430139788eSmatthieu 	 */
4440139788eSmatthieu 	agp_flush_cache();
4450139788eSmatthieu 
4460139788eSmatthieu 	/*
4470139788eSmatthieu 	 * Make sure the chipset gets the new mappings.
4480139788eSmatthieu 	 */
4498f6e6e82Soga 	sc->sc_methods->flush_tlb(sc->sc_chipc);
4500139788eSmatthieu 
4510139788eSmatthieu 	mem->am_offset = offset;
4520139788eSmatthieu 	mem->am_is_bound = 1;
4530139788eSmatthieu 
454f0c692fcSoga 	rw_exit_write(&sc->sc_lock);
4550139788eSmatthieu 
45640d7c10bSoga 	return (0);
4570139788eSmatthieu }
4580139788eSmatthieu 
4590139788eSmatthieu int
46040d7c10bSoga agp_generic_unbind_memory(struct agp_softc *sc, struct agp_memory *mem)
4610139788eSmatthieu {
46207fa6f2aSoga 	bus_addr_t	apaddr = sc->sc_apaddr + mem->am_offset;
46307fa6f2aSoga 	bus_size_t	i;
4640139788eSmatthieu 
465f0c692fcSoga 	rw_enter_write(&sc->sc_lock);
4660139788eSmatthieu 
467678c000dSoga 	if (mem->am_is_bound == 0) {
4680139788eSmatthieu 		printf("AGP: memory is not bound\n");
469f0c692fcSoga 		rw_exit_write(&sc->sc_lock);
47040d7c10bSoga 		return (EINVAL);
4710139788eSmatthieu 	}
4720139788eSmatthieu 
4734ad474a9Smpi 	if (mem->am_mapref > 0) {
4744ad474a9Smpi 		printf("AGP: memory is mapped\n");
4754ad474a9Smpi 		rw_exit_write(&sc->sc_lock);
4764ad474a9Smpi 		return (EINVAL);
4774ad474a9Smpi 	}
4780139788eSmatthieu 
4790139788eSmatthieu 	/*
4800139788eSmatthieu 	 * Unbind the individual pages and flush the chipset's
4810139788eSmatthieu 	 * TLB. Unwire the pages so they can be swapped.
4820139788eSmatthieu 	 */
4830139788eSmatthieu 	for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
48407fa6f2aSoga 		sc->sc_methods->unbind_page(sc->sc_chipc, apaddr + i);
4850139788eSmatthieu 
4860139788eSmatthieu 	agp_flush_cache();
4878f6e6e82Soga 	sc->sc_methods->flush_tlb(sc->sc_chipc);
4880139788eSmatthieu 
4890139788eSmatthieu 	bus_dmamap_unload(sc->sc_dmat, mem->am_dmamap);
4900139788eSmatthieu 	bus_dmamem_free(sc->sc_dmat, mem->am_dmaseg, mem->am_nseg);
4910139788eSmatthieu 
49240d7c10bSoga 	free(mem->am_dmaseg, M_AGP);
4930139788eSmatthieu 
4940139788eSmatthieu 	mem->am_offset = 0;
4950139788eSmatthieu 	mem->am_is_bound = 0;
4960139788eSmatthieu 
497f0c692fcSoga 	rw_exit_write(&sc->sc_lock);
4980139788eSmatthieu 
49940d7c10bSoga 	return (0);
5000139788eSmatthieu }
5010139788eSmatthieu 
502d4ab52b1Soga /*
503d4ab52b1Soga  * Allocates a single-segment block of zeroed, wired dma memory.
504d4ab52b1Soga  */
5050139788eSmatthieu int
506d4ab52b1Soga agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t *mapp,
507d4ab52b1Soga     bus_addr_t *baddr, bus_dma_segment_t *seg)
5080139788eSmatthieu {
509d4ab52b1Soga 	int error, level = 0, nseg;
5100139788eSmatthieu 
5110139788eSmatthieu 	if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0,
512d4ab52b1Soga 	    seg, 1, &nseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO)) != 0)
5130139788eSmatthieu 		goto out;
5140139788eSmatthieu 	level++;
5150139788eSmatthieu 
516d4ab52b1Soga 	if ((error = bus_dmamap_create(tag, size, nseg, size, 0,
5170139788eSmatthieu 	    BUS_DMA_NOWAIT, mapp)) != 0)
5180139788eSmatthieu 		goto out;
5190139788eSmatthieu 	level++;
5200139788eSmatthieu 
521d4ab52b1Soga 	if ((error = bus_dmamap_load_raw(tag, *mapp, seg, nseg, size,
5220139788eSmatthieu 	    BUS_DMA_NOWAIT)) != 0)
5230139788eSmatthieu 		goto out;
5240139788eSmatthieu 
5250139788eSmatthieu 	*baddr = (*mapp)->dm_segs[0].ds_addr;
5260139788eSmatthieu 
52740d7c10bSoga 	return (0);
5280139788eSmatthieu out:
5290139788eSmatthieu 	switch (level) {
530d4ab52b1Soga 	case 2:
5310139788eSmatthieu 		bus_dmamap_destroy(tag, *mapp);
5320139788eSmatthieu 		/* FALLTHROUGH */
5330139788eSmatthieu 	case 1:
534d4ab52b1Soga 		bus_dmamem_free(tag, seg, nseg);
5350139788eSmatthieu 		break;
5360139788eSmatthieu 	default:
5370139788eSmatthieu 		break;
5380139788eSmatthieu 	}
5390139788eSmatthieu 
54040d7c10bSoga 	return (error);
5410139788eSmatthieu }
5420139788eSmatthieu 
5430139788eSmatthieu void
5440139788eSmatthieu agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map,
545d4ab52b1Soga     bus_dma_segment_t *seg)
5460139788eSmatthieu {
5470139788eSmatthieu 	bus_dmamap_unload(tag, map);
5480139788eSmatthieu 	bus_dmamap_destroy(tag, map);
549d4ab52b1Soga 	bus_dmamem_free(tag, seg, 1);
5500139788eSmatthieu }
55140d7c10bSoga 
55240d7c10bSoga /* Helper functions used in both user and kernel APIs */
55340d7c10bSoga 
55470456743Soga int
55540d7c10bSoga agp_acquire_helper(void *dev, enum agp_acquire_state state)
55640d7c10bSoga {
55740d7c10bSoga 	struct agp_softc *sc = (struct agp_softc *)dev;
55840d7c10bSoga 
5599d238d47Soga 	if (sc->sc_chipc == NULL)
5609d238d47Soga 		return (EINVAL);
5619d238d47Soga 
56240d7c10bSoga 	if (sc->sc_state != AGP_ACQUIRE_FREE)
56340d7c10bSoga 		return (EBUSY);
56440d7c10bSoga 	sc->sc_state = state;
56540d7c10bSoga 
56640d7c10bSoga 	return (0);
56740d7c10bSoga }
56840d7c10bSoga 
56970456743Soga int
57040d7c10bSoga agp_release_helper(void *dev, enum agp_acquire_state state)
57140d7c10bSoga {
57240d7c10bSoga 	struct agp_softc *sc = (struct agp_softc *)dev;
57340d7c10bSoga 	struct agp_memory* mem;
57440d7c10bSoga 
57540d7c10bSoga 	if (sc->sc_state == AGP_ACQUIRE_FREE)
57640d7c10bSoga 		return (0);
57740d7c10bSoga 
57840d7c10bSoga 	if (sc->sc_state != state)
57940d7c10bSoga 		return (EBUSY);
58040d7c10bSoga 
58140d7c10bSoga 	/*
58240d7c10bSoga 	 * Clear out the aperture and free any
58340d7c10bSoga 	 * outstanding memory blocks.
58440d7c10bSoga 	 */
58540d7c10bSoga 	TAILQ_FOREACH(mem, &sc->sc_memory, am_link) {
58640d7c10bSoga 		if (mem->am_is_bound) {
58740d7c10bSoga 			printf("agp_release_helper: mem %d is bound\n",
58840d7c10bSoga 			    mem->am_id);
589678c000dSoga 			agp_unbind_memory(sc, mem);
59040d7c10bSoga 		}
59140d7c10bSoga 	}
59240d7c10bSoga 	sc->sc_state = AGP_ACQUIRE_FREE;
59340d7c10bSoga 	return (0);
59440d7c10bSoga }
59540d7c10bSoga 
59640d7c10bSoga /* Implementation of the kernel api */
59740d7c10bSoga 
59840d7c10bSoga void *
59940d7c10bSoga agp_find_device(int unit)
60040d7c10bSoga {
6018f8e4ea1Soga 	if (unit >= agp_cd.cd_ndevs || unit < 0)
6028f8e4ea1Soga 		return (NULL);
6038f8e4ea1Soga 	return (agp_cd.cd_devs[unit]);
60440d7c10bSoga }
60540d7c10bSoga 
60640d7c10bSoga enum agp_acquire_state
60740d7c10bSoga agp_state(void *dev)
60840d7c10bSoga {
60940d7c10bSoga 	struct agp_softc *sc = (struct agp_softc *) dev;
61040d7c10bSoga         return (sc->sc_state);
61140d7c10bSoga }
61240d7c10bSoga 
61340d7c10bSoga void
61440d7c10bSoga agp_get_info(void *dev, struct agp_info *info)
61540d7c10bSoga {
61640d7c10bSoga 	struct agp_softc *sc = (struct agp_softc *)dev;
61740d7c10bSoga 
6188f6e6e82Soga 	if (sc->sc_capoff != 0)
61940d7c10bSoga 		info->ai_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
6208f6e6e82Soga 		    AGP_STATUS + sc->sc_capoff);
6218f6e6e82Soga 	else
6228f6e6e82Soga 		info->ai_mode = 0; /* i810 doesn't have real AGP */
62340d7c10bSoga 	info->ai_aperture_base = sc->sc_apaddr;
624b113917fSoga 	info->ai_aperture_size = sc->sc_apsize;
62540d7c10bSoga 	info->ai_memory_allowed = sc->sc_maxmem;
62640d7c10bSoga 	info->ai_memory_used = sc->sc_allocated;
62785ff9379Sjsg 	info->ai_devid = sc->sc_id;
62840d7c10bSoga }
62940d7c10bSoga 
63040d7c10bSoga int
63140d7c10bSoga agp_acquire(void *dev)
63240d7c10bSoga {
63340d7c10bSoga 	struct agp_softc *sc = (struct agp_softc *)dev;
634e47997a5Soga 
63540d7c10bSoga         return (agp_acquire_helper(sc, AGP_ACQUIRE_KERNEL));
63640d7c10bSoga }
63740d7c10bSoga 
63840d7c10bSoga int
63940d7c10bSoga agp_release(void *dev)
64040d7c10bSoga {
64140d7c10bSoga 	struct agp_softc *sc = (struct agp_softc *)dev;
642e47997a5Soga 
64340d7c10bSoga         return (agp_release_helper(sc, AGP_ACQUIRE_KERNEL));
64440d7c10bSoga }
64540d7c10bSoga 
64640d7c10bSoga int
64740d7c10bSoga agp_enable(void *dev, u_int32_t mode)
64840d7c10bSoga {
649678c000dSoga 	struct agp_softc	*sc = dev;
650678c000dSoga 	int			 ret;
651e47997a5Soga 
652678c000dSoga 	if (sc->sc_methods->enable != NULL) {
653678c000dSoga 		ret = sc->sc_methods->enable(sc->sc_chipc, mode);
654678c000dSoga 	} else {
655678c000dSoga 		ret = agp_generic_enable(sc, mode);
656678c000dSoga 	}
657678c000dSoga 	return (ret);
65840d7c10bSoga }
65940d7c10bSoga 
660e47997a5Soga void *
661e47997a5Soga agp_alloc_memory(void *dev, int type, vsize_t bytes)
66240d7c10bSoga {
663678c000dSoga 	struct agp_softc	*sc = dev;
664678c000dSoga 	struct agp_memory	*mem;
665e47997a5Soga 
666678c000dSoga 	if (sc->sc_methods->alloc_memory != NULL) {
667678c000dSoga 		mem = sc->sc_methods->alloc_memory(sc->sc_chipc, type, bytes);
668678c000dSoga 	} else {
669678c000dSoga 		mem = agp_generic_alloc_memory(sc, type, bytes);
670678c000dSoga 	}
671678c000dSoga         return  (mem);
67240d7c10bSoga }
67340d7c10bSoga 
674e47997a5Soga void
675e47997a5Soga agp_free_memory(void *dev, void *handle)
67640d7c10bSoga {
677678c000dSoga 	struct agp_softc *sc = dev;
678678c000dSoga         struct agp_memory *mem = handle;
679e47997a5Soga 
680678c000dSoga 	if (sc->sc_methods->free_memory != NULL) {
681678c000dSoga 		sc->sc_methods->free_memory(sc->sc_chipc, mem);
682678c000dSoga 	} else {
683678c000dSoga 		agp_generic_free_memory(sc, mem);
684678c000dSoga 	}
68540d7c10bSoga }
68640d7c10bSoga 
687e47997a5Soga int
688e47997a5Soga agp_bind_memory(void *dev, void *handle, off_t offset)
68940d7c10bSoga {
690678c000dSoga 	struct agp_softc	*sc = dev;
691678c000dSoga 	struct agp_memory	*mem = handle;
692678c000dSoga 	int			 ret;
693e47997a5Soga 
694678c000dSoga 	if (sc->sc_methods->bind_memory != NULL) {
695678c000dSoga 		ret = sc->sc_methods->bind_memory(sc->sc_chipc, mem, offset);
696678c000dSoga 	} else {
697678c000dSoga 		ret = agp_generic_bind_memory(sc, mem, offset);
698678c000dSoga 	}
699678c000dSoga 	return (ret);
70040d7c10bSoga }
70140d7c10bSoga 
702e47997a5Soga int
703e47997a5Soga agp_unbind_memory(void *dev, void *handle)
70440d7c10bSoga {
705678c000dSoga 	struct agp_softc	*sc = dev;
706678c000dSoga         struct agp_memory	*mem = handle;
707678c000dSoga 	int			 ret;
708e47997a5Soga 
709678c000dSoga 	if (sc->sc_methods->unbind_memory != NULL) {
710678c000dSoga 		ret = sc->sc_methods->unbind_memory(sc->sc_chipc, mem);
711678c000dSoga 	} else {
712678c000dSoga 		ret = agp_generic_unbind_memory(sc, mem);
713678c000dSoga 	}
714678c000dSoga 	return (ret);
71540d7c10bSoga }
71640d7c10bSoga 
717e47997a5Soga void
7189d238d47Soga agp_memory_info(void *dev, void *handle, struct agp_memory_info *mi)
71940d7c10bSoga {
72040d7c10bSoga         struct agp_memory *mem = (struct agp_memory *) handle;
72140d7c10bSoga 
72240d7c10bSoga         mi->ami_size = mem->am_size;
72340d7c10bSoga         mi->ami_physical = mem->am_physical;
72440d7c10bSoga         mi->ami_offset = mem->am_offset;
72540d7c10bSoga         mi->ami_is_bound = mem->am_is_bound;
72640d7c10bSoga }
7274ad474a9Smpi 
7284ad474a9Smpi void *
7294ad474a9Smpi agp_map(struct agp_softc *sc, bus_size_t address, bus_size_t size,
7304ad474a9Smpi     bus_space_handle_t *memh)
7314ad474a9Smpi {
7324ad474a9Smpi 	struct agp_memory* mem;
7334ad474a9Smpi 
7344ad474a9Smpi 	if (sc->sc_chipc == NULL)
7354ad474a9Smpi 		return (NULL);
7364ad474a9Smpi 
7374ad474a9Smpi 	if (address >= sc->sc_apsize)
7384ad474a9Smpi 		return (NULL);
7394ad474a9Smpi 
7404ad474a9Smpi 	if (sc->sc_apaddr) {
7414ad474a9Smpi 		if (bus_space_map(sc->sc_memt, sc->sc_apaddr + address, size,
7424ad474a9Smpi 		    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, memh))
7434ad474a9Smpi 			return (NULL);
7444ad474a9Smpi 	} else {
7454ad474a9Smpi 		/*
7464ad474a9Smpi 		 * If the aperture base address is 0 assume that the AGP
7474ad474a9Smpi 		 * bridge does not support remapping for processor accesses.
7484ad474a9Smpi 		 */
7494ad474a9Smpi 		mem = agp_lookup_memory(sc, address);
7504ad474a9Smpi 		if (mem == NULL)
7514ad474a9Smpi 			return (NULL);
7524ad474a9Smpi 
7534ad474a9Smpi 		/*
7544ad474a9Smpi 		 * Map the whole memory region because it is easier to
7554ad474a9Smpi 		 * do so and it is improbable that only a part of it
7564ad474a9Smpi 		 * will be used.
7574ad474a9Smpi 		 */
7584ad474a9Smpi 		if (mem->am_mapref == 0)
7594ad474a9Smpi 			if (bus_dmamem_map(sc->sc_dmat, mem->am_dmaseg,
7604ad474a9Smpi 			    mem->am_nseg, mem->am_size, &mem->am_kva,
7614ad474a9Smpi 			    BUS_DMA_NOWAIT | BUS_DMA_NOCACHE))
7624ad474a9Smpi 				return (NULL);
7634ad474a9Smpi 
7644ad474a9Smpi 		mem->am_mapref++;
7654ad474a9Smpi 
7664ad474a9Smpi 		/*
7674ad474a9Smpi 		 * XXX Fake a bus handle even if it is managed memory,
7684ad474a9Smpi 		 * this is needed at least by radeondrm(4).
7694ad474a9Smpi 		 */
7704ad474a9Smpi 		*memh = (bus_space_handle_t)(mem->am_kva + address);
7714ad474a9Smpi 	}
7724ad474a9Smpi 
7734ad474a9Smpi 	return bus_space_vaddr(sc->sc_memt, *memh);
7744ad474a9Smpi }
7754ad474a9Smpi 
7764ad474a9Smpi void
7774ad474a9Smpi agp_unmap(struct agp_softc *sc, void *address, size_t size,
7784ad474a9Smpi     bus_space_handle_t memh)
7794ad474a9Smpi {
7804ad474a9Smpi 	struct agp_memory* mem;
7814ad474a9Smpi 	caddr_t kva;
7824ad474a9Smpi 
7834ad474a9Smpi 	if (sc->sc_apaddr)
7844ad474a9Smpi 		return bus_space_unmap(sc->sc_memt, memh, size);
7854ad474a9Smpi 
7864ad474a9Smpi 	kva = (caddr_t)address;
7874ad474a9Smpi 	TAILQ_FOREACH(mem, &sc->sc_memory, am_link) {
7884ad474a9Smpi 		if (mem->am_is_bound == 0)
7894ad474a9Smpi 			continue;
7904ad474a9Smpi 
7914ad474a9Smpi 		if (kva >= mem->am_kva && kva < (mem->am_kva + mem->am_size)) {
7924ad474a9Smpi 			mem->am_mapref--;
7934ad474a9Smpi 
7944ad474a9Smpi 			if (mem->am_mapref == 0) {
7954ad474a9Smpi 				bus_dmamem_unmap(sc->sc_dmat, mem->am_kva,
7964ad474a9Smpi 				    mem->am_size);
7974ad474a9Smpi 				mem->am_kva = 0;
7984ad474a9Smpi 			}
7994ad474a9Smpi 			break;
8004ad474a9Smpi 		}
8014ad474a9Smpi 	}
8024ad474a9Smpi }
8034ad474a9Smpi 
8044ad474a9Smpi paddr_t
8054ad474a9Smpi agp_mmap(struct agp_softc *sc, off_t off, int prot)
8064ad474a9Smpi {
8074ad474a9Smpi 	struct agp_memory* mem;
8084ad474a9Smpi 
8094ad474a9Smpi 	if (sc->sc_chipc == NULL)
8104ad474a9Smpi 		return (-1);
8114ad474a9Smpi 
8124ad474a9Smpi 	if (off >= sc->sc_apsize)
8134ad474a9Smpi 		return (-1);
8144ad474a9Smpi 
8154ad474a9Smpi 	if (sc->sc_apaddr)
8164ad474a9Smpi 		return bus_space_mmap(sc->sc_memt, sc->sc_apaddr, off, prot, 0);
8174ad474a9Smpi 
8184ad474a9Smpi 	mem = agp_lookup_memory(sc, off);
8194ad474a9Smpi 	if (mem == NULL)
8204ad474a9Smpi 		return (-1);
8214ad474a9Smpi 
8224ad474a9Smpi 	return bus_dmamem_mmap(sc->sc_dmat, mem->am_dmaseg, mem->am_nseg, off,
8234ad474a9Smpi 	    prot, BUS_DMA_NOCACHE);
8244ad474a9Smpi }
825