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