On Tue, Jul 12, 2016 at 06:20:17PM +0900, Christoph Hellwig wrote: > Add a function to allocate and free a range of interrupt vectors, using > MSI-X, MSI or legacy vectors (in that order) based on the capabilities > of the underlying device and PCIe complex. > > Additionally a new helper is provided to get the Linux IRQ number for > given device-relative vector so that the drivers don't need to allocate > their own arrays to keep track of the vectors for the multi vector > MSI-X case. > > Signed-off-by: Christoph Hellwig <hch@xxxxxx> > --- > Documentation/PCI/MSI-HOWTO.txt | 474 +++++++--------------------------------- > drivers/pci/msi.c | 89 ++++++++ > include/linux/pci.h | 27 +++ > 3 files changed, 193 insertions(+), 397 deletions(-) > > diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt > index 1179850..0af91e8 100644 > --- a/Documentation/PCI/MSI-HOWTO.txt > +++ b/Documentation/PCI/MSI-HOWTO.txt > @@ -82,418 +82,98 @@ Most of the hard work is done for the driver in the PCI layer. It simply > has to request that the PCI layer set up the MSI capability for this > device. > > -4.2.1 pci_enable_msi > - > -int pci_enable_msi(struct pci_dev *dev) > - > -A successful call allocates ONE interrupt to the device, regardless > -of how many MSIs the device supports. The device is switched from > -pin-based interrupt mode to MSI mode. The dev->irq number is changed > -to a new number which represents the message signaled interrupt; > -consequently, this function should be called before the driver calls > -request_irq(), because an MSI is delivered via a vector that is > -different from the vector of a pin-based interrupt. > - > -4.2.2 pci_enable_msi_range > - > -int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) > - > -This function allows a device driver to request any number of MSI > -interrupts within specified range from 'minvec' to 'maxvec'. > - > -If this function returns a positive number it indicates the number of > -MSI interrupts that have been successfully allocated. In this case > -the device is switched from pin-based interrupt mode to MSI mode and > -updates dev->irq to be the lowest of the new interrupts assigned to it. > -The other interrupts assigned to the device are in the range dev->irq > -to dev->irq + returned value - 1. Device driver can use the returned > -number of successfully allocated MSI interrupts to further allocate > -and initialize device resources. > - > -If this function returns a negative number, it indicates an error and > -the driver should not attempt to request any more MSI interrupts for > -this device. > - > -This function should be called before the driver calls request_irq(), > -because MSI interrupts are delivered via vectors that are different > -from the vector of a pin-based interrupt. > - > -It is ideal if drivers can cope with a variable number of MSI interrupts; > -there are many reasons why the platform may not be able to provide the > -exact number that a driver asks for. > - > -There could be devices that can not operate with just any number of MSI > -interrupts within a range. See chapter 4.3.1.3 to get the idea how to > -handle such devices for MSI-X - the same logic applies to MSI. > - > -4.2.1.1 Maximum possible number of MSI interrupts > - > -The typical usage of MSI interrupts is to allocate as many vectors as > -possible, likely up to the limit returned by pci_msi_vec_count() function: > - > -static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec) > -{ > - return pci_enable_msi_range(pdev, 1, nvec); > -} > - > -Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive, > -the value of 0 would be meaningless and could result in error. > - > -Some devices have a minimal limit on number of MSI interrupts. > -In this case the function could look like this: > - > -static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec) > -{ > - return pci_enable_msi_range(pdev, FOO_DRIVER_MINIMUM_NVEC, nvec); > -} > - > -4.2.1.2 Exact number of MSI interrupts > +To automatically use MSI or MSI-X interrupt vectors use the following > +function: > + > +int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, > + unsigned int max_vecs, unsigned int flags) > + > +Which allocates up to max_vecs interrupt vectors for a PCI devices. Returns > +the number of vectors allocated or a negative error. If the device 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. > + > +To get the Linux IRQ numbers passed to request_irq and free_irq > +and the vectors use the following function: > + > +int pci_irq_vector(struct pci_dev *dev, unsigned int nr); > + > +Any allocated resources should be freed before removing the device using the > +following function: > + > +void pci_free_irq_vectors(struct pci_dev *dev) > + > +If a device supports both MSI-X and MSI capabilities, this API will use > +the MSI-X facilities in preference to the MSI facilities. MSI-X > +supports any number of interrupts between 1 and 2048. In contrast, MSI > +is restricted to a maximum of 32 interrupts (and must be a power of two). > +In addition, the MSI interrupt vectors must be allocated consecutively, > +so the system might not be able to allocate as many vectors for MSI as > +it could for MSI-X. On some platforms, MSI interrupts must all be > +targeted at the same set of CPUs whereas MSI-X interrupts can all be > +targeted at different CPUs. > + > +If a device supports neither MSI-X or MSI it will fall back to a single > +legacy IRQ vectors. > + > +The typical usage of MSI or MSI-X interrupts is to allocate as many vectors as > +possible, likely up to the limit supported by the device. If nvec is 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); > + if (nvec < 0) > + goto out_err; > > If a driver is unable or unwilling to deal with a variable number of MSI > interrupts it could request a particular number of interrupts by passing > -that number to pci_enable_msi_range() function as both 'minvec' and 'maxvec' > -parameters: > +that number to pci_alloc_irq_vectors() function as both 'min_vecs' and > +'max_vecs' parameters: > > -static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec) > -{ > - return pci_enable_msi_range(pdev, nvec, nvec); > -} > - > -Note, unlike pci_enable_msi_exact() function, which could be also used to > -enable a particular number of MSI-X interrupts, pci_enable_msi_range() > -returns either a negative errno or 'nvec' (not negative errno or 0 - as > -pci_enable_msi_exact() does). > - > -4.2.1.3 Single MSI mode > + ret = pci_alloc_irq_vectors(pdev, nvec, nvec, 0); > + 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 'minvec' and 'maxvec': > - > -static int foo_driver_enable_single_msi(struct pci_dev *pdev) > -{ > - return pci_enable_msi_range(pdev, 1, 1); > -} > - > -Note, unlike pci_enable_msi() function, which could be also used to > -enable the single MSI mode, pci_enable_msi_range() returns either a > -negative errno or 1 (not negative errno or 0 - as pci_enable_msi() > -does). > - > -4.2.3 pci_enable_msi_exact > - > -int pci_enable_msi_exact(struct pci_dev *dev, int nvec) > - > -This variation on pci_enable_msi_range() call allows a device driver to > -request exactly 'nvec' MSIs. > - > -If this function returns a negative number, it indicates an error and > -the driver should not attempt to request any more MSI interrupts for > -this device. > - > -By contrast with pci_enable_msi_range() function, pci_enable_msi_exact() > -returns zero in case of success, which indicates MSI interrupts have been > -successfully allocated. > - > -4.2.4 pci_disable_msi > - > -void pci_disable_msi(struct pci_dev *dev) > - > -This function should be used to undo the effect of pci_enable_msi_range(). > -Calling it restores dev->irq to the pin-based interrupt number and frees > -the previously allocated MSIs. The interrupts may subsequently be assigned > -to another device, so drivers should not cache the value of dev->irq. > - > -Before calling this function, a device driver must always call free_irq() > -on any interrupt for which it previously called request_irq(). > -Failure to do so results in a BUG_ON(), leaving the device with > -MSI enabled and thus leaking its vector. > - > -4.2.4 pci_msi_vec_count > - > -int pci_msi_vec_count(struct pci_dev *dev) > - > -This function could be used to retrieve the number of MSI vectors the > -device requested (via the Multiple Message Capable register). The MSI > -specification only allows the returned value to be a power of two, > -up to a maximum of 2^5 (32). > - > -If this function returns a negative number, it indicates the device is > -not capable of sending MSIs. > - > -If this function returns a positive number, it indicates the maximum > -number of MSI interrupt vectors that could be allocated. > - > -4.3 Using MSI-X > - > -The MSI-X capability is much more flexible than the MSI capability. > -It supports up to 2048 interrupts, each of which can be controlled > -independently. To support this flexibility, drivers must use an array of > -`struct msix_entry': > - > -struct msix_entry { > - u16 vector; /* kernel uses to write alloc vector */ > - u16 entry; /* driver uses to specify entry */ > -}; > - > -This allows for the device to use these interrupts in a sparse fashion; > -for example, it could use interrupts 3 and 1027 and yet allocate only a > -two-element array. The driver is expected to fill in the 'entry' value > -in each element of the array to indicate for which entries the kernel > -should assign interrupts; it is invalid to fill in two entries with the > -same number. > - > -4.3.1 pci_enable_msix_range > - > -int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, > - int minvec, int maxvec) > - > -Calling this function asks the PCI subsystem to allocate any number of > -MSI-X interrupts within specified range from 'minvec' to 'maxvec'. > -The 'entries' argument is a pointer to an array of msix_entry structs > -which should be at least 'maxvec' entries in size. > - > -On success, the device is switched into MSI-X mode and the function > -returns the number of MSI-X interrupts that have been successfully > -allocated. In this case the 'vector' member in entries numbered from > -0 to the returned value - 1 is populated with the interrupt number; > -the driver should then call request_irq() for each 'vector' that it > -decides to use. The device driver is responsible for keeping track of the > -interrupts assigned to the MSI-X vectors so it can free them again later. > -Device driver can use the returned number of successfully allocated MSI-X > -interrupts to further allocate and initialize device resources. > - > -If this function returns a negative number, it indicates an error and > -the driver should not attempt to allocate any more MSI-X interrupts for > -this device. > - > -This function, in contrast with pci_enable_msi_range(), does not adjust > -dev->irq. The device will not generate interrupts for this interrupt > -number once MSI-X is enabled. > - > -Device drivers should normally call this function once per device > -during the initialization phase. > - > -It is ideal if drivers can cope with a variable number of MSI-X interrupts; > -there are many reasons why the platform may not be able to provide the > -exact number that a driver asks for. > - > -There could be devices that can not operate with just any number of MSI-X > -interrupts within a range. E.g., an network adapter might need let's say > -four vectors per each queue it provides. Therefore, a number of MSI-X > -interrupts allocated should be a multiple of four. In this case interface > -pci_enable_msix_range() can not be used alone to request MSI-X interrupts > -(since it can allocate any number within the range, without any notion of > -the multiple of four) and the device driver should master a custom logic > -to request the required number of MSI-X interrupts. > - > -4.3.1.1 Maximum possible number of MSI-X interrupts > - > -The typical usage of MSI-X interrupts is to allocate as many vectors as > -possible, likely up to the limit returned by pci_msix_vec_count() function: > - > -static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) > -{ > - return pci_enable_msix_range(adapter->pdev, adapter->msix_entries, > - 1, nvec); > -} > - > -Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive, > -the value of 0 would be meaningless and could result in error. > - > -Some devices have a minimal limit on number of MSI-X interrupts. > -In this case the function could look like this: > - > -static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) > -{ > - return pci_enable_msix_range(adapter->pdev, adapter->msix_entries, > - FOO_DRIVER_MINIMUM_NVEC, nvec); > -} > - > -4.3.1.2 Exact number of MSI-X interrupts > - > -If a driver is unable or unwilling to deal with a variable number of MSI-X > -interrupts it could request a particular number of interrupts by passing > -that number to pci_enable_msix_range() function as both 'minvec' and 'maxvec' > -parameters: > - > -static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) > -{ > - return pci_enable_msix_range(adapter->pdev, adapter->msix_entries, > - nvec, nvec); > -} > - > -Note, unlike pci_enable_msix_exact() function, which could be also used to > -enable a particular number of MSI-X interrupts, pci_enable_msix_range() > -returns either a negative errno or 'nvec' (not negative errno or 0 - as > -pci_enable_msix_exact() does). > - > -4.3.1.3 Specific requirements to the number of MSI-X interrupts > - > -As noted above, there could be devices that can not operate with just any > -number of MSI-X interrupts within a range. E.g., let's assume a device that > -is only capable sending the number of MSI-X interrupts which is a power of > -two. A routine that enables MSI-X mode for such device might look like this: > - > -/* > - * Assume 'minvec' and 'maxvec' are non-zero > - */ > -static int foo_driver_enable_msix(struct foo_adapter *adapter, > - int minvec, int maxvec) > -{ > - int rc; > - > - minvec = roundup_pow_of_two(minvec); > - maxvec = rounddown_pow_of_two(maxvec); > - > - if (minvec > maxvec) > - return -ERANGE; > - > -retry: > - rc = pci_enable_msix_range(adapter->pdev, adapter->msix_entries, > - maxvec, maxvec); > - /* > - * -ENOSPC is the only error code allowed to be analyzed > - */ > - if (rc == -ENOSPC) { > - if (maxvec == 1) > - return -ENOSPC; > - > - maxvec /= 2; > - > - if (minvec > maxvec) > - return -ENOSPC; > - > - goto retry; > - } > - > - return rc; > -} > - > -Note how pci_enable_msix_range() return value is analyzed for a fallback - > -any error code other than -ENOSPC indicates a fatal error and should not > -be retried. > - > -4.3.2 pci_enable_msix_exact > - > -int pci_enable_msix_exact(struct pci_dev *dev, > - struct msix_entry *entries, int nvec) > - > -This variation on pci_enable_msix_range() call allows a device driver to > -request exactly 'nvec' MSI-Xs. > - > -If this function returns a negative number, it indicates an error and > -the driver should not attempt to allocate any more MSI-X interrupts for > -this device. > - > -By contrast with pci_enable_msix_range() function, pci_enable_msix_exact() > -returns zero in case of success, which indicates MSI-X interrupts have been > -successfully allocated. > - > -Another version of a routine that enables MSI-X mode for a device with > -specific requirements described in chapter 4.3.1.3 might look like this: > - > -/* > - * Assume 'minvec' and 'maxvec' are non-zero > - */ > -static int foo_driver_enable_msix(struct foo_adapter *adapter, > - int minvec, int maxvec) > -{ > - int rc; > - > - minvec = roundup_pow_of_two(minvec); > - maxvec = rounddown_pow_of_two(maxvec); > - > - if (minvec > maxvec) > - return -ERANGE; > - > -retry: > - rc = pci_enable_msix_exact(adapter->pdev, > - adapter->msix_entries, maxvec); > - > - /* > - * -ENOSPC is the only error code allowed to be analyzed > - */ > - if (rc == -ENOSPC) { > - if (maxvec == 1) > - return -ENOSPC; > - > - maxvec /= 2; > - > - if (minvec > maxvec) > - return -ENOSPC; > - > - goto retry; > - } else if (rc < 0) { > - return rc; > - } > - > - return maxvec; > -} > - > -4.3.3 pci_disable_msix > - > -void pci_disable_msix(struct pci_dev *dev) > - > -This function should be used to undo the effect of pci_enable_msix_range(). > -It frees the previously allocated MSI-X interrupts. The interrupts may > -subsequently be assigned to another device, so drivers should not cache > -the value of the 'vector' elements over a call to pci_disable_msix(). > - > -Before calling this function, a device driver must always call free_irq() > -on any interrupt for which it previously called request_irq(). > -Failure to do so results in a BUG_ON(), leaving the device with > -MSI-X enabled and thus leaking its vector. > - > -4.3.3 The MSI-X Table > - > -The MSI-X capability specifies a BAR and offset within that BAR for the > -MSI-X Table. This address is mapped by the PCI subsystem, and should not > -be accessed directly by the device driver. If the driver wishes to > -mask or unmask an interrupt, it should call disable_irq() / enable_irq(). > - > -4.3.4 pci_msix_vec_count > - > -int pci_msix_vec_count(struct pci_dev *dev) > +two 1s as 'min_vecs' and 'max_vecs': > > -This function could be used to retrieve number of entries in the device > -MSI-X table. > + ret = pci_alloc_irq_vectors(pdev, 1, 1, 0); > + if (ret < 0) > + goto out_err; > > -If this function returns a negative number, it indicates the device is > -not capable of sending MSI-Xs. > +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: > > -If this function returns a positive number, it indicates the maximum > -number of MSI-X interrupt vectors that could be allocated. > + nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_NOLEGACY); > + if (nvec < 0) > + goto out_err; > > -4.4 Handling devices implementing both MSI and MSI-X capabilities > +4.3 Legacy APIs > > -If a device implements both MSI and MSI-X capabilities, it can > -run in either MSI mode or MSI-X mode, but not both simultaneously. > -This is a requirement of the PCI spec, and it is enforced by the > -PCI layer. Calling pci_enable_msi_range() when MSI-X is already > -enabled or pci_enable_msix_range() when MSI is already enabled > -results in an error. If a device driver wishes to switch between MSI > -and MSI-X at runtime, it must first quiesce the device, then switch > -it back to pin-interrupt mode, before calling pci_enable_msi_range() > -or pci_enable_msix_range() and resuming operation. This is not expected > -to be a common operation but may be useful for debugging or testing > -during development. > +The old APIs to enable and disable MSI or MSI-X interrupts should not > +be used in new code: > > -4.5 Considerations when using MSIs > + pci_enable_msi, pci_enable_msi_range, pci_enable_msi_exact, pci_disable_msi, > + pci_enable_msix_range, pci_enable_msix_exact, pci_disable_msix > > -4.5.1 Choosing between MSI-X and MSI > +Additionally there are APIs to provide the number of support MSI or MSI-X > +vectors called pci_msi_vec_count, pci_msix_vec_count. In general these > +should be avoided in favor of letting pci_alloc_irq_vectors cap the > +number of vectors. If you have a legitimate special use case for the count > +of vectors we might have to revisit that decision and add a pci_nr_irq_vectors > +helper that handles MSI and MSI-X transparently. > > -If your device supports both MSI-X and MSI capabilities, you should use > -the MSI-X facilities in preference to the MSI facilities. As mentioned > -above, MSI-X supports any number of interrupts between 1 and 2048. > -In contrast, MSI is restricted to a maximum of 32 interrupts (and > -must be a power of two). In addition, the MSI interrupt vectors must > -be allocated consecutively, so the system might not be able to allocate > -as many vectors for MSI as it could for MSI-X. On some platforms, MSI > -interrupts must all be targeted at the same set of CPUs whereas MSI-X > -interrupts can all be targeted at different CPUs. > +4.4 Considerations when using MSIs > > -4.5.2 Spinlocks > +4.4.1 Spinlocks > > Most device drivers have a per-device spinlock which is taken in the > interrupt handler. With pin-based interrupts or a single MSI, it is not > @@ -505,7 +185,7 @@ acquire the spinlock. Such deadlocks can be avoided by using > spin_lock_irqsave() or spin_lock_irq() which disable local interrupts > and acquire the lock (see Documentation/DocBook/kernel-locking). > > -4.6 How to tell whether MSI/MSI-X is enabled on a device > +4.5 How to tell whether MSI/MSI-X is enabled on a device > > Using 'lspci -v' (as root) may show some devices with "MSI", "Message > Signalled Interrupts" or "MSI-X" capabilities. Each of these capabilities > diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c > index 98ace67..00657bf 100644 > --- a/drivers/pci/msi.c > +++ b/drivers/pci/msi.c > @@ -4,6 +4,7 @@ > * > * Copyright (C) 2003-2004 Intel > * Copyright (C) Tom Long Nguyen (tom.l.nguyen@xxxxxxxxx) > + * Copyright (C) 2016 Christoph Hellwig. > */ > > #include <linux/err.h> > @@ -1121,6 +1122,94 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, > } > EXPORT_SYMBOL(pci_enable_msix_range); > > +/** > + * pci_alloc_irq_vectors - allocate multiple IRQs for a device > + * @dev: PCI device to operate on > + * @min_vecs: minimum number of vectors required (must be >= 1) > + * @max_vecs: maximum (desired) number of vectors > + * @flags: flags or quirks for the allocation > + * > + * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI > + * vectors if available, and fall back to a single legacy vector > + * if neither is available. Return the number of vectors allocated, > + * (which might be smaller than @max_vecs) if successful, or a negative > + * error code on error. If less than @min_vecs interrupt vectors are > + * available for @dev the function will fail with -ENOSPC. > + * > + * To get the Linux irq number used for a vector that can be passed to > + * request_irq use the pci_irq_vector() helper. > + */ > +int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, > + unsigned int max_vecs, unsigned int flags) > +{ > + int vecs = -ENOSPC; > + > + if (!(flags & PCI_IRQ_NOMSIX)) { > + vecs = pci_enable_msix_range(dev, NULL, min_vecs, max_vecs); > + if (vecs > 0) > + return vecs; > + } > + > + if (!(flags & PCI_IRQ_NOMSI)) { > + vecs = pci_enable_msi_range(dev, min_vecs, max_vecs); > + if (vecs > 0) > + return vecs; > + } > + > + /* use legacy irq if allowed */ > + if (!(flags & PCI_IRQ_NOLEGACY) && min_vecs == 1) > + return 1; > + return vecs; > +} > +EXPORT_SYMBOL(pci_alloc_irq_vectors); > + > +/** > + * pci_free_irq_vectors - free previously allocated IRQs for a device > + * @dev: PCI device to operate on > + * > + * Undoes the allocations and enabling in pci_alloc_irq_vectors(). > + */ > +void pci_free_irq_vectors(struct pci_dev *dev) > +{ > + pci_disable_msix(dev); > + pci_disable_msi(dev); > +} > +EXPORT_SYMBOL(pci_free_irq_vectors); > + > +/** > + * pci_irq_vector - return Linux IRQ number of a device vector > + * @dev: PCI device to operate on > + * @nr: device-relative interrupt vector index (0-based). > + */ > +int pci_irq_vector(struct pci_dev *dev, unsigned int nr) > +{ > + if (dev->msix_enabled) { > + struct msi_desc *entry; > + int i = 0; > + > + for_each_pci_msi_entry(entry, dev) { > + if (i == nr) > + return entry->irq; > + i++; > + } > + WARN_ON_ONCE(1); > + return -EINVAL; > + } > + > + if (dev->msi_enabled) { > + struct msi_desc *entry = first_pci_msi_entry(dev); > + > + if (WARN_ON_ONCE(nr >= entry->nvec_used)) > + return -EINVAL; > + } else { > + if (WARN_ON_ONCE(nr > 0)) > + return -EINVAL; > + } > + > + return dev->irq + nr; > +} > +EXPORT_SYMBOL(pci_irq_vector); > + > struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc) > { > return to_pci_dev(desc->dev); > diff --git a/include/linux/pci.h b/include/linux/pci.h > index b67e4df..52ecd49 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -1237,6 +1237,10 @@ 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 */ > + > /* kmem_cache style wrapper around pci_alloc_consistent() */ > > #include <linux/pci-dma.h> > @@ -1284,6 +1288,11 @@ static inline int pci_enable_msix_exact(struct pci_dev *dev, > return rc; > return 0; > } > +int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, > + unsigned int max_vecs, unsigned int flags); > +void pci_free_irq_vectors(struct pci_dev *dev); > +int pci_irq_vector(struct pci_dev *dev, unsigned int nr); > + > #else > static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; } > static inline void pci_msi_shutdown(struct pci_dev *dev) { } > @@ -1307,6 +1316,24 @@ static inline int pci_enable_msix_range(struct pci_dev *dev, > static inline int pci_enable_msix_exact(struct pci_dev *dev, > struct msix_entry *entries, int nvec) > { return -ENOSYS; } > +static inline int pci_alloc_irq_vectors(struct pci_dev *dev, > + unsigned int min_vecs, unsigned int max_vecs, > + unsigned int flags) > +{ > + if (min_vecs > 1) > + return -EINVAL; > + return 1; > +} > +static inline void pci_free_irq_vectors(struct pci_dev *dev) > +{ > +} > + > +static inline int pci_irq_vector(struct pci_dev *dev, unsigned int nr) > +{ > + if (WARN_ON_ONCE(nr > 0)) > + return -EINVAL; > + return dev->irq; > +} > #endif > > #ifdef CONFIG_PCIEPORTBUS > -- > 2.1.4 > Reviewed-by: Alexander Gordeev <agordeev@xxxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html