Commit e7708f5b authored by Krzysztof Wilczyński's avatar Krzysztof Wilczyński Committed by Bjorn Helgaas
Browse files

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: default avatarBjorn Helgaas <bhelgaas@google.com>
Link: https://lore.kernel.org/r/20201129230743.3006978-2-kw@linux.com


Tested-by: default avatarMichael Walle <michael@walle.cc>
Signed-off-by: default avatarKrzysztof Wilczyński <kw@linux.com>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarJon Derrick <jonathan.derrick@intel.com>
Reviewed-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent f8394f23
Loading
Loading
Loading
Loading
+2 −10
Original line number Diff line number Diff line
@@ -76,7 +76,6 @@ static int al_pcie_init(struct pci_config_window *cfg)
}

const struct pci_ecam_ops al_pcie_ops = {
	.bus_shift    = 20,
	.init         =  al_pcie_init,
	.pci_ops      = {
		.map_bus    = al_pcie_map_bus,
@@ -138,8 +137,6 @@ struct al_pcie {
	struct al_pcie_target_bus_cfg target_bus_cfg;
};

#define PCIE_ECAM_DEVFN(x)		(((x) & 0xff) << 12)

#define to_al_pcie(x)		dev_get_drvdata((x)->dev)

static inline u32 al_pcie_controller_readl(struct al_pcie *pcie, u32 offset)
@@ -226,11 +223,6 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
	struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg;
	unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask;
	unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask;
	void __iomem *pci_base_addr;

	pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base +
					 (busnr_ecam << 20) +
					 PCIE_ECAM_DEVFN(devfn));

	if (busnr_reg != target_bus_cfg->reg_val) {
		dev_dbg(pcie->pci->dev, "Changing target bus busnum val from 0x%x to 0x%x\n",
@@ -241,7 +233,7 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
				       target_bus_cfg->reg_mask);
	}

	return pci_base_addr + where;
	return pp->va_cfg0_base + PCIE_ECAM_OFFSET(busnr_ecam, devfn, where);
}

static struct pci_ops al_child_pci_ops = {
@@ -264,7 +256,7 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)

	target_bus_cfg = &pcie->target_bus_cfg;

	ecam_bus_mask = (pcie->ecam_size >> 20) - 1;
	ecam_bus_mask = (pcie->ecam_size >> PCIE_ECAM_BUS_SHIFT) - 1;
	if (ecam_bus_mask > 255) {
		dev_warn(pcie->dev, "ECAM window size is larger than 256MB. Cutting off at 256\n");
		ecam_bus_mask = 255;
+0 −2
Original line number Diff line number Diff line
@@ -100,7 +100,6 @@ static int hisi_pcie_init(struct pci_config_window *cfg)
}

const struct pci_ecam_ops hisi_pcie_ops = {
	.bus_shift    = 20,
	.init         =  hisi_pcie_init,
	.pci_ops      = {
		.map_bus    = hisi_pcie_map_bus,
@@ -135,7 +134,6 @@ static int hisi_pcie_platform_init(struct pci_config_window *cfg)
}

static const struct pci_ecam_ops hisi_pcie_platform_ops = {
	.bus_shift    = 20,
	.init         =  hisi_pcie_platform_init,
	.pci_ops      = {
		.map_bus    = hisi_pcie_map_bus,
+3 −10
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/init.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
@@ -164,14 +165,6 @@
#define PCIE_CONFIG_WR_TYPE0			0xa
#define PCIE_CONFIG_WR_TYPE1			0xb

#define PCIE_CONF_BUS(bus)			(((bus) & 0xff) << 20)
#define PCIE_CONF_DEV(dev)			(((dev) & 0x1f) << 15)
#define PCIE_CONF_FUNC(fun)			(((fun) & 0x7)	<< 12)
#define PCIE_CONF_REG(reg)			((reg) & 0xffc)
#define PCIE_CONF_ADDR(bus, devfn, where)	\
	(PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn))	| \
	 PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))

#define PIO_RETRY_CNT			500
#define PIO_RETRY_DELAY			2 /* 2 us*/

@@ -687,7 +680,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
	advk_writel(pcie, reg, PIO_CTRL);

	/* Program the address registers */
	reg = PCIE_CONF_ADDR(bus->number, devfn, where);
	reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4);
	advk_writel(pcie, reg, PIO_ADDR_LS);
	advk_writel(pcie, 0, PIO_ADDR_MS);

@@ -748,7 +741,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
	advk_writel(pcie, reg, PIO_CTRL);

	/* Program the address registers */
	reg = PCIE_CONF_ADDR(bus->number, devfn, where);
	reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4);
	advk_writel(pcie, reg, PIO_ADDR_LS);
	advk_writel(pcie, 0, PIO_ADDR_MS);

+0 −1
Original line number Diff line number Diff line
@@ -49,7 +49,6 @@ static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus,
}

static const struct pci_ecam_ops pci_dw_ecam_bus_ops = {
	.bus_shift	= 20,
	.pci_ops	= {
		.map_bus	= pci_dw_ecam_map_bus,
		.read		= pci_generic_config_read,
+0 −1
Original line number Diff line number Diff line
@@ -346,7 +346,6 @@ static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,
}

const struct pci_ecam_ops pci_thunder_ecam_ops = {
	.bus_shift	= 20,
	.pci_ops	= {
		.map_bus        = pci_ecam_map_bus,
		.read           = thunder_ecam_config_read,
Loading