Module Name: src Committed By: riastradh Date: Fri May 23 22:58:56 UTC 2014
Modified Files: src/sys/dev/pci: agp_i810.c agp_i810var.h agpreg.h Log Message: Implement Intel AGP chipset flush. While here, fix the use of the I915 PCI MSAC register: it lies on the bridge device (bus 0 dev 0 func 0), not the graphics device (bus 0 dev 2 func 0). I'm not sure we ever need to consult this register, really -- the PCI BARs should be sized. But I'll leave a rototill of this mess for another day. To generate a diff of this commit: cvs rdiff -u -r1.74 -r1.75 src/sys/dev/pci/agp_i810.c cvs rdiff -u -r1.2 -r1.3 src/sys/dev/pci/agp_i810var.h cvs rdiff -u -r1.20 -r1.21 src/sys/dev/pci/agpreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/agp_i810.c diff -u src/sys/dev/pci/agp_i810.c:1.74 src/sys/dev/pci/agp_i810.c:1.75 --- src/sys/dev/pci/agp_i810.c:1.74 Tue Mar 18 18:20:41 2014 +++ src/sys/dev/pci/agp_i810.c Fri May 23 22:58:56 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: agp_i810.c,v 1.74 2014/03/18 18:20:41 riastradh Exp $ */ +/* $NetBSD: agp_i810.c,v 1.75 2014/05/23 22:58:56 riastradh Exp $ */ /*- * Copyright (c) 2000 Doug Rabson @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v 1.74 2014/03/18 18:20:41 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v 1.75 2014/05/23 22:58:56 riastradh Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -39,6 +39,7 @@ __KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v #include <sys/proc.h> #include <sys/device.h> #include <sys/conf.h> +#include <sys/xcall.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> @@ -86,6 +87,7 @@ static int agp_i810_unbind_memory(struct static bool agp_i810_resume(device_t, const pmf_qual_t *); static int agp_i810_init(struct agp_softc *); +static int agp_i810_setup_chipset_flush_page(struct agp_softc *); static int agp_i810_init(struct agp_softc *); static struct agp_methods agp_i810_methods = { @@ -184,6 +186,40 @@ agp_i810_post_gtt_entry(struct agp_i810_ (void)READ4(base_off + wroff); } +static void +agp_flush_cache_xc(void *a __unused, void *b __unused) +{ + + agp_flush_cache(); +} + +void +agp_i810_chipset_flush(struct agp_i810_softc *isc) +{ + unsigned int timo = 20000; /* * 50 us = 1 s */ + + switch (isc->chiptype) { + case CHIP_I810: + break; + case CHIP_I830: + case CHIP_I855: + xc_wait(xc_broadcast(0, &agp_flush_cache_xc, NULL, NULL)); + WRITE4(AGP_I830_HIC, READ4(AGP_I830_HIC) | __BIT(31)); + while (ISSET(READ4(AGP_I830_HIC), __BIT(31))) { + if (timo-- == 0) + break; + DELAY(50); + } + break; + case CHIP_I915: + case CHIP_I965: + case CHIP_G33: + case CHIP_G4X: + bus_space_write_4(isc->flush_bst, isc->flush_bsh, 0, 1); + break; + } +} + /* XXXthorpej -- duplicated code (see arch/x86/pci/pchb.c) */ static int agp_i810_vgamatch(const struct pci_attach_args *pa) @@ -441,9 +477,88 @@ agp_i810_attach(device_t parent, device_ agp_i810_vga_regbase = mmadr; agp_i810_vga_bsh = isc->bsh; + /* Set up a chipset flush page if necessary. */ + switch (isc->chiptype) { + case CHIP_I915: + case CHIP_I965: + case CHIP_G33: + case CHIP_G4X: + error = agp_i810_setup_chipset_flush_page(sc); + if (error) { + aprint_error_dev(self, + "failed to set up chipset flush page: %d\n", + error); + agp_generic_detach(sc); + return error; + } + break; + } + return agp_i810_init(sc); } +static int +agp_i810_setup_chipset_flush_page(struct agp_softc *sc) +{ + struct agp_i810_softc *const isc = sc->as_chipc; + pcireg_t reg, lo, hi; + bus_addr_t addr, minaddr, maxaddr; + int error; + + /* We always use memory-mapped I/O. */ + isc->flush_bst = isc->vga_pa.pa_memt; + + /* No page allocated yet. */ + isc->flush_addr = 0; + + /* Read the PCI config register: 4-byte on gen3, 8-byte on gen>=4. */ + if (isc->chiptype == CHIP_I915) { + reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I915_IFPADDR); + addr = reg; + minaddr = PAGE_SIZE; /* XXX PCIBIOS_MIN_MEM? */ + maxaddr = UINT32_MAX; + } else { + hi = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I965_IFPADDR+4); + lo = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I965_IFPADDR); + addr = ((bus_addr_t)hi << 32) | lo; + minaddr = PAGE_SIZE; /* XXX PCIBIOS_MIN_MEM? */ + maxaddr = UINT64_MAX; + } + + /* Allocate or map a pre-allocated a page for it. */ + if (ISSET(addr, 1)) { + /* BIOS allocated it for us. Use that. */ + error = bus_space_map(isc->flush_bst, addr & ~1, PAGE_SIZE, 0, + &isc->flush_bsh); + if (error) + return error; + } else { + /* None allocated. Allocate one. */ + error = bus_space_alloc(isc->flush_bst, minaddr, maxaddr, + PAGE_SIZE, PAGE_SIZE, 0, 0, + &isc->flush_addr, &isc->flush_bsh); + if (error) + return error; + KASSERT(isc->flush_addr != 0); + /* Write it into the PCI config register. */ + addr = isc->flush_addr | 1; + if (isc->chiptype == CHIP_I915) { + pci_conf_write(sc->as_pc, sc->as_tag, AGP_I915_IFPADDR, + addr); + } else { + pci_conf_write(sc->as_pc, sc->as_tag, + AGP_I965_IFPADDR + 4, + __SHIFTOUT(addr, __BITS(63, 32))); + pci_conf_write(sc->as_pc, sc->as_tag, + AGP_I965_IFPADDR, + __SHIFTOUT(addr, __BITS(31, 0))); + } + } + + /* Success! */ + return 0; +} + /* * XXX horrible hack to allow drm code to use our mapping * of VGA chip registers @@ -713,6 +828,33 @@ agp_i810_detach(struct agp_softc *sc) if (error) return error; + switch (isc->chiptype) { + case CHIP_I915: + case CHIP_I965: + case CHIP_G33: + case CHIP_G4X: + if (isc->flush_addr) { + /* If we allocated a page, clear it. */ + if (isc->chiptype == CHIP_I915) { + pci_conf_write(sc->as_pc, sc->as_tag, + AGP_I915_IFPADDR, 0); + } else { + pci_conf_write(sc->as_pc, sc->as_tag, + AGP_I915_IFPADDR, 0); + pci_conf_write(sc->as_pc, sc->as_tag, + AGP_I915_IFPADDR + 4, 0); + } + isc->flush_addr = 0; + bus_space_free(isc->flush_bst, isc->flush_bsh, + PAGE_SIZE); + } else { + /* Otherwise, just unmap the pre-allocated page. */ + bus_space_unmap(isc->flush_bst, isc->flush_bsh, + PAGE_SIZE); + } + break; + } + /* Clear the GATT base. */ if (sc->chiptype == CHIP_I810) { WRITE4(AGP_I810_PGTBL_CTL, 0); @@ -770,7 +912,8 @@ agp_i810_get_aperture(struct agp_softc * case CHIP_I915: case CHIP_G33: case CHIP_G4X: - reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I915_MSAC); + reg = pci_conf_read(isc->vga_pa.pa_pc, isc->vga_pa.pa_tag, + AGP_I915_MSAC); msac = (u_int16_t)(reg >> 16); if (msac & AGP_I915_MSAC_APER_128M) size = 128 * 1024 * 1024; Index: src/sys/dev/pci/agp_i810var.h diff -u src/sys/dev/pci/agp_i810var.h:1.2 src/sys/dev/pci/agp_i810var.h:1.3 --- src/sys/dev/pci/agp_i810var.h:1.2 Tue Mar 18 18:20:41 2014 +++ src/sys/dev/pci/agp_i810var.h Fri May 23 22:58:56 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: agp_i810var.h,v 1.2 2014/03/18 18:20:41 riastradh Exp $ */ +/* $NetBSD: agp_i810var.h,v 1.3 2014/05/23 22:58:56 riastradh Exp $ */ /*- * Copyright (c) 2000 Doug Rabson @@ -48,9 +48,14 @@ struct agp_i810_softc { struct pci_attach_args vga_pa; u_int32_t pgtblctl; + + bus_space_tag_t flush_bst; /* flush page bus_space tag */ + bus_space_handle_t flush_bsh; /* flush page bus_space handle */ + bus_addr_t flush_addr; /* flush page bus address */ }; extern struct agp_softc *agp_i810_sc; int agp_i810_write_gtt_entry(struct agp_i810_softc *, off_t, bus_addr_t); void agp_i810_post_gtt_entry(struct agp_i810_softc *, off_t); +void agp_i810_chipset_flush(struct agp_i810_softc *); Index: src/sys/dev/pci/agpreg.h diff -u src/sys/dev/pci/agpreg.h:1.20 src/sys/dev/pci/agpreg.h:1.21 --- src/sys/dev/pci/agpreg.h:1.20 Sat Nov 29 23:48:12 2008 +++ src/sys/dev/pci/agpreg.h Fri May 23 22:58:56 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: agpreg.h,v 1.20 2008/11/29 23:48:12 christos Exp $ */ +/* $NetBSD: agpreg.h,v 1.21 2014/05/23 22:58:56 riastradh Exp $ */ /*- * Copyright (c) 2000 Doug Rabson @@ -206,6 +206,10 @@ #define AGP_I830_GCC1_GMASIZE_64 0x01 #define AGP_I830_GCC1_GMASIZE_128 0x00 +/* + * Memory mapped register offsets for i830 chipset. + */ +#define AGP_I830_HIC 0x70 /* * Config registers for 852GM/855GM/865G device 0 @@ -228,6 +232,12 @@ #define AGP_I915_MMADR 0x10 #define AGP_I915_GMADR 0x18 #define AGP_I915_GTTADR 0x1c +#define AGP_I915_MSAC 0x60 /* upper word */ +#define AGP_I915_MSAC_APER_128M 0x02 + +/* + * Config registers for 915G/915GM device 0 + */ #define AGP_I915_GCC1 0x52 #define AGP_I915_GCC1_GMS 0x70 #define AGP_I915_GCC1_GMS_STOLEN_0M 0x00 @@ -237,8 +247,7 @@ #define AGP_I915_GCC1_GMS_STOLEN_32M 0x50 #define AGP_I915_GCC1_GMS_STOLEN_48M 0x60 #define AGP_I915_GCC1_GMS_STOLEN_64M 0x70 -#define AGP_I915_MSAC 0x60 /* upper word */ -#define AGP_I915_MSAC_APER_128M 0x02 +#define AGP_I915_IFPADDR 0x60 /* * Config registers for 965G/965Q @@ -252,6 +261,10 @@ #define AGP_I965_PGTBL_SIZE_2MB (4 << 1) #define AGP_I965_PGTBL_SIZE_1_5MB (5 << 1) +/* + * Config registers for 965G/965Q device 0 + */ +#define AGP_I965_IFPADDR 0x70 /* * Config registers for G33