提交 ff57b454 编写于 作者: G Gavin Shan 提交者: Benjamin Herrenschmidt

powerpc/eeh: Do probe on pci_dn

Originally, EEH core probes on device_node or pci_dev to populate
EEH devices and PEs, which conflicts with the fact: SRIOV VFs are
usually enabled and created by PF's driver and they don't have the
corresponding device_nodes. Instead, SRIOV VFs have dynamically
created pci_dn, which can be used for EEH probe.

The patch reworks EEH probe for PowerNV and pSeries platforms to
do probing based on pci_dn, instead of pci_dev or device_node any
more.
Signed-off-by: NGavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: NBenjamin Herrenschmidt <benh@kernel.crashing.org>
上级 e8e9b34c
...@@ -207,8 +207,7 @@ struct eeh_ops { ...@@ -207,8 +207,7 @@ struct eeh_ops {
char *name; char *name;
int (*init)(void); int (*init)(void);
int (*post_init)(void); int (*post_init)(void);
void* (*of_probe)(struct device_node *dn, void *flag); void* (*probe)(struct pci_dn *pdn, void *data);
int (*dev_probe)(struct pci_dev *dev, void *flag);
int (*set_option)(struct eeh_pe *pe, int option); int (*set_option)(struct eeh_pe *pe, int option);
int (*get_pe_addr)(struct eeh_pe *pe); int (*get_pe_addr)(struct eeh_pe *pe);
int (*get_state)(struct eeh_pe *pe, int *state); int (*get_state)(struct eeh_pe *pe, int *state);
...@@ -287,8 +286,8 @@ int __exit eeh_ops_unregister(const char *name); ...@@ -287,8 +286,8 @@ int __exit eeh_ops_unregister(const char *name);
int eeh_check_failure(const volatile void __iomem *token); int eeh_check_failure(const volatile void __iomem *token);
int eeh_dev_check_failure(struct eeh_dev *edev); int eeh_dev_check_failure(struct eeh_dev *edev);
void eeh_addr_cache_build(void); void eeh_addr_cache_build(void);
void eeh_add_device_early(struct device_node *); void eeh_add_device_early(struct pci_dn *);
void eeh_add_device_tree_early(struct device_node *); void eeh_add_device_tree_early(struct pci_dn *);
void eeh_add_device_late(struct pci_dev *); void eeh_add_device_late(struct pci_dev *);
void eeh_add_device_tree_late(struct pci_bus *); void eeh_add_device_tree_late(struct pci_bus *);
void eeh_add_sysfs_files(struct pci_bus *); void eeh_add_sysfs_files(struct pci_bus *);
...@@ -346,9 +345,9 @@ static inline int eeh_check_failure(const volatile void __iomem *token) ...@@ -346,9 +345,9 @@ static inline int eeh_check_failure(const volatile void __iomem *token)
static inline void eeh_addr_cache_build(void) { } static inline void eeh_addr_cache_build(void) { }
static inline void eeh_add_device_early(struct device_node *dn) { } static inline void eeh_add_device_early(struct pci_dn *pdn) { }
static inline void eeh_add_device_tree_early(struct device_node *dn) { } static inline void eeh_add_device_tree_early(struct pci_dn *pdn) { }
static inline void eeh_add_device_late(struct pci_dev *dev) { } static inline void eeh_add_device_late(struct pci_dev *dev) { }
......
...@@ -969,7 +969,7 @@ static struct notifier_block eeh_reboot_nb = { ...@@ -969,7 +969,7 @@ static struct notifier_block eeh_reboot_nb = {
int eeh_init(void) int eeh_init(void)
{ {
struct pci_controller *hose, *tmp; struct pci_controller *hose, *tmp;
struct device_node *phb; struct pci_dn *pdn;
static int cnt = 0; static int cnt = 0;
int ret = 0; int ret = 0;
...@@ -1004,20 +1004,9 @@ int eeh_init(void) ...@@ -1004,20 +1004,9 @@ int eeh_init(void)
return ret; return ret;
/* Enable EEH for all adapters */ /* Enable EEH for all adapters */
if (eeh_has_flag(EEH_PROBE_MODE_DEVTREE)) { list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
list_for_each_entry_safe(hose, tmp, pdn = hose->pci_data;
&hose_list, list_node) { traverse_pci_dn(pdn, eeh_ops->probe, NULL);
phb = hose->dn;
traverse_pci_devices(phb, eeh_ops->of_probe, NULL);
}
} else if (eeh_has_flag(EEH_PROBE_MODE_DEV)) {
list_for_each_entry_safe(hose, tmp,
&hose_list, list_node)
pci_walk_bus(hose->bus, eeh_ops->dev_probe, NULL);
} else {
pr_warn("%s: Invalid probe mode %x",
__func__, eeh_subsystem_flags);
return -EINVAL;
} }
/* /*
...@@ -1043,7 +1032,7 @@ core_initcall_sync(eeh_init); ...@@ -1043,7 +1032,7 @@ core_initcall_sync(eeh_init);
/** /**
* eeh_add_device_early - Enable EEH for the indicated device_node * eeh_add_device_early - Enable EEH for the indicated device_node
* @dn: device node for which to set up EEH * @pdn: PCI device node for which to set up EEH
* *
* This routine must be used to perform EEH initialization for PCI * This routine must be used to perform EEH initialization for PCI
* devices that were added after system boot (e.g. hotplug, dlpar). * devices that were added after system boot (e.g. hotplug, dlpar).
...@@ -1053,44 +1042,41 @@ core_initcall_sync(eeh_init); ...@@ -1053,44 +1042,41 @@ core_initcall_sync(eeh_init);
* on the CEC architecture, type of the device, on earlier boot * on the CEC architecture, type of the device, on earlier boot
* command-line arguments & etc. * command-line arguments & etc.
*/ */
void eeh_add_device_early(struct device_node *dn) void eeh_add_device_early(struct pci_dn *pdn)
{ {
struct pci_controller *phb; struct pci_controller *phb;
struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
/* if (!edev)
* If we're doing EEH probe based on PCI device, we
* would delay the probe until late stage because
* the PCI device isn't available this moment.
*/
if (!eeh_has_flag(EEH_PROBE_MODE_DEVTREE))
return;
if (!of_node_to_eeh_dev(dn))
return; return;
phb = of_node_to_eeh_dev(dn)->phb;
/* USB Bus children of PCI devices will not have BUID's */ /* USB Bus children of PCI devices will not have BUID's */
if (NULL == phb || 0 == phb->buid) phb = edev->phb;
if (NULL == phb ||
(eeh_has_flag(EEH_PROBE_MODE_DEVTREE) && 0 == phb->buid))
return; return;
eeh_ops->of_probe(dn, NULL); eeh_ops->probe(pdn, NULL);
} }
/** /**
* eeh_add_device_tree_early - Enable EEH for the indicated device * eeh_add_device_tree_early - Enable EEH for the indicated device
* @dn: device node * @pdn: PCI device node
* *
* This routine must be used to perform EEH initialization for the * This routine must be used to perform EEH initialization for the
* indicated PCI device that was added after system boot (e.g. * indicated PCI device that was added after system boot (e.g.
* hotplug, dlpar). * hotplug, dlpar).
*/ */
void eeh_add_device_tree_early(struct device_node *dn) void eeh_add_device_tree_early(struct pci_dn *pdn)
{ {
struct device_node *sib; struct pci_dn *n;
if (!pdn)
return;
for_each_child_of_node(dn, sib) list_for_each_entry(n, &pdn->child_list, list)
eeh_add_device_tree_early(sib); eeh_add_device_tree_early(n);
eeh_add_device_early(dn); eeh_add_device_early(pdn);
} }
EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
...@@ -1144,13 +1130,6 @@ void eeh_add_device_late(struct pci_dev *dev) ...@@ -1144,13 +1130,6 @@ void eeh_add_device_late(struct pci_dev *dev)
edev->pdev = dev; edev->pdev = dev;
dev->dev.archdata.edev = edev; dev->dev.archdata.edev = edev;
/*
* We have to do the EEH probe here because the PCI device
* hasn't been created yet in the early stage.
*/
if (eeh_has_flag(EEH_PROBE_MODE_DEV))
eeh_ops->dev_probe(dev, NULL);
eeh_addr_cache_insert_dev(dev); eeh_addr_cache_insert_dev(dev);
} }
......
...@@ -72,7 +72,7 @@ static int of_pci_phb_probe(struct platform_device *dev) ...@@ -72,7 +72,7 @@ static int of_pci_phb_probe(struct platform_device *dev)
/* Register devices with EEH */ /* Register devices with EEH */
if (dev->dev.of_node->child) if (dev->dev.of_node->child)
eeh_add_device_tree_early(dev->dev.of_node); eeh_add_device_tree_early(PCI_DN(dev->dev.of_node));
/* Scan the bus */ /* Scan the bus */
pcibios_scan_phb(phb); pcibios_scan_phb(phb);
......
...@@ -75,7 +75,7 @@ void pcibios_add_pci_devices(struct pci_bus * bus) ...@@ -75,7 +75,7 @@ void pcibios_add_pci_devices(struct pci_bus * bus)
struct pci_dev *dev; struct pci_dev *dev;
struct device_node *dn = pci_bus_to_OF_node(bus); struct device_node *dn = pci_bus_to_OF_node(bus);
eeh_add_device_tree_early(dn); eeh_add_device_tree_early(PCI_DN(dn));
mode = PCI_PROBE_NORMAL; mode = PCI_PROBE_NORMAL;
if (ppc_md.pci_probe_mode) if (ppc_md.pci_probe_mode)
......
...@@ -286,10 +286,82 @@ static int pnv_eeh_post_init(void) ...@@ -286,10 +286,82 @@ static int pnv_eeh_post_init(void)
return ret; return ret;
} }
static int pnv_eeh_cap_start(struct pci_dn *pdn)
{
u32 status;
if (!pdn)
return 0;
pnv_pci_cfg_read(pdn, PCI_STATUS, 2, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
return PCI_CAPABILITY_LIST;
}
static int pnv_eeh_find_cap(struct pci_dn *pdn, int cap)
{
int pos = pnv_eeh_cap_start(pdn);
int cnt = 48; /* Maximal number of capabilities */
u32 id;
if (!pos)
return 0;
while (cnt--) {
pnv_pci_cfg_read(pdn, pos, 1, &pos);
if (pos < 0x40)
break;
pos &= ~3;
pnv_pci_cfg_read(pdn, pos + PCI_CAP_LIST_ID, 1, &id);
if (id == 0xff)
break;
/* Found */
if (id == cap)
return pos;
/* Next one */
pos += PCI_CAP_LIST_NEXT;
}
return 0;
}
static int pnv_eeh_find_ecap(struct pci_dn *pdn, int cap)
{
struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
u32 header;
int pos = 256, ttl = (4096 - 256) / 8;
if (!edev || !edev->pcie_cap)
return 0;
if (pnv_pci_cfg_read(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL)
return 0;
else if (!header)
return 0;
while (ttl-- > 0) {
if (PCI_EXT_CAP_ID(header) == cap && pos)
return pos;
pos = PCI_EXT_CAP_NEXT(header);
if (pos < 256)
break;
if (pnv_pci_cfg_read(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL)
break;
}
return 0;
}
/** /**
* pnv_eeh_dev_probe - Do probe on PCI device * pnv_eeh_probe - Do probe on PCI device
* @dev: PCI device * @pdn: PCI device node
* @flag: unused * @data: unused
* *
* When EEH module is installed during system boot, all PCI devices * When EEH module is installed during system boot, all PCI devices
* are checked one by one to see if it supports EEH. The function * are checked one by one to see if it supports EEH. The function
...@@ -303,12 +375,12 @@ static int pnv_eeh_post_init(void) ...@@ -303,12 +375,12 @@ static int pnv_eeh_post_init(void)
* was possiblly triggered by EEH core, the binding between EEH device * was possiblly triggered by EEH core, the binding between EEH device
* and the PCI device isn't built yet. * and the PCI device isn't built yet.
*/ */
static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag) static void *pnv_eeh_probe(struct pci_dn *pdn, void *data)
{ {
struct pci_controller *hose = pci_bus_to_host(dev->bus); struct pci_controller *hose = pdn->phb;
struct pnv_phb *phb = hose->private_data; struct pnv_phb *phb = hose->private_data;
struct device_node *dn = pci_device_to_OF_node(dev); struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
struct eeh_dev *edev = of_node_to_eeh_dev(dn); uint32_t pcie_flags;
int ret; int ret;
/* /*
...@@ -317,40 +389,42 @@ static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag) ...@@ -317,40 +389,42 @@ static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag)
* the root bridge. So it's not reasonable to continue * the root bridge. So it's not reasonable to continue
* the probing. * the probing.
*/ */
if (!dn || !edev || edev->pe) if (!edev || edev->pe)
return 0; return NULL;
/* Skip for PCI-ISA bridge */ /* Skip for PCI-ISA bridge */
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA) if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA)
return 0; return NULL;
/* Initialize eeh device */ /* Initialize eeh device */
edev->class_code = dev->class; edev->class_code = pdn->class_code;
edev->mode &= 0xFFFFFF00; edev->mode &= 0xFFFFFF00;
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) edev->pcix_cap = pnv_eeh_find_cap(pdn, PCI_CAP_ID_PCIX);
edev->pcie_cap = pnv_eeh_find_cap(pdn, PCI_CAP_ID_EXP);
edev->aer_cap = pnv_eeh_find_ecap(pdn, PCI_EXT_CAP_ID_ERR);
if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) {
edev->mode |= EEH_DEV_BRIDGE; edev->mode |= EEH_DEV_BRIDGE;
edev->pcix_cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (edev->pcie_cap) {
if (pci_is_pcie(dev)) { pnv_pci_cfg_read(pdn, edev->pcie_cap + PCI_EXP_FLAGS,
edev->pcie_cap = pci_pcie_cap(dev); 2, &pcie_flags);
pcie_flags = (pcie_flags & PCI_EXP_FLAGS_TYPE) >> 4;
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) if (pcie_flags == PCI_EXP_TYPE_ROOT_PORT)
edev->mode |= EEH_DEV_ROOT_PORT; edev->mode |= EEH_DEV_ROOT_PORT;
else if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) else if (pcie_flags == PCI_EXP_TYPE_DOWNSTREAM)
edev->mode |= EEH_DEV_DS_PORT; edev->mode |= EEH_DEV_DS_PORT;
}
edev->aer_cap = pci_find_ext_capability(dev,
PCI_EXT_CAP_ID_ERR);
} }
edev->config_addr = ((dev->bus->number << 8) | dev->devfn); edev->config_addr = (pdn->busno << 8) | (pdn->devfn);
edev->pe_config_addr = phb->bdfn_to_pe(phb, dev->bus, dev->devfn & 0xff); edev->pe_config_addr = phb->ioda.pe_rmap[edev->config_addr];
/* Create PE */ /* Create PE */
ret = eeh_add_to_parent_pe(edev); ret = eeh_add_to_parent_pe(edev);
if (ret) { if (ret) {
pr_warn("%s: Can't add PCI dev %s to parent PE (%d)\n", pr_warn("%s: Can't add PCI dev %04x:%02x:%02x.%01x to parent PE (%d)\n",
__func__, pci_name(dev), ret); __func__, hose->global_number, pdn->busno,
return ret; PCI_SLOT(pdn->devfn), PCI_FUNC(pdn->devfn), ret);
return NULL;
} }
/* /*
...@@ -369,8 +443,10 @@ static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag) ...@@ -369,8 +443,10 @@ static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag)
* Broadcom Austin 4-ports NICs (14e4:1657) * Broadcom Austin 4-ports NICs (14e4:1657)
* Broadcom Shiner 2-ports 10G NICs (14e4:168e) * Broadcom Shiner 2-ports 10G NICs (14e4:168e)
*/ */
if ((dev->vendor == PCI_VENDOR_ID_BROADCOM && dev->device == 0x1657) || if ((pdn->vendor_id == PCI_VENDOR_ID_BROADCOM &&
(dev->vendor == PCI_VENDOR_ID_BROADCOM && dev->device == 0x168e)) pdn->device_id == 0x1657) ||
(pdn->vendor_id == PCI_VENDOR_ID_BROADCOM &&
pdn->device_id == 0x168e))
edev->pe->state |= EEH_PE_CFG_RESTRICTED; edev->pe->state |= EEH_PE_CFG_RESTRICTED;
/* /*
...@@ -380,7 +456,8 @@ static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag) ...@@ -380,7 +456,8 @@ static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag)
* to PE reset. * to PE reset.
*/ */
if (!edev->pe->bus) if (!edev->pe->bus)
edev->pe->bus = dev->bus; edev->pe->bus = pci_find_bus(hose->global_number,
pdn->busno);
/* /*
* Enable EEH explicitly so that we will do EEH check * Enable EEH explicitly so that we will do EEH check
...@@ -391,7 +468,7 @@ static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag) ...@@ -391,7 +468,7 @@ static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag)
/* Save memory bars */ /* Save memory bars */
eeh_save_bars(edev); eeh_save_bars(edev);
return 0; return NULL;
} }
/** /**
...@@ -1432,8 +1509,7 @@ static struct eeh_ops pnv_eeh_ops = { ...@@ -1432,8 +1509,7 @@ static struct eeh_ops pnv_eeh_ops = {
.name = "powernv", .name = "powernv",
.init = pnv_eeh_init, .init = pnv_eeh_init,
.post_init = pnv_eeh_post_init, .post_init = pnv_eeh_post_init,
.of_probe = NULL, .probe = pnv_eeh_probe,
.dev_probe = pnv_eeh_dev_probe,
.set_option = pnv_eeh_set_option, .set_option = pnv_eeh_set_option,
.get_pe_addr = pnv_eeh_get_pe_addr, .get_pe_addr = pnv_eeh_get_pe_addr,
.get_state = pnv_eeh_get_state, .get_state = pnv_eeh_get_state,
......
...@@ -118,9 +118,8 @@ static int pseries_eeh_init(void) ...@@ -118,9 +118,8 @@ static int pseries_eeh_init(void)
return 0; return 0;
} }
static int pseries_eeh_cap_start(struct device_node *dn) static int pseries_eeh_cap_start(struct pci_dn *pdn)
{ {
struct pci_dn *pdn = PCI_DN(dn);
u32 status; u32 status;
if (!pdn) if (!pdn)
...@@ -134,10 +133,9 @@ static int pseries_eeh_cap_start(struct device_node *dn) ...@@ -134,10 +133,9 @@ static int pseries_eeh_cap_start(struct device_node *dn)
} }
static int pseries_eeh_find_cap(struct device_node *dn, int cap) static int pseries_eeh_find_cap(struct pci_dn *pdn, int cap)
{ {
struct pci_dn *pdn = PCI_DN(dn); int pos = pseries_eeh_cap_start(pdn);
int pos = pseries_eeh_cap_start(dn);
int cnt = 48; /* Maximal number of capabilities */ int cnt = 48; /* Maximal number of capabilities */
u32 id; u32 id;
...@@ -160,10 +158,9 @@ static int pseries_eeh_find_cap(struct device_node *dn, int cap) ...@@ -160,10 +158,9 @@ static int pseries_eeh_find_cap(struct device_node *dn, int cap)
return 0; return 0;
} }
static int pseries_eeh_find_ecap(struct device_node *dn, int cap) static int pseries_eeh_find_ecap(struct pci_dn *pdn, int cap)
{ {
struct pci_dn *pdn = PCI_DN(dn); struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
struct eeh_dev *edev = of_node_to_eeh_dev(dn);
u32 header; u32 header;
int pos = 256; int pos = 256;
int ttl = (4096 - 256) / 8; int ttl = (4096 - 256) / 8;
...@@ -191,53 +188,44 @@ static int pseries_eeh_find_ecap(struct device_node *dn, int cap) ...@@ -191,53 +188,44 @@ static int pseries_eeh_find_ecap(struct device_node *dn, int cap)
} }
/** /**
* pseries_eeh_of_probe - EEH probe on the given device * pseries_eeh_probe - EEH probe on the given device
* @dn: OF node * @pdn: PCI device node
* @flag: Unused * @data: Unused
* *
* When EEH module is installed during system boot, all PCI devices * When EEH module is installed during system boot, all PCI devices
* are checked one by one to see if it supports EEH. The function * are checked one by one to see if it supports EEH. The function
* is introduced for the purpose. * is introduced for the purpose.
*/ */
static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) static void *pseries_eeh_probe(struct pci_dn *pdn, void *data)
{ {
struct eeh_dev *edev; struct eeh_dev *edev;
struct eeh_pe pe; struct eeh_pe pe;
struct pci_dn *pdn = PCI_DN(dn);
const __be32 *classp, *vendorp, *devicep;
u32 class_code;
const __be32 *regs;
u32 pcie_flags; u32 pcie_flags;
int enable = 0; int enable = 0;
int ret; int ret;
/* Retrieve OF node and eeh device */ /* Retrieve OF node and eeh device */
edev = of_node_to_eeh_dev(dn); edev = pdn_to_eeh_dev(pdn);
if (edev->pe || !of_device_is_available(dn)) if (!edev || edev->pe)
return NULL; return NULL;
/* Retrieve class/vendor/device IDs */ /* Check class/vendor/device IDs */
classp = of_get_property(dn, "class-code", NULL); if (!pdn->vendor_id || !pdn->device_id || !pdn->class_code)
vendorp = of_get_property(dn, "vendor-id", NULL);
devicep = of_get_property(dn, "device-id", NULL);
/* Skip for bad OF node or PCI-ISA bridge */
if (!classp || !vendorp || !devicep)
return NULL;
if (dn->type && !strcmp(dn->type, "isa"))
return NULL; return NULL;
class_code = of_read_number(classp, 1); /* Skip for PCI-ISA bridge */
if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA)
return NULL;
/* /*
* Update class code and mode of eeh device. We need * Update class code and mode of eeh device. We need
* correctly reflects that current device is root port * correctly reflects that current device is root port
* or PCIe switch downstream port. * or PCIe switch downstream port.
*/ */
edev->class_code = class_code; edev->class_code = pdn->class_code;
edev->pcix_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_PCIX); edev->pcix_cap = pseries_eeh_find_cap(pdn, PCI_CAP_ID_PCIX);
edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP); edev->pcie_cap = pseries_eeh_find_cap(pdn, PCI_CAP_ID_EXP);
edev->aer_cap = pseries_eeh_find_ecap(dn, PCI_EXT_CAP_ID_ERR); edev->aer_cap = pseries_eeh_find_ecap(pdn, PCI_EXT_CAP_ID_ERR);
edev->mode &= 0xFFFFFF00; edev->mode &= 0xFFFFFF00;
if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) { if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) {
edev->mode |= EEH_DEV_BRIDGE; edev->mode |= EEH_DEV_BRIDGE;
...@@ -252,24 +240,16 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) ...@@ -252,24 +240,16 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
} }
} }
/* Retrieve the device address */
regs = of_get_property(dn, "reg", NULL);
if (!regs) {
pr_warn("%s: OF node property %s::reg not found\n",
__func__, dn->full_name);
return NULL;
}
/* Initialize the fake PE */ /* Initialize the fake PE */
memset(&pe, 0, sizeof(struct eeh_pe)); memset(&pe, 0, sizeof(struct eeh_pe));
pe.phb = edev->phb; pe.phb = edev->phb;
pe.config_addr = of_read_number(regs, 1); pe.config_addr = (pdn->busno << 16) | (pdn->devfn << 8);
/* Enable EEH on the device */ /* Enable EEH on the device */
ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE); ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE);
if (!ret) { if (!ret) {
edev->config_addr = of_read_number(regs, 1);
/* Retrieve PE address */ /* Retrieve PE address */
edev->config_addr = (pdn->busno << 16) | (pdn->devfn << 8);
edev->pe_config_addr = eeh_ops->get_pe_addr(&pe); edev->pe_config_addr = eeh_ops->get_pe_addr(&pe);
pe.addr = edev->pe_config_addr; pe.addr = edev->pe_config_addr;
...@@ -285,16 +265,17 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) ...@@ -285,16 +265,17 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
eeh_add_flag(EEH_ENABLED); eeh_add_flag(EEH_ENABLED);
eeh_add_to_parent_pe(edev); eeh_add_to_parent_pe(edev);
pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n", pr_debug("%s: EEH enabled on %02x:%02x.%01x PHB#%d-PE#%x\n",
__func__, dn->full_name, pe.phb->global_number, __func__, pdn->busno, PCI_SLOT(pdn->devfn),
pe.addr, pe.config_addr); PCI_FUNC(pdn->devfn), pe.phb->global_number,
} else if (dn->parent && of_node_to_eeh_dev(dn->parent) && pe.addr);
(of_node_to_eeh_dev(dn->parent))->pe) { } else if (pdn->parent && pdn_to_eeh_dev(pdn->parent) &&
(pdn_to_eeh_dev(pdn->parent))->pe) {
/* This device doesn't support EEH, but it may have an /* This device doesn't support EEH, but it may have an
* EEH parent, in which case we mark it as supported. * EEH parent, in which case we mark it as supported.
*/ */
edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr; edev->config_addr = pdn_to_eeh_dev(pdn->parent)->config_addr;
edev->pe_config_addr = of_node_to_eeh_dev(dn->parent)->pe_config_addr; edev->pe_config_addr = pdn_to_eeh_dev(pdn->parent)->pe_config_addr;
eeh_add_to_parent_pe(edev); eeh_add_to_parent_pe(edev);
} }
} }
...@@ -707,8 +688,7 @@ static int pseries_eeh_write_config(struct device_node *dn, int where, int size, ...@@ -707,8 +688,7 @@ static int pseries_eeh_write_config(struct device_node *dn, int where, int size,
static struct eeh_ops pseries_eeh_ops = { static struct eeh_ops pseries_eeh_ops = {
.name = "pseries", .name = "pseries",
.init = pseries_eeh_init, .init = pseries_eeh_init,
.of_probe = pseries_eeh_of_probe, .probe = pseries_eeh_probe,
.dev_probe = NULL,
.set_option = pseries_eeh_set_option, .set_option = pseries_eeh_set_option,
.get_pe_addr = pseries_eeh_get_pe_addr, .get_pe_addr = pseries_eeh_get_pe_addr,
.get_state = pseries_eeh_get_state, .get_state = pseries_eeh_get_state,
......
...@@ -82,7 +82,7 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn) ...@@ -82,7 +82,7 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn)
eeh_dev_phb_init_dynamic(phb); eeh_dev_phb_init_dynamic(phb);
if (dn->child) if (dn->child)
eeh_add_device_tree_early(dn); eeh_add_device_tree_early(PCI_DN(dn));
pcibios_scan_phb(phb); pcibios_scan_phb(phb);
pcibios_finish_adding_to_bus(phb->bus); pcibios_finish_adding_to_bus(phb->bus);
......
...@@ -146,7 +146,7 @@ static void dlpar_pci_add_bus(struct device_node *dn) ...@@ -146,7 +146,7 @@ static void dlpar_pci_add_bus(struct device_node *dn)
struct pci_controller *phb = pdn->phb; struct pci_controller *phb = pdn->phb;
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
eeh_add_device_tree_early(dn); eeh_add_device_tree_early(pdn);
/* Add EADS device to PHB bus, adding new entry to bus->devices */ /* Add EADS device to PHB bus, adding new entry to bus->devices */
dev = of_create_pci_dev(dn, phb->bus, pdn->devfn); dev = of_create_pci_dev(dn, phb->bus, pdn->devfn);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册