agp_i810.c revision 103272
163010Sdfr/*- 263010Sdfr * Copyright (c) 2000 Doug Rabson 363010Sdfr * Copyright (c) 2000 Ruslan Ermilov 463010Sdfr * All rights reserved. 563010Sdfr * 663010Sdfr * Redistribution and use in source and binary forms, with or without 763010Sdfr * modification, are permitted provided that the following conditions 863010Sdfr * are met: 963010Sdfr * 1. Redistributions of source code must retain the above copyright 1063010Sdfr * notice, this list of conditions and the following disclaimer. 1163010Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1263010Sdfr * notice, this list of conditions and the following disclaimer in the 1363010Sdfr * documentation and/or other materials provided with the distribution. 1463010Sdfr * 1563010Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1663010Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1763010Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1863010Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1963010Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2063010Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2163010Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2263010Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2363010Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2463010Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2563010Sdfr * SUCH DAMAGE. 2663010Sdfr * 2763010Sdfr * $FreeBSD: head/sys/dev/agp/agp_i810.c 103272 2002-09-13 04:17:28Z anholt $ 2863010Sdfr */ 2963010Sdfr 30103243Sanholt/* 31103243Sanholt * Fixes for 830/845G support: David Dawes <dawes@xfree86.org> 32103243Sanholt */ 33103243Sanholt 3463010Sdfr#include "opt_bus.h" 3563010Sdfr#include "opt_pci.h" 3663010Sdfr 3763010Sdfr#include <sys/param.h> 3863010Sdfr#include <sys/systm.h> 3963010Sdfr#include <sys/malloc.h> 4063010Sdfr#include <sys/kernel.h> 4163010Sdfr#include <sys/bus.h> 4263010Sdfr#include <sys/lock.h> 43102480Sbde#include <sys/lockmgr.h> 4476827Salfred#include <sys/mutex.h> 4579339Sjhb#include <sys/proc.h> 4663010Sdfr 4763010Sdfr#include <pci/pcivar.h> 4863010Sdfr#include <pci/pcireg.h> 4963010Sdfr#include <pci/agppriv.h> 5063010Sdfr#include <pci/agpreg.h> 5163010Sdfr 5263010Sdfr#include <vm/vm.h> 5363010Sdfr#include <vm/vm_object.h> 5463010Sdfr#include <vm/vm_page.h> 5563010Sdfr#include <vm/vm_pageout.h> 5663010Sdfr#include <vm/pmap.h> 5763010Sdfr 5863010Sdfr#include <machine/bus.h> 5963010Sdfr#include <machine/resource.h> 6063010Sdfr#include <sys/rman.h> 6163010Sdfr 6263010SdfrMALLOC_DECLARE(M_AGP); 6363010Sdfr 6463010Sdfr#define READ1(off) bus_space_read_1(sc->bst, sc->bsh, off) 65103243Sanholt#define READ4(off) bus_space_read_4(sc->bst, sc->bsh, off) 6663010Sdfr#define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v) 6763010Sdfr 68103243Sanholt#define CHIP_I810 0 /* i810/i815 */ 69103243Sanholt#define CHIP_I830 1 /* i830/i845 */ 70103243Sanholt 7163010Sdfrstruct agp_i810_softc { 7263010Sdfr struct agp_softc agp; 7363010Sdfr u_int32_t initial_aperture; /* aperture size at startup */ 7463010Sdfr struct agp_gatt *gatt; 75103243Sanholt int chiptype; /* i810-like or i830 */ 76103243Sanholt u_int32_t dcache_size; /* i810 only */ 77103243Sanholt u_int32_t stolen; /* number of i830/845 gtt entries for stolen memory */ 7863010Sdfr device_t bdev; /* bridge device */ 7963010Sdfr struct resource *regs; /* memory mapped GC registers */ 8063010Sdfr bus_space_tag_t bst; /* bus_space tag */ 8163010Sdfr bus_space_handle_t bsh; /* bus_space handle */ 8263010Sdfr}; 8363010Sdfr 8463010Sdfrstatic const char* 8563010Sdfragp_i810_match(device_t dev) 8663010Sdfr{ 8763010Sdfr if (pci_get_class(dev) != PCIC_DISPLAY 8863010Sdfr || pci_get_subclass(dev) != PCIS_DISPLAY_VGA) 8963010Sdfr return NULL; 9063010Sdfr 9163010Sdfr switch (pci_get_devid(dev)) { 9263010Sdfr case 0x71218086: 9363010Sdfr return ("Intel 82810 (i810 GMCH) SVGA controller"); 9463010Sdfr 9563010Sdfr case 0x71238086: 9663010Sdfr return ("Intel 82810-DC100 (i810-DC100 GMCH) SVGA controller"); 9763010Sdfr 9863010Sdfr case 0x71258086: 9963010Sdfr return ("Intel 82810E (i810E GMCH) SVGA controller"); 10067197Sru 10167197Sru case 0x11328086: 10267197Sru return ("Intel 82815 (i815 GMCH) SVGA controller"); 103103243Sanholt 104103243Sanholt case 0x35778086: 105103243Sanholt return ("Intel 82830 (i830M GMCH) SVGA controller"); 106103243Sanholt 107103243Sanholt case 0x25628086: 108103243Sanholt return ("Intel 82845 (i845 GMCH) SVGA controller"); 10963010Sdfr }; 11063010Sdfr 11163010Sdfr return NULL; 11263010Sdfr} 11363010Sdfr 11463010Sdfr/* 11563010Sdfr * Find bridge device. 11663010Sdfr */ 11763010Sdfrstatic device_t 11863010Sdfragp_i810_find_bridge(device_t dev) 11963010Sdfr{ 12063010Sdfr device_t *children, child; 12163010Sdfr int nchildren, i; 12263010Sdfr u_int32_t devid; 12363010Sdfr 12463010Sdfr /* 12567197Sru * Calculate bridge device's ID. 12663010Sdfr */ 12767197Sru devid = pci_get_devid(dev); 12867197Sru switch (devid) { 12967197Sru case 0x71218086: 13067197Sru case 0x71238086: 13167197Sru case 0x71258086: 13267197Sru devid -= 0x10000; 13367197Sru break; 13467197Sru 13567197Sru case 0x11328086: 136103243Sanholt case 0x35778086: 137103243Sanholt case 0x25628086: 138103243Sanholt devid -= 0x20000; 13967197Sru break; 14067197Sru }; 14163010Sdfr if (device_get_children(device_get_parent(dev), &children, &nchildren)) 14263010Sdfr return 0; 14363010Sdfr 14463010Sdfr for (i = 0; i < nchildren; i++) { 14563010Sdfr child = children[i]; 14663010Sdfr 14763010Sdfr if (pci_get_devid(child) == devid) { 14863010Sdfr free(children, M_TEMP); 14963010Sdfr return child; 15063010Sdfr } 15163010Sdfr } 15263010Sdfr free(children, M_TEMP); 15363010Sdfr return 0; 15463010Sdfr} 15563010Sdfr 15663010Sdfrstatic int 15763010Sdfragp_i810_probe(device_t dev) 15863010Sdfr{ 15963010Sdfr const char *desc; 16063010Sdfr 16163010Sdfr desc = agp_i810_match(dev); 16263010Sdfr if (desc) { 16363010Sdfr device_t bdev; 16463010Sdfr u_int8_t smram; 165103243Sanholt int devid = pci_get_devid(dev); 16663010Sdfr 16763010Sdfr bdev = agp_i810_find_bridge(dev); 16863010Sdfr if (!bdev) { 16963010Sdfr if (bootverbose) 17063010Sdfr printf("I810: can't find bridge device\n"); 17163010Sdfr return ENXIO; 17263010Sdfr } 17363010Sdfr 174103243Sanholt /* 175103243Sanholt * checking whether internal graphics device has been activated. 176103243Sanholt */ 177103243Sanholt if ( (devid != 0x35778086 ) && 178103243Sanholt (devid != 0x25628086 ) ) { 179103243Sanholt smram = pci_read_config(bdev, AGP_I810_SMRAM, 1); 180103243Sanholt if ((smram & AGP_I810_SMRAM_GMS) 181103243Sanholt == AGP_I810_SMRAM_GMS_DISABLED) { 182103243Sanholt if (bootverbose) 183103243Sanholt printf("I810: disabled, not probing\n"); 184103243Sanholt return ENXIO; 185103243Sanholt } 186103243Sanholt } else { /* I830MG */ 187103243Sanholt unsigned int gcc1; 188103243Sanholt gcc1 = pci_read_config(bdev, AGP_I830_GCC1, 1); 189103243Sanholt if ((gcc1 & AGP_I830_GCC1_DEV2) == AGP_I830_GCC1_DEV2_DISABLED) { 190103243Sanholt if (bootverbose) 191103243Sanholt printf("I830: disabled, not probing\n"); 192103243Sanholt return ENXIO; 193103243Sanholt } 19463010Sdfr } 19563010Sdfr 19663010Sdfr device_verbose(dev); 19763010Sdfr device_set_desc(dev, desc); 19863010Sdfr return 0; 19963010Sdfr } 20063010Sdfr 20163010Sdfr return ENXIO; 20263010Sdfr} 20363010Sdfr 20463010Sdfrstatic int 20563010Sdfragp_i810_attach(device_t dev) 20663010Sdfr{ 20763010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 20863010Sdfr struct agp_gatt *gatt; 20963010Sdfr int error, rid; 21063010Sdfr 21163010Sdfr sc->bdev = agp_i810_find_bridge(dev); 21263010Sdfr if (!sc->bdev) 21363010Sdfr return ENOENT; 21463010Sdfr 21563010Sdfr error = agp_generic_attach(dev); 21663010Sdfr if (error) 21763010Sdfr return error; 21863010Sdfr 219103243Sanholt switch (pci_get_devid(dev)) { 220103243Sanholt case 0x71218086: 221103243Sanholt case 0x71238086: 222103243Sanholt case 0x71258086: 223103243Sanholt case 0x11328086: 224103243Sanholt sc->chiptype = CHIP_I810; 225103243Sanholt case 0x35778086: 226103243Sanholt case 0x25628086: 227103243Sanholt sc->chiptype = CHIP_I830; 228103243Sanholt }; 229103243Sanholt 230103243Sanholt /* Same for i810 and i830 */ 23163010Sdfr rid = AGP_I810_MMADR; 23263010Sdfr sc->regs = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 23363010Sdfr 0, ~0, 1, RF_ACTIVE); 23463010Sdfr if (!sc->regs) { 23563010Sdfr agp_generic_detach(dev); 23663010Sdfr return ENOMEM; 23763010Sdfr } 23863010Sdfr sc->bst = rman_get_bustag(sc->regs); 23963010Sdfr sc->bsh = rman_get_bushandle(sc->regs); 24063010Sdfr 24163010Sdfr sc->initial_aperture = AGP_GET_APERTURE(dev); 24263010Sdfr 243103243Sanholt gatt = malloc( sizeof(struct agp_gatt), M_AGP, M_NOWAIT); 244103243Sanholt if (!gatt) { 245103243Sanholt agp_generic_detach(dev); 246103243Sanholt return ENOMEM; 247103243Sanholt } 248103243Sanholt sc->gatt = gatt; 24963010Sdfr 250103243Sanholt gatt->ag_entries = AGP_GET_APERTURE(dev) >> AGP_PAGE_SHIFT; 25163010Sdfr 252103243Sanholt if ( sc->chiptype == CHIP_I810 ) { 253103243Sanholt /* Some i810s have on-chip memory called dcache */ 254103243Sanholt if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED) 255103243Sanholt sc->dcache_size = 4 * 1024 * 1024; 256103243Sanholt else 257103243Sanholt sc->dcache_size = 0; 258103243Sanholt 259103243Sanholt /* According to the specs the gatt on the i810 must be 64k */ 260103243Sanholt gatt->ag_virtual = contigmalloc( 64 * 1024, M_AGP, 0, 261103243Sanholt 0, ~0, PAGE_SIZE, 0); 262103243Sanholt if (!gatt->ag_virtual) { 263103243Sanholt if (bootverbose) 264103243Sanholt device_printf(dev, "contiguous allocation failed\n"); 265103243Sanholt free(gatt, M_AGP); 26663010Sdfr agp_generic_detach(dev); 26763010Sdfr return ENOMEM; 26863010Sdfr } 269103243Sanholt bzero(gatt->ag_virtual, gatt->ag_entries * sizeof(u_int32_t)); 270103243Sanholt 271103243Sanholt gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual); 272103243Sanholt agp_flush_cache(); 273103243Sanholt /* Install the GATT. */ 274103243Sanholt WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1); 275103243Sanholt } else { 276103243Sanholt /* The i830 automatically initializes the 128k gatt on boot. */ 277103243Sanholt unsigned int gcc1, pgtblctl; 278103243Sanholt 279103243Sanholt gcc1 = pci_read_config(sc->bdev, AGP_I830_GCC1, 1); 280103243Sanholt switch (gcc1 & AGP_I830_GCC1_GMS) { 281103243Sanholt case AGP_I830_GCC1_GMS_STOLEN_512: 282103243Sanholt sc->stolen = (512 - 132) * 1024 / 4096; 283103243Sanholt break; 284103243Sanholt case AGP_I830_GCC1_GMS_STOLEN_1024: 285103243Sanholt sc->stolen = (1024 - 132) * 1024 / 4096; 286103243Sanholt break; 287103243Sanholt case AGP_I830_GCC1_GMS_STOLEN_8192: 288103243Sanholt sc->stolen = (8192 - 132) * 1024 / 4096; 289103243Sanholt break; 290103243Sanholt default: 291103243Sanholt sc->stolen = 0; 292103243Sanholt device_printf(dev, "unknown memory configuration, disabling\n"); 293103243Sanholt agp_generic_detach(dev); 294103243Sanholt return EINVAL; 295103243Sanholt } 296103243Sanholt if (sc->stolen > 0) 297103243Sanholt device_printf(dev, "detected %dk stolen memory\n", sc->stolen * 4); 298103243Sanholt device_printf(dev, "aperture size is %dM\n", sc->initial_aperture / 1024 / 1024); 299103243Sanholt 300103243Sanholt /* GATT address is already in there, make sure it's enabled */ 301103243Sanholt pgtblctl = READ4(AGP_I810_PGTBL_CTL); 302103243Sanholt#if 0 303103243Sanholt device_printf(dev, "PGTBL_CTL is 0x%08x\n", pgtblctl); 304103243Sanholt#endif 305103243Sanholt pgtblctl |= 1; 306103243Sanholt WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 307103243Sanholt 308103243Sanholt gatt->ag_physical = pgtblctl & ~1; 30963010Sdfr } 31063010Sdfr 31163010Sdfr /* 31263010Sdfr * Make sure the chipset can see everything. 31363010Sdfr */ 31463010Sdfr agp_flush_cache(); 31563010Sdfr 31663010Sdfr return 0; 31763010Sdfr} 31863010Sdfr 31963010Sdfrstatic int 32063010Sdfragp_i810_detach(device_t dev) 32163010Sdfr{ 32263010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 32363010Sdfr int error; 32463010Sdfr 32563010Sdfr error = agp_generic_detach(dev); 32663010Sdfr if (error) 32763010Sdfr return error; 32863010Sdfr 32963010Sdfr /* Clear the GATT base. */ 330103243Sanholt if ( sc->chiptype == CHIP_I810 ) { 331103243Sanholt WRITE4(AGP_I810_PGTBL_CTL, 0); 332103243Sanholt } else { 333103243Sanholt unsigned int pgtblctl; 334103243Sanholt pgtblctl = READ4(AGP_I810_PGTBL_CTL); 335103243Sanholt pgtblctl &= ~1; 336103243Sanholt WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 337103243Sanholt } 33863010Sdfr 33963010Sdfr /* Put the aperture back the way it started. */ 34063010Sdfr AGP_SET_APERTURE(dev, sc->initial_aperture); 34163010Sdfr 342103243Sanholt if ( sc->chiptype == CHIP_I810 ) { 343103243Sanholt contigfree(sc->gatt->ag_virtual, 64 * 1024, M_AGP); 344103243Sanholt } 345103243Sanholt free(sc->gatt, M_AGP); 34663010Sdfr 34763010Sdfr bus_release_resource(dev, SYS_RES_MEMORY, 34863010Sdfr AGP_I810_MMADR, sc->regs); 34963010Sdfr 35063010Sdfr return 0; 35163010Sdfr} 35263010Sdfr 35363010Sdfrstatic u_int32_t 35463010Sdfragp_i810_get_aperture(device_t dev) 35563010Sdfr{ 35663010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 35763010Sdfr 358103243Sanholt if ( sc->chiptype == CHIP_I810 ) { 359103243Sanholt u_int16_t miscc; 360103243Sanholt miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2); 361103243Sanholt if ((miscc & AGP_I810_MISCC_WINSIZE) == AGP_I810_MISCC_WINSIZE_32) 362103243Sanholt return 32 * 1024 * 1024; 363103243Sanholt else 364103243Sanholt return 64 * 1024 * 1024; 365103243Sanholt } else { /* I830 */ 366103243Sanholt unsigned int gcc1; 367103243Sanholt 368103243Sanholt gcc1 = pci_read_config(sc->bdev, AGP_I830_GCC1, 2); 369103243Sanholt if ((gcc1 & AGP_I830_GCC1_GMASIZE) == AGP_I830_GCC1_GMASIZE_64) 370103243Sanholt return 64 * 1024 * 1024; 371103243Sanholt else 372103243Sanholt return 128 * 1024 * 1024; 373103243Sanholt } 37463010Sdfr} 37563010Sdfr 37663010Sdfrstatic int 37763010Sdfragp_i810_set_aperture(device_t dev, u_int32_t aperture) 37863010Sdfr{ 37963010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 38063010Sdfr u_int16_t miscc; 38163010Sdfr 382103243Sanholt if ( sc->chiptype == CHIP_I810 ) { 383103243Sanholt /* 384103243Sanholt * Double check for sanity. 385103243Sanholt */ 386103243Sanholt if (aperture != 32 * 1024 * 1024 && aperture != 64 * 1024 * 1024) { 387103243Sanholt device_printf(dev, "bad aperture size %d\n", aperture); 388103243Sanholt return EINVAL; 389103243Sanholt } 390103243Sanholt 391103243Sanholt miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2); 392103243Sanholt miscc &= ~AGP_I810_MISCC_WINSIZE; 393103243Sanholt if (aperture == 32 * 1024 * 1024) 394103243Sanholt miscc |= AGP_I810_MISCC_WINSIZE_32; 395103243Sanholt else 396103243Sanholt miscc |= AGP_I810_MISCC_WINSIZE_64; 397103243Sanholt 398103243Sanholt pci_write_config(sc->bdev, AGP_I810_MISCC, miscc, 2); 399103243Sanholt } else { /* I830 */ 400103243Sanholt unsigned int gcc1; 40163010Sdfr 402103243Sanholt if (aperture != 64 * 1024 * 1024 && aperture != 128 * 1024 * 1024) { 403103243Sanholt device_printf(dev, "bad aperture size %d\n", aperture); 404103243Sanholt return EINVAL; 405103243Sanholt } 406103243Sanholt gcc1 = pci_read_config(sc->bdev, AGP_I830_GCC1, 2); 407103243Sanholt gcc1 &= ~AGP_I830_GCC1_GMASIZE; 408103243Sanholt if (aperture == 64 * 1024 * 1024) 409103243Sanholt gcc1 |= AGP_I830_GCC1_GMASIZE_64; 410103243Sanholt else 411103243Sanholt gcc1 |= AGP_I830_GCC1_GMASIZE_128; 41263010Sdfr 413103243Sanholt pci_write_config(sc->bdev, AGP_I830_GCC1, gcc1, 2); 414103243Sanholt } 41563010Sdfr 41663010Sdfr return 0; 41763010Sdfr} 41863010Sdfr 41963010Sdfrstatic int 42063010Sdfragp_i810_bind_page(device_t dev, int offset, vm_offset_t physical) 42163010Sdfr{ 42263010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 42363010Sdfr 424103243Sanholt if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) { 425103243Sanholt device_printf(dev, "failed: offset is 0x%08x, shift is %d, entries is %d\n", offset, AGP_PAGE_SHIFT, sc->gatt->ag_entries); 42663010Sdfr return EINVAL; 427103243Sanholt } 42863010Sdfr 429103243Sanholt if ( sc->chiptype == CHIP_I830 ) { 430103243Sanholt if ( (offset >> AGP_PAGE_SHIFT) < sc->stolen ) { 431103243Sanholt device_printf(dev, "trying to bind into stolen memory"); 432103243Sanholt return EINVAL; 433103243Sanholt } 434103243Sanholt } 435103243Sanholt 43663010Sdfr WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, physical | 1); 43763010Sdfr return 0; 43863010Sdfr} 43963010Sdfr 44063010Sdfrstatic int 44163010Sdfragp_i810_unbind_page(device_t dev, int offset) 44263010Sdfr{ 44363010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 44463010Sdfr 44563010Sdfr if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 44663010Sdfr return EINVAL; 44763010Sdfr 448103243Sanholt if ( sc->chiptype == CHIP_I830 ) { 449103272Sanholt if ( (offset >> AGP_PAGE_SHIFT) < sc->stolen ) { 450103243Sanholt device_printf(dev, "trying to unbind from stolen memory"); 451103272Sanholt return EINVAL; 452103272Sanholt } 453103243Sanholt } 454103243Sanholt 45563010Sdfr WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, 0); 45663010Sdfr return 0; 45763010Sdfr} 45863010Sdfr 45963010Sdfr/* 46063010Sdfr * Writing via memory mapped registers already flushes all TLBs. 46163010Sdfr */ 46263010Sdfrstatic void 46363010Sdfragp_i810_flush_tlb(device_t dev) 46463010Sdfr{ 46563010Sdfr} 46663010Sdfr 46763010Sdfrstatic int 46863010Sdfragp_i810_enable(device_t dev, u_int32_t mode) 46963010Sdfr{ 47063010Sdfr 47163010Sdfr return 0; 47263010Sdfr} 47363010Sdfr 47463010Sdfrstatic struct agp_memory * 47563010Sdfragp_i810_alloc_memory(device_t dev, int type, vm_size_t size) 47663010Sdfr{ 47763010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 47863010Sdfr struct agp_memory *mem; 47963010Sdfr 48063010Sdfr if ((size & (AGP_PAGE_SIZE - 1)) != 0) 48163010Sdfr return 0; 48263010Sdfr 48363010Sdfr if (sc->agp.as_allocated + size > sc->agp.as_maxmem) 48463010Sdfr return 0; 48563010Sdfr 48663010Sdfr if (type == 1) { 48763010Sdfr /* 48863010Sdfr * Mapping local DRAM into GATT. 48963010Sdfr */ 490103243Sanholt if ( sc->chiptype == CHIP_I830 ) 491103243Sanholt return 0; 49263010Sdfr if (size != sc->dcache_size) 49363010Sdfr return 0; 49463010Sdfr } else if (type == 2) { 49563010Sdfr /* 49663010Sdfr * Bogus mapping of a single page for the hardware cursor. 49763010Sdfr */ 49863010Sdfr if (size != AGP_PAGE_SIZE) 49963010Sdfr return 0; 50063010Sdfr } 50163010Sdfr 50263010Sdfr mem = malloc(sizeof *mem, M_AGP, M_WAITOK); 50363010Sdfr mem->am_id = sc->agp.as_nextid++; 50463010Sdfr mem->am_size = size; 50563010Sdfr mem->am_type = type; 50663010Sdfr if (type != 1) 50763010Sdfr mem->am_obj = vm_object_allocate(OBJT_DEFAULT, 50863010Sdfr atop(round_page(size))); 50963010Sdfr else 51063010Sdfr mem->am_obj = 0; 51163010Sdfr 51263010Sdfr if (type == 2) { 51363010Sdfr /* 51463010Sdfr * Allocate and wire down the page now so that we can 51563010Sdfr * get its physical address. 51663010Sdfr */ 51763010Sdfr vm_page_t m; 518101647Salc m = vm_page_grab(mem->am_obj, 0, 519101647Salc VM_ALLOC_WIRED | VM_ALLOC_ZERO | VM_ALLOC_RETRY); 520100422Salc if ((m->flags & PG_ZERO) == 0) 521102382Salc pmap_zero_page(m); 52299988Salc vm_page_lock_queues(); 52363010Sdfr mem->am_physical = VM_PAGE_TO_PHYS(m); 52463010Sdfr vm_page_wakeup(m); 52599988Salc vm_page_unlock_queues(); 52663010Sdfr } else { 52763010Sdfr mem->am_physical = 0; 52863010Sdfr } 52963010Sdfr 53063010Sdfr mem->am_offset = 0; 53163010Sdfr mem->am_is_bound = 0; 53263010Sdfr TAILQ_INSERT_TAIL(&sc->agp.as_memory, mem, am_link); 53363010Sdfr sc->agp.as_allocated += size; 53463010Sdfr 53563010Sdfr return mem; 53663010Sdfr} 53763010Sdfr 53863010Sdfrstatic int 53963010Sdfragp_i810_free_memory(device_t dev, struct agp_memory *mem) 54063010Sdfr{ 54163010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 54263010Sdfr 54363010Sdfr if (mem->am_is_bound) 54463010Sdfr return EBUSY; 54563010Sdfr 54663010Sdfr if (mem->am_type == 2) { 54763010Sdfr /* 54863010Sdfr * Unwire the page which we wired in alloc_memory. 54963010Sdfr */ 55063010Sdfr vm_page_t m = vm_page_lookup(mem->am_obj, 0); 55199927Salc vm_page_lock_queues(); 55263010Sdfr vm_page_unwire(m, 0); 55399927Salc vm_page_unlock_queues(); 55463010Sdfr } 55563010Sdfr 55663010Sdfr sc->agp.as_allocated -= mem->am_size; 55763010Sdfr TAILQ_REMOVE(&sc->agp.as_memory, mem, am_link); 55863010Sdfr if (mem->am_obj) 55963010Sdfr vm_object_deallocate(mem->am_obj); 56063010Sdfr free(mem, M_AGP); 56163010Sdfr return 0; 56263010Sdfr} 56363010Sdfr 56463010Sdfrstatic int 56563010Sdfragp_i810_bind_memory(device_t dev, struct agp_memory *mem, 56663010Sdfr vm_offset_t offset) 56763010Sdfr{ 56863010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 56963010Sdfr vm_offset_t i; 57063010Sdfr 57163010Sdfr if (mem->am_type != 1) 57263010Sdfr return agp_generic_bind_memory(dev, mem, offset); 57363010Sdfr 574103272Sanholt if ( sc->chiptype == CHIP_I830 ) 575103243Sanholt return EINVAL; 576103243Sanholt 57763010Sdfr for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) { 57863010Sdfr WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, 57963010Sdfr i | 3); 58063010Sdfr } 58163010Sdfr 58263010Sdfr return 0; 58363010Sdfr} 58463010Sdfr 58563010Sdfrstatic int 58663010Sdfragp_i810_unbind_memory(device_t dev, struct agp_memory *mem) 58763010Sdfr{ 58863010Sdfr struct agp_i810_softc *sc = device_get_softc(dev); 58963010Sdfr vm_offset_t i; 59063010Sdfr 59163010Sdfr if (mem->am_type != 1) 59263010Sdfr return agp_generic_unbind_memory(dev, mem); 59363010Sdfr 594103243Sanholt if ( sc->chiptype == CHIP_I830 ) 595103243Sanholt return EINVAL; 596103243Sanholt 59763010Sdfr for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 59863010Sdfr WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0); 59963010Sdfr 60063010Sdfr return 0; 60163010Sdfr} 60263010Sdfr 60363010Sdfrstatic device_method_t agp_i810_methods[] = { 60463010Sdfr /* Device interface */ 60563010Sdfr DEVMETHOD(device_probe, agp_i810_probe), 60663010Sdfr DEVMETHOD(device_attach, agp_i810_attach), 60763010Sdfr DEVMETHOD(device_detach, agp_i810_detach), 60863010Sdfr DEVMETHOD(device_shutdown, bus_generic_shutdown), 60963010Sdfr DEVMETHOD(device_suspend, bus_generic_suspend), 61063010Sdfr DEVMETHOD(device_resume, bus_generic_resume), 61163010Sdfr 61263010Sdfr /* AGP interface */ 61363010Sdfr DEVMETHOD(agp_get_aperture, agp_i810_get_aperture), 61463010Sdfr DEVMETHOD(agp_set_aperture, agp_i810_set_aperture), 61563010Sdfr DEVMETHOD(agp_bind_page, agp_i810_bind_page), 61663010Sdfr DEVMETHOD(agp_unbind_page, agp_i810_unbind_page), 61763010Sdfr DEVMETHOD(agp_flush_tlb, agp_i810_flush_tlb), 61863010Sdfr DEVMETHOD(agp_enable, agp_i810_enable), 61963010Sdfr DEVMETHOD(agp_alloc_memory, agp_i810_alloc_memory), 62063010Sdfr DEVMETHOD(agp_free_memory, agp_i810_free_memory), 62163010Sdfr DEVMETHOD(agp_bind_memory, agp_i810_bind_memory), 62263010Sdfr DEVMETHOD(agp_unbind_memory, agp_i810_unbind_memory), 62363010Sdfr 62463010Sdfr { 0, 0 } 62563010Sdfr}; 62663010Sdfr 62763010Sdfrstatic driver_t agp_i810_driver = { 62863010Sdfr "agp", 62963010Sdfr agp_i810_methods, 63063010Sdfr sizeof(struct agp_i810_softc), 63163010Sdfr}; 63263010Sdfr 63363010Sdfrstatic devclass_t agp_devclass; 63463010Sdfr 63563010SdfrDRIVER_MODULE(agp_i810, pci, agp_i810_driver, agp_devclass, 0, 0); 636