Skip to content

Commit 276b738

Browse files
ChristianKoenigAMDbjorn-helgaas
authored andcommitted
PCI: Add resizable BAR infrastructure
Add resizable BAR infrastructure, including defines and helper functions to read the possible sizes of a BAR and update its size. See PCIe r3.1, sec 7.22. Link: https://pcisig.com/sites/default/files/specification_documents/ECN_Resizable-BAR_24Apr2008.pdf Signed-off-by: Christian König <christian.koenig@amd.com> [bhelgaas: rename to functions with "rebar" (to match #defines), drop shift #defines, drop "_MASK" suffixes, fix typos, fix kerneldoc] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
1 parent cb21bc9 commit 276b738

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
lines changed

drivers/pci/pci.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2965,6 +2965,107 @@ bool pci_acs_path_enabled(struct pci_dev *start,
29652965
return true;
29662966
}
29672967

2968+
/**
2969+
* pci_rebar_find_pos - find position of resize ctrl reg for BAR
2970+
* @pdev: PCI device
2971+
* @bar: BAR to find
2972+
*
2973+
* Helper to find the position of the ctrl register for a BAR.
2974+
* Returns -ENOTSUPP if resizable BARs are not supported at all.
2975+
* Returns -ENOENT if no ctrl register for the BAR could be found.
2976+
*/
2977+
static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
2978+
{
2979+
unsigned int pos, nbars, i;
2980+
u32 ctrl;
2981+
2982+
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
2983+
if (!pos)
2984+
return -ENOTSUPP;
2985+
2986+
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
2987+
nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >>
2988+
PCI_REBAR_CTRL_NBAR_SHIFT;
2989+
2990+
for (i = 0; i < nbars; i++, pos += 8) {
2991+
int bar_idx;
2992+
2993+
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
2994+
bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
2995+
if (bar_idx == bar)
2996+
return pos;
2997+
}
2998+
2999+
return -ENOENT;
3000+
}
3001+
3002+
/**
3003+
* pci_rebar_get_possible_sizes - get possible sizes for BAR
3004+
* @pdev: PCI device
3005+
* @bar: BAR to query
3006+
*
3007+
* Get the possible sizes of a resizable BAR as bitmask defined in the spec
3008+
* (bit 0=1MB, bit 19=512GB). Returns 0 if BAR isn't resizable.
3009+
*/
3010+
u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar)
3011+
{
3012+
int pos;
3013+
u32 cap;
3014+
3015+
pos = pci_rebar_find_pos(pdev, bar);
3016+
if (pos < 0)
3017+
return 0;
3018+
3019+
pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap);
3020+
return (cap & PCI_REBAR_CAP_SIZES) >> 4;
3021+
}
3022+
3023+
/**
3024+
* pci_rebar_get_current_size - get the current size of a BAR
3025+
* @pdev: PCI device
3026+
* @bar: BAR to set size to
3027+
*
3028+
* Read the size of a BAR from the resizable BAR config.
3029+
* Returns size if found or negative error code.
3030+
*/
3031+
int pci_rebar_get_current_size(struct pci_dev *pdev, int bar)
3032+
{
3033+
int pos;
3034+
u32 ctrl;
3035+
3036+
pos = pci_rebar_find_pos(pdev, bar);
3037+
if (pos < 0)
3038+
return pos;
3039+
3040+
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
3041+
return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> 8;
3042+
}
3043+
3044+
/**
3045+
* pci_rebar_set_size - set a new size for a BAR
3046+
* @pdev: PCI device
3047+
* @bar: BAR to set size to
3048+
* @size: new size as defined in the spec (0=1MB, 19=512GB)
3049+
*
3050+
* Set the new size of a BAR as defined in the spec.
3051+
* Returns zero if resizing was successful, error code otherwise.
3052+
*/
3053+
int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size)
3054+
{
3055+
int pos;
3056+
u32 ctrl;
3057+
3058+
pos = pci_rebar_find_pos(pdev, bar);
3059+
if (pos < 0)
3060+
return pos;
3061+
3062+
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
3063+
ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
3064+
ctrl |= size << 8;
3065+
pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
3066+
return 0;
3067+
}
3068+
29683069
/**
29693070
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
29703071
* @dev: the PCI device

drivers/pci/pci.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,4 +366,12 @@ int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
366366
struct resource *res);
367367
#endif
368368

369+
u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar);
370+
int pci_rebar_get_current_size(struct pci_dev *pdev, int bar);
371+
int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size);
372+
static inline u64 pci_rebar_size_to_bytes(int size)
373+
{
374+
return 1ULL << (size + 20);
375+
}
376+
369377
#endif /* DRIVERS_PCI_H */

include/uapi/linux/pci_regs.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -939,9 +939,13 @@
939939
#define PCI_SATA_SIZEOF_LONG 16
940940

941941
/* Resizable BARs */
942+
#define PCI_REBAR_CAP 4 /* capability register */
943+
#define PCI_REBAR_CAP_SIZES 0x00FFFFF0 /* supported BAR sizes */
942944
#define PCI_REBAR_CTRL 8 /* control register */
943-
#define PCI_REBAR_CTRL_NBAR_MASK (7 << 5) /* mask for # bars */
944-
#define PCI_REBAR_CTRL_NBAR_SHIFT 5 /* shift for # bars */
945+
#define PCI_REBAR_CTRL_BAR_IDX 0x00000007 /* BAR index */
946+
#define PCI_REBAR_CTRL_NBAR_MASK 0x000000E0 /* # of resizable BARs */
947+
#define PCI_REBAR_CTRL_NBAR_SHIFT 5 /* shift for # of BARs */
948+
#define PCI_REBAR_CTRL_BAR_SIZE 0x00001F00 /* BAR size */
945949

946950
/* Dynamic Power Allocation */
947951
#define PCI_DPA_CAP 4 /* capability register */

0 commit comments

Comments
 (0)