xref: /linux/drivers/pci/rebar.c (revision bb1fabd0d94efc29f88f86fb996c40ac06db3669)
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