Endpoint Root complex
┌───────┐ ┌─────────┐
┌─────┐ │ EP │ │ │ ┌─────┐
│ │ │ Ctrl │ │ │ │ CPU │
│ DDR │ │ │ │ ┌────┐ │ └──┬──┘
│ │◄──────┼─ATU ◄─┼────────┼─┤BarN│◄─┼─────────┘
│ │ │ │ │ └────┘ │ Outbound Transfer
└─────┘ │ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │ Inbound Transfer
│ │ │ │ ┌──▼──┐
┌───────┐ │ │ │ ┌───────┼─────►│DDR │
│ │ outbound Transfer* │ │ │ └─────┘
┌─────┐ │ Bus ┼─────►│ ATU ─┬────────┼─┘ │
│ │ │ Fabric│Bus │ │ PCI Addr │
│ CPU ├───►│ │Addr │ │ 0xA000_0000 │
│ │CPU │ │0x8000_0000 │ │ │
└─────┘Addr└───────┘ │ │ │ │
0x7000_0000 └───────┘ └─────────┘
Add `bus_addr_base` to configure the outbound window address for CPU write.
The bus fabric generally passes the same address to the PCIe EP controller,
but some bus fabrics convert the address before sending it to the PCIe EP
controller.
Above diagram, CPU write data to outbound windows address 0x7000_0000,
Bus fabric convert it to 0x8000_0000. ATU should use bus address
0x8000_0000 as input address and convert to PCI address 0xA000_0000.
Previously, `cpu_addr_fixup()` was used to handle address conversion. Now,
the device tree provides this information, preferring a common method.
bus@5f000000 {
compatible = "simple-bus";
ranges = <0x80000000 0x0 0x70000000 0x10000000>;
pcie-ep@5f010000 {
reg = <0x5f010000 0x00010000>,
<0x80000000 0x10000000>;
reg-names = "dbi", "addr_space";
...
};
...
};
'ranges' in bus@5f000000 descript how address convert from CPU address
to bus address.
Use `of_property_read_reg()` to obtain the bus address and set it to the
ATU correctly, eliminating the need for vendor-specific cpu_addr_fixup().
Add 'using_dtbus_info' to indicate device tree reflect correctly bus
address translation in case break compatibility.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change from v2 to v3
- Add using_dtbus_info to control if use device tree bus ranges
information.
---
drivers/pci/controller/dwc/pcie-designware-ep.c | 14 +++++++++++++-
drivers/pci/controller/dwc/pcie-designware.h | 9 +++++++++
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 43ba5c6738df1..81b4057befa62 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -9,6 +9,7 @@
#include <linux/align.h>
#include <linux/bitfield.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include "pcie-designware.h"
@@ -294,7 +295,7 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
atu.func_no = func_no;
atu.type = PCIE_ATU_TYPE_MEM;
- atu.cpu_addr = addr;
+ atu.cpu_addr = addr - ep->phys_base + ep->bus_addr_base;
atu.pci_addr = pci_addr;
atu.size = size;
ret = dw_pcie_ep_outbound_atu(ep, &atu);
@@ -861,6 +862,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
struct device *dev = pci->dev;
struct platform_device *pdev = to_platform_device(dev);
struct device_node *np = dev->of_node;
+ int index;
INIT_LIST_HEAD(&ep->func_list);
@@ -873,6 +875,16 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
return -EINVAL;
ep->phys_base = res->start;
+ ep->bus_addr_base = ep->phys_base;
+
+ if (pci->using_dtbus_info) {
+ index = of_property_match_string(np, "reg-names", "addr_space");
+ if (index < 0)
+ return -EINVAL;
+
+ of_property_read_reg(np, index, &ep->bus_addr_base, NULL);
+ }
+
ep->addr_size = resource_size(res);
if (ep->ops->pre_init)
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 347ab74ac35aa..e22d32b5a5f19 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -410,6 +410,7 @@ struct dw_pcie_ep {
struct list_head func_list;
const struct dw_pcie_ep_ops *ops;
phys_addr_t phys_base;
+ phys_addr_t bus_addr_base;
size_t addr_size;
size_t page_size;
u8 bar_to_atu[PCI_STD_NUM_BARS];
@@ -463,6 +464,14 @@ struct dw_pcie {
struct reset_control_bulk_data core_rsts[DW_PCIE_NUM_CORE_RSTS];
struct gpio_desc *pe_rst;
bool suspended;
+ /*
+ * Use device tree 'ranges' property of bus node instead using
+ * cpu_addr_fixup(). Some old platform dts 'ranges' in bus node may not
+ * reflect real hardware's behavior. In case break these platform back
+ * compatibility, add below flags. Set it true if dts already correct
+ * indicate bus fabric address convert.
+ */
+ bool using_dtbus_info;
};
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
--
2.34.1
Hi Frank, kernel test robot noticed the following build errors: [auto build test ERROR on afb15ca28055352101286046c1f9f01fdaa1ace1] url: https://github.com/intel-lab-lkp/linux/commits/Frank-Li/PCI-dwc-ep-Add-bus_addr_base-for-outbound-window/20241022-041043 base: afb15ca28055352101286046c1f9f01fdaa1ace1 patch link: https://lore.kernel.org/r/20241021-pcie_ep_range-v3-1-b13526eb0089%40nxp.com patch subject: [PATCH v3 1/4] PCI: dwc: ep: Add bus_addr_base for outbound window config: arm-allmodconfig (https://download.01.org/0day-ci/archive/20241023/202410230328.BTHareG1-lkp@intel.com/config) compiler: arm-linux-gnueabi-gcc (GCC) 14.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241023/202410230328.BTHareG1-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202410230328.BTHareG1-lkp@intel.com/ All errors (new ones prefixed by >>): drivers/pci/controller/dwc/pcie-designware-ep.c: In function 'dw_pcie_ep_init': >> drivers/pci/controller/dwc/pcie-designware-ep.c:885:49: error: passing argument 3 of 'of_property_read_reg' from incompatible pointer type [-Wincompatible-pointer-types] 885 | of_property_read_reg(np, index, &ep->bus_addr_base, NULL); | ^~~~~~~~~~~~~~~~~~ | | | phys_addr_t * {aka unsigned int *} In file included from drivers/pci/controller/dwc/pcie-designware-ep.c:12: include/linux/of_address.h:75:64: note: expected 'u64 *' {aka 'long long unsigned int *'} but argument is of type 'phys_addr_t *' {aka 'unsigned int *'} 75 | int of_property_read_reg(struct device_node *np, int idx, u64 *addr, u64 *size); | ~~~~~^~~~ Kconfig warnings: (for reference only) WARNING: unmet direct dependencies detected for GET_FREE_REGION Depends on [n]: SPARSEMEM [=n] Selected by [m]: - RESOURCE_KUNIT_TEST [=m] && RUNTIME_TESTING_MENU [=y] && KUNIT [=m] vim +/of_property_read_reg +885 drivers/pci/controller/dwc/pcie-designware-ep.c 846 847 /** 848 * dw_pcie_ep_init - Initialize the endpoint device 849 * @ep: DWC EP device 850 * 851 * Initialize the endpoint device. Allocate resources and create the EPC 852 * device with the endpoint framework. 853 * 854 * Return: 0 if success, errno otherwise. 855 */ 856 int dw_pcie_ep_init(struct dw_pcie_ep *ep) 857 { 858 int ret; 859 struct resource *res; 860 struct pci_epc *epc; 861 struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 862 struct device *dev = pci->dev; 863 struct platform_device *pdev = to_platform_device(dev); 864 struct device_node *np = dev->of_node; 865 int index; 866 867 INIT_LIST_HEAD(&ep->func_list); 868 869 ret = dw_pcie_get_resources(pci); 870 if (ret) 871 return ret; 872 873 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); 874 if (!res) 875 return -EINVAL; 876 877 ep->phys_base = res->start; 878 ep->bus_addr_base = ep->phys_base; 879 880 if (pci->using_dtbus_info) { 881 index = of_property_match_string(np, "reg-names", "addr_space"); 882 if (index < 0) 883 return -EINVAL; 884 > 885 of_property_read_reg(np, index, &ep->bus_addr_base, NULL); -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
Hi Frank, kernel test robot noticed the following build errors: [auto build test ERROR on afb15ca28055352101286046c1f9f01fdaa1ace1] url: https://github.com/intel-lab-lkp/linux/commits/Frank-Li/PCI-dwc-ep-Add-bus_addr_base-for-outbound-window/20241022-041043 base: afb15ca28055352101286046c1f9f01fdaa1ace1 patch link: https://lore.kernel.org/r/20241021-pcie_ep_range-v3-1-b13526eb0089%40nxp.com patch subject: [PATCH v3 1/4] PCI: dwc: ep: Add bus_addr_base for outbound window config: i386-buildonly-randconfig-002-20241023 (https://download.01.org/0day-ci/archive/20241023/202410230325.DxAdrnbW-lkp@intel.com/config) compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241023/202410230325.DxAdrnbW-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202410230325.DxAdrnbW-lkp@intel.com/ All errors (new ones prefixed by >>): >> drivers/pci/controller/dwc/pcie-designware-ep.c:885:35: error: incompatible pointer types passing 'phys_addr_t *' (aka 'unsigned int *') to parameter of type 'u64 *' (aka 'unsigned long long *') [-Werror,-Wincompatible-pointer-types] 885 | of_property_read_reg(np, index, &ep->bus_addr_base, NULL); | ^~~~~~~~~~~~~~~~~~ include/linux/of_address.h:75:64: note: passing argument to parameter 'addr' here 75 | int of_property_read_reg(struct device_node *np, int idx, u64 *addr, u64 *size); | ^ 1 error generated. vim +885 drivers/pci/controller/dwc/pcie-designware-ep.c 846 847 /** 848 * dw_pcie_ep_init - Initialize the endpoint device 849 * @ep: DWC EP device 850 * 851 * Initialize the endpoint device. Allocate resources and create the EPC 852 * device with the endpoint framework. 853 * 854 * Return: 0 if success, errno otherwise. 855 */ 856 int dw_pcie_ep_init(struct dw_pcie_ep *ep) 857 { 858 int ret; 859 struct resource *res; 860 struct pci_epc *epc; 861 struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 862 struct device *dev = pci->dev; 863 struct platform_device *pdev = to_platform_device(dev); 864 struct device_node *np = dev->of_node; 865 int index; 866 867 INIT_LIST_HEAD(&ep->func_list); 868 869 ret = dw_pcie_get_resources(pci); 870 if (ret) 871 return ret; 872 873 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); 874 if (!res) 875 return -EINVAL; 876 877 ep->phys_base = res->start; 878 ep->bus_addr_base = ep->phys_base; 879 880 if (pci->using_dtbus_info) { 881 index = of_property_match_string(np, "reg-names", "addr_space"); 882 if (index < 0) 883 return -EINVAL; 884 > 885 of_property_read_reg(np, index, &ep->bus_addr_base, NULL); -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2024 Red Hat, Inc.