Commit 29b10c60 authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branch 'pci/dwc'

- Always set DesignWare "TLP Digest" bit so generic code can enable ECRC
  via the AER Capability (Vidya Sagar)

- Drop support for config space in DT 'ranges' (Rob Herring)

- Increase width of outbound iATU size to u64 (Shradha Todi)

- Add upper limit address for outbound iATU (Shradha Todi)

- Allow dwc-based drivers that don't override any default ops (Jisheng
  Zhang)

- Drop unnecessary dw_pcie_ops from the al driver (Jisheng Zhang)

* pci/dwc:
  PCI: al: Remove useless dw_pcie_ops
  PCI: dwc: Don't assume the ops in dw_pcie always exist
  PCI: dwc: Add upper limit address for outbound iATU
  PCI: dwc: Change size to u64 for EP outbound iATU
  PCI: dwc: Drop support for config space in 'ranges'
  PCI: dwc: Work around ECRC configuration issue
parents 59189d06 2a34b86f
...@@ -314,9 +314,6 @@ static const struct dw_pcie_host_ops al_pcie_host_ops = { ...@@ -314,9 +314,6 @@ static const struct dw_pcie_host_ops al_pcie_host_ops = {
.host_init = al_pcie_host_init, .host_init = al_pcie_host_init,
}; };
static const struct dw_pcie_ops dw_pcie_ops = {
};
static int al_pcie_probe(struct platform_device *pdev) static int al_pcie_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -334,7 +331,6 @@ static int al_pcie_probe(struct platform_device *pdev) ...@@ -334,7 +331,6 @@ static int al_pcie_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
pci->dev = dev; pci->dev = dev;
pci->ops = &dw_pcie_ops;
pci->pp.ops = &al_pcie_host_ops; pci->pp.ops = &al_pcie_host_ops;
al_pcie->pci = pci; al_pcie->pci = pci;
......
...@@ -434,9 +434,7 @@ static void dw_pcie_ep_stop(struct pci_epc *epc) ...@@ -434,9 +434,7 @@ static void dw_pcie_ep_stop(struct pci_epc *epc)
struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
if (!pci->ops->stop_link) if (pci->ops && pci->ops->stop_link)
return;
pci->ops->stop_link(pci); pci->ops->stop_link(pci);
} }
...@@ -445,7 +443,7 @@ static int dw_pcie_ep_start(struct pci_epc *epc) ...@@ -445,7 +443,7 @@ static int dw_pcie_ep_start(struct pci_epc *epc)
struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
if (!pci->ops->start_link) if (!pci->ops || !pci->ops->start_link)
return -EINVAL; return -EINVAL;
return pci->ops->start_link(pci); return pci->ops->start_link(pci);
......
...@@ -305,8 +305,13 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -305,8 +305,13 @@ int dw_pcie_host_init(struct pcie_port *pp)
if (cfg_res) { if (cfg_res) {
pp->cfg0_size = resource_size(cfg_res); pp->cfg0_size = resource_size(cfg_res);
pp->cfg0_base = cfg_res->start; pp->cfg0_base = cfg_res->start;
} else if (!pp->va_cfg0_base) {
pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, cfg_res);
if (IS_ERR(pp->va_cfg0_base))
return PTR_ERR(pp->va_cfg0_base);
} else {
dev_err(dev, "Missing *config* reg space\n"); dev_err(dev, "Missing *config* reg space\n");
return -ENODEV;
} }
if (!pci->dbi_base) { if (!pci->dbi_base) {
...@@ -322,38 +327,12 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -322,38 +327,12 @@ int dw_pcie_host_init(struct pcie_port *pp)
pp->bridge = bridge; pp->bridge = bridge;
/* Get the I/O and memory ranges from DT */ /* Get the I/O range from DT */
resource_list_for_each_entry(win, &bridge->windows) { win = resource_list_first_type(&bridge->windows, IORESOURCE_IO);
switch (resource_type(win->res)) { if (win) {
case IORESOURCE_IO:
pp->io_size = resource_size(win->res); pp->io_size = resource_size(win->res);
pp->io_bus_addr = win->res->start - win->offset; pp->io_bus_addr = win->res->start - win->offset;
pp->io_base = pci_pio_to_address(win->res->start); pp->io_base = pci_pio_to_address(win->res->start);
break;
case 0:
dev_err(dev, "Missing *config* reg space\n");
pp->cfg0_size = resource_size(win->res);
pp->cfg0_base = win->res->start;
if (!pci->dbi_base) {
pci->dbi_base = devm_pci_remap_cfgspace(dev,
pp->cfg0_base,
pp->cfg0_size);
if (!pci->dbi_base) {
dev_err(dev, "Error with ioremap\n");
return -ENOMEM;
}
}
break;
}
}
if (!pp->va_cfg0_base) {
pp->va_cfg0_base = devm_pci_remap_cfgspace(dev,
pp->cfg0_base, pp->cfg0_size);
if (!pp->va_cfg0_base) {
dev_err(dev, "Error with ioremap in function\n");
return -ENOMEM;
}
} }
if (pci->link_gen < 1) if (pci->link_gen < 1)
...@@ -425,7 +404,7 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -425,7 +404,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
dw_pcie_setup_rc(pp); dw_pcie_setup_rc(pp);
dw_pcie_msi_init(pp); dw_pcie_msi_init(pp);
if (!dw_pcie_link_up(pci) && pci->ops->start_link) { if (!dw_pcie_link_up(pci) && pci->ops && pci->ops->start_link) {
ret = pci->ops->start_link(pci); ret = pci->ops->start_link(pci);
if (ret) if (ret)
goto err_free_msi; goto err_free_msi;
......
...@@ -141,7 +141,7 @@ u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size) ...@@ -141,7 +141,7 @@ u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size)
int ret; int ret;
u32 val; u32 val;
if (pci->ops->read_dbi) if (pci->ops && pci->ops->read_dbi)
return pci->ops->read_dbi(pci, pci->dbi_base, reg, size); return pci->ops->read_dbi(pci, pci->dbi_base, reg, size);
ret = dw_pcie_read(pci->dbi_base + reg, size, &val); ret = dw_pcie_read(pci->dbi_base + reg, size, &val);
...@@ -156,7 +156,7 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val) ...@@ -156,7 +156,7 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
{ {
int ret; int ret;
if (pci->ops->write_dbi) { if (pci->ops && pci->ops->write_dbi) {
pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val); pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val);
return; return;
} }
...@@ -171,7 +171,7 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val) ...@@ -171,7 +171,7 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
{ {
int ret; int ret;
if (pci->ops->write_dbi2) { if (pci->ops && pci->ops->write_dbi2) {
pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val); pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val);
return; return;
} }
...@@ -186,7 +186,7 @@ static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg) ...@@ -186,7 +186,7 @@ static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
int ret; int ret;
u32 val; u32 val;
if (pci->ops->read_dbi) if (pci->ops && pci->ops->read_dbi)
return pci->ops->read_dbi(pci, pci->atu_base, reg, 4); return pci->ops->read_dbi(pci, pci->atu_base, reg, 4);
ret = dw_pcie_read(pci->atu_base + reg, 4, &val); ret = dw_pcie_read(pci->atu_base + reg, 4, &val);
...@@ -200,7 +200,7 @@ static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) ...@@ -200,7 +200,7 @@ static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
{ {
int ret; int ret;
if (pci->ops->write_dbi) { if (pci->ops && pci->ops->write_dbi) {
pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val); pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);
return; return;
} }
...@@ -225,6 +225,47 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, ...@@ -225,6 +225,47 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
dw_pcie_writel_atu(pci, offset + reg, val); dw_pcie_writel_atu(pci, offset + reg, val);
} }
static inline u32 dw_pcie_enable_ecrc(u32 val)
{
/*
* DesignWare core version 4.90A has a design issue where the 'TD'
* bit in the Control register-1 of the ATU outbound region acts
* like an override for the ECRC setting, i.e., the presence of TLP
* Digest (ECRC) in the outgoing TLPs is solely determined by this
* bit. This is contrary to the PCIe spec which says that the
* enablement of the ECRC is solely determined by the AER
* registers.
*
* Because of this, even when the ECRC is enabled through AER
* registers, the transactions going through ATU won't have TLP
* Digest as there is no way the PCI core AER code could program
* the TD bit which is specific to the DesignWare core.
*
* The best way to handle this scenario is to program the TD bit
* always. It affects only the traffic from root port to downstream
* devices.
*
* At this point,
* When ECRC is enabled in AER registers, everything works normally
* When ECRC is NOT enabled in AER registers, then,
* on Root Port:- TLP Digest (DWord size) gets appended to each packet
* even through it is not required. Since downstream
* TLPs are mostly for configuration accesses and BAR
* accesses, they are not in critical path and won't
* have much negative effect on the performance.
* on End Point:- TLP Digest is received for some/all the packets coming
* from the root port. TLP Digest is ignored because,
* as per the PCIe Spec r5.0 v1.0 section 2.2.3
* "TLP Digest Rules", when an endpoint receives TLP
* Digest when its ECRC check functionality is disabled
* in AER registers, received TLP Digest is just ignored.
* Since there is no issue or error reported either side, best way to
* handle the scenario is to program TD bit by default.
*/
return val | PCIE_ATU_TD;
}
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
int index, int type, int index, int type,
u64 cpu_addr, u64 pci_addr, u64 cpu_addr, u64 pci_addr,
...@@ -248,6 +289,8 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, ...@@ -248,6 +289,8 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
val = type | PCIE_ATU_FUNC_NUM(func_no); val = type | PCIE_ATU_FUNC_NUM(func_no);
val = upper_32_bits(size - 1) ? val = upper_32_bits(size - 1) ?
val | PCIE_ATU_INCREASE_REGION_SIZE : val; val | PCIE_ATU_INCREASE_REGION_SIZE : val;
if (pci->version == 0x490A)
val = dw_pcie_enable_ecrc(val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val); dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
PCIE_ATU_ENABLE); PCIE_ATU_ENABLE);
...@@ -273,7 +316,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, ...@@ -273,7 +316,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
{ {
u32 retries, val; u32 retries, val;
if (pci->ops->cpu_addr_fixup) if (pci->ops && pci->ops->cpu_addr_fixup)
cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr); cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
if (pci->iatu_unroll_enabled) { if (pci->iatu_unroll_enabled) {
...@@ -290,12 +333,19 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, ...@@ -290,12 +333,19 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
upper_32_bits(cpu_addr)); upper_32_bits(cpu_addr));
dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
lower_32_bits(cpu_addr + size - 1)); lower_32_bits(cpu_addr + size - 1));
if (pci->version >= 0x460A)
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT,
upper_32_bits(cpu_addr + size - 1));
dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
lower_32_bits(pci_addr)); lower_32_bits(pci_addr));
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
upper_32_bits(pci_addr)); upper_32_bits(pci_addr));
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | val = type | PCIE_ATU_FUNC_NUM(func_no);
PCIE_ATU_FUNC_NUM(func_no)); val = ((upper_32_bits(size - 1)) && (pci->version >= 0x460A)) ?
val | PCIE_ATU_INCREASE_REGION_SIZE : val;
if (pci->version == 0x490A)
val = dw_pcie_enable_ecrc(val);
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
/* /*
...@@ -321,7 +371,7 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, ...@@ -321,7 +371,7 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
int type, u64 cpu_addr, u64 pci_addr, int type, u64 cpu_addr, u64 pci_addr,
u32 size) u64 size)
{ {
__dw_pcie_prog_outbound_atu(pci, func_no, index, type, __dw_pcie_prog_outbound_atu(pci, func_no, index, type,
cpu_addr, pci_addr, size); cpu_addr, pci_addr, size);
...@@ -481,7 +531,7 @@ int dw_pcie_link_up(struct dw_pcie *pci) ...@@ -481,7 +531,7 @@ int dw_pcie_link_up(struct dw_pcie *pci)
{ {
u32 val; u32 val;
if (pci->ops->link_up) if (pci->ops && pci->ops->link_up)
return pci->ops->link_up(pci); return pci->ops->link_up(pci);
val = readl(pci->dbi_base + PCIE_PORT_DEBUG1); val = readl(pci->dbi_base + PCIE_PORT_DEBUG1);
......
...@@ -86,6 +86,7 @@ ...@@ -86,6 +86,7 @@
#define PCIE_ATU_TYPE_IO 0x2 #define PCIE_ATU_TYPE_IO 0x2
#define PCIE_ATU_TYPE_CFG0 0x4 #define PCIE_ATU_TYPE_CFG0 0x4
#define PCIE_ATU_TYPE_CFG1 0x5 #define PCIE_ATU_TYPE_CFG1 0x5
#define PCIE_ATU_TD BIT(8)
#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20) #define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20)
#define PCIE_ATU_CR2 0x908 #define PCIE_ATU_CR2 0x908
#define PCIE_ATU_ENABLE BIT(31) #define PCIE_ATU_ENABLE BIT(31)
...@@ -99,6 +100,7 @@ ...@@ -99,6 +100,7 @@
#define PCIE_ATU_DEV(x) FIELD_PREP(GENMASK(23, 19), x) #define PCIE_ATU_DEV(x) FIELD_PREP(GENMASK(23, 19), x)
#define PCIE_ATU_FUNC(x) FIELD_PREP(GENMASK(18, 16), x) #define PCIE_ATU_FUNC(x) FIELD_PREP(GENMASK(18, 16), x)
#define PCIE_ATU_UPPER_TARGET 0x91C #define PCIE_ATU_UPPER_TARGET 0x91C
#define PCIE_ATU_UPPER_LIMIT 0x924
#define PCIE_MISC_CONTROL_1_OFF 0x8BC #define PCIE_MISC_CONTROL_1_OFF 0x8BC
#define PCIE_DBI_RO_WR_EN BIT(0) #define PCIE_DBI_RO_WR_EN BIT(0)
...@@ -297,7 +299,7 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, ...@@ -297,7 +299,7 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
u64 size); u64 size);
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
int type, u64 cpu_addr, u64 pci_addr, int type, u64 cpu_addr, u64 pci_addr,
u32 size); u64 size);
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
int bar, u64 cpu_addr, int bar, u64 cpu_addr,
enum dw_pcie_as_type as_type); enum dw_pcie_as_type as_type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment