aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2017-10-24 15:40:20 -0400
committerBjorn Helgaas <bhelgaas@google.com>2017-10-24 15:40:20 -0400
commit276b738deb5bf856b9f6049fcd92a967f52643d7 (patch)
treecac0ccc12391b30c519e116c696955da34fdb8cb
parentcb21bc9469c4c8a4d38f52d779ccc11e4329f016 (diff)
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>
-rw-r--r--drivers/pci/pci.c101
-rw-r--r--drivers/pci/pci.h8
-rw-r--r--include/uapi/linux/pci_regs.h8
3 files changed, 115 insertions, 2 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 6078dfc11b11..832b96756e83 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2966,6 +2966,107 @@ bool pci_acs_path_enabled(struct pci_dev *start,
2966} 2966}
2967 2967
2968/** 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 */
2977static 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 */
3010u32 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 */
3031int 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 */
3053int 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
3069/**
2969 * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge 3070 * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
2970 * @dev: the PCI device 3071 * @dev: the PCI device
2971 * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) 3072 * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index a6560c9baa52..33469a33738d 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -366,4 +366,12 @@ int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
366 struct resource *res); 366 struct resource *res);
367#endif 367#endif
368 368
369u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar);
370int pci_rebar_get_current_size(struct pci_dev *pdev, int bar);
371int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size);
372static inline u64 pci_rebar_size_to_bytes(int size)
373{
374 return 1ULL << (size + 20);
375}
376
369#endif /* DRIVERS_PCI_H */ 377#endif /* DRIVERS_PCI_H */
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index f8d58045926f..d34000a59f24 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -939,9 +939,13 @@
939#define PCI_SATA_SIZEOF_LONG 16 939#define PCI_SATA_SIZEOF_LONG 16
940 940
941/* Resizable BARs */ 941/* Resizable BARs */
942#define PCI_REBAR_CAP 4 /* capability register */
943#define PCI_REBAR_CAP_SIZES 0x00FFFFF0 /* supported BAR sizes */
942#define PCI_REBAR_CTRL 8 /* control register */ 944#define PCI_REBAR_CTRL 8 /* control register */
943#define PCI_REBAR_CTRL_NBAR_MASK (7 << 5) /* mask for # bars */ 945#define PCI_REBAR_CTRL_BAR_IDX 0x00000007 /* BAR index */
944#define PCI_REBAR_CTRL_NBAR_SHIFT 5 /* shift for # bars */ 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 */
945 949
946/* Dynamic Power Allocation */ 950/* Dynamic Power Allocation */
947#define PCI_DPA_CAP 4 /* capability register */ 951#define PCI_DPA_CAP 4 /* capability register */