Skip to content

Commit

Permalink
BACKPORT: PCI: dwc: Support multiple ATU memory regions
Browse files Browse the repository at this point in the history
The current ATU setup only supports a single memory resource which
isn't sufficient if there are also prefetchable memory regions. In order
to support multiple memory regions, we need to move away from fixed ATU
slots and rework the assignment. As there's always an ATU entry for
config space, let's assign index 0 to config space. Then we assign
memory resources to index 1 and up. Finally, if we have an I/O region
and slots remaining, we assign the I/O region last. If there aren't
remaining slots, we keep the same config and I/O space sharing.

Link: https://lore.kernel.org/r/20201026181652.418729-1-robh@kernel.org
Tested-by: Vidya Sagar <vidyas@nvidia.com>
Signed-off-by: Rob Herring <robh@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Vidya Sagar <vidyas@nvidia.com>
Acked-by: Jingoo Han <jingoohan1@gmail.com>
Cc: Vidya Sagar <vidyas@nvidia.com>
Cc: Jingoo Han <jingoohan1@gmail.com>
Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Change-Id: I048f7605406a2cd0a4d8eee0c8541011f672756b
(cherry picked from commit 9f9e59a)
  • Loading branch information
robherring authored and rkhuangtao committed Jan 17, 2022
1 parent a2d8c2a commit 50a01d3
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 18 deletions.
45 changes: 33 additions & 12 deletions drivers/pci/controller/dwc/pcie-designware-host.c
Expand Up @@ -370,6 +370,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
if (!bridge)
return -ENOMEM;

pp->bridge = bridge;
ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
&bridge->windows, &pp->io_base);
if (ret)
Expand Down Expand Up @@ -555,12 +556,12 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
va_cfg_base = pp->va_cfg1_base;
}

dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
dw_pcie_prog_outbound_atu(pci, 0,
type, cpu_addr,
busdev, cfg_size);
ret = dw_pcie_read(va_cfg_base + where, size, val);
if (pci->num_viewport <= 2)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
if (!ret && pci->io_cfg_atu_shared)
dw_pcie_prog_outbound_atu(pci, 0,
PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size);

Expand Down Expand Up @@ -594,13 +595,12 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
va_cfg_base = pp->va_cfg1_base;
}

dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
dw_pcie_prog_outbound_atu(pci, 0,
type, cpu_addr,
busdev, cfg_size);
ret = dw_pcie_write(va_cfg_base + where, size, val);
if (pci->num_viewport <= 2)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
PCIE_ATU_TYPE_IO, pp->io_base,
if (!ret && pci->io_cfg_atu_shared)
dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size);

return ret;
Expand Down Expand Up @@ -674,6 +674,8 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
{
u32 val, ctrl, num_ctrls;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
int atu_idx = 0;
struct resource_entry *entry, *tmp;

dw_pcie_setup(pci);

Expand Down Expand Up @@ -725,16 +727,35 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci);
dev_dbg(pci->dev, "iATU unroll: %s\n",
pci->iatu_unroll_enabled ? "enabled" : "disabled");
}

dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_MEM, pp->mem_base,
pp->mem_bus_addr, pp->mem_size);
if (pci->num_viewport > 2)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
/* Get last memory resource entry */
resource_list_for_each_entry_safe(entry, tmp, &pp->bridge->windows) {
if (resource_type(entry->res) != IORESOURCE_MEM)
continue;

if (pci->num_viewport <= ++atu_idx)
break;

dw_pcie_prog_outbound_atu(pci, atu_idx,
PCIE_ATU_TYPE_MEM, entry->res->start,
entry->res->start - entry->offset,
resource_size(entry->res));
}

if (pp->io_size) {
if (pci->num_viewport > ++atu_idx)
dw_pcie_prog_outbound_atu(pci, atu_idx,
PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size);
else
pci->io_cfg_atu_shared = true;
}

if (pci->num_viewport <= atu_idx)
dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)",
pci->num_viewport);

dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);

/* Enable write permission for the DBI read-only register */
Expand Down
12 changes: 6 additions & 6 deletions drivers/pci/controller/dwc/pcie-designware.h
Expand Up @@ -56,11 +56,8 @@
#define PCIE_MSI_INTR0_STATUS 0x830

#define PCIE_ATU_VIEWPORT 0x900
#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
#define PCIE_ATU_REGION_INDEX2 (0x2 << 0)
#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
#define PCIE_ATU_REGION_INBOUND BIT(31)
#define PCIE_ATU_REGION_OUTBOUND 0
#define PCIE_ATU_CR1 0x904
#define PCIE_ATU_TYPE_MEM (0x0 << 0)
#define PCIE_ATU_TYPE_IO (0x2 << 0)
Expand Down Expand Up @@ -174,6 +171,7 @@ struct pcie_port {
u32 irq_status[MAX_MSI_CTRLS];
raw_spinlock_t lock;
int msi_ext;
struct pci_host_bridge *bridge;
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
};

Expand Down Expand Up @@ -223,11 +221,13 @@ struct dw_pcie {
void __iomem *dbi_base;
void __iomem *dbi_base2;
u32 num_viewport;
u8 iatu_unroll_enabled;
struct pcie_port pp;
struct dw_pcie_ep ep;
const struct dw_pcie_ops *ops;
int link_gen;
u8 n_fts[2];
bool iatu_unroll_enabled: 1;
bool io_cfg_atu_shared: 1;
};

#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
Expand Down

0 comments on commit 50a01d3

Please sign in to comment.