2020-04-08 15:39:23

by Prabhakar Mahadev Lad

[permalink] [raw]
Subject: [PATCH v7 0/8] Add support for PCIe controller to work in endpoint mode on R-Car/RZ/G2x SoCs

Hi All,

This patch series adds support for PCIe controller on R-Car/RZ-G2x to work in
endpoint mode, this also extends the epf framework to handle base region
for mapping PCI address locally.

Note:
The cadence/rockchip/designware endpoint drivers are build tested only.

Changes for v7 (Respun this version quickly to ML as the changes requested
were quite small and it has been reviewed substantially):
* Fixed review comments pointed by Shimoda-san
1] Made DT bindings dual licensed, added Shimoda-san as maintainer and fixed
the example as its built with #{address,size}-cells = <1>. I have still
restored the Ack from Rob and Shimoda-san with these changes.
2] Split up the patches so that they can be picked up by respective subsystem
patches 1/4-9/11 are now part of this series.
3] Dropped altering a comment in pci-epc.h
4] Used a local variable align_size in pci_epc_mem_alloc_addr() so that size
variable doesn't get overwritten in the loop.
5] Replaced i-=1 with i--
6] Replaced rcar with R-Car in patch subject and description.
7] Set MACCTLR in init() callback

Changes for v6:
1] Rebased patches on endpoint branch of https://git.kernel.org/pub/
scm/linux/kernel/git/lpieralisi/pci.git/
2] Fixed review comments from Shimoda-san
a] Made sure defconfig changes were in separate patch
b] Created rcar_pcie_host/rcar_pcie_ep structures
c] Added pci-id for R8A774C0
d] Added entry in MAINTAINERS for dt-binding
e] Dropped unnecessary braces
3] Added support for msi.

Changes for v5:
1] Rebased patches on next branch of https://git.kernel.org/pub/scm/
linux/kernel/git/helgaas/pci.git
2] Fixed review comments reported by Kishon while fetching the matching
window in function pci_epc_get_matching_window()
3] Fixed review comments reported by Bjorn
a] Split patch up first patch so that its easier to review and incremental
b] Fixed typos
4] Included Reviewed tag from Rob for the dt-binding patch
5] Fixed issue reported by Nathan for assigning variable to itself

Changes for v4:
1] Fixed dtb_check error reported by Rob
2] Fixed review comments reported by Kishon
a] Dropped pci_epc_find_best_fit_window()
b] Fixed initializing mem ptr in __pci_epc_mem_init()
c] Dropped map_size from pci_epc_mem_window structure

Changes for v3:
1] Fixed review comments from Bjorn and Kishon.
3] Converted to DT schema

Changes for v2:
1] Fixed review comments from Biju for dt-bindings to include an example
for a tested platform.
2] Fixed review comments from Kishon to extend the features of outbound
regions in epf framework.
3] Added support to parse outbound-ranges in OF.


Lad Prabhakar (8):
PCI: rcar: Rename pcie-rcar.c to pcie-rcar-host.c
PCI: rcar: Move shareable code to a common file
PCI: rcar: Fix calculating mask for PCIEPAMR register
PCI: endpoint: Add support to handle multiple base for mapping
outbound memory
dt-bindings: PCI: rcar: Add bindings for R-Car PCIe endpoint
controller
PCI: rcar: Add support for R-Car PCIe controller in endpoint mode
PCI: Add Renesas R8A774C0 device ID
MAINTAINERS: Add file patterns for rcar PCI device tree bindings

.../devicetree/bindings/pci/rcar-pci-ep.yaml | 77 ++
MAINTAINERS | 1 +
drivers/pci/controller/Kconfig | 18 +
drivers/pci/controller/Makefile | 3 +-
.../pci/controller/cadence/pcie-cadence-ep.c | 3 +-
.../pci/controller/dwc/pcie-designware-ep.c | 16 +-
drivers/pci/controller/pcie-rcar-ep.c | 555 ++++++++
drivers/pci/controller/pcie-rcar-host.c | 1065 +++++++++++++++
drivers/pci/controller/pcie-rcar.c | 1206 +----------------
drivers/pci/controller/pcie-rcar.h | 140 ++
drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
drivers/pci/endpoint/pci-epc-mem.c | 196 ++-
include/linux/pci-epc.h | 37 +-
include/linux/pci_ids.h | 1 +
14 files changed, 2071 insertions(+), 1249 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml
create mode 100644 drivers/pci/controller/pcie-rcar-ep.c
create mode 100644 drivers/pci/controller/pcie-rcar-host.c
create mode 100644 drivers/pci/controller/pcie-rcar.h

--
2.20.1


2020-04-08 15:39:39

by Prabhakar Mahadev Lad

[permalink] [raw]
Subject: [PATCH v7 2/8] PCI: rcar: Move shareable code to a common file

This patch moves sharable code to common file pcie-rcar.c and the #defines
to pcie-rcar.h so that the common code can be reused with endpoint driver.
There are no functional changes with this patch for the host controller
driver.

Signed-off-by: Lad Prabhakar <[email protected]>
Reviewed-by: Yoshihiro Shimoda <[email protected]>
---
drivers/pci/controller/Makefile | 2 +-
drivers/pci/controller/pcie-rcar-host.c | 378 ++++++------------------
drivers/pci/controller/pcie-rcar.c | 116 ++++++++
drivers/pci/controller/pcie-rcar.h | 131 ++++++++
4 files changed, 345 insertions(+), 282 deletions(-)
create mode 100644 drivers/pci/controller/pcie-rcar.c
create mode 100644 drivers/pci/controller/pcie-rcar.h

diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index 9dbccb5b24e1..39802ee32946 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
-obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar-host.o
+obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar.o pcie-rcar-host.o
obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c
index 759c6542c5c8..f5740995dd96 100644
--- a/drivers/pci/controller/pcie-rcar-host.c
+++ b/drivers/pci/controller/pcie-rcar-host.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* PCIe driver for Renesas R-Car SoCs
- * Copyright (C) 2014 Renesas Electronics Europe Ltd
+ * Copyright (C) 2014-2020 Renesas Electronics Europe Ltd
*
* Based on:
* arch/sh/drivers/pci/pcie-sh7786.c
@@ -30,104 +30,7 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>

-#define PCIECAR 0x000010
-#define PCIECCTLR 0x000018
-#define CONFIG_SEND_ENABLE BIT(31)
-#define TYPE0 (0 << 8)
-#define TYPE1 BIT(8)
-#define PCIECDR 0x000020
-#define PCIEMSR 0x000028
-#define PCIEINTXR 0x000400
-#define PCIEPHYSR 0x0007f0
-#define PHYRDY BIT(0)
-#define PCIEMSITXR 0x000840
-
-/* Transfer control */
-#define PCIETCTLR 0x02000
-#define DL_DOWN BIT(3)
-#define CFINIT BIT(0)
-#define PCIETSTR 0x02004
-#define DATA_LINK_ACTIVE BIT(0)
-#define PCIEERRFR 0x02020
-#define UNSUPPORTED_REQUEST BIT(4)
-#define PCIEMSIFR 0x02044
-#define PCIEMSIALR 0x02048
-#define MSIFE BIT(0)
-#define PCIEMSIAUR 0x0204c
-#define PCIEMSIIER 0x02050
-
-/* root port address */
-#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
-
-/* local address reg & mask */
-#define PCIELAR(x) (0x02200 + ((x) * 0x20))
-#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
-#define LAM_PREFETCH BIT(3)
-#define LAM_64BIT BIT(2)
-#define LAR_ENABLE BIT(1)
-
-/* PCIe address reg & mask */
-#define PCIEPALR(x) (0x03400 + ((x) * 0x20))
-#define PCIEPAUR(x) (0x03404 + ((x) * 0x20))
-#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
-#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
-#define PAR_ENABLE BIT(31)
-#define IO_SPACE BIT(8)
-
-/* Configuration */
-#define PCICONF(x) (0x010000 + ((x) * 0x4))
-#define PMCAP(x) (0x010040 + ((x) * 0x4))
-#define EXPCAP(x) (0x010070 + ((x) * 0x4))
-#define VCCAP(x) (0x010100 + ((x) * 0x4))
-
-/* link layer */
-#define IDSETR1 0x011004
-#define TLCTLR 0x011048
-#define MACSR 0x011054
-#define SPCHGFIN BIT(4)
-#define SPCHGFAIL BIT(6)
-#define SPCHGSUC BIT(7)
-#define LINK_SPEED (0xf << 16)
-#define LINK_SPEED_2_5GTS (1 << 16)
-#define LINK_SPEED_5_0GTS (2 << 16)
-#define MACCTLR 0x011058
-#define MACCTLR_NFTS_MASK GENMASK(23, 16) /* The name is from SH7786 */
-#define SPEED_CHANGE BIT(24)
-#define SCRAMBLE_DISABLE BIT(27)
-#define LTSMDIS BIT(31)
-#define MACCTLR_INIT_VAL (LTSMDIS | MACCTLR_NFTS_MASK)
-#define PMSR 0x01105c
-#define MACS2R 0x011078
-#define MACCGSPSETR 0x011084
-#define SPCNGRSN BIT(31)
-
-/* R-Car H1 PHY */
-#define H1_PCIEPHYADRR 0x04000c
-#define WRITE_CMD BIT(16)
-#define PHY_ACK BIT(24)
-#define RATE_POS 12
-#define LANE_POS 8
-#define ADR_POS 0
-#define H1_PCIEPHYDOUTR 0x040014
-
-/* R-Car Gen2 PHY */
-#define GEN2_PCIEPHYADDR 0x780
-#define GEN2_PCIEPHYDATA 0x784
-#define GEN2_PCIEPHYCTRL 0x78c
-
-#define INT_PCI_MSI_NR 32
-
-#define RCONF(x) (PCICONF(0) + (x))
-#define RPMCAP(x) (PMCAP(0) + (x))
-#define REXPCAP(x) (EXPCAP(0) + (x))
-#define RVCCAP(x) (VCCAP(0) + (x))
-
-#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
-#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
-#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
-
-#define RCAR_PCI_MAX_RESOURCES 4
-#define MAX_NR_INBOUND_MAPS 6
+#include "pcie-rcar.h"

struct rcar_msi {
DECLARE_BITMAP(used, INT_PCI_MSI_NR);
@@ -145,42 +48,15 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip)
}

/* Structure representing the PCIe interface */
-struct rcar_pcie {
- struct device *dev;
+struct rcar_pcie_host {
+ struct rcar_pcie pcie;
struct phy *phy;
- void __iomem *base;
struct list_head resources;
int root_bus_nr;
struct clk *bus_clk;
struct rcar_msi msi;
};

-static void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val,
- unsigned int reg)
-{
- writel(val, pcie->base + reg);
-}
-
-static u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg)
-{
- return readl(pcie->base + reg);
-}
-
-enum {
- RCAR_PCI_ACCESS_READ,
- RCAR_PCI_ACCESS_WRITE,
-};
-
-static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data)
-{
- unsigned int shift = BITS_PER_BYTE * (where & 3);
- u32 val = rcar_pci_read_reg(pcie, where & ~3);
-
- val &= ~(mask << shift);
- val |= data << shift;
- rcar_pci_write_reg(pcie, val, where & ~3);
-}
-
static u32 rcar_read_conf(struct rcar_pcie *pcie, int where)
{
unsigned int shift = BITS_PER_BYTE * (where & 3);
@@ -190,10 +66,11 @@ static u32 rcar_read_conf(struct rcar_pcie *pcie, int where)
}

/* Serialization is provided by 'pci_lock' in drivers/pci/access.c */
-static int rcar_pcie_config_access(struct rcar_pcie *pcie,
+static int rcar_pcie_config_access(struct rcar_pcie_host *host,
unsigned char access_type, struct pci_bus *bus,
unsigned int devfn, int where, u32 *data)
{
+ struct rcar_pcie *pcie = &host->pcie;
unsigned int dev, func, reg, index;

dev = PCI_SLOT(devfn);
@@ -225,7 +102,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie,
} else {
/* Keep an eye out for changes to the root bus number */
if (pci_is_root_bus(bus) && (reg == PCI_PRIMARY_BUS))
- pcie->root_bus_nr = *data & 0xff;
+ host->root_bus_nr = *data & 0xff;

rcar_pci_write_reg(pcie, *data, PCICONF(index));
}
@@ -233,7 +110,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie,
return PCIBIOS_SUCCESSFUL;
}

- if (pcie->root_bus_nr < 0)
+ if (host->root_bus_nr < 0)
return PCIBIOS_DEVICE_NOT_FOUND;

/* Clear errors */
@@ -244,7 +121,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie,
PCIE_CONF_DEV(dev) | PCIE_CONF_FUNC(func) | reg, PCIECAR);

/* Enable the configuration access */
- if (bus->parent->number == pcie->root_bus_nr)
+ if (bus->parent->number == host->root_bus_nr)
rcar_pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE0, PCIECCTLR);
else
rcar_pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE1, PCIECCTLR);
@@ -272,10 +149,10 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie,
static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *val)
{
- struct rcar_pcie *pcie = bus->sysdata;
+ struct rcar_pcie_host *host = bus->sysdata;
int ret;

- ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ,
+ ret = rcar_pcie_config_access(host, RCAR_PCI_ACCESS_READ,
bus, devfn, where, val);
if (ret != PCIBIOS_SUCCESSFUL) {
*val = 0xffffffff;
@@ -297,12 +174,12 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 val)
{
- struct rcar_pcie *pcie = bus->sysdata;
+ struct rcar_pcie_host *host = bus->sysdata;
unsigned int shift;
u32 data;
int ret;

- ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ,
+ ret = rcar_pcie_config_access(host, RCAR_PCI_ACCESS_READ,
bus, devfn, where, &data);
if (ret != PCIBIOS_SUCCESSFUL)
return ret;
@@ -321,7 +198,7 @@ static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
} else
data = val;

- ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_WRITE,
+ ret = rcar_pcie_config_access(host, RCAR_PCI_ACCESS_WRITE,
bus, devfn, where, &data);

return ret;
@@ -332,48 +209,14 @@ static struct pci_ops rcar_pcie_ops = {
.write = rcar_pcie_write_conf,
};

-static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie,
- struct resource *res)
-{
- /* Setup PCIe address space mappings for each resource */
- resource_size_t size;
- resource_size_t res_start;
- u32 mask;
-
- rcar_pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win));
-
- /*
- * The PAMR mask is calculated in units of 128Bytes, which
- * keeps things pretty simple.
- */
- size = resource_size(res);
- mask = (roundup_pow_of_two(size) / SZ_128) - 1;
- rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win));
-
- if (res->flags & IORESOURCE_IO)
- res_start = pci_pio_to_address(res->start);
- else
- res_start = res->start;
-
- rcar_pci_write_reg(pcie, upper_32_bits(res_start), PCIEPAUR(win));
- rcar_pci_write_reg(pcie, lower_32_bits(res_start) & ~0x7F,
- PCIEPALR(win));
-
- /* First resource is for IO */
- mask = PAR_ENABLE;
- if (res->flags & IORESOURCE_IO)
- mask |= IO_SPACE;
-
- rcar_pci_write_reg(pcie, mask, PCIEPTCTLR(win));
-}
-
-static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pci)
+static int rcar_pcie_setup(struct list_head *resource,
+ struct rcar_pcie_host *host)
{
struct resource_entry *win;
int i = 0;

/* Setup PCI resources */
- resource_list_for_each_entry(win, &pci->resources) {
+ resource_list_for_each_entry(win, &host->resources) {
struct resource *res = win->res;

if (!res->flags)
@@ -382,11 +225,11 @@ static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pci)
switch (resource_type(res)) {
case IORESOURCE_IO:
case IORESOURCE_MEM:
- rcar_pcie_setup_window(i, pci, res);
+ rcar_pcie_set_outbound(&host->pcie, i, res);
i++;
break;
case IORESOURCE_BUS:
- pci->root_bus_nr = res->start;
+ host->root_bus_nr = res->start;
break;
default:
continue;
@@ -452,28 +295,29 @@ static void rcar_pcie_force_speedup(struct rcar_pcie *pcie)
(macsr & LINK_SPEED) == LINK_SPEED_5_0GTS ? "5" : "2.5");
}

-static int rcar_pcie_enable(struct rcar_pcie *pcie)
+static int rcar_pcie_enable(struct rcar_pcie_host *host)
{
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host);
+ struct rcar_pcie *pcie = &host->pcie;
struct device *dev = pcie->dev;
- struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
struct pci_bus *bus, *child;
int ret;

/* Try setting 5 GT/s link speed */
rcar_pcie_force_speedup(pcie);

- rcar_pcie_setup(&bridge->windows, pcie);
+ rcar_pcie_setup(&bridge->windows, host);

pci_add_flags(PCI_REASSIGN_ALL_BUS);

bridge->dev.parent = dev;
- bridge->sysdata = pcie;
- bridge->busnr = pcie->root_bus_nr;
+ bridge->sysdata = host;
+ bridge->busnr = host->root_bus_nr;
bridge->ops = &rcar_pcie_ops;
bridge->map_irq = of_irq_parse_and_map_pci;
bridge->swizzle_irq = pci_common_swizzle;
if (IS_ENABLED(CONFIG_PCI_MSI))
- bridge->msi = &pcie->msi.chip;
+ bridge->msi = &host->msi.chip;

ret = pci_scan_root_bus_bridge(bridge);
if (ret < 0)
@@ -535,35 +379,6 @@ static void phy_write_reg(struct rcar_pcie *pcie,
phy_wait_for_ack(pcie);
}

-static int rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie)
-{
- unsigned int timeout = 10;
-
- while (timeout--) {
- if (rcar_pci_read_reg(pcie, PCIEPHYSR) & PHYRDY)
- return 0;
-
- msleep(5);
- }
-
- return -ETIMEDOUT;
-}
-
-static int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
-{
- unsigned int timeout = 10000;
-
- while (timeout--) {
- if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
- return 0;
-
- udelay(5);
- cpu_relax();
- }
-
- return -ETIMEDOUT;
-}
-
static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
{
int err;
@@ -601,7 +416,7 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie)

/* Enable data link layer active state reporting */
rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), PCI_EXP_LNKCAP_DLLLARC,
- PCI_EXP_LNKCAP_DLLLARC);
+ PCI_EXP_LNKCAP_DLLLARC);

/* Write out the physical slot number = 0 */
rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
@@ -634,8 +449,10 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
return 0;
}

-static int rcar_pcie_phy_init_h1(struct rcar_pcie *pcie)
+static int rcar_pcie_phy_init_h1(struct rcar_pcie_host *host)
{
+ struct rcar_pcie *pcie = &host->pcie;
+
/* Initialize the phy */
phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191);
phy_write_reg(pcie, 1, 0x42, 0x1, 0x0EC34180);
@@ -657,8 +474,10 @@ static int rcar_pcie_phy_init_h1(struct rcar_pcie *pcie)
return 0;
}

-static int rcar_pcie_phy_init_gen2(struct rcar_pcie *pcie)
+static int rcar_pcie_phy_init_gen2(struct rcar_pcie_host *host)
{
+ struct rcar_pcie *pcie = &host->pcie;
+
/*
* These settings come from the R-Car Series, 2nd Generation User's
* Manual, section 50.3.1 (2) Initialization of the physical layer.
@@ -677,17 +496,17 @@ static int rcar_pcie_phy_init_gen2(struct rcar_pcie *pcie)
return 0;
}

-static int rcar_pcie_phy_init_gen3(struct rcar_pcie *pcie)
+static int rcar_pcie_phy_init_gen3(struct rcar_pcie_host *host)
{
int err;

- err = phy_init(pcie->phy);
+ err = phy_init(host->phy);
if (err)
return err;

- err = phy_power_on(pcie->phy);
+ err = phy_power_on(host->phy);
if (err)
- phy_exit(pcie->phy);
+ phy_exit(host->phy);

return err;
}
@@ -730,8 +549,9 @@ static void rcar_msi_free(struct rcar_msi *chip, unsigned long irq)

static irqreturn_t rcar_pcie_msi_irq(int irq, void *data)
{
- struct rcar_pcie *pcie = data;
- struct rcar_msi *msi = &pcie->msi;
+ struct rcar_pcie_host *host = data;
+ struct rcar_pcie *pcie = &host->pcie;
+ struct rcar_msi *msi = &host->msi;
struct device *dev = pcie->dev;
unsigned long reg;

@@ -770,7 +590,9 @@ static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
struct msi_desc *desc)
{
struct rcar_msi *msi = to_rcar_msi(chip);
- struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip);
+ struct rcar_pcie_host *host = container_of(chip, struct rcar_pcie_host,
+ msi.chip);
+ struct rcar_pcie *pcie = &host->pcie;
struct msi_msg msg;
unsigned int irq;
int hwirq;
@@ -799,8 +621,10 @@ static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
static int rcar_msi_setup_irqs(struct msi_controller *chip,
struct pci_dev *pdev, int nvec, int type)
{
- struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip);
struct rcar_msi *msi = to_rcar_msi(chip);
+ struct rcar_pcie_host *host = container_of(chip, struct rcar_pcie_host,
+ msi.chip);
+ struct rcar_pcie *pcie = &host->pcie;
struct msi_desc *desc;
struct msi_msg msg;
unsigned int irq;
@@ -877,9 +701,9 @@ static const struct irq_domain_ops msi_domain_ops = {
.map = rcar_msi_map,
};

-static void rcar_pcie_unmap_msi(struct rcar_pcie *pcie)
+static void rcar_pcie_unmap_msi(struct rcar_pcie_host *host)
{
- struct rcar_msi *msi = &pcie->msi;
+ struct rcar_msi *msi = &host->msi;
int i, irq;

for (i = 0; i < INT_PCI_MSI_NR; i++) {
@@ -891,10 +715,11 @@ static void rcar_pcie_unmap_msi(struct rcar_pcie *pcie)
irq_domain_remove(msi->domain);
}

-static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
+static int rcar_pcie_enable_msi(struct rcar_pcie_host *host)
{
+ struct rcar_pcie *pcie = &host->pcie;
struct device *dev = pcie->dev;
- struct rcar_msi *msi = &pcie->msi;
+ struct rcar_msi *msi = &host->msi;
phys_addr_t base;
int err, i;

@@ -918,7 +743,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
/* Two irqs are for MSI, but they are also used for non-MSI irqs */
err = devm_request_irq(dev, msi->irq1, rcar_pcie_msi_irq,
IRQF_SHARED | IRQF_NO_THREAD,
- rcar_msi_irq_chip.name, pcie);
+ rcar_msi_irq_chip.name, host);
if (err < 0) {
dev_err(dev, "failed to request IRQ: %d\n", err);
goto err;
@@ -926,7 +751,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)

err = devm_request_irq(dev, msi->irq2, rcar_pcie_msi_irq,
IRQF_SHARED | IRQF_NO_THREAD,
- rcar_msi_irq_chip.name, pcie);
+ rcar_msi_irq_chip.name, host);
if (err < 0) {
dev_err(dev, "failed to request IRQ: %d\n", err);
goto err;
@@ -949,13 +774,14 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
return 0;

err:
- rcar_pcie_unmap_msi(pcie);
+ rcar_pcie_unmap_msi(host);
return err;
}

-static void rcar_pcie_teardown_msi(struct rcar_pcie *pcie)
+static void rcar_pcie_teardown_msi(struct rcar_pcie_host *host)
{
- struct rcar_msi *msi = &pcie->msi;
+ struct rcar_pcie *pcie = &host->pcie;
+ struct rcar_msi *msi = &host->msi;

/* Disable all MSI interrupts */
rcar_pci_write_reg(pcie, 0, PCIEMSIIER);
@@ -965,18 +791,19 @@ static void rcar_pcie_teardown_msi(struct rcar_pcie *pcie)

free_pages(msi->pages, 0);

- rcar_pcie_unmap_msi(pcie);
+ rcar_pcie_unmap_msi(host);
}

-static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
+static int rcar_pcie_get_resources(struct rcar_pcie_host *host)
{
+ struct rcar_pcie *pcie = &host->pcie;
struct device *dev = pcie->dev;
struct resource res;
int err, i;

- pcie->phy = devm_phy_optional_get(dev, "pcie");
- if (IS_ERR(pcie->phy))
- return PTR_ERR(pcie->phy);
+ host->phy = devm_phy_optional_get(dev, "pcie");
+ if (IS_ERR(host->phy))
+ return PTR_ERR(host->phy);

err = of_address_to_resource(dev->of_node, 0, &res);
if (err)
@@ -986,10 +813,10 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
if (IS_ERR(pcie->base))
return PTR_ERR(pcie->base);

- pcie->bus_clk = devm_clk_get(dev, "pcie_bus");
- if (IS_ERR(pcie->bus_clk)) {
+ host->bus_clk = devm_clk_get(dev, "pcie_bus");
+ if (IS_ERR(host->bus_clk)) {
dev_err(dev, "cannot get pcie bus clock\n");
- return PTR_ERR(pcie->bus_clk);
+ return PTR_ERR(host->bus_clk);
}

i = irq_of_parse_and_map(dev->of_node, 0);
@@ -998,7 +825,7 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
err = -ENOENT;
goto err_irq1;
}
- pcie->msi.irq1 = i;
+ host->msi.irq1 = i;

i = irq_of_parse_and_map(dev->of_node, 1);
if (!i) {
@@ -1006,12 +833,12 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie)
err = -ENOENT;
goto err_irq2;
}
- pcie->msi.irq2 = i;
+ host->msi.irq2 = i;

return 0;

err_irq2:
- irq_dispose_mapping(pcie->msi.irq1);
+ irq_dispose_mapping(host->msi.irq1);
err_irq1:
return err;
}
@@ -1054,21 +881,8 @@ static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie,
mask = roundup_pow_of_two(size) - 1;
mask &= ~0xf;

- /*
- * Set up 64-bit inbound regions as the range parser doesn't
- * distinguish between 32 and 64-bit types.
- */
- rcar_pci_write_reg(pcie, lower_32_bits(pci_addr),
- PCIEPRAR(idx));
- rcar_pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx));
- rcar_pci_write_reg(pcie, lower_32_bits(mask) | flags,
- PCIELAMR(idx));
-
- rcar_pci_write_reg(pcie, upper_32_bits(pci_addr),
- PCIEPRAR(idx + 1));
- rcar_pci_write_reg(pcie, upper_32_bits(cpu_addr),
- PCIELAR(idx + 1));
- rcar_pci_write_reg(pcie, 0, PCIELAMR(idx + 1));
+ rcar_pcie_set_inbound(pcie, cpu_addr, pci_addr,
+ lower_32_bits(mask) | flags, idx, true);

pci_addr += size;
cpu_addr += size;
@@ -1079,14 +893,14 @@ static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie,
return 0;
}

-static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie)
+static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie_host *host)
{
- struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host);
struct resource_entry *entry;
int index = 0, err = 0;

resource_list_for_each_entry(entry, &bridge->dma_ranges) {
- err = rcar_pcie_inbound_ranges(pcie, entry, &index);
+ err = rcar_pcie_inbound_ranges(&host->pcie, entry, &index);
if (err)
break;
}
@@ -1113,22 +927,23 @@ static const struct of_device_id rcar_pcie_of_match[] = {
static int rcar_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct rcar_pcie_host *host;
struct rcar_pcie *pcie;
u32 data;
int err;
- int (*phy_init_fn)(struct rcar_pcie *);
+ int (*phy_init_fn)(struct rcar_pcie_host *);
struct pci_host_bridge *bridge;

- bridge = pci_alloc_host_bridge(sizeof(*pcie));
+ bridge = pci_alloc_host_bridge(sizeof(*host));
if (!bridge)
return -ENOMEM;

- pcie = pci_host_bridge_priv(bridge);
-
+ host = pci_host_bridge_priv(bridge);
+ pcie = &host->pcie;
pcie->dev = dev;
- platform_set_drvdata(pdev, pcie);
+ platform_set_drvdata(pdev, host);

- err = pci_parse_request_of_pci_ranges(dev, &pcie->resources,
+ err = pci_parse_request_of_pci_ranges(dev, &host->resources,
&bridge->dma_ranges, NULL);
if (err)
goto err_free_bridge;
@@ -1140,24 +955,24 @@ static int rcar_pcie_probe(struct platform_device *pdev)
goto err_pm_disable;
}

- err = rcar_pcie_get_resources(pcie);
+ err = rcar_pcie_get_resources(host);
if (err < 0) {
dev_err(dev, "failed to request resources: %d\n", err);
goto err_pm_put;
}

- err = clk_prepare_enable(pcie->bus_clk);
+ err = clk_prepare_enable(host->bus_clk);
if (err) {
dev_err(dev, "failed to enable bus clock: %d\n", err);
goto err_unmap_msi_irqs;
}

- err = rcar_pcie_parse_map_dma_ranges(pcie);
+ err = rcar_pcie_parse_map_dma_ranges(host);
if (err)
goto err_clk_disable;

phy_init_fn = of_device_get_match_data(dev);
- err = phy_init_fn(pcie);
+ err = phy_init_fn(host);
if (err) {
dev_err(dev, "failed to init PCIe PHY\n");
goto err_clk_disable;
@@ -1174,7 +989,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
dev_info(dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);

if (IS_ENABLED(CONFIG_PCI_MSI)) {
- err = rcar_pcie_enable_msi(pcie);
+ err = rcar_pcie_enable_msi(host);
if (err < 0) {
dev_err(dev,
"failed to enable MSI support: %d\n",
@@ -1183,7 +998,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
}
}

- err = rcar_pcie_enable(pcie);
+ err = rcar_pcie_enable(host);
if (err)
goto err_msi_teardown;

@@ -1191,27 +1006,27 @@ static int rcar_pcie_probe(struct platform_device *pdev)

err_msi_teardown:
if (IS_ENABLED(CONFIG_PCI_MSI))
- rcar_pcie_teardown_msi(pcie);
+ rcar_pcie_teardown_msi(host);

err_phy_shutdown:
- if (pcie->phy) {
- phy_power_off(pcie->phy);
- phy_exit(pcie->phy);
+ if (host->phy) {
+ phy_power_off(host->phy);
+ phy_exit(host->phy);
}

err_clk_disable:
- clk_disable_unprepare(pcie->bus_clk);
+ clk_disable_unprepare(host->bus_clk);

err_unmap_msi_irqs:
- irq_dispose_mapping(pcie->msi.irq2);
- irq_dispose_mapping(pcie->msi.irq1);
+ irq_dispose_mapping(host->msi.irq2);
+ irq_dispose_mapping(host->msi.irq1);

err_pm_put:
pm_runtime_put(dev);

err_pm_disable:
pm_runtime_disable(dev);
- pci_free_resource_list(&pcie->resources);
+ pci_free_resource_list(&host->resources);

err_free_bridge:
pci_free_host_bridge(bridge);
@@ -1221,7 +1036,8 @@ static int rcar_pcie_probe(struct platform_device *pdev)

static int rcar_pcie_resume_noirq(struct device *dev)
{
- struct rcar_pcie *pcie = dev_get_drvdata(dev);
+ struct rcar_pcie_host *host = dev_get_drvdata(dev);
+ struct rcar_pcie *pcie = &host->pcie;

if (rcar_pci_read_reg(pcie, PMSR) &&
!(rcar_pci_read_reg(pcie, PCIETCTLR) & DL_DOWN))
diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c
new file mode 100644
index 000000000000..b82f200985ec
--- /dev/null
+++ b/drivers/pci/controller/pcie-rcar.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe driver for Renesas R-Car SoCs
+ * Copyright (C) 2014-2020 Renesas Electronics Europe Ltd
+ *
+ * Author: Phil Edworthy <[email protected]>
+ */
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "pcie-rcar.h"
+
+void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, unsigned int reg)
+{
+ writel(val, pcie->base + reg);
+}
+
+u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg)
+{
+ return readl(pcie->base + reg);
+}
+
+void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data)
+{
+ unsigned int shift = BITS_PER_BYTE * (where & 3);
+ u32 val = rcar_pci_read_reg(pcie, where & ~3);
+
+ val &= ~(mask << shift);
+ val |= data << shift;
+ rcar_pci_write_reg(pcie, val, where & ~3);
+}
+
+int rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie)
+{
+ unsigned int timeout = 10;
+
+ while (timeout--) {
+ if (rcar_pci_read_reg(pcie, PCIEPHYSR) & PHYRDY)
+ return 0;
+
+ msleep(5);
+ }
+
+ return -ETIMEDOUT;
+}
+
+int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
+{
+ unsigned int timeout = 10000;
+
+ while (timeout--) {
+ if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
+ return 0;
+
+ udelay(5);
+ cpu_relax();
+ }
+
+ return -ETIMEDOUT;
+}
+
+void rcar_pcie_set_outbound(struct rcar_pcie *pcie, int win,
+ struct resource *res)
+{
+ /* Setup PCIe address space mappings for each resource */
+ resource_size_t res_start;
+ resource_size_t size;
+ u32 mask;
+
+ rcar_pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win));
+
+ /*
+ * The PAMR mask is calculated in units of 128Bytes, which
+ * keeps things pretty simple.
+ */
+ size = resource_size(res);
+ mask = (roundup_pow_of_two(size) / SZ_128) - 1;
+ rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win));
+
+ if (res->flags & IORESOURCE_IO)
+ res_start = pci_pio_to_address(res->start);
+ else
+ res_start = res->start;
+
+ rcar_pci_write_reg(pcie, upper_32_bits(res_start), PCIEPAUR(win));
+ rcar_pci_write_reg(pcie, lower_32_bits(res_start) & ~0x7F,
+ PCIEPALR(win));
+
+ /* First resource is for IO */
+ mask = PAR_ENABLE;
+ if (res->flags & IORESOURCE_IO)
+ mask |= IO_SPACE;
+
+ rcar_pci_write_reg(pcie, mask, PCIEPTCTLR(win));
+}
+
+void rcar_pcie_set_inbound(struct rcar_pcie *pcie, u64 cpu_addr,
+ u64 pci_addr, u64 flags, int idx, bool host)
+{
+ /*
+ * Set up 64-bit inbound regions as the range parser doesn't
+ * distinguish between 32 and 64-bit types.
+ */
+ if (host)
+ rcar_pci_write_reg(pcie, lower_32_bits(pci_addr),
+ PCIEPRAR(idx));
+ rcar_pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx));
+ rcar_pci_write_reg(pcie, flags, PCIELAMR(idx));
+
+ if (host)
+ rcar_pci_write_reg(pcie, upper_32_bits(pci_addr),
+ PCIEPRAR(idx + 1));
+ rcar_pci_write_reg(pcie, upper_32_bits(cpu_addr), PCIELAR(idx + 1));
+ rcar_pci_write_reg(pcie, 0, PCIELAMR(idx + 1));
+}
diff --git a/drivers/pci/controller/pcie-rcar.h b/drivers/pci/controller/pcie-rcar.h
new file mode 100644
index 000000000000..cec7768b4725
--- /dev/null
+++ b/drivers/pci/controller/pcie-rcar.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PCIe driver for Renesas R-Car SoCs
+ * Copyright (C) 2014-2020 Renesas Electronics Europe Ltd
+ *
+ * Author: Phil Edworthy <[email protected]>
+ */
+
+#ifndef _PCIE_RCAR_H
+#define _PCIE_RCAR_H
+
+#define PCIECAR 0x000010
+#define PCIECCTLR 0x000018
+#define CONFIG_SEND_ENABLE BIT(31)
+#define TYPE0 (0 << 8)
+#define TYPE1 BIT(8)
+#define PCIECDR 0x000020
+#define PCIEMSR 0x000028
+#define PCIEINTXR 0x000400
+#define PCIEPHYSR 0x0007f0
+#define PHYRDY BIT(0)
+#define PCIEMSITXR 0x000840
+
+/* Transfer control */
+#define PCIETCTLR 0x02000
+#define DL_DOWN BIT(3)
+#define CFINIT BIT(0)
+#define PCIETSTR 0x02004
+#define DATA_LINK_ACTIVE BIT(0)
+#define PCIEERRFR 0x02020
+#define UNSUPPORTED_REQUEST BIT(4)
+#define PCIEMSIFR 0x02044
+#define PCIEMSIALR 0x02048
+#define MSIFE BIT(0)
+#define PCIEMSIAUR 0x0204c
+#define PCIEMSIIER 0x02050
+
+/* root port address */
+#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
+
+/* local address reg & mask */
+#define PCIELAR(x) (0x02200 + ((x) * 0x20))
+#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
+#define LAM_PREFETCH BIT(3)
+#define LAM_64BIT BIT(2)
+#define LAR_ENABLE BIT(1)
+
+/* PCIe address reg & mask */
+#define PCIEPALR(x) (0x03400 + ((x) * 0x20))
+#define PCIEPAUR(x) (0x03404 + ((x) * 0x20))
+#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
+#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
+#define PAR_ENABLE BIT(31)
+#define IO_SPACE BIT(8)
+
+/* Configuration */
+#define PCICONF(x) (0x010000 + ((x) * 0x4))
+#define PMCAP(x) (0x010040 + ((x) * 0x4))
+#define EXPCAP(x) (0x010070 + ((x) * 0x4))
+#define VCCAP(x) (0x010100 + ((x) * 0x4))
+
+/* link layer */
+#define IDSETR1 0x011004
+#define TLCTLR 0x011048
+#define MACSR 0x011054
+#define SPCHGFIN BIT(4)
+#define SPCHGFAIL BIT(6)
+#define SPCHGSUC BIT(7)
+#define LINK_SPEED (0xf << 16)
+#define LINK_SPEED_2_5GTS (1 << 16)
+#define LINK_SPEED_5_0GTS (2 << 16)
+#define MACCTLR 0x011058
+#define MACCTLR_NFTS_MASK GENMASK(23, 16) /* The name is from SH7786 */
+#define SPEED_CHANGE BIT(24)
+#define SCRAMBLE_DISABLE BIT(27)
+#define LTSMDIS BIT(31)
+#define MACCTLR_INIT_VAL (LTSMDIS | MACCTLR_NFTS_MASK)
+#define PMSR 0x01105c
+#define MACS2R 0x011078
+#define MACCGSPSETR 0x011084
+#define SPCNGRSN BIT(31)
+
+/* R-Car H1 PHY */
+#define H1_PCIEPHYADRR 0x04000c
+#define WRITE_CMD BIT(16)
+#define PHY_ACK BIT(24)
+#define RATE_POS 12
+#define LANE_POS 8
+#define ADR_POS 0
+#define H1_PCIEPHYDOUTR 0x040014
+
+/* R-Car Gen2 PHY */
+#define GEN2_PCIEPHYADDR 0x780
+#define GEN2_PCIEPHYDATA 0x784
+#define GEN2_PCIEPHYCTRL 0x78c
+
+#define INT_PCI_MSI_NR 32
+
+#define RCONF(x) (PCICONF(0) + (x))
+#define RPMCAP(x) (PMCAP(0) + (x))
+#define REXPCAP(x) (EXPCAP(0) + (x))
+#define RVCCAP(x) (VCCAP(0) + (x))
+
+#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
+#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
+#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
+
+#define RCAR_PCI_MAX_RESOURCES 4
+#define MAX_NR_INBOUND_MAPS 6
+
+struct rcar_pcie {
+ struct device *dev;
+ void __iomem *base;
+};
+
+enum {
+ RCAR_PCI_ACCESS_READ,
+ RCAR_PCI_ACCESS_WRITE,
+};
+
+void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, unsigned int reg);
+u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg);
+void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data);
+int rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie);
+int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie);
+void rcar_pcie_set_outbound(struct rcar_pcie *pcie, int win,
+ struct resource *res);
+void rcar_pcie_set_inbound(struct rcar_pcie *pcie, u64 cpu_addr,
+ u64 pci_addr, u64 flags, int idx, bool host);
+
+#endif
--
2.20.1

2020-04-08 15:39:42

by Prabhakar Mahadev Lad

[permalink] [raw]
Subject: [PATCH v7 3/8] PCI: rcar: Fix calculating mask for PCIEPAMR register

The mask value was calculated incorrectly for PCIEPAMR register if the
size was less than 128 bytes. Fix this issue by adding a check on size.

Signed-off-by: Lad Prabhakar <[email protected]>
Reviewed-by: Yoshihiro Shimoda <[email protected]>
---
drivers/pci/controller/pcie-rcar.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c
index b82f200985ec..b46c69ac62f2 100644
--- a/drivers/pci/controller/pcie-rcar.c
+++ b/drivers/pci/controller/pcie-rcar.c
@@ -75,7 +75,10 @@ void rcar_pcie_set_outbound(struct rcar_pcie *pcie, int win,
* keeps things pretty simple.
*/
size = resource_size(res);
- mask = (roundup_pow_of_two(size) / SZ_128) - 1;
+ if (size > 128)
+ mask = (roundup_pow_of_two(size) / SZ_128) - 1;
+ else
+ mask = 0x0;
rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win));

if (res->flags & IORESOURCE_IO)
--
2.20.1

2020-04-08 15:39:56

by Prabhakar Mahadev Lad

[permalink] [raw]
Subject: [PATCH v7 4/8] PCI: endpoint: Add support to handle multiple base for mapping outbound memory

R-Car PCIe controller has support to map multiple memory regions for
mapping the outbound memory in local system also the controller limits
single allocation for each region (that is, once a chunk is used from the
region it cannot be used to allocate a new one). This features inspires to
add support for handling multiple memory bases in endpoint framework.

With this patch pci_epc_mem_init() initializes address space for endpoint
controller which support single window and whereas __pci_epc_mem_init()
now accepts pointer to multiple windows supported by endpoint controller.

Signed-off-by: Lad Prabhakar <[email protected]>
---
.../pci/controller/cadence/pcie-cadence-ep.c | 3 +-
.../pci/controller/dwc/pcie-designware-ep.c | 16 +-
drivers/pci/controller/pcie-rockchip-ep.c | 2 +-
drivers/pci/endpoint/pci-epc-mem.c | 196 ++++++++++++------
include/linux/pci-epc.h | 37 ++--
5 files changed, 174 insertions(+), 80 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 1c173dad67d1..d62eec6bbbbb 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -450,7 +450,8 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
epc->max_functions = 1;

ret = pci_epc_mem_init(epc, pcie->mem_res->start,
- resource_size(pcie->mem_res));
+ resource_size(pcie->mem_res),
+ PAGE_SIZE);
if (ret < 0) {
dev_err(dev, "failed to initialize the memory space\n");
goto err_init;
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 1cdcbd102ce8..a78902cbf2f0 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -412,11 +412,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
reg = ep->msi_cap + PCI_MSI_DATA_32;
msg_data = dw_pcie_readw_dbi(pci, reg);
}
- aligned_offset = msg_addr_lower & (epc->mem->page_size - 1);
+ aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1);
msg_addr = ((u64)msg_addr_upper) << 32 |
(msg_addr_lower & ~aligned_offset);
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
- epc->mem->page_size);
+ epc->mem->window.page_size);
if (ret)
return ret;

@@ -459,9 +459,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
return -EPERM;
}

- aligned_offset = msg_addr & (epc->mem->page_size - 1);
+ aligned_offset = msg_addr & (epc->mem->window.page_size - 1);
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
- epc->mem->page_size);
+ epc->mem->window.page_size);
if (ret)
return ret;

@@ -477,7 +477,7 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
struct pci_epc *epc = ep->epc;

pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
- epc->mem->page_size);
+ epc->mem->window.page_size);

pci_epc_mem_exit(epc);
}
@@ -610,15 +610,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
if (ret < 0)
epc->max_functions = 1;

- ret = __pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
- ep->page_size);
+ ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
+ ep->page_size);
if (ret < 0) {
dev_err(dev, "Failed to initialize address space\n");
return ret;
}

ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
- epc->mem->page_size);
+ epc->mem->window.page_size);
if (!ep->msi_mem) {
dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
return -ENOMEM;
diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
index d743b0a48988..5eaf36629a75 100644
--- a/drivers/pci/controller/pcie-rockchip-ep.c
+++ b/drivers/pci/controller/pcie-rockchip-ep.c
@@ -615,7 +615,7 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
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));
+ resource_size(rockchip->mem_res), PAGE_SIZE);
if (err < 0) {
dev_err(dev, "failed to initialize the memory space\n");
goto err_uninit_port;
diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c
index abfac1109a13..97b74937dc9e 100644
--- a/drivers/pci/endpoint/pci-epc-mem.c
+++ b/drivers/pci/endpoint/pci-epc-mem.c
@@ -23,7 +23,7 @@
static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
{
int order;
- unsigned int page_shift = ilog2(mem->page_size);
+ unsigned int page_shift = ilog2(mem->window.page_size);

size--;
size >>= page_shift;
@@ -38,61 +38,95 @@ static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
/**
* __pci_epc_mem_init() - initialize the pci_epc_mem structure
* @epc: the EPC device that invoked pci_epc_mem_init
- * @phys_base: the physical address of the base
- * @size: the size of the address space
- * @page_size: size of each page
+ * @windows: pointer to windows supported by the device
+ * @num_windows: number of windows device supports
*
* Invoke to initialize the pci_epc_mem structure used by the
* endpoint functions to allocate mapped PCI address.
*/
-int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size,
- size_t page_size)
+int __pci_epc_mem_init(struct pci_epc *epc, struct pci_epc_mem_window *windows,
+ unsigned int num_windows)
{
- int ret;
- struct pci_epc_mem *mem;
- unsigned long *bitmap;
+ struct pci_epc_mem *mem = NULL;
+ unsigned long *bitmap = NULL;
unsigned int page_shift;
- int pages;
+ size_t page_size;
int bitmap_size;
+ int pages;
+ int ret;
+ int i;

- if (page_size < PAGE_SIZE)
- page_size = PAGE_SIZE;
+ epc->num_windows = 0;

- page_shift = ilog2(page_size);
- pages = size >> page_shift;
- bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
+ if (!windows || !num_windows)
+ return -EINVAL;

- mem = kzalloc(sizeof(*mem), GFP_KERNEL);
- if (!mem) {
- ret = -ENOMEM;
- goto err;
- }
+ epc->windows = kcalloc(num_windows, sizeof(*mem), GFP_KERNEL);
+ if (!epc->windows)
+ return -ENOMEM;

- bitmap = kzalloc(bitmap_size, GFP_KERNEL);
- if (!bitmap) {
- ret = -ENOMEM;
- goto err_mem;
- }
+ for (i = 0; i < num_windows; i++) {
+ page_size = windows[i].page_size;
+ if (page_size < PAGE_SIZE)
+ page_size = PAGE_SIZE;
+ page_shift = ilog2(page_size);
+ pages = windows[i].size >> page_shift;
+ bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);

- mem->bitmap = bitmap;
- mem->phys_base = phys_base;
- mem->page_size = page_size;
- mem->pages = pages;
- mem->size = size;
- mutex_init(&mem->lock);
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ ret = -ENOMEM;
+ i--;
+ goto err_mem;
+ }
+
+ bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!bitmap) {
+ ret = -ENOMEM;
+ kfree(mem);
+ i--;
+ goto err_mem;
+ }
+
+ mem->window.phys_base = windows[i].phys_base;
+ mem->window.size = windows[i].size;
+ mem->window.page_size = page_size;
+ mem->bitmap = bitmap;
+ mem->pages = pages;
+ mutex_init(&mem->lock);
+ epc->windows[i] = mem;
+ }

- epc->mem = mem;
+ epc->mem = epc->windows[0];
+ epc->num_windows = num_windows;

return 0;

err_mem:
- kfree(mem);
+ for (; i >= 0; i--) {
+ mem = epc->windows[i];
+ kfree(mem->bitmap);
+ kfree(mem);
+ }
+ kfree(epc->windows);

-err:
-return ret;
+ return ret;
}
EXPORT_SYMBOL_GPL(__pci_epc_mem_init);

+int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base,
+ size_t size, size_t page_size)
+{
+ struct pci_epc_mem_window mem_window;
+
+ mem_window.phys_base = base;
+ mem_window.size = size;
+ mem_window.page_size = page_size;
+
+ return __pci_epc_mem_init(epc, &mem_window, 1);
+}
+EXPORT_SYMBOL_GPL(pci_epc_mem_init);
+
/**
* pci_epc_mem_exit() - cleanup the pci_epc_mem structure
* @epc: the EPC device that invoked pci_epc_mem_exit
@@ -102,11 +136,22 @@ EXPORT_SYMBOL_GPL(__pci_epc_mem_init);
*/
void pci_epc_mem_exit(struct pci_epc *epc)
{
- struct pci_epc_mem *mem = epc->mem;
+ struct pci_epc_mem *mem;
+ int i;
+
+ if (!epc->num_windows)
+ return;

+ for (i = 0; i <= epc->num_windows; i++) {
+ mem = epc->windows[i];
+ kfree(mem->bitmap);
+ kfree(mem);
+ }
+ kfree(epc->windows);
+
+ epc->windows = NULL;
epc->mem = NULL;
- kfree(mem->bitmap);
- kfree(mem);
+ epc->num_windows = 0;
}
EXPORT_SYMBOL_GPL(pci_epc_mem_exit);

@@ -122,31 +167,57 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
phys_addr_t *phys_addr, size_t size)
{
- int pageno;
void __iomem *virt_addr = NULL;
- struct pci_epc_mem *mem = epc->mem;
- unsigned int page_shift = ilog2(mem->page_size);
+ struct pci_epc_mem *mem;
+ unsigned int page_shift;
+ size_t align_size;
+ int pageno;
int order;
+ int i;

- size = ALIGN(size, mem->page_size);
- order = pci_epc_mem_get_order(mem, size);
-
- mutex_lock(&mem->lock);
- pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order);
- if (pageno < 0)
- goto ret;
+ for (i = 0; i < epc->num_windows; i++) {
+ mem = epc->windows[i];
+ mutex_lock(&mem->lock);
+ align_size = ALIGN(size, mem->window.page_size);
+ order = pci_epc_mem_get_order(mem, align_size);

- *phys_addr = mem->phys_base + ((phys_addr_t)pageno << page_shift);
- virt_addr = ioremap(*phys_addr, size);
- if (!virt_addr)
- bitmap_release_region(mem->bitmap, pageno, order);
+ pageno = bitmap_find_free_region(mem->bitmap, mem->pages,
+ order);
+ if (pageno >= 0) {
+ page_shift = ilog2(mem->window.page_size);
+ *phys_addr = mem->window.phys_base +
+ ((phys_addr_t)pageno << page_shift);
+ virt_addr = ioremap(*phys_addr, align_size);
+ if (!virt_addr)
+ bitmap_release_region(mem->bitmap,
+ pageno, order);
+ mutex_unlock(&mem->lock);
+ return virt_addr;
+ }
+ mutex_unlock(&mem->lock);
+ }

-ret:
- mutex_unlock(&mem->lock);
return virt_addr;
}
EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);

+struct pci_epc_mem *pci_epc_get_matching_window(struct pci_epc *epc,
+ phys_addr_t phys_addr)
+{
+ struct pci_epc_mem *mem;
+ int i;
+
+ for (i = 0; i < epc->num_windows; i++) {
+ mem = epc->windows[i];
+
+ if (phys_addr >= mem->window.phys_base &&
+ phys_addr < (mem->window.phys_base + mem->window.size))
+ return mem;
+ }
+
+ return NULL;
+}
+
/**
* pci_epc_mem_free_addr() - free the allocated memory address
* @epc: the EPC device on which memory was allocated
@@ -159,14 +230,23 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
void __iomem *virt_addr, size_t size)
{
+ struct pci_epc_mem *mem;
+ unsigned int page_shift;
+ size_t page_size;
int pageno;
- struct pci_epc_mem *mem = epc->mem;
- unsigned int page_shift = ilog2(mem->page_size);
int order;

+ mem = pci_epc_get_matching_window(epc, phys_addr);
+ if (!mem) {
+ pr_err("failed to get matching window\n");
+ return;
+ }
+
+ page_size = mem->window.page_size;
+ page_shift = ilog2(page_size);
iounmap(virt_addr);
- pageno = (phys_addr - mem->phys_base) >> page_shift;
- size = ALIGN(size, mem->page_size);
+ pageno = (phys_addr - mem->window.phys_base) >> page_shift;
+ size = ALIGN(size, page_size);
order = pci_epc_mem_get_order(mem, size);
mutex_lock(&mem->lock);
bitmap_release_region(mem->bitmap, pageno, order);
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index e0ed9d01f6e5..3cbc21e75442 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -65,20 +65,28 @@ struct pci_epc_ops {
struct module *owner;
};

+/**
+ * struct pci_epc_mem_window - address window of the endpoint controller
+ * @phys_base: physical base address of the PCI address window
+ * @size: the size of the PCI address window
+ * @page_size: size of each page
+ */
+struct pci_epc_mem_window {
+ phys_addr_t phys_base;
+ size_t size;
+ size_t page_size;
+};
+
/**
* struct pci_epc_mem - address space of the endpoint controller
- * @phys_base: physical base address of the PCI address space
- * @size: the size of the PCI address space
+ * @window: address window of the endpoint controller
* @bitmap: bitmap to manage the PCI address space
* @pages: number of bits representing the address region
- * @page_size: size of each page
* @lock: mutex to protect bitmap
*/
struct pci_epc_mem {
- phys_addr_t phys_base;
- size_t size;
+ struct pci_epc_mem_window window;
unsigned long *bitmap;
- size_t page_size;
int pages;
/* mutex to protect against concurrent access for memory allocation*/
struct mutex lock;
@@ -89,7 +97,11 @@ struct pci_epc_mem {
* @dev: PCI EPC device
* @pci_epf: list of endpoint functions present in this EPC device
* @ops: function pointers for performing endpoint operations
- * @mem: address space of the endpoint controller
+ * @windows: array of address space of the endpoint controller
+ * @mem: first window of the endpoint controller, which corresponds to
+ * default address space of the endpoint controller supporting
+ * single window.
+ * @num_windows: number of windows supported by device
* @max_functions: max number of functions that can be configured in this EPC
* @group: configfs group representing the PCI EPC device
* @lock: mutex to protect pci_epc ops
@@ -100,7 +112,9 @@ struct pci_epc {
struct device dev;
struct list_head pci_epf;
const struct pci_epc_ops *ops;
+ struct pci_epc_mem **windows;
struct pci_epc_mem *mem;
+ unsigned int num_windows;
u8 max_functions;
struct config_group *group;
/* mutex to protect against concurrent access of EP controller */
@@ -137,9 +151,6 @@ struct pci_epc_features {
#define devm_pci_epc_create(dev, ops) \
__devm_pci_epc_create((dev), (ops), THIS_MODULE)

-#define pci_epc_mem_init(epc, phys_addr, size) \
- __pci_epc_mem_init((epc), (phys_addr), (size), PAGE_SIZE)
-
static inline void epc_set_drvdata(struct pci_epc *epc, void *data)
{
dev_set_drvdata(&epc->dev, data);
@@ -195,8 +206,10 @@ unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
struct pci_epc *pci_epc_get(const char *epc_name);
void pci_epc_put(struct pci_epc *epc);

-int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size,
- size_t page_size);
+int __pci_epc_mem_init(struct pci_epc *epc, struct pci_epc_mem_window *window,
+ unsigned int num_windows);
+int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base,
+ size_t size, size_t page_size);
void pci_epc_mem_exit(struct pci_epc *epc);
void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
phys_addr_t *phys_addr, size_t size);
--
2.20.1

2020-04-08 15:40:28

by Prabhakar Mahadev Lad

[permalink] [raw]
Subject: [PATCH v7 7/8] PCI: Add Renesas R8A774C0 device ID

Add R8A774C0 device ID so that this can be used by
pci_endpoint_test driver.

Signed-off-by: Lad Prabhakar <[email protected]>
Reviewed-by: Yoshihiro Shimoda <[email protected]>
---
include/linux/pci_ids.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 1dfc4e1dcb94..9e957c18abeb 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2460,6 +2460,7 @@
#define PCI_DEVICE_ID_RENESAS_SH7763 0x0004
#define PCI_DEVICE_ID_RENESAS_SH7785 0x0007
#define PCI_DEVICE_ID_RENESAS_SH7786 0x0010
+#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d

#define PCI_VENDOR_ID_SOLARFLARE 0x1924
#define PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0 0x0703
--
2.20.1

2020-04-08 15:41:23

by Prabhakar Mahadev Lad

[permalink] [raw]
Subject: [PATCH v7 5/8] dt-bindings: PCI: rcar: Add bindings for R-Car PCIe endpoint controller

This patch adds the bindings for the R-Car PCIe endpoint driver.

Signed-off-by: Lad Prabhakar <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Reviewed-by: Yoshihiro Shimoda <[email protected]>
---
.../devicetree/bindings/pci/rcar-pci-ep.yaml | 77 +++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml

diff --git a/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml b/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml
new file mode 100644
index 000000000000..65d32ccba4b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2020 Renesas Electronics Europe GmbH - https://www.renesas.com/eu/en/
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/rcar-pci-ep.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas R-Car PCIe Endpoint
+
+maintainers:
+ - Lad Prabhakar <[email protected]>
+ - Yoshihiro Shimoda <[email protected]>
+
+properties:
+ compatible:
+ items:
+ - const: renesas,r8a774c0-pcie-ep
+ - const: renesas,rcar-gen3-pcie-ep
+
+ reg:
+ maxItems: 5
+
+ reg-names:
+ items:
+ - const: apb-base
+ - const: memory0
+ - const: memory1
+ - const: memory2
+ - const: memory3
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: pcie
+
+ max-functions:
+ minimum: 1
+ maximum: 6
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - resets
+ - power-domains
+ - clocks
+ - clock-names
+ - max-functions
+
+examples:
+ - |
+ #include <dt-bindings/clock/r8a774c0-cpg-mssr.h>
+ #include <dt-bindings/power/r8a774c0-sysc.h>
+
+ pcie0_ep: pcie-ep@fe000000 {
+ compatible = "renesas,r8a774c0-pcie-ep",
+ "renesas,rcar-gen3-pcie-ep";
+ reg = <0xfe000000 0x80000>,
+ <0xfe100000 0x100000>,
+ <0xfe200000 0x200000>,
+ <0x30000000 0x8000000>,
+ <0x38000000 0x8000000>;
+ reg-names = "apb-base", "memory0", "memory1", "memory2", "memory3";
+ resets = <&cpg 319>;
+ power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
+ clocks = <&cpg CPG_MOD 319>;
+ clock-names = "pcie";
+ max-functions = /bits/ 8 <1>;
+ };
--
2.20.1

2020-04-08 15:41:23

by Prabhakar Mahadev Lad

[permalink] [raw]
Subject: [PATCH v7 6/8] PCI: rcar: Add support for R-Car PCIe controller in endpoint mode

This patch adds support for R-Car PCIe controller to work in endpoint mode.

Signed-off-by: Lad Prabhakar <[email protected]>
---
drivers/pci/controller/Kconfig | 8 +
drivers/pci/controller/Makefile | 1 +
drivers/pci/controller/pcie-rcar-ep.c | 555 ++++++++++++++++++++++++++
drivers/pci/controller/pcie-rcar.h | 9 +
4 files changed, 573 insertions(+)
create mode 100644 drivers/pci/controller/pcie-rcar-ep.c

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index cfdc898450d0..1f9793467f6d 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -71,6 +71,14 @@ config PCIE_RCAR_HOST
Say Y here if you want PCIe controller support on R-Car SoCs in host
mode.

+config PCIE_RCAR_EP
+ bool "Renesas R-Car PCIe endpoint controller"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ depends on PCI_ENDPOINT
+ help
+ Say Y here if you want PCIe controller support on R-Car SoCs in
+ endpoint mode.
+
config PCI_HOST_COMMON
bool
select PCI_ECAM
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index 39802ee32946..741a5204aa5e 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar.o pcie-rcar-host.o
+obj-$(CONFIG_PCIE_RCAR_EP) += pcie-rcar.o pcie-rcar-ep.o
obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c
new file mode 100644
index 000000000000..751394b04af1
--- /dev/null
+++ b/drivers/pci/controller/pcie-rcar-ep.c
@@ -0,0 +1,555 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe endpoint driver for Renesas R-Car SoCs
+ * Copyright (c) 2020 Renesas Electronics Europe GmbH
+ *
+ * Author: Lad Prabhakar <[email protected]>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/pci-epc.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+#include "pcie-rcar.h"
+
+/* Structure representing the PCIe interface */
+struct rcar_pcie_endpoint {
+ struct rcar_pcie pcie;
+ phys_addr_t *ob_mapped_addr;
+ struct pci_epc_mem_window *ob_window;
+ u8 max_functions;
+ unsigned int bar_to_atu[MAX_NR_INBOUND_MAPS];
+ unsigned long *ib_window_map;
+ u32 num_ib_windows;
+ u32 num_ob_windows;
+};
+
+static void rcar_pcie_ep_hw_init(struct rcar_pcie *pcie)
+{
+ u32 val;
+
+ rcar_pci_write_reg(pcie, 0, PCIETCTLR);
+
+ /* Set endpoint mode */
+ rcar_pci_write_reg(pcie, 0, PCIEMSR);
+
+ /* Initialize default capabilities. */
+ rcar_rmw32(pcie, REXPCAP(0), 0xff, PCI_CAP_ID_EXP);
+ rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
+ PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ENDPOINT << 4);
+ rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
+ PCI_HEADER_TYPE_NORMAL);
+
+ /* Write out the physical slot number = 0 */
+ rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
+
+ val = rcar_pci_read_reg(pcie, EXPCAP(1));
+ /* device supports fixed 128 bytes MPSS */
+ val &= ~GENMASK(2, 0);
+ rcar_pci_write_reg(pcie, val, EXPCAP(1));
+
+ val = rcar_pci_read_reg(pcie, EXPCAP(2));
+ /* read requests size 128 bytes */
+ val &= ~GENMASK(14, 12);
+ /* payload size 128 bytes */
+ val &= ~GENMASK(7, 5);
+ rcar_pci_write_reg(pcie, val, EXPCAP(2));
+
+ /* Set target link speed to 5.0 GT/s */
+ rcar_rmw32(pcie, EXPCAP(12), PCI_EXP_LNKSTA_CLS,
+ PCI_EXP_LNKSTA_CLS_5_0GB);
+
+ /* Set the completion timer timeout to the maximum 50ms. */
+ rcar_rmw32(pcie, TLCTLR + 1, 0x3f, 50);
+
+ /* Terminate list of capabilities (Next Capability Offset=0) */
+ rcar_rmw32(pcie, RVCCAP(0), 0xfff00000, 0);
+
+ /* flush modifications */
+ wmb();
+}
+
+static int rcar_pcie_ep_get_window(struct rcar_pcie_endpoint *ep,
+ phys_addr_t addr)
+{
+ int i;
+
+ for (i = 0; i < ep->num_ob_windows; i++)
+ if (ep->ob_window[i].phys_base == addr)
+ return i;
+
+ return -EINVAL;
+}
+
+static int rcar_pcie_parse_outbound_ranges(struct rcar_pcie_endpoint *ep,
+ struct platform_device *pdev)
+{
+ struct rcar_pcie *pcie = &ep->pcie;
+ char outbound_name[10];
+ struct resource *res;
+ unsigned int i = 0;
+
+ ep->num_ob_windows = 0;
+ for (i = 0; i < RCAR_PCI_MAX_RESOURCES; i++) {
+ sprintf(outbound_name, "memory%u", i);
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM,
+ outbound_name);
+ if (!res) {
+ dev_err(pcie->dev, "missing outbound window %u\n", i);
+ return -EINVAL;
+ }
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res),
+ outbound_name)) {
+ dev_err(pcie->dev, "Cannot request memory region %s.\n",
+ outbound_name);
+ return -EIO;
+ }
+
+ ep->ob_window[i].phys_base = res->start;
+ ep->ob_window[i].size = resource_size(res);
+ /* controller doesn't support multiple allocation
+ * from same window, so set page_size to window size
+ */
+ ep->ob_window[i].page_size = resource_size(res);
+ }
+ ep->num_ob_windows = i;
+
+ return 0;
+}
+
+static int rcar_pcie_ep_get_pdata(struct rcar_pcie_endpoint *ep,
+ struct platform_device *pdev)
+{
+ struct rcar_pcie *pcie = &ep->pcie;
+ struct pci_epc_mem_window *window;
+ struct device *dev = pcie->dev;
+ struct resource res;
+ int err;
+
+ err = of_address_to_resource(dev->of_node, 0, &res);
+ if (err)
+ return err;
+ pcie->base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(pcie->base))
+ return PTR_ERR(pcie->base);
+
+ ep->ob_window = devm_kcalloc(dev, RCAR_PCI_MAX_RESOURCES,
+ sizeof(*window), GFP_KERNEL);
+ if (!ep->ob_window)
+ return -ENOMEM;
+
+ rcar_pcie_parse_outbound_ranges(ep, pdev);
+
+ err = of_property_read_u8(dev->of_node, "max-functions",
+ &ep->max_functions);
+ if (err < 0)
+ ep->max_functions = 1;
+
+ return 0;
+}
+
+static int rcar_pcie_ep_write_header(struct pci_epc *epc, u8 fn,
+ struct pci_epf_header *hdr)
+{
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+ struct rcar_pcie *pcie = &ep->pcie;
+ u32 val;
+
+ if (!fn)
+ val = hdr->vendorid;
+ else
+ val = rcar_pci_read_reg(pcie, IDSETR0);
+ val |= hdr->deviceid << 16;
+ rcar_pci_write_reg(pcie, val, IDSETR0);
+
+ val = hdr->revid;
+ val |= hdr->progif_code << 8;
+ val |= hdr->subclass_code << 16;
+ val |= hdr->baseclass_code << 24;
+ rcar_pci_write_reg(pcie, val, IDSETR1);
+
+ if (!fn)
+ val = hdr->subsys_vendor_id;
+ else
+ val = rcar_pci_read_reg(pcie, SUBIDSETR);
+ val |= hdr->subsys_id << 16;
+ rcar_pci_write_reg(pcie, val, SUBIDSETR);
+
+ if (hdr->interrupt_pin > PCI_INTERRUPT_INTA)
+ return -EINVAL;
+ val = rcar_pci_read_reg(pcie, PCICONF(15));
+ val |= (hdr->interrupt_pin << 8);
+ rcar_pci_write_reg(pcie, val, PCICONF(15));
+
+ return 0;
+}
+
+static int rcar_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
+ struct pci_epf_bar *epf_bar)
+{
+ int flags = epf_bar->flags | LAR_ENABLE | LAM_64BIT;
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+ u64 size = 1ULL << fls64(epf_bar->size - 1);
+ dma_addr_t cpu_addr = epf_bar->phys_addr;
+ enum pci_barno bar = epf_bar->barno;
+ struct rcar_pcie *pcie = &ep->pcie;
+ u32 mask;
+ int idx;
+ int err;
+
+ idx = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows);
+ if (idx >= ep->num_ib_windows) {
+ dev_err(pcie->dev, "no free inbound window\n");
+ return -EINVAL;
+ }
+
+ if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+ flags |= IO_SPACE;
+
+ ep->bar_to_atu[bar] = idx;
+ /* use 64 bit bars */
+ set_bit(idx, ep->ib_window_map);
+ set_bit(idx + 1, ep->ib_window_map);
+
+ if (cpu_addr > 0) {
+ unsigned long nr_zeros = __ffs64(cpu_addr);
+ u64 alignment = 1ULL << nr_zeros;
+
+ size = min(size, alignment);
+ }
+
+ size = min(size, 1ULL << 32);
+
+ mask = roundup_pow_of_two(size) - 1;
+ mask &= ~0xf;
+
+ rcar_pcie_set_inbound(pcie, cpu_addr,
+ 0x0, mask | flags, idx, false);
+
+ err = rcar_pcie_wait_for_phyrdy(pcie);
+ if (err) {
+ dev_err(pcie->dev, "phy not ready\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void rcar_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
+ struct pci_epf_bar *epf_bar)
+{
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+ enum pci_barno bar = epf_bar->barno;
+ u32 atu_index = ep->bar_to_atu[bar];
+
+ rcar_pcie_set_inbound(&ep->pcie, 0x0, 0x0, 0x0, bar, false);
+
+ clear_bit(atu_index, ep->ib_window_map);
+ clear_bit(atu_index + 1, ep->ib_window_map);
+}
+
+static int rcar_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 interrupts)
+{
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+ struct rcar_pcie *pcie = &ep->pcie;
+ u32 flags;
+
+ flags = rcar_pci_read_reg(pcie, MSICAP(fn));
+ flags |= interrupts << MSICAP0_MMESCAP_OFFSET;
+ rcar_pci_write_reg(pcie, flags, MSICAP(fn));
+
+ return 0;
+}
+
+static int rcar_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
+{
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+ struct rcar_pcie *pcie = &ep->pcie;
+ u32 flags;
+
+ flags = rcar_pci_read_reg(pcie, MSICAP(fn));
+ if (!(flags & MSICAP0_MSIE))
+ return -EINVAL;
+
+ return ((flags & MSICAP0_MMENUM_MASK) >> MSICAP0_MMENUM_OFFSET);
+}
+
+static int rcar_pcie_ep_map_addr(struct pci_epc *epc, u8 fn,
+ phys_addr_t addr, u64 pci_addr, size_t size)
+{
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+ struct rcar_pcie *pcie = &ep->pcie;
+ struct resource res;
+ int window;
+ int err;
+
+ /* check if we have a link. */
+ err = rcar_pcie_wait_for_dl(pcie);
+ if (err) {
+ dev_err(pcie->dev, "link not up\n");
+ return err;
+ }
+
+ window = rcar_pcie_ep_get_window(ep, addr);
+ if (window < 0) {
+ dev_err(pcie->dev, "failed to get corresponding window\n");
+ return -EINVAL;
+ }
+
+ memset(&res, 0x0, sizeof(res));
+ res.start = pci_addr;
+ res.end = pci_addr + size - 1;
+ res.flags = IORESOURCE_MEM;
+
+ rcar_pcie_set_outbound(pcie, window, &res);
+
+ ep->ob_mapped_addr[window] = addr;
+
+ return 0;
+}
+
+static void rcar_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn,
+ phys_addr_t addr)
+{
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+ struct resource res;
+ int idx;
+
+ for (idx = 0; idx < ep->num_ob_windows; idx++)
+ if (ep->ob_mapped_addr[idx] == addr)
+ break;
+
+ if (idx >= ep->num_ob_windows)
+ return;
+
+ memset(&res, 0x0, sizeof(res));
+ rcar_pcie_set_outbound(&ep->pcie, idx, &res);
+
+ ep->ob_mapped_addr[idx] = 0;
+}
+
+static int rcar_pcie_ep_assert_intx(struct rcar_pcie_endpoint *ep,
+ u8 fn, u8 intx)
+{
+ struct rcar_pcie *pcie = &ep->pcie;
+ u32 val;
+
+ val = rcar_pci_read_reg(pcie, PCIEMSITXR);
+ if ((val & PCI_MSI_FLAGS_ENABLE)) {
+ dev_err(pcie->dev, "MSI is enabled, cannot assert INTx\n");
+ return -EINVAL;
+ }
+
+ val = rcar_pci_read_reg(pcie, PCICONF(1));
+ if ((val & INTDIS)) {
+ dev_err(pcie->dev, "INTx message transmission is disabled\n");
+ return -EINVAL;
+ }
+
+ val = rcar_pci_read_reg(pcie, PCIEINTXR);
+ if ((val & ASTINTX)) {
+ dev_err(pcie->dev, "INTx is already asserted\n");
+ return -EINVAL;
+ }
+
+ val |= ASTINTX;
+ rcar_pci_write_reg(pcie, val, PCIEINTXR);
+ mdelay(1);
+ val = rcar_pci_read_reg(pcie, PCIEINTXR);
+ val &= ~ASTINTX;
+ rcar_pci_write_reg(pcie, val, PCIEINTXR);
+
+ return 0;
+}
+
+static int rcar_pcie_ep_assert_msi(struct rcar_pcie *pcie,
+ u8 fn, u8 interrupt_num)
+{
+ u16 msi_count;
+ u32 val;
+
+ /* Check MSI enable bit */
+ val = rcar_pci_read_reg(pcie, MSICAP(fn));
+ if (!(val & MSICAP0_MSIE))
+ return -EINVAL;
+
+ /* Get MSI numbers from MME */
+ msi_count = ((val & MSICAP0_MMENUM_MASK) >> MSICAP0_MMENUM_OFFSET);
+ msi_count = 1 << msi_count;
+
+ if (!interrupt_num || interrupt_num > msi_count)
+ return -EINVAL;
+
+ val = rcar_pci_read_reg(pcie, PCIEMSITXR);
+ rcar_pci_write_reg(pcie, val | (interrupt_num - 1), PCIEMSITXR);
+
+ return 0;
+}
+
+static int rcar_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
+ enum pci_epc_irq_type type,
+ u16 interrupt_num)
+{
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+
+ switch (type) {
+ case PCI_EPC_IRQ_LEGACY:
+ return rcar_pcie_ep_assert_intx(ep, fn, 0);
+
+ case PCI_EPC_IRQ_MSI:
+ return rcar_pcie_ep_assert_msi(&ep->pcie, fn, interrupt_num);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rcar_pcie_ep_start(struct pci_epc *epc)
+{
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+
+ rcar_pci_write_reg(&ep->pcie, MACCTLR_INIT_VAL, MACCTLR);
+ rcar_pci_write_reg(&ep->pcie, CFINIT, PCIETCTLR);
+
+ return 0;
+}
+
+static void rcar_pcie_ep_stop(struct pci_epc *epc)
+{
+ struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+
+ rcar_pci_write_reg(&ep->pcie, 0, PCIETCTLR);
+}
+
+static const struct pci_epc_features rcar_pcie_epc_features = {
+ .linkup_notifier = false,
+ .msi_capable = true,
+ .msix_capable = false,
+ /* use 64-bit bars so mark bar1/3/5 as reserved */
+ .reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5,
+ .bar_fixed_64bit = 1 << BAR_0 | 1 << BAR_2 | 1 << BAR_4,
+ .bar_fixed_size[0] = 128,
+ .bar_fixed_size[2] = 256,
+ .bar_fixed_size[4] = 256,
+};
+
+static const struct pci_epc_features*
+rcar_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
+{
+ return &rcar_pcie_epc_features;
+}
+
+static const struct pci_epc_ops rcar_pcie_epc_ops = {
+ .write_header = rcar_pcie_ep_write_header,
+ .set_bar = rcar_pcie_ep_set_bar,
+ .clear_bar = rcar_pcie_ep_clear_bar,
+ .set_msi = rcar_pcie_ep_set_msi,
+ .get_msi = rcar_pcie_ep_get_msi,
+ .map_addr = rcar_pcie_ep_map_addr,
+ .unmap_addr = rcar_pcie_ep_unmap_addr,
+ .raise_irq = rcar_pcie_ep_raise_irq,
+ .start = rcar_pcie_ep_start,
+ .stop = rcar_pcie_ep_stop,
+ .get_features = rcar_pcie_ep_get_features,
+};
+
+static const struct of_device_id rcar_pcie_ep_of_match[] = {
+ { .compatible = "renesas,r8a774c0-pcie-ep", },
+ { .compatible = "renesas,rcar-gen3-pcie-ep" },
+ { },
+};
+
+static int rcar_pcie_ep_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rcar_pcie_endpoint *ep;
+ struct rcar_pcie *pcie;
+ struct pci_epc *epc;
+ int err;
+
+ ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+ return -ENOMEM;
+
+ pcie = &ep->pcie;
+ pcie->dev = dev;
+
+ pm_runtime_enable(dev);
+ err = pm_runtime_get_sync(dev);
+ if (err < 0) {
+ dev_err(dev, "pm_runtime_get_sync failed\n");
+ goto err_pm_disable;
+ }
+
+ err = rcar_pcie_ep_get_pdata(ep, pdev);
+ if (err < 0) {
+ dev_err(dev, "failed to request resources: %d\n", err);
+ goto err_pm_put;
+ }
+
+ ep->num_ib_windows = MAX_NR_INBOUND_MAPS;
+ ep->ib_window_map =
+ devm_kcalloc(dev, BITS_TO_LONGS(ep->num_ib_windows),
+ sizeof(long), GFP_KERNEL);
+ if (!ep->ib_window_map) {
+ err = -ENOMEM;
+ dev_err(dev, "failed to allocate memory for inbound map\n");
+ goto err_pm_put;
+ }
+
+ ep->ob_mapped_addr = devm_kcalloc(dev, ep->num_ob_windows,
+ sizeof(*ep->ob_mapped_addr),
+ GFP_KERNEL);
+ if (!ep->ob_mapped_addr) {
+ err = -ENOMEM;
+ dev_err(dev, "failed to allocate memory for outbound memory pointers\n");
+ goto err_pm_put;
+ }
+
+ epc = devm_pci_epc_create(dev, &rcar_pcie_epc_ops);
+ if (IS_ERR(epc)) {
+ dev_err(dev, "failed to create epc device\n");
+ err = PTR_ERR(epc);
+ goto err_pm_put;
+ }
+
+ epc->max_functions = ep->max_functions;
+ epc_set_drvdata(epc, ep);
+
+ rcar_pcie_ep_hw_init(pcie);
+
+ err = __pci_epc_mem_init(epc, ep->ob_window, ep->num_ob_windows);
+ if (err < 0) {
+ dev_err(dev, "failed to initialize the epc memory space\n");
+ goto err_pm_put;
+ }
+
+ return 0;
+
+err_pm_put:
+ pm_runtime_put(dev);
+
+err_pm_disable:
+ pm_runtime_disable(dev);
+
+ return err;
+}
+
+static struct platform_driver rcar_pcie_ep_driver = {
+ .driver = {
+ .name = "rcar-pcie-ep",
+ .of_match_table = rcar_pcie_ep_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = rcar_pcie_ep_probe,
+};
+builtin_platform_driver(rcar_pcie_ep_driver);
diff --git a/drivers/pci/controller/pcie-rcar.h b/drivers/pci/controller/pcie-rcar.h
index cec7768b4725..0fbeff3d7b78 100644
--- a/drivers/pci/controller/pcie-rcar.h
+++ b/drivers/pci/controller/pcie-rcar.h
@@ -17,6 +17,7 @@
#define PCIECDR 0x000020
#define PCIEMSR 0x000028
#define PCIEINTXR 0x000400
+#define ASTINTX BIT(16)
#define PCIEPHYSR 0x0007f0
#define PHYRDY BIT(0)
#define PCIEMSITXR 0x000840
@@ -55,12 +56,20 @@

/* Configuration */
#define PCICONF(x) (0x010000 + ((x) * 0x4))
+#define INTDIS BIT(10)
#define PMCAP(x) (0x010040 + ((x) * 0x4))
+#define MSICAP(x) (0x010050 + ((x) * 0x4))
+#define MSICAP0_MSIE BIT(16)
+#define MSICAP0_MMESCAP_OFFSET 17
+#define MSICAP0_MMENUM_OFFSET 20
+#define MSICAP0_MMENUM_MASK GENMASK(22, 20)
#define EXPCAP(x) (0x010070 + ((x) * 0x4))
#define VCCAP(x) (0x010100 + ((x) * 0x4))

/* link layer */
+#define IDSETR0 0x011000
#define IDSETR1 0x011004
+#define SUBIDSETR 0x011024
#define TLCTLR 0x011048
#define MACSR 0x011054
#define SPCHGFIN BIT(4)
--
2.20.1

2020-04-08 18:12:29

by Prabhakar Mahadev Lad

[permalink] [raw]
Subject: [PATCH v7 1/8] PCI: rcar: Rename pcie-rcar.c to pcie-rcar-host.c

This commit renames pcie-rcar.c to pcie-rcar-host.c in preparation for
adding support for endpoint mode. CONFIG_PCIE_RCAR is kept so that arm64
defconfig change can be a separate patch.

With this patch both config options PCIE_RCAR and PCIE_RCAR_HOST will be
available but PCIE_RCAR internally selects PCIE_RCAR_HOST so that bisect
builds wont be affected.

Signed-off-by: Lad Prabhakar <[email protected]>
Reviewed-by: Yoshihiro Shimoda <[email protected]>
---
drivers/pci/controller/Kconfig | 10 ++++++++++
drivers/pci/controller/Makefile | 2 +-
.../pci/controller/{pcie-rcar.c => pcie-rcar-host.c} | 0
3 files changed, 11 insertions(+), 1 deletion(-)
rename drivers/pci/controller/{pcie-rcar.c => pcie-rcar-host.c} (100%)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index af0f0bc11917..cfdc898450d0 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -58,8 +58,18 @@ config PCIE_RCAR
bool "Renesas R-Car PCIe controller"
depends on ARCH_RENESAS || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN
+ select PCIE_RCAR_HOST
help
Say Y here if you want PCIe controller support on R-Car SoCs.
+ This option will be removed after arm64 defconfig is updated.
+
+config PCIE_RCAR_HOST
+ bool "Renesas R-Car PCIe host controller"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ depends on PCI_MSI_IRQ_DOMAIN
+ help
+ Say Y here if you want PCIe controller support on R-Car SoCs in host
+ mode.

config PCI_HOST_COMMON
bool
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index 158c59771824..9dbccb5b24e1 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
-obj-$(CONFIG_PCIE_RCAR) += pcie-rcar.o
+obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar-host.o
obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar-host.c
similarity index 100%
rename from drivers/pci/controller/pcie-rcar.c
rename to drivers/pci/controller/pcie-rcar-host.c
--
2.20.1

2020-04-08 18:13:21

by Prabhakar Mahadev Lad

[permalink] [raw]
Subject: [PATCH v7 8/8] MAINTAINERS: Add file patterns for rcar PCI device tree bindings

Add file pattern entry for rcar PCI devicetree binding, so that when
people run ./scripts/get_maintainer.pl the rcar PCI maintainers could also
be listed.

Signed-off-by: Lad Prabhakar <[email protected]>
Reviewed-by: Yoshihiro Shimoda <[email protected]>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 3f0f2ee2af32..87df2d31a54b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12933,6 +12933,7 @@ L: [email protected]
L: [email protected]
S: Maintained
F: drivers/pci/controller/*rcar*
+F: Documentation/devicetree/bindings/pci/*rcar*

PCI DRIVER FOR SAMSUNG EXYNOS
M: Jingoo Han <[email protected]>
--
2.20.1

2020-04-08 23:31:14

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v7 2/8] PCI: rcar: Move shareable code to a common file

On Wed, Apr 08, 2020 at 04:37:54PM +0100, Lad Prabhakar wrote:
> This patch moves sharable code to common file pcie-rcar.c and the #defines
> to pcie-rcar.h so that the common code can be reused with endpoint driver.
> There are no functional changes with this patch for the host controller
> driver.

s/This patch moves/Move/
s/sharable/shareable/

2020-04-08 23:48:40

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v7 4/8] PCI: endpoint: Add support to handle multiple base for mapping outbound memory

On Wed, Apr 08, 2020 at 04:37:56PM +0100, Lad Prabhakar wrote:
> R-Car PCIe controller has support to map multiple memory regions for
> mapping the outbound memory in local system also the controller limits
> single allocation for each region (that is, once a chunk is used from the
> region it cannot be used to allocate a new one). This features inspires to
> add support for handling multiple memory bases in endpoint framework.
>
> With this patch pci_epc_mem_init() initializes address space for endpoint
> controller which support single window and whereas __pci_epc_mem_init()
> now accepts pointer to multiple windows supported by endpoint controller.

Adding a double underscore prefix usually indicates an internal
function that skips some checking.

It doesn't seem like quite the right thing for this external interface
that adds functionality. Maybe the name could include something like
"multi"?

> Signed-off-by: Lad Prabhakar <[email protected]>

This needs an ack from Kishon, of course.

This patch seems like it does several things that could possibly be
split into separate patches?

- Change pci_epc_mem_init() interface to add page_size argument (the
only one that touches cadence & rockchip; it would be nice if this
were a tiny patch)

- Add struct pci_epc_mem_window

- Add a pci_epc_multi_mem_init() or similar, implement
pci_epc_mem_init() in terms of it (as you already do)

Bjorn

2020-04-08 23:52:26

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v7 6/8] PCI: rcar: Add support for R-Car PCIe controller in endpoint mode

Maybe:

PCI: rcar: Add endpoint mode support

so the important "endpoint mode" part is early and doesn't get chopped
off or wrapped. We already know it's PCIe and rcar-related.

On Wed, Apr 08, 2020 at 04:37:58PM +0100, Lad Prabhakar wrote:
> This patch adds support for R-Car PCIe controller to work in endpoint mode.

s/This patch adds/Add/

> +static int rcar_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
> + struct pci_epf_bar *epf_bar)
> +{
> + int flags = epf_bar->flags | LAR_ENABLE | LAM_64BIT;
> + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
> + u64 size = 1ULL << fls64(epf_bar->size - 1);
> + dma_addr_t cpu_addr = epf_bar->phys_addr;
> + enum pci_barno bar = epf_bar->barno;
> + struct rcar_pcie *pcie = &ep->pcie;
> + u32 mask;
> + int idx;
> + int err;
> +
> + idx = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows);
> + if (idx >= ep->num_ib_windows) {
> + dev_err(pcie->dev, "no free inbound window\n");
> + return -EINVAL;
> + }
> +
> + if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
> + flags |= IO_SPACE;
> +
> + ep->bar_to_atu[bar] = idx;
> + /* use 64 bit bars */

s/64 bit bars/64-bit BARs/

> +static const struct pci_epc_features rcar_pcie_epc_features = {
> + .linkup_notifier = false,
> + .msi_capable = true,
> + .msix_capable = false,
> + /* use 64-bit bars so mark bar1/3/5 as reserved */

s/bar/BAR/g

2020-04-08 23:54:21

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v7 7/8] PCI: Add Renesas R8A774C0 device ID

On Wed, Apr 08, 2020 at 04:37:59PM +0100, Lad Prabhakar wrote:
> Add R8A774C0 device ID so that this can be used by
> pci_endpoint_test driver.
>
> Signed-off-by: Lad Prabhakar <[email protected]>
> Reviewed-by: Yoshihiro Shimoda <[email protected]>
> ---
> include/linux/pci_ids.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> index 1dfc4e1dcb94..9e957c18abeb 100644
> --- a/include/linux/pci_ids.h
> +++ b/include/linux/pci_ids.h
> @@ -2460,6 +2460,7 @@
> #define PCI_DEVICE_ID_RENESAS_SH7763 0x0004
> #define PCI_DEVICE_ID_RENESAS_SH7785 0x0007
> #define PCI_DEVICE_ID_RENESAS_SH7786 0x0010
> +#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d

We don't add device IDs here anymore unless they're used in more than
one place (see the comment at the top of the file). This series
doesn't use it at all, so please move this patch to the series that
adds multiple uses of this ID.

> #define PCI_VENDOR_ID_SOLARFLARE 0x1924
> #define PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0 0x0703
> --
> 2.20.1
>

2020-04-09 09:37:09

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH v7 7/8] PCI: Add Renesas R8A774C0 device ID

Hello!

On 08.04.2020 18:37, Lad Prabhakar wrote:

> Add R8A774C0 device ID so that this can be used by
> pci_endpoint_test driver.
>
> Signed-off-by: Lad Prabhakar <[email protected]>
> Reviewed-by: Yoshihiro Shimoda <[email protected]>
> ---
> include/linux/pci_ids.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> index 1dfc4e1dcb94..9e957c18abeb 100644
> --- a/include/linux/pci_ids.h
> +++ b/include/linux/pci_ids.h
> @@ -2460,6 +2460,7 @@
> #define PCI_DEVICE_ID_RENESAS_SH7763 0x0004
> #define PCI_DEVICE_ID_RENESAS_SH7785 0x0007
> #define PCI_DEVICE_ID_RENESAS_SH7786 0x0010
> +#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d

We don't add the device IDs in this file, unless used in several places.
Is it?

[...]

MBR, Sergei

2020-04-09 10:06:11

by Lad, Prabhakar

[permalink] [raw]
Subject: Re: [PATCH v7 7/8] PCI: Add Renesas R8A774C0 device ID

Hi Sergei and Bjorn,

On Thu, Apr 9, 2020 at 10:36 AM Sergei Shtylyov
<[email protected]> wrote:
>
> Hello!
>
> On 08.04.2020 18:37, Lad Prabhakar wrote:
>
> > Add R8A774C0 device ID so that this can be used by
> > pci_endpoint_test driver.
> >
> > Signed-off-by: Lad Prabhakar <[email protected]>
> > Reviewed-by: Yoshihiro Shimoda <[email protected]>
> > ---
> > include/linux/pci_ids.h | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> > index 1dfc4e1dcb94..9e957c18abeb 100644
> > --- a/include/linux/pci_ids.h
> > +++ b/include/linux/pci_ids.h
> > @@ -2460,6 +2460,7 @@
> > #define PCI_DEVICE_ID_RENESAS_SH7763 0x0004
> > #define PCI_DEVICE_ID_RENESAS_SH7785 0x0007
> > #define PCI_DEVICE_ID_RENESAS_SH7786 0x0010
> > +#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d
>
> We don't add the device IDs in this file, unless used in several places.
> Is it?
>
My bad I should have checked it before making this change actually it
was suggested in my previous version of the series but anyway atm this
was planned to be used only in pci_endpoint_test driver, so in that
case Ill drop this patch.

Cheers,
--Prabhakar

> [...]
>
> MBR, Sergei

2020-04-09 10:07:29

by Lad, Prabhakar

[permalink] [raw]
Subject: Re: [PATCH v7 2/8] PCI: rcar: Move shareable code to a common file

Hi Bjorn,

Thank you for the review.

On Thu, Apr 9, 2020 at 12:30 AM Bjorn Helgaas <[email protected]> wrote:
>
> On Wed, Apr 08, 2020 at 04:37:54PM +0100, Lad Prabhakar wrote:
> > This patch moves sharable code to common file pcie-rcar.c and the #defines
> > to pcie-rcar.h so that the common code can be reused with endpoint driver.
> > There are no functional changes with this patch for the host controller
> > driver.
>
> s/This patch moves/Move/
> s/sharable/shareable/

My bad shall replace it.

Cheers,
--Prabhakar

2020-04-09 10:14:21

by Lad, Prabhakar

[permalink] [raw]
Subject: Re: [PATCH v7 4/8] PCI: endpoint: Add support to handle multiple base for mapping outbound memory

Hi Bjorn,

Thank you for the review.

On Thu, Apr 9, 2020 at 12:46 AM Bjorn Helgaas <[email protected]> wrote:
>
> On Wed, Apr 08, 2020 at 04:37:56PM +0100, Lad Prabhakar wrote:
> > R-Car PCIe controller has support to map multiple memory regions for
> > mapping the outbound memory in local system also the controller limits
> > single allocation for each region (that is, once a chunk is used from the
> > region it cannot be used to allocate a new one). This features inspires to
> > add support for handling multiple memory bases in endpoint framework.
> >
> > With this patch pci_epc_mem_init() initializes address space for endpoint
> > controller which support single window and whereas __pci_epc_mem_init()
> > now accepts pointer to multiple windows supported by endpoint controller.
>
> Adding a double underscore prefix usually indicates an internal
> function that skips some checking.
>
> It doesn't seem like quite the right thing for this external interface
> that adds functionality. Maybe the name could include something like
> "multi"?
>
Agreed. how about pci_epc_mem_multi_init() ?

> > Signed-off-by: Lad Prabhakar <[email protected]>
>
> This needs an ack from Kishon, of course.
>
Yes waiting for Kishon to review it.

> This patch seems like it does several things that could possibly be
> split into separate patches?
>
> - Change pci_epc_mem_init() interface to add page_size argument (the
> only one that touches cadence & rockchip; it would be nice if this
> were a tiny patch)
>
Can be done.

> - Add struct pci_epc_mem_window
>
> - Add a pci_epc_multi_mem_init() or similar, implement
> pci_epc_mem_init() in terms of it (as you already do)
>
The above two needs to be single patch. Is that OK with you ?

Cheers,
--Prabhakar

2020-04-09 10:16:18

by Lad, Prabhakar

[permalink] [raw]
Subject: Re: [PATCH v7 6/8] PCI: rcar: Add support for R-Car PCIe controller in endpoint mode

Hi Bjorn,

Thank you for the review.

On Thu, Apr 9, 2020 at 12:51 AM Bjorn Helgaas <[email protected]> wrote:
>
> Maybe:
>
> PCI: rcar: Add endpoint mode support
>
> so the important "endpoint mode" part is early and doesn't get chopped
> off or wrapped. We already know it's PCIe and rcar-related.
>
Agreed will change it.

> On Wed, Apr 08, 2020 at 04:37:58PM +0100, Lad Prabhakar wrote:
> > This patch adds support for R-Car PCIe controller to work in endpoint mode.
>
> s/This patch adds/Add/
>
OK

> > +static int rcar_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
> > + struct pci_epf_bar *epf_bar)
> > +{
> > + int flags = epf_bar->flags | LAR_ENABLE | LAM_64BIT;
> > + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
> > + u64 size = 1ULL << fls64(epf_bar->size - 1);
> > + dma_addr_t cpu_addr = epf_bar->phys_addr;
> > + enum pci_barno bar = epf_bar->barno;
> > + struct rcar_pcie *pcie = &ep->pcie;
> > + u32 mask;
> > + int idx;
> > + int err;
> > +
> > + idx = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows);
> > + if (idx >= ep->num_ib_windows) {
> > + dev_err(pcie->dev, "no free inbound window\n");
> > + return -EINVAL;
> > + }
> > +
> > + if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
> > + flags |= IO_SPACE;
> > +
> > + ep->bar_to_atu[bar] = idx;
> > + /* use 64 bit bars */
>
> s/64 bit bars/64-bit BARs/
>
OK shall replace it.

> > +static const struct pci_epc_features rcar_pcie_epc_features = {
> > + .linkup_notifier = false,
> > + .msi_capable = true,
> > + .msix_capable = false,
> > + /* use 64-bit bars so mark bar1/3/5 as reserved */
>
> s/bar/BAR/g
OK shall replace it.

Cheers,
--Prabhakar

2020-04-10 00:41:53

by Yoshihiro Shimoda

[permalink] [raw]
Subject: RE: [PATCH v7 7/8] PCI: Add Renesas R8A774C0 device ID

Hi Prabhakar, Sergei, Bjorn,

> From: Lad, Prabhakar, Sent: Thursday, April 9, 2020 7:05 PM
<snip>
> > > diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> > > index 1dfc4e1dcb94..9e957c18abeb 100644
> > > --- a/include/linux/pci_ids.h
> > > +++ b/include/linux/pci_ids.h
> > > @@ -2460,6 +2460,7 @@
> > > #define PCI_DEVICE_ID_RENESAS_SH7763 0x0004
> > > #define PCI_DEVICE_ID_RENESAS_SH7785 0x0007
> > > #define PCI_DEVICE_ID_RENESAS_SH7786 0x0010
> > > +#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d
> >
> > We don't add the device IDs in this file, unless used in several places.
> > Is it?
> >
> My bad I should have checked it before making this change actually it
> was suggested in my previous version of the series but anyway atm this
> was planned to be used only in pci_endpoint_test driver, so in that
> case Ill drop this patch.

I'm very sorry, this is my fault. I suggested this but I didn't check
this pci_ids.h's rule...

Best regards,
Yoshihiro Shimoda