Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 017ffe64 authored by Yijing Wang's avatar Yijing Wang Committed by Bjorn Helgaas
Browse files

PCI: Hold pci_slot_mutex while searching bus->slots list



Previously, pci_setup_device() and similar functions searched the
pci_bus->slots list without any locking.  It was possible for another
thread to update the list while we searched it.

Add pci_dev_assign_slot() to search the list while holding pci_slot_mutex.

[bhelgaas: changelog, fold in CONFIG_SYSFS fix]
Tested-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarYijing Wang <wangyijing@huawei.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 67546762
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -126,7 +126,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
{
	struct pci_dev *dev;
	const char *type;
	struct pci_slot *slot;

	dev = pci_alloc_dev(bus);
	if (!dev)
@@ -145,10 +144,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
	dev->needs_freset = 0;		/* pcie fundamental reset required */
	set_pcie_port_type(dev);

	list_for_each_entry(slot, &dev->bus->slots, list)
		if (PCI_SLOT(dev->devfn) == slot->number)
			dev->slot = slot;

	pci_dev_assign_slot(dev);
	dev->vendor = get_int_prop(node, "vendor-id", 0xffff);
	dev->device = get_int_prop(node, "device-id", 0xffff);
	dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0);
+1 −5
Original line number Diff line number Diff line
@@ -249,7 +249,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
					 struct pci_bus *bus, int devfn)
{
	struct dev_archdata *sd;
	struct pci_slot *slot;
	struct platform_device *op;
	struct pci_dev *dev;
	const char *type;
@@ -290,10 +289,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
	dev->multifunction = 0;		/* maybe a lie? */
	set_pcie_port_type(dev);

	list_for_each_entry(slot, &dev->bus->slots, list)
		if (PCI_SLOT(dev->devfn) == slot->number)
			dev->slot = slot;

	pci_dev_assign_slot(dev);
	dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
	dev->device = of_getintprop_default(node, "device-id", 0xffff);
	dev->subsystem_vendor =
+1 −5
Original line number Diff line number Diff line
@@ -1133,7 +1133,6 @@ int pci_setup_device(struct pci_dev *dev)
{
	u32 class;
	u8 hdr_type;
	struct pci_slot *slot;
	int pos = 0;
	struct pci_bus_region region;
	struct resource *res;
@@ -1149,10 +1148,7 @@ int pci_setup_device(struct pci_dev *dev)
	dev->error_state = pci_channel_io_normal;
	set_pcie_port_type(dev);

	list_for_each_entry(slot, &dev->bus->slots, list)
		if (PCI_SLOT(dev->devfn) == slot->number)
			dev->slot = slot;

	pci_dev_assign_slot(dev);
	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
	   set this higher, assuming the system even supports it.  */
	dev->dma_mask = 0xffffffff;
+11 −0
Original line number Diff line number Diff line
@@ -194,6 +194,17 @@ static int rename_slot(struct pci_slot *slot, const char *name)
	return result;
}

void pci_dev_assign_slot(struct pci_dev *dev)
{
	struct pci_slot *slot;

	mutex_lock(&pci_slot_mutex);
	list_for_each_entry(slot, &dev->bus->slots, list)
		if (PCI_SLOT(dev->devfn) == slot->number)
			dev->slot = slot;
	mutex_unlock(&pci_slot_mutex);
}

static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
{
	struct pci_slot *slot;
+5 −0
Original line number Diff line number Diff line
@@ -798,6 +798,11 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
				 const char *name,
				 struct hotplug_slot *hotplug);
void pci_destroy_slot(struct pci_slot *slot);
#ifdef CONFIG_SYSFS
void pci_dev_assign_slot(struct pci_dev *dev);
#else
static inline void pci_dev_assign_slot(struct pci_dev *dev) { }
#endif
int pci_scan_slot(struct pci_bus *bus, int devfn);
struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn);
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);