Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Michał Winiarski and committed by
Bjorn Helgaas
e200f4f7 535bdbea

+67 -6
+21
drivers/pci/iov.c
··· 154 154 return dev->sriov->barsz[pci_resource_num_to_vf_bar(resno)]; 155 155 } 156 156 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 + 157 178 static void pci_read_vf_config_common(struct pci_dev *virtfn) 158 179 { 159 180 struct pci_dev *physfn = virtfn->physfn;
+7 -1
drivers/pci/pci.c
··· 3752 3752 unsigned int pos, nbars, i; 3753 3753 u32 ctrl; 3754 3754 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 + 3756 3762 if (!pos) 3757 3763 return -ENOTSUPP; 3758 3764
+9
drivers/pci/pci.h
··· 711 711 resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno); 712 712 void pci_restore_iov_state(struct pci_dev *dev); 713 713 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); 714 717 static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev) 715 718 { 716 719 if (!dev->is_physfn) ··· 752 749 static inline int pci_iov_bus_range(struct pci_bus *bus) 753 750 { 754 751 return 0; 752 + } 753 + static inline void pci_iov_resource_set_size(struct pci_dev *dev, int resno, 754 + resource_size_t size) { } 755 + static inline bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev) 756 + { 757 + return false; 755 758 } 756 759 static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev) 757 760 {
+30 -5
drivers/pci/setup-res.c
··· 423 423 } 424 424 EXPORT_SYMBOL(pci_release_resource); 425 425 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 + 426 453 int pci_resize_resource(struct pci_dev *dev, int resno, int size) 427 454 { 428 455 struct resource *res = pci_resource_n(dev, resno); 429 456 struct pci_host_bridge *host; 430 457 int old, ret; 431 458 u32 sizes; 432 - u16 cmd; 433 459 434 460 /* Check if we must preserve the firmware's resource assignment */ 435 461 host = pci_find_host_bridge(dev->bus); ··· 466 440 if (!(res->flags & IORESOURCE_UNSET)) 467 441 return -EBUSY; 468 442 469 - pci_read_config_word(dev, PCI_COMMAND, &cmd); 470 - if (cmd & PCI_COMMAND_MEMORY) 443 + if (pci_resize_is_memory_decoding_enabled(dev, resno)) 471 444 return -EBUSY; 472 445 473 446 sizes = pci_rebar_get_possible_sizes(dev, resno); ··· 484 459 if (ret) 485 460 return ret; 486 461 487 - resource_set_size(res, pci_rebar_size_to_bytes(size)); 462 + pci_resize_resource_set_size(dev, resno, size); 488 463 489 464 /* Check if the new config works by trying to assign everything. */ 490 465 if (dev->bus->self) { ··· 496 471 497 472 error_resize: 498 473 pci_rebar_set_size(dev, resno, old); 499 - resource_set_size(res, pci_rebar_size_to_bytes(old)); 474 + pci_resize_resource_set_size(dev, resno, old); 500 475 return ret; 501 476 } 502 477 EXPORT_SYMBOL(pci_resize_resource);