Skip to content

Commit 5a8f77e

Browse files
mwiniarsbjorn-helgaas
authored andcommitted
PCI/IOV: Restore VF resizable BAR state after reset
Similar to regular resizable BARs, VF BARs can also be resized, e.g. by the system firmware or the PCI subsystem itself. The capability layout is the same as PCI_EXT_CAP_ID_REBAR. Add the capability ID and restore it as a part of IOV state. See PCIe r6.2, sec 7.8.7. 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> Reviewed-by: Christian König <christian.koenig@amd.com> Link: https://patch.msgid.link/20250702093522.518099-2-michal.winiarski@intel.com
1 parent 19272b3 commit 5a8f77e

3 files changed

Lines changed: 50 additions & 1 deletion

File tree

drivers/pci/iov.c

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

10+
#include <linux/bitfield.h>
1011
#include <linux/pci.h>
1112
#include <linux/slab.h>
1213
#include <linux/export.h>
@@ -850,6 +851,7 @@ static int sriov_init(struct pci_dev *dev, int pos)
850851
pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
851852
if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)
852853
iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link);
854+
iov->vf_rebar_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VF_REBAR);
853855

854856
if (pdev)
855857
iov->dev = pci_dev_get(pdev);
@@ -888,6 +890,30 @@ static void sriov_release(struct pci_dev *dev)
888890
dev->sriov = NULL;
889891
}
890892

893+
static void sriov_restore_vf_rebar_state(struct pci_dev *dev)
894+
{
895+
unsigned int pos, nbars, i;
896+
u32 ctrl;
897+
898+
pos = pci_iov_vf_rebar_cap(dev);
899+
if (!pos)
900+
return;
901+
902+
pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
903+
nbars = FIELD_GET(PCI_VF_REBAR_CTRL_NBAR_MASK, ctrl);
904+
905+
for (i = 0; i < nbars; i++, pos += 8) {
906+
int bar_idx, size;
907+
908+
pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
909+
bar_idx = FIELD_GET(PCI_VF_REBAR_CTRL_BAR_IDX, ctrl);
910+
size = pci_rebar_bytes_to_size(dev->sriov->barsz[bar_idx]);
911+
ctrl &= ~PCI_VF_REBAR_CTRL_BAR_SIZE;
912+
ctrl |= FIELD_PREP(PCI_VF_REBAR_CTRL_BAR_SIZE, size);
913+
pci_write_config_dword(dev, pos + PCI_VF_REBAR_CTRL, ctrl);
914+
}
915+
}
916+
891917
static void sriov_restore_state(struct pci_dev *dev)
892918
{
893919
int i;
@@ -1047,8 +1073,10 @@ resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
10471073
*/
10481074
void pci_restore_iov_state(struct pci_dev *dev)
10491075
{
1050-
if (dev->is_physfn)
1076+
if (dev->is_physfn) {
1077+
sriov_restore_vf_rebar_state(dev);
10511078
sriov_restore_state(dev);
1079+
}
10521080
}
10531081

10541082
/**

drivers/pci/pci.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ struct pci_sriov {
486486
u16 subsystem_vendor; /* VF subsystem vendor */
487487
u16 subsystem_device; /* VF subsystem device */
488488
resource_size_t barsz[PCI_SRIOV_NUM_BARS]; /* VF BAR size */
489+
u16 vf_rebar_cap; /* VF Resizable BAR capability offset */
489490
bool drivers_autoprobe; /* Auto probing of VFs by driver */
490491
};
491492

@@ -710,6 +711,13 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno);
710711
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
711712
void pci_restore_iov_state(struct pci_dev *dev);
712713
int pci_iov_bus_range(struct pci_bus *bus);
714+
static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev)
715+
{
716+
if (!dev->is_physfn)
717+
return 0;
718+
719+
return dev->sriov->vf_rebar_cap;
720+
}
713721
static inline bool pci_resource_is_iov(int resno)
714722
{
715723
return resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END;
@@ -734,6 +742,10 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
734742
{
735743
return 0;
736744
}
745+
static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev)
746+
{
747+
return 0;
748+
}
737749
static inline bool pci_resource_is_iov(int resno)
738750
{
739751
return false;

include/uapi/linux/pci_regs.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,7 @@
745745
#define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */
746746
#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */
747747
#define PCI_EXT_CAP_ID_DVSEC 0x23 /* Designated Vendor-Specific */
748+
#define PCI_EXT_CAP_ID_VF_REBAR 0x24 /* VF Resizable BAR */
748749
#define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */
749750
#define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */
750751
#define PCI_EXT_CAP_ID_NPEM 0x29 /* Native PCIe Enclosure Management */
@@ -1141,6 +1142,14 @@
11411142
#define PCI_DVSEC_HEADER2 0x8 /* Designated Vendor-Specific Header2 */
11421143
#define PCI_DVSEC_HEADER2_ID(x) ((x) & 0xffff)
11431144

1145+
/* VF Resizable BARs, same layout as PCI_REBAR */
1146+
#define PCI_VF_REBAR_CAP PCI_REBAR_CAP
1147+
#define PCI_VF_REBAR_CAP_SIZES PCI_REBAR_CAP_SIZES
1148+
#define PCI_VF_REBAR_CTRL PCI_REBAR_CTRL
1149+
#define PCI_VF_REBAR_CTRL_BAR_IDX PCI_REBAR_CTRL_BAR_IDX
1150+
#define PCI_VF_REBAR_CTRL_NBAR_MASK PCI_REBAR_CTRL_NBAR_MASK
1151+
#define PCI_VF_REBAR_CTRL_BAR_SIZE PCI_REBAR_CTRL_BAR_SIZE
1152+
11441153
/* Data Link Feature */
11451154
#define PCI_DLF_CAP 0x04 /* Capabilities Register */
11461155
#define PCI_DLF_EXCHANGE_ENABLE 0x80000000 /* Data Link Feature Exchange Enable */

0 commit comments

Comments
 (0)