1 /* $NetBSD: agp_i810.c,v 1.34 2006/10/12 01:31:27 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 Doug Rabson 5 * Copyright (c) 2000 Ruslan Ermilov 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: src/sys/pci/agp_i810.c,v 1.4 2001/07/05 21:28:47 jhb Exp $ 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v 1.34 2006/10/12 01:31:27 christos Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/malloc.h> 38 #include <sys/kernel.h> 39 #include <sys/lock.h> 40 #include <sys/proc.h> 41 #include <sys/device.h> 42 #include <sys/conf.h> 43 44 #include <uvm/uvm_extern.h> 45 46 #include <dev/pci/pcivar.h> 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pcidevs.h> 49 #include <dev/pci/agpvar.h> 50 #include <dev/pci/agpreg.h> 51 52 #include <sys/agpio.h> 53 54 #include <machine/bus.h> 55 56 #include "agp_intel.h" 57 58 #define READ1(off) bus_space_read_1(isc->bst, isc->bsh, off) 59 #define READ4(off) bus_space_read_4(isc->bst, isc->bsh, off) 60 #define WRITE4(off,v) bus_space_write_4(isc->bst, isc->bsh, off, v) 61 #define WRITEGTT(off, v) \ 62 do { \ 63 if (isc->chiptype == CHIP_I915) { \ 64 bus_space_write_4(isc->gtt_bst, isc->gtt_bsh, \ 65 (u_int32_t)((off) >> AGP_PAGE_SHIFT) * 4, \ 66 (v)); \ 67 } else { \ 68 WRITE4(AGP_I810_GTT + \ 69 (u_int32_t)((off) >> AGP_PAGE_SHIFT) * 4, \ 70 (v)); \ 71 } \ 72 } while (0) 73 74 #define CHIP_I810 0 /* i810/i815 */ 75 #define CHIP_I830 1 /* 830M/845G */ 76 #define CHIP_I855 2 /* 852GM/855GM/865G */ 77 #define CHIP_I915 3 /* 915G/915GM/945G/945GM */ 78 79 struct agp_i810_softc { 80 u_int32_t initial_aperture; /* aperture size at startup */ 81 struct agp_gatt *gatt; 82 int chiptype; /* i810-like or i830 */ 83 u_int32_t dcache_size; /* i810 only */ 84 u_int32_t stolen; /* number of i830/845 gtt entries 85 for stolen memory */ 86 bus_space_tag_t bst; /* register bus_space tag */ 87 bus_space_handle_t bsh; /* register bus_space handle */ 88 bus_space_tag_t gtt_bst; /* GTT bus_space tag */ 89 bus_space_handle_t gtt_bsh; /* GTT bus_space handle */ 90 struct pci_attach_args vga_pa; 91 92 void *sc_powerhook; 93 struct pci_conf_state sc_pciconf; 94 }; 95 96 static u_int32_t agp_i810_get_aperture(struct agp_softc *); 97 static int agp_i810_set_aperture(struct agp_softc *, u_int32_t); 98 static int agp_i810_bind_page(struct agp_softc *, off_t, bus_addr_t); 99 static int agp_i810_unbind_page(struct agp_softc *, off_t); 100 static void agp_i810_flush_tlb(struct agp_softc *); 101 static int agp_i810_enable(struct agp_softc *, u_int32_t mode); 102 static struct agp_memory *agp_i810_alloc_memory(struct agp_softc *, int, 103 vsize_t); 104 static int agp_i810_free_memory(struct agp_softc *, struct agp_memory *); 105 static int agp_i810_bind_memory(struct agp_softc *, struct agp_memory *, off_t); 106 static int agp_i810_unbind_memory(struct agp_softc *, struct agp_memory *); 107 static void agp_i810_powerhook(int, void *); 108 109 static struct agp_methods agp_i810_methods = { 110 agp_i810_get_aperture, 111 agp_i810_set_aperture, 112 agp_i810_bind_page, 113 agp_i810_unbind_page, 114 agp_i810_flush_tlb, 115 agp_i810_enable, 116 agp_i810_alloc_memory, 117 agp_i810_free_memory, 118 agp_i810_bind_memory, 119 agp_i810_unbind_memory, 120 }; 121 122 /* XXXthorpej -- duplicated code (see arch/i386/pci/pchb.c) */ 123 static int 124 agp_i810_vgamatch(struct pci_attach_args *pa) 125 { 126 127 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY || 128 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA) 129 return (0); 130 131 switch (PCI_PRODUCT(pa->pa_id)) { 132 case PCI_PRODUCT_INTEL_82810_GC: 133 case PCI_PRODUCT_INTEL_82810_DC100_GC: 134 case PCI_PRODUCT_INTEL_82810E_GC: 135 case PCI_PRODUCT_INTEL_82815_FULL_GRAPH: 136 case PCI_PRODUCT_INTEL_82830MP_IV: 137 case PCI_PRODUCT_INTEL_82845G_IGD: 138 case PCI_PRODUCT_INTEL_82855GM_IGD: 139 case PCI_PRODUCT_INTEL_82865_IGD: 140 case PCI_PRODUCT_INTEL_82915G_IGD: 141 case PCI_PRODUCT_INTEL_82915GM_IGD: 142 case PCI_PRODUCT_INTEL_82945P_IGD: 143 case PCI_PRODUCT_INTEL_82945GM_IGD: 144 case PCI_PRODUCT_INTEL_82945GM_IGD_1: 145 return (1); 146 } 147 148 return (0); 149 } 150 151 int 152 agp_i810_attach(struct device *parent, struct device *self, void *aux) 153 { 154 struct agp_softc *sc = (void *)self; 155 struct agp_i810_softc *isc; 156 struct agp_gatt *gatt; 157 int error, apbase; 158 159 isc = malloc(sizeof *isc, M_AGP, M_NOWAIT|M_ZERO); 160 if (isc == NULL) { 161 aprint_error(": can't allocate chipset-specific softc\n"); 162 return ENOMEM; 163 } 164 sc->as_chipc = isc; 165 sc->as_methods = &agp_i810_methods; 166 167 if (pci_find_device(&isc->vga_pa, agp_i810_vgamatch) == 0) { 168 #if NAGP_INTEL > 0 169 const struct pci_attach_args *pa = aux; 170 171 switch (PCI_PRODUCT(pa->pa_id)) { 172 case PCI_PRODUCT_INTEL_82840_HB: 173 case PCI_PRODUCT_INTEL_82865_HB: 174 case PCI_PRODUCT_INTEL_82845G_DRAM: 175 case PCI_PRODUCT_INTEL_82815_FULL_HUB: 176 return agp_intel_attach(parent, self, aux); 177 } 178 #endif 179 aprint_error(": can't find internal VGA device config space\n"); 180 free(isc, M_AGP); 181 return ENOENT; 182 } 183 184 /* XXXfvdl */ 185 sc->as_dmat = isc->vga_pa.pa_dmat; 186 187 switch (PCI_PRODUCT(isc->vga_pa.pa_id)) { 188 case PCI_PRODUCT_INTEL_82810_GC: 189 case PCI_PRODUCT_INTEL_82810_DC100_GC: 190 case PCI_PRODUCT_INTEL_82810E_GC: 191 case PCI_PRODUCT_INTEL_82815_FULL_GRAPH: 192 isc->chiptype = CHIP_I810; 193 break; 194 case PCI_PRODUCT_INTEL_82830MP_IV: 195 case PCI_PRODUCT_INTEL_82845G_IGD: 196 isc->chiptype = CHIP_I830; 197 break; 198 case PCI_PRODUCT_INTEL_82855GM_IGD: 199 case PCI_PRODUCT_INTEL_82865_IGD: 200 isc->chiptype = CHIP_I855; 201 break; 202 case PCI_PRODUCT_INTEL_82915G_IGD: 203 case PCI_PRODUCT_INTEL_82915GM_IGD: 204 case PCI_PRODUCT_INTEL_82945P_IGD: 205 case PCI_PRODUCT_INTEL_82945GM_IGD: 206 case PCI_PRODUCT_INTEL_82945GM_IGD_1: 207 isc->chiptype = CHIP_I915; 208 break; 209 } 210 211 apbase = isc->chiptype == CHIP_I915 ? AGP_I915_GMADR : AGP_I810_GMADR; 212 error = agp_map_aperture(&isc->vga_pa, sc, apbase); 213 if (error != 0) { 214 aprint_error(": can't map aperture\n"); 215 free(isc, M_AGP); 216 return error; 217 } 218 219 if (isc->chiptype == CHIP_I915) { 220 error = pci_mapreg_map(&isc->vga_pa, AGP_I915_MMADR, 221 PCI_MAPREG_TYPE_MEM, 0, &isc->bst, &isc->bsh, NULL, NULL); 222 if (error != 0) { 223 aprint_error(": can't map mmadr registers\n"); 224 agp_generic_detach(sc); 225 return error; 226 } 227 error = pci_mapreg_map(&isc->vga_pa, AGP_I915_GTTADR, 228 PCI_MAPREG_TYPE_MEM, 0, &isc->gtt_bst, &isc->gtt_bsh, 229 NULL, NULL); 230 if (error != 0) { 231 aprint_error(": can't map gttadr registers\n"); 232 /* XXX we should release mmadr here */ 233 agp_generic_detach(sc); 234 return error; 235 } 236 } else { 237 error = pci_mapreg_map(&isc->vga_pa, AGP_I810_MMADR, 238 PCI_MAPREG_TYPE_MEM, 0, &isc->bst, &isc->bsh, NULL, NULL); 239 if (error != 0) { 240 aprint_error(": can't map mmadr registers\n"); 241 agp_generic_detach(sc); 242 return error; 243 } 244 } 245 246 isc->initial_aperture = AGP_GET_APERTURE(sc); 247 248 gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT); 249 if (!gatt) { 250 agp_generic_detach(sc); 251 return ENOMEM; 252 } 253 isc->gatt = gatt; 254 255 gatt->ag_entries = AGP_GET_APERTURE(sc) >> AGP_PAGE_SHIFT; 256 257 if (isc->chiptype == CHIP_I810) { 258 caddr_t virtual; 259 int dummyseg; 260 261 /* Some i810s have on-chip memory called dcache */ 262 if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED) 263 isc->dcache_size = 4 * 1024 * 1024; 264 else 265 isc->dcache_size = 0; 266 267 /* According to the specs the gatt on the i810 must be 64k */ 268 if (agp_alloc_dmamem(sc->as_dmat, 64 * 1024, 269 0, &gatt->ag_dmamap, &virtual, &gatt->ag_physical, 270 &gatt->ag_dmaseg, 1, &dummyseg) != 0) { 271 free(gatt, M_AGP); 272 agp_generic_detach(sc); 273 return ENOMEM; 274 } 275 gatt->ag_virtual = (uint32_t *)virtual; 276 277 gatt->ag_size = gatt->ag_entries * sizeof(u_int32_t); 278 memset(gatt->ag_virtual, 0, gatt->ag_size); 279 280 agp_flush_cache(); 281 /* Install the GATT. */ 282 WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1); 283 } else if (isc->chiptype == CHIP_I830) { 284 /* The i830 automatically initializes the 128k gatt on boot. */ 285 pcireg_t reg; 286 u_int32_t pgtblctl; 287 u_int16_t gcc1; 288 289 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 290 gcc1 = (u_int16_t)(reg >> 16); 291 switch (gcc1 & AGP_I830_GCC1_GMS) { 292 case AGP_I830_GCC1_GMS_STOLEN_512: 293 isc->stolen = (512 - 132) * 1024 / 4096; 294 break; 295 case AGP_I830_GCC1_GMS_STOLEN_1024: 296 isc->stolen = (1024 - 132) * 1024 / 4096; 297 break; 298 case AGP_I830_GCC1_GMS_STOLEN_8192: 299 isc->stolen = (8192 - 132) * 1024 / 4096; 300 break; 301 default: 302 isc->stolen = 0; 303 aprint_error( 304 ": unknown memory configuration, disabling\n"); 305 agp_generic_detach(sc); 306 return EINVAL; 307 } 308 if (isc->stolen > 0) { 309 aprint_error(": detected %dk stolen memory\n%s", 310 isc->stolen * 4, sc->as_dev.dv_xname); 311 } 312 313 /* GATT address is already in there, make sure it's enabled */ 314 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 315 pgtblctl |= 1; 316 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 317 318 gatt->ag_physical = pgtblctl & ~1; 319 } else if (isc->chiptype == CHIP_I855) { 320 /* The 855GM automatically initializes the 128k gatt on boot. */ 321 pcireg_t reg; 322 u_int32_t pgtblctl; 323 u_int16_t gcc1; 324 325 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I855_GCC1); 326 gcc1 = (u_int16_t)(reg >> 16); 327 switch (gcc1 & AGP_I855_GCC1_GMS) { 328 case AGP_I855_GCC1_GMS_STOLEN_1M: 329 isc->stolen = (1024 - 132) * 1024 / 4096; 330 break; 331 case AGP_I855_GCC1_GMS_STOLEN_4M: 332 isc->stolen = (4096 - 132) * 1024 / 4096; 333 break; 334 case AGP_I855_GCC1_GMS_STOLEN_8M: 335 isc->stolen = (8192 - 132) * 1024 / 4096; 336 break; 337 case AGP_I855_GCC1_GMS_STOLEN_16M: 338 isc->stolen = (16384 - 132) * 1024 / 4096; 339 break; 340 case AGP_I855_GCC1_GMS_STOLEN_32M: 341 isc->stolen = (32768 - 132) * 1024 / 4096; 342 break; 343 default: 344 isc->stolen = 0; 345 aprint_error( 346 ": unknown memory configuration, disabling\n"); 347 agp_generic_detach(sc); 348 return EINVAL; 349 } 350 if (isc->stolen > 0) { 351 aprint_error(": detected %dk stolen memory\n%s", 352 isc->stolen * 4, sc->as_dev.dv_xname); 353 } 354 355 /* GATT address is already in there, make sure it's enabled */ 356 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 357 pgtblctl |= 1; 358 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 359 360 gatt->ag_physical = pgtblctl & ~1; 361 } else { /* CHIP_I915 */ 362 /* The 915G automatically initializes the 256k gatt on boot. */ 363 pcireg_t reg; 364 u_int32_t pgtblctl; 365 u_int16_t gcc1; 366 367 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I915_GCC1); 368 gcc1 = (u_int16_t)(reg >> 16); 369 switch (gcc1 & AGP_I915_GCC1_GMS) { 370 case AGP_I915_GCC1_GMS_STOLEN_0M: 371 isc->stolen = 0; 372 break; 373 case AGP_I915_GCC1_GMS_STOLEN_1M: 374 isc->stolen = (1024 - 260) * 1024 / 4096; 375 break; 376 case AGP_I915_GCC1_GMS_STOLEN_8M: 377 isc->stolen = (8192 - 260) * 1024 / 4096; 378 break; 379 default: 380 isc->stolen = 0; 381 aprint_error( 382 ": unknown memory configuration, disabling\n"); 383 agp_generic_detach(sc); 384 return EINVAL; 385 } 386 if (isc->stolen > 0) { 387 aprint_error(": detected %dk stolen memory\n%s", 388 isc->stolen * 4, sc->as_dev.dv_xname); 389 } 390 391 /* GATT address is already in there, make sure it's enabled */ 392 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 393 pgtblctl |= 1; 394 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 395 396 gatt->ag_physical = pgtblctl & ~1; 397 } 398 399 /* 400 * Make sure the chipset can see everything. 401 */ 402 agp_flush_cache(); 403 404 isc->sc_powerhook = powerhook_establish(sc->as_dev.dv_xname, 405 agp_i810_powerhook, sc); 406 if (isc->sc_powerhook == NULL) 407 printf("%s: WARNING: unable to establish PCI power hook\n", 408 sc->as_dev.dv_xname); 409 410 return 0; 411 } 412 413 #if 0 414 static int 415 agp_i810_detach(struct agp_softc *sc) 416 { 417 int error; 418 struct agp_i810_softc *isc = sc->as_chipc; 419 420 error = agp_generic_detach(sc); 421 if (error) 422 return error; 423 424 /* Clear the GATT base. */ 425 if (sc->chiptype == CHIP_I810) { 426 WRITE4(AGP_I810_PGTBL_CTL, 0); 427 } else { 428 unsigned int pgtblctl; 429 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 430 pgtblctl &= ~1; 431 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 432 } 433 434 /* Put the aperture back the way it started. */ 435 AGP_SET_APERTURE(sc, isc->initial_aperture); 436 437 if (sc->chiptype == CHIP_I810) { 438 agp_free_dmamem(sc->as_dmat, gatt->ag_size, gatt->ag_dmamap, 439 (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1); 440 } 441 free(sc->gatt, M_AGP); 442 443 return 0; 444 } 445 #endif 446 447 static u_int32_t 448 agp_i810_get_aperture(struct agp_softc *sc) 449 { 450 struct agp_i810_softc *isc = sc->as_chipc; 451 pcireg_t reg; 452 453 if (isc->chiptype == CHIP_I810) { 454 u_int16_t miscc; 455 456 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM); 457 miscc = (u_int16_t)(reg >> 16); 458 if ((miscc & AGP_I810_MISCC_WINSIZE) == 459 AGP_I810_MISCC_WINSIZE_32) 460 return 32 * 1024 * 1024; 461 else 462 return 64 * 1024 * 1024; 463 } else if (isc->chiptype == CHIP_I830) { 464 u_int16_t gcc1; 465 466 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 467 gcc1 = (u_int16_t)(reg >> 16); 468 if ((gcc1 & AGP_I830_GCC1_GMASIZE) == AGP_I830_GCC1_GMASIZE_64) 469 return 64 * 1024 * 1024; 470 else 471 return 128 * 1024 * 1024; 472 } else if (isc->chiptype == CHIP_I855) { 473 return 128 * 1024 * 1024; 474 } else { /* CHIP_I915 */ 475 u_int16_t msac; 476 477 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I915_MSAC); 478 msac = (u_int16_t)(reg >> 16); 479 if (msac & AGP_I915_MSAC_APER_128M) 480 return 128 * 1024 * 1024; 481 else 482 return 256 * 1024 * 1024; 483 } 484 } 485 486 static int 487 agp_i810_set_aperture(struct agp_softc *sc, u_int32_t aperture) 488 { 489 struct agp_i810_softc *isc = sc->as_chipc; 490 pcireg_t reg; 491 492 if (isc->chiptype == CHIP_I810) { 493 u_int16_t miscc; 494 495 /* 496 * Double check for sanity. 497 */ 498 if (aperture != (32 * 1024 * 1024) && 499 aperture != (64 * 1024 * 1024)) { 500 printf("%s: bad aperture size %d\n", 501 sc->as_dev.dv_xname, aperture); 502 return EINVAL; 503 } 504 505 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM); 506 miscc = (u_int16_t)(reg >> 16); 507 miscc &= ~AGP_I810_MISCC_WINSIZE; 508 if (aperture == 32 * 1024 * 1024) 509 miscc |= AGP_I810_MISCC_WINSIZE_32; 510 else 511 miscc |= AGP_I810_MISCC_WINSIZE_64; 512 513 reg &= 0x0000ffff; 514 reg |= ((pcireg_t)miscc) << 16; 515 pci_conf_write(sc->as_pc, sc->as_tag, AGP_I810_SMRAM, reg); 516 } else if (isc->chiptype == CHIP_I830) { 517 u_int16_t gcc1; 518 519 if (aperture != (64 * 1024 * 1024) && 520 aperture != (128 * 1024 * 1024)) { 521 printf("%s: bad aperture size %d\n", 522 sc->as_dev.dv_xname, aperture); 523 return EINVAL; 524 } 525 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 526 gcc1 = (u_int16_t)(reg >> 16); 527 gcc1 &= ~AGP_I830_GCC1_GMASIZE; 528 if (aperture == 64 * 1024 * 1024) 529 gcc1 |= AGP_I830_GCC1_GMASIZE_64; 530 else 531 gcc1 |= AGP_I830_GCC1_GMASIZE_128; 532 533 reg &= 0x0000ffff; 534 reg |= ((pcireg_t)gcc1) << 16; 535 pci_conf_write(sc->as_pc, sc->as_tag, AGP_I830_GCC0, reg); 536 } else { /* CHIP_I855 or CHIP_I915 */ 537 if (aperture != agp_i810_get_aperture(sc)) { 538 printf("%s: bad aperture size %d\n", 539 sc->as_dev.dv_xname, aperture); 540 return EINVAL; 541 } 542 } 543 544 return 0; 545 } 546 547 static int 548 agp_i810_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical) 549 { 550 struct agp_i810_softc *isc = sc->as_chipc; 551 552 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) { 553 #ifdef AGP_DEBUG 554 printf("%s: failed: offset 0x%08x, shift %d, entries %d\n", 555 sc->as_dev.dv_xname, (int)offset, AGP_PAGE_SHIFT, 556 isc->gatt->ag_entries); 557 #endif 558 return EINVAL; 559 } 560 561 if (isc->chiptype != CHIP_I830) { 562 if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) { 563 #ifdef AGP_DEBUG 564 printf("%s: trying to bind into stolen memory", 565 sc->as_dev.dv_xname); 566 #endif 567 return EINVAL; 568 } 569 } 570 571 WRITEGTT(offset, physical | 1); 572 return 0; 573 } 574 575 static int 576 agp_i810_unbind_page(struct agp_softc *sc, off_t offset) 577 { 578 struct agp_i810_softc *isc = sc->as_chipc; 579 580 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) 581 return EINVAL; 582 583 if (isc->chiptype != CHIP_I810 ) { 584 if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) { 585 #ifdef AGP_DEBUG 586 printf("%s: trying to unbind from stolen memory", 587 sc->as_dev.dv_xname); 588 #endif 589 return EINVAL; 590 } 591 } 592 593 WRITEGTT(offset, 0); 594 return 0; 595 } 596 597 /* 598 * Writing via memory mapped registers already flushes all TLBs. 599 */ 600 static void 601 agp_i810_flush_tlb(struct agp_softc *sc __unused) 602 { 603 } 604 605 static int 606 agp_i810_enable(struct agp_softc *sc __unused, u_int32_t mode __unused) 607 { 608 609 return 0; 610 } 611 612 static struct agp_memory * 613 agp_i810_alloc_memory(struct agp_softc *sc, int type, vsize_t size) 614 { 615 struct agp_i810_softc *isc = sc->as_chipc; 616 struct agp_memory *mem; 617 618 #ifdef AGP_DEBUG 619 printf("AGP: alloc(%d, 0x%x)\n", type, (int) size); 620 #endif 621 622 if ((size & (AGP_PAGE_SIZE - 1)) != 0) 623 return 0; 624 625 if (sc->as_allocated + size > sc->as_maxmem) 626 return 0; 627 628 if (type == 1) { 629 /* 630 * Mapping local DRAM into GATT. 631 */ 632 if (isc->chiptype != CHIP_I810 ) 633 return 0; 634 if (size != isc->dcache_size) 635 return 0; 636 } else if (type == 2) { 637 /* 638 * Bogus mapping for the hardware cursor. 639 */ 640 if (size != AGP_PAGE_SIZE && size != 4 * AGP_PAGE_SIZE) 641 return 0; 642 } 643 644 mem = malloc(sizeof *mem, M_AGP, M_WAITOK|M_ZERO); 645 if (mem == NULL) 646 return NULL; 647 mem->am_id = sc->as_nextid++; 648 mem->am_size = size; 649 mem->am_type = type; 650 651 if (type == 2) { 652 /* 653 * Allocate and wire down the memory now so that we can 654 * get its physical address. 655 */ 656 mem->am_dmaseg = malloc(sizeof *mem->am_dmaseg, M_AGP, 657 M_WAITOK); 658 if (mem->am_dmaseg == NULL) { 659 free(mem, M_AGP); 660 return NULL; 661 } 662 if (agp_alloc_dmamem(sc->as_dmat, size, 0, 663 &mem->am_dmamap, &mem->am_virtual, &mem->am_physical, 664 mem->am_dmaseg, 1, &mem->am_nseg) != 0) { 665 free(mem->am_dmaseg, M_AGP); 666 free(mem, M_AGP); 667 return NULL; 668 } 669 memset(mem->am_virtual, 0, size); 670 } else if (type != 1) { 671 if (bus_dmamap_create(sc->as_dmat, size, size / PAGE_SIZE + 1, 672 size, 0, BUS_DMA_NOWAIT, 673 &mem->am_dmamap) != 0) { 674 free(mem, M_AGP); 675 return NULL; 676 } 677 } 678 679 TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link); 680 sc->as_allocated += size; 681 682 return mem; 683 } 684 685 static int 686 agp_i810_free_memory(struct agp_softc *sc, struct agp_memory *mem) 687 { 688 if (mem->am_is_bound) 689 return EBUSY; 690 691 if (mem->am_type == 2) { 692 agp_free_dmamem(sc->as_dmat, mem->am_size, mem->am_dmamap, 693 mem->am_virtual, mem->am_dmaseg, mem->am_nseg); 694 free(mem->am_dmaseg, M_AGP); 695 } 696 697 sc->as_allocated -= mem->am_size; 698 TAILQ_REMOVE(&sc->as_memory, mem, am_link); 699 free(mem, M_AGP); 700 return 0; 701 } 702 703 static int 704 agp_i810_bind_memory(struct agp_softc *sc, struct agp_memory *mem, 705 off_t offset) 706 { 707 struct agp_i810_softc *isc = sc->as_chipc; 708 u_int32_t regval, i; 709 710 /* 711 * XXX evil hack: the PGTBL_CTL appearently gets overwritten by the 712 * X server for mysterious reasons which leads to crashes if we write 713 * to the GTT through the MMIO window. 714 * Until the issue is solved, simply restore it. 715 */ 716 regval = bus_space_read_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL); 717 if (regval != (isc->gatt->ag_physical | 1)) { 718 printf("agp_i810_bind_memory: PGTBL_CTL is 0x%x - fixing\n", 719 regval); 720 bus_space_write_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL, 721 isc->gatt->ag_physical | 1); 722 } 723 724 if (mem->am_type == 2) { 725 WRITEGTT(offset, mem->am_physical | 1); 726 mem->am_offset = offset; 727 mem->am_is_bound = 1; 728 return 0; 729 } 730 731 if (mem->am_type != 1) 732 return agp_generic_bind_memory(sc, mem, offset); 733 734 if (isc->chiptype != CHIP_I810) 735 return EINVAL; 736 737 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 738 WRITEGTT(offset, i | 3); 739 mem->am_is_bound = 1; 740 return 0; 741 } 742 743 static int 744 agp_i810_unbind_memory(struct agp_softc *sc, struct agp_memory *mem) 745 { 746 struct agp_i810_softc *isc = sc->as_chipc; 747 u_int32_t i; 748 749 if (mem->am_type == 2) { 750 WRITEGTT(mem->am_offset, 0); 751 mem->am_offset = 0; 752 mem->am_is_bound = 0; 753 return 0; 754 } 755 756 if (mem->am_type != 1) 757 return agp_generic_unbind_memory(sc, mem); 758 759 if (isc->chiptype != CHIP_I810) 760 return EINVAL; 761 762 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 763 WRITEGTT(i, 0); 764 mem->am_is_bound = 0; 765 return 0; 766 } 767 768 static void 769 agp_i810_powerhook(int why, void *arg) 770 { 771 struct agp_softc *sc = (struct agp_softc *)arg; 772 struct agp_i810_softc *isc = sc->as_chipc; 773 774 if (why == PWR_RESUME) { 775 pci_conf_restore(sc->as_pc, sc->as_tag, &isc->sc_pciconf); 776 agp_flush_cache(); 777 } else if ((why == PWR_STANDBY) || (why == PWR_SUSPEND)) 778 pci_conf_capture(sc->as_pc, sc->as_tag, &isc->sc_pciconf); 779 780 return; 781 } 782