1*8f8e4ea1Soga /* $OpenBSD: agp.c,v 1.20 2008/04/09 18:59:58 oga 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 4940d7c10bSoga #include "agp_ali.h" 5040d7c10bSoga #include "agp_amd.h" 5140d7c10bSoga #include "agp_amd64.h" 5240d7c10bSoga #include "agp_apple.h" 5340d7c10bSoga #include "agp_i810.h" 5440d7c10bSoga #include "agp_intel.h" 5540d7c10bSoga #include "agp_sis.h" 5640d7c10bSoga #include "agp_via.h" 570139788eSmatthieu 5840d7c10bSoga struct agp_memory *agp_find_memory(struct agp_softc *sc, int id); 5940d7c10bSoga const struct agp_product *agp_lookup(struct pci_attach_args *pa); 6040d7c10bSoga /* userland ioctl functions */ 6170456743Soga int agp_info_user(void *, agp_info *); 6270456743Soga int agp_setup_user(void *, agp_setup *); 6370456743Soga int agp_allocate_user(void *, agp_allocate *); 6470456743Soga int agp_deallocate_user(void *, int); 6570456743Soga int agp_bind_user(void *, agp_bind *); 6670456743Soga int agp_unbind_user(void *, agp_unbind *); 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 7040d7c10bSoga const struct agp_product agp_products[] = { 7140d7c10bSoga #if NAGP_ALI > 0 7240d7c10bSoga { PCI_VENDOR_ALI, -1, agp_ali_attach }, 7340d7c10bSoga #endif 7440d7c10bSoga #if NAGP_AMD > 0 7540d7c10bSoga { PCI_VENDOR_AMD, -1, agp_amd_attach }, 7640d7c10bSoga #endif 7740d7c10bSoga #if NAGP_I810 > 0 78c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_HB, agp_i810_attach }, 79c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_DC100_HB, agp_i810_attach }, 80c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810E_HB, agp_i810_attach }, 81c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82815_HB, agp_i810_attach }, 82c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82830M_HB, agp_i810_attach }, 83c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82845G_HB, agp_i810_attach }, 84c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82855GM_HB, agp_i810_attach }, 85c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82865G_HB, agp_i810_attach }, 8640d7c10bSoga { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82915G_HB, agp_i810_attach }, 8740d7c10bSoga { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82915GM_HB, agp_i810_attach }, 88c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82945G_HB, agp_i810_attach }, 89c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82945GM_HB, agp_i810_attach }, 90c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82G965_HB, agp_i810_attach }, 91c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82Q965_HB, agp_i810_attach }, 92c839f1b1Skettenis { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82GM965_HB, agp_i810_attach }, 939671a04fSdamien { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82G33_HB, agp_i810_attach }, 9440d7c10bSoga #endif 9540d7c10bSoga #if NAGP_INTEL > 0 9640d7c10bSoga { PCI_VENDOR_INTEL, -1, agp_intel_attach }, 9740d7c10bSoga #endif 9840d7c10bSoga #if NAGP_SIS > 0 9940d7c10bSoga { PCI_VENDOR_SIS, -1, agp_sis_attach }, 10040d7c10bSoga #endif 10140d7c10bSoga #if NAGP_VIA > 0 10240d7c10bSoga { PCI_VENDOR_VIATECH, -1, agp_via_attach }, 10340d7c10bSoga #endif 10440d7c10bSoga { 0, 0, NULL } 10540d7c10bSoga }; 10640d7c10bSoga 10740d7c10bSoga 10870456743Soga int 10940d7c10bSoga agp_probe(struct device *parent, void *match, void *aux) 11040d7c10bSoga { 11140d7c10bSoga struct agpbus_attach_args *aaa = aux; 11240d7c10bSoga struct pci_attach_args *pa = &aaa->apa_pci_args; 11340d7c10bSoga 114f2fa622eSoga /* pci_args must be a pchb */ 115f2fa622eSoga if (PCI_CLASS(pa->pa_class) != PCI_CLASS_BRIDGE || 116f2fa622eSoga PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_BRIDGE_HOST) 117f2fa622eSoga return (0); 118f2fa622eSoga 11940d7c10bSoga if (agp_lookup(pa) == NULL) 12040d7c10bSoga return (0); 12140d7c10bSoga 12240d7c10bSoga return (1); 12340d7c10bSoga } 1240139788eSmatthieu 1250139788eSmatthieu void 1260139788eSmatthieu agp_attach(struct device *parent, struct device *self, void *aux) 1270139788eSmatthieu { 12840d7c10bSoga struct agpbus_attach_args *aaa = aux; 12940d7c10bSoga struct pci_attach_args *pa = &aaa->apa_pci_args; 13040d7c10bSoga struct agp_softc *sc = (struct agp_softc *)self; 1310139788eSmatthieu const struct agp_product *ap; 1320139788eSmatthieu u_int memsize; 1330139788eSmatthieu int i, ret; 1340139788eSmatthieu 1350139788eSmatthieu ap = agp_lookup(pa); 1360139788eSmatthieu if (ap) { 1370139788eSmatthieu static const int agp_max[][2] = { 1380139788eSmatthieu {0, 0}, 1390139788eSmatthieu {32, 4}, 1400139788eSmatthieu {64, 28}, 1410139788eSmatthieu {128, 96}, 1420139788eSmatthieu {256, 204}, 1430139788eSmatthieu {512, 440}, 1440139788eSmatthieu {1024, 942}, 1450139788eSmatthieu {2048, 1920}, 1460139788eSmatthieu {4096, 3932} 1470139788eSmatthieu }; 1480139788eSmatthieu #define agp_max_size (sizeof(agp_max)/sizeof(agp_max[0])) 1490139788eSmatthieu 1500139788eSmatthieu /* 1510139788eSmatthieu * Work out an upper bound for agp memory allocation. This 1520139788eSmatthieu * uses a heuristic table from the Linux driver. 1530139788eSmatthieu */ 1540139788eSmatthieu memsize = ptoa(physmem) >> 20; 1550139788eSmatthieu 1560139788eSmatthieu for (i = 0; i < agp_max_size && memsize > agp_max[i][0]; i++) 1570139788eSmatthieu ; 1580139788eSmatthieu if (i == agp_max_size) 1590139788eSmatthieu i = agp_max_size - 1; 1600139788eSmatthieu sc->sc_maxmem = agp_max[i][1] << 20; 1610139788eSmatthieu 1620139788eSmatthieu /* 1630139788eSmatthieu * The lock is used to prevent re-entry to 1640139788eSmatthieu * agp_generic_bind_memory() since that function can sleep. 1650139788eSmatthieu */ 1660139788eSmatthieu 167f0c692fcSoga rw_init(&sc->sc_lock, "agplk"); 1680139788eSmatthieu 1690139788eSmatthieu TAILQ_INIT(&sc->sc_memory); 1700139788eSmatthieu 1710139788eSmatthieu sc->sc_pcitag = pa->pa_tag; 1720139788eSmatthieu sc->sc_pc = pa->pa_pc; 1730139788eSmatthieu sc->sc_id = pa->pa_id; 1740139788eSmatthieu sc->sc_dmat = pa->pa_dmat; 1750139788eSmatthieu 1760139788eSmatthieu pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP, 1770139788eSmatthieu &sc->sc_capoff, NULL); 1780139788eSmatthieu 1791d396234Sderaadt printf(": "); 18040d7c10bSoga ret = (*ap->ap_attach)(sc, pa); 1810139788eSmatthieu if (ret == 0) 1821d396234Sderaadt printf("aperture at 0x%lx, size 0x%lx\n", 1830139788eSmatthieu (u_long)sc->sc_apaddr, 1840139788eSmatthieu (u_long)AGP_GET_APERTURE(sc)); 1850139788eSmatthieu else { 1860139788eSmatthieu sc->sc_chipc = NULL; 1870139788eSmatthieu } 1880139788eSmatthieu } 1890139788eSmatthieu } 1900139788eSmatthieu 19140d7c10bSoga struct cfattach agp_ca = { 19240d7c10bSoga sizeof (struct agp_softc), agp_probe, agp_attach, 19340d7c10bSoga NULL, NULL 19440d7c10bSoga }; 19540d7c10bSoga 19640d7c10bSoga struct cfdriver agp_cd = { 19740d7c10bSoga NULL, "agp", DV_DULL 19840d7c10bSoga }; 19940d7c10bSoga 2000139788eSmatthieu paddr_t 20140d7c10bSoga agpmmap(void *v, off_t off, int prot) 2020139788eSmatthieu { 20340d7c10bSoga struct agp_softc* sc = (struct agp_softc *)v; 2040139788eSmatthieu 2050139788eSmatthieu if (sc->sc_apaddr) { 2060139788eSmatthieu 2070139788eSmatthieu if (off > AGP_GET_APERTURE(sc)) 2080139788eSmatthieu return (-1); 2090139788eSmatthieu 21040d7c10bSoga /* 21140d7c10bSoga * XXX this should use bus_space_mmap() but it's not 21240d7c10bSoga * availiable on all archs. 21340d7c10bSoga */ 2140139788eSmatthieu return atop(sc->sc_apaddr + off); 2150139788eSmatthieu } 21640d7c10bSoga return (-1); 2170139788eSmatthieu } 2180139788eSmatthieu 219e47997a5Soga int 220e47997a5Soga agpopen(dev_t dev, int oflags, int devtype, struct proc *p) 2210139788eSmatthieu { 222*8f8e4ea1Soga struct agp_softc *sc = agp_find_device(AGPUNIT(dev)); 22340d7c10bSoga 22440d7c10bSoga if (sc == NULL) 22540d7c10bSoga return (ENXIO); 22640d7c10bSoga 22740d7c10bSoga if (sc->sc_chipc == NULL) 22840d7c10bSoga return (ENXIO); 22940d7c10bSoga 23040d7c10bSoga if (!sc->sc_opened) 23140d7c10bSoga sc->sc_opened = 1; 23240d7c10bSoga else 23340d7c10bSoga return (EBUSY); 23440d7c10bSoga 23540d7c10bSoga return (0); 23640d7c10bSoga } 23740d7c10bSoga 23840d7c10bSoga 23940d7c10bSoga int 24040d7c10bSoga agpioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *pb) 24140d7c10bSoga { 242*8f8e4ea1Soga struct agp_softc *sc = agp_find_device(AGPUNIT(dev)); 24340d7c10bSoga 24440d7c10bSoga if (sc ==NULL) 24540d7c10bSoga return (ENODEV); 2460139788eSmatthieu 247ccb3d2ebSderaadt if (sc->sc_methods == NULL || sc->sc_chipc == NULL) 2481791d3edSderaadt return (ENXIO); 2491791d3edSderaadt 2500139788eSmatthieu if (cmd != AGPIOC_INFO && !(flag & FWRITE)) 2510139788eSmatthieu return (EPERM); 25240d7c10bSoga 2530139788eSmatthieu switch(cmd) { 2540139788eSmatthieu case AGPIOC_INFO: 25540d7c10bSoga return (agp_info_user(sc, (agp_info *)addr)); 2560139788eSmatthieu 2570139788eSmatthieu case AGPIOC_ACQUIRE: 25840d7c10bSoga return (agp_acquire_helper(sc, AGP_ACQUIRE_USER)); 2590139788eSmatthieu 2600139788eSmatthieu case AGPIOC_RELEASE: 26140d7c10bSoga return (agp_release_helper(sc, AGP_ACQUIRE_USER)); 2620139788eSmatthieu 2630139788eSmatthieu case AGPIOC_SETUP: 26440d7c10bSoga return (agp_setup_user(sc, (agp_setup *)addr)); 2650139788eSmatthieu 2660139788eSmatthieu case AGPIOC_ALLOCATE: 26740d7c10bSoga return (agp_allocate_user(sc, (agp_allocate *)addr)); 2680139788eSmatthieu 2690139788eSmatthieu case AGPIOC_DEALLOCATE: 27040d7c10bSoga return (agp_deallocate_user(sc, *(int *)addr)); 2710139788eSmatthieu 2720139788eSmatthieu case AGPIOC_BIND: 27340d7c10bSoga return (agp_bind_user(sc, (agp_bind *)addr)); 2740139788eSmatthieu 2750139788eSmatthieu case AGPIOC_UNBIND: 27640d7c10bSoga return (agp_unbind_user(sc, (agp_unbind *)addr)); 27740d7c10bSoga 2780139788eSmatthieu default: 27940d7c10bSoga return (ENOTTY); 2800139788eSmatthieu } 2810139788eSmatthieu 2820139788eSmatthieu } 2830139788eSmatthieu 28440d7c10bSoga int 28540d7c10bSoga agpclose(dev_t dev, int flags, int devtype, struct proc *p) 2860139788eSmatthieu { 287*8f8e4ea1Soga struct agp_softc *sc = agp_find_device(AGPUNIT(dev)); 2880139788eSmatthieu struct agp_memory *mem; 2890139788eSmatthieu 2900139788eSmatthieu /* 29140d7c10bSoga * Clear the GATT and force release on last close 2920139788eSmatthieu */ 29340d7c10bSoga if (sc->sc_state == AGP_ACQUIRE_USER) { 29440d7c10bSoga while ((mem = TAILQ_FIRST(&sc->sc_memory)) != 0) { 29540d7c10bSoga if (mem->am_is_bound) 2960139788eSmatthieu AGP_UNBIND_MEMORY(sc, mem); 2970139788eSmatthieu AGP_FREE_MEMORY(sc, mem); 2980139788eSmatthieu } 29940d7c10bSoga agp_release_helper(sc, AGP_ACQUIRE_USER); 3000139788eSmatthieu } 30140d7c10bSoga sc->sc_opened = 0; 30240d7c10bSoga 30340d7c10bSoga return (0); 30440d7c10bSoga } 3050139788eSmatthieu 3060139788eSmatthieu struct agp_memory * 30740d7c10bSoga agp_find_memory(struct agp_softc *sc, int id) 3080139788eSmatthieu { 3090139788eSmatthieu struct agp_memory *mem; 3100139788eSmatthieu 3110139788eSmatthieu AGP_DPF("searching for memory block %d\n", id); 3120139788eSmatthieu TAILQ_FOREACH(mem, &sc->sc_memory, am_link) { 3130139788eSmatthieu AGP_DPF("considering memory block %d\n", mem->am_id); 3140139788eSmatthieu if (mem->am_id == id) 3150139788eSmatthieu return (mem); 3160139788eSmatthieu } 31740d7c10bSoga return (0); 3180139788eSmatthieu } 3190139788eSmatthieu 3200139788eSmatthieu const struct agp_product * 3210139788eSmatthieu agp_lookup(struct pci_attach_args *pa) 3220139788eSmatthieu { 3230139788eSmatthieu const struct agp_product *ap; 3240139788eSmatthieu 3250139788eSmatthieu /* First find the vendor. */ 3260139788eSmatthieu for (ap = agp_products; ap->ap_attach != NULL; ap++) 3270139788eSmatthieu if (ap->ap_vendor == PCI_VENDOR(pa->pa_id)) 3280139788eSmatthieu break; 3290139788eSmatthieu 3300139788eSmatthieu if (ap->ap_attach == NULL) 3310139788eSmatthieu return (NULL); 3320139788eSmatthieu 3330139788eSmatthieu /* Now find the product within the vendor's domain. */ 3340139788eSmatthieu for (; ap->ap_attach != NULL; ap++) { 3350139788eSmatthieu /* Ran out of this vendor's section of the table. */ 3360139788eSmatthieu if (ap->ap_vendor != PCI_VENDOR(pa->pa_id)) 3370139788eSmatthieu return (NULL); 3380139788eSmatthieu 3390139788eSmatthieu if (ap->ap_product == PCI_PRODUCT(pa->pa_id)) 3400139788eSmatthieu break; /* Exact match. */ 3410139788eSmatthieu if (ap->ap_product == (u_int32_t) -1) 3420139788eSmatthieu break; /* Wildcard match. */ 3430139788eSmatthieu } 3440139788eSmatthieu 3450139788eSmatthieu if (ap->ap_attach == NULL) 3460139788eSmatthieu ap = NULL; 3470139788eSmatthieu 3480139788eSmatthieu return (ap); 3490139788eSmatthieu } 3500139788eSmatthieu 3510139788eSmatthieu int 35240d7c10bSoga agp_map_aperture(struct pci_attach_args *pa, struct agp_softc *sc, u_int32_t bar, u_int32_t memtype) 3530139788eSmatthieu { 354ac9c0c59Sbrad /* Find the aperture. Don't map it (yet), this would eat KVA */ 35540d7c10bSoga if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, 3567f10d90bSreyk memtype, &sc->sc_apaddr, &sc->sc_apsize, 3570139788eSmatthieu &sc->sc_apflags) != 0) 35840d7c10bSoga return (ENXIO); 3590139788eSmatthieu 36040d7c10bSoga return (0); 3610139788eSmatthieu } 3620139788eSmatthieu 3630c73c53fSoga u_int32_t 3640c73c53fSoga agp_generic_get_aperture(struct agp_softc *sc) 3650c73c53fSoga { 3660c73c53fSoga return (sc->sc_apsize); 3670c73c53fSoga } 3680c73c53fSoga 3690c73c53fSoga int 3700c73c53fSoga agp_generic_set_aperture(struct agp_softc *sc, u_int32_t aperture) 3710c73c53fSoga { 3720c73c53fSoga if (aperture != AGP_GET_APERTURE(sc)) 3730c73c53fSoga return (EINVAL); 3740c73c53fSoga 3750c73c53fSoga return (0); 3760c73c53fSoga } 3770c73c53fSoga 3780139788eSmatthieu struct agp_gatt * 37940d7c10bSoga agp_alloc_gatt(struct agp_softc *sc) 3800139788eSmatthieu { 3810139788eSmatthieu u_int32_t apsize = AGP_GET_APERTURE(sc); 3820139788eSmatthieu u_int32_t entries = apsize >> AGP_PAGE_SHIFT; 3830139788eSmatthieu struct agp_gatt *gatt; 3840139788eSmatthieu int nseg; 3850139788eSmatthieu 38640d7c10bSoga gatt = malloc(sizeof(*gatt), M_AGP, M_NOWAIT | M_ZERO); 3870139788eSmatthieu if (!gatt) 3880139788eSmatthieu return (NULL); 3890139788eSmatthieu gatt->ag_entries = entries; 3900139788eSmatthieu 3910139788eSmatthieu if (agp_alloc_dmamem(sc->sc_dmat, entries * sizeof(u_int32_t), 3920139788eSmatthieu 0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual, 3930139788eSmatthieu &gatt->ag_physical, &gatt->ag_dmaseg, 1, &nseg) != 0) 39440d7c10bSoga return (NULL); 3950139788eSmatthieu 3960139788eSmatthieu gatt->ag_size = entries * sizeof(u_int32_t); 3970139788eSmatthieu memset(gatt->ag_virtual, 0, gatt->ag_size); 3980139788eSmatthieu agp_flush_cache(); 3990139788eSmatthieu 40040d7c10bSoga return (gatt); 4010139788eSmatthieu } 4020139788eSmatthieu 4030139788eSmatthieu void 40440d7c10bSoga agp_free_gatt(struct agp_softc *sc, struct agp_gatt *gatt) 4050139788eSmatthieu { 4060139788eSmatthieu agp_free_dmamem(sc->sc_dmat, gatt->ag_size, gatt->ag_dmamap, 4070139788eSmatthieu (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1); 40840d7c10bSoga free(gatt, M_AGP); 4090139788eSmatthieu } 4100139788eSmatthieu 4110139788eSmatthieu int 41240d7c10bSoga agp_generic_detach(struct agp_softc *sc) 4130139788eSmatthieu { 4140139788eSmatthieu agp_flush_cache(); 41540d7c10bSoga return (0); 4160139788eSmatthieu } 4170139788eSmatthieu 4180139788eSmatthieu int 41940d7c10bSoga agp_generic_enable(struct agp_softc *sc, u_int32_t mode) 4200139788eSmatthieu { 4210139788eSmatthieu pcireg_t tstatus, mstatus; 4220139788eSmatthieu pcireg_t command; 4230139788eSmatthieu int rq, sba, fw, rate, capoff; 4240139788eSmatthieu 4250139788eSmatthieu if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP, 4260139788eSmatthieu &capoff, NULL) == 0) { 4270139788eSmatthieu printf("agp_generic_enable: not an AGP capable device\n"); 42840d7c10bSoga return (-1); 4290139788eSmatthieu } 4300139788eSmatthieu 4310139788eSmatthieu tstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag, 4320139788eSmatthieu sc->sc_capoff + AGP_STATUS); 4330139788eSmatthieu mstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag, 4340139788eSmatthieu capoff + AGP_STATUS); 4350139788eSmatthieu 4360139788eSmatthieu /* Set RQ to the min of mode, tstatus and mstatus */ 4370139788eSmatthieu rq = AGP_MODE_GET_RQ(mode); 4380139788eSmatthieu if (AGP_MODE_GET_RQ(tstatus) < rq) 4390139788eSmatthieu rq = AGP_MODE_GET_RQ(tstatus); 4400139788eSmatthieu if (AGP_MODE_GET_RQ(mstatus) < rq) 4410139788eSmatthieu rq = AGP_MODE_GET_RQ(mstatus); 4420139788eSmatthieu 4430139788eSmatthieu /* Set SBA if all three can deal with SBA */ 4440139788eSmatthieu sba = (AGP_MODE_GET_SBA(tstatus) 4450139788eSmatthieu & AGP_MODE_GET_SBA(mstatus) 4460139788eSmatthieu & AGP_MODE_GET_SBA(mode)); 4470139788eSmatthieu 4480139788eSmatthieu /* Similar for FW */ 4490139788eSmatthieu fw = (AGP_MODE_GET_FW(tstatus) 4500139788eSmatthieu & AGP_MODE_GET_FW(mstatus) 4510139788eSmatthieu & AGP_MODE_GET_FW(mode)); 4520139788eSmatthieu 4530139788eSmatthieu /* Figure out the max rate */ 4540139788eSmatthieu rate = (AGP_MODE_GET_RATE(tstatus) 4550139788eSmatthieu & AGP_MODE_GET_RATE(mstatus) 4560139788eSmatthieu & AGP_MODE_GET_RATE(mode)); 4570139788eSmatthieu if (rate & AGP_MODE_RATE_4x) 4580139788eSmatthieu rate = AGP_MODE_RATE_4x; 4590139788eSmatthieu else if (rate & AGP_MODE_RATE_2x) 4600139788eSmatthieu rate = AGP_MODE_RATE_2x; 4610139788eSmatthieu else 4620139788eSmatthieu rate = AGP_MODE_RATE_1x; 4630139788eSmatthieu 4640139788eSmatthieu /* Construct the new mode word and tell the hardware */ 4650139788eSmatthieu command = AGP_MODE_SET_RQ(0, rq); 4660139788eSmatthieu command = AGP_MODE_SET_SBA(command, sba); 4670139788eSmatthieu command = AGP_MODE_SET_FW(command, fw); 4680139788eSmatthieu command = AGP_MODE_SET_RATE(command, rate); 4690139788eSmatthieu command = AGP_MODE_SET_AGP(command, 1); 4700139788eSmatthieu pci_conf_write(sc->sc_pc, sc->sc_pcitag, 4710139788eSmatthieu sc->sc_capoff + AGP_COMMAND, command); 4720139788eSmatthieu pci_conf_write(sc->sc_pc, sc->sc_pcitag, capoff + AGP_COMMAND, command); 47340d7c10bSoga return (0); 4740139788eSmatthieu } 4750139788eSmatthieu 4760139788eSmatthieu struct agp_memory * 47740d7c10bSoga agp_generic_alloc_memory(struct agp_softc *sc, int type, vsize_t size) 4780139788eSmatthieu { 4790139788eSmatthieu struct agp_memory *mem; 4800139788eSmatthieu 4810139788eSmatthieu if (type != 0) { 4820139788eSmatthieu printf("agp_generic_alloc_memory: unsupported type %d\n", type); 48340d7c10bSoga return (0); 4840139788eSmatthieu } 4850139788eSmatthieu 48640d7c10bSoga mem = malloc(sizeof *mem, M_AGP, M_WAITOK | M_ZERO); 4870139788eSmatthieu 4880139788eSmatthieu if (bus_dmamap_create(sc->sc_dmat, size, size / PAGE_SIZE + 1, 4890139788eSmatthieu size, 0, BUS_DMA_NOWAIT, &mem->am_dmamap) != 0) { 49040d7c10bSoga free(mem, M_AGP); 49140d7c10bSoga return (NULL); 4920139788eSmatthieu } 4930139788eSmatthieu 4940139788eSmatthieu mem->am_id = sc->sc_nextid++; 4950139788eSmatthieu mem->am_size = size; 4960139788eSmatthieu TAILQ_INSERT_TAIL(&sc->sc_memory, mem, am_link); 4970139788eSmatthieu sc->sc_allocated += size; 4980139788eSmatthieu 49940d7c10bSoga return (mem); 5000139788eSmatthieu } 5010139788eSmatthieu 5020139788eSmatthieu int 50340d7c10bSoga agp_generic_free_memory(struct agp_softc *sc, struct agp_memory *mem) 5040139788eSmatthieu { 5050139788eSmatthieu if (mem->am_is_bound) 50640d7c10bSoga return (EBUSY); 5070139788eSmatthieu 5080139788eSmatthieu sc->sc_allocated -= mem->am_size; 5090139788eSmatthieu TAILQ_REMOVE(&sc->sc_memory, mem, am_link); 5100139788eSmatthieu bus_dmamap_destroy(sc->sc_dmat, mem->am_dmamap); 51140d7c10bSoga free(mem, M_AGP); 51240d7c10bSoga return (0); 5130139788eSmatthieu } 5140139788eSmatthieu 5150139788eSmatthieu int 51640d7c10bSoga agp_generic_bind_memory(struct agp_softc *sc, struct agp_memory *mem, 5170139788eSmatthieu off_t offset) 5180139788eSmatthieu { 5190139788eSmatthieu bus_dma_segment_t *segs, *seg; 5200139788eSmatthieu bus_size_t done, j; 5210139788eSmatthieu bus_addr_t pa; 5220139788eSmatthieu off_t i, k; 523eabb5cdaSdim int nseg, error; 5240139788eSmatthieu 525f0c692fcSoga rw_enter_write(&sc->sc_lock); 5260139788eSmatthieu 5270139788eSmatthieu if (mem->am_is_bound) { 5280139788eSmatthieu printf("AGP: memory already bound\n"); 529f0c692fcSoga rw_exit_write(&sc->sc_lock); 53040d7c10bSoga return (EINVAL); 5310139788eSmatthieu } 5320139788eSmatthieu 5330139788eSmatthieu if (offset < 0 5340139788eSmatthieu || (offset & (AGP_PAGE_SIZE - 1)) != 0 5350139788eSmatthieu || offset + mem->am_size > AGP_GET_APERTURE(sc)) { 5360139788eSmatthieu printf("AGP: binding memory at bad offset %#lx\n", 5370139788eSmatthieu (unsigned long) offset); 538f0c692fcSoga rw_exit_write(&sc->sc_lock); 53940d7c10bSoga return (EINVAL); 5400139788eSmatthieu } 5410139788eSmatthieu 5420139788eSmatthieu /* 5430139788eSmatthieu * The memory here needs to be directly accessable from the 5440139788eSmatthieu * AGP video card, so it should be allocated using bus_dma. 5450139788eSmatthieu * However, it need not be contiguous, since individual pages 5460139788eSmatthieu * are translated using the GATT. 5470139788eSmatthieu */ 5480139788eSmatthieu 549eabb5cdaSdim nseg = (mem->am_size + PAGE_SIZE - 1) / PAGE_SIZE; 55040d7c10bSoga segs = malloc(nseg * sizeof *segs, M_AGP, M_WAITOK); 5510139788eSmatthieu if ((error = bus_dmamem_alloc(sc->sc_dmat, mem->am_size, PAGE_SIZE, 0, 5520139788eSmatthieu segs, nseg, &mem->am_nseg, BUS_DMA_WAITOK)) != 0) { 55340d7c10bSoga free(segs, M_AGP); 554f0c692fcSoga rw_exit_write(&sc->sc_lock); 5550139788eSmatthieu AGP_DPF("bus_dmamem_alloc failed %d\n", error); 55640d7c10bSoga return (error); 5570139788eSmatthieu } 5580139788eSmatthieu if ((error = bus_dmamem_map(sc->sc_dmat, segs, mem->am_nseg, 5590139788eSmatthieu mem->am_size, &mem->am_virtual, BUS_DMA_WAITOK)) != 0) { 5600139788eSmatthieu bus_dmamem_free(sc->sc_dmat, segs, mem->am_nseg); 56140d7c10bSoga free(segs, M_AGP); 562f0c692fcSoga rw_exit_write(&sc->sc_lock); 5630139788eSmatthieu AGP_DPF("bus_dmamem_map failed %d\n", error); 56440d7c10bSoga return (error); 5650139788eSmatthieu } 5660139788eSmatthieu if ((error = bus_dmamap_load(sc->sc_dmat, mem->am_dmamap, 5670139788eSmatthieu mem->am_virtual, mem->am_size, NULL, 5680139788eSmatthieu BUS_DMA_WAITOK)) != 0) { 5690139788eSmatthieu bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual, 5700139788eSmatthieu mem->am_size); 5710139788eSmatthieu bus_dmamem_free(sc->sc_dmat, segs, mem->am_nseg); 57240d7c10bSoga free(segs, M_AGP); 573f0c692fcSoga rw_exit_write(&sc->sc_lock); 5740139788eSmatthieu AGP_DPF("bus_dmamap_load failed %d\n", error); 57540d7c10bSoga return (error); 5760139788eSmatthieu } 5770139788eSmatthieu mem->am_dmaseg = segs; 5780139788eSmatthieu 5790139788eSmatthieu /* 5800139788eSmatthieu * Bind the individual pages and flush the chipset's 5810139788eSmatthieu * TLB. 5820139788eSmatthieu */ 5830139788eSmatthieu done = 0; 5840139788eSmatthieu for (i = 0; i < mem->am_dmamap->dm_nsegs; i++) { 5850139788eSmatthieu seg = &mem->am_dmamap->dm_segs[i]; 5860139788eSmatthieu /* 5870139788eSmatthieu * Install entries in the GATT, making sure that if 5880139788eSmatthieu * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not 5890139788eSmatthieu * aligned to PAGE_SIZE, we don't modify too many GATT 5900139788eSmatthieu * entries. 5910139788eSmatthieu */ 5920139788eSmatthieu for (j = 0; j < seg->ds_len && (done + j) < mem->am_size; 5930139788eSmatthieu j += AGP_PAGE_SIZE) { 5940139788eSmatthieu pa = seg->ds_addr + j; 5950139788eSmatthieu AGP_DPF("binding offset %#lx to pa %#lx\n", 5960139788eSmatthieu (unsigned long)(offset + done + j), 5970139788eSmatthieu (unsigned long)pa); 5980139788eSmatthieu error = AGP_BIND_PAGE(sc, offset + done + j, pa); 5990139788eSmatthieu if (error) { 6000139788eSmatthieu /* 6010139788eSmatthieu * Bail out. Reverse all the mappings 6020139788eSmatthieu * and unwire the pages. 6030139788eSmatthieu */ 6040139788eSmatthieu for (k = 0; k < done + j; k += AGP_PAGE_SIZE) 6050139788eSmatthieu AGP_UNBIND_PAGE(sc, offset + k); 6060139788eSmatthieu 6070139788eSmatthieu bus_dmamap_unload(sc->sc_dmat, mem->am_dmamap); 6080139788eSmatthieu bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual, 6090139788eSmatthieu mem->am_size); 6100139788eSmatthieu bus_dmamem_free(sc->sc_dmat, mem->am_dmaseg, 6110139788eSmatthieu mem->am_nseg); 61240d7c10bSoga free(mem->am_dmaseg, M_AGP); 613f0c692fcSoga rw_exit_write(&sc->sc_lock); 614eabb5cdaSdim AGP_DPF("AGP_BIND_PAGE failed %d\n", error); 61540d7c10bSoga return (error); 6160139788eSmatthieu } 6170139788eSmatthieu } 6180139788eSmatthieu done += seg->ds_len; 6190139788eSmatthieu } 6200139788eSmatthieu 6210139788eSmatthieu /* 6220139788eSmatthieu * Flush the cpu cache since we are providing a new mapping 6230139788eSmatthieu * for these pages. 6240139788eSmatthieu */ 6250139788eSmatthieu agp_flush_cache(); 6260139788eSmatthieu 6270139788eSmatthieu /* 6280139788eSmatthieu * Make sure the chipset gets the new mappings. 6290139788eSmatthieu */ 6300139788eSmatthieu AGP_FLUSH_TLB(sc); 6310139788eSmatthieu 6320139788eSmatthieu mem->am_offset = offset; 6330139788eSmatthieu mem->am_is_bound = 1; 6340139788eSmatthieu 635f0c692fcSoga rw_exit_write(&sc->sc_lock); 6360139788eSmatthieu 63740d7c10bSoga return (0); 6380139788eSmatthieu } 6390139788eSmatthieu 6400139788eSmatthieu int 64140d7c10bSoga agp_generic_unbind_memory(struct agp_softc *sc, struct agp_memory *mem) 6420139788eSmatthieu { 6430139788eSmatthieu int i; 6440139788eSmatthieu 645f0c692fcSoga rw_enter_write(&sc->sc_lock); 6460139788eSmatthieu 6470139788eSmatthieu if (!mem->am_is_bound) { 6480139788eSmatthieu printf("AGP: memory is not bound\n"); 649f0c692fcSoga rw_exit_write(&sc->sc_lock); 65040d7c10bSoga return (EINVAL); 6510139788eSmatthieu } 6520139788eSmatthieu 6530139788eSmatthieu 6540139788eSmatthieu /* 6550139788eSmatthieu * Unbind the individual pages and flush the chipset's 6560139788eSmatthieu * TLB. Unwire the pages so they can be swapped. 6570139788eSmatthieu */ 6580139788eSmatthieu for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 6590139788eSmatthieu AGP_UNBIND_PAGE(sc, mem->am_offset + i); 6600139788eSmatthieu 6610139788eSmatthieu agp_flush_cache(); 6620139788eSmatthieu AGP_FLUSH_TLB(sc); 6630139788eSmatthieu 6640139788eSmatthieu bus_dmamap_unload(sc->sc_dmat, mem->am_dmamap); 6650139788eSmatthieu bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual, mem->am_size); 6660139788eSmatthieu bus_dmamem_free(sc->sc_dmat, mem->am_dmaseg, mem->am_nseg); 6670139788eSmatthieu 66840d7c10bSoga free(mem->am_dmaseg, M_AGP); 6690139788eSmatthieu 6700139788eSmatthieu mem->am_offset = 0; 6710139788eSmatthieu mem->am_is_bound = 0; 6720139788eSmatthieu 673f0c692fcSoga rw_exit_write(&sc->sc_lock); 6740139788eSmatthieu 67540d7c10bSoga return (0); 6760139788eSmatthieu } 6770139788eSmatthieu 6780139788eSmatthieu int 6790139788eSmatthieu agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, int flags, 6800139788eSmatthieu bus_dmamap_t *mapp, caddr_t *vaddr, bus_addr_t *baddr, 6810139788eSmatthieu bus_dma_segment_t *seg, int nseg, int *rseg) 6820139788eSmatthieu 6830139788eSmatthieu { 6840139788eSmatthieu int error, level = 0; 6850139788eSmatthieu 6860139788eSmatthieu if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0, 6870139788eSmatthieu seg, nseg, rseg, BUS_DMA_NOWAIT)) != 0) 6880139788eSmatthieu goto out; 6890139788eSmatthieu level++; 6900139788eSmatthieu 6910139788eSmatthieu if ((error = bus_dmamem_map(tag, seg, *rseg, size, vaddr, 6920139788eSmatthieu BUS_DMA_NOWAIT | flags)) != 0) 6930139788eSmatthieu goto out; 6940139788eSmatthieu level++; 6950139788eSmatthieu 6960139788eSmatthieu if ((error = bus_dmamap_create(tag, size, *rseg, size, 0, 6970139788eSmatthieu BUS_DMA_NOWAIT, mapp)) != 0) 6980139788eSmatthieu goto out; 6990139788eSmatthieu level++; 7000139788eSmatthieu 7010139788eSmatthieu if ((error = bus_dmamap_load(tag, *mapp, *vaddr, size, NULL, 7020139788eSmatthieu BUS_DMA_NOWAIT)) != 0) 7030139788eSmatthieu goto out; 7040139788eSmatthieu 7050139788eSmatthieu *baddr = (*mapp)->dm_segs[0].ds_addr; 7060139788eSmatthieu 70740d7c10bSoga return (0); 7080139788eSmatthieu out: 7090139788eSmatthieu switch (level) { 7100139788eSmatthieu case 3: 7110139788eSmatthieu bus_dmamap_destroy(tag, *mapp); 7120139788eSmatthieu /* FALLTHROUGH */ 7130139788eSmatthieu case 2: 7140139788eSmatthieu bus_dmamem_unmap(tag, *vaddr, size); 7150139788eSmatthieu /* FALLTHROUGH */ 7160139788eSmatthieu case 1: 7170139788eSmatthieu bus_dmamem_free(tag, seg, *rseg); 7180139788eSmatthieu break; 7190139788eSmatthieu default: 7200139788eSmatthieu break; 7210139788eSmatthieu } 7220139788eSmatthieu 72340d7c10bSoga return (error); 7240139788eSmatthieu } 7250139788eSmatthieu 7260139788eSmatthieu void 7270139788eSmatthieu agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map, 7280139788eSmatthieu caddr_t vaddr, bus_dma_segment_t *seg, int nseg) 7290139788eSmatthieu { 7300139788eSmatthieu 7310139788eSmatthieu bus_dmamap_unload(tag, map); 7320139788eSmatthieu bus_dmamap_destroy(tag, map); 7330139788eSmatthieu bus_dmamem_unmap(tag, vaddr, size); 7340139788eSmatthieu bus_dmamem_free(tag, seg, nseg); 7350139788eSmatthieu } 73640d7c10bSoga 73740d7c10bSoga /* Helper functions used in both user and kernel APIs */ 73840d7c10bSoga 73970456743Soga int 74040d7c10bSoga agp_acquire_helper(void *dev, enum agp_acquire_state state) 74140d7c10bSoga { 74240d7c10bSoga struct agp_softc *sc = (struct agp_softc *)dev; 74340d7c10bSoga 74440d7c10bSoga if (sc->sc_state != AGP_ACQUIRE_FREE) 74540d7c10bSoga return (EBUSY); 74640d7c10bSoga sc->sc_state = state; 74740d7c10bSoga 74840d7c10bSoga return (0); 74940d7c10bSoga } 75040d7c10bSoga 75170456743Soga int 75240d7c10bSoga agp_release_helper(void *dev, enum agp_acquire_state state) 75340d7c10bSoga { 75440d7c10bSoga struct agp_softc *sc = (struct agp_softc *)dev; 75540d7c10bSoga struct agp_memory* mem; 75640d7c10bSoga 75740d7c10bSoga if (sc->sc_state == AGP_ACQUIRE_FREE) 75840d7c10bSoga return (0); 75940d7c10bSoga 76040d7c10bSoga if (sc->sc_state != state) 76140d7c10bSoga return (EBUSY); 76240d7c10bSoga 76340d7c10bSoga /* 76440d7c10bSoga * Clear out the aperture and free any 76540d7c10bSoga * outstanding memory blocks. 76640d7c10bSoga */ 76740d7c10bSoga TAILQ_FOREACH(mem, &sc->sc_memory, am_link) { 76840d7c10bSoga if (mem->am_is_bound) { 76940d7c10bSoga printf("agp_release_helper: mem %d is bound\n", 77040d7c10bSoga mem->am_id); 77140d7c10bSoga AGP_UNBIND_MEMORY(sc, mem); 77240d7c10bSoga } 77340d7c10bSoga } 77440d7c10bSoga sc->sc_state = AGP_ACQUIRE_FREE; 77540d7c10bSoga return (0); 77640d7c10bSoga } 77740d7c10bSoga 77840d7c10bSoga /* Implementation of the userland ioctl API */ 77940d7c10bSoga 78070456743Soga int 78140d7c10bSoga agp_info_user(void *dev, agp_info *info) 78240d7c10bSoga { 78340d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 78440d7c10bSoga 78540d7c10bSoga if (!sc->sc_chipc) 78640d7c10bSoga return (ENXIO); 78740d7c10bSoga 78840d7c10bSoga bzero(info, sizeof *info); 78940d7c10bSoga info->bridge_id = sc->sc_id; 79040d7c10bSoga if (sc->sc_capoff != 0) 79140d7c10bSoga info->agp_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, 79240d7c10bSoga AGP_STATUS + sc->sc_capoff); 79340d7c10bSoga else 79440d7c10bSoga info->agp_mode = 0; /* i810 doesn't have real AGP */ 79540d7c10bSoga info->aper_base = sc->sc_apaddr; 79640d7c10bSoga info->aper_size = AGP_GET_APERTURE(sc) >> 20; 79740d7c10bSoga info->pg_total = 79840d7c10bSoga info->pg_system = sc->sc_maxmem >> AGP_PAGE_SHIFT; 79940d7c10bSoga info->pg_used = sc->sc_allocated >> AGP_PAGE_SHIFT; 80040d7c10bSoga 80140d7c10bSoga return (0); 80240d7c10bSoga } 80340d7c10bSoga 80470456743Soga int 80540d7c10bSoga agp_setup_user(void *dev, agp_setup *setup) 80640d7c10bSoga { 80740d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 808e47997a5Soga 80940d7c10bSoga return (AGP_ENABLE(sc, setup->agp_mode)); 81040d7c10bSoga } 81140d7c10bSoga 81270456743Soga int 81340d7c10bSoga agp_allocate_user(void *dev, agp_allocate *alloc) 81440d7c10bSoga { 81540d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 81640d7c10bSoga struct agp_memory* mem; 81740d7c10bSoga size_t size = alloc->pg_count << AGP_PAGE_SHIFT; 81840d7c10bSoga 81940d7c10bSoga if (sc->sc_allocated + size > sc->sc_maxmem) 82040d7c10bSoga return (EINVAL); 82140d7c10bSoga 82240d7c10bSoga mem = AGP_ALLOC_MEMORY(sc, alloc->type, size); 82340d7c10bSoga if (mem) { 82440d7c10bSoga alloc->key = mem->am_id; 82540d7c10bSoga alloc->physical = mem->am_physical; 82640d7c10bSoga return (0); 82740d7c10bSoga } else 82840d7c10bSoga return (ENOMEM); 82940d7c10bSoga } 83040d7c10bSoga 83170456743Soga int 83240d7c10bSoga agp_deallocate_user(void *dev, int id) 83340d7c10bSoga { 83440d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 83540d7c10bSoga struct agp_memory *mem = agp_find_memory(sc, id); 83640d7c10bSoga if (mem) { 83740d7c10bSoga AGP_FREE_MEMORY(sc, mem); 83840d7c10bSoga return (0); 83940d7c10bSoga } else 84040d7c10bSoga return (ENOENT); 84140d7c10bSoga } 84240d7c10bSoga 84370456743Soga int 84440d7c10bSoga agp_bind_user(void *dev, agp_bind *bind) 84540d7c10bSoga { 84640d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 84740d7c10bSoga struct agp_memory *mem = agp_find_memory(sc, bind->key); 84840d7c10bSoga 84940d7c10bSoga if (!mem) 85040d7c10bSoga return (ENOENT); 85140d7c10bSoga 85240d7c10bSoga return (AGP_BIND_MEMORY(sc, mem, bind->pg_start << AGP_PAGE_SHIFT)); 85340d7c10bSoga } 85440d7c10bSoga 85540d7c10bSoga 85670456743Soga int 85740d7c10bSoga agp_unbind_user(void *dev, agp_unbind *unbind) 85840d7c10bSoga { 85940d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 86040d7c10bSoga struct agp_memory *mem = agp_find_memory(sc, unbind->key); 86140d7c10bSoga 86240d7c10bSoga if (!mem) 86340d7c10bSoga return (ENOENT); 86440d7c10bSoga 86540d7c10bSoga return (AGP_UNBIND_MEMORY(sc, mem)); 86640d7c10bSoga } 86740d7c10bSoga 86840d7c10bSoga /* Implementation of the kernel api */ 86940d7c10bSoga 87040d7c10bSoga void * 87140d7c10bSoga agp_find_device(int unit) 87240d7c10bSoga { 873*8f8e4ea1Soga if (unit >= agp_cd.cd_ndevs || unit < 0) 874*8f8e4ea1Soga return (NULL); 875*8f8e4ea1Soga return (agp_cd.cd_devs[unit]); 87640d7c10bSoga } 87740d7c10bSoga 87840d7c10bSoga enum agp_acquire_state 87940d7c10bSoga agp_state(void *dev) 88040d7c10bSoga { 88140d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 88240d7c10bSoga return (sc->sc_state); 88340d7c10bSoga } 88440d7c10bSoga 88540d7c10bSoga void 88640d7c10bSoga agp_get_info(void *dev, struct agp_info *info) 88740d7c10bSoga { 88840d7c10bSoga struct agp_softc *sc = (struct agp_softc *)dev; 88940d7c10bSoga 89040d7c10bSoga info->ai_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, 89140d7c10bSoga sc->sc_capoff + AGP_STATUS); 89240d7c10bSoga info->ai_aperture_base = sc->sc_apaddr; 89340d7c10bSoga info->ai_aperture_size = sc->sc_apsize; 89440d7c10bSoga info->ai_memory_allowed = sc->sc_maxmem; 89540d7c10bSoga info->ai_memory_used = sc->sc_allocated; 89640d7c10bSoga } 89740d7c10bSoga 89840d7c10bSoga int 89940d7c10bSoga agp_acquire(void *dev) 90040d7c10bSoga { 90140d7c10bSoga struct agp_softc *sc = (struct agp_softc *)dev; 902e47997a5Soga 90340d7c10bSoga return (agp_acquire_helper(sc, AGP_ACQUIRE_KERNEL)); 90440d7c10bSoga } 90540d7c10bSoga 90640d7c10bSoga int 90740d7c10bSoga agp_release(void *dev) 90840d7c10bSoga { 90940d7c10bSoga struct agp_softc *sc = (struct agp_softc *)dev; 910e47997a5Soga 91140d7c10bSoga return (agp_release_helper(sc, AGP_ACQUIRE_KERNEL)); 91240d7c10bSoga } 91340d7c10bSoga 91440d7c10bSoga int 91540d7c10bSoga agp_enable(void *dev, u_int32_t mode) 91640d7c10bSoga { 91740d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 918e47997a5Soga 91940d7c10bSoga return (AGP_ENABLE(sc, mode)); 92040d7c10bSoga } 92140d7c10bSoga 922e47997a5Soga void * 923e47997a5Soga agp_alloc_memory(void *dev, int type, vsize_t bytes) 92440d7c10bSoga { 92540d7c10bSoga struct agp_softc *sc = (struct agp_softc *)dev; 926e47997a5Soga 92740d7c10bSoga return ((void *) AGP_ALLOC_MEMORY(sc, type, bytes)); 92840d7c10bSoga } 92940d7c10bSoga 930e47997a5Soga void 931e47997a5Soga agp_free_memory(void *dev, void *handle) 93240d7c10bSoga { 93340d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 93440d7c10bSoga struct agp_memory *mem = (struct agp_memory *) handle; 935e47997a5Soga 93640d7c10bSoga AGP_FREE_MEMORY(sc, mem); 93740d7c10bSoga } 93840d7c10bSoga 939e47997a5Soga int 940e47997a5Soga agp_bind_memory(void *dev, void *handle, off_t offset) 94140d7c10bSoga { 94240d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 94340d7c10bSoga struct agp_memory *mem = (struct agp_memory *) handle; 944e47997a5Soga 94540d7c10bSoga return (AGP_BIND_MEMORY(sc, mem, offset)); 94640d7c10bSoga } 94740d7c10bSoga 948e47997a5Soga int 949e47997a5Soga agp_unbind_memory(void *dev, void *handle) 95040d7c10bSoga { 95140d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev; 95240d7c10bSoga struct agp_memory *mem = (struct agp_memory *) handle; 953e47997a5Soga 95440d7c10bSoga return (AGP_UNBIND_MEMORY(sc, mem)); 95540d7c10bSoga } 95640d7c10bSoga 957e47997a5Soga void 958e47997a5Soga agp_memory_info(void *dev, void *handle, struct 95940d7c10bSoga agp_memory_info *mi) 96040d7c10bSoga { 96140d7c10bSoga struct agp_memory *mem = (struct agp_memory *) handle; 96240d7c10bSoga 96340d7c10bSoga mi->ami_size = mem->am_size; 96440d7c10bSoga mi->ami_physical = mem->am_physical; 96540d7c10bSoga mi->ami_offset = mem->am_offset; 96640d7c10bSoga mi->ami_is_bound = mem->am_is_bound; 96740d7c10bSoga } 968