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/log2.h> 11 #include <linux/pci.h> 12 #include <linux/sizes.h> 13 #include <linux/types.h> 14 15 #include "pci.h" 16 17 #define PCI_REBAR_MIN_SIZE ((resource_size_t)SZ_1M) 18 19 /** 20 * pci_rebar_bytes_to_size - Convert size in bytes to PCI BAR Size 21 * @bytes: size in bytes 22 * 23 * Convert size in bytes to encoded BAR Size in Resizable BAR Capability 24 * (PCIe r6.2, sec. 7.8.6.3). 25 * 26 * Return: encoded BAR Size as defined in the PCIe spec (0=1MB, 31=128TB) 27 */ 28 int pci_rebar_bytes_to_size(u64 bytes) 29 { 30 int rebar_minsize = ilog2(PCI_REBAR_MIN_SIZE); 31 32 bytes = roundup_pow_of_two(bytes); 33 34 return max(ilog2(bytes), rebar_minsize) - rebar_minsize; 35 } 36 EXPORT_SYMBOL_GPL(pci_rebar_bytes_to_size); 37 38 /** 39 * pci_rebar_size_to_bytes - Convert encoded BAR Size to size in bytes 40 * @size: encoded BAR Size as defined in the PCIe spec (0=1MB, 31=128TB) 41 * 42 * Return: BAR size in bytes 43 */ 44 resource_size_t pci_rebar_size_to_bytes(int size) 45 { 46 return 1ULL << (size + ilog2(PCI_REBAR_MIN_SIZE)); 47 } 48 EXPORT_SYMBOL_GPL(pci_rebar_size_to_bytes); 49 50 void pci_rebar_init(struct pci_dev *pdev) 51 { 52 pdev->rebar_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR); 53 } 54 55 /** 56 * pci_rebar_find_pos - find position of resize ctrl reg for BAR 57 * @pdev: PCI device 58 * @bar: BAR to find 59 * 60 * Helper to find the position of the ctrl register for a BAR. 61 * Returns -ENOTSUPP if resizable BARs are not supported at all. 62 * Returns -ENOENT if no ctrl register for the BAR could be found. 63 */ 64 static int pci_rebar_find_pos(struct pci_dev *pdev, int bar) 65 { 66 unsigned int pos, nbars, i; 67 u32 ctrl; 68 69 if (pci_resource_is_iov(bar)) { 70 pos = pci_iov_vf_rebar_cap(pdev); 71 bar = pci_resource_num_to_vf_bar(bar); 72 } else { 73 pos = pdev->rebar_cap; 74 } 75 76 if (!pos) 77 return -ENOTSUPP; 78 79 pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 80 nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl); 81 82 for (i = 0; i < nbars; i++, pos += 8) { 83 int bar_idx; 84 85 pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 86 bar_idx = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, ctrl); 87 if (bar_idx == bar) 88 return pos; 89 } 90 91 return -ENOENT; 92 } 93 94 /** 95 * pci_rebar_get_possible_sizes - get possible sizes for BAR 96 * @pdev: PCI device 97 * @bar: BAR to query 98 * 99 * Get the possible sizes of a resizable BAR as bitmask defined in the spec 100 * (bit 0=1MB, bit 31=128TB). Returns 0 if BAR isn't resizable. 101 */ 102 u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar) 103 { 104 int pos; 105 u32 cap; 106 107 pos = pci_rebar_find_pos(pdev, bar); 108 if (pos < 0) 109 return 0; 110 111 pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap); 112 cap = FIELD_GET(PCI_REBAR_CAP_SIZES, cap); 113 114 /* Sapphire RX 5600 XT Pulse has an invalid cap dword for BAR 0 */ 115 if (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x731f && 116 bar == 0 && cap == 0x700) 117 return 0x3f00; 118 119 return cap; 120 } 121 EXPORT_SYMBOL(pci_rebar_get_possible_sizes); 122 123 /** 124 * pci_rebar_get_current_size - get the current size of a BAR 125 * @pdev: PCI device 126 * @bar: BAR to set size to 127 * 128 * Read the size of a BAR from the resizable BAR config. 129 * Returns size if found or negative error code. 130 */ 131 int pci_rebar_get_current_size(struct pci_dev *pdev, int bar) 132 { 133 int pos; 134 u32 ctrl; 135 136 pos = pci_rebar_find_pos(pdev, bar); 137 if (pos < 0) 138 return pos; 139 140 pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 141 return FIELD_GET(PCI_REBAR_CTRL_BAR_SIZE, ctrl); 142 } 143 144 /** 145 * pci_rebar_set_size - set a new size for a BAR 146 * @pdev: PCI device 147 * @bar: BAR to set size to 148 * @size: new size as defined in the spec (0=1MB, 31=128TB) 149 * 150 * Set the new size of a BAR as defined in the spec. 151 * Returns zero if resizing was successful, error code otherwise. 152 */ 153 int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) 154 { 155 int pos; 156 u32 ctrl; 157 158 pos = pci_rebar_find_pos(pdev, bar); 159 if (pos < 0) 160 return pos; 161 162 pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 163 ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; 164 ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size); 165 pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); 166 167 if (pci_resource_is_iov(bar)) 168 pci_iov_resource_set_size(pdev, bar, size); 169 170 return 0; 171 } 172 173 void pci_restore_rebar_state(struct pci_dev *pdev) 174 { 175 unsigned int pos, nbars, i; 176 u32 ctrl; 177 178 pos = pdev->rebar_cap; 179 if (!pos) 180 return; 181 182 pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 183 nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl); 184 185 for (i = 0; i < nbars; i++, pos += 8) { 186 struct resource *res; 187 int bar_idx, size; 188 189 pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); 190 bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX; 191 res = pci_resource_n(pdev, bar_idx); 192 size = pci_rebar_bytes_to_size(resource_size(res)); 193 ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; 194 ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size); 195 pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); 196 } 197 } 198 199 static bool pci_resize_is_memory_decoding_enabled(struct pci_dev *dev, 200 int resno) 201 { 202 u16 cmd; 203 204 if (pci_resource_is_iov(resno)) 205 return pci_iov_is_memory_decoding_enabled(dev); 206 207 pci_read_config_word(dev, PCI_COMMAND, &cmd); 208 209 return cmd & PCI_COMMAND_MEMORY; 210 } 211 212 void pci_resize_resource_set_size(struct pci_dev *dev, int resno, int size) 213 { 214 resource_size_t res_size = pci_rebar_size_to_bytes(size); 215 struct resource *res = pci_resource_n(dev, resno); 216 217 if (pci_resource_is_iov(resno)) 218 res_size *= pci_sriov_get_totalvfs(dev); 219 220 resource_set_size(res, res_size); 221 } 222 223 /** 224 * pci_resize_resource - reconfigure a Resizable BAR and resources 225 * @dev: the PCI device 226 * @resno: index of the BAR to be resized 227 * @size: new size as defined in the spec (0=1MB, 31=128TB) 228 * @exclude_bars: a mask of BARs that should not be released 229 * 230 * Reconfigure @resno to @size and re-run resource assignment algorithm 231 * with the new size. 232 * 233 * Prior to resize, release @dev resources that share a bridge window with 234 * @resno. This unpins the bridge window resource to allow changing it. 235 * 236 * The caller may prevent releasing a particular BAR by providing 237 * @exclude_bars mask, but this may result in the resize operation failing 238 * due to insufficient space. 239 * 240 * Return: 0 on success, or negative on error. In case of an error, the 241 * resources are restored to their original places. 242 */ 243 int pci_resize_resource(struct pci_dev *dev, int resno, int size, 244 int exclude_bars) 245 { 246 struct pci_host_bridge *host; 247 int old, ret; 248 u32 sizes; 249 250 /* Check if we must preserve the firmware's resource assignment */ 251 host = pci_find_host_bridge(dev->bus); 252 if (host->preserve_config) 253 return -ENOTSUPP; 254 255 if (pci_resize_is_memory_decoding_enabled(dev, resno)) 256 return -EBUSY; 257 258 sizes = pci_rebar_get_possible_sizes(dev, resno); 259 if (!sizes) 260 return -ENOTSUPP; 261 262 if (!(sizes & BIT(size))) 263 return -EINVAL; 264 265 old = pci_rebar_get_current_size(dev, resno); 266 if (old < 0) 267 return old; 268 269 ret = pci_rebar_set_size(dev, resno, size); 270 if (ret) 271 return ret; 272 273 ret = pci_do_resource_release_and_resize(dev, resno, size, exclude_bars); 274 if (ret) 275 goto error_resize; 276 return 0; 277 278 error_resize: 279 pci_rebar_set_size(dev, resno, old); 280 return ret; 281 } 282 EXPORT_SYMBOL(pci_resize_resource); 283