Annotation of sys/dev/pci/agp.c, Revision 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