Skip to content

Commit 84f8904

Browse files
mwiniarsbjorn-helgaas
authored andcommitted
PCI/IOV: Allow drivers to control VF BAR size
Drivers could leverage the fact that the VF BAR MMIO reservation is created for total number of VFs supported by the device by resizing the BAR to larger size when smaller number of VFs is enabled. Add pci_iov_vf_bar_set_size() to control the size and a pci_iov_vf_bar_get_sizes() helper to get the VF BAR sizes that will allow up to num_vfs to be successfully enabled with the current underlying reservation size. Signed-off-by: Michał Winiarski <michal.winiarski@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Link: https://patch.msgid.link/20250702093522.518099-6-michal.winiarski@intel.com
1 parent e1ba95a commit 84f8904

2 files changed

Lines changed: 79 additions & 0 deletions

File tree

drivers/pci/iov.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88
*/
99

1010
#include <linux/bitfield.h>
11+
#include <linux/bits.h>
12+
#include <linux/log2.h>
1113
#include <linux/pci.h>
14+
#include <linux/sizes.h>
1215
#include <linux/slab.h>
1316
#include <linux/export.h>
1417
#include <linux/string.h>
1518
#include <linux/delay.h>
19+
#include <asm/div64.h>
1620
#include "pci.h"
1721

1822
#define VIRTFN_ID_LEN 17 /* "virtfn%u\0" for 2^32 - 1 */
@@ -1313,3 +1317,72 @@ int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn)
13131317
return nr_virtfn;
13141318
}
13151319
EXPORT_SYMBOL_GPL(pci_sriov_configure_simple);
1320+
1321+
/**
1322+
* pci_iov_vf_bar_set_size - set a new size for a VF BAR
1323+
* @dev: the PCI device
1324+
* @resno: the resource number
1325+
* @size: new size as defined in the spec (0=1MB, 31=128TB)
1326+
*
1327+
* Set the new size of a VF BAR that supports VF resizable BAR capability.
1328+
* Unlike pci_resize_resource(), this does not cause the resource that
1329+
* reserves the MMIO space (originally up to total_VFs) to be resized, which
1330+
* means that following calls to pci_enable_sriov() can fail if the resources
1331+
* no longer fit.
1332+
*
1333+
* Return: 0 on success, or negative on failure.
1334+
*/
1335+
int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size)
1336+
{
1337+
u32 sizes;
1338+
int ret;
1339+
1340+
if (!pci_resource_is_iov(resno))
1341+
return -EINVAL;
1342+
1343+
if (pci_iov_is_memory_decoding_enabled(dev))
1344+
return -EBUSY;
1345+
1346+
sizes = pci_rebar_get_possible_sizes(dev, resno);
1347+
if (!sizes)
1348+
return -ENOTSUPP;
1349+
1350+
if (!(sizes & BIT(size)))
1351+
return -EINVAL;
1352+
1353+
ret = pci_rebar_set_size(dev, resno, size);
1354+
if (ret)
1355+
return ret;
1356+
1357+
pci_iov_resource_set_size(dev, resno, pci_rebar_size_to_bytes(size));
1358+
1359+
return 0;
1360+
}
1361+
EXPORT_SYMBOL_GPL(pci_iov_vf_bar_set_size);
1362+
1363+
/**
1364+
* pci_iov_vf_bar_get_sizes - get VF BAR sizes allowing to create up to num_vfs
1365+
* @dev: the PCI device
1366+
* @resno: the resource number
1367+
* @num_vfs: number of VFs
1368+
*
1369+
* Get the sizes of a VF resizable BAR that can accommodate @num_vfs within
1370+
* the currently assigned size of the resource @resno.
1371+
*
1372+
* Return: A bitmask of sizes in format defined in the spec (bit 0=1MB,
1373+
* bit 31=128TB).
1374+
*/
1375+
u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs)
1376+
{
1377+
u64 vf_len = pci_resource_len(dev, resno);
1378+
u32 sizes;
1379+
1380+
if (!num_vfs)
1381+
return 0;
1382+
1383+
do_div(vf_len, num_vfs);
1384+
sizes = (roundup_pow_of_two(vf_len + 1) - 1) >> ilog2(SZ_1M);
1385+
1386+
return sizes & pci_rebar_get_possible_sizes(dev, resno);
1387+
}
1388+
EXPORT_SYMBOL_GPL(pci_iov_vf_bar_get_sizes);

include/linux/pci.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,6 +2438,8 @@ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
24382438
int pci_sriov_get_totalvfs(struct pci_dev *dev);
24392439
int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn);
24402440
resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno);
2441+
int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size);
2442+
u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs);
24412443
void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe);
24422444

24432445
/* Arch may override these (weak) */
@@ -2490,6 +2492,10 @@ static inline int pci_sriov_get_totalvfs(struct pci_dev *dev)
24902492
#define pci_sriov_configure_simple NULL
24912493
static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
24922494
{ return 0; }
2495+
static inline int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size)
2496+
{ return -ENODEV; }
2497+
static inline u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs)
2498+
{ return 0; }
24932499
static inline void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe) { }
24942500
#endif
24952501

0 commit comments

Comments
 (0)