Skip to content

Commit 0da48c5

Browse files
PCI: dwc: Support ECAM mechanism by enabling iATU 'CFG Shift Feature'
Designware databook r5.20a, sec 3.10.10.3 documents the 'CFG Shift Feature' of the internal Address Translation Unit (iATU). When this feature is enabled, it shifts/maps the BDF contained in the bits [27:12] of the target address in MEM TLP to become BDF of the CFG TLP. This essentially implements the Enhanced Configuration Address Mapping (ECAM) mechanism as defined in PCIe r6.0, sec 7.2.2. Currently, the driver is not making use of this CFG shift feature, thereby creating the iATU outbound map for each config access to the devices, causing latency and wasting CPU cycles. So to avoid this, configure the controller to enable CFG shift feature by enabling the 'CFG Shift' bit of the 'iATU Control 2 Register'. As a result of enabling CFG shift (ECAM), there is no longer a need to map the DBI register space separately as the DBI region falls under the 'config' space used for ECAM (as DBI is used to access the Root Port). For enabling ECAM using CFG shift, the platform has to satisfy following requirements: 1. Size of the 'config' memory space to be used as ECAM memory should be able to accommodate the number of buses defined in the 'bus-range' property of the host bridge DT node. 2. The 'config' memory space should be 256 MiB aligned. This requirement comes from PCIe r6.0, sec 7.2.2, which says the base address of ECAM memory should be aligned to a 2^(n+20) byte address boundary. For the DWC cores, n is 8, so this results in 2^28 byte alignment requirement. It should be noted that some DWC vendor glue drivers like pcie-al may use their own ECAM mechanism. For those controllers, set 'dw_pcie_rp::native_ecam' flag and skip enabling the CFG Shift feature in the DWC core. Signed-off-by: Krishna Chaitanya Chundru <[email protected]> [mani: code split, reworded subject/description, comment, native_ecam flag] Signed-off-by: Manivannan Sadhasivam <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 4660e50 commit 0da48c5

File tree

3 files changed

+34
-0
lines changed

3 files changed

+34
-0
lines changed

drivers/pci/controller/dwc/pcie-al.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ static int al_pcie_probe(struct platform_device *pdev)
352352
return -ENOENT;
353353
}
354354
al_pcie->ecam_size = resource_size(ecam_res);
355+
pci->pp.native_ecam = true;
355356

356357
controller_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
357358
"controller");

drivers/pci/controller/dwc/pcie-designware-host.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Author: Jingoo Han <[email protected]>
99
*/
1010

11+
#include <linux/align.h>
1112
#include <linux/iopoll.h>
1213
#include <linux/irqchip/chained_irq.h>
1314
#include <linux/irqchip/irq-msi-lib.h>
@@ -32,6 +33,8 @@ static struct pci_ops dw_child_pcie_ops;
3233
MSI_FLAG_PCI_MSIX | \
3334
MSI_GENERIC_FLAGS_MASK)
3435

36+
#define IS_256MB_ALIGNED(x) IS_ALIGNED(x, SZ_256M)
37+
3538
static const struct msi_parent_ops dw_pcie_msi_parent_ops = {
3639
.required_flags = DW_PCIE_MSI_FLAGS_REQUIRED,
3740
.supported_flags = DW_PCIE_MSI_FLAGS_SUPPORTED,
@@ -474,6 +477,34 @@ static int dw_pcie_create_ecam_window(struct dw_pcie_rp *pp, struct resource *re
474477
return 0;
475478
}
476479

480+
static bool dw_pcie_ecam_enabled(struct dw_pcie_rp *pp, struct resource *config_res)
481+
{
482+
struct resource *bus_range;
483+
u64 nr_buses;
484+
485+
/* Vendor glue drivers may implement their own ECAM mechanism */
486+
if (pp->native_ecam)
487+
return false;
488+
489+
/*
490+
* PCIe spec r6.0, sec 7.2.2 mandates the base address used for ECAM to
491+
* be aligned on a 2^(n+20) byte boundary, where n is the number of bits
492+
* used for representing 'bus' in BDF. Since the DWC cores always use 8
493+
* bits for representing 'bus', the base address has to be aligned to
494+
* 2^28 byte boundary, which is 256 MiB.
495+
*/
496+
if (!IS_256MB_ALIGNED(config_res->start))
497+
return false;
498+
499+
bus_range = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS)->res;
500+
if (!bus_range)
501+
return false;
502+
503+
nr_buses = resource_size(config_res) >> PCIE_ECAM_BUS_SHIFT;
504+
505+
return nr_buses >= resource_size(bus_range);
506+
}
507+
477508
static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp)
478509
{
479510
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -492,6 +523,7 @@ static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp)
492523
pp->cfg0_size = resource_size(res);
493524
pp->cfg0_base = res->start;
494525

526+
pp->ecam_enabled = dw_pcie_ecam_enabled(pp, res);
495527
if (pp->ecam_enabled) {
496528
ret = dw_pcie_create_ecam_window(pp, res);
497529
if (ret)

drivers/pci/controller/dwc/pcie-designware.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ struct dw_pcie_rp {
429429
struct pci_eq_presets presets;
430430
struct pci_config_window *cfg;
431431
bool ecam_enabled;
432+
bool native_ecam;
432433
};
433434

434435
struct dw_pcie_ep_ops {

0 commit comments

Comments
 (0)