Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Unify ECAM constants in native PCI Express drivers

Add ECAM-related constants to provide a set of standard constants
defining memory address shift values to the byte-level address that can
be used to access the PCI Express Configuration Space, and then move
native PCI Express controller drivers to use the newly introduced
definitions retiring driver-specific ones.

Refactor pci_ecam_map_bus() function to use newly added constants so
that limits to the bus, device function and offset (now limited to 4K as
per the specification) are in place to prevent the defective or
malicious caller from supplying incorrect configuration offset and thus
targeting the wrong device when accessing extended configuration space.

This refactor also allows for the ".bus_shift" initialisers to be
dropped when the user is not using a custom value as a default value
will be used as per the PCI Express Specification.

Thanks to Qian Cai <qcai@redhat.com>, Michael Walle <michael@walle.cc>,
and Vladimir Oltean <olteanv@gmail.com> for reporting a pci_ecam_create()
issue with .bus_shift and to Vladimir for proposing the fix.

[bhelgaas: incorporate Vladimir's fix, update commit log]
Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://lore.kernel.org/r/20201129230743.3006978-2-kw@linux.com
Tested-by: Michael Walle <michael@walle.cc>
Signed-off-by: Krzysztof Wilczyński <kw@linux.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Jon Derrick <jonathan.derrick@intel.com>
Reviewed-by: Bjorn Helgaas <bhelgaas@google.com>

authored by

Krzysztof Wilczyński and committed by
Bjorn Helgaas
e7708f5b f8394f23

+80 -91
+2 -10
drivers/pci/controller/dwc/pcie-al.c
··· 76 76 } 77 77 78 78 const struct pci_ecam_ops al_pcie_ops = { 79 - .bus_shift = 20, 80 79 .init = al_pcie_init, 81 80 .pci_ops = { 82 81 .map_bus = al_pcie_map_bus, ··· 136 137 struct al_pcie_reg_offsets reg_offsets; 137 138 struct al_pcie_target_bus_cfg target_bus_cfg; 138 139 }; 139 - 140 - #define PCIE_ECAM_DEVFN(x) (((x) & 0xff) << 12) 141 140 142 141 #define to_al_pcie(x) dev_get_drvdata((x)->dev) 143 142 ··· 223 226 struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg; 224 227 unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask; 225 228 unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask; 226 - void __iomem *pci_base_addr; 227 - 228 - pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base + 229 - (busnr_ecam << 20) + 230 - PCIE_ECAM_DEVFN(devfn)); 231 229 232 230 if (busnr_reg != target_bus_cfg->reg_val) { 233 231 dev_dbg(pcie->pci->dev, "Changing target bus busnum val from 0x%x to 0x%x\n", ··· 233 241 target_bus_cfg->reg_mask); 234 242 } 235 243 236 - return pci_base_addr + where; 244 + return pp->va_cfg0_base + PCIE_ECAM_OFFSET(busnr_ecam, devfn, where); 237 245 } 238 246 239 247 static struct pci_ops al_child_pci_ops = { ··· 256 264 257 265 target_bus_cfg = &pcie->target_bus_cfg; 258 266 259 - ecam_bus_mask = (pcie->ecam_size >> 20) - 1; 267 + ecam_bus_mask = (pcie->ecam_size >> PCIE_ECAM_BUS_SHIFT) - 1; 260 268 if (ecam_bus_mask > 255) { 261 269 dev_warn(pcie->dev, "ECAM window size is larger than 256MB. Cutting off at 256\n"); 262 270 ecam_bus_mask = 255;
-2
drivers/pci/controller/dwc/pcie-hisi.c
··· 100 100 } 101 101 102 102 const struct pci_ecam_ops hisi_pcie_ops = { 103 - .bus_shift = 20, 104 103 .init = hisi_pcie_init, 105 104 .pci_ops = { 106 105 .map_bus = hisi_pcie_map_bus, ··· 134 135 } 135 136 136 137 static const struct pci_ecam_ops hisi_pcie_platform_ops = { 137 - .bus_shift = 20, 138 138 .init = hisi_pcie_platform_init, 139 139 .pci_ops = { 140 140 .map_bus = hisi_pcie_map_bus,
+3 -10
drivers/pci/controller/pci-aardvark.c
··· 16 16 #include <linux/kernel.h> 17 17 #include <linux/module.h> 18 18 #include <linux/pci.h> 19 + #include <linux/pci-ecam.h> 19 20 #include <linux/init.h> 20 21 #include <linux/phy/phy.h> 21 22 #include <linux/platform_device.h> ··· 164 163 #define PCIE_CONFIG_RD_TYPE1 0x9 165 164 #define PCIE_CONFIG_WR_TYPE0 0xa 166 165 #define PCIE_CONFIG_WR_TYPE1 0xb 167 - 168 - #define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20) 169 - #define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15) 170 - #define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12) 171 - #define PCIE_CONF_REG(reg) ((reg) & 0xffc) 172 - #define PCIE_CONF_ADDR(bus, devfn, where) \ 173 - (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \ 174 - PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where)) 175 166 176 167 #define PIO_RETRY_CNT 500 177 168 #define PIO_RETRY_DELAY 2 /* 2 us*/ ··· 680 687 advk_writel(pcie, reg, PIO_CTRL); 681 688 682 689 /* Program the address registers */ 683 - reg = PCIE_CONF_ADDR(bus->number, devfn, where); 690 + reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4); 684 691 advk_writel(pcie, reg, PIO_ADDR_LS); 685 692 advk_writel(pcie, 0, PIO_ADDR_MS); 686 693 ··· 741 748 advk_writel(pcie, reg, PIO_CTRL); 742 749 743 750 /* Program the address registers */ 744 - reg = PCIE_CONF_ADDR(bus->number, devfn, where); 751 + reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4); 745 752 advk_writel(pcie, reg, PIO_ADDR_LS); 746 753 advk_writel(pcie, 0, PIO_ADDR_MS); 747 754
-1
drivers/pci/controller/pci-host-generic.c
··· 49 49 } 50 50 51 51 static const struct pci_ecam_ops pci_dw_ecam_bus_ops = { 52 - .bus_shift = 20, 53 52 .pci_ops = { 54 53 .map_bus = pci_dw_ecam_map_bus, 55 54 .read = pci_generic_config_read,
-1
drivers/pci/controller/pci-thunder-ecam.c
··· 346 346 } 347 347 348 348 const struct pci_ecam_ops pci_thunder_ecam_ops = { 349 - .bus_shift = 20, 350 349 .pci_ops = { 351 350 .map_bus = pci_ecam_map_bus, 352 351 .read = thunder_ecam_config_read,
+2 -14
drivers/pci/controller/pcie-brcmstb.c
··· 22 22 #include <linux/of_pci.h> 23 23 #include <linux/of_platform.h> 24 24 #include <linux/pci.h> 25 + #include <linux/pci-ecam.h> 25 26 #include <linux/printk.h> 26 27 #include <linux/reset.h> 27 28 #include <linux/sizes.h> ··· 128 127 #define MSI_INT_MASK_CLR 0x14 129 128 130 129 #define PCIE_EXT_CFG_DATA 0x8000 131 - 132 130 #define PCIE_EXT_CFG_INDEX 0x9000 133 - #define PCIE_EXT_BUSNUM_SHIFT 20 134 - #define PCIE_EXT_SLOT_SHIFT 15 135 - #define PCIE_EXT_FUNC_SHIFT 12 136 131 137 132 #define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1 138 133 #define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0 ··· 692 695 return dla && plu; 693 696 } 694 697 695 - /* Configuration space read/write support */ 696 - static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg) 697 - { 698 - return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT) 699 - | ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT) 700 - | (busnr << PCIE_EXT_BUSNUM_SHIFT) 701 - | (reg & ~3); 702 - } 703 - 704 698 static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn, 705 699 int where) 706 700 { ··· 704 716 return PCI_SLOT(devfn) ? NULL : base + where; 705 717 706 718 /* For devices, write to the config space index register */ 707 - idx = brcm_pcie_cfg_index(bus->number, devfn, 0); 719 + idx = PCIE_ECAM_OFFSET(bus->number, devfn, 0); 708 720 writel(idx, pcie->base + PCIE_EXT_CFG_INDEX); 709 721 return base + PCIE_EXT_CFG_DATA + where; 710 722 }
+13 -14
drivers/pci/controller/pcie-rockchip-host.c
··· 157 157 struct pci_bus *bus, u32 devfn, 158 158 int where, int size, u32 *val) 159 159 { 160 - u32 busdev; 160 + void __iomem *addr; 161 161 162 - busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn), 163 - PCI_FUNC(devfn), where); 162 + addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where); 164 163 165 - if (!IS_ALIGNED(busdev, size)) { 164 + if (!IS_ALIGNED((uintptr_t)addr, size)) { 166 165 *val = 0; 167 166 return PCIBIOS_BAD_REGISTER_NUMBER; 168 167 } ··· 174 175 AXI_WRAPPER_TYPE1_CFG); 175 176 176 177 if (size == 4) { 177 - *val = readl(rockchip->reg_base + busdev); 178 + *val = readl(addr); 178 179 } else if (size == 2) { 179 - *val = readw(rockchip->reg_base + busdev); 180 + *val = readw(addr); 180 181 } else if (size == 1) { 181 - *val = readb(rockchip->reg_base + busdev); 182 + *val = readb(addr); 182 183 } else { 183 184 *val = 0; 184 185 return PCIBIOS_BAD_REGISTER_NUMBER; ··· 190 191 struct pci_bus *bus, u32 devfn, 191 192 int where, int size, u32 val) 192 193 { 193 - u32 busdev; 194 + void __iomem *addr; 194 195 195 - busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn), 196 - PCI_FUNC(devfn), where); 197 - if (!IS_ALIGNED(busdev, size)) 196 + addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where); 197 + 198 + if (!IS_ALIGNED((uintptr_t)addr, size)) 198 199 return PCIBIOS_BAD_REGISTER_NUMBER; 199 200 200 201 if (pci_is_root_bus(bus->parent)) ··· 205 206 AXI_WRAPPER_TYPE1_CFG); 206 207 207 208 if (size == 4) 208 - writel(val, rockchip->reg_base + busdev); 209 + writel(val, addr); 209 210 else if (size == 2) 210 - writew(val, rockchip->reg_base + busdev); 211 + writew(val, addr); 211 212 else if (size == 1) 212 - writeb(val, rockchip->reg_base + busdev); 213 + writeb(val, addr); 213 214 else 214 215 return PCIBIOS_BAD_REGISTER_NUMBER; 215 216
+1 -7
drivers/pci/controller/pcie-rockchip.h
··· 13 13 14 14 #include <linux/kernel.h> 15 15 #include <linux/pci.h> 16 + #include <linux/pci-ecam.h> 16 17 17 18 /* 18 19 * The upper 16 bits of PCIE_CLIENT_CONFIG are a write mask for the lower 16 ··· 179 178 #define MIN_AXI_ADDR_BITS_PASSED 8 180 179 #define PCIE_RC_SEND_PME_OFF 0x11960 181 180 #define ROCKCHIP_VENDOR_ID 0x1d87 182 - #define PCIE_ECAM_BUS(x) (((x) & 0xff) << 20) 183 - #define PCIE_ECAM_DEV(x) (((x) & 0x1f) << 15) 184 - #define PCIE_ECAM_FUNC(x) (((x) & 0x7) << 12) 185 - #define PCIE_ECAM_REG(x) (((x) & 0xfff) << 0) 186 - #define PCIE_ECAM_ADDR(bus, dev, func, reg) \ 187 - (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \ 188 - PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg)) 189 181 #define PCIE_LINK_IS_L2(x) \ 190 182 (((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2) 191 183 #define PCIE_LINK_UP(x) \
-1
drivers/pci/controller/pcie-tango.c
··· 208 208 } 209 209 210 210 static const struct pci_ecam_ops smp8759_ecam_ops = { 211 - .bus_shift = 20, 212 211 .pci_ops = { 213 212 .map_bus = pci_ecam_map_bus, 214 213 .read = smp8759_config_read,
+2 -7
drivers/pci/controller/pcie-xilinx-nwl.c
··· 18 18 #include <linux/of_platform.h> 19 19 #include <linux/of_irq.h> 20 20 #include <linux/pci.h> 21 + #include <linux/pci-ecam.h> 21 22 #include <linux/platform_device.h> 22 23 #include <linux/irqchip/chained_irq.h> 23 24 ··· 125 124 #define E_ECAM_CR_ENABLE BIT(0) 126 125 #define E_ECAM_SIZE_LOC GENMASK(20, 16) 127 126 #define E_ECAM_SIZE_SHIFT 16 128 - #define ECAM_BUS_LOC_SHIFT 20 129 - #define ECAM_DEV_LOC_SHIFT 12 130 127 #define NWL_ECAM_VALUE_DEFAULT 12 131 128 132 129 #define CFG_DMA_REG_BAR GENMASK(2, 0) ··· 239 240 int where) 240 241 { 241 242 struct nwl_pcie *pcie = bus->sysdata; 242 - int relbus; 243 243 244 244 if (!nwl_pcie_valid_device(bus, devfn)) 245 245 return NULL; 246 246 247 - relbus = (bus->number << ECAM_BUS_LOC_SHIFT) | 248 - (devfn << ECAM_DEV_LOC_SHIFT); 249 - 250 - return pcie->ecam_base + relbus + where; 247 + return pcie->ecam_base + PCIE_ECAM_OFFSET(bus->number, devfn, where); 251 248 } 252 249 253 250 /* PCIe operations */
+2 -9
drivers/pci/controller/pcie-xilinx.c
··· 21 21 #include <linux/of_platform.h> 22 22 #include <linux/of_irq.h> 23 23 #include <linux/pci.h> 24 + #include <linux/pci-ecam.h> 24 25 #include <linux/platform_device.h> 25 26 26 27 #include "../pci.h" ··· 86 85 87 86 /* Phy Status/Control Register definitions */ 88 87 #define XILINX_PCIE_REG_PSCR_LNKUP BIT(11) 89 - 90 - /* ECAM definitions */ 91 - #define ECAM_BUS_NUM_SHIFT 20 92 - #define ECAM_DEV_NUM_SHIFT 12 93 88 94 89 /* Number of MSI IRQs */ 95 90 #define XILINX_NUM_MSI_IRQS 128 ··· 180 183 unsigned int devfn, int where) 181 184 { 182 185 struct xilinx_pcie_port *port = bus->sysdata; 183 - int relbus; 184 186 185 187 if (!xilinx_pcie_valid_device(bus, devfn)) 186 188 return NULL; 187 189 188 - relbus = (bus->number << ECAM_BUS_NUM_SHIFT) | 189 - (devfn << ECAM_DEV_NUM_SHIFT); 190 - 191 - return port->reg_base + relbus + where; 190 + return port->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where); 192 191 } 193 192 194 193 /* PCIe operations */
+5 -6
drivers/pci/controller/vmd.c
··· 11 11 #include <linux/module.h> 12 12 #include <linux/msi.h> 13 13 #include <linux/pci.h> 14 + #include <linux/pci-ecam.h> 14 15 #include <linux/srcu.h> 15 16 #include <linux/rculist.h> 16 17 #include <linux/rcupdate.h> ··· 329 328 static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, 330 329 unsigned int devfn, int reg, int len) 331 330 { 332 - char __iomem *addr = vmd->cfgbar + 333 - ((bus->number - vmd->busn_start) << 20) + 334 - (devfn << 12) + reg; 331 + unsigned int busnr_ecam = bus->number - vmd->busn_start; 332 + u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg); 335 333 336 - if ((addr - vmd->cfgbar) + len >= 337 - resource_size(&vmd->dev->resource[VMD_CFGBAR])) 334 + if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR])) 338 335 return NULL; 339 336 340 - return addr; 337 + return vmd->cfgbar + offset; 341 338 } 342 339 343 340 /*
+23 -9
drivers/pci/ecam.c
··· 28 28 struct resource *cfgres, struct resource *busr, 29 29 const struct pci_ecam_ops *ops) 30 30 { 31 + unsigned int bus_shift = ops->bus_shift; 31 32 struct pci_config_window *cfg; 32 33 unsigned int bus_range, bus_range_max, bsz; 33 34 struct resource *conflict; ··· 41 40 if (!cfg) 42 41 return ERR_PTR(-ENOMEM); 43 42 43 + /* ECAM-compliant platforms need not supply ops->bus_shift */ 44 + if (!bus_shift) 45 + bus_shift = PCIE_ECAM_BUS_SHIFT; 46 + 44 47 cfg->parent = dev; 45 48 cfg->ops = ops; 46 49 cfg->busr.start = busr->start; 47 50 cfg->busr.end = busr->end; 48 51 cfg->busr.flags = IORESOURCE_BUS; 49 52 bus_range = resource_size(&cfg->busr); 50 - bus_range_max = resource_size(cfgres) >> ops->bus_shift; 53 + bus_range_max = resource_size(cfgres) >> bus_shift; 51 54 if (bus_range > bus_range_max) { 52 55 bus_range = bus_range_max; 53 56 cfg->busr.end = busr->start + bus_range - 1; 54 57 dev_warn(dev, "ECAM area %pR can only accommodate %pR (reduced from %pR desired)\n", 55 58 cfgres, &cfg->busr, busr); 56 59 } 57 - bsz = 1 << ops->bus_shift; 60 + bsz = 1 << bus_shift; 58 61 59 62 cfg->res.start = cfgres->start; 60 63 cfg->res.end = cfgres->end; ··· 136 131 int where) 137 132 { 138 133 struct pci_config_window *cfg = bus->sysdata; 134 + unsigned int bus_shift = cfg->ops->bus_shift; 139 135 unsigned int devfn_shift = cfg->ops->bus_shift - 8; 140 136 unsigned int busn = bus->number; 141 137 void __iomem *base; 138 + u32 bus_offset, devfn_offset; 142 139 143 140 if (busn < cfg->busr.start || busn > cfg->busr.end) 144 141 return NULL; 145 142 146 143 busn -= cfg->busr.start; 147 - if (per_bus_mapping) 144 + if (per_bus_mapping) { 148 145 base = cfg->winp[busn]; 149 - else 150 - base = cfg->win + (busn << cfg->ops->bus_shift); 151 - return base + (devfn << devfn_shift) + where; 146 + busn = 0; 147 + } else 148 + base = cfg->win; 149 + 150 + if (cfg->ops->bus_shift) { 151 + bus_offset = (busn & PCIE_ECAM_BUS_MASK) << bus_shift; 152 + devfn_offset = (devfn & PCIE_ECAM_DEVFN_MASK) << devfn_shift; 153 + where &= PCIE_ECAM_REG_MASK; 154 + 155 + return base + (bus_offset | devfn_offset | where); 156 + } 157 + 158 + return base + PCIE_ECAM_OFFSET(busn, devfn, where); 152 159 } 153 160 EXPORT_SYMBOL_GPL(pci_ecam_map_bus); 154 161 155 162 /* ECAM ops */ 156 163 const struct pci_ecam_ops pci_generic_ecam_ops = { 157 - .bus_shift = 20, 158 164 .pci_ops = { 159 165 .map_bus = pci_ecam_map_bus, 160 166 .read = pci_generic_config_read, ··· 177 161 #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) 178 162 /* ECAM ops for 32-bit access only (non-compliant) */ 179 163 const struct pci_ecam_ops pci_32b_ops = { 180 - .bus_shift = 20, 181 164 .pci_ops = { 182 165 .map_bus = pci_ecam_map_bus, 183 166 .read = pci_generic_config_read32, ··· 186 171 187 172 /* ECAM ops for 32-bit read only (non-compliant) */ 188 173 const struct pci_ecam_ops pci_32b_read_ops = { 189 - .bus_shift = 20, 190 174 .pci_ops = { 191 175 .map_bus = pci_ecam_map_bus, 192 176 .read = pci_generic_config_read32,
+27
include/linux/pci-ecam.h
··· 10 10 #include <linux/platform_device.h> 11 11 12 12 /* 13 + * Memory address shift values for the byte-level address that 14 + * can be used when accessing the PCI Express Configuration Space. 15 + */ 16 + 17 + /* 18 + * Enhanced Configuration Access Mechanism (ECAM) 19 + * 20 + * See PCI Express Base Specification, Revision 5.0, Version 1.0, 21 + * Section 7.2.2, Table 7-1, p. 677. 22 + */ 23 + #define PCIE_ECAM_BUS_SHIFT 20 /* Bus number */ 24 + #define PCIE_ECAM_DEVFN_SHIFT 12 /* Device and Function number */ 25 + 26 + #define PCIE_ECAM_BUS_MASK 0xff 27 + #define PCIE_ECAM_DEVFN_MASK 0xff 28 + #define PCIE_ECAM_REG_MASK 0xfff /* Limit offset to a maximum of 4K */ 29 + 30 + #define PCIE_ECAM_BUS(x) (((x) & PCIE_ECAM_BUS_MASK) << PCIE_ECAM_BUS_SHIFT) 31 + #define PCIE_ECAM_DEVFN(x) (((x) & PCIE_ECAM_DEVFN_MASK) << PCIE_ECAM_DEVFN_SHIFT) 32 + #define PCIE_ECAM_REG(x) ((x) & PCIE_ECAM_REG_MASK) 33 + 34 + #define PCIE_ECAM_OFFSET(bus, devfn, where) \ 35 + (PCIE_ECAM_BUS(bus) | \ 36 + PCIE_ECAM_DEVFN(devfn) | \ 37 + PCIE_ECAM_REG(where)) 38 + 39 + /* 13 40 * struct to hold pci ops and bus shift of the config window 14 41 * for a PCI controller. 15 42 */