Merge branch 'pci/hotplug'

- Remove unused cpcihp struct cpci_hp_controller_ops.hardware_test
  (Guilherme Giacomo Simoes)

- Remove unused cpqphp struct ctrl_dbg.ctrl (Christophe JAILLET)

- Clean up cpqphp PCIBIOS_* return value confusion (Ilpo Järvinen)

- Use pci_bus_read_dev_vendor_id() instead of hand-coded presence detection
  in cpqphp (Ilpo Järvinen)

- Simplify cpqphp enumeration, which is already simple-minded and doesn't
  handle devices below hot-added bridges (Ilpo Järvinen)

- Retain a reference to the pci_bus for the lifetime of a pci_slot to avoid
  a use-after-free when the thunderbolt driver resets USB4 host routers on
  boot, causing hotplug remove/add of downstream docks or other devices
  (Lukas Wunner)

* pci/hotplug:
  PCI: Fix use-after-free of slot->bus on hot remove
  PCI: cpqphp: Simplify PCI_ScanBusForNonBridge()
  PCI: cpqphp: Use define to read class/revision dword
  PCI: cpqphp: Use pci_bus_read_dev_vendor_id() to detect presence
  PCI: cpqphp: Fix PCIBIOS_* return value confusion
  PCI: cpqphp: Remove unused struct ctrl_dbg.ctrl
  PCI: cpcihp: Remove unused struct cpci_hp_controller_ops.hardware_test
This commit is contained in:
Bjorn Helgaas 2024-11-25 13:40:44 -06:00
commit dcd12456b3
4 changed files with 22 additions and 31 deletions

View File

@ -44,7 +44,6 @@ struct cpci_hp_controller_ops {
int (*enable_irq)(void);
int (*disable_irq)(void);
int (*check_irq)(void *dev_id);
int (*hardware_test)(struct slot *slot, u32 value);
u8 (*get_power)(struct slot *slot);
int (*set_power)(struct slot *slot, int value);
};

View File

@ -12,8 +12,11 @@
*
*/
#define pr_fmt(fmt) "cpqphp: " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@ -132,18 +135,6 @@ int cpqhp_unconfigure_device(struct pci_func *func)
return 0;
}
static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value)
{
u32 vendID = 0;
if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendID) == -1)
return -1;
if (PCI_POSSIBLE_ERROR(vendID))
return -1;
return pci_bus_read_config_dword(bus, devfn, offset, value);
}
/*
* cpqhp_set_irq
*
@ -202,13 +193,16 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 *dev_
{
u16 tdevice;
u32 work;
u8 tbus;
int ret = -1;
ctrl->pci_bus->number = bus_num;
for (tdevice = 0; tdevice < 0xFF; tdevice++) {
/* Scan for access first */
if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
if (!pci_bus_read_dev_vendor_id(ctrl->pci_bus, tdevice, &work, 0))
continue;
ret = pci_bus_read_config_dword(ctrl->pci_bus, tdevice, PCI_CLASS_REVISION, &work);
if (ret)
continue;
dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice);
/* Yep we got one. Not a bridge ? */
@ -216,23 +210,20 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 *dev_
*dev_num = tdevice;
dbg("found it !\n");
return 0;
}
}
for (tdevice = 0; tdevice < 0xFF; tdevice++) {
/* Scan for access first */
if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
continue;
dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice);
/* Yep we got one. bridge ? */
if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus);
/* XXX: no recursion, wtf? */
dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice);
return 0;
} else {
/*
* XXX: Code whose debug printout indicated
* recursion to buses underneath bridges might be
* necessary was removed because it never did
* any recursion.
*/
ret = 0;
pr_warn("missing feature: bridge scan recursion not implemented\n");
}
}
return -1;
return ret;
}

View File

@ -123,7 +123,6 @@ static int spew_debug_info(struct controller *ctrl, char *data, int size)
struct ctrl_dbg {
int size;
char *data;
struct controller *ctrl;
};
#define MAX_OUTPUT (4*PAGE_SIZE)

View File

@ -79,6 +79,7 @@ static void pci_slot_release(struct kobject *kobj)
up_read(&pci_bus_sem);
list_del(&slot->list);
pci_bus_put(slot->bus);
kfree(slot);
}
@ -261,7 +262,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
goto err;
}
slot->bus = parent;
slot->bus = pci_bus_get(parent);
slot->number = slot_nr;
slot->kobj.kset = pci_slots_kset;
@ -269,6 +270,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
slot_name = make_slot_name(name);
if (!slot_name) {
err = -ENOMEM;
pci_bus_put(slot->bus);
kfree(slot);
goto err;
}