powerpc/eeh: pseries platform config space access in EEH
With the original EEH implementation, the access to config space of
the corresponding PCI device is done by RTAS sensitive function. That
depends on pci_dn heavily. That would limit EEH extension to other
platforms like powernv because other platforms might have different
ways to access PCI config space.
The patch splits those functions used to access PCI config space
and implement them in platform related EEH component. It would be
helpful to support EEH on multiple platforms simutaneously in future.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index daaad91..d60f998 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -102,6 +102,8 @@
int (*wait_state)(struct device_node *dn, int max_wait);
int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len);
int (*configure_bridge)(struct device_node *dn);
+ int (*read_config)(struct device_node *dn, int where, int size, u32 *val);
+ int (*write_config)(struct device_node *dn, int where, int size, u32 val);
};
extern struct eeh_ops *eeh_ops;
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 1d08cd7..8011088 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -141,11 +141,11 @@
n += scnprintf(buf+n, len-n, "%s\n", dn->full_name);
printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name);
- rtas_read_config(PCI_DN(dn), PCI_VENDOR_ID, 4, &cfg);
+ eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg);
n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg);
- rtas_read_config(PCI_DN(dn), PCI_COMMAND, 4, &cfg);
+ eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg);
n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg);
@@ -156,11 +156,11 @@
/* Gather bridge-specific registers */
if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
- rtas_read_config(PCI_DN(dn), PCI_SEC_STATUS, 2, &cfg);
+ eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg);
n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg);
printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg);
- rtas_read_config(PCI_DN(dn), PCI_BRIDGE_CONTROL, 2, &cfg);
+ eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg);
n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg);
printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg);
}
@@ -168,11 +168,11 @@
/* Dump out the PCI-X command and status regs */
cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
if (cap) {
- rtas_read_config(PCI_DN(dn), cap, 4, &cfg);
+ eeh_ops->read_config(dn, cap, 4, &cfg);
n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg);
- rtas_read_config(PCI_DN(dn), cap+4, 4, &cfg);
+ eeh_ops->read_config(dn, cap+4, 4, &cfg);
n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);
}
@@ -185,7 +185,7 @@
"EEH: PCI-E capabilities and status follow:\n");
for (i=0; i<=8; i++) {
- rtas_read_config(PCI_DN(dn), cap+4*i, 4, &cfg);
+ eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
}
@@ -197,7 +197,7 @@
"EEH: PCI-E AER capability register set follows:\n");
for (i=0; i<14; i++) {
- rtas_read_config(PCI_DN(dn), cap+4*i, 4, &cfg);
+ eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);
}
@@ -746,28 +746,28 @@
return;
for (i=4; i<10; i++) {
- rtas_write_config(PCI_DN(dn), i*4, 4, edev->config_space[i]);
+ eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);
}
/* 12 == Expansion ROM Address */
- rtas_write_config(PCI_DN(dn), 12*4, 4, edev->config_space[12]);
+ eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]);
#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
- rtas_write_config(PCI_DN(dn), PCI_CACHE_LINE_SIZE, 1,
+ eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,
SAVED_BYTE(PCI_CACHE_LINE_SIZE));
- rtas_write_config(PCI_DN(dn), PCI_LATENCY_TIMER, 1,
+ eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1,
SAVED_BYTE(PCI_LATENCY_TIMER));
/* max latency, min grant, interrupt pin and line */
- rtas_write_config(PCI_DN(dn), 15*4, 4, edev->config_space[15]);
+ eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]);
/* Restore PERR & SERR bits, some devices require it,
* don't touch the other command bits
*/
- rtas_read_config(PCI_DN(dn), PCI_COMMAND, 4, &cmd);
+ eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd);
if (edev->config_space[1] & PCI_COMMAND_PARITY)
cmd |= PCI_COMMAND_PARITY;
else
@@ -776,7 +776,7 @@
cmd |= PCI_COMMAND_SERR;
else
cmd &= ~PCI_COMMAND_SERR;
- rtas_write_config(PCI_DN(dn), PCI_COMMAND, 4, cmd);
+ eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd);
}
/**
@@ -818,7 +818,7 @@
dn = eeh_dev_to_of_node(edev);
for (i = 0; i < 16; i++)
- rtas_read_config(PCI_DN(dn), i * 4, 4, &edev->config_space[i]);
+ eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]);
}
/**
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 36a1af1..8752f79 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -503,6 +503,42 @@
return ret;
}
+/**
+ * pseries_eeh_read_config - Read PCI config space
+ * @dn: device node
+ * @where: PCI address
+ * @size: size to read
+ * @val: return value
+ *
+ * Read config space from the speicifed device
+ */
+static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val)
+{
+ struct pci_dn *pdn;
+
+ pdn = PCI_DN(dn);
+
+ return rtas_read_config(pdn, where, size, val);
+}
+
+/**
+ * pseries_eeh_write_config - Write PCI config space
+ * @dn: device node
+ * @where: PCI address
+ * @size: size to write
+ * @val: value to be written
+ *
+ * Write config space to the specified device
+ */
+static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val)
+{
+ struct pci_dn *pdn;
+
+ pdn = PCI_DN(dn);
+
+ return rtas_write_config(pdn, where, size, val);
+}
+
static struct eeh_ops pseries_eeh_ops = {
.name = "pseries",
.init = pseries_eeh_init,
@@ -512,7 +548,9 @@
.reset = pseries_eeh_reset,
.wait_state = pseries_eeh_wait_state,
.get_log = pseries_eeh_get_log,
- .configure_bridge = pseries_eeh_configure_bridge
+ .configure_bridge = pseries_eeh_configure_bridge,
+ .read_config = pseries_eeh_read_config,
+ .write_config = pseries_eeh_write_config
};
/**