On 4/4/23 17:24, Rick Wertenbroek wrote: > The RK3399 PCI endpoint core has 33 windows for PCIe space, now in the > driver up to 32 fixed size (1M) windows are used and pages are allocated > and mapped accordingly. The driver first used a single window and allocated > space inside which caused translation issues (between CPU space and PCI > space) because a window can only have a single translation at a given > time, which if multiple pages are allocated inside will cause conflicts. > Now each window is a single region of 1M which will always guarantee that > the translation is not in conflict. > > Set the translation register addresses for physical function. As documented > in the technical reference manual (TRM) section 17.5.5 "PCIe Address > Translation" and section 17.6.8 "Address Translation Registers Description" > > Fixes: cf590b078391 ("PCI: rockchip: Add EP driver for Rockchip PCIe controller") > Cc: stable@xxxxxxxxxxxxxxx > Signed-off-by: Rick Wertenbroek <rick.wertenbroek@xxxxxxxxx> > --- > drivers/pci/controller/pcie-rockchip-ep.c | 110 +++++++++------------- > drivers/pci/controller/pcie-rockchip.h | 30 +++--- > 2 files changed, 64 insertions(+), 76 deletions(-) > > diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c > index 7591a7be78e0..f366846ad77c 100644 > --- a/drivers/pci/controller/pcie-rockchip-ep.c > +++ b/drivers/pci/controller/pcie-rockchip-ep.c > @@ -64,52 +64,30 @@ static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip, > } > > static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn, > - u32 r, u32 type, u64 cpu_addr, > - u64 pci_addr, size_t size) > + u32 r, u64 cpu_addr, u64 pci_addr, > + size_t size) > { > u64 sz = 1ULL << fls64(size - 1); > int num_pass_bits = ilog2(sz); > - u32 addr0, addr1, desc0, desc1; > - bool is_nor_msg = (type == AXI_WRAPPER_NOR_MSG); > + u32 addr0, addr1, desc0; > > - /* The minimal region size is 1MB */ > if (num_pass_bits < 8) > num_pass_bits = 8; > > - cpu_addr -= rockchip->mem_res->start; > - addr0 = ((is_nor_msg ? 0x10 : (num_pass_bits - 1)) & > - PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) | > - (lower_32_bits(cpu_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR); > - addr1 = upper_32_bits(is_nor_msg ? cpu_addr : pci_addr); > - desc0 = ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(fn) | type; > - desc1 = 0; > - > - if (is_nor_msg) { > - rockchip_pcie_write(rockchip, 0, > - ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r)); > - rockchip_pcie_write(rockchip, 0, > - ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r)); > - rockchip_pcie_write(rockchip, desc0, > - ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r)); > - rockchip_pcie_write(rockchip, desc1, > - ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r)); > - } else { > - /* PCI bus address region */ > - rockchip_pcie_write(rockchip, addr0, > - ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r)); > - rockchip_pcie_write(rockchip, addr1, > - ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r)); > - rockchip_pcie_write(rockchip, desc0, > - ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r)); > - rockchip_pcie_write(rockchip, desc1, > - ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r)); > - > - addr0 = > - ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) | > - (lower_32_bits(cpu_addr) & > - PCIE_CORE_OB_REGION_ADDR0_LO_ADDR); > - addr1 = upper_32_bits(cpu_addr); > - } > + addr0 = ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) | > + (lower_32_bits(pci_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR); > + addr1 = upper_32_bits(pci_addr); > + desc0 = ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(fn) | AXI_WRAPPER_MEM_WRITE; > + > + /* PCI bus address region */ > + rockchip_pcie_write(rockchip, addr0, > + ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r)); > + rockchip_pcie_write(rockchip, addr1, > + ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r)); > + rockchip_pcie_write(rockchip, desc0, > + ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r)); > + rockchip_pcie_write(rockchip, 0, > + ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r)); > } > > static int rockchip_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn, > @@ -248,6 +226,11 @@ static void rockchip_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn, > ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar)); > } > > +static inline u32 rockchip_ob_region(phys_addr_t addr) > +{ > + return (addr >> ilog2(SZ_1M)) & 0x1f; > +} > + > static int rockchip_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn, > phys_addr_t addr, u64 pci_addr, > size_t size) > @@ -256,18 +239,9 @@ static int rockchip_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn, > struct rockchip_pcie *pcie = &ep->rockchip; > u32 r; > > - r = find_first_zero_bit(&ep->ob_region_map, BITS_PER_LONG); > - /* > - * Region 0 is reserved for configuration space and shouldn't > - * be used elsewhere per TRM, so leave it out. > - */ > - if (r >= ep->max_regions - 1) { > - dev_err(&epc->dev, "no free outbound region\n"); > - return -EINVAL; > - } > + r = rockchip_ob_region(addr); Nit: you can move this together with the decalration: u32 r = rockchip_ob_region(addr); > > - rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, AXI_WRAPPER_MEM_WRITE, addr, > - pci_addr, size); > + rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, addr, pci_addr, size); > > set_bit(r, &ep->ob_region_map); > ep->ob_addr[r] = addr; > @@ -282,15 +256,11 @@ static void rockchip_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn, > struct rockchip_pcie *rockchip = &ep->rockchip; > u32 r; > > - for (r = 0; r < ep->max_regions - 1; r++) > + for (r = 0; r < ep->max_regions; r++) > if (ep->ob_addr[r] == addr) > break; > > - /* > - * Region 0 is reserved for configuration space and shouldn't > - * be used elsewhere per TRM, so leave it out. > - */ > - if (r == ep->max_regions - 1) > + if (r == ep->max_regions) > return; > > rockchip_pcie_clear_ep_ob_atu(rockchip, r); > @@ -388,6 +358,7 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn, > u16 flags, mme, data, data_mask; > u8 msi_count; > u64 pci_addr, pci_addr_mask = 0xff; Nit: pci_addr_mask is constant and never changed, so we could get rid of this variable and use a macro instead. > + u32 r; > > /* Check MSI enable bit */ > flags = rockchip_pcie_read(&ep->rockchip, > @@ -421,13 +392,12 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn, > ROCKCHIP_PCIE_EP_FUNC_BASE(fn) + > ROCKCHIP_PCIE_EP_MSI_CTRL_REG + > PCI_MSI_ADDRESS_LO); > - pci_addr &= GENMASK_ULL(63, 2); > > /* Set the outbound region if needed. */ > if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) || > ep->irq_pci_fn != fn)) { > - rockchip_pcie_prog_ep_ob_atu(rockchip, fn, ep->max_regions - 1, > - AXI_WRAPPER_MEM_WRITE, > + r = rockchip_ob_region(ep->irq_phys_addr); > + rockchip_pcie_prog_ep_ob_atu(rockchip, fn, r, > ep->irq_phys_addr, > pci_addr & ~pci_addr_mask, > pci_addr_mask + 1); > @@ -516,6 +486,8 @@ static int rockchip_pcie_parse_ep_dt(struct rockchip_pcie *rockchip, > if (err < 0 || ep->max_regions > MAX_REGION_LIMIT) > ep->max_regions = MAX_REGION_LIMIT; > > + ep->ob_region_map = 0; > + > err = of_property_read_u8(dev->of_node, "max-functions", > &ep->epc->max_functions); > if (err < 0) > @@ -536,7 +508,8 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev) > struct rockchip_pcie *rockchip; > struct pci_epc *epc; > size_t max_regions; > - int err; > + struct pci_epc_mem_window *windows = NULL; > + int err, i; > > ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); > if (!ep) > @@ -583,15 +556,26 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev) > /* Only enable function 0 by default */ > rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG); > > - err = pci_epc_mem_init(epc, rockchip->mem_res->start, > - resource_size(rockchip->mem_res), PAGE_SIZE); > + windows = devm_kcalloc(dev, ep->max_regions, sizeof(struct pci_epc_mem_window), GFP_KERNEL); Nit: long line. Please split it at sizeof(...). > + if (!windows) { > + err = -ENOMEM; > + goto err_uninit_port; > + } > + for (i = 0; i < ep->max_regions; i++) { > + windows[i].phys_base = rockchip->mem_res->start + (SZ_1M * i); > + windows[i].size = SZ_1M; > + windows[i].page_size = SZ_1M; > + } > + err = pci_epc_multi_mem_init(epc, windows, ep->max_regions); > + devm_kfree(dev, windows); > + > if (err < 0) { > dev_err(dev, "failed to initialize the memory space\n"); > goto err_uninit_port; > } > > ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr, > - SZ_128K); > + SZ_1M); > if (!ep->irq_cpu_addr) { > dev_err(dev, "failed to reserve memory space for MSI\n"); > err = -ENOMEM; > diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h > index ffc68a3a5fee..5797ba73bb6b 100644 > --- a/drivers/pci/controller/pcie-rockchip.h > +++ b/drivers/pci/controller/pcie-rockchip.h > @@ -139,6 +139,7 @@ > > #define PCIE_RC_RP_ATS_BASE 0x400000 > #define PCIE_RC_CONFIG_NORMAL_BASE 0x800000 > +#define PCIE_EP_PF_CONFIG_REGS_BASE 0x800000 > #define PCIE_RC_CONFIG_BASE 0xa00000 > #define PCIE_EP_CONFIG_BASE 0xa00000 > #define PCIE_EP_CONFIG_DID_VID (PCIE_EP_CONFIG_BASE + 0x00) > @@ -232,13 +233,15 @@ > #define ROCKCHIP_PCIE_EP_MSI_CTRL_ME BIT(16) > #define ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP BIT(24) > #define ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR 0x1 > -#define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12)) > +#define ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR 0x3 > +#define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) \ > + (PCIE_EP_PF_CONFIG_REGS_BASE + (((fn) << 12) & GENMASK(19, 12))) > +#define ROCKCHIP_PCIE_EP_VIRT_FUNC_BASE(fn) \ > + (PCIE_EP_PF_CONFIG_REGS_BASE + 0x10000 + (((fn) << 12) & GENMASK(19, 12))) > #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \ > - (PCIE_RC_RP_ATS_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008) > + (PCIE_CORE_AXI_CONF_BASE + 0x0828 + (fn) * 0x0040 + (bar) * 0x0008) > #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \ > - (PCIE_RC_RP_ATS_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008) > -#define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r) \ > - (PCIE_RC_RP_ATS_BASE + 0x0000 + ((r) & 0x1f) * 0x0020) > + (PCIE_CORE_AXI_CONF_BASE + 0x082c + (fn) * 0x0040 + (bar) * 0x0008) > #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12) > #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \ > (((devfn) << 12) & \ > @@ -246,20 +249,21 @@ > #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20) > #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \ > (((bus) << 20) & ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK) > +#define PCIE_RC_EP_ATR_OB_REGIONS_1_32 (PCIE_CORE_AXI_CONF_BASE + 0x0020) > +#define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r) \ > + (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0000 + ((r) & 0x1f) * 0x0020) > #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r) \ > - (PCIE_RC_RP_ATS_BASE + 0x0004 + ((r) & 0x1f) * 0x0020) > + (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0004 + ((r) & 0x1f) * 0x0020) > #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23) > #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24) > #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \ > (((devfn) << 24) & ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK) > #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r) \ > - (PCIE_RC_RP_ATS_BASE + 0x0008 + ((r) & 0x1f) * 0x0020) > -#define ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r) \ > - (PCIE_RC_RP_ATS_BASE + 0x000c + ((r) & 0x1f) * 0x0020) > -#define ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(r) \ > - (PCIE_RC_RP_ATS_BASE + 0x0018 + ((r) & 0x1f) * 0x0020) > -#define ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(r) \ > - (PCIE_RC_RP_ATS_BASE + 0x001c + ((r) & 0x1f) * 0x0020) > + (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0008 + ((r) & 0x1f) * 0x0020) > +#define ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r) \ > + (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x000c + ((r) & 0x1f) * 0x0020) > +#define ROCKCHIP_PCIE_AT_OB_REGION_DESC2(r) \ > + (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0010 + ((r) & 0x1f) * 0x0020) > > #define ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG0(fn) \ > (PCIE_CORE_CTRL_MGMT_BASE + 0x0240 + (fn) * 0x0008)