diff options
author | John Baldwin <jhb@FreeBSD.org> | 2009-03-05 15:33:04 +0000 |
---|---|---|
committer | John Baldwin <jhb@FreeBSD.org> | 2009-03-05 15:33:04 +0000 |
commit | c4e8c9df9eeab46fa7e885cfda40feeb48af0314 (patch) | |
tree | 715599f2e35ace9045187a26f03520e98da860cc /sys/dev/pci | |
parent | d004885d3a458502c42e379ec19b024e5efcbb08 (diff) | |
download | src-c4e8c9df9eeab46fa7e885cfda40feeb48af0314.tar.gz src-c4e8c9df9eeab46fa7e885cfda40feeb48af0314.zip |
Always read/write the full 64-bit value of 64-bit BARs. Specifically,
when determining the size of a BAR by writing all 1's to the BAR and
reading back the result, always operate on the full 64-bit size.
Reviewed by: imp
MFC after: 1 month
Notes
Notes:
svn path=/head/; revision=189401
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/pci.c | 55 | ||||
-rw-r--r-- | sys/dev/pci/pcireg.h | 2 |
2 files changed, 34 insertions, 23 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 2eaff39c95bf..db2561557984 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -71,10 +71,10 @@ __FBSDID("$FreeBSD$"); #define ACPI_PWR_FOR_SLEEP(x, y, z) #endif -static uint32_t pci_mapbase(unsigned mapreg); -static const char *pci_maptype(unsigned mapreg); -static int pci_mapsize(unsigned testval); -static int pci_maprange(unsigned mapreg); +static pci_addr_t pci_mapbase(uint64_t mapreg); +static const char *pci_maptype(uint64_t mapreg); +static int pci_mapsize(uint64_t testval); +static int pci_maprange(uint64_t mapreg); static void pci_fixancient(pcicfgregs *cfg); static int pci_porten(device_t pcib, int b, int s, int f); @@ -316,8 +316,8 @@ pci_find_device(uint16_t vendor, uint16_t device) /* return base address of memory or port map */ -static uint32_t -pci_mapbase(uint32_t mapreg) +static pci_addr_t +pci_mapbase(uint64_t mapreg) { if (PCI_BAR_MEM(mapreg)) @@ -329,7 +329,7 @@ pci_mapbase(uint32_t mapreg) /* return map type of memory or port map */ static const char * -pci_maptype(unsigned mapreg) +pci_maptype(uint64_t mapreg) { if (PCI_BAR_IO(mapreg)) @@ -342,7 +342,7 @@ pci_maptype(unsigned mapreg) /* return log2 of map size decoded for memory or port map */ static int -pci_mapsize(uint32_t testval) +pci_mapsize(uint64_t testval) { int ln2size; @@ -361,7 +361,7 @@ pci_mapsize(uint32_t testval) /* return log2 of address range supported by map register */ static int -pci_maprange(unsigned mapreg) +pci_maprange(uint64_t mapreg) { int ln2range = 0; @@ -2279,8 +2279,7 @@ pci_add_map(device_t pcib, device_t bus, device_t dev, int b, int s, int f, int reg, struct resource_list *rl, int force, int prefetch) { - uint32_t map; - pci_addr_t base; + pci_addr_t base, map; pci_addr_t start, end, count; uint8_t ln2size; uint8_t ln2range; @@ -2291,6 +2290,10 @@ pci_add_map(device_t pcib, device_t bus, device_t dev, struct resource *res; map = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); + ln2range = pci_maprange(map); + if (ln2range == 64) + map |= (uint64_t)PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, 4) << + 32; /* * Disable decoding via the command register before @@ -2308,9 +2311,16 @@ pci_add_map(device_t pcib, device_t bus, device_t dev, */ PCIB_WRITE_CONFIG(pcib, b, s, f, reg, 0xffffffff, 4); testval = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); + if (ln2range == 64) { + PCIB_WRITE_CONFIG(pcib, b, s, f, reg + 4, 0xffffffff, 4); + testval |= (uint64_t)PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, + 4) << 32; + } /* Restore the BAR and command register. */ PCIB_WRITE_CONFIG(pcib, b, s, f, reg, map, 4); + if (ln2range == 64) + PCIB_WRITE_CONFIG(pcib, b, s, f, reg + 4, map >> 32, 4); PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND, cmd, 2); if (PCI_BAR_MEM(map)) { @@ -2320,7 +2330,6 @@ pci_add_map(device_t pcib, device_t bus, device_t dev, } else type = SYS_RES_IOPORT; ln2size = pci_mapsize(testval); - ln2range = pci_maprange(testval); base = pci_mapbase(map); barlen = ln2range == 64 ? 2 : 1; @@ -2337,12 +2346,6 @@ pci_add_map(device_t pcib, device_t bus, device_t dev, (type == SYS_RES_IOPORT && ln2size < 2)) return (barlen); - if (ln2range == 64) - /* - * Read the other half of a 64bit map register. We - * assume that the size of the BAR is less than 2^32. - */ - base |= (uint64_t) PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, 4) << 32; if (bootverbose) { printf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d", reg, pci_maptype(map), ln2range, (uintmax_t)base, ln2size); @@ -3421,7 +3424,7 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid, struct resource *res; pci_addr_t map, testval; uint16_t cmd; - int mapsize; + int maprange, mapsize; /* * Weed out the bogons, and figure out how large the BAR/map @@ -3432,6 +3435,9 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid, */ res = NULL; map = pci_read_config(child, *rid, 4); + maprange = pci_maprange(map); + if (maprange == 64) + map |= (pci_addr_t)pci_read_config(child, *rid + 4, 4) << 32; /* * Disable decoding via the command register before @@ -3445,8 +3451,11 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid, /* Determine the BAR's length. */ pci_write_config(child, *rid, 0xffffffff, 4); testval = pci_read_config(child, *rid, 4); - if (pci_maprange(testval) == 64) - map |= (pci_addr_t)pci_read_config(child, *rid + 4, 4) << 32; + if (maprange == 64) { + pci_write_config(child, *rid + 4, 0xffffffff, 4); + testval |= (pci_addr_t)pci_read_config(child, *rid + 4, 4) << + 32; + } /* * Restore the original value of the BAR. We may have reprogrammed @@ -3454,6 +3463,8 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid, * we need the console device addressable. */ pci_write_config(child, *rid, map, 4); + if (maprange == 64) + pci_write_config(child, *rid + 4, map, 4); pci_write_config(child, PCIR_COMMAND, cmd, 2); /* Ignore a BAR with a base of 0. */ @@ -3520,7 +3531,7 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid, count, *rid, type, rman_get_start(res)); map = rman_get_start(res); pci_write_config(child, *rid, map, 4); - if (pci_maprange(testval) == 64) + if (maprange == 64) pci_write_config(child, *rid + 4, map >> 32, 4); out:; return (res); diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index 04e0f35fcb8d..9dfe7913a5ea 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -132,7 +132,7 @@ #define PCIM_BAR_MEM_1MB 2 /* Locate below 1MB in PCI <= 2.1 */ #define PCIM_BAR_MEM_64 4 #define PCIM_BAR_MEM_PREFETCH 0x00000008 -#define PCIM_BAR_MEM_BASE 0xfffffff0 +#define PCIM_BAR_MEM_BASE 0xfffffffffffffff0ULL #define PCIM_BAR_IO_RESERVED 0x00000002 #define PCIM_BAR_IO_BASE 0xfffffffc #define PCIR_CIS 0x28 |