Skip to content

Commit 29ccb7b

Browse files
committed
Merge branch 'pci/resources'
- Restore VF resizable BAR state after reset (Michał Winiarski) - Add pci_resource_num_to_vf_bar() and pci_resource_num_from_vf_bar() to convert between VF BAR number and the dev->resource[] index (Michał Winiarski) - Allow IOV resources (VF BARs) to be resized (Michał Winiarski) - Add pci_iov_vf_bar_set_size() so drivers can control VF BAR size (Michał Winiarski) * pci/resources: PCI/IOV: Allow drivers to control VF BAR size PCI/IOV: Check that VF BAR fits within the reservation PCI/IOV: Allow IOV resources to be resized in pci_resize_resource() PCI/IOV: Add pci_resource_num_to_vf_bar() to convert VF BAR number to/from IOV resource PCI/IOV: Restore VF resizable BAR state after reset
2 parents 618c1ea + 84f8904 commit 29ccb7b

7 files changed

Lines changed: 235 additions & 18 deletions

File tree

drivers/pci/iov.c

Lines changed: 142 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@
77
* Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
88
*/
99

10+
#include <linux/bitfield.h>
11+
#include <linux/bits.h>
12+
#include <linux/log2.h>
1013
#include <linux/pci.h>
14+
#include <linux/sizes.h>
1115
#include <linux/slab.h>
1216
#include <linux/export.h>
1317
#include <linux/string.h>
1418
#include <linux/delay.h>
19+
#include <asm/div64.h>
1520
#include "pci.h"
1621

1722
#define VIRTFN_ID_LEN 17 /* "virtfn%u\0" for 2^32 - 1 */
@@ -150,7 +155,28 @@ resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
150155
if (!dev->is_physfn)
151156
return 0;
152157

153-
return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
158+
return dev->sriov->barsz[pci_resource_num_to_vf_bar(resno)];
159+
}
160+
161+
void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
162+
resource_size_t size)
163+
{
164+
if (!pci_resource_is_iov(resno)) {
165+
pci_warn(dev, "%s is not an IOV resource\n",
166+
pci_resource_name(dev, resno));
167+
return;
168+
}
169+
170+
dev->sriov->barsz[pci_resource_num_to_vf_bar(resno)] = size;
171+
}
172+
173+
bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
174+
{
175+
u16 cmd;
176+
177+
pci_read_config_word(dev, dev->sriov->pos + PCI_SRIOV_CTRL, &cmd);
178+
179+
return cmd & PCI_SRIOV_CTRL_MSE;
154180
}
155181

156182
static void pci_read_vf_config_common(struct pci_dev *virtfn)
@@ -341,12 +367,14 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
341367
virtfn->multifunction = 0;
342368

343369
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
344-
res = &dev->resource[i + PCI_IOV_RESOURCES];
370+
int idx = pci_resource_num_from_vf_bar(i);
371+
372+
res = &dev->resource[idx];
345373
if (!res->parent)
346374
continue;
347375
virtfn->resource[i].name = pci_name(virtfn);
348376
virtfn->resource[i].flags = res->flags;
349-
size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES);
377+
size = pci_iov_resource_size(dev, idx);
350378
resource_set_range(&virtfn->resource[i],
351379
res->start + size * id, size);
352380
rc = request_resource(res, &virtfn->resource[i]);
@@ -643,8 +671,13 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
643671

644672
nres = 0;
645673
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
646-
bars |= (1 << (i + PCI_IOV_RESOURCES));
647-
res = &dev->resource[i + PCI_IOV_RESOURCES];
674+
int idx = pci_resource_num_from_vf_bar(i);
675+
resource_size_t vf_bar_sz = pci_iov_resource_size(dev, idx);
676+
677+
bars |= (1 << idx);
678+
res = &dev->resource[idx];
679+
if (vf_bar_sz * nr_virtfn > resource_size(res))
680+
continue;
648681
if (res->parent)
649682
nres++;
650683
}
@@ -810,8 +843,10 @@ static int sriov_init(struct pci_dev *dev, int pos)
810843

811844
nres = 0;
812845
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
813-
res = &dev->resource[i + PCI_IOV_RESOURCES];
814-
res_name = pci_resource_name(dev, i + PCI_IOV_RESOURCES);
846+
int idx = pci_resource_num_from_vf_bar(i);
847+
848+
res = &dev->resource[idx];
849+
res_name = pci_resource_name(dev, idx);
815850

816851
/*
817852
* If it is already FIXED, don't change it, something
@@ -850,6 +885,7 @@ static int sriov_init(struct pci_dev *dev, int pos)
850885
pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
851886
if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)
852887
iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link);
888+
iov->vf_rebar_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VF_REBAR);
853889

854890
if (pdev)
855891
iov->dev = pci_dev_get(pdev);
@@ -869,7 +905,7 @@ static int sriov_init(struct pci_dev *dev, int pos)
869905
dev->is_physfn = 0;
870906
failed:
871907
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
872-
res = &dev->resource[i + PCI_IOV_RESOURCES];
908+
res = &dev->resource[pci_resource_num_from_vf_bar(i)];
873909
res->flags = 0;
874910
}
875911

@@ -888,6 +924,30 @@ static void sriov_release(struct pci_dev *dev)
888924
dev->sriov = NULL;
889925
}
890926

927+
static void sriov_restore_vf_rebar_state(struct pci_dev *dev)
928+
{
929+
unsigned int pos, nbars, i;
930+
u32 ctrl;
931+
932+
pos = pci_iov_vf_rebar_cap(dev);
933+
if (!pos)
934+
return;
935+
936+
pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
937+
nbars = FIELD_GET(PCI_VF_REBAR_CTRL_NBAR_MASK, ctrl);
938+
939+
for (i = 0; i < nbars; i++, pos += 8) {
940+
int bar_idx, size;
941+
942+
pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
943+
bar_idx = FIELD_GET(PCI_VF_REBAR_CTRL_BAR_IDX, ctrl);
944+
size = pci_rebar_bytes_to_size(dev->sriov->barsz[bar_idx]);
945+
ctrl &= ~PCI_VF_REBAR_CTRL_BAR_SIZE;
946+
ctrl |= FIELD_PREP(PCI_VF_REBAR_CTRL_BAR_SIZE, size);
947+
pci_write_config_dword(dev, pos + PCI_VF_REBAR_CTRL, ctrl);
948+
}
949+
}
950+
891951
static void sriov_restore_state(struct pci_dev *dev)
892952
{
893953
int i;
@@ -907,7 +967,7 @@ static void sriov_restore_state(struct pci_dev *dev)
907967
pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl);
908968

909969
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
910-
pci_update_resource(dev, i + PCI_IOV_RESOURCES);
970+
pci_update_resource(dev, pci_resource_num_from_vf_bar(i));
911971

912972
pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
913973
pci_iov_set_numvfs(dev, iov->num_VFs);
@@ -973,7 +1033,7 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno)
9731033
{
9741034
struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL;
9751035
struct resource *res = pci_resource_n(dev, resno);
976-
int vf_bar = resno - PCI_IOV_RESOURCES;
1036+
int vf_bar = pci_resource_num_to_vf_bar(resno);
9771037
struct pci_bus_region region;
9781038
u16 cmd;
9791039
u32 new;
@@ -1047,8 +1107,10 @@ resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
10471107
*/
10481108
void pci_restore_iov_state(struct pci_dev *dev)
10491109
{
1050-
if (dev->is_physfn)
1110+
if (dev->is_physfn) {
1111+
sriov_restore_vf_rebar_state(dev);
10511112
sriov_restore_state(dev);
1113+
}
10521114
}
10531115

10541116
/**
@@ -1255,3 +1317,72 @@ int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn)
12551317
return nr_virtfn;
12561318
}
12571319
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);

drivers/pci/pci.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3756,7 +3756,13 @@ static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
37563756
unsigned int pos, nbars, i;
37573757
u32 ctrl;
37583758

3759-
pos = pdev->rebar_cap;
3759+
if (pci_resource_is_iov(bar)) {
3760+
pos = pci_iov_vf_rebar_cap(pdev);
3761+
bar = pci_resource_num_to_vf_bar(bar);
3762+
} else {
3763+
pos = pdev->rebar_cap;
3764+
}
3765+
37603766
if (!pos)
37613767
return -ENOTSUPP;
37623768

drivers/pci/pci.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ struct pci_sriov {
492492
u16 subsystem_vendor; /* VF subsystem vendor */
493493
u16 subsystem_device; /* VF subsystem device */
494494
resource_size_t barsz[PCI_SRIOV_NUM_BARS]; /* VF BAR size */
495+
u16 vf_rebar_cap; /* VF Resizable BAR capability offset */
495496
bool drivers_autoprobe; /* Auto probing of VFs by driver */
496497
};
497498

@@ -716,10 +717,28 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno);
716717
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
717718
void pci_restore_iov_state(struct pci_dev *dev);
718719
int pci_iov_bus_range(struct pci_bus *bus);
720+
void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
721+
resource_size_t size);
722+
bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev);
723+
static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev)
724+
{
725+
if (!dev->is_physfn)
726+
return 0;
727+
728+
return dev->sriov->vf_rebar_cap;
729+
}
719730
static inline bool pci_resource_is_iov(int resno)
720731
{
721732
return resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END;
722733
}
734+
static inline int pci_resource_num_from_vf_bar(int resno)
735+
{
736+
return resno + PCI_IOV_RESOURCES;
737+
}
738+
static inline int pci_resource_num_to_vf_bar(int resno)
739+
{
740+
return resno - PCI_IOV_RESOURCES;
741+
}
723742
extern const struct attribute_group sriov_pf_dev_attr_group;
724743
extern const struct attribute_group sriov_vf_dev_attr_group;
725744
#else
@@ -740,10 +759,30 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
740759
{
741760
return 0;
742761
}
762+
static inline void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
763+
resource_size_t size) { }
764+
static inline bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
765+
{
766+
return false;
767+
}
768+
static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev)
769+
{
770+
return 0;
771+
}
743772
static inline bool pci_resource_is_iov(int resno)
744773
{
745774
return false;
746775
}
776+
static inline int pci_resource_num_from_vf_bar(int resno)
777+
{
778+
WARN_ON_ONCE(1);
779+
return -ENODEV;
780+
}
781+
static inline int pci_resource_num_to_vf_bar(int resno)
782+
{
783+
WARN_ON_ONCE(1);
784+
return -ENODEV;
785+
}
747786
#endif /* CONFIG_PCI_IOV */
748787

749788
#ifdef CONFIG_PCIE_TPH

drivers/pci/setup-bus.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1888,7 +1888,8 @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data)
18881888
bool *unassigned = data;
18891889

18901890
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
1891-
struct resource *r = &dev->resource[i + PCI_IOV_RESOURCES];
1891+
int idx = pci_resource_num_from_vf_bar(i);
1892+
struct resource *r = &dev->resource[idx];
18921893
struct pci_bus_region region;
18931894

18941895
/* Not assigned or rejected by kernel? */

0 commit comments

Comments
 (0)