diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-08-26 21:26:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-08-26 21:26:07 -0400 |
commit | 219c04cea3f17a6e3ab11d257af741f527c16195 (patch) | |
tree | 4a62b80dd1df75b3b13f528eda6648ba5561034a | |
parent | 61c04572de404e52a655a36752e696bbcb483cf5 (diff) | |
parent | 21c80c9fefc3db10b530a96eb0478c29eb28bf77 (diff) |
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
-rw-r--r-- | Documentation/PCI/MSI-HOWTO.txt | 24 | ||||
-rw-r--r-- | Documentation/kernel-parameters.txt | 4 | ||||
-rw-r--r-- | arch/x86/pci/vmd.c | 10 | ||||
-rw-r--r-- | drivers/pci/msi.c | 18 | ||||
-rw-r--r-- | include/linux/pci.h | 10 |
5 files changed, 38 insertions, 28 deletions
diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt index c55df2911136..cd9c9f6a7cd9 100644 --- a/Documentation/PCI/MSI-HOWTO.txt +++ b/Documentation/PCI/MSI-HOWTO.txt | |||
@@ -94,14 +94,11 @@ has a requirements for a minimum number of vectors the driver can pass a | |||
94 | min_vecs argument set to this limit, and the PCI core will return -ENOSPC | 94 | min_vecs argument set to this limit, and the PCI core will return -ENOSPC |
95 | if it can't meet the minimum number of vectors. | 95 | if it can't meet the minimum number of vectors. |
96 | 96 | ||
97 | The flags argument should normally be set to 0, but can be used to pass the | 97 | The flags argument is used to specify which type of interrupt can be used |
98 | PCI_IRQ_NOMSI and PCI_IRQ_NOMSIX flag in case a device claims to support | 98 | by the device and the driver (PCI_IRQ_LEGACY, PCI_IRQ_MSI, PCI_IRQ_MSIX). |
99 | MSI or MSI-X, but the support is broken, or to pass PCI_IRQ_NOLEGACY in | 99 | A convenient short-hand (PCI_IRQ_ALL_TYPES) is also available to ask for |
100 | case the device does not support legacy interrupt lines. | 100 | any possible kind of interrupt. If the PCI_IRQ_AFFINITY flag is set, |
101 | 101 | pci_alloc_irq_vectors() will spread the interrupts around the available CPUs. | |
102 | By default this function will spread the interrupts around the available | ||
103 | CPUs, but this feature can be disabled by passing the PCI_IRQ_NOAFFINITY | ||
104 | flag. | ||
105 | 102 | ||
106 | To get the Linux IRQ numbers passed to request_irq() and free_irq() and the | 103 | To get the Linux IRQ numbers passed to request_irq() and free_irq() and the |
107 | vectors, use the following function: | 104 | vectors, use the following function: |
@@ -131,7 +128,7 @@ larger than the number supported by the device it will automatically be | |||
131 | capped to the supported limit, so there is no need to query the number of | 128 | capped to the supported limit, so there is no need to query the number of |
132 | vectors supported beforehand: | 129 | vectors supported beforehand: |
133 | 130 | ||
134 | nvec = pci_alloc_irq_vectors(pdev, 1, nvec, 0); | 131 | nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_ALL_TYPES) |
135 | if (nvec < 0) | 132 | if (nvec < 0) |
136 | goto out_err; | 133 | goto out_err; |
137 | 134 | ||
@@ -140,7 +137,7 @@ interrupts it can request a particular number of interrupts by passing that | |||
140 | number to pci_alloc_irq_vectors() function as both 'min_vecs' and | 137 | number to pci_alloc_irq_vectors() function as both 'min_vecs' and |
141 | 'max_vecs' parameters: | 138 | 'max_vecs' parameters: |
142 | 139 | ||
143 | ret = pci_alloc_irq_vectors(pdev, nvec, nvec, 0); | 140 | ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_ALL_TYPES); |
144 | if (ret < 0) | 141 | if (ret < 0) |
145 | goto out_err; | 142 | goto out_err; |
146 | 143 | ||
@@ -148,15 +145,14 @@ The most notorious example of the request type described above is enabling | |||
148 | the single MSI mode for a device. It could be done by passing two 1s as | 145 | the single MSI mode for a device. It could be done by passing two 1s as |
149 | 'min_vecs' and 'max_vecs': | 146 | 'min_vecs' and 'max_vecs': |
150 | 147 | ||
151 | ret = pci_alloc_irq_vectors(pdev, 1, 1, 0); | 148 | ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); |
152 | if (ret < 0) | 149 | if (ret < 0) |
153 | goto out_err; | 150 | goto out_err; |
154 | 151 | ||
155 | Some devices might not support using legacy line interrupts, in which case | 152 | Some devices might not support using legacy line interrupts, in which case |
156 | the PCI_IRQ_NOLEGACY flag can be used to fail the request if the platform | 153 | the driver can specify that only MSI or MSI-X is acceptable: |
157 | can't provide MSI or MSI-X interrupts: | ||
158 | 154 | ||
159 | nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_NOLEGACY); | 155 | nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_MSI | PCI_IRQ_MSIX); |
160 | if (nvec < 0) | 156 | if (nvec < 0) |
161 | goto out_err; | 157 | goto out_err; |
162 | 158 | ||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 46c030a49186..a4f4d693e2c1 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -3032,6 +3032,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
3032 | PAGE_SIZE is used as alignment. | 3032 | PAGE_SIZE is used as alignment. |
3033 | PCI-PCI bridge can be specified, if resource | 3033 | PCI-PCI bridge can be specified, if resource |
3034 | windows need to be expanded. | 3034 | windows need to be expanded. |
3035 | To specify the alignment for several | ||
3036 | instances of a device, the PCI vendor, | ||
3037 | device, subvendor, and subdevice may be | ||
3038 | specified, e.g., 4096@pci:8086:9c22:103c:198f | ||
3035 | ecrc= Enable/disable PCIe ECRC (transaction layer | 3039 | ecrc= Enable/disable PCIe ECRC (transaction layer |
3036 | end-to-end CRC checking). | 3040 | end-to-end CRC checking). |
3037 | bios: Use BIOS/firmware settings. This is the | 3041 | bios: Use BIOS/firmware settings. This is the |
diff --git a/arch/x86/pci/vmd.c b/arch/x86/pci/vmd.c index b814ca675131..7948be342ee9 100644 --- a/arch/x86/pci/vmd.c +++ b/arch/x86/pci/vmd.c | |||
@@ -41,6 +41,7 @@ static DEFINE_RAW_SPINLOCK(list_lock); | |||
41 | * @node: list item for parent traversal. | 41 | * @node: list item for parent traversal. |
42 | * @rcu: RCU callback item for freeing. | 42 | * @rcu: RCU callback item for freeing. |
43 | * @irq: back pointer to parent. | 43 | * @irq: back pointer to parent. |
44 | * @enabled: true if driver enabled IRQ | ||
44 | * @virq: the virtual IRQ value provided to the requesting driver. | 45 | * @virq: the virtual IRQ value provided to the requesting driver. |
45 | * | 46 | * |
46 | * Every MSI/MSI-X IRQ requested for a device in a VMD domain will be mapped to | 47 | * Every MSI/MSI-X IRQ requested for a device in a VMD domain will be mapped to |
@@ -50,6 +51,7 @@ struct vmd_irq { | |||
50 | struct list_head node; | 51 | struct list_head node; |
51 | struct rcu_head rcu; | 52 | struct rcu_head rcu; |
52 | struct vmd_irq_list *irq; | 53 | struct vmd_irq_list *irq; |
54 | bool enabled; | ||
53 | unsigned int virq; | 55 | unsigned int virq; |
54 | }; | 56 | }; |
55 | 57 | ||
@@ -122,7 +124,9 @@ static void vmd_irq_enable(struct irq_data *data) | |||
122 | unsigned long flags; | 124 | unsigned long flags; |
123 | 125 | ||
124 | raw_spin_lock_irqsave(&list_lock, flags); | 126 | raw_spin_lock_irqsave(&list_lock, flags); |
127 | WARN_ON(vmdirq->enabled); | ||
125 | list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list); | 128 | list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list); |
129 | vmdirq->enabled = true; | ||
126 | raw_spin_unlock_irqrestore(&list_lock, flags); | 130 | raw_spin_unlock_irqrestore(&list_lock, flags); |
127 | 131 | ||
128 | data->chip->irq_unmask(data); | 132 | data->chip->irq_unmask(data); |
@@ -136,8 +140,10 @@ static void vmd_irq_disable(struct irq_data *data) | |||
136 | data->chip->irq_mask(data); | 140 | data->chip->irq_mask(data); |
137 | 141 | ||
138 | raw_spin_lock_irqsave(&list_lock, flags); | 142 | raw_spin_lock_irqsave(&list_lock, flags); |
139 | list_del_rcu(&vmdirq->node); | 143 | if (vmdirq->enabled) { |
140 | INIT_LIST_HEAD_RCU(&vmdirq->node); | 144 | list_del_rcu(&vmdirq->node); |
145 | vmdirq->enabled = false; | ||
146 | } | ||
141 | raw_spin_unlock_irqrestore(&list_lock, flags); | 147 | raw_spin_unlock_irqrestore(&list_lock, flags); |
142 | } | 148 | } |
143 | 149 | ||
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index eafa6138a6b8..98f12223c734 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -1069,7 +1069,7 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, | |||
1069 | nvec = maxvec; | 1069 | nvec = maxvec; |
1070 | 1070 | ||
1071 | for (;;) { | 1071 | for (;;) { |
1072 | if (!(flags & PCI_IRQ_NOAFFINITY)) { | 1072 | if (flags & PCI_IRQ_AFFINITY) { |
1073 | dev->irq_affinity = irq_create_affinity_mask(&nvec); | 1073 | dev->irq_affinity = irq_create_affinity_mask(&nvec); |
1074 | if (nvec < minvec) | 1074 | if (nvec < minvec) |
1075 | return -ENOSPC; | 1075 | return -ENOSPC; |
@@ -1105,7 +1105,7 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, | |||
1105 | **/ | 1105 | **/ |
1106 | int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) | 1106 | int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) |
1107 | { | 1107 | { |
1108 | return __pci_enable_msi_range(dev, minvec, maxvec, PCI_IRQ_NOAFFINITY); | 1108 | return __pci_enable_msi_range(dev, minvec, maxvec, 0); |
1109 | } | 1109 | } |
1110 | EXPORT_SYMBOL(pci_enable_msi_range); | 1110 | EXPORT_SYMBOL(pci_enable_msi_range); |
1111 | 1111 | ||
@@ -1120,7 +1120,7 @@ static int __pci_enable_msix_range(struct pci_dev *dev, | |||
1120 | return -ERANGE; | 1120 | return -ERANGE; |
1121 | 1121 | ||
1122 | for (;;) { | 1122 | for (;;) { |
1123 | if (!(flags & PCI_IRQ_NOAFFINITY)) { | 1123 | if (flags & PCI_IRQ_AFFINITY) { |
1124 | dev->irq_affinity = irq_create_affinity_mask(&nvec); | 1124 | dev->irq_affinity = irq_create_affinity_mask(&nvec); |
1125 | if (nvec < minvec) | 1125 | if (nvec < minvec) |
1126 | return -ENOSPC; | 1126 | return -ENOSPC; |
@@ -1160,8 +1160,7 @@ static int __pci_enable_msix_range(struct pci_dev *dev, | |||
1160 | int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, | 1160 | int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, |
1161 | int minvec, int maxvec) | 1161 | int minvec, int maxvec) |
1162 | { | 1162 | { |
1163 | return __pci_enable_msix_range(dev, entries, minvec, maxvec, | 1163 | return __pci_enable_msix_range(dev, entries, minvec, maxvec, 0); |
1164 | PCI_IRQ_NOAFFINITY); | ||
1165 | } | 1164 | } |
1166 | EXPORT_SYMBOL(pci_enable_msix_range); | 1165 | EXPORT_SYMBOL(pci_enable_msix_range); |
1167 | 1166 | ||
@@ -1187,22 +1186,25 @@ int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, | |||
1187 | { | 1186 | { |
1188 | int vecs = -ENOSPC; | 1187 | int vecs = -ENOSPC; |
1189 | 1188 | ||
1190 | if (!(flags & PCI_IRQ_NOMSIX)) { | 1189 | if (flags & PCI_IRQ_MSIX) { |
1191 | vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs, | 1190 | vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs, |
1192 | flags); | 1191 | flags); |
1193 | if (vecs > 0) | 1192 | if (vecs > 0) |
1194 | return vecs; | 1193 | return vecs; |
1195 | } | 1194 | } |
1196 | 1195 | ||
1197 | if (!(flags & PCI_IRQ_NOMSI)) { | 1196 | if (flags & PCI_IRQ_MSI) { |
1198 | vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, flags); | 1197 | vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, flags); |
1199 | if (vecs > 0) | 1198 | if (vecs > 0) |
1200 | return vecs; | 1199 | return vecs; |
1201 | } | 1200 | } |
1202 | 1201 | ||
1203 | /* use legacy irq if allowed */ | 1202 | /* use legacy irq if allowed */ |
1204 | if (!(flags & PCI_IRQ_NOLEGACY) && min_vecs == 1) | 1203 | if ((flags & PCI_IRQ_LEGACY) && min_vecs == 1) { |
1204 | pci_intx(dev, 1); | ||
1205 | return 1; | 1205 | return 1; |
1206 | } | ||
1207 | |||
1206 | return vecs; | 1208 | return vecs; |
1207 | } | 1209 | } |
1208 | EXPORT_SYMBOL(pci_alloc_irq_vectors); | 1210 | EXPORT_SYMBOL(pci_alloc_irq_vectors); |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 2599a980340f..fbc1fa625c3e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -1251,10 +1251,12 @@ resource_size_t pcibios_iov_resource_alignment(struct pci_dev *dev, int resno); | |||
1251 | int pci_set_vga_state(struct pci_dev *pdev, bool decode, | 1251 | int pci_set_vga_state(struct pci_dev *pdev, bool decode, |
1252 | unsigned int command_bits, u32 flags); | 1252 | unsigned int command_bits, u32 flags); |
1253 | 1253 | ||
1254 | #define PCI_IRQ_NOLEGACY (1 << 0) /* don't use legacy interrupts */ | 1254 | #define PCI_IRQ_LEGACY (1 << 0) /* allow legacy interrupts */ |
1255 | #define PCI_IRQ_NOMSI (1 << 1) /* don't use MSI interrupts */ | 1255 | #define PCI_IRQ_MSI (1 << 1) /* allow MSI interrupts */ |
1256 | #define PCI_IRQ_NOMSIX (1 << 2) /* don't use MSI-X interrupts */ | 1256 | #define PCI_IRQ_MSIX (1 << 2) /* allow MSI-X interrupts */ |
1257 | #define PCI_IRQ_NOAFFINITY (1 << 3) /* don't auto-assign affinity */ | 1257 | #define PCI_IRQ_AFFINITY (1 << 3) /* auto-assign affinity */ |
1258 | #define PCI_IRQ_ALL_TYPES \ | ||
1259 | (PCI_IRQ_LEGACY | PCI_IRQ_MSI | PCI_IRQ_MSIX) | ||
1258 | 1260 | ||
1259 | /* kmem_cache style wrapper around pci_alloc_consistent() */ | 1261 | /* kmem_cache style wrapper around pci_alloc_consistent() */ |
1260 | 1262 | ||