}
const struct pci_ecam_ops al_pcie_ops = {
- .bus_shift = 20,
.init = al_pcie_init,
.pci_ops = {
.map_bus = al_pcie_map_bus,
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)
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",
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 = {
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;
}
const struct pci_ecam_ops hisi_pcie_ops = {
- .bus_shift = 20,
.init = hisi_pcie_init,
.pci_ops = {
.map_bus = hisi_pcie_map_bus,
}
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,
#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>
#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*/
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);
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);
}
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,
}
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,
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
+#include <linux/pci-ecam.h>
#include <linux/printk.h>
#include <linux/reset.h>
#include <linux/sizes.h>
#define MSI_INT_MASK_CLR 0x14
#define PCIE_EXT_CFG_DATA 0x8000
-
#define PCIE_EXT_CFG_INDEX 0x9000
-#define PCIE_EXT_BUSNUM_SHIFT 20
-#define PCIE_EXT_SLOT_SHIFT 15
-#define PCIE_EXT_FUNC_SHIFT 12
#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0
return dla && plu;
}
-/* Configuration space read/write support */
-static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg)
-{
- return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT)
- | ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT)
- | (busnr << PCIE_EXT_BUSNUM_SHIFT)
- | (reg & ~3);
-}
-
static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
int where)
{
return PCI_SLOT(devfn) ? NULL : base + where;
/* For devices, write to the config space index register */
- idx = brcm_pcie_cfg_index(bus->number, devfn, 0);
+ idx = PCIE_ECAM_OFFSET(bus->number, devfn, 0);
writel(idx, pcie->base + PCIE_EXT_CFG_INDEX);
return base + PCIE_EXT_CFG_DATA + where;
}
struct pci_bus *bus, u32 devfn,
int where, int size, u32 *val)
{
- u32 busdev;
+ void __iomem *addr;
- busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
- PCI_FUNC(devfn), where);
+ addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
- if (!IS_ALIGNED(busdev, size)) {
+ if (!IS_ALIGNED((uintptr_t)addr, size)) {
*val = 0;
return PCIBIOS_BAD_REGISTER_NUMBER;
}
AXI_WRAPPER_TYPE1_CFG);
if (size == 4) {
- *val = readl(rockchip->reg_base + busdev);
+ *val = readl(addr);
} else if (size == 2) {
- *val = readw(rockchip->reg_base + busdev);
+ *val = readw(addr);
} else if (size == 1) {
- *val = readb(rockchip->reg_base + busdev);
+ *val = readb(addr);
} else {
*val = 0;
return PCIBIOS_BAD_REGISTER_NUMBER;
struct pci_bus *bus, u32 devfn,
int where, int size, u32 val)
{
- u32 busdev;
+ void __iomem *addr;
- busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
- PCI_FUNC(devfn), where);
- if (!IS_ALIGNED(busdev, size))
+ addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
+
+ if (!IS_ALIGNED((uintptr_t)addr, size))
return PCIBIOS_BAD_REGISTER_NUMBER;
if (pci_is_root_bus(bus->parent))
AXI_WRAPPER_TYPE1_CFG);
if (size == 4)
- writel(val, rockchip->reg_base + busdev);
+ writel(val, addr);
else if (size == 2)
- writew(val, rockchip->reg_base + busdev);
+ writew(val, addr);
else if (size == 1)
- writeb(val, rockchip->reg_base + busdev);
+ writeb(val, addr);
else
return PCIBIOS_BAD_REGISTER_NUMBER;
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/pci-ecam.h>
/*
* The upper 16 bits of PCIE_CLIENT_CONFIG are a write mask for the lower 16
#define MIN_AXI_ADDR_BITS_PASSED 8
#define PCIE_RC_SEND_PME_OFF 0x11960
#define ROCKCHIP_VENDOR_ID 0x1d87
-#define PCIE_ECAM_BUS(x) (((x) & 0xff) << 20)
-#define PCIE_ECAM_DEV(x) (((x) & 0x1f) << 15)
-#define PCIE_ECAM_FUNC(x) (((x) & 0x7) << 12)
-#define PCIE_ECAM_REG(x) (((x) & 0xfff) << 0)
-#define PCIE_ECAM_ADDR(bus, dev, func, reg) \
- (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \
- PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))
#define PCIE_LINK_IS_L2(x) \
(((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2)
#define PCIE_LINK_UP(x) \
}
static const struct pci_ecam_ops smp8759_ecam_ops = {
- .bus_shift = 20,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = smp8759_config_read,
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/pci.h>
+#include <linux/pci-ecam.h>
#include <linux/platform_device.h>
#include <linux/irqchip/chained_irq.h>
#define E_ECAM_CR_ENABLE BIT(0)
#define E_ECAM_SIZE_LOC GENMASK(20, 16)
#define E_ECAM_SIZE_SHIFT 16
-#define ECAM_BUS_LOC_SHIFT 20
-#define ECAM_DEV_LOC_SHIFT 12
#define NWL_ECAM_VALUE_DEFAULT 12
#define CFG_DMA_REG_BAR GENMASK(2, 0)
int where)
{
struct nwl_pcie *pcie = bus->sysdata;
- int relbus;
if (!nwl_pcie_valid_device(bus, devfn))
return NULL;
- relbus = (bus->number << ECAM_BUS_LOC_SHIFT) |
- (devfn << ECAM_DEV_LOC_SHIFT);
-
- return pcie->ecam_base + relbus + where;
+ return pcie->ecam_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
}
/* PCIe operations */
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/pci.h>
+#include <linux/pci-ecam.h>
#include <linux/platform_device.h>
#include "../pci.h"
/* Phy Status/Control Register definitions */
#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11)
-/* ECAM definitions */
-#define ECAM_BUS_NUM_SHIFT 20
-#define ECAM_DEV_NUM_SHIFT 12
-
/* Number of MSI IRQs */
#define XILINX_NUM_MSI_IRQS 128
unsigned int devfn, int where)
{
struct xilinx_pcie_port *port = bus->sysdata;
- int relbus;
if (!xilinx_pcie_valid_device(bus, devfn))
return NULL;
- relbus = (bus->number << ECAM_BUS_NUM_SHIFT) |
- (devfn << ECAM_DEV_NUM_SHIFT);
-
- return port->reg_base + relbus + where;
+ return port->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
}
/* PCIe operations */
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/pci.h>
+#include <linux/pci-ecam.h>
#include <linux/srcu.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
unsigned int devfn, int reg, int len)
{
- char __iomem *addr = vmd->cfgbar +
- ((bus->number - vmd->busn_start) << 20) +
- (devfn << 12) + reg;
+ unsigned int busnr_ecam = bus->number - vmd->busn_start;
+ u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg);
- if ((addr - vmd->cfgbar) + len >=
- resource_size(&vmd->dev->resource[VMD_CFGBAR]))
+ if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR]))
return NULL;
- return addr;
+ return vmd->cfgbar + offset;
}
/*
struct resource *cfgres, struct resource *busr,
const struct pci_ecam_ops *ops)
{
+ unsigned int bus_shift = ops->bus_shift;
struct pci_config_window *cfg;
unsigned int bus_range, bus_range_max, bsz;
struct resource *conflict;
if (!cfg)
return ERR_PTR(-ENOMEM);
+ /* ECAM-compliant platforms need not supply ops->bus_shift */
+ if (!bus_shift)
+ bus_shift = PCIE_ECAM_BUS_SHIFT;
+
cfg->parent = dev;
cfg->ops = ops;
cfg->busr.start = busr->start;
cfg->busr.end = busr->end;
cfg->busr.flags = IORESOURCE_BUS;
bus_range = resource_size(&cfg->busr);
- bus_range_max = resource_size(cfgres) >> ops->bus_shift;
+ bus_range_max = resource_size(cfgres) >> bus_shift;
if (bus_range > bus_range_max) {
bus_range = bus_range_max;
cfg->busr.end = busr->start + bus_range - 1;
dev_warn(dev, "ECAM area %pR can only accommodate %pR (reduced from %pR desired)\n",
cfgres, &cfg->busr, busr);
}
- bsz = 1 << ops->bus_shift;
+ bsz = 1 << bus_shift;
cfg->res.start = cfgres->start;
cfg->res.end = cfgres->end;
int where)
{
struct pci_config_window *cfg = bus->sysdata;
+ unsigned int bus_shift = cfg->ops->bus_shift;
unsigned int devfn_shift = cfg->ops->bus_shift - 8;
unsigned int busn = bus->number;
void __iomem *base;
+ u32 bus_offset, devfn_offset;
if (busn < cfg->busr.start || busn > cfg->busr.end)
return NULL;
busn -= cfg->busr.start;
- if (per_bus_mapping)
+ if (per_bus_mapping) {
base = cfg->winp[busn];
- else
- base = cfg->win + (busn << cfg->ops->bus_shift);
- return base + (devfn << devfn_shift) + where;
+ busn = 0;
+ } else
+ base = cfg->win;
+
+ if (cfg->ops->bus_shift) {
+ bus_offset = (busn & PCIE_ECAM_BUS_MASK) << bus_shift;
+ devfn_offset = (devfn & PCIE_ECAM_DEVFN_MASK) << devfn_shift;
+ where &= PCIE_ECAM_REG_MASK;
+
+ return base + (bus_offset | devfn_offset | where);
+ }
+
+ return base + PCIE_ECAM_OFFSET(busn, devfn, where);
}
EXPORT_SYMBOL_GPL(pci_ecam_map_bus);
/* ECAM ops */
const struct pci_ecam_ops pci_generic_ecam_ops = {
- .bus_shift = 20,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read,
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
/* ECAM ops for 32-bit access only (non-compliant) */
const struct pci_ecam_ops pci_32b_ops = {
- .bus_shift = 20,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32,
/* ECAM ops for 32-bit read only (non-compliant) */
const struct pci_ecam_ops pci_32b_read_ops = {
- .bus_shift = 20,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32,
#include <linux/kernel.h>
#include <linux/platform_device.h>
+/*
+ * Memory address shift values for the byte-level address that
+ * can be used when accessing the PCI Express Configuration Space.
+ */
+
+/*
+ * Enhanced Configuration Access Mechanism (ECAM)
+ *
+ * See PCI Express Base Specification, Revision 5.0, Version 1.0,
+ * Section 7.2.2, Table 7-1, p. 677.
+ */
+#define PCIE_ECAM_BUS_SHIFT 20 /* Bus number */
+#define PCIE_ECAM_DEVFN_SHIFT 12 /* Device and Function number */
+
+#define PCIE_ECAM_BUS_MASK 0xff
+#define PCIE_ECAM_DEVFN_MASK 0xff
+#define PCIE_ECAM_REG_MASK 0xfff /* Limit offset to a maximum of 4K */
+
+#define PCIE_ECAM_BUS(x) (((x) & PCIE_ECAM_BUS_MASK) << PCIE_ECAM_BUS_SHIFT)
+#define PCIE_ECAM_DEVFN(x) (((x) & PCIE_ECAM_DEVFN_MASK) << PCIE_ECAM_DEVFN_SHIFT)
+#define PCIE_ECAM_REG(x) ((x) & PCIE_ECAM_REG_MASK)
+
+#define PCIE_ECAM_OFFSET(bus, devfn, where) \
+ (PCIE_ECAM_BUS(bus) | \
+ PCIE_ECAM_DEVFN(devfn) | \
+ PCIE_ECAM_REG(where))
+
/*
* struct to hold pci ops and bus shift of the config window
* for a PCI controller.