Skip to content

Commit e86350f

Browse files
oohalmpe
authored andcommitted
powerpc/eeh: Rework eeh_ops->probe()
With the EEH early probe now being pseries specific there's no need for eeh_ops->probe() to take a pci_dn. Instead, we can make it take a pci_dev and use the probe function to map a pci_dev to an eeh_dev. This allows the platform to implement it's own method for finding (or creating) an eeh_dev for a given pci_dev which also removes a use of pci_dn in generic EEH code. This patch also renames eeh_device_add_late() to eeh_device_probe(). This better reflects what it does does and removes the last vestiges of the early/late EEH probe split. Reviewed-by: Sam Bobroff <[email protected]> Signed-off-by: Oliver O'Halloran <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b6eebb0 commit e86350f

File tree

4 files changed

+62
-41
lines changed

4 files changed

+62
-41
lines changed

arch/powerpc/include/asm/eeh.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ enum {
215215
struct eeh_ops {
216216
char *name;
217217
int (*init)(void);
218-
void* (*probe)(struct pci_dn *pdn, void *data);
218+
struct eeh_dev *(*probe)(struct pci_dev *pdev);
219219
int (*set_option)(struct eeh_pe *pe, int option);
220220
int (*get_pe_addr)(struct eeh_pe *pe);
221221
int (*get_state)(struct eeh_pe *pe, int *delay);
@@ -301,7 +301,7 @@ int __exit eeh_ops_unregister(const char *name);
301301
int eeh_check_failure(const volatile void __iomem *token);
302302
int eeh_dev_check_failure(struct eeh_dev *edev);
303303
void eeh_addr_cache_init(void);
304-
void eeh_add_device_late(struct pci_dev *);
304+
void eeh_probe_device(struct pci_dev *pdev);
305305
void eeh_remove_device(struct pci_dev *);
306306
int eeh_unfreeze_pe(struct eeh_pe *pe);
307307
int eeh_pe_reset_and_recover(struct eeh_pe *pe);
@@ -356,7 +356,7 @@ static inline int eeh_check_failure(const volatile void __iomem *token)
356356

357357
static inline void eeh_addr_cache_init(void) { }
358358

359-
static inline void eeh_add_device_late(struct pci_dev *dev) { }
359+
static inline void eeh_probe_device(struct pci_dev *dev) { }
360360

361361
static inline void eeh_remove_device(struct pci_dev *dev) { }
362362

arch/powerpc/kernel/eeh.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,35 +1107,43 @@ static int eeh_init(void)
11071107
core_initcall_sync(eeh_init);
11081108

11091109
/**
1110-
* eeh_add_device_late - Perform EEH initialization for the indicated pci device
1110+
* eeh_probe_device() - Perform EEH initialization for the indicated pci device
11111111
* @dev: pci device for which to set up EEH
11121112
*
11131113
* This routine must be used to complete EEH initialization for PCI
11141114
* devices that were added after system boot (e.g. hotplug, dlpar).
11151115
*/
1116-
void eeh_add_device_late(struct pci_dev *dev)
1116+
void eeh_probe_device(struct pci_dev *dev)
11171117
{
1118-
struct pci_dn *pdn;
11191118
struct eeh_dev *edev;
11201119

1121-
if (!dev)
1120+
pr_debug("EEH: Adding device %s\n", pci_name(dev));
1121+
1122+
/*
1123+
* pci_dev_to_eeh_dev() can only work if eeh_probe_dev() was
1124+
* already called for this device.
1125+
*/
1126+
if (WARN_ON_ONCE(pci_dev_to_eeh_dev(dev))) {
1127+
pci_dbg(dev, "Already bound to an eeh_dev!\n");
11221128
return;
1129+
}
11231130

1124-
pdn = pci_get_pdn_by_devfn(dev->bus, dev->devfn);
1125-
edev = pdn_to_eeh_dev(pdn);
1126-
eeh_edev_dbg(edev, "Adding device\n");
1127-
if (edev->pdev == dev) {
1128-
eeh_edev_dbg(edev, "Device already referenced!\n");
1131+
edev = eeh_ops->probe(dev);
1132+
if (!edev) {
1133+
pr_debug("EEH: Adding device failed\n");
11291134
return;
11301135
}
11311136

11321137
/*
1133-
* The EEH cache might not be removed correctly because of
1134-
* unbalanced kref to the device during unplug time, which
1135-
* relies on pcibios_release_device(). So we have to remove
1136-
* that here explicitly.
1138+
* FIXME: We rely on pcibios_release_device() to remove the
1139+
* existing EEH state. The release function is only called if
1140+
* the pci_dev's refcount drops to zero so if something is
1141+
* keeping a ref to a device (e.g. a filesystem) we need to
1142+
* remove the old EEH state.
1143+
*
1144+
* FIXME: HEY MA, LOOK AT ME, NO LOCKING!
11371145
*/
1138-
if (edev->pdev) {
1146+
if (edev->pdev && edev->pdev != dev) {
11391147
eeh_rmv_from_parent_pe(edev);
11401148
eeh_addr_cache_rmv_dev(edev->pdev);
11411149
eeh_sysfs_remove_device(edev->pdev);
@@ -1146,17 +1154,11 @@ void eeh_add_device_late(struct pci_dev *dev)
11461154
* into error handler afterwards.
11471155
*/
11481156
edev->mode |= EEH_DEV_NO_HANDLER;
1149-
1150-
edev->pdev = NULL;
1151-
dev->dev.archdata.edev = NULL;
11521157
}
11531158

1154-
if (eeh_has_flag(EEH_PROBE_MODE_DEV))
1155-
eeh_ops->probe(pdn, NULL);
1156-
1159+
/* bind the pdev and the edev together */
11571160
edev->pdev = dev;
11581161
dev->dev.archdata.edev = edev;
1159-
11601162
eeh_addr_cache_insert_dev(dev);
11611163
eeh_sysfs_add_device(dev);
11621164
}

arch/powerpc/platforms/powernv/eeh-powernv.c

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static int eeh_event_irq = -EINVAL;
4141
void pnv_pcibios_bus_add_device(struct pci_dev *pdev)
4242
{
4343
dev_dbg(&pdev->dev, "EEH: Setting up device\n");
44-
eeh_add_device_late(pdev);
44+
eeh_probe_device(pdev);
4545
}
4646

4747
static int pnv_eeh_init(void)
@@ -340,23 +340,13 @@ static int pnv_eeh_find_ecap(struct pci_dn *pdn, int cap)
340340

341341
/**
342342
* pnv_eeh_probe - Do probe on PCI device
343-
* @pdn: PCI device node
344-
* @data: unused
343+
* @pdev: pci_dev to probe
345344
*
346-
* When EEH module is installed during system boot, all PCI devices
347-
* are checked one by one to see if it supports EEH. The function
348-
* is introduced for the purpose. By default, EEH has been enabled
349-
* on all PCI devices. That's to say, we only need do necessary
350-
* initialization on the corresponding eeh device and create PE
351-
* accordingly.
352-
*
353-
* It's notable that's unsafe to retrieve the EEH device through
354-
* the corresponding PCI device. During the PCI device hotplug, which
355-
* was possiblly triggered by EEH core, the binding between EEH device
356-
* and the PCI device isn't built yet.
345+
* Create, or find the existing, eeh_dev for this pci_dev.
357346
*/
358-
static void *pnv_eeh_probe(struct pci_dn *pdn, void *data)
347+
static struct eeh_dev *pnv_eeh_probe(struct pci_dev *pdev)
359348
{
349+
struct pci_dn *pdn = pci_get_pdn(pdev);
360350
struct pci_controller *hose = pdn->phb;
361351
struct pnv_phb *phb = hose->private_data;
362352
struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
@@ -373,6 +363,14 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data)
373363
if (!edev || edev->pe)
374364
return NULL;
375365

366+
/* already configured? */
367+
if (edev->pdev) {
368+
pr_debug("%s: found existing edev for %04x:%02x:%02x.%01x\n",
369+
__func__, hose->global_number, config_addr >> 8,
370+
PCI_SLOT(config_addr), PCI_FUNC(config_addr));
371+
return edev;
372+
}
373+
376374
/* Skip for PCI-ISA bridge */
377375
if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA)
378376
return NULL;
@@ -464,7 +462,7 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data)
464462

465463
eeh_edev_dbg(edev, "EEH enabled on device\n");
466464

467-
return NULL;
465+
return edev;
468466
}
469467

470468
/**

arch/powerpc/platforms/pseries/eeh_pseries.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ void pseries_pcibios_bus_add_device(struct pci_dev *pdev)
7777
eeh_add_to_parent_pe(edev); /* Add as VF PE type */
7878
}
7979
#endif
80-
eeh_add_device_late(pdev);
80+
eeh_probe_device(pdev);
8181
}
8282

8383
/*
@@ -335,6 +335,26 @@ void pseries_eeh_init_edev(struct pci_dn *pdn)
335335
eeh_save_bars(edev);
336336
}
337337

338+
static struct eeh_dev *pseries_eeh_probe(struct pci_dev *pdev)
339+
{
340+
struct eeh_dev *edev;
341+
struct pci_dn *pdn;
342+
343+
pdn = pci_get_pdn_by_devfn(pdev->bus, pdev->devfn);
344+
if (!pdn)
345+
return NULL;
346+
347+
/*
348+
* If the system supports EEH on this device then the eeh_dev was
349+
* configured and inserted into a PE in pseries_eeh_init_edev()
350+
*/
351+
edev = pdn_to_eeh_dev(pdn);
352+
if (!edev || !edev->pe)
353+
return NULL;
354+
355+
return edev;
356+
}
357+
338358
/**
339359
* pseries_eeh_init_edev_recursive - Enable EEH for the indicated device
340360
* @pdn: PCI device node
@@ -813,6 +833,7 @@ static int pseries_notify_resume(struct pci_dn *pdn)
813833
static struct eeh_ops pseries_eeh_ops = {
814834
.name = "pseries",
815835
.init = pseries_eeh_init,
836+
.probe = pseries_eeh_probe,
816837
.set_option = pseries_eeh_set_option,
817838
.get_pe_addr = pseries_eeh_get_pe_addr,
818839
.get_state = pseries_eeh_get_state,

0 commit comments

Comments
 (0)