aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDong Bo <dongbo4@huawei.com>2016-07-04 12:14:43 -0400
committerBjorn Helgaas <bhelgaas@google.com>2016-08-23 17:55:16 -0400
commit68a0bfec72cb4f117198ae31df114dad4c5e405d (patch)
treef6a484428d37d909ae5363fac43e4d19260651d8
parentfe48cb8538421fbd16ecf8bf95829faf8d8c001e (diff)
PCI: designware: Exchange viewport of `MEMORYs' and `CFGs/IOs'
When we have only two view ports in a DesignWare PCIe platform, iatu0 is used for both CFG and IO accesses. When CFGs are sent to peripherals (e.g., lspci), iatu0 frequently switches between CFG and IO. For such scenarios, a MEMORY might be sent as an IOs by mistake. Considering the following configurations: MEMORY -> BASE_ADDR: 0xb4100000, LIMIT: 0xb4100FFF, TYPE=mem CFG -> BASE_ADDR: 0xb4000000, LIMIT: 0xb4000FFF, TYPE=cfg IO -> BASE_ADDR: 0xFFFFFFFF, LIMIT: 0xFFFFFFFE, TYPE=io Suppose PCIe has just completed a CFG access. To switch back to IO, it sets the BASE_ADDR to 0xFFFFFFFF, LIMIT 0xFFFFFFFE and TYPE to IO. When another CFG comes, the BASE_ADDR is set to 0xb4000000 to switch to CFG. At this moment, a MEMORY access shows up, since it matches with iatu0 (due to 0xb4000000 <= MEMORY BASE_ADDR <= MEMORY LIMIT <= 0xFFFFFFF), it is treated as an IO access by mistake, then sent to perpheral. This patch fixes the problem by exchanging the assignments of `MEMORYs' and `CFGs/IOs', which assigning MEMORYs to iatu0, CFGs and IOs to iatu1. We can still have issues with IO transfer, however memory transfer is used predominantly therefore we are just minimizing the risk of failure. Actually, we can not do much when we have only two viewports. We can either not allow the less frequent IO transfers at all, or can live with a remote possibility of getting it corrupted. Signed-off-by: Dong Bo <dongbo4@huawei.com> [pratyush.anand@gmail.com: Modified commit log to capture remote risk] Signed-off-by: Pratyush Anand <pratyush.anand@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/pci/host/pcie-designware.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 38460138327a..c3b88bbe18bf 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -708,12 +708,12 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
708 va_cfg_base = pp->va_cfg1_base; 708 va_cfg_base = pp->va_cfg1_base;
709 } 709 }
710 710
711 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, 711 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
712 type, cpu_addr, 712 type, cpu_addr,
713 busdev, cfg_size); 713 busdev, cfg_size);
714 ret = dw_pcie_cfg_read(va_cfg_base + where, size, val); 714 ret = dw_pcie_cfg_read(va_cfg_base + where, size, val);
715 if (pp->num_viewport <= 2) 715 if (pp->num_viewport <= 2)
716 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, 716 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
717 PCIE_ATU_TYPE_IO, pp->io_base, 717 PCIE_ATU_TYPE_IO, pp->io_base,
718 pp->io_bus_addr, pp->io_size); 718 pp->io_bus_addr, pp->io_size);
719 719
@@ -746,12 +746,12 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
746 va_cfg_base = pp->va_cfg1_base; 746 va_cfg_base = pp->va_cfg1_base;
747 } 747 }
748 748
749 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, 749 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
750 type, cpu_addr, 750 type, cpu_addr,
751 busdev, cfg_size); 751 busdev, cfg_size);
752 ret = dw_pcie_cfg_write(va_cfg_base + where, size, val); 752 ret = dw_pcie_cfg_write(va_cfg_base + where, size, val);
753 if (pp->num_viewport <= 2) 753 if (pp->num_viewport <= 2)
754 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, 754 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
755 PCIE_ATU_TYPE_IO, pp->io_base, 755 PCIE_ATU_TYPE_IO, pp->io_base,
756 pp->io_bus_addr, pp->io_size); 756 pp->io_bus_addr, pp->io_size);
757 757
@@ -890,7 +890,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
890 * we should not program the ATU here. 890 * we should not program the ATU here.
891 */ 891 */
892 if (!pp->ops->rd_other_conf) { 892 if (!pp->ops->rd_other_conf) {
893 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1, 893 dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
894 PCIE_ATU_TYPE_MEM, pp->mem_base, 894 PCIE_ATU_TYPE_MEM, pp->mem_base,
895 pp->mem_bus_addr, pp->mem_size); 895 pp->mem_bus_addr, pp->mem_size);
896 if (pp->num_viewport > 2) 896 if (pp->num_viewport > 2)