* [PATCH v2 1/3] ppc/pnv: Add null checks for OpenCapi PHBs
2026-05-27 18:08 [PATCH v2 0/3] ppc/pnv: Fix panics and refactor pnv_php.c Aditya Gupta
@ 2026-05-27 18:08 ` Aditya Gupta
2026-05-27 19:34 ` sashiko-bot
2026-05-27 18:08 ` [PATCH v2 2/3] ppc/pnv: Refactor PNV PCI hotplug driver Aditya Gupta
2026-05-27 18:08 ` [PATCH v2 3/3] ppc/pnv: Refactor PNV PCI Hotplug to group PCIe functions Aditya Gupta
2 siblings, 1 reply; 7+ messages in thread
From: Aditya Gupta @ 2026-05-27 18:08 UTC (permalink / raw)
To: linux-kernel, linuxppc-dev, Madhavan Srinivasan, Timothy Pearson,
Bjorn Helgaas, Shawn Anastasio
Cc: sashiko-bot, linux-pci, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), stable
For opencapi phb direct slots, the .pdev for php_slots will be NULL
Various sections of the code in pnv_php can do a null dereference and
crash the kernel.
Originally, the issue was hit during boot:
[ 1.568588] PowerPC PowerNV PCI Hotplug Driver version: 0.1
[ 1.569722] BUG: Kernel NULL pointer dereference at 0x00000074
[ 1.569811] Faulting instruction address: 0xc000000000b75fd0
[ 1.569890] Oops: Kernel access of bad area, sig: 11 [#1]
[ 1.569963] LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA PowerNV
...
[ 1.571492] NIP [c000000000b75fd0] pnv_php_get_adapter_state+0x60/0x154
[ 1.571604] LR [c000000000b75fbc] pnv_php_get_adapter_state+0x4c/0x154
[ 1.571690] Call Trace:
[ 1.571725] [c000c0000688f990] [c000000000b75fbc] pnv_php_get_adapter_state+0x4c/0x154 (unreliable)
[ 1.571783] [c000c0000688fa20] [c000000000b78bd0] pnv_php_enable+0x94/0x378
[ 1.571951] [c000c0000688fac0] [c000000000b7912c] pnv_php_register_one.isra.0+0x11c/0x1e0
This occurs for hotplug slots on root buses where bus->self == NULL,
such as OpenCAPI PHB direct slots. An added debug print (not part of
this patch) confirmed it was opencapi:
[ 1.617227] pnv_php: slot 'OPENCAPI-0009' has NULL pdev (bus 0009:00, parent=NO (root bus))
[ 1.617308] pnv_php: slot 'OPENCAPI-0009' dn->full_name='pciex@603a000000000', compatible='ibm,power10-pau-opencapi-pciex'
This only required null check in 'pnv_php_get_adapter_state', which
caused the kernel to boot.
Even with 'pnv_php_get_adapter_state' null check, there are more
possible null dereferences pointed by sashiko, including cases where
userspace crashes the kernel, such as:
$ cat /sys/bus/pci/slots/*/attention
...
[ 557.036295] Kernel attempted to read user page (6e) - exploit attempt? (uid: 0)
[ 557.036354] BUG: Kernel NULL pointer dereference on read at 0x0000006e
[ 557.036383] Faulting instruction address: 0xc000000000a83334
[ 557.036413] Oops: Kernel access of bad area, sig: 11 [#1]
[ 557.036449] LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA PowerNV
...
[ 557.037749] [c000000046707a20] [c000000046707b90] 0xc000000046707b90 (unreliable)
[ 557.037795] [c000000046707a70] [0000000000000001] 0x1
[ 557.037850] [c000000046707ab0] [c000000000acb00c] attention_read_file+0x54/0xa8
[ 557.037910] [c000000046707b30] [c000000000abfbfc] pci_slot_attr_show+0x3c/0x58
[ 557.037977] [c000000046707b50] [c0000000008181ec] sysfs_kf_seq_show+0xd4/0x204
[ 557.038022] [c000000046707be0] [c000000000815004] kernfs_seq_show+0x44/0x58
Add null checks to prevent the null dereferences.
Cc: stable@vger.kernel.org
Fixes: 80f9fc236279 ("PCI: pnv_php: Work around switches with broken presence detection")
Signed-off-by: Aditya Gupta <adityag@linux.ibm.com>
---
drivers/pci/hotplug/pnv_php.c | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
index ff92a5c301b8..d0f5e8ad1f71 100644
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -47,6 +47,9 @@ static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
struct pci_dev *pdev = php_slot->pdev;
u16 ctrl;
+ if (!pdev)
+ return;
+
if (php_slot->irq > 0) {
pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
ctrl &= ~(PCI_EXP_SLTCTL_HPIE |
@@ -414,7 +417,8 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
*/
ret = pnv_pci_get_presence_state(php_slot->id, &presence);
if (ret >= 0) {
- if (pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
+ if (php_slot->pdev &&
+ pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
presence == OPAL_PCI_SLOT_EMPTY) {
/*
* Similar to pciehp_hpc, check whether the Link Active
@@ -442,6 +446,11 @@ static int pnv_php_get_raw_indicator_status(struct hotplug_slot *slot, u8 *state
struct pci_dev *bridge = php_slot->pdev;
u16 status;
+ if (!bridge) {
+ *state = 0;
+ return 0;
+ }
+
pcie_capability_read_word(bridge, PCI_EXP_SLTCTL, &status);
*state = (status & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6;
return 0;
@@ -514,11 +523,13 @@ static int pnv_php_activate_slot(struct pnv_php_slot *php_slot,
* fence / freeze.
*/
SLOT_WARN(php_slot, "Try %d...\n", i + 1);
- pci_set_pcie_reset_state(php_slot->pdev,
- pcie_warm_reset);
- msleep(250);
- pci_set_pcie_reset_state(php_slot->pdev,
- pcie_deassert_reset);
+ if (php_slot->pdev) {
+ pci_set_pcie_reset_state(php_slot->pdev,
+ pcie_warm_reset);
+ msleep(250);
+ pci_set_pcie_reset_state(php_slot->pdev,
+ pcie_deassert_reset);
+ }
ret = pnv_php_set_slot_power_state(
slot, OPAL_PCI_SLOT_POWER_ON);
@@ -911,6 +922,9 @@ pnv_php_detect_clear_suprise_removal_freeze(struct pnv_php_slot *php_slot)
struct eeh_pe *pe;
int i, rc;
+ if (!pdev)
+ return;
+
/*
* When a device is surprise removed from a downstream bridge slot,
* the upstream bridge port can still end up frozen due to related EEH
@@ -1093,6 +1107,9 @@ static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
struct pci_dev *pdev = php_slot->pdev;
int irq, ret;
+ if (!pdev)
+ return;
+
/*
* The MSI/MSIx interrupt might have been occupied by other
* drivers. Don't populate the surprise hotplug capability
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 2/3] ppc/pnv: Refactor PNV PCI hotplug driver
2026-05-27 18:08 [PATCH v2 0/3] ppc/pnv: Fix panics and refactor pnv_php.c Aditya Gupta
2026-05-27 18:08 ` [PATCH v2 1/3] ppc/pnv: Add null checks for OpenCapi PHBs Aditya Gupta
@ 2026-05-27 18:08 ` Aditya Gupta
2026-05-27 20:00 ` sashiko-bot
2026-05-27 18:08 ` [PATCH v2 3/3] ppc/pnv: Refactor PNV PCI Hotplug to group PCIe functions Aditya Gupta
2 siblings, 1 reply; 7+ messages in thread
From: Aditya Gupta @ 2026-05-27 18:08 UTC (permalink / raw)
To: linux-kernel, linuxppc-dev, Madhavan Srinivasan, Timothy Pearson,
Bjorn Helgaas, Shawn Anastasio
Cc: sashiko-bot, linux-pci, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP)
Currently the pnv_php driver handles both PCIe and OpenCAPI slots.
The slots has many common functionality, but many operations are pcie
specific, and assume the slot having a parent device, which isn't the
case with opencapi slots
This requires handling the case of parent device being NULL, at many
places, which can be hard to maintain and add code to.
Instead, have PCIe/OpenCAPI operations as .backend_ops in pnv_php_slot,
so that PCIe code is cleanly separated.
With this, future patches can just edit the PCIe/OpenCAPI specific ops,
instead of editing the common code.
No functional change is intended other than reset_slot for OpenCAPI
slots returning -ENODEV when not probing.
Signed-off-by: Aditya Gupta <adityag@linux.ibm.com>
---
arch/powerpc/include/asm/pnv-pci.h | 16 +++
drivers/pci/hotplug/pnv_php.c | 160 +++++++++++++++++++----------
2 files changed, 123 insertions(+), 53 deletions(-)
diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h
index 7e9a479951a3..f1020f1e61cd 100644
--- a/arch/powerpc/include/asm/pnv-pci.h
+++ b/arch/powerpc/include/asm/pnv-pci.h
@@ -27,6 +27,9 @@ extern int pnv_pci_set_power_state(uint64_t id, uint8_t state,
int64_t pnv_opal_pci_msi_eoi(struct irq_data *d);
bool is_pnv_opal_msi(struct irq_chip *chip);
+/* To be set for hotplug operations for PCIe/OpenCAPI */
+struct pnv_php_backend_ops;
+
struct pnv_php_slot {
struct hotplug_slot slot;
uint64_t id;
@@ -50,10 +53,23 @@ struct pnv_php_slot {
void *fdt;
void *dt;
struct of_changeset ocs;
+ const struct pnv_php_backend_ops *backend_ops;
struct pnv_php_slot *parent;
struct list_head children;
struct list_head link;
};
+
+struct pnv_php_backend_ops {
+ void (*enable_irq)(struct pnv_php_slot *slot);
+ void (*disable_irq)(struct pnv_php_slot *slot, bool disable_device, bool disable_msi);
+ void (*fixup_presence_state)(struct pnv_php_slot *slot, u8 *presence);
+ void (*get_attention_state)(struct pnv_php_slot *slot, u8 *state);
+ void (*set_attention_state)(struct pnv_php_slot *slot, u8 state);
+ void (*fundamental_reset)(struct pnv_php_slot *slot);
+ void (*detect_surprise_removal)(struct pnv_php_slot *slot);
+ int (*reset_slot)(struct pnv_php_slot *slot, bool probe);
+};
+
extern struct pnv_php_slot *pnv_php_find_slot(struct device_node *dn);
extern int pnv_php_set_slot_power_state(struct hotplug_slot *slot,
uint8_t state);
diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
index d0f5e8ad1f71..997412eea486 100644
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -39,17 +39,53 @@ static void pnv_php_register(struct device_node *dn);
static void pnv_php_unregister_one(struct device_node *dn);
static void pnv_php_unregister(struct device_node *dn);
-static void pnv_php_enable_irq(struct pnv_php_slot *php_slot);
+static void pcie_enable_irq(struct pnv_php_slot *php_slot);
+static int pcie_check_link_active(struct pci_dev *pdev);
+static void pcie_detect_surprise_removal(struct pnv_php_slot *php_slot);
+
+static void pcie_fixup_presence_state(struct pnv_php_slot *php_slot, u8 *presence)
+{
+ if (pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
+ *presence == OPAL_PCI_SLOT_EMPTY) {
+ /*
+ * Similar to pciehp_hpc, check whether the Link Active
+ * bit is set to account for broken downstream bridges
+ * that don't properly assert Presence Detect State, as
+ * was observed on the Microsemi Switchtec PM8533 PFX
+ * [11f8:8533].
+ */
+ if (pcie_check_link_active(php_slot->pdev) > 0)
+ *presence = OPAL_PCI_SLOT_PRESENT;
+ }
+}
+
+static void pcie_fundamental_reset(struct pnv_php_slot *php_slot)
+{
+ pci_set_pcie_reset_state(php_slot->pdev, pcie_warm_reset);
+ msleep(250);
+ pci_set_pcie_reset_state(php_slot->pdev, pcie_deassert_reset);
+}
+
+static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
+{
+ if (php_slot->backend_ops->enable_irq)
+ php_slot->backend_ops->enable_irq(php_slot);
+}
static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
bool disable_device, bool disable_msi)
+{
+ if (php_slot->backend_ops->disable_irq)
+ php_slot->backend_ops->disable_irq(php_slot, disable_device,
+ disable_msi);
+}
+
+static void pcie_disable_irq(struct pnv_php_slot *php_slot,
+ bool disable_device, bool disable_msi)
{
struct pci_dev *pdev = php_slot->pdev;
u16 ctrl;
- if (!pdev)
- return;
-
if (php_slot->irq > 0) {
pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
ctrl &= ~(PCI_EXP_SLTCTL_HPIE |
@@ -417,19 +453,8 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
*/
ret = pnv_pci_get_presence_state(php_slot->id, &presence);
if (ret >= 0) {
- if (php_slot->pdev &&
- pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
- presence == OPAL_PCI_SLOT_EMPTY) {
- /*
- * Similar to pciehp_hpc, check whether the Link Active
- * bit is set to account for broken downstream bridges
- * that don't properly assert Presence Detect State, as
- * was observed on the Microsemi Switchtec PM8533 PFX
- * [11f8:8533].
- */
- if (pcie_check_link_active(php_slot->pdev) > 0)
- presence = OPAL_PCI_SLOT_PRESENT;
- }
+ if (php_slot->backend_ops->fixup_presence_state)
+ php_slot->backend_ops->fixup_presence_state(php_slot, &presence);
*state = presence;
ret = 0;
@@ -440,28 +465,24 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
return ret;
}
-static int pnv_php_get_raw_indicator_status(struct hotplug_slot *slot, u8 *state)
+static void pcie_get_attention_state(struct pnv_php_slot *php_slot, u8 *state)
{
- struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
struct pci_dev *bridge = php_slot->pdev;
u16 status;
- if (!bridge) {
- *state = 0;
- return 0;
- }
-
pcie_capability_read_word(bridge, PCI_EXP_SLTCTL, &status);
*state = (status & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6;
- return 0;
}
-
static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state)
{
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
- pnv_php_get_raw_indicator_status(slot, &php_slot->attention_state);
+ if (php_slot->backend_ops->get_attention_state)
+ php_slot->backend_ops->get_attention_state(php_slot, &php_slot->attention_state);
+ else
+ php_slot->attention_state = 0;
+
*state = php_slot->attention_state;
return 0;
}
@@ -469,13 +490,19 @@ static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state)
static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
{
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
+
+ if (php_slot->backend_ops->set_attention_state)
+ php_slot->backend_ops->set_attention_state(php_slot, state);
+
+ return 0;
+}
+
+static void pcie_set_attention_state(struct pnv_php_slot *php_slot, u8 state)
+{
struct pci_dev *bridge = php_slot->pdev;
u16 new, mask;
php_slot->attention_state = state;
- if (!bridge)
- return 0;
-
mask = PCI_EXP_SLTCTL_AIC;
if (state)
@@ -484,8 +511,6 @@ static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
new = PCI_EXP_SLTCTL_ATTN_IND_OFF;
pcie_capability_clear_and_set_word(bridge, PCI_EXP_SLTCTL, mask, new);
-
- return 0;
}
static int pnv_php_activate_slot(struct pnv_php_slot *php_slot,
@@ -523,13 +548,8 @@ static int pnv_php_activate_slot(struct pnv_php_slot *php_slot,
* fence / freeze.
*/
SLOT_WARN(php_slot, "Try %d...\n", i + 1);
- if (php_slot->pdev) {
- pci_set_pcie_reset_state(php_slot->pdev,
- pcie_warm_reset);
- msleep(250);
- pci_set_pcie_reset_state(php_slot->pdev,
- pcie_deassert_reset);
- }
+ if (php_slot->backend_ops->fundamental_reset)
+ php_slot->backend_ops->fundamental_reset(php_slot);
ret = pnv_php_set_slot_power_state(
slot, OPAL_PCI_SLOT_POWER_ON);
@@ -633,16 +653,18 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
static int pnv_php_reset_slot(struct hotplug_slot *slot, bool probe)
{
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
+ if (php_slot->backend_ops->reset_slot)
+ return php_slot->backend_ops->reset_slot(php_slot, probe);
+ return probe ? 0 : -ENODEV;
+}
+
+static int pcie_reset_slot(struct pnv_php_slot *php_slot, bool probe)
+{
struct pci_dev *bridge = php_slot->pdev;
uint16_t sts;
- /*
- * The CAPI folks want pnv_php to drive OpenCAPI slots
- * which don't have a bridge. Only claim to support
- * reset_slot() if we have a bridge device (for now...)
- */
if (probe)
- return !bridge;
+ return 0;
/* mask our interrupt while resetting the bridge */
if (php_slot->irq > 0)
@@ -778,6 +800,26 @@ static void pnv_php_release(struct pnv_php_slot *php_slot)
pnv_php_put_slot(php_slot->parent);
}
+static const struct pnv_php_backend_ops pnv_php_pcie_ops = {
+ .enable_irq = pcie_enable_irq,
+ .disable_irq = pcie_disable_irq,
+ .get_attention_state = pcie_get_attention_state,
+ .set_attention_state = pcie_set_attention_state,
+ .fixup_presence_state = pcie_fixup_presence_state,
+ .fundamental_reset = pcie_fundamental_reset,
+ .detect_surprise_removal = pcie_detect_surprise_removal,
+ .reset_slot = pcie_reset_slot,
+};
+
+static int opencapi_reset_slot(struct pnv_php_slot *slot, bool probe)
+{
+ return probe ? 1 : -ENODEV;
+}
+
+static const struct pnv_php_backend_ops pnv_php_opencapi_ops = {
+ .reset_slot = opencapi_reset_slot,
+};
+
static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
{
struct pnv_php_slot *php_slot;
@@ -830,6 +872,12 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
php_slot->power_state_check = false;
php_slot->slot.ops = &php_slot_ops;
+ /* OpenCAPI slots don't have a parent bridge */
+ if (php_slot->pdev)
+ php_slot->backend_ops = &pnv_php_pcie_ops;
+ else
+ php_slot->backend_ops = &pnv_php_opencapi_ops;
+
INIT_LIST_HEAD(&php_slot->children);
INIT_LIST_HEAD(&php_slot->link);
@@ -886,7 +934,7 @@ static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
return 0;
}
-static int pnv_php_enable_msix(struct pnv_php_slot *php_slot)
+static int pcie_enable_msix(struct pnv_php_slot *php_slot)
{
struct pci_dev *pdev = php_slot->pdev;
struct msix_entry entry;
@@ -915,7 +963,13 @@ static int pnv_php_enable_msix(struct pnv_php_slot *php_slot)
}
static void
-pnv_php_detect_clear_suprise_removal_freeze(struct pnv_php_slot *php_slot)
+pnv_php_detect_clear_surprise_removal_freeze(struct pnv_php_slot *php_slot)
+{
+ if (php_slot->backend_ops->detect_surprise_removal)
+ php_slot->backend_ops->detect_surprise_removal(php_slot);
+}
+
+static void pcie_detect_surprise_removal(struct pnv_php_slot *php_slot)
{
struct pci_dev *pdev = php_slot->pdev;
struct eeh_dev *edev;
@@ -972,7 +1026,7 @@ static void pnv_php_event_handler(struct work_struct *work)
pnv_php_enable_slot(&php_slot->slot);
} else {
pnv_php_disable_slot(&php_slot->slot);
- pnv_php_detect_clear_suprise_removal_freeze(php_slot);
+ pnv_php_detect_clear_surprise_removal_freeze(php_slot);
}
kfree(event);
@@ -1055,7 +1109,7 @@ static irqreturn_t pnv_php_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
+static void pcie_init_irq(struct pnv_php_slot *php_slot, int irq)
{
struct pci_dev *pdev = php_slot->pdev;
u32 broken_pdc = 0;
@@ -1102,7 +1156,7 @@ static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
php_slot->irq = irq;
}
-static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
+static void pcie_enable_irq(struct pnv_php_slot *php_slot)
{
struct pci_dev *pdev = php_slot->pdev;
int irq, ret;
@@ -1127,9 +1181,9 @@ static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
pci_set_master(pdev);
/* Enable MSIx interrupt */
- irq = pnv_php_enable_msix(php_slot);
+ irq = pcie_enable_msix(php_slot);
if (irq > 0) {
- pnv_php_init_irq(php_slot, irq);
+ pcie_init_irq(php_slot, irq);
return;
}
@@ -1140,7 +1194,7 @@ static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
ret = pci_enable_msi(pdev);
if (!ret || pdev->irq) {
irq = pdev->irq;
- pnv_php_init_irq(php_slot, irq);
+ pcie_init_irq(php_slot, irq);
}
}
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 3/3] ppc/pnv: Refactor PNV PCI Hotplug to group PCIe functions
2026-05-27 18:08 [PATCH v2 0/3] ppc/pnv: Fix panics and refactor pnv_php.c Aditya Gupta
2026-05-27 18:08 ` [PATCH v2 1/3] ppc/pnv: Add null checks for OpenCapi PHBs Aditya Gupta
2026-05-27 18:08 ` [PATCH v2 2/3] ppc/pnv: Refactor PNV PCI hotplug driver Aditya Gupta
@ 2026-05-27 18:08 ` Aditya Gupta
2026-05-27 20:26 ` sashiko-bot
2 siblings, 1 reply; 7+ messages in thread
From: Aditya Gupta @ 2026-05-27 18:08 UTC (permalink / raw)
To: linux-kernel, linuxppc-dev, Madhavan Srinivasan, Timothy Pearson,
Bjorn Helgaas, Shawn Anastasio
Cc: sashiko-bot, linux-pci, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP)
With the refactor change to pnv_php.c, pnv_php_* and pcie_* are mixed
up.
Move and group pcie, opencapi, and pnv_php*.
No functional change. Only moves code, and no logic has been modified.
Signed-off-by: Aditya Gupta <adityag@linux.ibm.com>
---
drivers/pci/hotplug/pnv_php.c | 559 +++++++++++++++++-----------------
1 file changed, 279 insertions(+), 280 deletions(-)
diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
index 997412eea486..dd8e00b879e1 100644
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -38,46 +38,125 @@ static DEFINE_SPINLOCK(pnv_php_lock);
static void pnv_php_register(struct device_node *dn);
static void pnv_php_unregister_one(struct device_node *dn);
static void pnv_php_unregister(struct device_node *dn);
+static irqreturn_t pnv_php_interrupt(int irq, void *data);
+static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
+ bool disable_device, bool disable_msi);
-static void pcie_enable_irq(struct pnv_php_slot *php_slot);
-static int pcie_check_link_active(struct pci_dev *pdev);
-static void pcie_detect_surprise_removal(struct pnv_php_slot *php_slot);
-
-static void pcie_fixup_presence_state(struct pnv_php_slot *php_slot, u8 *presence)
+static void pcie_init_irq(struct pnv_php_slot *php_slot, int irq)
{
- if (pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
- *presence == OPAL_PCI_SLOT_EMPTY) {
- /*
- * Similar to pciehp_hpc, check whether the Link Active
- * bit is set to account for broken downstream bridges
- * that don't properly assert Presence Detect State, as
- * was observed on the Microsemi Switchtec PM8533 PFX
- * [11f8:8533].
- */
- if (pcie_check_link_active(php_slot->pdev) > 0)
- *presence = OPAL_PCI_SLOT_PRESENT;
+ struct pci_dev *pdev = php_slot->pdev;
+ u32 broken_pdc = 0;
+ u16 sts, ctrl;
+ int ret;
+
+ /* Check PDC (Presence Detection Change) is broken or not */
+ ret = of_property_read_u32(php_slot->dn, "ibm,slot-broken-pdc",
+ &broken_pdc);
+ if (!ret && broken_pdc)
+ php_slot->flags |= PNV_PHP_FLAG_BROKEN_PDC;
+
+ /* Clear pending interrupts */
+ pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
+ if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC)
+ sts |= PCI_EXP_SLTSTA_DLLSC;
+ else
+ sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
+ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
+
+ /* Request the interrupt */
+ ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED,
+ php_slot->name, php_slot);
+ if (ret) {
+ pnv_php_disable_irq(php_slot, true, true);
+ SLOT_WARN(php_slot, "Error %d enabling IRQ %d\n", ret, irq);
+ return;
}
-}
-static void pcie_fundamental_reset(struct pnv_php_slot *php_slot)
-{
- pci_set_pcie_reset_state(php_slot->pdev, pcie_warm_reset);
- msleep(250);
- pci_set_pcie_reset_state(php_slot->pdev, pcie_deassert_reset);
+ /* Enable the interrupts */
+ pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
+ if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) {
+ ctrl &= ~PCI_EXP_SLTCTL_PDCE;
+ ctrl |= (PCI_EXP_SLTCTL_HPIE |
+ PCI_EXP_SLTCTL_DLLSCE);
+ } else {
+ ctrl |= (PCI_EXP_SLTCTL_HPIE |
+ PCI_EXP_SLTCTL_PDCE |
+ PCI_EXP_SLTCTL_DLLSCE);
+ }
+ pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
+
+ /* The interrupt is initialized successfully when @irq is valid */
+ php_slot->irq = irq;
}
-static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
+static int pcie_enable_msix(struct pnv_php_slot *php_slot)
{
- if (php_slot->backend_ops->enable_irq)
- php_slot->backend_ops->enable_irq(php_slot);
+ struct pci_dev *pdev = php_slot->pdev;
+ struct msix_entry entry;
+ int nr_entries, ret;
+ u16 pcie_flag;
+
+ /* Get total number of MSIx entries */
+ nr_entries = pci_msix_vec_count(pdev);
+ if (nr_entries < 0)
+ return nr_entries;
+
+ /* Check hotplug MSIx entry is in range */
+ pcie_capability_read_word(pdev, PCI_EXP_FLAGS, &pcie_flag);
+ entry.entry = FIELD_GET(PCI_EXP_FLAGS_IRQ, pcie_flag);
+ if (entry.entry >= nr_entries)
+ return -ERANGE;
+
+ /* Enable MSIx */
+ ret = pci_enable_msix_exact(pdev, &entry, 1);
+ if (ret) {
+ SLOT_WARN(php_slot, "Error %d enabling MSIx\n", ret);
+ return ret;
+ }
+
+ return entry.vector;
}
-static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
- bool disable_device, bool disable_msi)
+static void pcie_enable_irq(struct pnv_php_slot *php_slot)
{
- if (php_slot->backend_ops->disable_irq)
- php_slot->backend_ops->disable_irq(php_slot, disable_device,
- disable_msi);
+ struct pci_dev *pdev = php_slot->pdev;
+ int irq, ret;
+
+ if (!pdev)
+ return;
+
+ /*
+ * The MSI/MSIx interrupt might have been occupied by other
+ * drivers. Don't populate the surprise hotplug capability
+ * in that case.
+ */
+ if (pci_dev_msi_enabled(pdev))
+ return;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ SLOT_WARN(php_slot, "Error %d enabling device\n", ret);
+ return;
+ }
+
+ pci_set_master(pdev);
+
+ /* Enable MSIx interrupt */
+ irq = pcie_enable_msix(php_slot);
+ if (irq > 0) {
+ pcie_init_irq(php_slot, irq);
+ return;
+ }
+
+ /*
+ * Use MSI if MSIx doesn't work. Fail back to legacy INTx
+ * if MSI doesn't work either
+ */
+ ret = pci_enable_msi(pdev);
+ if (!ret || pdev->irq) {
+ irq = pdev->irq;
+ pcie_init_irq(php_slot, irq);
+ }
}
static void pcie_disable_irq(struct pnv_php_slot *php_slot,
@@ -104,8 +183,176 @@ static void pcie_disable_irq(struct pnv_php_slot *php_slot,
pci_disable_msi(pdev);
}
- if (disable_device)
- pci_disable_device(pdev);
+ if (disable_device)
+ pci_disable_device(pdev);
+}
+
+static void pcie_get_attention_state(struct pnv_php_slot *php_slot, u8 *state)
+{
+ struct pci_dev *bridge = php_slot->pdev;
+ u16 status;
+
+ pcie_capability_read_word(bridge, PCI_EXP_SLTCTL, &status);
+ *state = (status & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6;
+}
+
+static void pcie_set_attention_state(struct pnv_php_slot *php_slot, u8 state)
+{
+ struct pci_dev *bridge = php_slot->pdev;
+ u16 new, mask;
+
+ php_slot->attention_state = state;
+ mask = PCI_EXP_SLTCTL_AIC;
+
+ if (state)
+ new = FIELD_PREP(PCI_EXP_SLTCTL_AIC, state);
+ else
+ new = PCI_EXP_SLTCTL_ATTN_IND_OFF;
+
+ pcie_capability_clear_and_set_word(bridge, PCI_EXP_SLTCTL, mask, new);
+}
+
+static int pcie_check_link_active(struct pci_dev *pdev)
+{
+ u16 lnk_status;
+ int ret;
+
+ ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
+ if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status))
+ return -ENODEV;
+
+ ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
+
+ return ret;
+}
+
+static void pcie_fixup_presence_state(struct pnv_php_slot *php_slot, u8 *presence)
+{
+ if (pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
+ *presence == OPAL_PCI_SLOT_EMPTY) {
+ /*
+ * Similar to pciehp_hpc, check whether the Link Active
+ * bit is set to account for broken downstream bridges
+ * that don't properly assert Presence Detect State, as
+ * was observed on the Microsemi Switchtec PM8533 PFX
+ * [11f8:8533].
+ */
+ if (pcie_check_link_active(php_slot->pdev) > 0)
+ *presence = OPAL_PCI_SLOT_PRESENT;
+ }
+}
+
+static void pcie_fundamental_reset(struct pnv_php_slot *php_slot)
+{
+ pci_set_pcie_reset_state(php_slot->pdev, pcie_warm_reset);
+ msleep(250);
+ pci_set_pcie_reset_state(php_slot->pdev, pcie_deassert_reset);
+}
+
+static void pcie_detect_surprise_removal(struct pnv_php_slot *php_slot)
+{
+ struct pci_dev *pdev = php_slot->pdev;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ int i, rc;
+
+ if (!pdev)
+ return;
+
+ /*
+ * When a device is surprise removed from a downstream bridge slot,
+ * the upstream bridge port can still end up frozen due to related EEH
+ * events, which will in turn block the MSI interrupts for slot hotplug
+ * detection.
+ *
+ * Detect and thaw any frozen upstream PE after slot deactivation.
+ */
+ edev = pci_dev_to_eeh_dev(pdev);
+ pe = edev ? edev->pe : NULL;
+ rc = eeh_pe_get_state(pe);
+ if ((rc == -ENODEV) || (rc == -ENOENT)) {
+ SLOT_WARN(
+ php_slot,
+ "Upstream bridge PE state unknown, hotplug detect may fail\n");
+ } else {
+ if (pe->state & EEH_PE_ISOLATED) {
+ SLOT_WARN(
+ php_slot,
+ "Upstream bridge PE %02x frozen, thawing...\n",
+ pe->addr);
+ for (i = 0; i < 3; i++)
+ if (!eeh_unfreeze_pe(pe))
+ break;
+ if (i >= 3)
+ SLOT_WARN(
+ php_slot,
+ "Unable to thaw PE %02x, hotplug detect will fail!\n",
+ pe->addr);
+ else
+ SLOT_WARN(php_slot,
+ "PE %02x thawed successfully\n",
+ pe->addr);
+ }
+ }
+}
+
+static int pcie_reset_slot(struct pnv_php_slot *php_slot, bool probe)
+{
+ struct pci_dev *bridge = php_slot->pdev;
+ uint16_t sts;
+
+ if (probe)
+ return 0;
+
+ /* mask our interrupt while resetting the bridge */
+ if (php_slot->irq > 0)
+ disable_irq(php_slot->irq);
+
+ pci_bridge_secondary_bus_reset(bridge);
+
+ /* clear any state changes that happened due to the reset */
+ pcie_capability_read_word(php_slot->pdev, PCI_EXP_SLTSTA, &sts);
+ sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
+ pcie_capability_write_word(php_slot->pdev, PCI_EXP_SLTSTA, sts);
+
+ if (php_slot->irq > 0)
+ enable_irq(php_slot->irq);
+
+ return 0;
+}
+
+static const struct pnv_php_backend_ops pnv_php_pcie_ops = {
+ .enable_irq = pcie_enable_irq,
+ .disable_irq = pcie_disable_irq,
+ .get_attention_state = pcie_get_attention_state,
+ .set_attention_state = pcie_set_attention_state,
+ .fixup_presence_state = pcie_fixup_presence_state,
+ .fundamental_reset = pcie_fundamental_reset,
+ .detect_surprise_removal = pcie_detect_surprise_removal,
+ .reset_slot = pcie_reset_slot,
+};
+
+static int opencapi_reset_slot(struct pnv_php_slot *slot, bool probe)
+{
+ return probe ? 1 : -ENODEV;
+}
+
+static const struct pnv_php_backend_ops pnv_php_opencapi_ops = {
+ .reset_slot = opencapi_reset_slot,
+};
+
+static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
+{
+ if (php_slot->backend_ops->enable_irq)
+ php_slot->backend_ops->enable_irq(php_slot);
+}
+
+static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
+ bool disable_device, bool disable_msi)
+{
+ if (php_slot->backend_ops->disable_irq)
+ php_slot->backend_ops->disable_irq(php_slot, disable_device,
+ disable_msi);
}
static void pnv_php_free_slot(struct kref *kref)
@@ -427,20 +674,6 @@ static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
return 0;
}
-static int pcie_check_link_active(struct pci_dev *pdev)
-{
- u16 lnk_status;
- int ret;
-
- ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
- if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status))
- return -ENODEV;
-
- ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
-
- return ret;
-}
-
static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
{
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
@@ -465,15 +698,6 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
return ret;
}
-static void pcie_get_attention_state(struct pnv_php_slot *php_slot, u8 *state)
-{
- struct pci_dev *bridge = php_slot->pdev;
- u16 status;
-
- pcie_capability_read_word(bridge, PCI_EXP_SLTCTL, &status);
- *state = (status & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6;
-}
-
static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state)
{
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
@@ -497,22 +721,6 @@ static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
return 0;
}
-static void pcie_set_attention_state(struct pnv_php_slot *php_slot, u8 state)
-{
- struct pci_dev *bridge = php_slot->pdev;
- u16 new, mask;
-
- php_slot->attention_state = state;
- mask = PCI_EXP_SLTCTL_AIC;
-
- if (state)
- new = FIELD_PREP(PCI_EXP_SLTCTL_AIC, state);
- else
- new = PCI_EXP_SLTCTL_ATTN_IND_OFF;
-
- pcie_capability_clear_and_set_word(bridge, PCI_EXP_SLTCTL, mask, new);
-}
-
static int pnv_php_activate_slot(struct pnv_php_slot *php_slot,
struct hotplug_slot *slot)
{
@@ -658,31 +866,6 @@ static int pnv_php_reset_slot(struct hotplug_slot *slot, bool probe)
return probe ? 0 : -ENODEV;
}
-static int pcie_reset_slot(struct pnv_php_slot *php_slot, bool probe)
-{
- struct pci_dev *bridge = php_slot->pdev;
- uint16_t sts;
-
- if (probe)
- return 0;
-
- /* mask our interrupt while resetting the bridge */
- if (php_slot->irq > 0)
- disable_irq(php_slot->irq);
-
- pci_bridge_secondary_bus_reset(bridge);
-
- /* clear any state changes that happened due to the reset */
- pcie_capability_read_word(php_slot->pdev, PCI_EXP_SLTSTA, &sts);
- sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
- pcie_capability_write_word(php_slot->pdev, PCI_EXP_SLTSTA, sts);
-
- if (php_slot->irq > 0)
- enable_irq(php_slot->irq);
-
- return 0;
-}
-
static int pnv_php_enable_slot(struct hotplug_slot *slot)
{
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
@@ -800,26 +983,6 @@ static void pnv_php_release(struct pnv_php_slot *php_slot)
pnv_php_put_slot(php_slot->parent);
}
-static const struct pnv_php_backend_ops pnv_php_pcie_ops = {
- .enable_irq = pcie_enable_irq,
- .disable_irq = pcie_disable_irq,
- .get_attention_state = pcie_get_attention_state,
- .set_attention_state = pcie_set_attention_state,
- .fixup_presence_state = pcie_fixup_presence_state,
- .fundamental_reset = pcie_fundamental_reset,
- .detect_surprise_removal = pcie_detect_surprise_removal,
- .reset_slot = pcie_reset_slot,
-};
-
-static int opencapi_reset_slot(struct pnv_php_slot *slot, bool probe)
-{
- return probe ? 1 : -ENODEV;
-}
-
-static const struct pnv_php_backend_ops pnv_php_opencapi_ops = {
- .reset_slot = opencapi_reset_slot,
-};
-
static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
{
struct pnv_php_slot *php_slot;
@@ -934,34 +1097,6 @@ static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
return 0;
}
-static int pcie_enable_msix(struct pnv_php_slot *php_slot)
-{
- struct pci_dev *pdev = php_slot->pdev;
- struct msix_entry entry;
- int nr_entries, ret;
- u16 pcie_flag;
-
- /* Get total number of MSIx entries */
- nr_entries = pci_msix_vec_count(pdev);
- if (nr_entries < 0)
- return nr_entries;
-
- /* Check hotplug MSIx entry is in range */
- pcie_capability_read_word(pdev, PCI_EXP_FLAGS, &pcie_flag);
- entry.entry = FIELD_GET(PCI_EXP_FLAGS_IRQ, pcie_flag);
- if (entry.entry >= nr_entries)
- return -ERANGE;
-
- /* Enable MSIx */
- ret = pci_enable_msix_exact(pdev, &entry, 1);
- if (ret) {
- SLOT_WARN(php_slot, "Error %d enabling MSIx\n", ret);
- return ret;
- }
-
- return entry.vector;
-}
-
static void
pnv_php_detect_clear_surprise_removal_freeze(struct pnv_php_slot *php_slot)
{
@@ -969,53 +1104,6 @@ pnv_php_detect_clear_surprise_removal_freeze(struct pnv_php_slot *php_slot)
php_slot->backend_ops->detect_surprise_removal(php_slot);
}
-static void pcie_detect_surprise_removal(struct pnv_php_slot *php_slot)
-{
- struct pci_dev *pdev = php_slot->pdev;
- struct eeh_dev *edev;
- struct eeh_pe *pe;
- int i, rc;
-
- if (!pdev)
- return;
-
- /*
- * When a device is surprise removed from a downstream bridge slot,
- * the upstream bridge port can still end up frozen due to related EEH
- * events, which will in turn block the MSI interrupts for slot hotplug
- * detection.
- *
- * Detect and thaw any frozen upstream PE after slot deactivation.
- */
- edev = pci_dev_to_eeh_dev(pdev);
- pe = edev ? edev->pe : NULL;
- rc = eeh_pe_get_state(pe);
- if ((rc == -ENODEV) || (rc == -ENOENT)) {
- SLOT_WARN(
- php_slot,
- "Upstream bridge PE state unknown, hotplug detect may fail\n");
- } else {
- if (pe->state & EEH_PE_ISOLATED) {
- SLOT_WARN(
- php_slot,
- "Upstream bridge PE %02x frozen, thawing...\n",
- pe->addr);
- for (i = 0; i < 3; i++)
- if (!eeh_unfreeze_pe(pe))
- break;
- if (i >= 3)
- SLOT_WARN(
- php_slot,
- "Unable to thaw PE %02x, hotplug detect will fail!\n",
- pe->addr);
- else
- SLOT_WARN(php_slot,
- "PE %02x thawed successfully\n",
- pe->addr);
- }
- }
-}
-
static void pnv_php_event_handler(struct work_struct *work)
{
struct pnv_php_event *event =
@@ -1109,95 +1197,6 @@ static irqreturn_t pnv_php_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-static void pcie_init_irq(struct pnv_php_slot *php_slot, int irq)
-{
- struct pci_dev *pdev = php_slot->pdev;
- u32 broken_pdc = 0;
- u16 sts, ctrl;
- int ret;
-
- /* Check PDC (Presence Detection Change) is broken or not */
- ret = of_property_read_u32(php_slot->dn, "ibm,slot-broken-pdc",
- &broken_pdc);
- if (!ret && broken_pdc)
- php_slot->flags |= PNV_PHP_FLAG_BROKEN_PDC;
-
- /* Clear pending interrupts */
- pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
- if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC)
- sts |= PCI_EXP_SLTSTA_DLLSC;
- else
- sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
- pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
-
- /* Request the interrupt */
- ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED,
- php_slot->name, php_slot);
- if (ret) {
- pnv_php_disable_irq(php_slot, true, true);
- SLOT_WARN(php_slot, "Error %d enabling IRQ %d\n", ret, irq);
- return;
- }
-
- /* Enable the interrupts */
- pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
- if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) {
- ctrl &= ~PCI_EXP_SLTCTL_PDCE;
- ctrl |= (PCI_EXP_SLTCTL_HPIE |
- PCI_EXP_SLTCTL_DLLSCE);
- } else {
- ctrl |= (PCI_EXP_SLTCTL_HPIE |
- PCI_EXP_SLTCTL_PDCE |
- PCI_EXP_SLTCTL_DLLSCE);
- }
- pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
-
- /* The interrupt is initialized successfully when @irq is valid */
- php_slot->irq = irq;
-}
-
-static void pcie_enable_irq(struct pnv_php_slot *php_slot)
-{
- struct pci_dev *pdev = php_slot->pdev;
- int irq, ret;
-
- if (!pdev)
- return;
-
- /*
- * The MSI/MSIx interrupt might have been occupied by other
- * drivers. Don't populate the surprise hotplug capability
- * in that case.
- */
- if (pci_dev_msi_enabled(pdev))
- return;
-
- ret = pci_enable_device(pdev);
- if (ret) {
- SLOT_WARN(php_slot, "Error %d enabling device\n", ret);
- return;
- }
-
- pci_set_master(pdev);
-
- /* Enable MSIx interrupt */
- irq = pcie_enable_msix(php_slot);
- if (irq > 0) {
- pcie_init_irq(php_slot, irq);
- return;
- }
-
- /*
- * Use MSI if MSIx doesn't work. Fail back to legacy INTx
- * if MSI doesn't work either
- */
- ret = pci_enable_msi(pdev);
- if (!ret || pdev->irq) {
- irq = pdev->irq;
- pcie_init_irq(php_slot, irq);
- }
-}
-
static int pnv_php_register_one(struct device_node *dn)
{
struct pnv_php_slot *php_slot;
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread