Skip to content

Commit e200f4f

Browse files
mwiniarsbjorn-helgaas
authored andcommitted
PCI/IOV: Allow IOV resources to be resized in pci_resize_resource()
Similar to regular resizable BARs, VF BARs can also be resized. The capability layout is the same as PCI_EXT_CAP_ID_REBAR, which means we can reuse most of the implementation, the only difference being resource size calculation (which is multiplied by total VFs) and memory decoding (which is controlled by a separate VF MSE field in SR-IOV cap). Extend the pci_resize_resource() function to accept IOV resources. 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> Link: https://patch.msgid.link/20250702093522.518099-4-michal.winiarski@intel.com
1 parent 535bdbe commit e200f4f

4 files changed

Lines changed: 67 additions & 6 deletions

File tree

drivers/pci/iov.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,27 @@ resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
154154
return dev->sriov->barsz[pci_resource_num_to_vf_bar(resno)];
155155
}
156156

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

drivers/pci/pci.c

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

3755-
pos = pdev->rebar_cap;
3755+
if (pci_resource_is_iov(bar)) {
3756+
pos = pci_iov_vf_rebar_cap(pdev);
3757+
bar = pci_resource_num_to_vf_bar(bar);
3758+
} else {
3759+
pos = pdev->rebar_cap;
3760+
}
3761+
37563762
if (!pos)
37573763
return -ENOTSUPP;
37583764

drivers/pci/pci.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,9 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno);
711711
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
712712
void pci_restore_iov_state(struct pci_dev *dev);
713713
int pci_iov_bus_range(struct pci_bus *bus);
714+
void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
715+
resource_size_t size);
716+
bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev);
714717
static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev)
715718
{
716719
if (!dev->is_physfn)
@@ -750,6 +753,12 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
750753
{
751754
return 0;
752755
}
756+
static inline void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
757+
resource_size_t size) { }
758+
static inline bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
759+
{
760+
return false;
761+
}
753762
static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev)
754763
{
755764
return 0;

drivers/pci/setup-res.c

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -423,13 +423,39 @@ void pci_release_resource(struct pci_dev *dev, int resno)
423423
}
424424
EXPORT_SYMBOL(pci_release_resource);
425425

426+
static bool pci_resize_is_memory_decoding_enabled(struct pci_dev *dev,
427+
int resno)
428+
{
429+
u16 cmd;
430+
431+
if (pci_resource_is_iov(resno))
432+
return pci_iov_is_memory_decoding_enabled(dev);
433+
434+
pci_read_config_word(dev, PCI_COMMAND, &cmd);
435+
436+
return cmd & PCI_COMMAND_MEMORY;
437+
}
438+
439+
static void pci_resize_resource_set_size(struct pci_dev *dev, int resno,
440+
int size)
441+
{
442+
resource_size_t res_size = pci_rebar_size_to_bytes(size);
443+
struct resource *res = pci_resource_n(dev, resno);
444+
445+
if (!pci_resource_is_iov(resno)) {
446+
resource_set_size(res, res_size);
447+
} else {
448+
resource_set_size(res, res_size * pci_sriov_get_totalvfs(dev));
449+
pci_iov_resource_set_size(dev, resno, res_size);
450+
}
451+
}
452+
426453
int pci_resize_resource(struct pci_dev *dev, int resno, int size)
427454
{
428455
struct resource *res = pci_resource_n(dev, resno);
429456
struct pci_host_bridge *host;
430457
int old, ret;
431458
u32 sizes;
432-
u16 cmd;
433459

434460
/* Check if we must preserve the firmware's resource assignment */
435461
host = pci_find_host_bridge(dev->bus);
@@ -440,8 +466,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
440466
if (!(res->flags & IORESOURCE_UNSET))
441467
return -EBUSY;
442468

443-
pci_read_config_word(dev, PCI_COMMAND, &cmd);
444-
if (cmd & PCI_COMMAND_MEMORY)
469+
if (pci_resize_is_memory_decoding_enabled(dev, resno))
445470
return -EBUSY;
446471

447472
sizes = pci_rebar_get_possible_sizes(dev, resno);
@@ -459,7 +484,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
459484
if (ret)
460485
return ret;
461486

462-
resource_set_size(res, pci_rebar_size_to_bytes(size));
487+
pci_resize_resource_set_size(dev, resno, size);
463488

464489
/* Check if the new config works by trying to assign everything. */
465490
if (dev->bus->self) {
@@ -471,7 +496,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
471496

472497
error_resize:
473498
pci_rebar_set_size(dev, resno, old);
474-
resource_set_size(res, pci_rebar_size_to_bytes(old));
499+
pci_resize_resource_set_size(dev, resno, old);
475500
return ret;
476501
}
477502
EXPORT_SYMBOL(pci_resize_resource);

0 commit comments

Comments
 (0)