diff options
author | Kleber Sacilotto de Souza <klebers@linux.vnet.ibm.com> | 2013-05-03 08:43:12 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-05-05 19:25:38 -0400 |
commit | d82fb31abc46620b7c22758c75707069f2763646 (patch) | |
tree | 29a92372ff460db1008565aa027a7fc60f2277e9 /arch/powerpc | |
parent | e61133dda480062d221f09e4fc18f66763f8ecd0 (diff) |
powerpc/pseries: Perform proper max_bus_speed detection
On pseries machines the detection for max_bus_speed should be done
through an OpenFirmware property. This patch adds a function to perform
this detection and a hook to perform dynamic adding of the function only
for pseries. This is done by overwriting the weak
pcibios_root_bridge_prepare function which is called by
pci_create_root_bus().
From: Lucas Kannebley Tavares <lucaskt@linux.vnet.ibm.com>
Signed-off-by: Kleber Sacilotto de Souza <klebers@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/machdep.h | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci-common.c | 8 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci.c | 53 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pseries.h | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 2 |
5 files changed, 70 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 3f3f691be2e7..92386fc4e82a 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h | |||
@@ -29,6 +29,7 @@ struct rtc_time; | |||
29 | struct file; | 29 | struct file; |
30 | struct pci_controller; | 30 | struct pci_controller; |
31 | struct kimage; | 31 | struct kimage; |
32 | struct pci_host_bridge; | ||
32 | 33 | ||
33 | struct machdep_calls { | 34 | struct machdep_calls { |
34 | char *name; | 35 | char *name; |
@@ -108,6 +109,8 @@ struct machdep_calls { | |||
108 | void (*pcibios_fixup)(void); | 109 | void (*pcibios_fixup)(void); |
109 | int (*pci_probe_mode)(struct pci_bus *); | 110 | int (*pci_probe_mode)(struct pci_bus *); |
110 | void (*pci_irq_fixup)(struct pci_dev *dev); | 111 | void (*pci_irq_fixup)(struct pci_dev *dev); |
112 | int (*pcibios_root_bridge_prepare)(struct pci_host_bridge | ||
113 | *bridge); | ||
111 | 114 | ||
112 | /* To setup PHBs when using automatic OF platform driver for PCI */ | 115 | /* To setup PHBs when using automatic OF platform driver for PCI */ |
113 | int (*pci_setup_phb)(struct pci_controller *host); | 116 | int (*pci_setup_phb)(struct pci_controller *host); |
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index f325dc923409..d5811d8cc2c6 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c | |||
@@ -845,6 +845,14 @@ int pci_proc_domain(struct pci_bus *bus) | |||
845 | return 1; | 845 | return 1; |
846 | } | 846 | } |
847 | 847 | ||
848 | int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) | ||
849 | { | ||
850 | if (ppc_md.pcibios_root_bridge_prepare) | ||
851 | return ppc_md.pcibios_root_bridge_prepare(bridge); | ||
852 | |||
853 | return 0; | ||
854 | } | ||
855 | |||
848 | /* This header fixup will do the resource fixup for all devices as they are | 856 | /* This header fixup will do the resource fixup for all devices as they are |
849 | * probed, but not for bridge ranges | 857 | * probed, but not for bridge ranges |
850 | */ | 858 | */ |
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 0b580f413a9a..5f93856cdf47 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c | |||
@@ -108,3 +108,56 @@ static void fixup_winbond_82c105(struct pci_dev* dev) | |||
108 | } | 108 | } |
109 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, | 109 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, |
110 | fixup_winbond_82c105); | 110 | fixup_winbond_82c105); |
111 | |||
112 | int pseries_root_bridge_prepare(struct pci_host_bridge *bridge) | ||
113 | { | ||
114 | struct device_node *dn, *pdn; | ||
115 | struct pci_bus *bus; | ||
116 | const uint32_t *pcie_link_speed_stats; | ||
117 | |||
118 | bus = bridge->bus; | ||
119 | |||
120 | dn = pcibios_get_phb_of_node(bus); | ||
121 | if (!dn) | ||
122 | return 0; | ||
123 | |||
124 | for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) { | ||
125 | pcie_link_speed_stats = (const uint32_t *) of_get_property(pdn, | ||
126 | "ibm,pcie-link-speed-stats", NULL); | ||
127 | if (pcie_link_speed_stats) | ||
128 | break; | ||
129 | } | ||
130 | |||
131 | of_node_put(pdn); | ||
132 | |||
133 | if (!pcie_link_speed_stats) { | ||
134 | pr_err("no ibm,pcie-link-speed-stats property\n"); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | switch (pcie_link_speed_stats[0]) { | ||
139 | case 0x01: | ||
140 | bus->max_bus_speed = PCIE_SPEED_2_5GT; | ||
141 | break; | ||
142 | case 0x02: | ||
143 | bus->max_bus_speed = PCIE_SPEED_5_0GT; | ||
144 | break; | ||
145 | default: | ||
146 | bus->max_bus_speed = PCI_SPEED_UNKNOWN; | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | switch (pcie_link_speed_stats[1]) { | ||
151 | case 0x01: | ||
152 | bus->cur_bus_speed = PCIE_SPEED_2_5GT; | ||
153 | break; | ||
154 | case 0x02: | ||
155 | bus->cur_bus_speed = PCIE_SPEED_5_0GT; | ||
156 | break; | ||
157 | default: | ||
158 | bus->cur_bus_speed = PCI_SPEED_UNKNOWN; | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | return 0; | ||
163 | } | ||
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 8af71e4cc17f..c2a3a258001c 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h | |||
@@ -63,4 +63,8 @@ extern int dlpar_detach_node(struct device_node *); | |||
63 | /* Snooze Delay, pseries_idle */ | 63 | /* Snooze Delay, pseries_idle */ |
64 | DECLARE_PER_CPU(long, smt_snooze_delay); | 64 | DECLARE_PER_CPU(long, smt_snooze_delay); |
65 | 65 | ||
66 | /* PCI root bridge prepare function override for pseries */ | ||
67 | struct pci_host_bridge; | ||
68 | int pseries_root_bridge_prepare(struct pci_host_bridge *bridge); | ||
69 | |||
66 | #endif /* _PSERIES_PSERIES_H */ | 70 | #endif /* _PSERIES_PSERIES_H */ |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index ac932a9eb440..c11c8238797c 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -466,6 +466,8 @@ static void __init pSeries_setup_arch(void) | |||
466 | else | 466 | else |
467 | ppc_md.enable_pmcs = power4_enable_pmcs; | 467 | ppc_md.enable_pmcs = power4_enable_pmcs; |
468 | 468 | ||
469 | ppc_md.pcibios_root_bridge_prepare = pseries_root_bridge_prepare; | ||
470 | |||
469 | if (firmware_has_feature(FW_FEATURE_SET_MODE)) { | 471 | if (firmware_has_feature(FW_FEATURE_SET_MODE)) { |
470 | long rc; | 472 | long rc; |
471 | if ((rc = pSeries_enable_reloc_on_exc()) != H_SUCCESS) { | 473 | if ((rc = pSeries_enable_reloc_on_exc()) != H_SUCCESS) { |