Index: sys/pci/agp_i810.c =================================================================== RCS file: /home/ncvs/src/sys/pci/agp_i810.c,v retrieving revision 1.39 diff -u -u -r1.39 agp_i810.c --- sys/pci/agp_i810.c 27 Sep 2006 06:38:54 -0000 1.39 +++ sys/pci/agp_i810.c 4 Apr 2007 23:16:34 -0000 @@ -67,10 +67,13 @@ #define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v) #define WRITEGTT(off,v) bus_space_write_4(sc->gtt_bst, sc->gtt_bsh, off, v) -#define CHIP_I810 0 /* i810/i815 */ -#define CHIP_I830 1 /* 830M/845G */ -#define CHIP_I855 2 /* 852GM/855GM/865G */ -#define CHIP_I915 3 /* 915G/915GM */ +enum { + CHIP_I810, /* i810/i815 */ + CHIP_I830, /* 830M/845G */ + CHIP_I855, /* 852GM/855GM/865G */ + CHIP_I915, /* 915G/915GM */ + CHIP_I965 /* G965 */ +}; struct agp_i810_softc { struct agp_softc agp; @@ -92,6 +95,11 @@ struct resource *gm; /* unmapped (but allocated) aperture */ void *argb_cursor; /* contigmalloc area for ARGB cursor */ + + /* list of allocated resources */ + struct resource_spec resource_specs[4]; + struct resource *resources[4]; + int resource_count; }; /* For adding new devices, devid is the id of the graphics controller @@ -127,6 +135,14 @@ "Intel 82945G (945G GMCH) SVGA controller"}, {0x27A28086, CHIP_I915, 0x00020000, "Intel 82945GM (945GM GMCH) SVGA controller"}, + {0x29728086, CHIP_I965, 0x00020000, + "Intel 946GZ SVGA controller"}, + {0x29828086, CHIP_I965, 0x00020000, + "Intel 965G SVGA controller"}, + {0x29928086, CHIP_I965, 0x00020000, + "Intel 965Q SVGA controller"}, + {0x29A28086, CHIP_I965, 0x00020000, + "Intel 965G SVGA controller"}, {0, 0, 0, NULL} }; @@ -194,6 +210,8 @@ { device_t bdev; const struct agp_i810_match *match; + u_int8_t smram; + int gcc1, deven; if (resource_disabled("agp", device_get_unit(dev))) return (ENXIO); @@ -211,20 +229,18 @@ /* * checking whether internal graphics device has been activated. */ - if (match->chiptype == CHIP_I810) { - u_int8_t smram; - + switch (match->chiptype) { + case CHIP_I810: smram = pci_read_config(bdev, AGP_I810_SMRAM, 1); - if ((smram & AGP_I810_SMRAM_GMS) - == AGP_I810_SMRAM_GMS_DISABLED) { + if ((smram & AGP_I810_SMRAM_GMS) == + AGP_I810_SMRAM_GMS_DISABLED) { if (bootverbose) printf("I810: disabled, not probing\n"); return ENXIO; } - } else if (match->chiptype == CHIP_I830 || - match->chiptype == CHIP_I855) { - unsigned int gcc1; - + break; + case CHIP_I830: + case CHIP_I855: gcc1 = pci_read_config(bdev, AGP_I830_GCC1, 1); if ((gcc1 & AGP_I830_GCC1_DEV2) == AGP_I830_GCC1_DEV2_DISABLED) { @@ -232,16 +248,17 @@ printf("I830: disabled, not probing\n"); return ENXIO; } - } else if (match->chiptype == CHIP_I915) { - unsigned int gcc1; - - gcc1 = pci_read_config(bdev, AGP_I915_DEVEN, 4); - if ((gcc1 & AGP_I915_DEVEN_D2F0) == + break; + case CHIP_I915: + case CHIP_I965: + deven = pci_read_config(bdev, AGP_I915_DEVEN, 4); + if ((deven & AGP_I915_DEVEN_D2F0) == AGP_I915_DEVEN_D2F0_DISABLED) { if (bootverbose) printf("I915: disabled, not probing\n"); return ENXIO; } + break; } if (match->devid == 0x35828086) { @@ -274,13 +291,75 @@ return BUS_PROBE_DEFAULT; } +static void +agp_i810_dump_regs(device_t dev) +{ + struct agp_i810_softc *sc = device_get_softc(dev); + + device_printf(dev, "AGP_I810_PGTBL_CTL: %08x\n", + READ4(AGP_I810_PGTBL_CTL)); + + switch (sc->chiptype) { + case CHIP_I810: + device_printf(dev, "AGP_I810_MISCC: 0x%04x\n", + pci_read_config(sc->bdev, AGP_I810_MISCC, 2)); + break; + case CHIP_I830: + device_printf(dev, "AGP_I830_GCC1: 0x%02x\n", + pci_read_config(sc->bdev, AGP_I830_GCC1, 1)); + break; + case CHIP_I855: + device_printf(dev, "AGP_I855_GCC1: 0x%02x\n", + pci_read_config(sc->bdev, AGP_I855_GCC1, 1)); + break; + case CHIP_I915: + case CHIP_I965: + device_printf(dev, "AGP_I855_GCC1: 0x%02x\n", + pci_read_config(sc->bdev, AGP_I855_GCC1, 1)); + device_printf(dev, "AGP_I915_MSAC: 0x%02x\n", + pci_read_config(sc->bdev, AGP_I915_MSAC, 1)); + device_printf(dev, "Aperture resource size: %d bytes\n", + (int)rman_get_size(sc->gm)); + break; + } +} + +/** + * Allocates a PCI resource like bus_alloc_resource, but tracks the allocation + * for cleanup. + */ +static struct resource * +agp_i810_alloc_resource(device_t dev, int type, int rid, u_long start, + u_long end, int flags) +{ + struct agp_i810_softc *sc = device_get_softc(dev); + struct resource *res; + + res = bus_alloc_resource(dev, type, &rid, start, end, + end - start, flags); + if (res == NULL) + return NULL; + + sc->resource_specs[sc->resource_count].type = type; + sc->resource_specs[sc->resource_count].rid = rid; + sc->resources[sc->resource_count] = res; + sc->resource_count++; + + /* Terminate the list */ + sc->resources[sc->resource_count] = NULL; + sc->resource_specs[sc->resource_count].type = -1; + + return res; +} + + static int agp_i810_attach(device_t dev) { struct agp_i810_softc *sc = device_get_softc(dev); struct agp_gatt *gatt; const struct agp_i810_match *match; - int error, rid; + int error; sc->bdev = agp_i810_find_bridge(dev); if (!sc->bdev) @@ -293,48 +372,70 @@ match = agp_i810_match(dev); sc->chiptype = match->chiptype; - /* Same for i810 and i830 */ - if (sc->chiptype == CHIP_I915) - rid = AGP_I915_MMADR; - else - rid = AGP_I810_MMADR; - - sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, - RF_ACTIVE); - if (!sc->regs) { - agp_generic_detach(dev); - return ENODEV; - } - sc->bst = rman_get_bustag(sc->regs); - sc->bsh = rman_get_bushandle(sc->regs); - - if (sc->chiptype == CHIP_I915) { - rid = AGP_I915_GTTADR; - sc->gtt = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, - RF_ACTIVE); - if (!sc->gtt) { - bus_release_resource(dev, SYS_RES_MEMORY, - AGP_I915_MMADR, sc->regs); + /* The i810 through i855 have the registers at BAR 1, and the GATT + * gets allocated by us. The i915 has registers in BAR 0 and + * the GATT is at the start of the aperture, and should only be + * accessed by the OS through BAR 3. The G965 has registers and GATT + * in the same BAR (0) -- first 512kb is regisers, second 512kb is + * GATT. + */ + switch (sc->chiptype) { + case CHIP_I810: + case CHIP_I830: + case CHIP_I855: + sc->regs = agp_i810_alloc_resource(dev, SYS_RES_MEMORY, + AGP_I810_MMADR, 0, ~0, RF_ACTIVE | RF_SHAREABLE); + if (sc->regs == NULL) { + bus_release_resources(dev, sc->resource_specs, + sc->resources); + agp_generic_detach(dev); + return ENODEV; + } + break; + case CHIP_I915: + sc->regs = agp_i810_alloc_resource(dev, SYS_RES_MEMORY, + AGP_I915_MMADR, 0, ~0, RF_ACTIVE | RF_SHAREABLE); + sc->gtt = agp_i810_alloc_resource(dev, SYS_RES_MEMORY, + AGP_I915_GTTADR, 0, ~0, RF_ACTIVE); + if (sc->regs == NULL || sc->gtt == NULL) { + bus_release_resources(dev, sc->resource_specs, + sc->resources); agp_generic_detach(dev); return ENODEV; } sc->gtt_bst = rman_get_bustag(sc->gtt); sc->gtt_bsh = rman_get_bushandle(sc->gtt); + break; + case CHIP_I965: + sc->regs = agp_i810_alloc_resource(dev, SYS_RES_MEMORY, + AGP_I965_GTTMMADR, 0, 1024 * 1024, + RF_ACTIVE | RF_SHAREABLE); + if (sc->regs == NULL) { + bus_release_resources(dev, sc->resource_specs, + sc->resources); + agp_generic_detach(dev); + return ENODEV; + } + break; + } + + sc->bst = rman_get_bustag(sc->regs); + sc->bsh = rman_get_bushandle(sc->regs); + + if (sc->chiptype == CHIP_I915 || sc->chiptype == CHIP_I965) { /* While agp_generic_attach allocates the AGP_APBASE resource * to try to reserve the aperture, on the 915 the aperture * isn't in PCIR_BAR(0), it's in PCIR_BAR(2), so it allocated * the registers that we just mapped anyway. So, allocate the - * aperture here, which also gives us easy access to it for the + * aperture here, which also gives us easy access to it for * agp_i810_get_aperture(). */ - rid = AGP_I915_GMADR; - sc->gm = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0); + sc->gm = agp_i810_alloc_resource(dev, SYS_RES_MEMORY, + AGP_I915_GMADR, 0, ~0, 0); if (sc->gm == NULL) { - bus_release_resource(dev, SYS_RES_MEMORY, - AGP_I915_MMADR, sc->regs); - bus_release_resource(dev, SYS_RES_MEMORY, - AGP_I915_GTTADR, sc->regs); + bus_release_resources(dev, sc->resource_specs, + sc->resources); agp_generic_detach(dev); return ENODEV; } @@ -344,6 +445,8 @@ gatt = malloc( sizeof(struct agp_gatt), M_AGP, M_NOWAIT); if (!gatt) { + bus_release_resources(dev, sc->resource_specs, + sc->resources); agp_generic_detach(dev); return ENOMEM; } @@ -364,6 +467,8 @@ if (!gatt->ag_virtual) { if (bootverbose) device_printf(dev, "contiguous allocation failed\n"); + bus_release_resources(dev, sc->resource_specs, + sc->resources); free(gatt, M_AGP); agp_generic_detach(dev); return ENOMEM; @@ -392,6 +497,9 @@ default: sc->stolen = 0; device_printf(dev, "unknown memory configuration, disabling\n"); + bus_release_resources(dev, sc->resource_specs, + sc->resources); + free(gatt, M_AGP); agp_generic_detach(dev); return EINVAL; } @@ -405,47 +513,85 @@ WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); gatt->ag_physical = pgtblctl & ~1; - } else if (sc->chiptype == CHIP_I855 || sc->chiptype == CHIP_I915) { /* CHIP_I855 */ - unsigned int gcc1, pgtblctl, stolen; + } else if (sc->chiptype == CHIP_I855 || sc->chiptype == CHIP_I915 || + sc->chiptype == CHIP_I965) { + unsigned int gcc1, pgtblctl, stolen, gtt_size; /* Stolen memory is set up at the beginning of the aperture by * the BIOS, consisting of the GATT followed by 4kb for the BIOS * display. */ - if (sc->chiptype == CHIP_I855) - stolen = 132; - else - stolen = 260; - - gcc1 = pci_read_config(sc->bdev, AGP_I855_GCC1, 1); - switch (gcc1 & AGP_I855_GCC1_GMS) { - case AGP_I855_GCC1_GMS_STOLEN_1M: - sc->stolen = (1024 - stolen) * 1024 / 4096; - break; - case AGP_I855_GCC1_GMS_STOLEN_4M: - sc->stolen = (4096 - stolen) * 1024 / 4096; - break; - case AGP_I855_GCC1_GMS_STOLEN_8M: - sc->stolen = (8192 - stolen) * 1024 / 4096; - break; - case AGP_I855_GCC1_GMS_STOLEN_16M: - sc->stolen = (16384 - stolen) * 1024 / 4096; - break; - case AGP_I855_GCC1_GMS_STOLEN_32M: - sc->stolen = (32768 - stolen) * 1024 / 4096; + switch (sc->chiptype) { + case CHIP_I855: + gtt_size = 128; + break; + case CHIP_I915: + gtt_size = 256; + break; + case CHIP_I965: + switch (READ4(AGP_I810_PGTBL_CTL) & + AGP_I810_PGTBL_SIZE_MASK) { + case AGP_I810_PGTBL_SIZE_128KB: + gtt_size = 128; break; - case AGP_I915_GCC1_GMS_STOLEN_48M: - sc->stolen = (49152 - stolen) * 1024 / 4096; + case AGP_I810_PGTBL_SIZE_256KB: + gtt_size = 256; break; - case AGP_I915_GCC1_GMS_STOLEN_64M: - sc->stolen = (65536 - stolen) * 1024 / 4096; + case AGP_I810_PGTBL_SIZE_512KB: + gtt_size = 512; break; default: - sc->stolen = 0; - device_printf(dev, "unknown memory configuration, disabling\n"); + device_printf(dev, "Bad chiptype\n"); + bus_release_resources(dev, sc->resource_specs, + sc->resources); + free(gatt, M_AGP); agp_generic_detach(dev); return EINVAL; + } + break; + default: + device_printf(dev, "Bad chiptype\n"); + bus_release_resources(dev, sc->resource_specs, + sc->resources); + free(gatt, M_AGP); + agp_generic_detach(dev); + return EINVAL; + } + + /* GCC1 is called MGGC on i915+ */ + gcc1 = pci_read_config(sc->bdev, AGP_I855_GCC1, 1); + switch (gcc1 & AGP_I855_GCC1_GMS) { + case AGP_I855_GCC1_GMS_STOLEN_1M: + stolen = 1024; + break; + case AGP_I855_GCC1_GMS_STOLEN_4M: + stolen = 4096; + break; + case AGP_I855_GCC1_GMS_STOLEN_8M: + stolen = 8192; + break; + case AGP_I855_GCC1_GMS_STOLEN_16M: + stolen = 16384; + break; + case AGP_I855_GCC1_GMS_STOLEN_32M: + stolen = 32768; + break; + case AGP_I915_GCC1_GMS_STOLEN_48M: + stolen = 49152; + break; + case AGP_I915_GCC1_GMS_STOLEN_64M: + stolen = 65536; + break; + default: + device_printf(dev, "unknown memory configuration, " + "disabling\n"); + bus_release_resources(dev, sc->resource_specs, + sc->resources); + free(gatt, M_AGP); + agp_generic_detach(dev); + return EINVAL; } + sc->stolen = (stolen - gtt_size - 4) * 1024 / 4096; if (sc->stolen > 0) device_printf(dev, "detected %dk stolen memory\n", sc->stolen * 4); device_printf(dev, "aperture size is %dM\n", sc->initial_aperture / 1024 / 1024); @@ -458,6 +604,8 @@ gatt->ag_physical = pgtblctl & ~1; } + agp_i810_dump_regs(dev); + return 0; } @@ -489,17 +637,7 @@ } free(sc->gatt, M_AGP); - if (sc->chiptype == CHIP_I915) { - bus_release_resource(dev, SYS_RES_MEMORY, AGP_I915_GMADR, - sc->gm); - bus_release_resource(dev, SYS_RES_MEMORY, AGP_I915_GTTADR, - sc->gtt); - bus_release_resource(dev, SYS_RES_MEMORY, AGP_I915_MMADR, - sc->regs); - } else { - bus_release_resource(dev, SYS_RES_MEMORY, AGP_I810_MMADR, - sc->regs); - } + bus_release_resources(dev, sc->resource_specs, sc->resources); return 0; } @@ -527,12 +665,15 @@ case CHIP_I855: return 128 * 1024 * 1024; case CHIP_I915: + case CHIP_I965: /* The documentation states that AGP_I915_MSAC should have bit * 1 set if the aperture is 128MB instead of 256. However, * that bit appears to not get set, so we instead use the * aperture resource size, which should always be correct. */ return rman_get_size(sc->gm); + default: + device_printf(dev, "Unknown chipset\n"); } return 0; @@ -543,7 +684,6 @@ { struct agp_i810_softc *sc = device_get_softc(dev); u_int16_t miscc, gcc1; - u_int32_t temp; switch (sc->chiptype) { case CHIP_I810: @@ -580,34 +720,52 @@ pci_write_config(sc->bdev, AGP_I830_GCC1, gcc1, 2); break; case CHIP_I855: - if (aperture != 128 * 1024 * 1024) { - device_printf(dev, "bad aperture size %d\n", aperture); - return EINVAL; - } - break; case CHIP_I915: - temp = pci_read_config(dev, AGP_I915_MSAC, 1); - temp &= ~AGP_I915_MSAC_GMASIZE; - - switch (aperture) { - case 128 * 1024 * 1024: - temp |= AGP_I915_MSAC_GMASIZE_128; - break; - case 256 * 1024 * 1024: - temp |= AGP_I915_MSAC_GMASIZE_256; - break; - default: + case CHIP_I965: + if (aperture != agp_i810_get_aperture(dev)) { device_printf(dev, "bad aperture size %d\n", aperture); return EINVAL; } - - pci_write_config(dev, AGP_I915_MSAC, temp, 1); - break; } return 0; } +/** + * Writes a GTT entry mapping the page at the given offset from the beginning + * of the aperture to the given physical address. + */ +static void +agp_i810_write_gtt_entry(device_t dev, int offset, vm_offset_t physical, + int enabled) +{ + struct agp_i810_softc *sc = device_get_softc(dev); + u_int32_t pte; + + pte = (u_int32_t)physical | 1; + if (sc->chiptype == CHIP_I965) { + pte |= (physical & 0x0000000f00000000ull) >> 28; + } else { + /* If we do actually have memory above 4GB on an older system, + * crash cleanly rather than scribbling on system memory, + * so we know we need to fix it. + */ + KASSERT((pte & 0x0000000f00000000ull) == 0, + (">4GB physical address in agp")); + } + + if (sc->chiptype == CHIP_I965) { + /* Our GTT entires are the last 512KB of the 1024KB register + * space. + */ + WRITE4((offset >> AGP_PAGE_SHIFT) * 4 + (512 * 1024), pte); + } else if (sc->chiptype == CHIP_I915) { + WRITEGTT((offset >> AGP_PAGE_SHIFT) * 4, pte); + } else { + WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, pte); + } +} + static int agp_i810_bind_page(device_t dev, int offset, vm_offset_t physical) { @@ -625,11 +783,7 @@ } } - if (sc->chiptype == CHIP_I915) { - WRITEGTT((offset >> AGP_PAGE_SHIFT) * 4, physical | 1); - } else { - WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, physical | 1); - } + agp_i810_write_gtt_entry(dev, offset, physical, 1); return 0; } @@ -649,12 +803,8 @@ } } - if (sc->chiptype == CHIP_I915) { - WRITEGTT((offset >> AGP_PAGE_SHIFT) * 4, 0); - } else { - WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, 0); - } - + agp_i810_write_gtt_entry(dev, offset, 0, 0); + return 0; } @@ -812,16 +962,8 @@ } /* The memory's already wired down, just stick it in the GTT. */ for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) { - u_int32_t physical = mem->am_physical + i; - - if (sc->chiptype == CHIP_I915) { - WRITEGTT(((offset + i) >> AGP_PAGE_SHIFT) * 4, - physical | 1); - } else { - WRITE4(AGP_I810_GTT + - ((offset + i) >> AGP_PAGE_SHIFT) * 4, - physical | 1); - } + agp_i810_write_gtt_entry(dev, offset + i, + mem->am_physical + i, 1); } agp_flush_cache(); mem->am_offset = offset; @@ -858,15 +1000,8 @@ } for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) { - vm_offset_t offset = mem->am_offset; - - if (sc->chiptype == CHIP_I915) { - WRITEGTT(((offset + i) >> AGP_PAGE_SHIFT) * 4, - 0); - } else { - WRITE4(AGP_I810_GTT + - ((offset + i) >> AGP_PAGE_SHIFT) * 4, 0); - } + agp_i810_write_gtt_entry(dev, mem->am_offset + i, + 0, 0); } agp_flush_cache(); mem->am_is_bound = 0; Index: sys/pci/agpreg.h =================================================================== RCS file: /home/ncvs/src/sys/pci/agpreg.h,v retrieving revision 1.18 diff -u -u -r1.18 agpreg.h --- sys/pci/agpreg.h 5 Jan 2007 22:55:19 -0000 1.18 +++ sys/pci/agpreg.h 3 Apr 2007 18:12:46 -0000 @@ -180,11 +180,16 @@ * Memory mapped register offsets for i810 chipset. */ #define AGP_I810_PGTBL_CTL 0x2020 +/** This field determines the actual size of the global GTT on the 965 */ +#define AGP_I810_PGTBL_SIZE_MASK 0x0000000e +#define AGP_I810_PGTBL_SIZE_512KB (0 << 1) +#define AGP_I810_PGTBL_SIZE_256KB (1 << 1) +#define AGP_I810_PGTBL_SIZE_128KB (2 << 1) #define AGP_I810_DRT 0x3000 #define AGP_I810_DRT_UNPOPULATED 0x00 #define AGP_I810_DRT_POPULATED 0x01 #define AGP_I810_GTT 0x10000 - + /* * Config registers for i830MG device 0 */ @@ -244,6 +249,15 @@ #define AGP_I915_MSAC_GMASIZE_256 0x00 /* + * G965 registers + */ +#define AGP_I965_GTTMMADR 0x10 +#define AGP_I965_MSAC 0x62 +#define AGP_I965_MSAC_GMASIZE_128 0x00 +#define AGP_I965_MSAC_GMASIZE_256 0x02 +#define AGP_I965_MSAC_GMASIZE_512 0x06 + +/* * NVIDIA nForce/nForce2 registers */ #define AGP_NVIDIA_0_APBASE 0x10