[PATCH v3 1/4] PCI: dwc: ep: Add bus_addr_base for outbound window

Frank Li posted 4 patches 1 month ago
There is a newer version of this series
[PATCH v3 1/4] PCI: dwc: ep: Add bus_addr_base for outbound window
Posted by Frank Li 1 month ago
                               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

Re: [PATCH v3 1/4] PCI: dwc: ep: Add bus_addr_base for outbound window
Posted by kernel test robot 1 month ago
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
Re: [PATCH v3 1/4] PCI: dwc: ep: Add bus_addr_base for outbound window
Posted by kernel test robot 1 month ago
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