diff options
-rw-r--r-- | drivers/pci/probe.c | 25 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 39 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 11 | ||||
-rw-r--r-- | include/linux/pci.h | 1 | ||||
-rw-r--r-- | include/linux/pci_regs.h | 3 |
5 files changed, 27 insertions, 52 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9c5d2a992999..ef24cf765b2f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -269,15 +269,23 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child) | |||
269 | { | 269 | { |
270 | struct pci_dev *dev = child->self; | 270 | struct pci_dev *dev = child->self; |
271 | u8 io_base_lo, io_limit_lo; | 271 | u8 io_base_lo, io_limit_lo; |
272 | unsigned long base, limit; | 272 | unsigned long io_mask, io_granularity, base, limit; |
273 | struct pci_bus_region region; | 273 | struct pci_bus_region region; |
274 | struct resource *res, res2; | 274 | struct resource *res; |
275 | |||
276 | io_mask = PCI_IO_RANGE_MASK; | ||
277 | io_granularity = 0x1000; | ||
278 | if (dev->io_window_1k) { | ||
279 | /* Support 1K I/O space granularity */ | ||
280 | io_mask = PCI_IO_1K_RANGE_MASK; | ||
281 | io_granularity = 0x400; | ||
282 | } | ||
275 | 283 | ||
276 | res = child->resource[0]; | 284 | res = child->resource[0]; |
277 | pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); | 285 | pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); |
278 | pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); | 286 | pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); |
279 | base = (io_base_lo & PCI_IO_RANGE_MASK) << 8; | 287 | base = (io_base_lo & io_mask) << 8; |
280 | limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8; | 288 | limit = (io_limit_lo & io_mask) << 8; |
281 | 289 | ||
282 | if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { | 290 | if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { |
283 | u16 io_base_hi, io_limit_hi; | 291 | u16 io_base_hi, io_limit_hi; |
@@ -289,14 +297,9 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child) | |||
289 | 297 | ||
290 | if (base <= limit) { | 298 | if (base <= limit) { |
291 | res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; | 299 | res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; |
292 | res2.flags = res->flags; | ||
293 | region.start = base; | 300 | region.start = base; |
294 | region.end = limit + 0xfff; | 301 | region.end = limit + io_granularity - 1; |
295 | pcibios_bus_to_resource(dev, &res2, ®ion); | 302 | pcibios_bus_to_resource(dev, res, ®ion); |
296 | if (!res->start) | ||
297 | res->start = res2.start; | ||
298 | if (!res->end) | ||
299 | res->end = res2.end; | ||
300 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); | 303 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); |
301 | } | 304 | } |
302 | } | 305 | } |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 2a7521677541..356846bd7ffb 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -1938,53 +1938,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1 | |||
1938 | static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) | 1938 | static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) |
1939 | { | 1939 | { |
1940 | u16 en1k; | 1940 | u16 en1k; |
1941 | u8 io_base_lo, io_limit_lo; | ||
1942 | unsigned long base, limit; | ||
1943 | struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES; | ||
1944 | 1941 | ||
1945 | pci_read_config_word(dev, 0x40, &en1k); | 1942 | pci_read_config_word(dev, 0x40, &en1k); |
1946 | 1943 | ||
1947 | if (en1k & 0x200) { | 1944 | if (en1k & 0x200) { |
1948 | dev_info(&dev->dev, "Enable I/O Space to 1KB granularity\n"); | 1945 | dev_info(&dev->dev, "Enable I/O Space to 1KB granularity\n"); |
1949 | 1946 | dev->io_window_1k = 1; | |
1950 | pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); | ||
1951 | pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); | ||
1952 | base = (io_base_lo & (PCI_IO_RANGE_MASK | 0x0c)) << 8; | ||
1953 | limit = (io_limit_lo & (PCI_IO_RANGE_MASK | 0x0c)) << 8; | ||
1954 | |||
1955 | if (base <= limit) { | ||
1956 | res->start = base; | ||
1957 | res->end = limit + 0x3ff; | ||
1958 | } | ||
1959 | } | 1947 | } |
1960 | } | 1948 | } |
1961 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); | 1949 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); |
1962 | 1950 | ||
1963 | /* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2 | ||
1964 | * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge() | ||
1965 | * in drivers/pci/setup-bus.c | ||
1966 | */ | ||
1967 | static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev) | ||
1968 | { | ||
1969 | u16 en1k, iobl_adr, iobl_adr_1k; | ||
1970 | struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES; | ||
1971 | |||
1972 | pci_read_config_word(dev, 0x40, &en1k); | ||
1973 | |||
1974 | if (en1k & 0x200) { | ||
1975 | pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr); | ||
1976 | |||
1977 | iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00); | ||
1978 | |||
1979 | if (iobl_adr != iobl_adr_1k) { | ||
1980 | dev_info(&dev->dev, "Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1KB granularity\n", | ||
1981 | iobl_adr,iobl_adr_1k); | ||
1982 | pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k); | ||
1983 | } | ||
1984 | } | ||
1985 | } | ||
1986 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io_fix_iobl); | ||
1987 | |||
1988 | /* Under some circumstances, AER is not linked with extended capabilities. | 1951 | /* Under some circumstances, AER is not linked with extended capabilities. |
1989 | * Force it to be linked by setting the corresponding control bit in the | 1952 | * Force it to be linked by setting the corresponding control bit in the |
1990 | * config space. | 1953 | * config space. |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 8fa2d4be88de..dad5425f1f09 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -469,16 +469,23 @@ static void pci_setup_bridge_io(struct pci_bus *bus) | |||
469 | struct pci_dev *bridge = bus->self; | 469 | struct pci_dev *bridge = bus->self; |
470 | struct resource *res; | 470 | struct resource *res; |
471 | struct pci_bus_region region; | 471 | struct pci_bus_region region; |
472 | unsigned long io_mask; | ||
473 | u8 io_base_lo, io_limit_lo; | ||
472 | u32 l, io_upper16; | 474 | u32 l, io_upper16; |
473 | 475 | ||
476 | io_mask = PCI_IO_RANGE_MASK; | ||
477 | if (bridge->io_window_1k) | ||
478 | io_mask = PCI_IO_1K_RANGE_MASK; | ||
479 | |||
474 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ | 480 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ |
475 | res = bus->resource[0]; | 481 | res = bus->resource[0]; |
476 | pcibios_resource_to_bus(bridge, ®ion, res); | 482 | pcibios_resource_to_bus(bridge, ®ion, res); |
477 | if (res->flags & IORESOURCE_IO) { | 483 | if (res->flags & IORESOURCE_IO) { |
478 | pci_read_config_dword(bridge, PCI_IO_BASE, &l); | 484 | pci_read_config_dword(bridge, PCI_IO_BASE, &l); |
479 | l &= 0xffff0000; | 485 | l &= 0xffff0000; |
480 | l |= (region.start >> 8) & 0x00f0; | 486 | io_base_lo = (region.start >> 8) & io_mask; |
481 | l |= region.end & 0xf000; | 487 | io_limit_lo = (region.end >> 8) & io_mask; |
488 | l |= ((u32) io_limit_lo << 8) | io_base_lo; | ||
482 | /* Set up upper 16 bits of I/O base/limit. */ | 489 | /* Set up upper 16 bits of I/O base/limit. */ |
483 | io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); | 490 | io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); |
484 | dev_info(&bridge->dev, " bridge window %pR\n", res); | 491 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
diff --git a/include/linux/pci.h b/include/linux/pci.h index d8c379dba6ad..89b46fd245c6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -324,6 +324,7 @@ struct pci_dev { | |||
324 | unsigned int is_hotplug_bridge:1; | 324 | unsigned int is_hotplug_bridge:1; |
325 | unsigned int __aer_firmware_first_valid:1; | 325 | unsigned int __aer_firmware_first_valid:1; |
326 | unsigned int __aer_firmware_first:1; | 326 | unsigned int __aer_firmware_first:1; |
327 | unsigned int io_window_1k:1; /* Intel P2P bridge 1K I/O windows */ | ||
327 | pci_dev_flags_t dev_flags; | 328 | pci_dev_flags_t dev_flags; |
328 | atomic_t enable_cnt; /* pci_enable_device has been called */ | 329 | atomic_t enable_cnt; /* pci_enable_device has been called */ |
329 | 330 | ||
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 4b608f543412..88c9ea56e252 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h | |||
@@ -125,7 +125,8 @@ | |||
125 | #define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ | 125 | #define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ |
126 | #define PCI_IO_RANGE_TYPE_16 0x00 | 126 | #define PCI_IO_RANGE_TYPE_16 0x00 |
127 | #define PCI_IO_RANGE_TYPE_32 0x01 | 127 | #define PCI_IO_RANGE_TYPE_32 0x01 |
128 | #define PCI_IO_RANGE_MASK (~0x0fUL) | 128 | #define PCI_IO_RANGE_MASK (~0x0fUL) /* Standard 4K I/O windows */ |
129 | #define PCI_IO_1K_RANGE_MASK (~0x03UL) /* Intel 1K I/O windows */ | ||
129 | #define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ | 130 | #define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ |
130 | #define PCI_MEMORY_BASE 0x20 /* Memory range behind */ | 131 | #define PCI_MEMORY_BASE 0x20 /* Memory range behind */ |
131 | #define PCI_MEMORY_LIMIT 0x22 | 132 | #define PCI_MEMORY_LIMIT 0x22 |