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

Commit 3ec2574e authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/msi' into next

* pci/msi:
  PCI/MSI: Update MSI/MSI-X bits in PCIEBUS-HOWTO
  PCI/MSI: Document pci_alloc_irq_vectors(), deprecate pci_enable_msi()
  PCI/MSI: Return -ENOSPC if pci_enable_msi_range() can't get enough vectors
  PCI/portdrv: Use pci_irq_alloc_vectors()
  PCI/MSI: Check that we have a legacy interrupt line before using it
  PCI/MSI: Remove pci_msi_domain_{alloc,free}_irqs()
  PCI/MSI: Remove unused pci_msi_create_default_irq_domain()
  PCI/MSI: Return failure when msix_setup_entries() fails
  PCI/MSI: Remove pci_enable_msi_{exact,range}()
  amd-xgbe: Update PCI support to use new IRQ functions
  [media] cobalt: use pci_irq_allocate_vectors()
  PCI/MSI: Fix msi_capability_init() kernel-doc warnings
parents 906c1426 e4e7d597
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -162,8 +162,6 @@ The following old APIs to enable and disable MSI or MSI-X interrupts should
not be used in new code:

  pci_enable_msi()		/* deprecated */
  pci_enable_msi_range()	/* deprecated */
  pci_enable_msi_exact()	/* deprecated */
  pci_disable_msi()		/* deprecated */
  pci_enable_msix_range()	/* deprecated */
  pci_enable_msix_exact()	/* deprecated */
@@ -268,5 +266,5 @@ or disabled (0). If 0 is found in any of the msi_bus files belonging
to bridges between the PCI root and the device, MSIs are disabled.

It is also worth checking the device driver to see whether it supports MSIs.
For example, it may contain calls to pci_enable_msi_range() or
pci_enable_msix_range().
For example, it may contain calls to pci_irq_alloc_vectors() with the
PCI_IRQ_MSI or PCI_IRQ_MSIX flags.
+7 −26
Original line number Diff line number Diff line
@@ -161,21 +161,13 @@ Since all service drivers of a PCI-PCI Bridge Port device are
allowed to run simultaneously, below lists a few of possible resource
conflicts with proposed solutions.

6.1 MSI Vector Resource

The MSI capability structure enables a device software driver to call
pci_enable_msi to request MSI based interrupts. Once MSI interrupts
are enabled on a device, it stays in this mode until a device driver
calls pci_disable_msi to disable MSI interrupts and revert back to
INTx emulation mode. Since service drivers of the same PCI-PCI Bridge
port share the same physical device, if an individual service driver
calls pci_enable_msi/pci_disable_msi it may result unpredictable
behavior. For example, two service drivers run simultaneously on the
same physical Root Port. Both service drivers call pci_enable_msi to
request MSI based interrupts. A service driver may not know whether
any other service drivers have run on this Root Port. If either one
of them calls pci_disable_msi, it puts the other service driver
in a wrong interrupt mode.
6.1 MSI and MSI-X Vector Resource

Once MSI or MSI-X interrupts are enabled on a device, it stays in this
mode until they are disabled again.  Since service drivers of the same
PCI-PCI Bridge port share the same physical device, if an individual
service driver enables or disables MSI/MSI-X mode it may result
unpredictable behavior.

To avoid this situation all service drivers are not permitted to
switch interrupt mode on its device. The PCI Express Port Bus driver
@@ -187,17 +179,6 @@ driver. Service drivers should use (struct pcie_device*)dev->irq to
call request_irq/free_irq. In addition, the interrupt mode is stored
in the field interrupt_mode of struct pcie_device.

6.2 MSI-X Vector Resources

Similar to the MSI a device driver for an MSI-X capable device can
call pci_enable_msix to request MSI-X interrupts. All service drivers
are not permitted to switch interrupt mode on its device. The PCI
Express Port Bus driver is responsible for determining the interrupt
mode and this should be transparent to service drivers. Any attempt
by service driver to call pci_enable_msix/pci_disable_msix may
result unpredictable behavior. Service drivers should use
(struct pcie_device*)dev->irq and call request_irq/free_irq.

6.3 PCI Memory/IO Mapped Regions

Service drivers for PCI Express Power Management (PME), Advanced
+12 −12
Original line number Diff line number Diff line
@@ -382,18 +382,18 @@ The fundamental difference between MSI and MSI-X is how multiple
"vectors" get allocated. MSI requires contiguous blocks of vectors
while MSI-X can allocate several individual ones.

MSI capability can be enabled by calling pci_enable_msi() or
pci_enable_msix() before calling request_irq(). This causes
the PCI support to program CPU vector data into the PCI device
capability registers.

If your PCI device supports both, try to enable MSI-X first.
Only one can be enabled at a time.  Many architectures, chip-sets,
or BIOSes do NOT support MSI or MSI-X and the call to pci_enable_msi/msix
will fail. This is important to note since many drivers have
two (or more) interrupt handlers: one for MSI/MSI-X and another for IRQs.
They choose which handler to register with request_irq() based on the
return value from pci_enable_msi/msix().
MSI capability can be enabled by calling pci_alloc_irq_vectors() with the
PCI_IRQ_MSI and/or PCI_IRQ_MSIX flags before calling request_irq(). This
causes the PCI support to program CPU vector data into the PCI device
capability registers. Many architectures, chip-sets, or BIOSes do NOT
support MSI or MSI-X and a call to pci_alloc_irq_vectors with just
the PCI_IRQ_MSI and PCI_IRQ_MSIX flags will fail, so try to always
specify PCI_IRQ_LEGACY as well.

Drivers that have different interrupt handlers for MSI/MSI-X and
legacy INTx should chose the right one based on the msi_enabled
and msix_enabled flags in the pci_dev structure after calling
pci_alloc_irq_vectors.

There are (at least) two really good reasons for using MSI:
1) MSI is an exclusive interrupt vector by definition.
+1 −1
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
	if (domain == NULL)
		return -ENOSYS;

	return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
	return msi_domain_alloc_irqs(domain, &dev->dev, nvec);
}

void native_teardown_msi_irq(unsigned int irq)
+2 −6
Original line number Diff line number Diff line
@@ -308,9 +308,7 @@ static void cobalt_pci_iounmap(struct cobalt *cobalt, struct pci_dev *pci_dev)
static void cobalt_free_msi(struct cobalt *cobalt, struct pci_dev *pci_dev)
{
	free_irq(pci_dev->irq, (void *)cobalt);

	if (cobalt->msi_enabled)
		pci_disable_msi(pci_dev);
	pci_free_irq_vectors(pci_dev);
}

static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev,
@@ -387,14 +385,12 @@ static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev,
	   from being generated. */
	cobalt_set_interrupt(cobalt, false);

	if (pci_enable_msi_range(pci_dev, 1, 1) < 1) {
	if (pci_alloc_irq_vectors(pci_dev, 1, 1, PCI_IRQ_MSI) < 1) {
		cobalt_err("Could not enable MSI\n");
		cobalt->msi_enabled = false;
		ret = -EIO;
		goto err_release;
	}
	msi_config_show(cobalt, pci_dev);
	cobalt->msi_enabled = true;

	/* Register IRQ */
	if (request_irq(pci_dev->irq, cobalt_irq_handler, IRQF_SHARED,
Loading