1 /* $NetBSD: agp.c,v 1.14 2002/01/22 17:29:36 augustss Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 Doug Rabson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/sys/pci/agp.c,v 1.12 2001/05/19 01:28:07 alfred Exp $ 29 */ 30 31 /* 32 * Copyright (c) 2001 Wasabi Systems, Inc. 33 * All rights reserved. 34 * 35 * Written by Frank van der Linden for Wasabi Systems, Inc. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed for the NetBSD Project by 48 * Wasabi Systems, Inc. 49 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 50 * or promote products derived from this software without specific prior 51 * written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 55 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 56 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 57 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 58 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 59 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 60 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 61 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 62 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 63 * POSSIBILITY OF SUCH DAMAGE. 64 */ 65 66 67 #include <sys/cdefs.h> 68 __KERNEL_RCSID(0, "$NetBSD: agp.c,v 1.14 2002/01/22 17:29:36 augustss Exp $"); 69 70 #include <sys/param.h> 71 #include <sys/systm.h> 72 #include <sys/malloc.h> 73 #include <sys/kernel.h> 74 #include <sys/device.h> 75 #include <sys/conf.h> 76 #include <sys/ioctl.h> 77 #include <sys/fcntl.h> 78 #include <sys/agpio.h> 79 #include <sys/proc.h> 80 81 #include <uvm/uvm_extern.h> 82 83 #include <dev/pci/pcireg.h> 84 #include <dev/pci/pcivar.h> 85 #include <dev/pci/agpvar.h> 86 #include <dev/pci/agpreg.h> 87 #include <dev/pci/pcidevs.h> 88 89 #include <machine/bus.h> 90 91 /* Helper functions for implementing chipset mini drivers. */ 92 /* XXXfvdl get rid of this one. */ 93 94 extern struct cfdriver agp_cd; 95 cdev_decl(agp); 96 97 int agpmatch(struct device *, struct cfdata *, void *); 98 void agpattach(struct device *, struct device *, void *); 99 100 struct cfattach agp_ca = { 101 sizeof(struct agp_softc), agpmatch, agpattach 102 }; 103 104 static int agp_info_user(struct agp_softc *, agp_info *); 105 static int agp_setup_user(struct agp_softc *, agp_setup *); 106 static int agp_allocate_user(struct agp_softc *, agp_allocate *); 107 static int agp_deallocate_user(struct agp_softc *, int); 108 static int agp_bind_user(struct agp_softc *, agp_bind *); 109 static int agp_unbind_user(struct agp_softc *, agp_unbind *); 110 static int agpdev_match(struct pci_attach_args *); 111 112 #include "agp_ali.h" 113 #include "agp_amd.h" 114 #include "agp_i810.h" 115 #include "agp_intel.h" 116 #include "agp_sis.h" 117 #include "agp_via.h" 118 119 const struct agp_product { 120 uint32_t ap_vendor; 121 uint32_t ap_product; 122 int (*ap_match)(const struct pci_attach_args *); 123 int (*ap_attach)(struct device *, struct device *, void *); 124 } agp_products[] = { 125 #if NAGP_ALI > 0 126 { PCI_VENDOR_ALI, -1, 127 NULL, agp_ali_attach }, 128 #endif 129 130 #if NAGP_AMD > 0 131 { PCI_VENDOR_AMD, -1, 132 agp_amd_match, agp_amd_attach }, 133 #endif 134 135 #if NAGP_I810 > 0 136 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_MCH, 137 NULL, agp_i810_attach }, 138 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_DC100_MCH, 139 NULL, agp_i810_attach }, 140 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810E_MCH, 141 NULL, agp_i810_attach }, 142 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82815_FULL_HUB, 143 NULL, agp_i810_attach }, 144 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82840_HB, 145 NULL, agp_i810_attach }, 146 #if 0 147 /* XXX needs somewhat different driver */ 148 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82830MP_IO_1, 149 NULL, agp_i810_attach }, 150 #endif 151 #endif 152 153 #if NAGP_INTEL > 0 154 { PCI_VENDOR_INTEL, -1, 155 NULL, agp_intel_attach }, 156 #endif 157 158 #if NAGP_SIS > 0 159 { PCI_VENDOR_SIS, -1, 160 NULL, agp_sis_attach }, 161 #endif 162 163 #if NAGP_VIA > 0 164 { PCI_VENDOR_VIATECH, -1, 165 NULL, agp_via_attach }, 166 #endif 167 168 { 0, 0, 169 NULL, NULL }, 170 }; 171 172 static const struct agp_product * 173 agp_lookup(const struct pci_attach_args *pa) 174 { 175 const struct agp_product *ap; 176 177 /* First find the vendor. */ 178 for (ap = agp_products; ap->ap_attach != NULL; ap++) { 179 if (PCI_VENDOR(pa->pa_id) == ap->ap_vendor) 180 break; 181 } 182 183 if (ap->ap_attach == NULL) 184 return (NULL); 185 186 /* Now find the product within the vendor's domain. */ 187 for (; ap->ap_attach != NULL; ap++) { 188 if (PCI_VENDOR(pa->pa_id) != ap->ap_vendor) { 189 /* Ran out of this vendor's section of the table. */ 190 return (NULL); 191 } 192 if (ap->ap_product == PCI_PRODUCT(pa->pa_id)) { 193 /* Exact match. */ 194 break; 195 } 196 if (ap->ap_product == (uint32_t) -1) { 197 /* Wildcard match. */ 198 break; 199 } 200 } 201 202 if (ap->ap_attach == NULL) 203 return (NULL); 204 205 /* Now let the product-specific driver filter the match. */ 206 if (ap->ap_match != NULL && (*ap->ap_match)(pa) == 0) 207 return (NULL); 208 209 return (ap); 210 } 211 212 int 213 agpmatch(struct device *parent, struct cfdata *match, void *aux) 214 { 215 struct agpbus_attach_args *apa = aux; 216 struct pci_attach_args *pa = &apa->apa_pci_args; 217 218 if (strcmp(apa->apa_busname, "agp") != 0) 219 return (0); 220 221 if (agp_lookup(pa) == NULL) 222 return (0); 223 224 return (1); 225 } 226 227 static int agp_max[][2] = { 228 {0, 0}, 229 {32, 4}, 230 {64, 28}, 231 {128, 96}, 232 {256, 204}, 233 {512, 440}, 234 {1024, 942}, 235 {2048, 1920}, 236 {4096, 3932} 237 }; 238 #define agp_max_size (sizeof(agp_max) / sizeof(agp_max[0])) 239 240 void 241 agpattach(struct device *parent, struct device *self, void *aux) 242 { 243 struct agpbus_attach_args *apa = aux; 244 struct pci_attach_args *pa = &apa->apa_pci_args; 245 struct agp_softc *sc = (void *)self; 246 const struct agp_product *ap; 247 int memsize, i, ret; 248 249 ap = agp_lookup(pa); 250 if (ap == NULL) { 251 printf("\n"); 252 panic("agpattach: impossible"); 253 } 254 255 sc->as_dmat = pa->pa_dmat; 256 sc->as_pc = pa->pa_pc; 257 sc->as_tag = pa->pa_tag; 258 sc->as_id = pa->pa_id; 259 260 /* 261 * Work out an upper bound for agp memory allocation. This 262 * uses a heurisitc table from the Linux driver. 263 */ 264 memsize = ptoa(physmem) >> 20; 265 for (i = 0; i < agp_max_size; i++) { 266 if (memsize <= agp_max[i][0]) 267 break; 268 } 269 if (i == agp_max_size) 270 i = agp_max_size - 1; 271 sc->as_maxmem = agp_max[i][1] << 20U; 272 273 /* 274 * The lock is used to prevent re-entry to 275 * agp_generic_bind_memory() since that function can sleep. 276 */ 277 lockinit(&sc->as_lock, PZERO|PCATCH, "agplk", 0, 0); 278 279 TAILQ_INIT(&sc->as_memory); 280 281 ret = (*ap->ap_attach)(parent, self, pa); 282 if (ret == 0) 283 printf(": aperture at 0x%lx, size 0x%lx\n", 284 (unsigned long)sc->as_apaddr, 285 (unsigned long)AGP_GET_APERTURE(sc)); 286 else 287 sc->as_chipc = NULL; 288 } 289 int 290 agp_map_aperture(struct pci_attach_args *pa, struct agp_softc *sc) 291 { 292 /* 293 * Find and the aperture. Don't map it (yet), this would 294 * eat KVA. 295 */ 296 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE, 297 PCI_MAPREG_TYPE_MEM, &sc->as_apaddr, &sc->as_apsize, 298 &sc->as_apflags) != 0) 299 return ENXIO; 300 301 sc->as_apt = pa->pa_memt; 302 303 return 0; 304 } 305 306 struct agp_gatt * 307 agp_alloc_gatt(struct agp_softc *sc) 308 { 309 u_int32_t apsize = AGP_GET_APERTURE(sc); 310 u_int32_t entries = apsize >> AGP_PAGE_SHIFT; 311 struct agp_gatt *gatt; 312 int dummyseg; 313 314 gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT); 315 if (!gatt) 316 return NULL; 317 gatt->ag_entries = entries; 318 319 if (agp_alloc_dmamem(sc->as_dmat, entries * sizeof(u_int32_t), 320 0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual, 321 &gatt->ag_physical, &gatt->ag_dmaseg, 1, &dummyseg) != 0) 322 return NULL; 323 324 gatt->ag_size = entries * sizeof(u_int32_t); 325 memset(gatt->ag_virtual, 0, gatt->ag_size); 326 agp_flush_cache(); 327 328 return gatt; 329 } 330 331 void 332 agp_free_gatt(struct agp_softc *sc, struct agp_gatt *gatt) 333 { 334 agp_free_dmamem(sc->as_dmat, gatt->ag_size, gatt->ag_dmamap, 335 (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1); 336 free(gatt, M_AGP); 337 } 338 339 340 int 341 agp_generic_detach(struct agp_softc *sc) 342 { 343 lockmgr(&sc->as_lock, LK_DRAIN, 0); 344 agp_flush_cache(); 345 return 0; 346 } 347 348 static int 349 agpdev_match(struct pci_attach_args *pa) 350 { 351 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY && 352 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_DISPLAY_VGA) 353 return 1; 354 355 return 0; 356 } 357 358 int 359 agp_generic_enable(struct agp_softc *sc, u_int32_t mode) 360 { 361 struct pci_attach_args pa; 362 pcireg_t tstatus, mstatus; 363 pcireg_t command; 364 int rq, sba, fw, rate, capoff; 365 366 if (pci_find_device(&pa, agpdev_match) == 0 || 367 pci_get_capability(pa.pa_pc, pa.pa_tag, PCI_CAP_AGP, 368 &capoff, NULL) == 0) { 369 printf("%s: can't find display\n", sc->as_dev.dv_xname); 370 return ENXIO; 371 } 372 373 tstatus = pci_conf_read(sc->as_pc, sc->as_tag, 374 sc->as_capoff + AGP_STATUS); 375 mstatus = pci_conf_read(pa.pa_pc, pa.pa_tag, 376 capoff + AGP_STATUS); 377 378 /* Set RQ to the min of mode, tstatus and mstatus */ 379 rq = AGP_MODE_GET_RQ(mode); 380 if (AGP_MODE_GET_RQ(tstatus) < rq) 381 rq = AGP_MODE_GET_RQ(tstatus); 382 if (AGP_MODE_GET_RQ(mstatus) < rq) 383 rq = AGP_MODE_GET_RQ(mstatus); 384 385 /* Set SBA if all three can deal with SBA */ 386 sba = (AGP_MODE_GET_SBA(tstatus) 387 & AGP_MODE_GET_SBA(mstatus) 388 & AGP_MODE_GET_SBA(mode)); 389 390 /* Similar for FW */ 391 fw = (AGP_MODE_GET_FW(tstatus) 392 & AGP_MODE_GET_FW(mstatus) 393 & AGP_MODE_GET_FW(mode)); 394 395 /* Figure out the max rate */ 396 rate = (AGP_MODE_GET_RATE(tstatus) 397 & AGP_MODE_GET_RATE(mstatus) 398 & AGP_MODE_GET_RATE(mode)); 399 if (rate & AGP_MODE_RATE_4x) 400 rate = AGP_MODE_RATE_4x; 401 else if (rate & AGP_MODE_RATE_2x) 402 rate = AGP_MODE_RATE_2x; 403 else 404 rate = AGP_MODE_RATE_1x; 405 406 /* Construct the new mode word and tell the hardware */ 407 command = AGP_MODE_SET_RQ(0, rq); 408 command = AGP_MODE_SET_SBA(command, sba); 409 command = AGP_MODE_SET_FW(command, fw); 410 command = AGP_MODE_SET_RATE(command, rate); 411 command = AGP_MODE_SET_AGP(command, 1); 412 pci_conf_write(sc->as_pc, sc->as_tag, 413 sc->as_capoff + AGP_COMMAND, command); 414 pci_conf_write(pa.pa_pc, pa.pa_tag, capoff + AGP_COMMAND, command); 415 416 return 0; 417 } 418 419 struct agp_memory * 420 agp_generic_alloc_memory(struct agp_softc *sc, int type, vsize_t size) 421 { 422 struct agp_memory *mem; 423 424 if ((size & (AGP_PAGE_SIZE - 1)) != 0) 425 return 0; 426 427 if (sc->as_allocated + size > sc->as_maxmem) 428 return 0; 429 430 if (type != 0) { 431 printf("agp_generic_alloc_memory: unsupported type %d\n", 432 type); 433 return 0; 434 } 435 436 mem = malloc(sizeof *mem, M_AGP, M_WAITOK); 437 if (mem == NULL) 438 return NULL; 439 440 if (bus_dmamap_create(sc->as_dmat, size, size / PAGE_SIZE + 1, 441 size, 0, BUS_DMA_NOWAIT, &mem->am_dmamap) != 0) { 442 free(mem, M_AGP); 443 return NULL; 444 } 445 446 mem->am_id = sc->as_nextid++; 447 mem->am_size = size; 448 mem->am_type = 0; 449 mem->am_physical = 0; 450 mem->am_offset = 0; 451 mem->am_is_bound = 0; 452 TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link); 453 sc->as_allocated += size; 454 455 return mem; 456 } 457 458 int 459 agp_generic_free_memory(struct agp_softc *sc, struct agp_memory *mem) 460 { 461 if (mem->am_is_bound) 462 return EBUSY; 463 464 sc->as_allocated -= mem->am_size; 465 TAILQ_REMOVE(&sc->as_memory, mem, am_link); 466 bus_dmamap_destroy(sc->as_dmat, mem->am_dmamap); 467 free(mem, M_AGP); 468 return 0; 469 } 470 471 int 472 agp_generic_bind_memory(struct agp_softc *sc, struct agp_memory *mem, 473 off_t offset) 474 { 475 off_t i, k; 476 bus_size_t done, j; 477 int error; 478 bus_dma_segment_t *segs, *seg; 479 bus_addr_t pa; 480 int contigpages, nseg; 481 482 lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0); 483 484 if (mem->am_is_bound) { 485 printf("%s: memory already bound\n", sc->as_dev.dv_xname); 486 lockmgr(&sc->as_lock, LK_RELEASE, 0); 487 return EINVAL; 488 } 489 490 if (offset < 0 491 || (offset & (AGP_PAGE_SIZE - 1)) != 0 492 || offset + mem->am_size > AGP_GET_APERTURE(sc)) { 493 printf("%s: binding memory at bad offset %#lx\n", 494 sc->as_dev.dv_xname, (unsigned long) offset); 495 lockmgr(&sc->as_lock, LK_RELEASE, 0); 496 return EINVAL; 497 } 498 499 /* 500 * XXXfvdl 501 * The memory here needs to be directly accessable from the 502 * AGP video card, so it should be allocated using bus_dma. 503 * However, it need not be contiguous, since individual pages 504 * are translated using the GATT. 505 * 506 * Using a large chunk of contiguous memory may get in the way 507 * of other subsystems that may need one, so we try to be friendly 508 * and ask for allocation in chunks of a minimum of 8 pages 509 * of contiguous memory on average, falling back to 4, 2 and 1 510 * if really needed. Larger chunks are preferred, since allocating 511 * a bus_dma_segment per page would be overkill. 512 */ 513 514 for (contigpages = 8; contigpages > 0; contigpages >>= 1) { 515 nseg = (mem->am_size / (contigpages * PAGE_SIZE)) + 1; 516 segs = malloc(nseg * sizeof *segs, M_AGP, M_WAITOK); 517 if (segs == NULL) 518 return ENOMEM; 519 if (bus_dmamem_alloc(sc->as_dmat, mem->am_size, PAGE_SIZE, 0, 520 segs, nseg, &mem->am_nseg, 521 BUS_DMA_WAITOK) != 0) { 522 free(segs, M_AGP); 523 continue; 524 } 525 if (bus_dmamem_map(sc->as_dmat, segs, mem->am_nseg, 526 mem->am_size, &mem->am_virtual, BUS_DMA_WAITOK) != 0) { 527 bus_dmamem_free(sc->as_dmat, segs, mem->am_nseg); 528 free(segs, M_AGP); 529 continue; 530 } 531 if (bus_dmamap_load(sc->as_dmat, mem->am_dmamap, 532 mem->am_virtual, mem->am_size, NULL, BUS_DMA_WAITOK) != 0) { 533 bus_dmamem_unmap(sc->as_dmat, mem->am_virtual, 534 mem->am_size); 535 bus_dmamem_free(sc->as_dmat, segs, mem->am_nseg); 536 free(segs, M_AGP); 537 continue; 538 } 539 mem->am_dmaseg = segs; 540 break; 541 } 542 543 if (contigpages == 0) { 544 lockmgr(&sc->as_lock, LK_RELEASE, 0); 545 return ENOMEM; 546 } 547 548 549 /* 550 * Bind the individual pages and flush the chipset's 551 * TLB. 552 */ 553 done = 0; 554 for (i = 0; i < mem->am_dmamap->dm_nsegs; i++) { 555 seg = &mem->am_dmamap->dm_segs[i]; 556 /* 557 * Install entries in the GATT, making sure that if 558 * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not 559 * aligned to PAGE_SIZE, we don't modify too many GATT 560 * entries. 561 */ 562 for (j = 0; j < seg->ds_len && (done + j) < mem->am_size; 563 j += AGP_PAGE_SIZE) { 564 pa = seg->ds_addr + j; 565 AGP_DPF("binding offset %#lx to pa %#lx\n", 566 (unsigned long)(offset + done + j), 567 (unsigned long)pa); 568 error = AGP_BIND_PAGE(sc, offset + done + j, pa); 569 if (error) { 570 /* 571 * Bail out. Reverse all the mappings 572 * and unwire the pages. 573 */ 574 for (k = 0; k < done + j; k += AGP_PAGE_SIZE) 575 AGP_UNBIND_PAGE(sc, offset + k); 576 577 bus_dmamap_unload(sc->as_dmat, mem->am_dmamap); 578 bus_dmamem_unmap(sc->as_dmat, mem->am_virtual, 579 mem->am_size); 580 bus_dmamem_free(sc->as_dmat, mem->am_dmaseg, 581 mem->am_nseg); 582 free(mem->am_dmaseg, M_AGP); 583 lockmgr(&sc->as_lock, LK_RELEASE, 0); 584 return error; 585 } 586 } 587 done += seg->ds_len; 588 } 589 590 /* 591 * Flush the cpu cache since we are providing a new mapping 592 * for these pages. 593 */ 594 agp_flush_cache(); 595 596 /* 597 * Make sure the chipset gets the new mappings. 598 */ 599 AGP_FLUSH_TLB(sc); 600 601 mem->am_offset = offset; 602 mem->am_is_bound = 1; 603 604 lockmgr(&sc->as_lock, LK_RELEASE, 0); 605 606 return 0; 607 } 608 609 int 610 agp_generic_unbind_memory(struct agp_softc *sc, struct agp_memory *mem) 611 { 612 int i; 613 614 lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0); 615 616 if (!mem->am_is_bound) { 617 printf("%s: memory is not bound\n", sc->as_dev.dv_xname); 618 lockmgr(&sc->as_lock, LK_RELEASE, 0); 619 return EINVAL; 620 } 621 622 623 /* 624 * Unbind the individual pages and flush the chipset's 625 * TLB. Unwire the pages so they can be swapped. 626 */ 627 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 628 AGP_UNBIND_PAGE(sc, mem->am_offset + i); 629 630 agp_flush_cache(); 631 AGP_FLUSH_TLB(sc); 632 633 bus_dmamap_unload(sc->as_dmat, mem->am_dmamap); 634 bus_dmamem_unmap(sc->as_dmat, mem->am_virtual, mem->am_size); 635 bus_dmamem_free(sc->as_dmat, mem->am_dmaseg, mem->am_nseg); 636 637 free(mem->am_dmaseg, M_AGP); 638 639 mem->am_offset = 0; 640 mem->am_is_bound = 0; 641 642 lockmgr(&sc->as_lock, LK_RELEASE, 0); 643 644 return 0; 645 } 646 647 /* Helper functions for implementing user/kernel api */ 648 649 static int 650 agp_acquire_helper(struct agp_softc *sc, enum agp_acquire_state state) 651 { 652 if (sc->as_state != AGP_ACQUIRE_FREE) 653 return EBUSY; 654 sc->as_state = state; 655 656 return 0; 657 } 658 659 static int 660 agp_release_helper(struct agp_softc *sc, enum agp_acquire_state state) 661 { 662 struct agp_memory *mem; 663 664 if (sc->as_state == AGP_ACQUIRE_FREE) 665 return 0; 666 667 if (sc->as_state != state) 668 return EBUSY; 669 670 /* 671 * Clear out the aperture and free any outstanding memory blocks. 672 */ 673 TAILQ_FOREACH(mem, &sc->as_memory, am_link) { 674 if (mem->am_is_bound) { 675 printf("agp_release_helper: mem %d is bound\n", 676 mem->am_id); 677 AGP_UNBIND_MEMORY(sc, mem); 678 } 679 } 680 681 sc->as_state = AGP_ACQUIRE_FREE; 682 return 0; 683 } 684 685 static struct agp_memory * 686 agp_find_memory(struct agp_softc *sc, int id) 687 { 688 struct agp_memory *mem; 689 690 AGP_DPF("searching for memory block %d\n", id); 691 TAILQ_FOREACH(mem, &sc->as_memory, am_link) { 692 AGP_DPF("considering memory block %d\n", mem->am_id); 693 if (mem->am_id == id) 694 return mem; 695 } 696 return 0; 697 } 698 699 /* Implementation of the userland ioctl api */ 700 701 static int 702 agp_info_user(struct agp_softc *sc, agp_info *info) 703 { 704 memset(info, 0, sizeof *info); 705 info->bridge_id = sc->as_id; 706 if (sc->as_capoff != 0) 707 info->agp_mode = pci_conf_read(sc->as_pc, sc->as_tag, 708 sc->as_capoff + AGP_STATUS); 709 else 710 info->agp_mode = 0; /* i810 doesn't have real AGP */ 711 info->aper_base = sc->as_apaddr; 712 info->aper_size = AGP_GET_APERTURE(sc) >> 20; 713 info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT; 714 info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT; 715 716 return 0; 717 } 718 719 static int 720 agp_setup_user(struct agp_softc *sc, agp_setup *setup) 721 { 722 return AGP_ENABLE(sc, setup->agp_mode); 723 } 724 725 static int 726 agp_allocate_user(struct agp_softc *sc, agp_allocate *alloc) 727 { 728 struct agp_memory *mem; 729 730 mem = AGP_ALLOC_MEMORY(sc, 731 alloc->type, 732 alloc->pg_count << AGP_PAGE_SHIFT); 733 if (mem) { 734 alloc->key = mem->am_id; 735 alloc->physical = mem->am_physical; 736 return 0; 737 } else { 738 return ENOMEM; 739 } 740 } 741 742 static int 743 agp_deallocate_user(struct agp_softc *sc, int id) 744 { 745 struct agp_memory *mem = agp_find_memory(sc, id); 746 747 if (mem) { 748 AGP_FREE_MEMORY(sc, mem); 749 return 0; 750 } else { 751 return ENOENT; 752 } 753 } 754 755 static int 756 agp_bind_user(struct agp_softc *sc, agp_bind *bind) 757 { 758 struct agp_memory *mem = agp_find_memory(sc, bind->key); 759 760 if (!mem) 761 return ENOENT; 762 763 return AGP_BIND_MEMORY(sc, mem, bind->pg_start << AGP_PAGE_SHIFT); 764 } 765 766 static int 767 agp_unbind_user(struct agp_softc *sc, agp_unbind *unbind) 768 { 769 struct agp_memory *mem = agp_find_memory(sc, unbind->key); 770 771 if (!mem) 772 return ENOENT; 773 774 return AGP_UNBIND_MEMORY(sc, mem); 775 } 776 777 int 778 agpopen(dev_t dev, int oflags, int devtype, struct proc *p) 779 { 780 struct agp_softc *sc = device_lookup(&agp_cd, AGPUNIT(dev)); 781 782 if (sc == NULL) 783 return ENXIO; 784 785 if (sc->as_chipc == NULL) 786 return ENXIO; 787 788 if (!sc->as_isopen) 789 sc->as_isopen = 1; 790 else 791 return EBUSY; 792 793 return 0; 794 } 795 796 int 797 agpclose(dev_t dev, int fflag, int devtype, struct proc *p) 798 { 799 struct agp_softc *sc = device_lookup(&agp_cd, AGPUNIT(dev)); 800 801 /* 802 * Clear the GATT and force release on last close 803 */ 804 if (sc->as_state == AGP_ACQUIRE_USER) 805 agp_release_helper(sc, AGP_ACQUIRE_USER); 806 sc->as_isopen = 0; 807 808 return 0; 809 } 810 811 int 812 agpioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) 813 { 814 struct agp_softc *sc = device_lookup(&agp_cd, AGPUNIT(dev)); 815 816 if (sc == NULL) 817 return ENODEV; 818 819 if ((fflag & FWRITE) == 0 && cmd != AGPIOC_INFO) 820 return EPERM; 821 822 switch (cmd) { 823 case AGPIOC_INFO: 824 return agp_info_user(sc, (agp_info *) data); 825 826 case AGPIOC_ACQUIRE: 827 return agp_acquire_helper(sc, AGP_ACQUIRE_USER); 828 829 case AGPIOC_RELEASE: 830 return agp_release_helper(sc, AGP_ACQUIRE_USER); 831 832 case AGPIOC_SETUP: 833 return agp_setup_user(sc, (agp_setup *)data); 834 835 case AGPIOC_ALLOCATE: 836 return agp_allocate_user(sc, (agp_allocate *)data); 837 838 case AGPIOC_DEALLOCATE: 839 return agp_deallocate_user(sc, *(int *) data); 840 841 case AGPIOC_BIND: 842 return agp_bind_user(sc, (agp_bind *)data); 843 844 case AGPIOC_UNBIND: 845 return agp_unbind_user(sc, (agp_unbind *)data); 846 847 } 848 849 return EINVAL; 850 } 851 852 paddr_t 853 agpmmap(dev_t dev, off_t offset, int prot) 854 { 855 struct agp_softc *sc = device_lookup(&agp_cd, AGPUNIT(dev)); 856 857 if (offset > AGP_GET_APERTURE(sc)) 858 return -1; 859 860 return (bus_space_mmap(sc->as_apt, sc->as_apaddr, offset, prot, 861 BUS_SPACE_MAP_LINEAR)); 862 } 863 864 /* Implementation of the kernel api */ 865 866 void * 867 agp_find_device(int unit) 868 { 869 return device_lookup(&agp_cd, unit); 870 } 871 872 enum agp_acquire_state 873 agp_state(void *devcookie) 874 { 875 struct agp_softc *sc = devcookie; 876 return sc->as_state; 877 } 878 879 void 880 agp_get_info(void *devcookie, struct agp_info *info) 881 { 882 struct agp_softc *sc = devcookie; 883 884 info->ai_mode = pci_conf_read(sc->as_pc, sc->as_tag, 885 sc->as_capoff + AGP_STATUS); 886 info->ai_aperture_base = sc->as_apaddr; 887 info->ai_aperture_size = sc->as_apsize; /* XXXfvdl inconsistent */ 888 info->ai_memory_allowed = sc->as_maxmem; 889 info->ai_memory_used = sc->as_allocated; 890 } 891 892 int 893 agp_acquire(void *dev) 894 { 895 return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL); 896 } 897 898 int 899 agp_release(void *dev) 900 { 901 return agp_release_helper(dev, AGP_ACQUIRE_KERNEL); 902 } 903 904 int 905 agp_enable(void *dev, u_int32_t mode) 906 { 907 struct agp_softc *sc = dev; 908 909 return AGP_ENABLE(sc, mode); 910 } 911 912 void *agp_alloc_memory(void *dev, int type, vsize_t bytes) 913 { 914 struct agp_softc *sc = dev; 915 916 return (void *)AGP_ALLOC_MEMORY(sc, type, bytes); 917 } 918 919 void agp_free_memory(void *dev, void *handle) 920 { 921 struct agp_softc *sc = dev; 922 struct agp_memory *mem = (struct agp_memory *) handle; 923 AGP_FREE_MEMORY(sc, mem); 924 } 925 926 int agp_bind_memory(void *dev, void *handle, off_t offset) 927 { 928 struct agp_softc *sc = dev; 929 struct agp_memory *mem = (struct agp_memory *) handle; 930 931 return AGP_BIND_MEMORY(sc, mem, offset); 932 } 933 934 int agp_unbind_memory(void *dev, void *handle) 935 { 936 struct agp_softc *sc = dev; 937 struct agp_memory *mem = (struct agp_memory *) handle; 938 939 return AGP_UNBIND_MEMORY(sc, mem); 940 } 941 942 void agp_memory_info(void *dev, void *handle, struct agp_memory_info *mi) 943 { 944 struct agp_memory *mem = (struct agp_memory *) handle; 945 946 mi->ami_size = mem->am_size; 947 mi->ami_physical = mem->am_physical; 948 mi->ami_offset = mem->am_offset; 949 mi->ami_is_bound = mem->am_is_bound; 950 } 951 952 int 953 agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, int flags, 954 bus_dmamap_t *mapp, caddr_t *vaddr, bus_addr_t *baddr, 955 bus_dma_segment_t *seg, int nseg, int *rseg) 956 957 { 958 int error, level = 0; 959 960 if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0, 961 seg, nseg, rseg, BUS_DMA_NOWAIT)) != 0) 962 goto out; 963 level++; 964 965 if ((error = bus_dmamem_map(tag, seg, *rseg, size, vaddr, 966 BUS_DMA_NOWAIT | flags)) != 0) 967 goto out; 968 level++; 969 970 if ((error = bus_dmamap_create(tag, size, *rseg, size, 0, 971 BUS_DMA_NOWAIT, mapp)) != 0) 972 goto out; 973 level++; 974 975 if ((error = bus_dmamap_load(tag, *mapp, *vaddr, size, NULL, 976 BUS_DMA_NOWAIT)) != 0) 977 goto out; 978 979 *baddr = (*mapp)->dm_segs[0].ds_addr; 980 981 return 0; 982 out: 983 switch (level) { 984 case 3: 985 bus_dmamap_destroy(tag, *mapp); 986 /* FALLTHROUGH */ 987 case 2: 988 bus_dmamem_unmap(tag, *vaddr, size); 989 /* FALLTHROUGH */ 990 case 1: 991 bus_dmamem_free(tag, seg, *rseg); 992 break; 993 default: 994 break; 995 } 996 997 return error; 998 } 999 1000 void 1001 agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map, 1002 caddr_t vaddr, bus_dma_segment_t *seg, int nseg) 1003 { 1004 1005 bus_dmamap_unload(tag, map); 1006 bus_dmamap_destroy(tag, map); 1007 bus_dmamem_unmap(tag, vaddr, size); 1008 bus_dmamem_free(tag, seg, nseg); 1009 } 1010