Browse Source

Merge tag 'pci-v4.8-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/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
Linus Torvalds 9 years ago
parent
commit
219c04cea3

+ 10 - 14
Documentation/PCI/MSI-HOWTO.txt

@@ -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
 min_vecs argument set to this limit, and the PCI core will return -ENOSPC
 if it can't meet the minimum number of vectors.
 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
 To get the Linux IRQ numbers passed to request_irq() and free_irq() and the
 vectors, use the following function:
 vectors, use the following function:
@@ -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
 capped to the supported limit, so there is no need to query the number of
 vectors supported beforehand:
 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)
 	if (nvec < 0)
 		goto out_err;
 		goto out_err;
 
 
@@ -140,7 +137,7 @@ interrupts it can request a particular number of interrupts by passing that
 number to pci_alloc_irq_vectors() function as both 'min_vecs' and
 number to pci_alloc_irq_vectors() function as both 'min_vecs' and
 'max_vecs' parameters:
 '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)
 	if (ret < 0)
 		goto out_err;
 		goto out_err;
 
 
@@ -148,15 +145,14 @@ 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
 the single MSI mode for a device.  It could be done by passing two 1s as
 'min_vecs' and 'max_vecs':
 '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)
 	if (ret < 0)
 		goto out_err;
 		goto out_err;
 
 
 Some devices might not support using legacy line interrupts, in which case
 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)
 	if (nvec < 0)
 		goto out_err;
 		goto out_err;
 
 

+ 4 - 0
Documentation/kernel-parameters.txt

@@ -3032,6 +3032,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 				PAGE_SIZE is used as alignment.
 				PAGE_SIZE is used as alignment.
 				PCI-PCI bridge can be specified, if resource
 				PCI-PCI bridge can be specified, if resource
 				windows need to be expanded.
 				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
 		ecrc=		Enable/disable PCIe ECRC (transaction layer
 				end-to-end CRC checking).
 				end-to-end CRC checking).
 				bios: Use BIOS/firmware settings. This is the
 				bios: Use BIOS/firmware settings. This is the

+ 8 - 2
arch/x86/pci/vmd.c

@@ -41,6 +41,7 @@ static DEFINE_RAW_SPINLOCK(list_lock);
  * @node:	list item for parent traversal.
  * @node:	list item for parent traversal.
  * @rcu:	RCU callback item for freeing.
  * @rcu:	RCU callback item for freeing.
  * @irq:	back pointer to parent.
  * @irq:	back pointer to parent.
+ * @enabled:	true if driver enabled IRQ
  * @virq:	the virtual IRQ value provided to the requesting driver.
  * @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
  * Every MSI/MSI-X IRQ requested for a device in a VMD domain will be mapped to
@@ -50,6 +51,7 @@ struct vmd_irq {
 	struct list_head	node;
 	struct list_head	node;
 	struct rcu_head		rcu;
 	struct rcu_head		rcu;
 	struct vmd_irq_list	*irq;
 	struct vmd_irq_list	*irq;
+	bool			enabled;
 	unsigned int		virq;
 	unsigned int		virq;
 };
 };
 
 
@@ -122,7 +124,9 @@ static void vmd_irq_enable(struct irq_data *data)
 	unsigned long flags;
 	unsigned long flags;
 
 
 	raw_spin_lock_irqsave(&list_lock, flags);
 	raw_spin_lock_irqsave(&list_lock, flags);
+	WARN_ON(vmdirq->enabled);
 	list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
 	list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
+	vmdirq->enabled = true;
 	raw_spin_unlock_irqrestore(&list_lock, flags);
 	raw_spin_unlock_irqrestore(&list_lock, flags);
 
 
 	data->chip->irq_unmask(data);
 	data->chip->irq_unmask(data);
@@ -136,8 +140,10 @@ static void vmd_irq_disable(struct irq_data *data)
 	data->chip->irq_mask(data);
 	data->chip->irq_mask(data);
 
 
 	raw_spin_lock_irqsave(&list_lock, flags);
 	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);
 	raw_spin_unlock_irqrestore(&list_lock, flags);
 }
 }
 
 

+ 10 - 8
drivers/pci/msi.c

@@ -1069,7 +1069,7 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
 		nvec = maxvec;
 		nvec = maxvec;
 
 
 	for (;;) {
 	for (;;) {
-		if (!(flags & PCI_IRQ_NOAFFINITY)) {
+		if (flags & PCI_IRQ_AFFINITY) {
 			dev->irq_affinity = irq_create_affinity_mask(&nvec);
 			dev->irq_affinity = irq_create_affinity_mask(&nvec);
 			if (nvec < minvec)
 			if (nvec < minvec)
 				return -ENOSPC;
 				return -ENOSPC;
@@ -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)
 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);
 EXPORT_SYMBOL(pci_enable_msi_range);
 
 
@@ -1120,7 +1120,7 @@ static int __pci_enable_msix_range(struct pci_dev *dev,
 		return -ERANGE;
 		return -ERANGE;
 
 
 	for (;;) {
 	for (;;) {
-		if (!(flags & PCI_IRQ_NOAFFINITY)) {
+		if (flags & PCI_IRQ_AFFINITY) {
 			dev->irq_affinity = irq_create_affinity_mask(&nvec);
 			dev->irq_affinity = irq_create_affinity_mask(&nvec);
 			if (nvec < minvec)
 			if (nvec < minvec)
 				return -ENOSPC;
 				return -ENOSPC;
@@ -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 pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
 		int minvec, int maxvec)
 		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);
 EXPORT_SYMBOL(pci_enable_msix_range);
 
 
@@ -1187,22 +1186,25 @@ int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
 {
 {
 	int vecs = -ENOSPC;
 	int vecs = -ENOSPC;
 
 
-	if (!(flags & PCI_IRQ_NOMSIX)) {
+	if (flags & PCI_IRQ_MSIX) {
 		vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs,
 		vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs,
 				flags);
 				flags);
 		if (vecs > 0)
 		if (vecs > 0)
 			return vecs;
 			return vecs;
 	}
 	}
 
 
-	if (!(flags & PCI_IRQ_NOMSI)) {
+	if (flags & PCI_IRQ_MSI) {
 		vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, flags);
 		vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, flags);
 		if (vecs > 0)
 		if (vecs > 0)
 			return vecs;
 			return vecs;
 	}
 	}
 
 
 	/* use legacy irq if allowed */
 	/* 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 1;
+	}
+
 	return vecs;
 	return vecs;
 }
 }
 EXPORT_SYMBOL(pci_alloc_irq_vectors);
 EXPORT_SYMBOL(pci_alloc_irq_vectors);

+ 6 - 4
include/linux/pci.h

@@ -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,
 int pci_set_vga_state(struct pci_dev *pdev, bool decode,
 		      unsigned int command_bits, u32 flags);
 		      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() */
 /* kmem_cache style wrapper around pci_alloc_consistent() */