Skip to content

Commit 3ce4e86

Browse files
Alexander Gordeevbjorn-helgaas
authored andcommitted
PCI/MSI: Add pci_enable_msi_exact() and pci_enable_msix_exact()
The new functions are special cases for pci_enable_msi_range() and pci_enable_msix_range() when a particular number of MSI or MSI-X is needed. By contrast with pci_enable_msi_range() and pci_enable_msix_range() functions, pci_enable_msi_exact() and pci_enable_msix_exact() return zero in case of success, which indicates MSI or MSI-X interrupts have been successfully allocated. Signed-off-by: Alexander Gordeev <agordeev@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
1 parent 13f9653 commit 3ce4e86

File tree

2 files changed

+104
-2
lines changed

2 files changed

+104
-2
lines changed

Documentation/PCI/MSI-HOWTO.txt

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
159159
return pci_enable_msi_range(pdev, nvec, nvec);
160160
}
161161

162+
Note, unlike pci_enable_msi_exact() function, which could be also used to
163+
enable a particular number of MSI-X interrupts, pci_enable_msi_range()
164+
returns either a negative errno or 'nvec' (not negative errno or 0 - as
165+
pci_enable_msi_exact() does).
166+
162167
4.2.1.3 Single MSI mode
163168

164169
The most notorious example of the request type described above is
@@ -175,7 +180,22 @@ enable the single MSI mode, pci_enable_msi_range() returns either a
175180
negative errno or 1 (not negative errno or 0 - as pci_enable_msi()
176181
does).
177182

178-
4.2.3 pci_disable_msi
183+
4.2.3 pci_enable_msi_exact
184+
185+
int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
186+
187+
This variation on pci_enable_msi_range() call allows a device driver to
188+
request exactly 'nvec' MSIs.
189+
190+
If this function returns a negative number, it indicates an error and
191+
the driver should not attempt to request any more MSI interrupts for
192+
this device.
193+
194+
By contrast with pci_enable_msi_range() function, pci_enable_msi_exact()
195+
returns zero in case of success, which indicates MSI interrupts have been
196+
successfully allocated.
197+
198+
4.2.4 pci_disable_msi
179199

180200
void pci_disable_msi(struct pci_dev *dev)
181201

@@ -303,6 +323,11 @@ static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
303323
nvec, nvec);
304324
}
305325

326+
Note, unlike pci_enable_msix_exact() function, which could be also used to
327+
enable a particular number of MSI-X interrupts, pci_enable_msix_range()
328+
returns either a negative errno or 'nvec' (not negative errno or 0 - as
329+
pci_enable_msix_exact() does).
330+
306331
4.3.1.3 Specific requirements to the number of MSI-X interrupts
307332

308333
As noted above, there could be devices that can not operate with just any
@@ -349,7 +374,64 @@ Note how pci_enable_msix_range() return value is analized for a fallback -
349374
any error code other than -ENOSPC indicates a fatal error and should not
350375
be retried.
351376

352-
4.3.2 pci_disable_msix
377+
4.3.2 pci_enable_msix_exact
378+
379+
int pci_enable_msix_exact(struct pci_dev *dev,
380+
struct msix_entry *entries, int nvec)
381+
382+
This variation on pci_enable_msix_range() call allows a device driver to
383+
request exactly 'nvec' MSI-Xs.
384+
385+
If this function returns a negative number, it indicates an error and
386+
the driver should not attempt to allocate any more MSI-X interrupts for
387+
this device.
388+
389+
By contrast with pci_enable_msix_range() function, pci_enable_msix_exact()
390+
returns zero in case of success, which indicates MSI-X interrupts have been
391+
successfully allocated.
392+
393+
Another version of a routine that enables MSI-X mode for a device with
394+
specific requirements described in chapter 4.3.1.3 might look like this:
395+
396+
/*
397+
* Assume 'minvec' and 'maxvec' are non-zero
398+
*/
399+
static int foo_driver_enable_msix(struct foo_adapter *adapter,
400+
int minvec, int maxvec)
401+
{
402+
int rc;
403+
404+
minvec = roundup_pow_of_two(minvec);
405+
maxvec = rounddown_pow_of_two(maxvec);
406+
407+
if (minvec > maxvec)
408+
return -ERANGE;
409+
410+
retry:
411+
rc = pci_enable_msix_exact(adapter->pdev,
412+
adapter->msix_entries, maxvec);
413+
414+
/*
415+
* -ENOSPC is the only error code allowed to be analyzed
416+
*/
417+
if (rc == -ENOSPC) {
418+
if (maxvec == 1)
419+
return -ENOSPC;
420+
421+
maxvec /= 2;
422+
423+
if (minvec > maxvec)
424+
return -ENOSPC;
425+
426+
goto retry;
427+
} else if (rc < 0) {
428+
return rc;
429+
}
430+
431+
return maxvec;
432+
}
433+
434+
4.3.3 pci_disable_msix
353435

354436
void pci_disable_msix(struct pci_dev *dev)
355437

include/linux/pci.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,8 +1169,23 @@ void msi_remove_pci_irq_vectors(struct pci_dev *dev);
11691169
void pci_restore_msi_state(struct pci_dev *dev);
11701170
int pci_msi_enabled(void);
11711171
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec);
1172+
static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
1173+
{
1174+
int rc = pci_enable_msi_range(dev, nvec, nvec);
1175+
if (rc < 0)
1176+
return rc;
1177+
return 0;
1178+
}
11721179
int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
11731180
int minvec, int maxvec);
1181+
static inline int pci_enable_msix_exact(struct pci_dev *dev,
1182+
struct msix_entry *entries, int nvec)
1183+
{
1184+
int rc = pci_enable_msix_range(dev, entries, nvec, nvec);
1185+
if (rc < 0)
1186+
return rc;
1187+
return 0;
1188+
}
11741189
#else
11751190
static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
11761191
static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec)
@@ -1189,9 +1204,14 @@ static inline int pci_msi_enabled(void) { return 0; }
11891204
static inline int pci_enable_msi_range(struct pci_dev *dev, int minvec,
11901205
int maxvec)
11911206
{ return -ENOSYS; }
1207+
static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
1208+
{ return -ENOSYS; }
11921209
static inline int pci_enable_msix_range(struct pci_dev *dev,
11931210
struct msix_entry *entries, int minvec, int maxvec)
11941211
{ return -ENOSYS; }
1212+
static inline int pci_enable_msix_exact(struct pci_dev *dev,
1213+
struct msix_entry *entries, int nvec)
1214+
{ return -ENOSYS; }
11951215
#endif
11961216

11971217
#ifdef CONFIG_PCIEPORTBUS

0 commit comments

Comments
 (0)