Skip to content

Commit

Permalink
Merge tag 'pci-v4.8-fixes-1' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/helgaas/pci

Pull PCI fixes from Bjorn Helgaas:
 "Resource management:
   - Update "pci=resource_alignment" documentation (Mathias Koehrer)

  MSI:
   - Use positive flags in pci_alloc_irq_vectors() (Christoph Hellwig)
   - Call pci_intx() when using legacy interrupts in pci_alloc_irq_vectors() (Christoph Hellwig)

  Intel VMD host bridge driver:
   - Fix infinite loop executing irq's (Keith Busch)"

* tag 'pci-v4.8-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
  x86/PCI: VMD: Fix infinite loop executing irq's
  PCI: Call pci_intx() when using legacy interrupts in pci_alloc_irq_vectors()
  PCI: Use positive flags in pci_alloc_irq_vectors()
  PCI: Update "pci=resource_alignment" documentation
  • Loading branch information
torvalds committed Aug 27, 2016
2 parents 61c0457 + 21c80c9 commit 219c04c
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 28 deletions.
24 changes: 10 additions & 14 deletions Documentation/PCI/MSI-HOWTO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,11 @@ has a requirements for a minimum number of vectors the driver can pass a
min_vecs argument set to this limit, and the PCI core will return -ENOSPC
if it can't meet the minimum number of vectors.

The flags argument should normally be set to 0, but can be used to pass the
PCI_IRQ_NOMSI and PCI_IRQ_NOMSIX flag in case a device claims to support
MSI or MSI-X, but the support is broken, or to pass PCI_IRQ_NOLEGACY in
case the device does not support legacy interrupt lines.

By default this function will spread the interrupts around the available
CPUs, but this feature can be disabled by passing the PCI_IRQ_NOAFFINITY
flag.
The flags argument is used to specify which type of interrupt can be used
by the device and the driver (PCI_IRQ_LEGACY, PCI_IRQ_MSI, PCI_IRQ_MSIX).
A convenient short-hand (PCI_IRQ_ALL_TYPES) is also available to ask for
any possible kind of interrupt. If the PCI_IRQ_AFFINITY flag is set,
pci_alloc_irq_vectors() will spread the interrupts around the available CPUs.

To get the Linux IRQ numbers passed to request_irq() and free_irq() and the
vectors, use the following function:
Expand Down Expand Up @@ -131,7 +128,7 @@ larger than the number supported by the device it will automatically be
capped to the supported limit, so there is no need to query the number of
vectors supported beforehand:

nvec = pci_alloc_irq_vectors(pdev, 1, nvec, 0);
nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_ALL_TYPES)
if (nvec < 0)
goto out_err;

Expand All @@ -140,23 +137,22 @@ interrupts it can request a particular number of interrupts by passing that
number to pci_alloc_irq_vectors() function as both 'min_vecs' and
'max_vecs' parameters:

ret = pci_alloc_irq_vectors(pdev, nvec, nvec, 0);
ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_ALL_TYPES);
if (ret < 0)
goto out_err;

The most notorious example of the request type described above is enabling
the single MSI mode for a device. It could be done by passing two 1s as
'min_vecs' and 'max_vecs':

ret = pci_alloc_irq_vectors(pdev, 1, 1, 0);
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
if (ret < 0)
goto out_err;

Some devices might not support using legacy line interrupts, in which case
the PCI_IRQ_NOLEGACY flag can be used to fail the request if the platform
can't provide MSI or MSI-X interrupts:
the driver can specify that only MSI or MSI-X is acceptable:

nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_NOLEGACY);
nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_MSI | PCI_IRQ_MSIX);
if (nvec < 0)
goto out_err;

Expand Down
4 changes: 4 additions & 0 deletions Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3032,6 +3032,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
PAGE_SIZE is used as alignment.
PCI-PCI bridge can be specified, if resource
windows need to be expanded.
To specify the alignment for several
instances of a device, the PCI vendor,
device, subvendor, and subdevice may be
specified, e.g., 4096@pci:8086:9c22:103c:198f
ecrc= Enable/disable PCIe ECRC (transaction layer
end-to-end CRC checking).
bios: Use BIOS/firmware settings. This is the
Expand Down
10 changes: 8 additions & 2 deletions arch/x86/pci/vmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ static DEFINE_RAW_SPINLOCK(list_lock);
* @node: list item for parent traversal.
* @rcu: RCU callback item for freeing.
* @irq: back pointer to parent.
* @enabled: true if driver enabled IRQ
* @virq: the virtual IRQ value provided to the requesting driver.
*
* Every MSI/MSI-X IRQ requested for a device in a VMD domain will be mapped to
Expand All @@ -50,6 +51,7 @@ struct vmd_irq {
struct list_head node;
struct rcu_head rcu;
struct vmd_irq_list *irq;
bool enabled;
unsigned int virq;
};

Expand Down Expand Up @@ -122,7 +124,9 @@ static void vmd_irq_enable(struct irq_data *data)
unsigned long flags;

raw_spin_lock_irqsave(&list_lock, flags);
WARN_ON(vmdirq->enabled);
list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
vmdirq->enabled = true;
raw_spin_unlock_irqrestore(&list_lock, flags);

data->chip->irq_unmask(data);
Expand All @@ -136,8 +140,10 @@ static void vmd_irq_disable(struct irq_data *data)
data->chip->irq_mask(data);

raw_spin_lock_irqsave(&list_lock, flags);
list_del_rcu(&vmdirq->node);
INIT_LIST_HEAD_RCU(&vmdirq->node);
if (vmdirq->enabled) {
list_del_rcu(&vmdirq->node);
vmdirq->enabled = false;
}
raw_spin_unlock_irqrestore(&list_lock, flags);
}

Expand Down
18 changes: 10 additions & 8 deletions drivers/pci/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1069,7 +1069,7 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
nvec = maxvec;

for (;;) {
if (!(flags & PCI_IRQ_NOAFFINITY)) {
if (flags & PCI_IRQ_AFFINITY) {
dev->irq_affinity = irq_create_affinity_mask(&nvec);
if (nvec < minvec)
return -ENOSPC;
Expand Down Expand Up @@ -1105,7 +1105,7 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
**/
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
{
return __pci_enable_msi_range(dev, minvec, maxvec, PCI_IRQ_NOAFFINITY);
return __pci_enable_msi_range(dev, minvec, maxvec, 0);
}
EXPORT_SYMBOL(pci_enable_msi_range);

Expand All @@ -1120,7 +1120,7 @@ static int __pci_enable_msix_range(struct pci_dev *dev,
return -ERANGE;

for (;;) {
if (!(flags & PCI_IRQ_NOAFFINITY)) {
if (flags & PCI_IRQ_AFFINITY) {
dev->irq_affinity = irq_create_affinity_mask(&nvec);
if (nvec < minvec)
return -ENOSPC;
Expand Down Expand Up @@ -1160,8 +1160,7 @@ static int __pci_enable_msix_range(struct pci_dev *dev,
int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
int minvec, int maxvec)
{
return __pci_enable_msix_range(dev, entries, minvec, maxvec,
PCI_IRQ_NOAFFINITY);
return __pci_enable_msix_range(dev, entries, minvec, maxvec, 0);
}
EXPORT_SYMBOL(pci_enable_msix_range);

Expand All @@ -1187,22 +1186,25 @@ int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
{
int vecs = -ENOSPC;

if (!(flags & PCI_IRQ_NOMSIX)) {
if (flags & PCI_IRQ_MSIX) {
vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs,
flags);
if (vecs > 0)
return vecs;
}

if (!(flags & PCI_IRQ_NOMSI)) {
if (flags & PCI_IRQ_MSI) {
vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, flags);
if (vecs > 0)
return vecs;
}

/* use legacy irq if allowed */
if (!(flags & PCI_IRQ_NOLEGACY) && min_vecs == 1)
if ((flags & PCI_IRQ_LEGACY) && min_vecs == 1) {
pci_intx(dev, 1);
return 1;
}

return vecs;
}
EXPORT_SYMBOL(pci_alloc_irq_vectors);
Expand Down
10 changes: 6 additions & 4 deletions include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -1251,10 +1251,12 @@ resource_size_t pcibios_iov_resource_alignment(struct pci_dev *dev, int resno);
int pci_set_vga_state(struct pci_dev *pdev, bool decode,
unsigned int command_bits, u32 flags);

#define PCI_IRQ_NOLEGACY (1 << 0) /* don't use legacy interrupts */
#define PCI_IRQ_NOMSI (1 << 1) /* don't use MSI interrupts */
#define PCI_IRQ_NOMSIX (1 << 2) /* don't use MSI-X interrupts */
#define PCI_IRQ_NOAFFINITY (1 << 3) /* don't auto-assign affinity */
#define PCI_IRQ_LEGACY (1 << 0) /* allow legacy interrupts */
#define PCI_IRQ_MSI (1 << 1) /* allow MSI interrupts */
#define PCI_IRQ_MSIX (1 << 2) /* allow MSI-X interrupts */
#define PCI_IRQ_AFFINITY (1 << 3) /* auto-assign affinity */
#define PCI_IRQ_ALL_TYPES \
(PCI_IRQ_LEGACY | PCI_IRQ_MSI | PCI_IRQ_MSIX)

/* kmem_cache style wrapper around pci_alloc_consistent() */

Expand Down

0 comments on commit 219c04c

Please sign in to comment.