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

Commit a4b88505 authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by Bjorn Helgaas
Browse files

Merge branch 'pci/virtualization'

  - probe for device reset support during enumeration instead of runtime
    (Bjorn Helgaas)

  - add ACS quirk for Ampere (née APM) root ports (Feng Kan)

  - add function 1 DMA alias quirk for Marvell 88SE9220 (Thomas
    Vincent-Cross)

  - protect device restore with device lock (Sinan Kaya)

  - handle failure of FLR gracefully (Sinan Kaya)

  - handle CRS (config retry status) after device resets (Sinan Kaya)

  - skip various config reads for SR-IOV VFs as an optimization (KarimAllah
    Ahmed)

* pci/virtualization:
  PCI/IOV: Add missing prototypes for powerpc pcibios interfaces
  PCI/IOV: Use VF0 cached config registers for other VFs
  PCI/IOV: Skip BAR sizing for VFs
  PCI/IOV: Skip INTx config reads for VFs
  PCI: Wait for device to become ready after secondary bus reset
  PCI: Add a return type for pci_reset_bridge_secondary_bus()
  PCI: Wait for device to become ready after a power management reset
  PCI: Rename pci_flr_wait() to pci_dev_wait() and make it generic
  PCI: Handle FLR failure and allow other reset types
  PCI: Protect restore with device lock to be consistent
  PCI: Add function 1 DMA alias quirk for Marvell 88SE9220
  PCI: Add ACS quirk for Ampere root ports
  PCI: Remove redundant probes for device reset support
  PCI: Probe for device reset support during enumeration

Conflicts:
	include/linux/pci.h
parents 0eb6de78 619e6f34
Loading
Loading
Loading
Loading
+35 −7
Original line number Original line Diff line number Diff line
@@ -112,6 +112,29 @@ resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
	return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
	return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
}
}


static void pci_read_vf_config_common(struct pci_dev *virtfn)
{
	struct pci_dev *physfn = virtfn->physfn;

	/*
	 * Some config registers are the same across all associated VFs.
	 * Read them once from VF0 so we can skip reading them from the
	 * other VFs.
	 *
	 * PCIe r4.0, sec 9.3.4.1, technically doesn't require all VFs to
	 * have the same Revision ID and Subsystem ID, but we assume they
	 * do.
	 */
	pci_read_config_dword(virtfn, PCI_CLASS_REVISION,
			      &physfn->sriov->class);
	pci_read_config_byte(virtfn, PCI_HEADER_TYPE,
			     &physfn->sriov->hdr_type);
	pci_read_config_word(virtfn, PCI_SUBSYSTEM_VENDOR_ID,
			     &physfn->sriov->subsystem_vendor);
	pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID,
			     &physfn->sriov->subsystem_device);
}

int pci_iov_add_virtfn(struct pci_dev *dev, int id)
int pci_iov_add_virtfn(struct pci_dev *dev, int id)
{
{
	int i;
	int i;
@@ -134,13 +157,17 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
	virtfn->devfn = pci_iov_virtfn_devfn(dev, id);
	virtfn->devfn = pci_iov_virtfn_devfn(dev, id);
	virtfn->vendor = dev->vendor;
	virtfn->vendor = dev->vendor;
	virtfn->device = iov->vf_device;
	virtfn->device = iov->vf_device;
	virtfn->is_virtfn = 1;
	virtfn->physfn = pci_dev_get(dev);

	if (id == 0)
		pci_read_vf_config_common(virtfn);

	rc = pci_setup_device(virtfn);
	rc = pci_setup_device(virtfn);
	if (rc)
	if (rc)
		goto failed0;
		goto failed1;


	virtfn->dev.parent = dev->dev.parent;
	virtfn->dev.parent = dev->dev.parent;
	virtfn->physfn = pci_dev_get(dev);
	virtfn->is_virtfn = 1;
	virtfn->multifunction = 0;
	virtfn->multifunction = 0;


	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
@@ -161,10 +188,10 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
	sprintf(buf, "virtfn%u", id);
	sprintf(buf, "virtfn%u", id);
	rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
	rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
	if (rc)
	if (rc)
		goto failed1;
		goto failed2;
	rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn");
	rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn");
	if (rc)
	if (rc)
		goto failed2;
		goto failed3;


	kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);
	kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);


@@ -172,11 +199,12 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)


	return 0;
	return 0;


failed2:
failed3:
	sysfs_remove_link(&dev->dev.kobj, buf);
	sysfs_remove_link(&dev->dev.kobj, buf);
failed2:
	pci_stop_and_remove_bus_device(virtfn);
failed1:
failed1:
	pci_dev_put(dev);
	pci_dev_put(dev);
	pci_stop_and_remove_bus_device(virtfn);
failed0:
failed0:
	virtfn_remove_bus(dev->bus, bus);
	virtfn_remove_bus(dev->bus, bus);
failed:
failed:
+1 −2
Original line number Original line Diff line number Diff line
@@ -1515,11 +1515,10 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
	/* Active State Power Management */
	/* Active State Power Management */
	pcie_aspm_create_sysfs_dev_files(dev);
	pcie_aspm_create_sysfs_dev_files(dev);


	if (!pci_probe_reset_function(dev)) {
	if (dev->reset_fn) {
		retval = device_create_file(&dev->dev, &reset_attr);
		retval = device_create_file(&dev->dev, &reset_attr);
		if (retval)
		if (retval)
			goto error;
			goto error;
		dev->reset_fn = 1;
	}
	}
	return 0;
	return 0;


+51 −34
Original line number Original line Diff line number Diff line
@@ -127,6 +127,9 @@ static int __init pcie_port_pm_setup(char *str)
}
}
__setup("pcie_port_pm=", pcie_port_pm_setup);
__setup("pcie_port_pm=", pcie_port_pm_setup);


/* Time to wait after a reset for device to become responsive */
#define PCIE_RESET_READY_POLL_MS 60000

/**
/**
 * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
 * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
 * @bus: pointer to PCI bus structure to search
 * @bus: pointer to PCI bus structure to search
@@ -3969,20 +3972,13 @@ int pci_wait_for_pending_transaction(struct pci_dev *dev)
}
}
EXPORT_SYMBOL(pci_wait_for_pending_transaction);
EXPORT_SYMBOL(pci_wait_for_pending_transaction);


static void pci_flr_wait(struct pci_dev *dev)
static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
{
{
	int delay = 1, timeout = 60000;
	int delay = 1;
	u32 id;
	u32 id;


	/*
	/*
	 * Per PCIe r3.1, sec 6.6.2, a device must complete an FLR within
	 * After reset, the device should not silently discard config
	 * 100ms, but may silently discard requests while the FLR is in
	 * progress.  Wait 100ms before trying to access the device.
	 */
	msleep(100);

	/*
	 * After 100ms, the device should not silently discard config
	 * requests, but it may still indicate that it needs more time by
	 * requests, but it may still indicate that it needs more time by
	 * responding to them with CRS completions.  The Root Port will
	 * responding to them with CRS completions.  The Root Port will
	 * generally synthesize ~0 data to complete the read (except when
	 * generally synthesize ~0 data to complete the read (except when
@@ -3996,14 +3992,14 @@ static void pci_flr_wait(struct pci_dev *dev)
	pci_read_config_dword(dev, PCI_COMMAND, &id);
	pci_read_config_dword(dev, PCI_COMMAND, &id);
	while (id == ~0) {
	while (id == ~0) {
		if (delay > timeout) {
		if (delay > timeout) {
			pci_warn(dev, "not ready %dms after FLR; giving up\n",
			pci_warn(dev, "not ready %dms after %s; giving up\n",
				 100 + delay - 1);
				 delay - 1, reset_type);
			return;
			return -ENOTTY;
		}
		}


		if (delay > 1000)
		if (delay > 1000)
			pci_info(dev, "not ready %dms after FLR; waiting\n",
			pci_info(dev, "not ready %dms after %s; waiting\n",
				 100 + delay - 1);
				 delay - 1, reset_type);


		msleep(delay);
		msleep(delay);
		delay *= 2;
		delay *= 2;
@@ -4011,7 +4007,10 @@ static void pci_flr_wait(struct pci_dev *dev)
	}
	}


	if (delay > 1000)
	if (delay > 1000)
		pci_info(dev, "ready %dms after FLR\n", 100 + delay - 1);
		pci_info(dev, "ready %dms after %s\n", delay - 1,
			 reset_type);

	return 0;
}
}


/**
/**
@@ -4040,13 +4039,21 @@ static bool pcie_has_flr(struct pci_dev *dev)
 * device supports FLR before calling this function, e.g. by using the
 * device supports FLR before calling this function, e.g. by using the
 * pcie_has_flr() helper.
 * pcie_has_flr() helper.
 */
 */
void pcie_flr(struct pci_dev *dev)
int pcie_flr(struct pci_dev *dev)
{
{
	if (!pci_wait_for_pending_transaction(dev))
	if (!pci_wait_for_pending_transaction(dev))
		pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
		pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");


	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
	pci_flr_wait(dev);

	/*
	 * Per PCIe r4.0, sec 6.6.2, a device must complete an FLR within
	 * 100ms, but may silently discard requests while the FLR is in
	 * progress.  Wait 100ms before trying to access the device.
	 */
	msleep(100);

	return pci_dev_wait(dev, "FLR", PCIE_RESET_READY_POLL_MS);
}
}
EXPORT_SYMBOL_GPL(pcie_flr);
EXPORT_SYMBOL_GPL(pcie_flr);


@@ -4079,8 +4086,16 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
		pci_err(dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
		pci_err(dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");


	pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
	pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
	pci_flr_wait(dev);

	return 0;
	/*
	 * Per Advanced Capabilities for Conventional PCI ECN, 13 April 2006,
	 * updated 27 July 2006; a device must complete an FLR within
	 * 100ms, but may silently discard requests while the FLR is in
	 * progress.  Wait 100ms before trying to access the device.
	 */
	msleep(100);

	return pci_dev_wait(dev, "AF_FLR", PCIE_RESET_READY_POLL_MS);
}
}


/**
/**
@@ -4125,7 +4140,7 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
	pci_dev_d3_sleep(dev);
	pci_dev_d3_sleep(dev);


	return 0;
	return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS);
}
}


void pci_reset_secondary_bus(struct pci_dev *dev)
void pci_reset_secondary_bus(struct pci_dev *dev)
@@ -4167,9 +4182,11 @@ void __weak pcibios_reset_secondary_bus(struct pci_dev *dev)
 * Use the bridge control register to assert reset on the secondary bus.
 * Use the bridge control register to assert reset on the secondary bus.
 * Devices on the secondary bus are left in power-on state.
 * Devices on the secondary bus are left in power-on state.
 */
 */
void pci_reset_bridge_secondary_bus(struct pci_dev *dev)
int pci_reset_bridge_secondary_bus(struct pci_dev *dev)
{
{
	pcibios_reset_secondary_bus(dev);
	pcibios_reset_secondary_bus(dev);

	return pci_dev_wait(dev, "bus reset", PCIE_RESET_READY_POLL_MS);
}
}
EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus);
EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus);


@@ -4332,8 +4349,9 @@ int __pci_reset_function_locked(struct pci_dev *dev)
	if (rc != -ENOTTY)
	if (rc != -ENOTTY)
		return rc;
		return rc;
	if (pcie_has_flr(dev)) {
	if (pcie_has_flr(dev)) {
		pcie_flr(dev);
		rc = pcie_flr(dev);
		return 0;
		if (rc != -ENOTTY)
			return rc;
	}
	}
	rc = pci_af_flr(dev, 0);
	rc = pci_af_flr(dev, 0);
	if (rc != -ENOTTY)
	if (rc != -ENOTTY)
@@ -4403,9 +4421,8 @@ int pci_reset_function(struct pci_dev *dev)
{
{
	int rc;
	int rc;


	rc = pci_probe_reset_function(dev);
	if (!dev->reset_fn)
	if (rc)
		return -ENOTTY;
		return rc;


	pci_dev_lock(dev);
	pci_dev_lock(dev);
	pci_dev_save_and_disable(dev);
	pci_dev_save_and_disable(dev);
@@ -4440,9 +4457,8 @@ int pci_reset_function_locked(struct pci_dev *dev)
{
{
	int rc;
	int rc;


	rc = pci_probe_reset_function(dev);
	if (!dev->reset_fn)
	if (rc)
		return -ENOTTY;
		return rc;


	pci_dev_save_and_disable(dev);
	pci_dev_save_and_disable(dev);


@@ -4464,18 +4480,17 @@ int pci_try_reset_function(struct pci_dev *dev)
{
{
	int rc;
	int rc;


	rc = pci_probe_reset_function(dev);
	if (!dev->reset_fn)
	if (rc)
		return -ENOTTY;
		return rc;


	if (!pci_dev_trylock(dev))
	if (!pci_dev_trylock(dev))
		return -EAGAIN;
		return -EAGAIN;


	pci_dev_save_and_disable(dev);
	pci_dev_save_and_disable(dev);
	rc = __pci_reset_function_locked(dev);
	rc = __pci_reset_function_locked(dev);
	pci_dev_restore(dev);
	pci_dev_unlock(dev);
	pci_dev_unlock(dev);


	pci_dev_restore(dev);
	return rc;
	return rc;
}
}
EXPORT_SYMBOL_GPL(pci_try_reset_function);
EXPORT_SYMBOL_GPL(pci_try_reset_function);
@@ -4683,7 +4698,9 @@ static void pci_slot_restore(struct pci_slot *slot)
	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
		if (!dev->slot || dev->slot != slot)
		if (!dev->slot || dev->slot != slot)
			continue;
			continue;
		pci_dev_lock(dev);
		pci_dev_restore(dev);
		pci_dev_restore(dev);
		pci_dev_unlock(dev);
		if (dev->subordinate)
		if (dev->subordinate)
			pci_bus_restore(dev->subordinate);
			pci_bus_restore(dev->subordinate);
	}
	}
+4 −0
Original line number Original line Diff line number Diff line
@@ -293,6 +293,10 @@ struct pci_sriov {
	u16		driver_max_VFs;	/* Max num VFs driver supports */
	u16		driver_max_VFs;	/* Max num VFs driver supports */
	struct pci_dev	*dev;		/* Lowest numbered PF */
	struct pci_dev	*dev;		/* Lowest numbered PF */
	struct pci_dev	*self;		/* This PF */
	struct pci_dev	*self;		/* This PF */
	u32		class;		/* VF device */
	u8		hdr_type;	/* VF header type */
	u16		subsystem_vendor; /* VF subsystem vendor */
	u16		subsystem_device; /* VF subsystem device */
	resource_size_t	barsz[PCI_SRIOV_NUM_BARS];	/* VF BAR size */
	resource_size_t	barsz[PCI_SRIOV_NUM_BARS];	/* VF BAR size */
	bool		drivers_autoprobe; /* Auto probing of VFs by driver */
	bool		drivers_autoprobe; /* Auto probing of VFs by driver */
};
};
+56 −5
Original line number Original line Diff line number Diff line
@@ -329,6 +329,10 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
	if (dev->non_compliant_bars)
	if (dev->non_compliant_bars)
		return;
		return;


	/* Per PCIe r4.0, sec 9.3.4.1.11, the VF BARs are all RO Zero */
	if (dev->is_virtfn)
		return;

	for (pos = 0; pos < howmany; pos++) {
	for (pos = 0; pos < howmany; pos++) {
		struct resource *res = &dev->resource[pos];
		struct resource *res = &dev->resource[pos];
		reg = PCI_BASE_ADDRESS_0 + (pos << 2);
		reg = PCI_BASE_ADDRESS_0 + (pos << 2);
@@ -1240,6 +1244,13 @@ static void pci_read_irq(struct pci_dev *dev)
{
{
	unsigned char irq;
	unsigned char irq;


	/* VFs are not allowed to use INTx, so skip the config reads */
	if (dev->is_virtfn) {
		dev->pin = 0;
		dev->irq = 0;
		return;
	}

	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
	dev->pin = irq;
	dev->pin = irq;
	if (irq)
	if (irq)
@@ -1399,6 +1410,43 @@ int pci_cfg_space_size(struct pci_dev *dev)
	return PCI_CFG_SPACE_SIZE;
	return PCI_CFG_SPACE_SIZE;
}
}


static u32 pci_class(struct pci_dev *dev)
{
	u32 class;

#ifdef CONFIG_PCI_IOV
	if (dev->is_virtfn)
		return dev->physfn->sriov->class;
#endif
	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
	return class;
}

static void pci_subsystem_ids(struct pci_dev *dev, u16 *vendor, u16 *device)
{
#ifdef CONFIG_PCI_IOV
	if (dev->is_virtfn) {
		*vendor = dev->physfn->sriov->subsystem_vendor;
		*device = dev->physfn->sriov->subsystem_device;
		return;
	}
#endif
	pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, vendor);
	pci_read_config_word(dev, PCI_SUBSYSTEM_ID, device);
}

static u8 pci_hdr_type(struct pci_dev *dev)
{
	u8 hdr_type;

#ifdef CONFIG_PCI_IOV
	if (dev->is_virtfn)
		return dev->physfn->sriov->hdr_type;
#endif
	pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);
	return hdr_type;
}

#define LEGACY_IO_RESOURCE	(IORESOURCE_IO | IORESOURCE_PCI_FIXED)
#define LEGACY_IO_RESOURCE	(IORESOURCE_IO | IORESOURCE_PCI_FIXED)


static void pci_msi_setup_pci_dev(struct pci_dev *dev)
static void pci_msi_setup_pci_dev(struct pci_dev *dev)
@@ -1464,8 +1512,7 @@ int pci_setup_device(struct pci_dev *dev)
	struct pci_bus_region region;
	struct pci_bus_region region;
	struct resource *res;
	struct resource *res;


	if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
	hdr_type = pci_hdr_type(dev);
		return -EIO;


	dev->sysdata = dev->bus->sysdata;
	dev->sysdata = dev->bus->sysdata;
	dev->dev.parent = dev->bus->bridge;
	dev->dev.parent = dev->bus->bridge;
@@ -1487,7 +1534,8 @@ int pci_setup_device(struct pci_dev *dev)
		     dev->bus->number, PCI_SLOT(dev->devfn),
		     dev->bus->number, PCI_SLOT(dev->devfn),
		     PCI_FUNC(dev->devfn));
		     PCI_FUNC(dev->devfn));


	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
	class = pci_class(dev);

	dev->revision = class & 0xff;
	dev->revision = class & 0xff;
	dev->class = class >> 8;		    /* upper 3 bytes */
	dev->class = class >> 8;		    /* upper 3 bytes */


@@ -1527,8 +1575,8 @@ int pci_setup_device(struct pci_dev *dev)
			goto bad;
			goto bad;
		pci_read_irq(dev);
		pci_read_irq(dev);
		pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
		pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
		pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);

		pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
		pci_subsystem_ids(dev, &dev->subsystem_vendor, &dev->subsystem_device);


		/*
		/*
		 * Do the ugly legacy mode stuff here rather than broken chip
		 * Do the ugly legacy mode stuff here rather than broken chip
@@ -2131,6 +2179,9 @@ static void pci_init_capabilities(struct pci_dev *dev)


	/* Advanced Error Reporting */
	/* Advanced Error Reporting */
	pci_aer_init(dev);
	pci_aer_init(dev);

	if (pci_probe_reset_function(dev) == 0)
		dev->reset_fn = 1;
}
}


/*
/*
Loading