diff options
Diffstat (limited to 'sys/dev/pci/agp.c')
-rw-r--r-- | sys/dev/pci/agp.c | 606 |
1 files changed, 411 insertions, 195 deletions
diff --git a/sys/dev/pci/agp.c b/sys/dev/pci/agp.c index 52faa49e477..6c500c11bd2 100644 --- a/sys/dev/pci/agp.c +++ b/sys/dev/pci/agp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: agp.c,v 1.7 2007/09/17 01:33:33 krw Exp $ */ +/* $OpenBSD: agp.c,v 1.8 2007/11/25 17:11:12 oga Exp $ */ /*- * Copyright (c) 2000 Doug Rabson * All rights reserved. @@ -36,6 +36,7 @@ #include <uvm/uvm.h> #include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> #include <dev/ic/mc6845reg.h> #include <dev/ic/pcdisplayvar.h> @@ -45,17 +46,88 @@ #include <dev/pci/agpvar.h> #include <dev/pci/agpreg.h> -struct agp_memory *agp_find_memory(struct vga_pci_softc *sc, int id); +#include "agp_ali.h" +#include "agp_amd.h" +#include "agp_amd64.h" +#include "agp_apple.h" +#include "agp_i810.h" +#include "agp_intel.h" +#include "agp_sis.h" +#include "agp_via.h" + +struct agp_memory *agp_find_memory(struct agp_softc *sc, int id); const struct agp_product *agp_lookup(struct pci_attach_args *pa); +/* userland ioctl functions */ +static int agp_info_user(void *, agp_info *); +static int agp_setup_user(void *, agp_setup *); +static int agp_allocate_user(void *, agp_allocate *); +static int agp_deallocate_user(void *, int); +static int agp_bind_user(void *, agp_bind *); +static int agp_unbind_user(void *, agp_unbind *); +static int agp_acquire_helper(void *dev, enum agp_acquire_state state); +static int agp_release_helper(void *dev, enum agp_acquire_state state); + +const struct agp_product agp_products[] = { +#if NAGP_ALI > 0 + { PCI_VENDOR_ALI, -1, agp_ali_attach }, +#endif +#if NAGP_AMD > 0 + { PCI_VENDOR_AMD, -1, agp_amd_attach }, +#endif +#if NAGP_I810 > 0 + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_MCH, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_DC100_MCH, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810E_MCH, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82815_FULL_HUB, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82840_HB, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82830MP_IO_1, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82845G, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82852GM_HPB, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82865_IO_1, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82915G_HB, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82915GM_HB, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82945GP_MCH, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82945GM_MCH, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82Q963_HB, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82965_MCH, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82915G_IV, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82915GM_IGD, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82945G_IGD_1, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82945GM_IGD, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82965_IGD_1, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82965GM_IGD_1, agp_i810_attach }, +#endif +#if NAGP_INTEL > 0 + { PCI_VENDOR_INTEL, -1, agp_intel_attach }, +#endif +#if NAGP_SIS > 0 + { PCI_VENDOR_SIS, -1, agp_sis_attach }, +#endif +#if NAGP_VIA > 0 + { PCI_VENDOR_VIATECH, -1, agp_via_attach }, +#endif + { 0, 0, NULL } +}; -struct pci_attach_args agp_pchb_pa; -int agp_pchb_pa_set = 0; + +static int +agp_probe(struct device *parent, void *match, void *aux) +{ + struct agpbus_attach_args *aaa = aux; + struct pci_attach_args *pa = &aaa->apa_pci_args; + + if (agp_lookup(pa) == NULL) + return (0); + + return (1); +} void agp_attach(struct device *parent, struct device *self, void *aux) { - struct pci_attach_args *pa = aux; - struct vga_pci_softc *sc = (struct vga_pci_softc *)self; + struct agpbus_attach_args *aaa = aux; + struct pci_attach_args *pa = &aaa->apa_pci_args; + struct agp_softc *sc = (struct agp_softc *)self; const struct agp_product *ap; u_int memsize; int i, ret; @@ -104,7 +176,7 @@ agp_attach(struct device *parent, struct device *self, void *aux) pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP, &sc->sc_capoff, NULL); - ret = (*ap->ap_attach)(sc, pa, &agp_pchb_pa); + ret = (*ap->ap_attach)(sc, pa); if (ret == 0) printf(": aperture at 0x%lx, size 0x%lx", (u_long)sc->sc_apaddr, @@ -116,183 +188,123 @@ agp_attach(struct device *parent, struct device *self, void *aux) } } +struct cfattach agp_ca = { + sizeof (struct agp_softc), agp_probe, agp_attach, + NULL, NULL +}; + +struct cfdriver agp_cd = { + NULL, "agp", DV_DULL +}; + paddr_t -agp_mmap(void *v, off_t off, int prot) +agpmmap(void *v, off_t off, int prot) { - struct vga_config* vs = (struct vga_config*) v; - struct vga_pci_softc* sc = (struct vga_pci_softc *)vs->vc_softc; + struct agp_softc* sc = (struct agp_softc *)v; if (sc->sc_apaddr) { if (off > AGP_GET_APERTURE(sc)) return (-1); + /* + * XXX this should use bus_space_mmap() but it's not + * availiable on all archs. + */ return atop(sc->sc_apaddr + off); } - return -1; + return (-1); } +int agpopen(dev_t dev , int oflags, int devtype, struct proc * p) +{ + struct agp_softc *sc = (struct agp_softc *)device_lookup(&agp_cd, AGPUNIT(dev)); + + if (sc == NULL) + return (ENXIO); + + if (sc->sc_chipc == NULL) + return (ENXIO); + + if (!sc->sc_opened) + sc->sc_opened = 1; + else + return (EBUSY); + + return (0); +} + + int -agp_ioctl(void *v, u_long cmd, caddr_t addr, int flag, struct proc *pb) +agpioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *pb) { - struct vga_config *vc = v; - struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc; - struct agp_memory *mem; - agp_info *info; - agp_setup *setup; - agp_allocate *alloc; - agp_bind *bind; - agp_unbind *unbind; - vsize_t size; - int error = 0; + struct agp_softc *sc = (struct agp_softc *)device_lookup(&agp_cd, AGPUNIT(dev)); + + if (sc ==NULL) + return (ENODEV); if (sc->sc_methods == NULL || sc->sc_chipc == NULL) return (ENXIO); + + if (cmd != AGPIOC_INFO && !(flag & FWRITE)) + return (EPERM); - switch (cmd) { - case AGPIOC_INFO: - if (!sc->sc_chipc) - return (ENXIO); - case AGPIOC_ACQUIRE: - case AGPIOC_RELEASE: - case AGPIOC_SETUP: - case AGPIOC_ALLOCATE: - case AGPIOC_DEALLOCATE: - case AGPIOC_BIND: - case AGPIOC_UNBIND: - if (cmd != AGPIOC_INFO && !(flag & FWRITE)) - return (EPERM); - break; - } switch(cmd) { case AGPIOC_INFO: - info = (agp_info *)addr; - bzero(info, sizeof *info); - info->bridge_id = sc->sc_id; - if (sc->sc_capoff != 0) - info->agp_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, - AGP_STATUS + sc->sc_capoff); - else - info->agp_mode = 0; /* i810 doesn't have real AGP */ - info->aper_base = sc->sc_apaddr; - info->aper_size = AGP_GET_APERTURE(sc) >> 20; - info->pg_total = - info->pg_system = sc->sc_maxmem >> AGP_PAGE_SHIFT; - info->pg_used = sc->sc_allocated >> AGP_PAGE_SHIFT; - break; + return (agp_info_user(sc, (agp_info *)addr)); case AGPIOC_ACQUIRE: - if (sc->sc_state != AGP_ACQUIRE_FREE) - error = EBUSY; - else - sc->sc_state = AGP_ACQUIRE_USER; - break; + return (agp_acquire_helper(sc, AGP_ACQUIRE_USER)); case AGPIOC_RELEASE: - if (sc->sc_state == AGP_ACQUIRE_FREE) - break; - - if (sc->sc_state != AGP_ACQUIRE_USER) { - error = EBUSY; - break; - } - - /* - * Clear out the aperture and free any - * outstanding memory blocks. - */ - TAILQ_FOREACH(mem, &sc->sc_memory, am_link) { - if (mem->am_is_bound) { - printf("agp_release_helper: mem %d is bound\n", - mem->am_id); - AGP_UNBIND_MEMORY(sc, mem); - } - } - sc->sc_state = AGP_ACQUIRE_FREE; - break; + return (agp_release_helper(sc, AGP_ACQUIRE_USER)); case AGPIOC_SETUP: - setup = (agp_setup *)addr; - error = AGP_ENABLE(sc, setup->agp_mode); - break; + return (agp_setup_user(sc, (agp_setup *)addr)); case AGPIOC_ALLOCATE: - alloc = (agp_allocate *)addr; - size = alloc->pg_count << AGP_PAGE_SHIFT; - if (sc->sc_allocated + size > sc->sc_maxmem) - error = EINVAL; - else { - mem = AGP_ALLOC_MEMORY(sc, alloc->type, size); - if (mem) { - alloc->key = mem->am_id; - alloc->physical = mem->am_physical; - } else - error = ENOMEM; - } - break; + return (agp_allocate_user(sc, (agp_allocate *)addr)); case AGPIOC_DEALLOCATE: - mem = agp_find_memory(sc, *(int *)addr); - if (mem) - AGP_FREE_MEMORY(sc, mem); - else - error = ENOENT; - break; + return (agp_deallocate_user(sc, *(int *)addr)); case AGPIOC_BIND: - bind = (agp_bind *)addr; - mem = agp_find_memory(sc, bind->key); - if (!mem) - error = ENOENT; - else - error = AGP_BIND_MEMORY(sc, mem, - bind->pg_start << AGP_PAGE_SHIFT); - break; + return (agp_bind_user(sc, (agp_bind *)addr)); case AGPIOC_UNBIND: - unbind = (agp_unbind *)addr; - mem = agp_find_memory(sc, unbind->key); - if (!mem) - error = ENOENT; - else - error = AGP_UNBIND_MEMORY(sc, mem); - break; + return (agp_unbind_user(sc, (agp_unbind *)addr)); + default: - error = ENOTTY; + return (ENOTTY); } - return (error); } -#ifdef notyet -void -agp_close(void *v) +int +agpclose(dev_t dev, int flags, int devtype, struct proc *p) { - struct vga_config *vc = v; - struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc; + struct agp_softc *sc = + (struct agp_softc *)device_lookup(&agp_cd, AGPUNIT(dev)); struct agp_memory *mem; /* - * Clear out the aperture and free any - * outstanding memory blocks. - */ - TAILQ_FOREACH(mem, &sc->sc_memory, am_link) { - if (mem->am_is_bound) { - AGP_UNBIND_MEMORY(sc, mem); + * Clear the GATT and force release on last close + */ + if (sc->sc_state == AGP_ACQUIRE_USER) { + while ((mem = TAILQ_FIRST(&sc->sc_memory)) != 0) { + if (mem->am_is_bound) + AGP_UNBIND_MEMORY(sc, mem); + AGP_FREE_MEMORY(sc, mem); } + agp_release_helper(sc, AGP_ACQUIRE_USER); } + sc->sc_opened = 0; - while (!TAILQ_EMPTY(&sc->sc_memory)) { - mem = TAILQ_FIRST(&sc->sc_memory); - AGP_FREE_MEMORY(sc, mem); - } - - sc->sc_state = AGP_ACQUIRE_FREE; + return (0); } -#endif struct agp_memory * -agp_find_memory(struct vga_pci_softc *sc, int id) +agp_find_memory(struct agp_softc *sc, int id) { struct agp_memory *mem; @@ -302,7 +314,7 @@ agp_find_memory(struct vga_pci_softc *sc, int id) if (mem->am_id == id) return (mem); } - return 0; + return (0); } const struct agp_product * @@ -310,10 +322,6 @@ agp_lookup(struct pci_attach_args *pa) { const struct agp_product *ap; - if (!agp_pchb_pa_set) - return (NULL); - agp_pchb_pa_set = 0; - /* First find the vendor. */ for (ap = agp_products; ap->ap_attach != NULL; ap++) if (ap->ap_vendor == PCI_VENDOR(pa->pa_id)) @@ -340,39 +348,30 @@ agp_lookup(struct pci_attach_args *pa) return (ap); } -void -pciagp_set_pchb(struct pci_attach_args *pa) -{ - if (!agp_pchb_pa_set) { - memcpy(&agp_pchb_pa, pa, sizeof *pa); - agp_pchb_pa_set++; - } -} - int -agp_map_aperture(struct vga_pci_softc *sc, u_int32_t bar, u_int32_t memtype) +agp_map_aperture(struct pci_attach_args *pa, struct agp_softc *sc, u_int32_t bar, u_int32_t memtype) { /* * Find and the aperture. Don't map it (yet), this would * eat KVA. */ - if (pci_mapreg_info(sc->sc_pc, sc->sc_pcitag, bar, + if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, memtype, &sc->sc_apaddr, &sc->sc_apsize, &sc->sc_apflags) != 0) - return ENXIO; + return (ENXIO); - return 0; + return (0); } struct agp_gatt * -agp_alloc_gatt(struct vga_pci_softc *sc) +agp_alloc_gatt(struct agp_softc *sc) { u_int32_t apsize = AGP_GET_APERTURE(sc); u_int32_t entries = apsize >> AGP_PAGE_SHIFT; struct agp_gatt *gatt; int nseg; - gatt = malloc(sizeof(*gatt), M_DEVBUF, M_NOWAIT | M_ZERO); + gatt = malloc(sizeof(*gatt), M_AGP, M_NOWAIT | M_ZERO); if (!gatt) return (NULL); gatt->ag_entries = entries; @@ -380,33 +379,33 @@ agp_alloc_gatt(struct vga_pci_softc *sc) if (agp_alloc_dmamem(sc->sc_dmat, entries * sizeof(u_int32_t), 0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual, &gatt->ag_physical, &gatt->ag_dmaseg, 1, &nseg) != 0) - return NULL; + return (NULL); gatt->ag_size = entries * sizeof(u_int32_t); memset(gatt->ag_virtual, 0, gatt->ag_size); agp_flush_cache(); - return gatt; + return (gatt); } void -agp_free_gatt(struct vga_pci_softc *sc, struct agp_gatt *gatt) +agp_free_gatt(struct agp_softc *sc, struct agp_gatt *gatt) { agp_free_dmamem(sc->sc_dmat, gatt->ag_size, gatt->ag_dmamap, (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1); - free(gatt, M_DEVBUF); + free(gatt, M_AGP); } int -agp_generic_detach(struct vga_pci_softc *sc) +agp_generic_detach(struct agp_softc *sc) { lockmgr(&sc->sc_lock, LK_DRAIN, NULL); agp_flush_cache(); - return 0; + return (0); } int -agp_generic_enable(struct vga_pci_softc *sc, u_int32_t mode) +agp_generic_enable(struct agp_softc *sc, u_int32_t mode) { pcireg_t tstatus, mstatus; pcireg_t command; @@ -415,7 +414,7 @@ agp_generic_enable(struct vga_pci_softc *sc, u_int32_t mode) if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP, &capoff, NULL) == 0) { printf("agp_generic_enable: not an AGP capable device\n"); - return -1; + return (-1); } tstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag, @@ -460,27 +459,27 @@ agp_generic_enable(struct vga_pci_softc *sc, u_int32_t mode) pci_conf_write(sc->sc_pc, sc->sc_pcitag, sc->sc_capoff + AGP_COMMAND, command); pci_conf_write(sc->sc_pc, sc->sc_pcitag, capoff + AGP_COMMAND, command); - return 0; + return (0); } struct agp_memory * -agp_generic_alloc_memory(struct vga_pci_softc *sc, int type, vsize_t size) +agp_generic_alloc_memory(struct agp_softc *sc, int type, vsize_t size) { struct agp_memory *mem; if (type != 0) { printf("agp_generic_alloc_memory: unsupported type %d\n", type); - return 0; + return (0); } - mem = malloc(sizeof *mem, M_DEVBUF, M_WAITOK | M_ZERO); + mem = malloc(sizeof *mem, M_AGP, M_WAITOK | M_ZERO); if (mem == NULL) - return NULL; + return (NULL); if (bus_dmamap_create(sc->sc_dmat, size, size / PAGE_SIZE + 1, size, 0, BUS_DMA_NOWAIT, &mem->am_dmamap) != 0) { - free(mem, M_DEVBUF); - return NULL; + free(mem, M_AGP); + return (NULL); } mem->am_id = sc->sc_nextid++; @@ -488,24 +487,24 @@ agp_generic_alloc_memory(struct vga_pci_softc *sc, int type, vsize_t size) TAILQ_INSERT_TAIL(&sc->sc_memory, mem, am_link); sc->sc_allocated += size; - return mem; + return (mem); } int -agp_generic_free_memory(struct vga_pci_softc *sc, struct agp_memory *mem) +agp_generic_free_memory(struct agp_softc *sc, struct agp_memory *mem) { if (mem->am_is_bound) - return EBUSY; + return (EBUSY); sc->sc_allocated -= mem->am_size; TAILQ_REMOVE(&sc->sc_memory, mem, am_link); bus_dmamap_destroy(sc->sc_dmat, mem->am_dmamap); - free(mem, M_DEVBUF); - return 0; + free(mem, M_AGP); + return (0); } int -agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, +agp_generic_bind_memory(struct agp_softc *sc, struct agp_memory *mem, off_t offset) { bus_dma_segment_t *segs, *seg; @@ -519,7 +518,7 @@ agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, if (mem->am_is_bound) { printf("AGP: memory already bound\n"); lockmgr(&sc->sc_lock, LK_RELEASE, NULL); - return EINVAL; + return (EINVAL); } if (offset < 0 @@ -528,7 +527,7 @@ agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, printf("AGP: binding memory at bad offset %#lx\n", (unsigned long) offset); lockmgr(&sc->sc_lock, LK_RELEASE, NULL); - return EINVAL; + return (EINVAL); } /* @@ -539,27 +538,27 @@ agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, */ nseg = (mem->am_size + PAGE_SIZE - 1) / PAGE_SIZE; - segs = malloc(nseg * sizeof *segs, M_DEVBUF, M_WAITOK); + segs = malloc(nseg * sizeof *segs, M_AGP, M_WAITOK); if (segs == NULL) { lockmgr(&sc->sc_lock, LK_RELEASE, NULL); AGP_DPF("malloc segs (%u) failed\n", nseg * sizeof *segs); - return ENOMEM; + return (ENOMEM); } if ((error = bus_dmamem_alloc(sc->sc_dmat, mem->am_size, PAGE_SIZE, 0, segs, nseg, &mem->am_nseg, BUS_DMA_WAITOK)) != 0) { - free(segs, M_DEVBUF); + free(segs, M_AGP); lockmgr(&sc->sc_lock, LK_RELEASE, NULL); AGP_DPF("bus_dmamem_alloc failed %d\n", error); - return error; + return (error); } if ((error = bus_dmamem_map(sc->sc_dmat, segs, mem->am_nseg, mem->am_size, &mem->am_virtual, BUS_DMA_WAITOK)) != 0) { bus_dmamem_free(sc->sc_dmat, segs, mem->am_nseg); - free(segs, M_DEVBUF); + free(segs, M_AGP); lockmgr(&sc->sc_lock, LK_RELEASE, NULL); AGP_DPF("bus_dmamem_map failed %d\n", error); - return error; + return (error); } if ((error = bus_dmamap_load(sc->sc_dmat, mem->am_dmamap, mem->am_virtual, mem->am_size, NULL, @@ -567,10 +566,10 @@ agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual, mem->am_size); bus_dmamem_free(sc->sc_dmat, segs, mem->am_nseg); - free(segs, M_DEVBUF); + free(segs, M_AGP); lockmgr(&sc->sc_lock, LK_RELEASE, NULL); AGP_DPF("bus_dmamap_load failed %d\n", error); - return error; + return (error); } mem->am_dmaseg = segs; @@ -607,10 +606,10 @@ agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, mem->am_size); bus_dmamem_free(sc->sc_dmat, mem->am_dmaseg, mem->am_nseg); - free(mem->am_dmaseg, M_DEVBUF); + free(mem->am_dmaseg, M_AGP); lockmgr(&sc->sc_lock, LK_RELEASE, NULL); AGP_DPF("AGP_BIND_PAGE failed %d\n", error); - return error; + return (error); } } done += seg->ds_len; @@ -632,11 +631,11 @@ agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, lockmgr(&sc->sc_lock, LK_RELEASE, NULL); - return 0; + return (0); } int -agp_generic_unbind_memory(struct vga_pci_softc *sc, struct agp_memory *mem) +agp_generic_unbind_memory(struct agp_softc *sc, struct agp_memory *mem) { int i; @@ -645,7 +644,7 @@ agp_generic_unbind_memory(struct vga_pci_softc *sc, struct agp_memory *mem) if (!mem->am_is_bound) { printf("AGP: memory is not bound\n"); lockmgr(&sc->sc_lock, LK_RELEASE, NULL); - return EINVAL; + return (EINVAL); } @@ -663,14 +662,14 @@ agp_generic_unbind_memory(struct vga_pci_softc *sc, struct agp_memory *mem) bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual, mem->am_size); bus_dmamem_free(sc->sc_dmat, mem->am_dmaseg, mem->am_nseg); - free(mem->am_dmaseg, M_DEVBUF); + free(mem->am_dmaseg, M_AGP); mem->am_offset = 0; mem->am_is_bound = 0; lockmgr(&sc->sc_lock, LK_RELEASE, NULL); - return 0; + return (0); } int @@ -702,7 +701,7 @@ agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, int flags, *baddr = (*mapp)->dm_segs[0].ds_addr; - return 0; + return (0); out: switch (level) { case 3: @@ -718,7 +717,7 @@ out: break; } - return error; + return (error); } void @@ -731,3 +730,220 @@ agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map, bus_dmamem_unmap(tag, vaddr, size); bus_dmamem_free(tag, seg, nseg); } + +/* Helper functions used in both user and kernel APIs */ + +static int +agp_acquire_helper(void *dev, enum agp_acquire_state state) +{ + struct agp_softc *sc = (struct agp_softc *)dev; + + if (sc->sc_state != AGP_ACQUIRE_FREE) + return (EBUSY); + sc->sc_state = state; + + return (0); +} + +static int +agp_release_helper(void *dev, enum agp_acquire_state state) +{ + struct agp_softc *sc = (struct agp_softc *)dev; + struct agp_memory* mem; + + if (sc->sc_state == AGP_ACQUIRE_FREE) + return (0); + + if (sc->sc_state != state) + return (EBUSY); + + /* + * Clear out the aperture and free any + * outstanding memory blocks. + */ + TAILQ_FOREACH(mem, &sc->sc_memory, am_link) { + if (mem->am_is_bound) { + printf("agp_release_helper: mem %d is bound\n", + mem->am_id); + AGP_UNBIND_MEMORY(sc, mem); + } + } + sc->sc_state = AGP_ACQUIRE_FREE; + return (0); +} + +/* Implementation of the userland ioctl API */ + +static int +agp_info_user(void *dev, agp_info *info) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + + if (!sc->sc_chipc) + return (ENXIO); + + bzero(info, sizeof *info); + info->bridge_id = sc->sc_id; + if (sc->sc_capoff != 0) + info->agp_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, + AGP_STATUS + sc->sc_capoff); + else + info->agp_mode = 0; /* i810 doesn't have real AGP */ + info->aper_base = sc->sc_apaddr; + info->aper_size = AGP_GET_APERTURE(sc) >> 20; + info->pg_total = + info->pg_system = sc->sc_maxmem >> AGP_PAGE_SHIFT; + info->pg_used = sc->sc_allocated >> AGP_PAGE_SHIFT; + + return (0); +} + +static int +agp_setup_user(void *dev, agp_setup *setup) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + return (AGP_ENABLE(sc, setup->agp_mode)); +} + +static int +agp_allocate_user(void *dev, agp_allocate *alloc) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + struct agp_memory* mem; + size_t size = alloc->pg_count << AGP_PAGE_SHIFT; + + if (sc->sc_allocated + size > sc->sc_maxmem) + return (EINVAL); + + mem = AGP_ALLOC_MEMORY(sc, alloc->type, size); + if (mem) { + alloc->key = mem->am_id; + alloc->physical = mem->am_physical; + return (0); + } else + return (ENOMEM); +} + +static int +agp_deallocate_user(void *dev, int id) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + struct agp_memory *mem = agp_find_memory(sc, id); + if (mem) { + AGP_FREE_MEMORY(sc, mem); + return (0); + } else + return (ENOENT); +} + +static int +agp_bind_user(void *dev, agp_bind *bind) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + struct agp_memory *mem = agp_find_memory(sc, bind->key); + + if (!mem) + return (ENOENT); + + return (AGP_BIND_MEMORY(sc, mem, bind->pg_start << AGP_PAGE_SHIFT)); +} + + +static int +agp_unbind_user(void *dev, agp_unbind *unbind) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + struct agp_memory *mem = agp_find_memory(sc, unbind->key); + + if (!mem) + return (ENOENT); + + return (AGP_UNBIND_MEMORY(sc, mem)); +} + +/* Implementation of the kernel api */ + +void * +agp_find_device(int unit) +{ + return (device_lookup(&agp_cd, unit)); +} + +enum agp_acquire_state +agp_state(void *dev) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + return (sc->sc_state); +} + +void +agp_get_info(void *dev, struct agp_info *info) +{ + struct agp_softc *sc = (struct agp_softc *)dev; + + info->ai_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, + sc->sc_capoff + AGP_STATUS); + info->ai_aperture_base = sc->sc_apaddr; + info->ai_aperture_size = sc->sc_apsize; + info->ai_memory_allowed = sc->sc_maxmem; + info->ai_memory_used = sc->sc_allocated; +} + +int +agp_acquire(void *dev) +{ + struct agp_softc *sc = (struct agp_softc *)dev; + return (agp_acquire_helper(sc, AGP_ACQUIRE_KERNEL)); +} + +int +agp_release(void *dev) +{ + struct agp_softc *sc = (struct agp_softc *)dev; + return (agp_release_helper(sc, AGP_ACQUIRE_KERNEL)); +} + +int +agp_enable(void *dev, u_int32_t mode) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + return (AGP_ENABLE(sc, mode)); +} + +void *agp_alloc_memory(void *dev, int type, vsize_t bytes) +{ + struct agp_softc *sc = (struct agp_softc *)dev; + return ((void *) AGP_ALLOC_MEMORY(sc, type, bytes)); +} + +void agp_free_memory(void *dev, void *handle) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + struct agp_memory *mem = (struct agp_memory *) handle; + AGP_FREE_MEMORY(sc, mem); +} + +int agp_bind_memory(void *dev, void *handle, off_t offset) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + struct agp_memory *mem = (struct agp_memory *) handle; + return (AGP_BIND_MEMORY(sc, mem, offset)); +} + +int agp_unbind_memory(void *dev, void *handle) +{ + struct agp_softc *sc = (struct agp_softc *) dev; + struct agp_memory *mem = (struct agp_memory *) handle; + return (AGP_UNBIND_MEMORY(sc, mem)); +} + +void agp_memory_info(void *dev, void *handle, struct + agp_memory_info *mi) +{ + struct agp_memory *mem = (struct agp_memory *) handle; + + mi->ami_size = mem->am_size; + mi->ami_physical = mem->am_physical; + mi->ami_offset = mem->am_offset; + mi->ami_is_bound = mem->am_is_bound; +} |