diff options
author | Owain Ainsworth <oga@cvs.openbsd.org> | 2009-04-15 23:53:23 +0000 |
---|---|---|
committer | Owain Ainsworth <oga@cvs.openbsd.org> | 2009-04-15 23:53:23 +0000 |
commit | 1ff74c3375d0fd7c55eb9b12c57d1b83d0ce49f1 (patch) | |
tree | ecbfd609e2b9e9f9e010e0a4b62df3e70b29fd48 /sys/arch | |
parent | ef46b454c3ab32d6b7bd5171d51c6e1d3ae5a8b3 (diff) |
The current iommu code only touches the hardware if the bios did not
enable it (I have found the code that does enable it problematic on
quite a few machines, however, that's a different issue). So provide
some code that so if the bios initialised the iommu for us, we'll use
what it gave us. Makes iommu work on a machine of todd's.
while i'm here, we don't need to scan all pci functoins to find the
hypertransport bridge. the gart is always on function 3, so just scan
for all the bridges and not iterate over the functions too.
Thanks to todd for his infinite patience while I gave him diffs that
went ``Boom!''.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/amd64/pci/iommu.c | 194 |
1 files changed, 124 insertions, 70 deletions
diff --git a/sys/arch/amd64/pci/iommu.c b/sys/arch/amd64/pci/iommu.c index 1b00fc90b41..18c11bbf21d 100644 --- a/sys/arch/amd64/pci/iommu.c +++ b/sys/arch/amd64/pci/iommu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iommu.c,v 1.26 2009/03/11 23:38:51 oga Exp $ */ +/* $OpenBSD: iommu.c,v 1.27 2009/04/15 23:53:22 oga Exp $ */ /* * Copyright (c) 2005 Jason L. Wright (jason@thought.net) @@ -127,6 +127,7 @@ int amdgart_iommu_map(struct amdgart_softc *, bus_dmamap_t, int amdgart_iommu_unmap(struct amdgart_softc *, bus_dma_segment_t *); int amdgart_reload(struct amdgart_softc *, bus_dmamap_t); int amdgart_ok(pci_chipset_tag_t, pcitag_t); +int amdgart_enabled(pci_chipset_tag_t, pcitag_t); void amdgart_initpt(struct amdgart_softc *, u_long); int amdgart_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t, @@ -227,28 +228,42 @@ amdgart_ok(pci_chipset_tag_t pc, pcitag_t tag) pcireg_t v; v = pci_conf_read(pc, tag, PCI_ID_REG); - if (PCI_VENDOR(v) != PCI_VENDOR_AMD) - return (0); - if (PCI_PRODUCT(v) != PCI_PRODUCT_AMD_AMD64_0F_MISC && - PCI_PRODUCT(v) != PCI_PRODUCT_AMD_AMD64_10_MISC) - return (0); - - v = pci_conf_read(pc, tag, GART_APCTRL); - if (v & GART_APCTRL_ENABLE) - return (0); + if (PCI_VENDOR(v) == PCI_VENDOR_AMD && + (PCI_PRODUCT(v) == PCI_PRODUCT_AMD_AMD64_0F_MISC || + PCI_PRODUCT(v) == PCI_PRODUCT_AMD_AMD64_10_MISC)) + return (1); + return (0); +} - return (1); +int +amdgart_enabled(pci_chipset_tag_t pc, pcitag_t tag) +{ + return (pci_conf_read(pc, tag, GART_APCTRL) & GART_APCTRL_ENABLE); } +static const struct gart_size { + pcireg_t reg; + bus_size_t size; +} apsizes[] = { + { GART_APCTRL_SIZE_32M, 32 }, + { GART_APCTRL_SIZE_64M, 64 }, + { GART_APCTRL_SIZE_128M, 128 }, + { GART_APCTRL_SIZE_256M, 256 }, + { GART_APCTRL_SIZE_512M, 512 }, + { GART_APCTRL_SIZE_1G, 1024 }, + { GART_APCTRL_SIZE_2G, 2048 }, +}; + void amdgart_probe(struct pcibus_attach_args *pba) { struct amdgart_softc *sc; - int dev, func, count = 0, r, nseg; - u_long mapsize, ptesize; + int dev, count = 0, encount = 0, r, nseg; + u_long mapsize, ptesize, gartsize = 0; bus_dma_segment_t seg; pcitag_t tag; pcireg_t v; + paddr_t pa; void *scrib = NULL; u_int32_t *pte = NULL; paddr_t ptepa; @@ -256,18 +271,30 @@ amdgart_probe(struct pcibus_attach_args *pba) if (amdgart_enable == 0) return; + /* Function is always three */ for (count = 0, dev = 24; dev < 32; dev++) { - for (func = 0; func < 8; func++) { - tag = pci_make_tag(pba->pba_pc, 0, dev, func); - - if (amdgart_ok(pba->pba_pc, tag)) - count++; + tag = pci_make_tag(pba->pba_pc, 0, dev, 3); + + if (!amdgart_ok(pba->pba_pc, tag)) + continue; + count++; + if (amdgart_enabled(pba->pba_pc, tag)) { + encount++; + pa = pci_conf_read(pba->pba_pc, tag, + GART_APBASE) << 25; + v = pci_conf_read(pba->pba_pc, tag, + GART_APCTRL) & GART_APCTRL_SIZE; } } if (count == 0) return; + if (encount > 0 && encount != count) { + printf("\niommu: holy mismatched enabling, batman!\n"); + return; + } + sc = malloc(sizeof(*sc) + (sizeof(pcitag_t) * (count - 1)), M_DEVBUF, M_NOWAIT | M_ZERO); if (sc == NULL) { @@ -275,9 +302,37 @@ amdgart_probe(struct pcibus_attach_args *pba) return; } - sc->g_pa = IOMMU_START; + if (encount > 0) { + int i; + /* + * GART exists, use the current value. + * + * It appears that the bios mentions this in it's memory map + * (sample size of 1), so we don't need to allocate + * address space for it. + */ + sc->g_pa = pa; + for (i = 0; i < nitems(apsizes); i++) + if (apsizes[i].reg == v) + gartsize = apsizes[i].size; + if (gartsize == 0) { + printf("iommu: strange size\n"); + free(sc, M_DEVBUF); + return; + } - mapsize = IOMMU_SIZE * 1024 * 1024; + mapsize = gartsize * 1024 * 1024; + } else { + /* We've gotta allocate one. Heuristic time! */ + /* + * XXX right now we stuff the iommu where we want. this need + * XXX changing to allocate from pci space. + */ + sc->g_pa = IOMMU_START; + gartsize = IOMMU_SIZE; + } + + mapsize = gartsize * 1024 * 1024; ptesize = mapsize / (PAGE_SIZE / sizeof(u_int32_t)); /* @@ -323,61 +378,60 @@ amdgart_probe(struct pcibus_attach_args *pba) sc->g_dmat = pba->pba_dmat; for (count = 0, dev = 24; dev < 32; dev++) { - for (func = 0; func < 8; func++) { - tag = pci_make_tag(pba->pba_pc, 0, dev, func); - - if (!amdgart_ok(pba->pba_pc, tag)) - continue; - - v = pci_conf_read(pba->pba_pc, tag, GART_APCTRL); - v |= GART_APCTRL_DISCPU | GART_APCTRL_DISTBL | - GART_APCTRL_DISIO; - v &= ~(GART_APCTRL_ENABLE | GART_APCTRL_SIZE); - switch (IOMMU_SIZE) { - case 32: - v |= GART_APCTRL_SIZE_32M; - break; - case 64: - v |= GART_APCTRL_SIZE_64M; - break; - case 128: - v |= GART_APCTRL_SIZE_128M; - break; - case 256: - v |= GART_APCTRL_SIZE_256M; - break; - case 512: - v |= GART_APCTRL_SIZE_512M; - break; - case 1024: - v |= GART_APCTRL_SIZE_1G; - break; - case 2048: - v |= GART_APCTRL_SIZE_2G; - break; - default: - printf("\nGART: bad size"); - return; - } - pci_conf_write(pba->pba_pc, tag, GART_APCTRL, v); + tag = pci_make_tag(pba->pba_pc, 0, dev, 3); + + if (!amdgart_ok(pba->pba_pc, tag)) + continue; + + v = pci_conf_read(pba->pba_pc, tag, GART_APCTRL); + v |= GART_APCTRL_DISCPU | GART_APCTRL_DISTBL | + GART_APCTRL_DISIO; + v &= ~(GART_APCTRL_ENABLE | GART_APCTRL_SIZE); + switch (gartsize) { + case 32: + v |= GART_APCTRL_SIZE_32M; + break; + case 64: + v |= GART_APCTRL_SIZE_64M; + break; + case 128: + v |= GART_APCTRL_SIZE_128M; + break; + case 256: + v |= GART_APCTRL_SIZE_256M; + break; + case 512: + v |= GART_APCTRL_SIZE_512M; + break; + case 1024: + v |= GART_APCTRL_SIZE_1G; + break; + case 2048: + v |= GART_APCTRL_SIZE_2G; + break; + default: + printf("\nGART: bad size"); + return; + } + pci_conf_write(pba->pba_pc, tag, GART_APCTRL, v); - pci_conf_write(pba->pba_pc, tag, GART_APBASE, - sc->g_pa >> 25); + pci_conf_write(pba->pba_pc, tag, GART_APBASE, + sc->g_pa >> 25); - pci_conf_write(pba->pba_pc, tag, GART_TBLBASE, - (ptepa >> 8) & GART_TBLBASE_MASK); + pci_conf_write(pba->pba_pc, tag, GART_TBLBASE, + (ptepa >> 8) & GART_TBLBASE_MASK); - v = pci_conf_read(pba->pba_pc, tag, GART_APCTRL); - v |= GART_APCTRL_ENABLE; - v &= ~GART_APCTRL_DISIO; - pci_conf_write(pba->pba_pc, tag, GART_APCTRL, v); + v = pci_conf_read(pba->pba_pc, tag, GART_APCTRL); + v |= GART_APCTRL_ENABLE; + v &= ~GART_APCTRL_DISIO; + pci_conf_write(pba->pba_pc, tag, GART_APCTRL, v); - sc->g_tags[count] = tag; + sc->g_tags[count] = tag; - printf("\niommu%d at cpu%d: base 0x%lx length %dMB pte 0x%lx", - count, dev - 24, sc->g_pa, IOMMU_SIZE, ptepa); - count++; - } + printf("\niommu%d at cpu%d: base 0x%lx length %dMB" + " pte 0x%lx", count, dev - 24, sc->g_pa, + gartsize, ptepa); + count++; } amdgart_initpt(sc, ptesize / sizeof(*sc->g_pte)); sc->g_count = count; |