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