diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-13 15:14:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-13 15:14:47 -0500 |
commit | 193c0d682525987db59ac3a24531a77e4947aa95 (patch) | |
tree | 7b58346171c4d07e2c2ee6c3c469c325495149a4 /arch/x86/pci | |
parent | 8b0cab14951fbf8126795ab301835a8f8126a988 (diff) | |
parent | 1cb73f8c479e66541fefd3f7fa547b1fa56cdc54 (diff) |
Merge tag 'for-3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI update from Bjorn Helgaas:
"Host bridge hotplug:
- Untangle _PRT from struct pci_bus (Bjorn Helgaas)
- Request _OSC control before scanning root bus (Taku Izumi)
- Assign resources when adding host bridge (Yinghai Lu)
- Remove root bus when removing host bridge (Yinghai Lu)
- Remove _PRT during hot remove (Yinghai Lu)
SRIOV
- Add sysfs knobs to control numVFs (Don Dutile)
Power management
- Notify devices when power resource turned on (Huang Ying)
Bug fixes
- Work around broken _SEG on HP xw9300 (Bjorn Helgaas)
- Keep runtime PM enabled for unbound PCI devices (Huang Ying)
- Fix Optimus dual-GPU runtime D3 suspend issue (Dave Airlie)
- Fix xen frontend shutdown issue (David Vrabel)
- Work around PLX PCI 9050 BAR alignment erratum (Ian Abbott)
Miscellaneous
- Add GPL license for drivers/pci/ioapic (Andrew Cooks)
- Add standard PCI-X, PCIe ASPM register #defines (Bjorn Helgaas)
- NumaChip remote PCI support (Daniel Blueman)
- Fix PCIe Link Capabilities Supported Link Speed definition (Jingoo
Han)
- Convert dev_printk() to dev_info(), etc (Joe Perches)
- Add support for non PCI BAR ROM data (Matthew Garrett)
- Add x86 support for host bridge translation offset (Mike Yoknis)
- Report success only when every driver supports AER (Vijay
Pandarathil)"
Fix up trivial conflicts.
* tag 'for-3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (48 commits)
PCI: Use phys_addr_t for physical ROM address
x86/PCI: Add NumaChip remote PCI support
ath9k: Use standard #defines for PCIe Capability ASPM fields
iwlwifi: Use standard #defines for PCIe Capability ASPM fields
iwlwifi: collapse wrapper for pcie_capability_read_word()
iwlegacy: Use standard #defines for PCIe Capability ASPM fields
iwlegacy: collapse wrapper for pcie_capability_read_word()
cxgb3: Use standard #defines for PCIe Capability ASPM fields
PCI: Add standard PCIe Capability Link ASPM field names
PCI/portdrv: Use PCI Express Capability accessors
PCI: Use standard PCIe Capability Link register field names
x86: Use PCI setup data
PCI: Add support for non-BAR ROMs
PCI: Add pcibios_add_device
EFI: Stash ROMs if they're not in the PCI BAR
PCI: Add and use standard PCI-X Capability register names
PCI/PM: Keep runtime PM enabled for unbound PCI devices
xen-pcifront: Handle backend CLOSED without CLOSING
PCI: SRIOV control and status via sysfs (documentation)
PCI/AER: Report success only when every device has AER-aware driver
...
Diffstat (limited to 'arch/x86/pci')
-rw-r--r-- | arch/x86/pci/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/pci/acpi.c | 46 | ||||
-rw-r--r-- | arch/x86/pci/common.c | 32 | ||||
-rw-r--r-- | arch/x86/pci/numachip.c | 129 |
4 files changed, 202 insertions, 6 deletions
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile index 3af5a1e79c9c..ee0af58ca5bd 100644 --- a/arch/x86/pci/Makefile +++ b/arch/x86/pci/Makefile | |||
@@ -16,6 +16,7 @@ obj-$(CONFIG_STA2X11) += sta2x11-fixup.o | |||
16 | obj-$(CONFIG_X86_VISWS) += visws.o | 16 | obj-$(CONFIG_X86_VISWS) += visws.o |
17 | 17 | ||
18 | obj-$(CONFIG_X86_NUMAQ) += numaq_32.o | 18 | obj-$(CONFIG_X86_NUMAQ) += numaq_32.o |
19 | obj-$(CONFIG_X86_NUMACHIP) += numachip.o | ||
19 | 20 | ||
20 | obj-$(CONFIG_X86_INTEL_MID) += mrst.o | 21 | obj-$(CONFIG_X86_INTEL_MID) += mrst.o |
21 | 22 | ||
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 192397c98606..0c01261fe5a8 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -12,6 +12,7 @@ struct pci_root_info { | |||
12 | char name[16]; | 12 | char name[16]; |
13 | unsigned int res_num; | 13 | unsigned int res_num; |
14 | struct resource *res; | 14 | struct resource *res; |
15 | resource_size_t *res_offset; | ||
15 | struct pci_sysdata sd; | 16 | struct pci_sysdata sd; |
16 | #ifdef CONFIG_PCI_MMCONFIG | 17 | #ifdef CONFIG_PCI_MMCONFIG |
17 | bool mcfg_added; | 18 | bool mcfg_added; |
@@ -22,6 +23,7 @@ struct pci_root_info { | |||
22 | }; | 23 | }; |
23 | 24 | ||
24 | static bool pci_use_crs = true; | 25 | static bool pci_use_crs = true; |
26 | static bool pci_ignore_seg = false; | ||
25 | 27 | ||
26 | static int __init set_use_crs(const struct dmi_system_id *id) | 28 | static int __init set_use_crs(const struct dmi_system_id *id) |
27 | { | 29 | { |
@@ -35,7 +37,14 @@ static int __init set_nouse_crs(const struct dmi_system_id *id) | |||
35 | return 0; | 37 | return 0; |
36 | } | 38 | } |
37 | 39 | ||
38 | static const struct dmi_system_id pci_use_crs_table[] __initconst = { | 40 | static int __init set_ignore_seg(const struct dmi_system_id *id) |
41 | { | ||
42 | printk(KERN_INFO "PCI: %s detected: ignoring ACPI _SEG\n", id->ident); | ||
43 | pci_ignore_seg = true; | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static const struct dmi_system_id pci_crs_quirks[] __initconst = { | ||
39 | /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */ | 48 | /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */ |
40 | { | 49 | { |
41 | .callback = set_use_crs, | 50 | .callback = set_use_crs, |
@@ -98,6 +107,16 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = { | |||
98 | DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"), | 107 | DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"), |
99 | }, | 108 | }, |
100 | }, | 109 | }, |
110 | |||
111 | /* https://bugzilla.kernel.org/show_bug.cgi?id=15362 */ | ||
112 | { | ||
113 | .callback = set_ignore_seg, | ||
114 | .ident = "HP xw9300", | ||
115 | .matches = { | ||
116 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
117 | DMI_MATCH(DMI_PRODUCT_NAME, "HP xw9300 Workstation"), | ||
118 | }, | ||
119 | }, | ||
101 | {} | 120 | {} |
102 | }; | 121 | }; |
103 | 122 | ||
@@ -108,7 +127,7 @@ void __init pci_acpi_crs_quirks(void) | |||
108 | if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008) | 127 | if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008) |
109 | pci_use_crs = false; | 128 | pci_use_crs = false; |
110 | 129 | ||
111 | dmi_check_system(pci_use_crs_table); | 130 | dmi_check_system(pci_crs_quirks); |
112 | 131 | ||
113 | /* | 132 | /* |
114 | * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that | 133 | * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that |
@@ -305,6 +324,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data) | |||
305 | res->flags = flags; | 324 | res->flags = flags; |
306 | res->start = start; | 325 | res->start = start; |
307 | res->end = end; | 326 | res->end = end; |
327 | info->res_offset[info->res_num] = addr.translation_offset; | ||
308 | 328 | ||
309 | if (!pci_use_crs) { | 329 | if (!pci_use_crs) { |
310 | dev_printk(KERN_DEBUG, &info->bridge->dev, | 330 | dev_printk(KERN_DEBUG, &info->bridge->dev, |
@@ -374,7 +394,8 @@ static void add_resources(struct pci_root_info *info, | |||
374 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", | 394 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", |
375 | res, conflict->name, conflict); | 395 | res, conflict->name, conflict); |
376 | else | 396 | else |
377 | pci_add_resource(resources, res); | 397 | pci_add_resource_offset(resources, res, |
398 | info->res_offset[i]); | ||
378 | } | 399 | } |
379 | } | 400 | } |
380 | 401 | ||
@@ -382,6 +403,8 @@ static void free_pci_root_info_res(struct pci_root_info *info) | |||
382 | { | 403 | { |
383 | kfree(info->res); | 404 | kfree(info->res); |
384 | info->res = NULL; | 405 | info->res = NULL; |
406 | kfree(info->res_offset); | ||
407 | info->res_offset = NULL; | ||
385 | info->res_num = 0; | 408 | info->res_num = 0; |
386 | } | 409 | } |
387 | 410 | ||
@@ -432,10 +455,20 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, | |||
432 | return; | 455 | return; |
433 | 456 | ||
434 | size = sizeof(*info->res) * info->res_num; | 457 | size = sizeof(*info->res) * info->res_num; |
435 | info->res_num = 0; | ||
436 | info->res = kzalloc(size, GFP_KERNEL); | 458 | info->res = kzalloc(size, GFP_KERNEL); |
437 | if (!info->res) | 459 | if (!info->res) { |
460 | info->res_num = 0; | ||
461 | return; | ||
462 | } | ||
463 | |||
464 | size = sizeof(*info->res_offset) * info->res_num; | ||
465 | info->res_num = 0; | ||
466 | info->res_offset = kzalloc(size, GFP_KERNEL); | ||
467 | if (!info->res_offset) { | ||
468 | kfree(info->res); | ||
469 | info->res = NULL; | ||
438 | return; | 470 | return; |
471 | } | ||
439 | 472 | ||
440 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, | 473 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, |
441 | info); | 474 | info); |
@@ -455,6 +488,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
455 | int pxm; | 488 | int pxm; |
456 | #endif | 489 | #endif |
457 | 490 | ||
491 | if (pci_ignore_seg) | ||
492 | domain = 0; | ||
493 | |||
458 | if (domain && !pci_domains_supported) { | 494 | if (domain && !pci_domains_supported) { |
459 | printk(KERN_WARNING "pci_bus %04x:%02x: " | 495 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
460 | "ignored (multiple domains not supported)\n", | 496 | "ignored (multiple domains not supported)\n", |
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 720e973fc34a..1b1dda90a945 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <asm/io.h> | 17 | #include <asm/io.h> |
18 | #include <asm/smp.h> | 18 | #include <asm/smp.h> |
19 | #include <asm/pci_x86.h> | 19 | #include <asm/pci_x86.h> |
20 | #include <asm/setup.h> | ||
20 | 21 | ||
21 | unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | | 22 | unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | |
22 | PCI_PROBE_MMCONF; | 23 | PCI_PROBE_MMCONF; |
@@ -608,6 +609,35 @@ unsigned int pcibios_assign_all_busses(void) | |||
608 | return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; | 609 | return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; |
609 | } | 610 | } |
610 | 611 | ||
612 | int pcibios_add_device(struct pci_dev *dev) | ||
613 | { | ||
614 | struct setup_data *data; | ||
615 | struct pci_setup_rom *rom; | ||
616 | u64 pa_data; | ||
617 | |||
618 | pa_data = boot_params.hdr.setup_data; | ||
619 | while (pa_data) { | ||
620 | data = phys_to_virt(pa_data); | ||
621 | |||
622 | if (data->type == SETUP_PCI) { | ||
623 | rom = (struct pci_setup_rom *)data; | ||
624 | |||
625 | if ((pci_domain_nr(dev->bus) == rom->segment) && | ||
626 | (dev->bus->number == rom->bus) && | ||
627 | (PCI_SLOT(dev->devfn) == rom->device) && | ||
628 | (PCI_FUNC(dev->devfn) == rom->function) && | ||
629 | (dev->vendor == rom->vendor) && | ||
630 | (dev->device == rom->devid)) { | ||
631 | dev->rom = pa_data + | ||
632 | offsetof(struct pci_setup_rom, romdata); | ||
633 | dev->romlen = rom->pcilen; | ||
634 | } | ||
635 | } | ||
636 | pa_data = data->next; | ||
637 | } | ||
638 | return 0; | ||
639 | } | ||
640 | |||
611 | int pcibios_enable_device(struct pci_dev *dev, int mask) | 641 | int pcibios_enable_device(struct pci_dev *dev, int mask) |
612 | { | 642 | { |
613 | int err; | 643 | int err; |
@@ -626,7 +656,7 @@ void pcibios_disable_device (struct pci_dev *dev) | |||
626 | pcibios_disable_irq(dev); | 656 | pcibios_disable_irq(dev); |
627 | } | 657 | } |
628 | 658 | ||
629 | int pci_ext_cfg_avail(struct pci_dev *dev) | 659 | int pci_ext_cfg_avail(void) |
630 | { | 660 | { |
631 | if (raw_pci_ext_ops) | 661 | if (raw_pci_ext_ops) |
632 | return 1; | 662 | return 1; |
diff --git a/arch/x86/pci/numachip.c b/arch/x86/pci/numachip.c new file mode 100644 index 000000000000..7307d9d12d15 --- /dev/null +++ b/arch/x86/pci/numachip.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Numascale NumaConnect-specific PCI code | ||
7 | * | ||
8 | * Copyright (C) 2012 Numascale AS. All rights reserved. | ||
9 | * | ||
10 | * Send feedback to <support@numascale.com> | ||
11 | * | ||
12 | * PCI accessor functions derived from mmconfig_64.c | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/pci.h> | ||
17 | #include <asm/pci_x86.h> | ||
18 | |||
19 | static u8 limit __read_mostly; | ||
20 | |||
21 | static inline char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) | ||
22 | { | ||
23 | struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus); | ||
24 | |||
25 | if (cfg && cfg->virt) | ||
26 | return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12)); | ||
27 | return NULL; | ||
28 | } | ||
29 | |||
30 | static int pci_mmcfg_read_numachip(unsigned int seg, unsigned int bus, | ||
31 | unsigned int devfn, int reg, int len, u32 *value) | ||
32 | { | ||
33 | char __iomem *addr; | ||
34 | |||
35 | /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ | ||
36 | if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) { | ||
37 | err: *value = -1; | ||
38 | return -EINVAL; | ||
39 | } | ||
40 | |||
41 | /* Ensure AMD Northbridges don't decode reads to other devices */ | ||
42 | if (unlikely(bus == 0 && devfn >= limit)) { | ||
43 | *value = -1; | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | rcu_read_lock(); | ||
48 | addr = pci_dev_base(seg, bus, devfn); | ||
49 | if (!addr) { | ||
50 | rcu_read_unlock(); | ||
51 | goto err; | ||
52 | } | ||
53 | |||
54 | switch (len) { | ||
55 | case 1: | ||
56 | *value = mmio_config_readb(addr + reg); | ||
57 | break; | ||
58 | case 2: | ||
59 | *value = mmio_config_readw(addr + reg); | ||
60 | break; | ||
61 | case 4: | ||
62 | *value = mmio_config_readl(addr + reg); | ||
63 | break; | ||
64 | } | ||
65 | rcu_read_unlock(); | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static int pci_mmcfg_write_numachip(unsigned int seg, unsigned int bus, | ||
71 | unsigned int devfn, int reg, int len, u32 value) | ||
72 | { | ||
73 | char __iomem *addr; | ||
74 | |||
75 | /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ | ||
76 | if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) | ||
77 | return -EINVAL; | ||
78 | |||
79 | /* Ensure AMD Northbridges don't decode writes to other devices */ | ||
80 | if (unlikely(bus == 0 && devfn >= limit)) | ||
81 | return 0; | ||
82 | |||
83 | rcu_read_lock(); | ||
84 | addr = pci_dev_base(seg, bus, devfn); | ||
85 | if (!addr) { | ||
86 | rcu_read_unlock(); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | switch (len) { | ||
91 | case 1: | ||
92 | mmio_config_writeb(addr + reg, value); | ||
93 | break; | ||
94 | case 2: | ||
95 | mmio_config_writew(addr + reg, value); | ||
96 | break; | ||
97 | case 4: | ||
98 | mmio_config_writel(addr + reg, value); | ||
99 | break; | ||
100 | } | ||
101 | rcu_read_unlock(); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | const struct pci_raw_ops pci_mmcfg_numachip = { | ||
107 | .read = pci_mmcfg_read_numachip, | ||
108 | .write = pci_mmcfg_write_numachip, | ||
109 | }; | ||
110 | |||
111 | int __init pci_numachip_init(void) | ||
112 | { | ||
113 | int ret = 0; | ||
114 | u32 val; | ||
115 | |||
116 | /* For remote I/O, restrict bus 0 access to the actual number of AMD | ||
117 | Northbridges, which starts at device number 0x18 */ | ||
118 | ret = raw_pci_read(0, 0, PCI_DEVFN(0x18, 0), 0x60, sizeof(val), &val); | ||
119 | if (ret) | ||
120 | goto out; | ||
121 | |||
122 | /* HyperTransport fabric size in bits 6:4 */ | ||
123 | limit = PCI_DEVFN(0x18 + ((val >> 4) & 7) + 1, 0); | ||
124 | |||
125 | /* Use NumaChip PCI accessors for non-extended and extended access */ | ||
126 | raw_pci_ops = raw_pci_ext_ops = &pci_mmcfg_numachip; | ||
127 | out: | ||
128 | return ret; | ||
129 | } | ||