Commit dc525311 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/enumeration'

- Split out ARI "next function" handling from the traditional one (Niklas
  Schnelle)

- Move jailhouse "isolated function" (non-zero functions where function 0
  doesn't exist) handling to pci_scan_slot() to avoid duplicating
  multi-function scanning in pci_scan_child_bus_extend() (Niklas Schnelle)

- Extend "isolated function" probing to s390 (Niklas Schnelle).

- Allow s390 zPCI zbus without a function 0 (Niklas Schnelle)

* pci/enumeration:
  s390/pci: allow zPCI zbus without a function zero
  PCI: Extend isolated function probing to s390
  PCI: Move jailhouse's isolated function handling to pci_scan_slot()
  PCI: Split out next_ari_fn() from next_fn()
  PCI: Clean up pci_scan_slot()
parents 49210431 960ac362
Loading
Loading
Loading
Loading
+20 −62
Original line number Diff line number Diff line
@@ -145,9 +145,6 @@ int zpci_bus_scan_bus(struct zpci_bus *zbus)
	struct zpci_dev *zdev;
	int devfn, rc, ret = 0;

	if (!zbus->function[0])
		return 0;

	for (devfn = 0; devfn < ZPCI_FUNCTIONS_PER_BUS; devfn++) {
		zdev = zbus->function[devfn];
		if (zdev && zdev->state == ZPCI_FN_STATE_CONFIGURED) {
@@ -184,26 +181,26 @@ void zpci_bus_scan_busses(void)

/* zpci_bus_create_pci_bus - Create the PCI bus associated with this zbus
 * @zbus: the zbus holding the zdevices
 * @f0: function 0 of the bus
 * @fr: PCI root function that will determine the bus's domain, and bus speeed
 * @ops: the pci operations
 *
 * Function zero is taken as a parameter as this is used to determine the
 * domain, multifunction property and maximum bus speed of the entire bus.
 * The PCI function @fr determines the domain (its UID), multifunction property
 * and maximum bus speed of the entire bus.
 *
 * Return: 0 on success, an error code otherwise
 */
static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *f0, struct pci_ops *ops)
static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, struct pci_ops *ops)
{
	struct pci_bus *bus;
	int domain;

	domain = zpci_alloc_domain((u16)f0->uid);
	domain = zpci_alloc_domain((u16)fr->uid);
	if (domain < 0)
		return domain;

	zbus->domain_nr = domain;
	zbus->multifunction = f0->rid_available;
	zbus->max_bus_speed = f0->max_bus_speed;
	zbus->multifunction = fr->rid_available;
	zbus->max_bus_speed = fr->max_bus_speed;

	/*
	 * Note that the zbus->resources are taken over and zbus->resources
@@ -303,47 +300,6 @@ void pcibios_bus_add_device(struct pci_dev *pdev)
	}
}

/* zpci_bus_create_hotplug_slots - Add hotplug slot(s) for device added to bus
 * @zdev: the zPCI device that was newly added
 *
 * Add the hotplug slot(s) for the newly added PCI function. Normally this is
 * simply the slot for the function itself. If however we are adding the
 * function 0 on a zbus, it might be that we already registered functions on
 * that zbus but could not create their hotplug slots yet so add those now too.
 *
 * Return: 0 on success, an error code otherwise
 */
static int zpci_bus_create_hotplug_slots(struct zpci_dev *zdev)
{
	struct zpci_bus *zbus = zdev->zbus;
	int devfn, rc = 0;

	rc = zpci_init_slot(zdev);
	if (rc)
		return rc;
	zdev->has_hp_slot = 1;

	if (zdev->devfn == 0 && zbus->multifunction) {
		/* Now that function 0 is there we can finally create the
		 * hotplug slots for those functions with devfn != 0 that have
		 * been parked in zbus->function[] waiting for us to be able to
		 * create the PCI bus.
		 */
		for  (devfn = 1; devfn < ZPCI_FUNCTIONS_PER_BUS; devfn++) {
			zdev = zbus->function[devfn];
			if (zdev && !zdev->has_hp_slot) {
				rc = zpci_init_slot(zdev);
				if (rc)
					return rc;
				zdev->has_hp_slot = 1;
			}
		}

	}

	return rc;
}

static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
{
	int rc = -EINVAL;
@@ -352,21 +308,19 @@ static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
		pr_err("devfn %04x is already assigned\n", zdev->devfn);
		return rc;
	}

	zdev->zbus = zbus;
	zbus->function[zdev->devfn] = zdev;
	zpci_nb_devices++;

	if (zbus->bus) {
	if (zbus->multifunction && !zdev->rid_available) {
		WARN_ONCE(1, "rid_available not set for multifunction\n");
		goto error;
	}

		zpci_bus_create_hotplug_slots(zdev);
	} else {
		/* Hotplug slot will be created once function 0 appears */
		zbus->multifunction = 1;
	}
	rc = zpci_init_slot(zdev);
	if (rc)
		goto error;
	zdev->has_hp_slot = 1;

	return 0;

@@ -400,7 +354,11 @@ int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
			return -ENOMEM;
	}

	if (zdev->devfn == 0) {
	if (!zbus->bus) {
		/* The UID of the first PCI function registered with a zpci_bus
		 * is used as the domain number for that bus. Currently there
		 * is exactly one zpci_bus per domain.
		 */
		rc = zpci_bus_create_pci_bus(zbus, zdev, ops);
		if (rc)
			goto error;
+41 −46
Original line number Diff line number Diff line
@@ -2579,33 +2579,39 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
}
EXPORT_SYMBOL(pci_scan_single_device);

static unsigned int next_fn(struct pci_bus *bus, struct pci_dev *dev,
			    unsigned int fn)
static int next_ari_fn(struct pci_bus *bus, struct pci_dev *dev, int fn)
{
	int pos;
	u16 cap = 0;
	unsigned int next_fn;

	if (pci_ari_enabled(bus)) {
	if (!dev)
			return 0;
		return -ENODEV;

	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
	if (!pos)
			return 0;
		return -ENODEV;

	pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap);
	next_fn = PCI_ARI_CAP_NFN(cap);
	if (next_fn <= fn)
			return 0;	/* protect against malformed list */
		return -ENODEV;	/* protect against malformed list */

	return next_fn;
}

	/* dev may be NULL for non-contiguous multifunction devices */
	if (!dev || dev->multifunction)
		return (fn + 1) % 8;
static int next_fn(struct pci_bus *bus, struct pci_dev *dev, int fn)
{
	if (pci_ari_enabled(bus))
		return next_ari_fn(bus, dev, fn);

	return 0;
	if (fn >= 7)
		return -ENODEV;
	/* only multifunction devices may have more functions */
	if (dev && !dev->multifunction)
		return -ENODEV;

	return fn + 1;
}

static int only_one_child(struct pci_bus *bus)
@@ -2643,26 +2649,30 @@ static int only_one_child(struct pci_bus *bus)
 */
int pci_scan_slot(struct pci_bus *bus, int devfn)
{
	unsigned int fn, nr = 0;
	struct pci_dev *dev;
	int fn = 0, nr = 0;

	if (only_one_child(bus) && (devfn > 0))
		return 0; /* Already scanned the entire slot */

	dev = pci_scan_single_device(bus, devfn);
	if (!dev)
		return 0;
	if (!pci_dev_is_added(dev))
		nr++;

	for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
	do {
		dev = pci_scan_single_device(bus, devfn + fn);
		if (dev) {
			if (!pci_dev_is_added(dev))
				nr++;
			if (fn > 0)
				dev->multifunction = 1;
		} else if (fn == 0) {
			/*
			 * Function 0 is required unless we are running on
			 * a hypervisor that passes through individual PCI
			 * functions.
			 */
			if (!hypervisor_isolated_pci_functions())
				break;
		}
	}
		fn = next_fn(bus, dev, fn);
	} while (fn >= 0);

	/* Only one slot has PCIe device */
	if (bus->self && nr)
@@ -2858,29 +2868,14 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
{
	unsigned int used_buses, normal_bridges = 0, hotplug_bridges = 0;
	unsigned int start = bus->busn_res.start;
	unsigned int devfn, fn, cmax, max = start;
	unsigned int devfn, cmax, max = start;
	struct pci_dev *dev;
	int nr_devs;

	dev_dbg(&bus->dev, "scanning bus\n");

	/* Go find them, Rover! */
	for (devfn = 0; devfn < 256; devfn += 8) {
		nr_devs = pci_scan_slot(bus, devfn);

		/*
		 * The Jailhouse hypervisor may pass individual functions of a
		 * multi-function device to a guest without passing function 0.
		 * Look for them as well.
		 */
		if (jailhouse_paravirt() && nr_devs == 0) {
			for (fn = 1; fn < 8; fn++) {
				dev = pci_scan_single_device(bus, devfn + fn);
				if (dev)
					dev->multifunction = 1;
			}
		}
	}
	for (devfn = 0; devfn < 256; devfn += 8)
		pci_scan_slot(bus, devfn);

	/* Reserve buses for SR-IOV capability */
	used_buses = pci_iov_bus_range(bus);
+8 −0
Original line number Diff line number Diff line
@@ -32,4 +32,12 @@ static inline bool jailhouse_paravirt(void)

#endif /* !CONFIG_X86 */

static inline bool hypervisor_isolated_pci_functions(void)
{
	if (IS_ENABLED(CONFIG_S390))
		return true;

	return jailhouse_paravirt();
}

#endif /* __LINUX_HYPEVISOR_H */