154 lines
4.8 KiB
Diff
154 lines
4.8 KiB
Diff
From d82fb31abc46620b7c22758c75707069f2763646 Mon Sep 17 00:00:00 2001
|
|
From: Kleber Sacilotto de Souza <klebers@linux.vnet.ibm.com>
|
|
Date: Fri, 3 May 2013 12:43:12 +0000
|
|
Subject: [PATCH] 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>
|
|
---
|
|
arch/powerpc/include/asm/machdep.h | 3 ++
|
|
arch/powerpc/kernel/pci-common.c | 8 +++++
|
|
arch/powerpc/platforms/pseries/pci.c | 53 ++++++++++++++++++++++++++++++++
|
|
arch/powerpc/platforms/pseries/pseries.h | 4 +++
|
|
arch/powerpc/platforms/pseries/setup.c | 2 ++
|
|
5 files changed, 70 insertions(+)
|
|
|
|
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
|
|
index 3f3f691..92386fc 100644
|
|
--- a/arch/powerpc/include/asm/machdep.h
|
|
+++ b/arch/powerpc/include/asm/machdep.h
|
|
@@ -29,6 +29,7 @@ struct rtc_time;
|
|
struct file;
|
|
struct pci_controller;
|
|
struct kimage;
|
|
+struct pci_host_bridge;
|
|
|
|
struct machdep_calls {
|
|
char *name;
|
|
@@ -108,6 +109,8 @@ struct machdep_calls {
|
|
void (*pcibios_fixup)(void);
|
|
int (*pci_probe_mode)(struct pci_bus *);
|
|
void (*pci_irq_fixup)(struct pci_dev *dev);
|
|
+ int (*pcibios_root_bridge_prepare)(struct pci_host_bridge
|
|
+ *bridge);
|
|
|
|
/* To setup PHBs when using automatic OF platform driver for PCI */
|
|
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 f325dc9..d5811d8 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)
|
|
return 1;
|
|
}
|
|
|
|
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
|
|
+{
|
|
+ if (ppc_md.pcibios_root_bridge_prepare)
|
|
+ return ppc_md.pcibios_root_bridge_prepare(bridge);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/* This header fixup will do the resource fixup for all devices as they are
|
|
* probed, but not for bridge ranges
|
|
*/
|
|
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
|
|
index 0b580f4..5f93856 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)
|
|
}
|
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105,
|
|
fixup_winbond_82c105);
|
|
+
|
|
+int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
|
|
+{
|
|
+ struct device_node *dn, *pdn;
|
|
+ struct pci_bus *bus;
|
|
+ const uint32_t *pcie_link_speed_stats;
|
|
+
|
|
+ bus = bridge->bus;
|
|
+
|
|
+ dn = pcibios_get_phb_of_node(bus);
|
|
+ if (!dn)
|
|
+ return 0;
|
|
+
|
|
+ for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) {
|
|
+ pcie_link_speed_stats = (const uint32_t *) of_get_property(pdn,
|
|
+ "ibm,pcie-link-speed-stats", NULL);
|
|
+ if (pcie_link_speed_stats)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ of_node_put(pdn);
|
|
+
|
|
+ if (!pcie_link_speed_stats) {
|
|
+ pr_err("no ibm,pcie-link-speed-stats property\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ switch (pcie_link_speed_stats[0]) {
|
|
+ case 0x01:
|
|
+ bus->max_bus_speed = PCIE_SPEED_2_5GT;
|
|
+ break;
|
|
+ case 0x02:
|
|
+ bus->max_bus_speed = PCIE_SPEED_5_0GT;
|
|
+ break;
|
|
+ default:
|
|
+ bus->max_bus_speed = PCI_SPEED_UNKNOWN;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ switch (pcie_link_speed_stats[1]) {
|
|
+ case 0x01:
|
|
+ bus->cur_bus_speed = PCIE_SPEED_2_5GT;
|
|
+ break;
|
|
+ case 0x02:
|
|
+ bus->cur_bus_speed = PCIE_SPEED_5_0GT;
|
|
+ break;
|
|
+ default:
|
|
+ bus->cur_bus_speed = PCI_SPEED_UNKNOWN;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
|
|
index 8af71e4..c2a3a25 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 *);
|
|
/* Snooze Delay, pseries_idle */
|
|
DECLARE_PER_CPU(long, smt_snooze_delay);
|
|
|
|
+/* PCI root bridge prepare function override for pseries */
|
|
+struct pci_host_bridge;
|
|
+int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);
|
|
+
|
|
#endif /* _PSERIES_PSERIES_H */
|
|
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
|
|
index ac932a9..c11c823 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)
|
|
else
|
|
ppc_md.enable_pmcs = power4_enable_pmcs;
|
|
|
|
+ ppc_md.pcibios_root_bridge_prepare = pseries_root_bridge_prepare;
|
|
+
|
|
if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
|
|
long rc;
|
|
if ((rc = pSeries_enable_reloc_on_exc()) != H_SUCCESS) {
|
|
--
|
|
1.8.1.4
|
|
|