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

Commit fe99740c authored by Alex Chiang's avatar Alex Chiang Committed by Jesse Barnes
Browse files

PCI: construct one fakephp slot per PCI slot



Register one slot per slot, rather than one slot per function.  Change the
name of the slot to fake%d instead of the pci address.

Signed-off-by: default avatarAlex Chiang <achiang@hp.com>
Signed-off-by: default avatarMatthew Wilcox <matthew@wil.cx>
Cc: Greg KH <greg@kroah.com>
Cc: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Cc: Len Brown <lenb@kernel.org>
Cc: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 64dab204
Loading
Loading
Loading
Loading
+29 −55
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ struct dummy_slot {
	struct pci_dev *dev;
	struct work_struct remove_work;
	unsigned long removed;
	char name[8];
};

static int debug;
@@ -100,6 +101,7 @@ static int add_slot(struct pci_dev *dev)
	struct dummy_slot *dslot;
	struct hotplug_slot *slot;
	int retval = -ENOMEM;
	static int count = 1;

	slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
	if (!slot)
@@ -113,13 +115,13 @@ static int add_slot(struct pci_dev *dev)
	slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
	slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;

	slot->name = &dev->dev.bus_id[0];
	dbg("slot->name = %s\n", slot->name);

	dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
	if (!dslot)
		goto error_info;

	slot->name = dslot->name;
	snprintf(slot->name, sizeof(dslot->name), "fake%d", count++);
	dbg("slot->name = %s\n", slot->name);
	slot->ops = &dummy_hotplug_slot_ops;
	slot->release = &dummy_release;
	slot->private = dslot;
@@ -148,17 +150,17 @@ static int add_slot(struct pci_dev *dev)
static int __init pci_scan_buses(void)
{
	struct pci_dev *dev = NULL;
	int retval = 0;
	int lastslot = 0;

	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
		retval = add_slot(dev);
		if (retval) {
			pci_dev_put(dev);
			break;
		}
		if (PCI_FUNC(dev->devfn) > 0 &&
				lastslot == PCI_SLOT(dev->devfn))
			continue;
		lastslot = PCI_SLOT(dev->devfn);
		add_slot(dev);
	}

	return retval;
	return 0;
}

static void remove_slot(struct dummy_slot *dslot)
@@ -296,23 +298,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
	return 0;
}

/* find the hotplug_slot for the pci_dev */
static struct hotplug_slot *get_slot_from_dev(struct pci_dev *dev)
{
	struct dummy_slot *dslot;

	list_for_each_entry(dslot, &slot_list, node) {
		if (dslot->dev == dev)
			return dslot->slot;
	}
	return NULL;
}


static int disable_slot(struct hotplug_slot *slot)
{
	struct dummy_slot *dslot;
	struct hotplug_slot *hslot;
	struct pci_dev *dev;
	int func;

@@ -322,41 +310,27 @@ static int disable_slot(struct hotplug_slot *slot)

	dbg("%s - physical_slot = %s\n", __func__, slot->name);

	/* don't disable bridged devices just yet, we can't handle them easily... */
	if (dslot->dev->subordinate) {
		err("Can't remove PCI devices with other PCI devices behind it yet.\n");
		return -ENODEV;
	}
	for (func = 7; func >= 0; func--) {
		dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func);
		if (!dev)
			continue;

		if (test_and_set_bit(0, &dslot->removed)) {
			dbg("Slot already scheduled for removal\n");
			return -ENODEV;
		}
	/* search for subfunctions and disable them first */
	if (!(dslot->dev->devfn & 7)) {
		for (func = 1; func < 8; func++) {
			dev = pci_get_slot(dslot->dev->bus,
					dslot->dev->devfn + func);
			if (dev) {
				hslot = get_slot_from_dev(dev);
				if (hslot)
					disable_slot(hslot);
				else {
					err("Hotplug slot not found for subfunction of PCI device\n");
					return -ENODEV;
				}
				pci_dev_put(dev);
			} else
				dbg("No device in slot found\n");
		}
	}

	/* remove the device from the pci core */
	pci_remove_bus_device(dslot->dev);

	/* queue work item to blow away this sysfs entry and other parts. */
		/* queue work item to blow away this sysfs entry and other
		 * parts.
		 */
		INIT_WORK(&dslot->remove_work, remove_slot_worker);
		queue_work(dummyphp_wq, &dslot->remove_work);

		/* blow away this sysfs entry and other parts. */
		remove_slot(dslot);

		pci_dev_put(dev);
	}
	return 0;
}