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

PCI: Move Resizable BAR code to rebar.c

For lack of a better place to put it, Resizable BAR code has been placed
inside pci.c and setup-res.c that do not use it for anything. Upcoming
changes are going to add more Resizable BAR related functions, increasing
the code size.

As pci.c is huge as is, move the Resizable BAR related code and the BAR
resize code from setup-res.c to rebar.c.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Link: https://patch.msgid.link/20251113180053.27944-2-ilpo.jarvinen@linux.intel.com

authored by

Ilpo Järvinen and committed by
Bjorn Helgaas
9f71938c 7409c1b1

+252 -235
+3
Documentation/driver-api/pci/pci.rst
··· 37 37 .. kernel-doc:: drivers/pci/slot.c 38 38 :export: 39 39 40 + .. kernel-doc:: drivers/pci/rebar.c 41 + :export: 42 + 40 43 .. kernel-doc:: drivers/pci/rom.c 41 44 :export: 42 45
+1 -1
drivers/pci/Makefile
··· 4 4 5 5 obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \ 6 6 remove.o pci.o pci-driver.o search.o \ 7 - rom.o setup-res.o irq.o vpd.o \ 7 + rebar.o rom.o setup-res.o irq.o vpd.o \ 8 8 setup-bus.o vc.o mmap.o devres.o 9 9 10 10 obj-$(CONFIG_PCI) += msi/
-149
drivers/pci/pci.c
··· 1823 1823 } 1824 1824 } 1825 1825 1826 - static void pci_restore_rebar_state(struct pci_dev *pdev) 1827 - { 1828 - unsigned int pos, nbars, i; 1829 - u32 ctrl; 1830 - 1831 - pos = pdev->rebar_cap; 1832 - if (!pos) 1833 - return; 1834 - 1835 - pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 1836 - nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl); 1837 - 1838 - for (i = 0; i < nbars; i++, pos += 8) { 1839 - struct resource *res; 1840 - int bar_idx, size; 1841 - 1842 - pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 1843 - bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX; 1844 - res = pci_resource_n(pdev, bar_idx); 1845 - size = pci_rebar_bytes_to_size(resource_size(res)); 1846 - ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; 1847 - ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size); 1848 - pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); 1849 - } 1850 - } 1851 - 1852 1826 /** 1853 1827 * pci_restore_state - Restore the saved state of a PCI device 1854 1828 * @dev: PCI device that we're dealing with ··· 3659 3685 * quirks. 3660 3686 */ 3661 3687 pci_enable_acs(dev); 3662 - } 3663 - 3664 - void pci_rebar_init(struct pci_dev *pdev) 3665 - { 3666 - pdev->rebar_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR); 3667 - } 3668 - 3669 - /** 3670 - * pci_rebar_find_pos - find position of resize ctrl reg for BAR 3671 - * @pdev: PCI device 3672 - * @bar: BAR to find 3673 - * 3674 - * Helper to find the position of the ctrl register for a BAR. 3675 - * Returns -ENOTSUPP if resizable BARs are not supported at all. 3676 - * Returns -ENOENT if no ctrl register for the BAR could be found. 3677 - */ 3678 - static int pci_rebar_find_pos(struct pci_dev *pdev, int bar) 3679 - { 3680 - unsigned int pos, nbars, i; 3681 - u32 ctrl; 3682 - 3683 - if (pci_resource_is_iov(bar)) { 3684 - pos = pci_iov_vf_rebar_cap(pdev); 3685 - bar = pci_resource_num_to_vf_bar(bar); 3686 - } else { 3687 - pos = pdev->rebar_cap; 3688 - } 3689 - 3690 - if (!pos) 3691 - return -ENOTSUPP; 3692 - 3693 - pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 3694 - nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl); 3695 - 3696 - for (i = 0; i < nbars; i++, pos += 8) { 3697 - int bar_idx; 3698 - 3699 - pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 3700 - bar_idx = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, ctrl); 3701 - if (bar_idx == bar) 3702 - return pos; 3703 - } 3704 - 3705 - return -ENOENT; 3706 - } 3707 - 3708 - /** 3709 - * pci_rebar_get_possible_sizes - get possible sizes for BAR 3710 - * @pdev: PCI device 3711 - * @bar: BAR to query 3712 - * 3713 - * Get the possible sizes of a resizable BAR as bitmask defined in the spec 3714 - * (bit 0=1MB, bit 31=128TB). Returns 0 if BAR isn't resizable. 3715 - */ 3716 - u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar) 3717 - { 3718 - int pos; 3719 - u32 cap; 3720 - 3721 - pos = pci_rebar_find_pos(pdev, bar); 3722 - if (pos < 0) 3723 - return 0; 3724 - 3725 - pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap); 3726 - cap = FIELD_GET(PCI_REBAR_CAP_SIZES, cap); 3727 - 3728 - /* Sapphire RX 5600 XT Pulse has an invalid cap dword for BAR 0 */ 3729 - if (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x731f && 3730 - bar == 0 && cap == 0x700) 3731 - return 0x3f00; 3732 - 3733 - return cap; 3734 - } 3735 - EXPORT_SYMBOL(pci_rebar_get_possible_sizes); 3736 - 3737 - /** 3738 - * pci_rebar_get_current_size - get the current size of a BAR 3739 - * @pdev: PCI device 3740 - * @bar: BAR to set size to 3741 - * 3742 - * Read the size of a BAR from the resizable BAR config. 3743 - * Returns size if found or negative error code. 3744 - */ 3745 - int pci_rebar_get_current_size(struct pci_dev *pdev, int bar) 3746 - { 3747 - int pos; 3748 - u32 ctrl; 3749 - 3750 - pos = pci_rebar_find_pos(pdev, bar); 3751 - if (pos < 0) 3752 - return pos; 3753 - 3754 - pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 3755 - return FIELD_GET(PCI_REBAR_CTRL_BAR_SIZE, ctrl); 3756 - } 3757 - 3758 - /** 3759 - * pci_rebar_set_size - set a new size for a BAR 3760 - * @pdev: PCI device 3761 - * @bar: BAR to set size to 3762 - * @size: new size as defined in the spec (0=1MB, 31=128TB) 3763 - * 3764 - * Set the new size of a BAR as defined in the spec. 3765 - * Returns zero if resizing was successful, error code otherwise. 3766 - */ 3767 - int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) 3768 - { 3769 - int pos; 3770 - u32 ctrl; 3771 - 3772 - pos = pci_rebar_find_pos(pdev, bar); 3773 - if (pos < 0) 3774 - return pos; 3775 - 3776 - pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 3777 - ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; 3778 - ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size); 3779 - pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); 3780 - 3781 - if (pci_resource_is_iov(bar)) 3782 - pci_iov_resource_set_size(pdev, bar, size); 3783 - 3784 - return 0; 3785 3688 } 3786 3689 3787 3690 /**
+1
drivers/pci/pci.h
··· 1021 1021 #endif 1022 1022 1023 1023 void pci_rebar_init(struct pci_dev *pdev); 1024 + void pci_restore_rebar_state(struct pci_dev *pdev); 1024 1025 int pci_rebar_get_current_size(struct pci_dev *pdev, int bar); 1025 1026 int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size); 1026 1027 static inline u64 pci_rebar_size_to_bytes(int size)
+247
drivers/pci/rebar.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * PCI Resizable BAR Extended Capability handling. 4 + */ 5 + 6 + #include <linux/bitfield.h> 7 + #include <linux/errno.h> 8 + #include <linux/export.h> 9 + #include <linux/ioport.h> 10 + #include <linux/pci.h> 11 + #include <linux/types.h> 12 + 13 + #include "pci.h" 14 + 15 + void pci_rebar_init(struct pci_dev *pdev) 16 + { 17 + pdev->rebar_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR); 18 + } 19 + 20 + /** 21 + * pci_rebar_find_pos - find position of resize ctrl reg for BAR 22 + * @pdev: PCI device 23 + * @bar: BAR to find 24 + * 25 + * Helper to find the position of the ctrl register for a BAR. 26 + * Returns -ENOTSUPP if resizable BARs are not supported at all. 27 + * Returns -ENOENT if no ctrl register for the BAR could be found. 28 + */ 29 + static int pci_rebar_find_pos(struct pci_dev *pdev, int bar) 30 + { 31 + unsigned int pos, nbars, i; 32 + u32 ctrl; 33 + 34 + if (pci_resource_is_iov(bar)) { 35 + pos = pci_iov_vf_rebar_cap(pdev); 36 + bar = pci_resource_num_to_vf_bar(bar); 37 + } else { 38 + pos = pdev->rebar_cap; 39 + } 40 + 41 + if (!pos) 42 + return -ENOTSUPP; 43 + 44 + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 45 + nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl); 46 + 47 + for (i = 0; i < nbars; i++, pos += 8) { 48 + int bar_idx; 49 + 50 + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 51 + bar_idx = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, ctrl); 52 + if (bar_idx == bar) 53 + return pos; 54 + } 55 + 56 + return -ENOENT; 57 + } 58 + 59 + /** 60 + * pci_rebar_get_possible_sizes - get possible sizes for BAR 61 + * @pdev: PCI device 62 + * @bar: BAR to query 63 + * 64 + * Get the possible sizes of a resizable BAR as bitmask defined in the spec 65 + * (bit 0=1MB, bit 31=128TB). Returns 0 if BAR isn't resizable. 66 + */ 67 + u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar) 68 + { 69 + int pos; 70 + u32 cap; 71 + 72 + pos = pci_rebar_find_pos(pdev, bar); 73 + if (pos < 0) 74 + return 0; 75 + 76 + pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap); 77 + cap = FIELD_GET(PCI_REBAR_CAP_SIZES, cap); 78 + 79 + /* Sapphire RX 5600 XT Pulse has an invalid cap dword for BAR 0 */ 80 + if (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x731f && 81 + bar == 0 && cap == 0x700) 82 + return 0x3f00; 83 + 84 + return cap; 85 + } 86 + EXPORT_SYMBOL(pci_rebar_get_possible_sizes); 87 + 88 + /** 89 + * pci_rebar_get_current_size - get the current size of a BAR 90 + * @pdev: PCI device 91 + * @bar: BAR to set size to 92 + * 93 + * Read the size of a BAR from the resizable BAR config. 94 + * Returns size if found or negative error code. 95 + */ 96 + int pci_rebar_get_current_size(struct pci_dev *pdev, int bar) 97 + { 98 + int pos; 99 + u32 ctrl; 100 + 101 + pos = pci_rebar_find_pos(pdev, bar); 102 + if (pos < 0) 103 + return pos; 104 + 105 + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 106 + return FIELD_GET(PCI_REBAR_CTRL_BAR_SIZE, ctrl); 107 + } 108 + 109 + /** 110 + * pci_rebar_set_size - set a new size for a BAR 111 + * @pdev: PCI device 112 + * @bar: BAR to set size to 113 + * @size: new size as defined in the spec (0=1MB, 31=128TB) 114 + * 115 + * Set the new size of a BAR as defined in the spec. 116 + * Returns zero if resizing was successful, error code otherwise. 117 + */ 118 + int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) 119 + { 120 + int pos; 121 + u32 ctrl; 122 + 123 + pos = pci_rebar_find_pos(pdev, bar); 124 + if (pos < 0) 125 + return pos; 126 + 127 + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 128 + ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; 129 + ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size); 130 + pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); 131 + 132 + if (pci_resource_is_iov(bar)) 133 + pci_iov_resource_set_size(pdev, bar, size); 134 + 135 + return 0; 136 + } 137 + 138 + void pci_restore_rebar_state(struct pci_dev *pdev) 139 + { 140 + unsigned int pos, nbars, i; 141 + u32 ctrl; 142 + 143 + pos = pdev->rebar_cap; 144 + if (!pos) 145 + return; 146 + 147 + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 148 + nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl); 149 + 150 + for (i = 0; i < nbars; i++, pos += 8) { 151 + struct resource *res; 152 + int bar_idx, size; 153 + 154 + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 155 + bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX; 156 + res = pci_resource_n(pdev, bar_idx); 157 + size = pci_rebar_bytes_to_size(resource_size(res)); 158 + ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; 159 + ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size); 160 + pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); 161 + } 162 + } 163 + 164 + static bool pci_resize_is_memory_decoding_enabled(struct pci_dev *dev, 165 + int resno) 166 + { 167 + u16 cmd; 168 + 169 + if (pci_resource_is_iov(resno)) 170 + return pci_iov_is_memory_decoding_enabled(dev); 171 + 172 + pci_read_config_word(dev, PCI_COMMAND, &cmd); 173 + 174 + return cmd & PCI_COMMAND_MEMORY; 175 + } 176 + 177 + void pci_resize_resource_set_size(struct pci_dev *dev, int resno, int size) 178 + { 179 + resource_size_t res_size = pci_rebar_size_to_bytes(size); 180 + struct resource *res = pci_resource_n(dev, resno); 181 + 182 + if (pci_resource_is_iov(resno)) 183 + res_size *= pci_sriov_get_totalvfs(dev); 184 + 185 + resource_set_size(res, res_size); 186 + } 187 + 188 + /** 189 + * pci_resize_resource - reconfigure a Resizable BAR and resources 190 + * @dev: the PCI device 191 + * @resno: index of the BAR to be resized 192 + * @size: new size as defined in the spec (0=1MB, 31=128TB) 193 + * @exclude_bars: a mask of BARs that should not be released 194 + * 195 + * Reconfigure @resno to @size and re-run resource assignment algorithm 196 + * with the new size. 197 + * 198 + * Prior to resize, release @dev resources that share a bridge window with 199 + * @resno. This unpins the bridge window resource to allow changing it. 200 + * 201 + * The caller may prevent releasing a particular BAR by providing 202 + * @exclude_bars mask, but this may result in the resize operation failing 203 + * due to insufficient space. 204 + * 205 + * Return: 0 on success, or negative on error. In case of an error, the 206 + * resources are restored to their original places. 207 + */ 208 + int pci_resize_resource(struct pci_dev *dev, int resno, int size, 209 + int exclude_bars) 210 + { 211 + struct pci_host_bridge *host; 212 + int old, ret; 213 + u32 sizes; 214 + 215 + /* Check if we must preserve the firmware's resource assignment */ 216 + host = pci_find_host_bridge(dev->bus); 217 + if (host->preserve_config) 218 + return -ENOTSUPP; 219 + 220 + if (pci_resize_is_memory_decoding_enabled(dev, resno)) 221 + return -EBUSY; 222 + 223 + sizes = pci_rebar_get_possible_sizes(dev, resno); 224 + if (!sizes) 225 + return -ENOTSUPP; 226 + 227 + if (!(sizes & BIT(size))) 228 + return -EINVAL; 229 + 230 + old = pci_rebar_get_current_size(dev, resno); 231 + if (old < 0) 232 + return old; 233 + 234 + ret = pci_rebar_set_size(dev, resno, size); 235 + if (ret) 236 + return ret; 237 + 238 + ret = pci_do_resource_release_and_resize(dev, resno, size, exclude_bars); 239 + if (ret) 240 + goto error_resize; 241 + return 0; 242 + 243 + error_resize: 244 + pci_rebar_set_size(dev, resno, old); 245 + return ret; 246 + } 247 + EXPORT_SYMBOL(pci_resize_resource);
-85
drivers/pci/setup-res.c
··· 431 431 } 432 432 EXPORT_SYMBOL(pci_release_resource); 433 433 434 - static bool pci_resize_is_memory_decoding_enabled(struct pci_dev *dev, 435 - int resno) 436 - { 437 - u16 cmd; 438 - 439 - if (pci_resource_is_iov(resno)) 440 - return pci_iov_is_memory_decoding_enabled(dev); 441 - 442 - pci_read_config_word(dev, PCI_COMMAND, &cmd); 443 - 444 - return cmd & PCI_COMMAND_MEMORY; 445 - } 446 - 447 - void pci_resize_resource_set_size(struct pci_dev *dev, int resno, int size) 448 - { 449 - resource_size_t res_size = pci_rebar_size_to_bytes(size); 450 - struct resource *res = pci_resource_n(dev, resno); 451 - 452 - if (pci_resource_is_iov(resno)) 453 - res_size *= pci_sriov_get_totalvfs(dev); 454 - 455 - resource_set_size(res, res_size); 456 - } 457 - 458 - /** 459 - * pci_resize_resource - reconfigure a Resizable BAR and resources 460 - * @dev: the PCI device 461 - * @resno: index of the BAR to be resized 462 - * @size: new size as defined in the spec (0=1MB, 31=128TB) 463 - * @exclude_bars: a mask of BARs that should not be released 464 - * 465 - * Reconfigure @resno to @size and re-run resource assignment algorithm 466 - * with the new size. 467 - * 468 - * Prior to resize, release @dev resources that share a bridge window with 469 - * @resno. This unpins the bridge window resource to allow changing it. 470 - * 471 - * The caller may prevent releasing a particular BAR by providing 472 - * @exclude_bars mask, but this may result in the resize operation failing 473 - * due to insufficient space. 474 - * 475 - * Return: 0 on success, or negative on error. In case of an error, the 476 - * resources are restored to their original places. 477 - */ 478 - int pci_resize_resource(struct pci_dev *dev, int resno, int size, 479 - int exclude_bars) 480 - { 481 - struct pci_host_bridge *host; 482 - int old, ret; 483 - u32 sizes; 484 - 485 - /* Check if we must preserve the firmware's resource assignment */ 486 - host = pci_find_host_bridge(dev->bus); 487 - if (host->preserve_config) 488 - return -ENOTSUPP; 489 - 490 - if (pci_resize_is_memory_decoding_enabled(dev, resno)) 491 - return -EBUSY; 492 - 493 - sizes = pci_rebar_get_possible_sizes(dev, resno); 494 - if (!sizes) 495 - return -ENOTSUPP; 496 - 497 - if (!(sizes & BIT(size))) 498 - return -EINVAL; 499 - 500 - old = pci_rebar_get_current_size(dev, resno); 501 - if (old < 0) 502 - return old; 503 - 504 - ret = pci_rebar_set_size(dev, resno, size); 505 - if (ret) 506 - return ret; 507 - 508 - ret = pci_do_resource_release_and_resize(dev, resno, size, exclude_bars); 509 - if (ret) 510 - goto error_resize; 511 - return 0; 512 - 513 - error_resize: 514 - pci_rebar_set_size(dev, resno, old); 515 - return ret; 516 - } 517 - EXPORT_SYMBOL(pci_resize_resource); 518 - 519 434 int pci_enable_resources(struct pci_dev *dev, int mask) 520 435 { 521 436 u16 cmd, old_cmd;