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