File Index
Files and directories
Sign in
FILE

rebar.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/rebar.c C
  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 */
 30int 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}
 38EXPORT_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 */
 46resource_size_t pci_rebar_size_to_bytes(int size)
 47{
 48	return 1ULL << (size + ilog2(PCI_REBAR_MIN_SIZE));
 49}
 50EXPORT_SYMBOL_GPL(pci_rebar_size_to_bytes);
 51
 52void 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 */
 68static 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 */
108u64 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}
127EXPORT_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 */
138bool 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}
147EXPORT_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 */
159int 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}
169EXPORT_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 */
181int 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 */
204int 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	ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
215	ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size);
216	pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
217
218	if (pci_resource_is_iov(bar))
219		pci_iov_resource_set_size(pdev, bar, size);
220
221	return 0;
222}
223
224void pci_restore_rebar_state(struct pci_dev *pdev)
225{
226	unsigned int pos, nbars, i;
227	u32 ctrl;
228
229	pos = pdev->rebar_cap;
230	if (!pos)
231		return;
232
233	pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
234	nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl);
235
236	for (i = 0; i < nbars; i++, pos += 8) {
237		struct resource *res;
238		int bar_idx, size;
239
240		pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
241		bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
242		res = pci_resource_n(pdev, bar_idx);
243		size = pci_rebar_bytes_to_size(resource_size(res));
244		ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
245		ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size);
246		pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
247	}
248}
249
250static bool pci_resize_is_memory_decoding_enabled(struct pci_dev *dev,
251						  int resno)
252{
253	u16 cmd;
254
255	if (pci_resource_is_iov(resno))
256		return pci_iov_is_memory_decoding_enabled(dev);
257
258	pci_read_config_word(dev, PCI_COMMAND, &cmd);
259
260	return cmd & PCI_COMMAND_MEMORY;
261}
262
263void pci_resize_resource_set_size(struct pci_dev *dev, int resno, int size)
264{
265	resource_size_t res_size = pci_rebar_size_to_bytes(size);
266	struct resource *res = pci_resource_n(dev, resno);
267
268	if (pci_resource_is_iov(resno))
269		res_size *= pci_sriov_get_totalvfs(dev);
270
271	resource_set_size(res, res_size);
272}
273
274/**
275 * pci_resize_resource - reconfigure a Resizable BAR and resources
276 * @dev: the PCI device
277 * @resno: index of the BAR to be resized
278 * @size: new size as defined in the spec (0=1MB, 31=128TB)
279 * @exclude_bars: a mask of BARs that should not be released
280 *
281 * Reconfigure @resno to @size and re-run resource assignment algorithm
282 * with the new size.
283 *
284 * Prior to resize, release @dev resources that share a bridge window with
285 * @resno.  This unpins the bridge window resource to allow changing it.
286 *
287 * The caller may prevent releasing a particular BAR by providing
288 * @exclude_bars mask, but this may result in the resize operation failing
289 * due to insufficient space.
290 *
291 * Return: 0 on success, or negative on error. In case of an error, the
292 *         resources are restored to their original places.
293 */
294int pci_resize_resource(struct pci_dev *dev, int resno, int size,
295			int exclude_bars)
296{
297	struct pci_host_bridge *host;
298
299	/* Check if we must preserve the firmware's resource assignment */
300	host = pci_find_host_bridge(dev->bus);
301	if (host->preserve_config)
302		return -ENOTSUPP;
303
304	if (pci_resize_is_memory_decoding_enabled(dev, resno))
305		return -EBUSY;
306
307	if (!pci_rebar_size_supported(dev, resno, size))
308		return -EINVAL;
309
310	return pci_do_resource_release_and_resize(dev, resno, size, exclude_bars);
311}
312EXPORT_SYMBOL(pci_resize_resource);
~/ Read-only file preview.