summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powernv/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powernv/pci.c')
-rw-r--r--arch/powerpc/platforms/powernv/pci.c120
1 files changed, 73 insertions, 47 deletions
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 4c91e6dd1af2..a28d3b5e6393 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -231,47 +231,50 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
spin_unlock_irqrestore(&phb->lock, flags);
}
-static void pnv_pci_config_check_eeh(struct pnv_phb *phb, struct pci_bus *bus,
- u32 bdfn)
+static void pnv_pci_config_check_eeh(struct pnv_phb *phb,
+ struct device_node *dn)
{
s64 rc;
u8 fstate;
u16 pcierr;
u32 pe_no;
- /* Get PE# if we support IODA */
- pe_no = phb->bdfn_to_pe ? phb->bdfn_to_pe(phb, bus, bdfn & 0xff) : 0;
+ /*
+ * Get the PE#. During the PCI probe stage, we might not
+ * setup that yet. So all ER errors should be mapped to
+ * PE#0
+ */
+ pe_no = PCI_DN(dn)->pe_number;
+ if (pe_no == IODA_INVALID_PE)
+ pe_no = 0;
/* Read freeze status */
rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, &fstate, &pcierr,
NULL);
if (rc) {
- pr_warning("PCI %d: Failed to read EEH status for PE#%d,"
- " err %lld\n", phb->hose->global_number, pe_no, rc);
+ pr_warning("%s: Can't read EEH status (PE#%d) for "
+ "%s, err %lld\n",
+ __func__, pe_no, dn->full_name, rc);
return;
}
- cfg_dbg(" -> EEH check, bdfn=%04x PE%d fstate=%x\n",
- bdfn, pe_no, fstate);
+ cfg_dbg(" -> EEH check, bdfn=%04x PE#%d fstate=%x\n",
+ (PCI_DN(dn)->busno << 8) | (PCI_DN(dn)->devfn),
+ pe_no, fstate);
if (fstate != 0)
pnv_pci_handle_eeh_config(phb, pe_no);
}
-static int pnv_pci_read_config(struct pci_bus *bus,
- unsigned int devfn,
- int where, int size, u32 *val)
+int pnv_pci_cfg_read(struct device_node *dn,
+ int where, int size, u32 *val)
{
- struct pci_controller *hose = pci_bus_to_host(bus);
- struct pnv_phb *phb = hose->private_data;
+ struct pci_dn *pdn = PCI_DN(dn);
+ struct pnv_phb *phb = pdn->phb->private_data;
+ u32 bdfn = (pdn->busno << 8) | pdn->devfn;
#ifdef CONFIG_EEH
- struct device_node *busdn, *dn;
struct eeh_pe *phb_pe = NULL;
#endif
- u32 bdfn = (((uint64_t)bus->number) << 8) | devfn;
s64 rc;
- if (hose == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
switch (size) {
case 1: {
u8 v8;
@@ -295,8 +298,8 @@ static int pnv_pci_read_config(struct pci_bus *bus,
default:
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
- cfg_dbg("pnv_pci_read_config bus: %x devfn: %x +%x/%x -> %08x\n",
- bus->number, devfn, where, size, *val);
+ cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n",
+ __func__, pdn->busno, pdn->devfn, where, size, *val);
/*
* Check if the specified PE has been put into frozen
@@ -305,44 +308,33 @@ static int pnv_pci_read_config(struct pci_bus *bus,
* PHB-fatal errors.
*/
#ifdef CONFIG_EEH
- phb_pe = eeh_phb_pe_get(hose);
+ phb_pe = eeh_phb_pe_get(pdn->phb);
if (phb_pe && (phb_pe->state & EEH_PE_ISOLATED))
return PCIBIOS_SUCCESSFUL;
if (phb->eeh_state & PNV_EEH_STATE_ENABLED) {
- if (*val == EEH_IO_ERROR_VALUE(size)) {
- busdn = pci_bus_to_OF_node(bus);
- for (dn = busdn->child; dn; dn = dn->sibling) {
- struct pci_dn *pdn = PCI_DN(dn);
-
- if (pdn && pdn->devfn == devfn &&
- eeh_dev_check_failure(of_node_to_eeh_dev(dn)))
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- }
+ if (*val == EEH_IO_ERROR_VALUE(size) &&
+ eeh_dev_check_failure(of_node_to_eeh_dev(dn)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
} else {
- pnv_pci_config_check_eeh(phb, bus, bdfn);
+ pnv_pci_config_check_eeh(phb, dn);
}
#else
- pnv_pci_config_check_eeh(phb, bus, bdfn);
+ pnv_pci_config_check_eeh(phb, dn);
#endif
return PCIBIOS_SUCCESSFUL;
}
-static int pnv_pci_write_config(struct pci_bus *bus,
- unsigned int devfn,
- int where, int size, u32 val)
+int pnv_pci_cfg_write(struct device_node *dn,
+ int where, int size, u32 val)
{
- struct pci_controller *hose = pci_bus_to_host(bus);
- struct pnv_phb *phb = hose->private_data;
- u32 bdfn = (((uint64_t)bus->number) << 8) | devfn;
+ struct pci_dn *pdn = PCI_DN(dn);
+ struct pnv_phb *phb = pdn->phb->private_data;
+ u32 bdfn = (pdn->busno << 8) | pdn->devfn;
- if (hose == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- cfg_dbg("pnv_pci_write_config bus: %x devfn: %x +%x/%x -> %08x\n",
- bus->number, devfn, where, size, val);
+ cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n",
+ pdn->busno, pdn->devfn, where, size, val);
switch (size) {
case 1:
opal_pci_config_write_byte(phb->opal_id, bdfn, where, val);
@@ -360,16 +352,50 @@ static int pnv_pci_write_config(struct pci_bus *bus,
/* Check if the PHB got frozen due to an error (no response) */
#ifdef CONFIG_EEH
if (!(phb->eeh_state & PNV_EEH_STATE_ENABLED))
- pnv_pci_config_check_eeh(phb, bus, bdfn);
+ pnv_pci_config_check_eeh(phb, dn);
#else
- pnv_pci_config_check_eeh(phb, bus, bdfn);
+ pnv_pci_config_check_eeh(phb, dn);
#endif
return PCIBIOS_SUCCESSFUL;
}
+static int pnv_pci_read_config(struct pci_bus *bus,
+ unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ struct device_node *dn, *busdn = pci_bus_to_OF_node(bus);
+ struct pci_dn *pdn;
+
+ for (dn = busdn->child; dn; dn = dn->sibling) {
+ pdn = PCI_DN(dn);
+ if (pdn && pdn->devfn == devfn)
+ return pnv_pci_cfg_read(dn, where, size, val);
+ }
+
+ *val = 0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+}
+
+static int pnv_pci_write_config(struct pci_bus *bus,
+ unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct device_node *dn, *busdn = pci_bus_to_OF_node(bus);
+ struct pci_dn *pdn;
+
+ for (dn = busdn->child; dn; dn = dn->sibling) {
+ pdn = PCI_DN(dn);
+ if (pdn && pdn->devfn == devfn)
+ return pnv_pci_cfg_write(dn, where, size, val);
+ }
+
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
struct pci_ops pnv_pci_ops = {
- .read = pnv_pci_read_config,
+ .read = pnv_pci_read_config,
.write = pnv_pci_write_config,
};
OpenPOWER on IntegriCloud