[BACK]Return to agp.c CVS log [TXT][DIR] Up to [local] / sys / dev / pci

Annotation of sys/dev/pci/agp.c, Revision 1.1.1.1

1.1       nbrk        1: /* $OpenBSD: agp.c,v 1.6 2007/08/04 19:40:25 reyk Exp $ */
                      2: /*-
                      3:  * Copyright (c) 2000 Doug Rabson
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     16:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     17:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     18:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     19:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     20:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     21:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     22:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     23:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     24:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     25:  * SUCH DAMAGE.
                     26:  *
                     27:  *     $FreeBSD: src/sys/pci/agp.c,v 1.12 2001/05/19 01:28:07 alfred Exp $
                     28:  */
                     29:
                     30: #include <sys/param.h>
                     31: #include <sys/malloc.h>
                     32: #include <sys/agpio.h>
                     33: #include <sys/fcntl.h>
                     34: #include <sys/ioctl.h>
                     35:
                     36: #include <uvm/uvm.h>
                     37:
                     38: #include <dev/pci/pcivar.h>
                     39:
                     40: #include <dev/ic/mc6845reg.h>
                     41: #include <dev/ic/pcdisplayvar.h>
                     42: #include <dev/ic/vgareg.h>
                     43: #include <dev/ic/vgavar.h>
                     44:
                     45: #include <dev/pci/agpvar.h>
                     46: #include <dev/pci/agpreg.h>
                     47:
                     48: struct agp_memory *agp_find_memory(struct vga_pci_softc *sc, int id);
                     49: const struct agp_product *agp_lookup(struct pci_attach_args *pa);
                     50:
                     51: struct pci_attach_args agp_pchb_pa;
                     52: int agp_pchb_pa_set = 0;
                     53:
                     54: void
                     55: agp_attach(struct device *parent, struct device *self, void *aux)
                     56: {
                     57:        struct pci_attach_args *pa = aux;
                     58:        struct vga_pci_softc *sc = (struct vga_pci_softc *)self;
                     59:        const struct agp_product *ap;
                     60:        u_int memsize;
                     61:        int i, ret;
                     62:
                     63:        ap = agp_lookup(pa);
                     64:        if (ap) {
                     65:                static const int agp_max[][2] = {
                     66:                        {0,             0},
                     67:                        {32,            4},
                     68:                        {64,            28},
                     69:                        {128,           96},
                     70:                        {256,           204},
                     71:                        {512,           440},
                     72:                        {1024,          942},
                     73:                        {2048,          1920},
                     74:                        {4096,          3932}
                     75:                };
                     76: #define        agp_max_size     (sizeof(agp_max)/sizeof(agp_max[0]))
                     77:
                     78:                /*
                     79:                 * Work out an upper bound for agp memory allocation. This
                     80:                 * uses a heuristic table from the Linux driver.
                     81:                 */
                     82:                memsize = ptoa(physmem) >> 20;
                     83:
                     84:                for (i = 0; i < agp_max_size && memsize > agp_max[i][0]; i++)
                     85:                        ;
                     86:                if (i == agp_max_size)
                     87:                        i = agp_max_size - 1;
                     88:                sc->sc_maxmem = agp_max[i][1] << 20;
                     89:
                     90:                /*
                     91:                 * The lock is used to prevent re-entry to
                     92:                 * agp_generic_bind_memory() since that function can sleep.
                     93:                 */
                     94:
                     95:                lockinit(&sc->sc_lock, PZERO|PCATCH, "agplk", 0, 0);
                     96:
                     97:                TAILQ_INIT(&sc->sc_memory);
                     98:
                     99:                sc->sc_pcitag = pa->pa_tag;
                    100:                sc->sc_pc = pa->pa_pc;
                    101:                sc->sc_id = pa->pa_id;
                    102:                sc->sc_dmat = pa->pa_dmat;
                    103:
                    104:                pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP,
                    105:                    &sc->sc_capoff, NULL);
                    106:
                    107:                ret = (*ap->ap_attach)(sc, pa, &agp_pchb_pa);
                    108:                if (ret == 0)
                    109:                        printf(": aperture at 0x%lx, size 0x%lx",
                    110:                            (u_long)sc->sc_apaddr,
                    111:                            (u_long)AGP_GET_APERTURE(sc));
                    112:                else {
                    113:                        sc->sc_chipc = NULL;
                    114:                        printf(": AGP GART");
                    115:                }
                    116:        }
                    117: }
                    118:
                    119: paddr_t
                    120: agp_mmap(void *v, off_t off, int prot)
                    121: {
                    122:        struct vga_config* vs = (struct vga_config*) v;
                    123:        struct vga_pci_softc* sc = (struct vga_pci_softc *)vs->vc_softc;
                    124:
                    125:        if (sc->sc_apaddr) {
                    126:
                    127:                if (off > AGP_GET_APERTURE(sc))
                    128:                        return (-1);
                    129:
                    130:                return atop(sc->sc_apaddr + off);
                    131:        }
                    132:        return -1;
                    133: }
                    134:
                    135: int
                    136: agp_ioctl(void *v, u_long cmd, caddr_t addr, int flag, struct proc *pb)
                    137: {
                    138:        struct vga_config *vc = v;
                    139:        struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc;
                    140:        struct agp_memory *mem;
                    141:        agp_info *info;
                    142:        agp_setup *setup;
                    143:        agp_allocate *alloc;
                    144:        agp_bind *bind;
                    145:        agp_unbind *unbind;
                    146:        vsize_t size;
                    147:        int error = 0;
                    148:
                    149:        if (sc->sc_methods == NULL || sc->sc_chipc == NULL)
                    150:                return (ENXIO);
                    151:
                    152:        switch (cmd) {
                    153:        case AGPIOC_INFO:
                    154:                if (!sc->sc_chipc)
                    155:                        return (ENXIO);
                    156:        case AGPIOC_ACQUIRE:
                    157:        case AGPIOC_RELEASE:
                    158:        case AGPIOC_SETUP:
                    159:        case AGPIOC_ALLOCATE:
                    160:        case AGPIOC_DEALLOCATE:
                    161:        case AGPIOC_BIND:
                    162:        case AGPIOC_UNBIND:
                    163:                if (cmd != AGPIOC_INFO && !(flag & FWRITE))
                    164:                        return (EPERM);
                    165:                break;
                    166:        }
                    167:        switch(cmd) {
                    168:        case AGPIOC_INFO:
                    169:                info = (agp_info *)addr;
                    170:                bzero(info, sizeof *info);
                    171:                info->bridge_id = sc->sc_id;
                    172:                if (sc->sc_capoff != 0)
                    173:                        info->agp_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
                    174:                            AGP_STATUS + sc->sc_capoff);
                    175:                else
                    176:                        info->agp_mode = 0; /* i810 doesn't have real AGP */
                    177:                info->aper_base = sc->sc_apaddr;
                    178:                info->aper_size = AGP_GET_APERTURE(sc) >> 20;
                    179:                info->pg_total =
                    180:                info->pg_system = sc->sc_maxmem >> AGP_PAGE_SHIFT;
                    181:                info->pg_used = sc->sc_allocated >> AGP_PAGE_SHIFT;
                    182:                break;
                    183:
                    184:        case AGPIOC_ACQUIRE:
                    185:                if (sc->sc_state != AGP_ACQUIRE_FREE)
                    186:                        error = EBUSY;
                    187:                else
                    188:                        sc->sc_state = AGP_ACQUIRE_USER;
                    189:                break;
                    190:
                    191:        case AGPIOC_RELEASE:
                    192:                if (sc->sc_state == AGP_ACQUIRE_FREE)
                    193:                        break;
                    194:
                    195:                if (sc->sc_state != AGP_ACQUIRE_USER) {
                    196:                        error = EBUSY;
                    197:                        break;
                    198:                }
                    199:
                    200:                /*
                    201:                 * Clear out the aperture and free any
                    202:                 * outstanding memory blocks.
                    203:                 */
                    204:                TAILQ_FOREACH(mem, &sc->sc_memory, am_link) {
                    205:                        if (mem->am_is_bound) {
                    206:                                printf("agp_release_helper: mem %d is bound\n",
                    207:                                    mem->am_id);
                    208:                                AGP_UNBIND_MEMORY(sc, mem);
                    209:                        }
                    210:                }
                    211:                sc->sc_state = AGP_ACQUIRE_FREE;
                    212:                break;
                    213:
                    214:        case AGPIOC_SETUP:
                    215:                setup = (agp_setup *)addr;
                    216:                error = AGP_ENABLE(sc, setup->agp_mode);
                    217:                break;
                    218:
                    219:        case AGPIOC_ALLOCATE:
                    220:                alloc = (agp_allocate *)addr;
                    221:                size = alloc->pg_count << AGP_PAGE_SHIFT;
                    222:                if (sc->sc_allocated + size > sc->sc_maxmem)
                    223:                        error = EINVAL;
                    224:                else {
                    225:                        mem = AGP_ALLOC_MEMORY(sc, alloc->type, size);
                    226:                        if (mem) {
                    227:                                alloc->key = mem->am_id;
                    228:                                alloc->physical = mem->am_physical;
                    229:                        } else
                    230:                                error = ENOMEM;
                    231:                }
                    232:                break;
                    233:
                    234:        case AGPIOC_DEALLOCATE:
                    235:                mem = agp_find_memory(sc, *(int *)addr);
                    236:                if (mem)
                    237:                        AGP_FREE_MEMORY(sc, mem);
                    238:                else
                    239:                        error = ENOENT;
                    240:                break;
                    241:
                    242:        case AGPIOC_BIND:
                    243:                bind = (agp_bind *)addr;
                    244:                mem = agp_find_memory(sc, bind->key);
                    245:                if (!mem)
                    246:                        error = ENOENT;
                    247:                else
                    248:                        error = AGP_BIND_MEMORY(sc, mem,
                    249:                            bind->pg_start << AGP_PAGE_SHIFT);
                    250:                break;
                    251:
                    252:        case AGPIOC_UNBIND:
                    253:                unbind = (agp_unbind *)addr;
                    254:                mem = agp_find_memory(sc, unbind->key);
                    255:                if (!mem)
                    256:                        error = ENOENT;
                    257:                else
                    258:                        error = AGP_UNBIND_MEMORY(sc, mem);
                    259:                break;
                    260:        default:
                    261:                error = ENOTTY;
                    262:        }
                    263:
                    264:        return (error);
                    265: }
                    266:
                    267: #ifdef notyet
                    268: void
                    269: agp_close(void *v)
                    270: {
                    271:        struct vga_config *vc = v;
                    272:        struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc;
                    273:        struct agp_memory *mem;
                    274:
                    275:        /*
                    276:         * Clear out the aperture and free any
                    277:         * outstanding memory blocks.
                    278:         */
                    279:        TAILQ_FOREACH(mem, &sc->sc_memory, am_link) {
                    280:                if (mem->am_is_bound) {
                    281:                        AGP_UNBIND_MEMORY(sc, mem);
                    282:                }
                    283:        }
                    284:
                    285:        while (!TAILQ_EMPTY(&sc->sc_memory)) {
                    286:                mem = TAILQ_FIRST(&sc->sc_memory);
                    287:                AGP_FREE_MEMORY(sc, mem);
                    288:        }
                    289:
                    290:        sc->sc_state = AGP_ACQUIRE_FREE;
                    291: }
                    292: #endif
                    293:
                    294: struct agp_memory *
                    295: agp_find_memory(struct vga_pci_softc *sc, int id)
                    296: {
                    297:        struct agp_memory *mem;
                    298:
                    299:        AGP_DPF("searching for memory block %d\n", id);
                    300:        TAILQ_FOREACH(mem, &sc->sc_memory, am_link) {
                    301:                AGP_DPF("considering memory block %d\n", mem->am_id);
                    302:                if (mem->am_id == id)
                    303:                        return (mem);
                    304:        }
                    305:        return 0;
                    306: }
                    307:
                    308: const struct agp_product *
                    309: agp_lookup(struct pci_attach_args *pa)
                    310: {
                    311:        const struct agp_product *ap;
                    312:
                    313:        if (!agp_pchb_pa_set)
                    314:                return (NULL);
                    315:        agp_pchb_pa_set = 0;
                    316:
                    317:        /* First find the vendor. */
                    318:        for (ap = agp_products; ap->ap_attach != NULL; ap++)
                    319:                if (ap->ap_vendor == PCI_VENDOR(pa->pa_id))
                    320:                        break;
                    321:
                    322:        if (ap->ap_attach == NULL)
                    323:                return (NULL);
                    324:
                    325:        /* Now find the product within the vendor's domain. */
                    326:        for (; ap->ap_attach != NULL; ap++) {
                    327:                /* Ran out of this vendor's section of the table. */
                    328:                if (ap->ap_vendor != PCI_VENDOR(pa->pa_id))
                    329:                        return (NULL);
                    330:
                    331:                if (ap->ap_product == PCI_PRODUCT(pa->pa_id))
                    332:                        break;          /* Exact match. */
                    333:                if (ap->ap_product == (u_int32_t) -1)
                    334:                        break;          /* Wildcard match. */
                    335:        }
                    336:
                    337:        if (ap->ap_attach == NULL)
                    338:                ap = NULL;
                    339:
                    340:        return (ap);
                    341: }
                    342:
                    343: void
                    344: pciagp_set_pchb(struct pci_attach_args *pa)
                    345: {
                    346:        if (!agp_pchb_pa_set) {
                    347:                memcpy(&agp_pchb_pa, pa, sizeof *pa);
                    348:                agp_pchb_pa_set++;
                    349:        }
                    350: }
                    351:
                    352: int
                    353: agp_map_aperture(struct vga_pci_softc *sc, u_int32_t bar, u_int32_t memtype)
                    354: {
                    355:        /*
                    356:         * Find and the aperture. Don't map it (yet), this would
                    357:         * eat KVA.
                    358:         */
                    359:        if (pci_mapreg_info(sc->sc_pc, sc->sc_pcitag, bar,
                    360:            memtype, &sc->sc_apaddr, &sc->sc_apsize,
                    361:            &sc->sc_apflags) != 0)
                    362:                return ENXIO;
                    363:
                    364:        return 0;
                    365: }
                    366:
                    367: struct agp_gatt *
                    368: agp_alloc_gatt(struct vga_pci_softc *sc)
                    369: {
                    370:        u_int32_t apsize = AGP_GET_APERTURE(sc);
                    371:        u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
                    372:        struct agp_gatt *gatt;
                    373:        int nseg;
                    374:
                    375:        gatt = malloc(sizeof(*gatt), M_DEVBUF, M_NOWAIT);
                    376:        if (!gatt)
                    377:                return (NULL);
                    378:        bzero(gatt, sizeof(*gatt));
                    379:        gatt->ag_entries = entries;
                    380:
                    381:        if (agp_alloc_dmamem(sc->sc_dmat, entries * sizeof(u_int32_t),
                    382:            0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual,
                    383:            &gatt->ag_physical, &gatt->ag_dmaseg, 1, &nseg) != 0)
                    384:                return NULL;
                    385:
                    386:        gatt->ag_size = entries * sizeof(u_int32_t);
                    387:        memset(gatt->ag_virtual, 0, gatt->ag_size);
                    388:        agp_flush_cache();
                    389:
                    390:        return gatt;
                    391: }
                    392:
                    393: void
                    394: agp_free_gatt(struct vga_pci_softc *sc, struct agp_gatt *gatt)
                    395: {
                    396:        agp_free_dmamem(sc->sc_dmat, gatt->ag_size, gatt->ag_dmamap,
                    397:            (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1);
                    398:        free(gatt, M_DEVBUF);
                    399: }
                    400:
                    401: int
                    402: agp_generic_detach(struct vga_pci_softc *sc)
                    403: {
                    404:        lockmgr(&sc->sc_lock, LK_DRAIN, NULL);
                    405:        agp_flush_cache();
                    406:        return 0;
                    407: }
                    408:
                    409: int
                    410: agp_generic_enable(struct vga_pci_softc *sc, u_int32_t mode)
                    411: {
                    412:        pcireg_t tstatus, mstatus;
                    413:        pcireg_t command;
                    414:        int rq, sba, fw, rate, capoff;
                    415:
                    416:        if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP,
                    417:             &capoff, NULL) == 0) {
                    418:                printf("agp_generic_enable: not an AGP capable device\n");
                    419:                return -1;
                    420:        }
                    421:
                    422:        tstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
                    423:            sc->sc_capoff + AGP_STATUS);
                    424:        mstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
                    425:            capoff + AGP_STATUS);
                    426:
                    427:        /* Set RQ to the min of mode, tstatus and mstatus */
                    428:        rq = AGP_MODE_GET_RQ(mode);
                    429:        if (AGP_MODE_GET_RQ(tstatus) < rq)
                    430:                rq = AGP_MODE_GET_RQ(tstatus);
                    431:        if (AGP_MODE_GET_RQ(mstatus) < rq)
                    432:                rq = AGP_MODE_GET_RQ(mstatus);
                    433:
                    434:        /* Set SBA if all three can deal with SBA */
                    435:        sba = (AGP_MODE_GET_SBA(tstatus)
                    436:               & AGP_MODE_GET_SBA(mstatus)
                    437:               & AGP_MODE_GET_SBA(mode));
                    438:
                    439:        /* Similar for FW */
                    440:        fw = (AGP_MODE_GET_FW(tstatus)
                    441:               & AGP_MODE_GET_FW(mstatus)
                    442:               & AGP_MODE_GET_FW(mode));
                    443:
                    444:        /* Figure out the max rate */
                    445:        rate = (AGP_MODE_GET_RATE(tstatus)
                    446:                & AGP_MODE_GET_RATE(mstatus)
                    447:                & AGP_MODE_GET_RATE(mode));
                    448:        if (rate & AGP_MODE_RATE_4x)
                    449:                rate = AGP_MODE_RATE_4x;
                    450:        else if (rate & AGP_MODE_RATE_2x)
                    451:                rate = AGP_MODE_RATE_2x;
                    452:        else
                    453:                rate = AGP_MODE_RATE_1x;
                    454:
                    455:        /* Construct the new mode word and tell the hardware  */
                    456:        command = AGP_MODE_SET_RQ(0, rq);
                    457:        command = AGP_MODE_SET_SBA(command, sba);
                    458:        command = AGP_MODE_SET_FW(command, fw);
                    459:        command = AGP_MODE_SET_RATE(command, rate);
                    460:        command = AGP_MODE_SET_AGP(command, 1);
                    461:        pci_conf_write(sc->sc_pc, sc->sc_pcitag,
                    462:            sc->sc_capoff + AGP_COMMAND, command);
                    463:        pci_conf_write(sc->sc_pc, sc->sc_pcitag, capoff + AGP_COMMAND, command);
                    464:        return 0;
                    465: }
                    466:
                    467: struct agp_memory *
                    468: agp_generic_alloc_memory(struct vga_pci_softc *sc, int type, vsize_t size)
                    469: {
                    470:        struct agp_memory *mem;
                    471:
                    472:        if (type != 0) {
                    473:                printf("agp_generic_alloc_memory: unsupported type %d\n", type);
                    474:                return 0;
                    475:        }
                    476:
                    477:        mem = malloc(sizeof *mem, M_DEVBUF, M_WAITOK);
                    478:        if (mem == NULL)
                    479:                return NULL;
                    480:        bzero(mem, sizeof *mem);
                    481:
                    482:        if (bus_dmamap_create(sc->sc_dmat, size, size / PAGE_SIZE + 1,
                    483:            size, 0, BUS_DMA_NOWAIT, &mem->am_dmamap) != 0) {
                    484:                free(mem, M_DEVBUF);
                    485:                return NULL;
                    486:        }
                    487:
                    488:        mem->am_id = sc->sc_nextid++;
                    489:        mem->am_size = size;
                    490:        TAILQ_INSERT_TAIL(&sc->sc_memory, mem, am_link);
                    491:        sc->sc_allocated += size;
                    492:
                    493:        return mem;
                    494: }
                    495:
                    496: int
                    497: agp_generic_free_memory(struct vga_pci_softc *sc, struct agp_memory *mem)
                    498: {
                    499:        if (mem->am_is_bound)
                    500:                return EBUSY;
                    501:
                    502:        sc->sc_allocated -= mem->am_size;
                    503:        TAILQ_REMOVE(&sc->sc_memory, mem, am_link);
                    504:        bus_dmamap_destroy(sc->sc_dmat, mem->am_dmamap);
                    505:        free(mem, M_DEVBUF);
                    506:        return 0;
                    507: }
                    508:
                    509: int
                    510: agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem,
                    511:                        off_t offset)
                    512: {
                    513:        bus_dma_segment_t *segs, *seg;
                    514:        bus_size_t done, j;
                    515:        bus_addr_t pa;
                    516:        off_t i, k;
                    517:        int nseg, error;
                    518:
                    519:        lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL);
                    520:
                    521:        if (mem->am_is_bound) {
                    522:                printf("AGP: memory already bound\n");
                    523:                lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    524:                return EINVAL;
                    525:        }
                    526:
                    527:        if (offset < 0
                    528:            || (offset & (AGP_PAGE_SIZE - 1)) != 0
                    529:            || offset + mem->am_size > AGP_GET_APERTURE(sc)) {
                    530:                printf("AGP: binding memory at bad offset %#lx\n",
                    531:                              (unsigned long) offset);
                    532:                lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    533:                return EINVAL;
                    534:        }
                    535:
                    536:        /*
                    537:         * The memory here needs to be directly accessable from the
                    538:         * AGP video card, so it should be allocated using bus_dma.
                    539:         * However, it need not be contiguous, since individual pages
                    540:         * are translated using the GATT.
                    541:         */
                    542:
                    543:        nseg = (mem->am_size + PAGE_SIZE - 1) / PAGE_SIZE;
                    544:        segs = malloc(nseg * sizeof *segs, M_DEVBUF, M_WAITOK);
                    545:        if (segs == NULL) {
                    546:                lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    547:                AGP_DPF("malloc segs (%u) failed\n",
                    548:                    nseg * sizeof *segs);
                    549:                return ENOMEM;
                    550:        }
                    551:        if ((error = bus_dmamem_alloc(sc->sc_dmat, mem->am_size, PAGE_SIZE, 0,
                    552:            segs, nseg, &mem->am_nseg, BUS_DMA_WAITOK)) != 0) {
                    553:                free(segs, M_DEVBUF);
                    554:                lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    555:                AGP_DPF("bus_dmamem_alloc failed %d\n", error);
                    556:                return error;
                    557:        }
                    558:        if ((error = bus_dmamem_map(sc->sc_dmat, segs, mem->am_nseg,
                    559:            mem->am_size, &mem->am_virtual, BUS_DMA_WAITOK)) != 0) {
                    560:                bus_dmamem_free(sc->sc_dmat, segs, mem->am_nseg);
                    561:                free(segs, M_DEVBUF);
                    562:                lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    563:                AGP_DPF("bus_dmamem_map failed %d\n", error);
                    564:                return error;
                    565:        }
                    566:        if ((error = bus_dmamap_load(sc->sc_dmat, mem->am_dmamap,
                    567:            mem->am_virtual, mem->am_size, NULL,
                    568:            BUS_DMA_WAITOK)) != 0) {
                    569:                bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual,
                    570:                    mem->am_size);
                    571:                bus_dmamem_free(sc->sc_dmat, segs, mem->am_nseg);
                    572:                free(segs, M_DEVBUF);
                    573:                lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    574:                AGP_DPF("bus_dmamap_load failed %d\n", error);
                    575:                return error;
                    576:        }
                    577:        mem->am_dmaseg = segs;
                    578:
                    579:        /*
                    580:         * Bind the individual pages and flush the chipset's
                    581:         * TLB.
                    582:         */
                    583:        done = 0;
                    584:        for (i = 0; i < mem->am_dmamap->dm_nsegs; i++) {
                    585:                seg = &mem->am_dmamap->dm_segs[i];
                    586:                /*
                    587:                 * Install entries in the GATT, making sure that if
                    588:                 * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not
                    589:                 * aligned to PAGE_SIZE, we don't modify too many GATT
                    590:                 * entries.
                    591:                 */
                    592:                for (j = 0; j < seg->ds_len && (done + j) < mem->am_size;
                    593:                     j += AGP_PAGE_SIZE) {
                    594:                        pa = seg->ds_addr + j;
                    595:                        AGP_DPF("binding offset %#lx to pa %#lx\n",
                    596:                                (unsigned long)(offset + done + j),
                    597:                                (unsigned long)pa);
                    598:                        error = AGP_BIND_PAGE(sc, offset + done + j, pa);
                    599:                        if (error) {
                    600:                                /*
                    601:                                 * Bail out. Reverse all the mappings
                    602:                                 * and unwire the pages.
                    603:                                 */
                    604:                                for (k = 0; k < done + j; k += AGP_PAGE_SIZE)
                    605:                                        AGP_UNBIND_PAGE(sc, offset + k);
                    606:
                    607:                                bus_dmamap_unload(sc->sc_dmat, mem->am_dmamap);
                    608:                                bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual,
                    609:                                                 mem->am_size);
                    610:                                bus_dmamem_free(sc->sc_dmat, mem->am_dmaseg,
                    611:                                                mem->am_nseg);
                    612:                                free(mem->am_dmaseg, M_DEVBUF);
                    613:                                lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    614:                                AGP_DPF("AGP_BIND_PAGE failed %d\n", error);
                    615:                                return error;
                    616:                        }
                    617:                }
                    618:                done += seg->ds_len;
                    619:        }
                    620:
                    621:        /*
                    622:         * Flush the cpu cache since we are providing a new mapping
                    623:         * for these pages.
                    624:         */
                    625:        agp_flush_cache();
                    626:
                    627:        /*
                    628:         * Make sure the chipset gets the new mappings.
                    629:         */
                    630:        AGP_FLUSH_TLB(sc);
                    631:
                    632:        mem->am_offset = offset;
                    633:        mem->am_is_bound = 1;
                    634:
                    635:        lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    636:
                    637:        return 0;
                    638: }
                    639:
                    640: int
                    641: agp_generic_unbind_memory(struct vga_pci_softc *sc, struct agp_memory *mem)
                    642: {
                    643:        int i;
                    644:
                    645:        lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL);
                    646:
                    647:        if (!mem->am_is_bound) {
                    648:                printf("AGP: memory is not bound\n");
                    649:                lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    650:                return EINVAL;
                    651:        }
                    652:
                    653:
                    654:        /*
                    655:         * Unbind the individual pages and flush the chipset's
                    656:         * TLB. Unwire the pages so they can be swapped.
                    657:         */
                    658:        for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
                    659:                AGP_UNBIND_PAGE(sc, mem->am_offset + i);
                    660:
                    661:        agp_flush_cache();
                    662:        AGP_FLUSH_TLB(sc);
                    663:
                    664:        bus_dmamap_unload(sc->sc_dmat, mem->am_dmamap);
                    665:        bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual, mem->am_size);
                    666:        bus_dmamem_free(sc->sc_dmat, mem->am_dmaseg, mem->am_nseg);
                    667:
                    668:        free(mem->am_dmaseg, M_DEVBUF);
                    669:
                    670:        mem->am_offset = 0;
                    671:        mem->am_is_bound = 0;
                    672:
                    673:        lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
                    674:
                    675:        return 0;
                    676: }
                    677:
                    678: int
                    679: agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, int flags,
                    680:                 bus_dmamap_t *mapp, caddr_t *vaddr, bus_addr_t *baddr,
                    681:                 bus_dma_segment_t *seg, int nseg, int *rseg)
                    682:
                    683: {
                    684:        int error, level = 0;
                    685:
                    686:        if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0,
                    687:                        seg, nseg, rseg, BUS_DMA_NOWAIT)) != 0)
                    688:                goto out;
                    689:        level++;
                    690:
                    691:        if ((error = bus_dmamem_map(tag, seg, *rseg, size, vaddr,
                    692:                        BUS_DMA_NOWAIT | flags)) != 0)
                    693:                goto out;
                    694:        level++;
                    695:
                    696:        if ((error = bus_dmamap_create(tag, size, *rseg, size, 0,
                    697:                        BUS_DMA_NOWAIT, mapp)) != 0)
                    698:                goto out;
                    699:        level++;
                    700:
                    701:        if ((error = bus_dmamap_load(tag, *mapp, *vaddr, size, NULL,
                    702:                        BUS_DMA_NOWAIT)) != 0)
                    703:                goto out;
                    704:
                    705:        *baddr = (*mapp)->dm_segs[0].ds_addr;
                    706:
                    707:        return 0;
                    708: out:
                    709:        switch (level) {
                    710:        case 3:
                    711:                bus_dmamap_destroy(tag, *mapp);
                    712:                /* FALLTHROUGH */
                    713:        case 2:
                    714:                bus_dmamem_unmap(tag, *vaddr, size);
                    715:                /* FALLTHROUGH */
                    716:        case 1:
                    717:                bus_dmamem_free(tag, seg, *rseg);
                    718:                break;
                    719:        default:
                    720:                break;
                    721:        }
                    722:
                    723:        return error;
                    724: }
                    725:
                    726: void
                    727: agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map,
                    728:                caddr_t vaddr, bus_dma_segment_t *seg, int nseg)
                    729: {
                    730:
                    731:        bus_dmamap_unload(tag, map);
                    732:        bus_dmamap_destroy(tag, map);
                    733:        bus_dmamem_unmap(tag, vaddr, size);
                    734:        bus_dmamem_free(tag, seg, nseg);
                    735: }

CVSweb