This patchset final purpose is add PCIe driver for StarFive JH7110 SoC.
JH7110 using PLDA XpressRICH PCIe IP. Microchip PolarFire Using the
same IP and have commit their codes, which are mixed with PLDA
controller codes and Microchip platform codes.
For re-use the PLDA controller codes, I request refactoring microchip
codes, move PLDA common codes to PLDA files.
Desigware and Cadence is good example for refactoring codes.
----------------------------------------------------------
The refactoring patches total number is 16,(patch 1-16)
which do NOT contain changing logic of codes.
These patches just contain three type basic operations.
(rename, modify codes to support starfive platform, and moving to common file)
If these patched are all be reviewed. They can be accepted first.
Refactoring patches can be devided to different groups
1. (patch 1- 3 is the prepare work of refactoring)
patch1 is move PLDA XpressRICH PCIe host common properties dt-binding
docs from microchip,pcie-host.yaml
patch2 is move PolarFire codes to PLDA directory.
patch3 is move PLDA IP register macros to plda-pcie.h
2. (patch4 - 6 is processing and re-use PCIe host instance)
patch4 is add bridge_addr field to PCIe host instance.
patch5 is rename data structure in microchip codes.
patch6 is moving two data structures to head file
3. (patch 7 - 9 are for re-use two PCIe setup function)
patch7 is rename two setup functions in microchip codes, prepare to move
to common file.
patch8 is change the arguments of plda_pcie_setup_iomems()
patch9 is move the two setup functions to common file pcie-plda-host.c
4.(patch 10 - 16 are for re-use interupt processing codes)
patch10 is rename the IRQ related functions, prepare to move to
pcie-plda-host.c
patch 11 - 15 is modify the interrupt event codes, preparing for support starfive
and microchip two platforms.
patch16 is move IRQ related functions to pcie-plda-host.c
------------------------------------------------------------
The remainder patches (patch 17 -21) are not refactoring patch.
They are for adding StarFive codes and dont modify the microchip's
codes.
patch17 is Add host init/deinit functions.
patch18 is add StarFive JH7110 PCIe dt-binding doc.
patch19 is Add a PCIe delay time macro
patch20 is add StarFive JH7110 Soc PCIe codes.
patch21 is Starfive dts config
This patchset is base on v6.7-rc4
previous version:
v6:https://patchwork.kernel.org/project/linux-pci/cover/[email protected]/
v7:https://patchwork.kernel.org/project/linux-pci/cover/[email protected]/
v8:https://patchwork.kernel.org/project/linux-pci/cover/[email protected]/
v9:https://patchwork.kernel.org/project/linux-pci/cover/[email protected]/
v10:https://patchwork.kernel.org/project/linux-pci/cover/[email protected]/
v11:https://patchwork.kernel.org/project/linux-pci/cover/[email protected]/
v12:https://patchwork.kernel.org/project/linux-pci/cover/[email protected]/
change:
v13:
patch14: 1. Add plda_get_event() function. This can be compare with mc_get_event() easily and
track the codes changes in case in the future..
2. The host event_ops is directly set to plda host port.
3. Setting default host event_ops instead of checking event ops.
patch15:1. Add PLDA event irq_chip instead of event_domain_ops, The
event_domain_ops can be re-used.
2. The host event irq_chip is directly set to plda host port.
3. Add PLDA event irqchip ops codes.
4. Remove Conor's review tag due to whole patch have been changed.
patch16: Also move the new added PLDA event codes.
patch17: Add plda host init and deinit function only.
v12:
patch17: modify the commit message and add starfive review tag.
Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS to patch 19.
patch20: Add disable runtime pm function in starfive_pcie_remove()
Add "depens on ARCH_STARFIVE || COMPILE_TEST" in Starfive PCie Kconfig
v11:
check and modify some commit messages again.
All the codes are the same with v10.
v10:
All the commit message set to fit in 75 columns.
All the codes fit in less than 80 colunms.
patch 14:
Commit message changes suggested by Conor.
patch 20:
Add 100 ms delay macro to pci.h
generic phy pointer related codes moving to pcie-starfive.c
This patch Change pcie-starfive only, bus_ops move to patch 16.
Some Codes changes suggested by Bjorn.
v9:
v8 patch 10 squash to v9 patch 12, v8 patch 18 squash to v9 patch 16.
patch 4 - 16: Add new review tags and add more accurate commit messages.
patch 17: move the plda_pcie_host_init/deinit from patch 19. Make
plda driver become to whole driver.
v8:
The patch description in cover-letter has been changed.
v7 patch 4 split to v8 patch 4 - 6.
(It is patches about re-use pcie host data structure, new patches just contain one
function modification. It is more reguluar and easier to review).
patch 7- 9: modify the commit messages and add reason of
modifcation.
patch10- 16 :
Add review tag and add more commit messages to declear the
reason of modifying the codes.
patch17: plda_handle_events() using bit mask macro. The function are
easier to read.
v7:
patch17: fix the build warning.
patch20: Some format changes (Emil's comment)
patch21: change the pcie node sequences by alphabetical
delete the "interupt-parent" in pcie node.
v6:
v5 patch 4 split to patch 4 -9. New patches just contain one function modification. It is more reguluar.
patch 9: Just move the two setup functions only
patch 19 : draw a graph of PLDA local register, make it easier to
review the codes.
v5 patch 7 split to patch 10- 16. Each patch just contain one
function modification. It is more regular.
patch 10: rename IRQ related functions.
patch 11 - 15 : modify the events codes, total five patch.
patch 16: move IRQ related functions to pcie-plda-host.c
patch 20- 21 using "linux,pci-domain" dts setting.
Kevin Xie (1):
PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time value
Minda Chen (20):
dt-bindings: PCI: Add PLDA XpressRICH PCIe host common properties
PCI: microchip: Move pcie-microchip-host.c to plda directory
PCI: microchip: Move PLDA IP register macros to pcie-plda.h
PCI: microchip: Add bridge_addr field to struct mc_pcie
PCI: microchip: Rename two PCIe data structures
PCI: microchip: Move PCIe host data structures to plda-pcie.h
PCI: microchip: Rename two setup functions
PCI: microchip: Change the argument of plda_pcie_setup_iomems()
PCI: microchip: Move setup functions to pcie-plda-host.c
PCI: microchip: Rename interrupt related functions
PCI: microchip: Add num_events field to struct plda_pcie_rp
PCI: microchip: Add request_event_irq() callback function
PCI: microchip: Add INTx and MSI event num to struct plda_event
PCI: microchip: Add get_events() callback and add PLDA get_event()
PCI: microchip: Add event irqchip field to host port and add PLDA
irqchip
PCI: microchip: Move IRQ functions to pcie-plda-host.c
PCI: plda: Add host init/deinit and map bus functions
dt-bindings: PCI: Add StarFive JH7110 PCIe controller
PCI: starfive: Add JH7110 PCIe controller
riscv: dts: starfive: add PCIe dts configuration for JH7110
.../bindings/pci/microchip,pcie-host.yaml | 55 +-
.../pci/plda,xpressrich3-axi-common.yaml | 75 ++
.../bindings/pci/starfive,jh7110-pcie.yaml | 120 ++++
MAINTAINERS | 19 +-
.../jh7110-starfive-visionfive-2.dtsi | 64 ++
arch/riscv/boot/dts/starfive/jh7110.dtsi | 86 +++
drivers/pci/controller/Kconfig | 9 +-
drivers/pci/controller/Makefile | 2 +-
drivers/pci/controller/plda/Kconfig | 30 +
drivers/pci/controller/plda/Makefile | 4 +
.../{ => plda}/pcie-microchip-host.c | 614 ++--------------
drivers/pci/controller/plda/pcie-plda-host.c | 656 ++++++++++++++++++
drivers/pci/controller/plda/pcie-plda.h | 265 +++++++
drivers/pci/controller/plda/pcie-starfive.c | 462 ++++++++++++
drivers/pci/pci.h | 16 +
15 files changed, 1861 insertions(+), 616 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml
create mode 100644 Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
create mode 100644 drivers/pci/controller/plda/Kconfig
create mode 100644 drivers/pci/controller/plda/Makefile
rename drivers/pci/controller/{ => plda}/pcie-microchip-host.c (54%)
create mode 100644 drivers/pci/controller/plda/pcie-plda-host.c
create mode 100644 drivers/pci/controller/plda/pcie-plda.h
create mode 100644 drivers/pci/controller/plda/pcie-starfive.c
base-commit: 33cc938e65a98f1d29d0a18403dbbee050dcad9a
--
2.17.1
Move the common data structures definition to head file for these two data
structures can be re-used.
Signed-off-by: Minda Chen <[email protected]>
Reviewed-by: Conor Dooley <[email protected]>
---
.../pci/controller/plda/pcie-microchip-host.c | 20 ------------------
drivers/pci/controller/plda/pcie-plda.h | 21 +++++++++++++++++++
2 files changed, 21 insertions(+), 20 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 3dc4d4ca9d0c..261147a0a446 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -21,9 +21,6 @@
#include "../../pci.h"
#include "pcie-plda.h"
-/* Number of MSI IRQs */
-#define PLDA_MAX_NUM_MSI_IRQS 32
-
/* PCIe Bridge Phy and Controller Phy offsets */
#define MC_PCIE1_BRIDGE_ADDR 0x00008000u
#define MC_PCIE1_CTRL_ADDR 0x0000a000u
@@ -179,23 +176,6 @@ struct event_map {
u32 event_bit;
};
-struct plda_msi {
- struct mutex lock; /* Protect used bitmap */
- struct irq_domain *msi_domain;
- struct irq_domain *dev_domain;
- u32 num_vectors;
- u64 vector_phy;
- DECLARE_BITMAP(used, PLDA_MAX_NUM_MSI_IRQS);
-};
-
-struct plda_pcie_rp {
- struct device *dev;
- struct irq_domain *intx_domain;
- struct irq_domain *event_domain;
- raw_spinlock_t lock;
- struct plda_msi msi;
- void __iomem *bridge_addr;
-};
struct mc_pcie {
struct plda_pcie_rp plda;
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index 727fc54312c9..363fcbbaf6ec 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -6,6 +6,9 @@
#ifndef _PCIE_PLDA_H
#define _PCIE_PLDA_H
+/* Number of MSI IRQs */
+#define PLDA_MAX_NUM_MSI_IRQS 32
+
/* PCIe Bridge Phy Regs */
#define PCIE_PCI_IRQ_DW0 0xa8
#define MSIX_CAP_MASK BIT(31)
@@ -99,4 +102,22 @@
#define EVENT_PM_MSI_INT_SYS_ERR 12
#define NUM_PLDA_EVENTS 13
+struct plda_msi {
+ struct mutex lock; /* Protect used bitmap */
+ struct irq_domain *msi_domain;
+ struct irq_domain *dev_domain;
+ u32 num_vectors;
+ u64 vector_phy;
+ DECLARE_BITMAP(used, PLDA_MAX_NUM_MSI_IRQS);
+};
+
+struct plda_pcie_rp {
+ struct device *dev;
+ struct irq_domain *intx_domain;
+ struct irq_domain *event_domain;
+ raw_spinlock_t lock;
+ struct plda_msi msi;
+ void __iomem *bridge_addr;
+};
+
#endif
--
2.17.1
Add PLDA PCIe related data structures by rename data structure name from
mc_* to plda_*.
axi_base_addr is stayed in struct mc_pcie for it's microchip its own data.
The event interrupt codes is still using struct mc_pcie because the event
interrupt codes can not be re-used.
The modification includes:
mc_pcie --> plda_pcie_rp (Get most of data members)
mc_msi --> plda_msi
Signed-off-by: Minda Chen <[email protected]>
Reviewed-by: Conor Dooley <[email protected]>
---
.../pci/controller/plda/pcie-microchip-host.c | 96 ++++++++++---------
1 file changed, 53 insertions(+), 43 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 60870ee1f1c9..3dc4d4ca9d0c 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -22,7 +22,7 @@
#include "pcie-plda.h"
/* Number of MSI IRQs */
-#define MC_MAX_NUM_MSI_IRQS 32
+#define PLDA_MAX_NUM_MSI_IRQS 32
/* PCIe Bridge Phy and Controller Phy offsets */
#define MC_PCIE1_BRIDGE_ADDR 0x00008000u
@@ -179,25 +179,29 @@ struct event_map {
u32 event_bit;
};
-struct mc_msi {
+struct plda_msi {
struct mutex lock; /* Protect used bitmap */
struct irq_domain *msi_domain;
struct irq_domain *dev_domain;
u32 num_vectors;
u64 vector_phy;
- DECLARE_BITMAP(used, MC_MAX_NUM_MSI_IRQS);
+ DECLARE_BITMAP(used, PLDA_MAX_NUM_MSI_IRQS);
};
-struct mc_pcie {
- void __iomem *axi_base_addr;
+struct plda_pcie_rp {
struct device *dev;
struct irq_domain *intx_domain;
struct irq_domain *event_domain;
raw_spinlock_t lock;
- struct mc_msi msi;
+ struct plda_msi msi;
void __iomem *bridge_addr;
};
+struct mc_pcie {
+ struct plda_pcie_rp plda;
+ void __iomem *axi_base_addr;
+};
+
struct cause {
const char *sym;
const char *str;
@@ -313,7 +317,7 @@ static struct mc_pcie *port;
static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
{
- struct mc_msi *msi = &port->msi;
+ struct plda_msi *msi = &port->plda.msi;
u16 reg;
u8 queue_size;
@@ -336,10 +340,10 @@ static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
static void mc_handle_msi(struct irq_desc *desc)
{
- struct mc_pcie *port = irq_desc_get_handler_data(desc);
+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
struct device *dev = port->dev;
- struct mc_msi *msi = &port->msi;
+ struct plda_msi *msi = &port->msi;
void __iomem *bridge_base_addr = port->bridge_addr;
unsigned long status;
u32 bit;
@@ -364,7 +368,7 @@ static void mc_handle_msi(struct irq_desc *desc)
static void mc_msi_bottom_irq_ack(struct irq_data *data)
{
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
void __iomem *bridge_base_addr = port->bridge_addr;
u32 bitpos = data->hwirq;
@@ -373,7 +377,7 @@ static void mc_msi_bottom_irq_ack(struct irq_data *data)
static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
phys_addr_t addr = port->msi.vector_phy;
msg->address_lo = lower_32_bits(addr);
@@ -400,8 +404,8 @@ static struct irq_chip mc_msi_bottom_irq_chip = {
static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *args)
{
- struct mc_pcie *port = domain->host_data;
- struct mc_msi *msi = &port->msi;
+ struct plda_pcie_rp *port = domain->host_data;
+ struct plda_msi *msi = &port->msi;
unsigned long bit;
mutex_lock(&msi->lock);
@@ -425,8 +429,8 @@ static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs)
{
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
- struct mc_pcie *port = irq_data_get_irq_chip_data(d);
- struct mc_msi *msi = &port->msi;
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
+ struct plda_msi *msi = &port->msi;
mutex_lock(&msi->lock);
@@ -456,11 +460,11 @@ static struct msi_domain_info mc_msi_domain_info = {
.chip = &mc_msi_irq_chip,
};
-static int mc_allocate_msi_domains(struct mc_pcie *port)
+static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
{
struct device *dev = port->dev;
struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
- struct mc_msi *msi = &port->msi;
+ struct plda_msi *msi = &port->msi;
mutex_init(&port->msi.lock);
@@ -484,7 +488,7 @@ static int mc_allocate_msi_domains(struct mc_pcie *port)
static void mc_handle_intx(struct irq_desc *desc)
{
- struct mc_pcie *port = irq_desc_get_handler_data(desc);
+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
struct device *dev = port->dev;
void __iomem *bridge_base_addr = port->bridge_addr;
@@ -511,7 +515,7 @@ static void mc_handle_intx(struct irq_desc *desc)
static void mc_ack_intx_irq(struct irq_data *data)
{
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
void __iomem *bridge_base_addr = port->bridge_addr;
u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
@@ -520,7 +524,7 @@ static void mc_ack_intx_irq(struct irq_data *data)
static void mc_mask_intx_irq(struct irq_data *data)
{
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
void __iomem *bridge_base_addr = port->bridge_addr;
unsigned long flags;
u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
@@ -535,7 +539,7 @@ static void mc_mask_intx_irq(struct irq_data *data)
static void mc_unmask_intx_irq(struct irq_data *data)
{
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
void __iomem *bridge_base_addr = port->bridge_addr;
unsigned long flags;
u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
@@ -625,21 +629,22 @@ static u32 local_events(struct mc_pcie *port)
return val;
}
-static u32 get_events(struct mc_pcie *port)
+static u32 get_events(struct plda_pcie_rp *port)
{
+ struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
u32 events = 0;
- events |= pcie_events(port);
- events |= sec_errors(port);
- events |= ded_errors(port);
- events |= local_events(port);
+ events |= pcie_events(mc_port);
+ events |= sec_errors(mc_port);
+ events |= ded_errors(mc_port);
+ events |= local_events(mc_port);
return events;
}
static irqreturn_t mc_event_handler(int irq, void *dev_id)
{
- struct mc_pcie *port = dev_id;
+ struct plda_pcie_rp *port = dev_id;
struct device *dev = port->dev;
struct irq_data *data;
@@ -655,7 +660,7 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
static void mc_handle_event(struct irq_desc *desc)
{
- struct mc_pcie *port = irq_desc_get_handler_data(desc);
+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
unsigned long events;
u32 bit;
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -672,12 +677,13 @@ static void mc_handle_event(struct irq_desc *desc)
static void mc_ack_event_irq(struct irq_data *data)
{
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
u32 event = data->hwirq;
void __iomem *addr;
u32 mask;
- addr = port->axi_base_addr + event_descs[event].base +
+ addr = mc_port->axi_base_addr + event_descs[event].base +
event_descs[event].offset;
mask = event_descs[event].mask;
mask |= event_descs[event].enb_mask;
@@ -687,13 +693,14 @@ static void mc_ack_event_irq(struct irq_data *data)
static void mc_mask_event_irq(struct irq_data *data)
{
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
u32 event = data->hwirq;
void __iomem *addr;
u32 mask;
u32 val;
- addr = port->axi_base_addr + event_descs[event].base +
+ addr = mc_port->axi_base_addr + event_descs[event].base +
event_descs[event].mask_offset;
mask = event_descs[event].mask;
if (event_descs[event].enb_mask) {
@@ -717,13 +724,14 @@ static void mc_mask_event_irq(struct irq_data *data)
static void mc_unmask_event_irq(struct irq_data *data)
{
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
u32 event = data->hwirq;
void __iomem *addr;
u32 mask;
u32 val;
- addr = port->axi_base_addr + event_descs[event].base +
+ addr = mc_port->axi_base_addr + event_descs[event].base +
event_descs[event].mask_offset;
mask = event_descs[event].mask;
@@ -811,7 +819,7 @@ static int mc_pcie_init_clks(struct device *dev)
return 0;
}
-static int mc_pcie_init_irq_domains(struct mc_pcie *port)
+static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
{
struct device *dev = port->dev;
struct device_node *node = dev->of_node;
@@ -889,7 +897,7 @@ static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
}
static int mc_pcie_setup_windows(struct platform_device *pdev,
- struct mc_pcie *port)
+ struct plda_pcie_rp *port)
{
void __iomem *bridge_base_addr = port->bridge_addr;
struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
@@ -970,7 +978,7 @@ static void mc_disable_interrupts(struct mc_pcie *port)
writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
}
-static int mc_init_interrupts(struct platform_device *pdev, struct mc_pcie *port)
+static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
{
struct device *dev = &pdev->dev;
int irq;
@@ -1043,12 +1051,12 @@ static int mc_platform_init(struct pci_config_window *cfg)
mc_pcie_enable_msi(port, cfg->win);
/* Configure non-config space outbound ranges */
- ret = mc_pcie_setup_windows(pdev, port);
+ ret = mc_pcie_setup_windows(pdev, &port->plda);
if (ret)
return ret;
/* Address translation is up; safe to enable interrupts */
- ret = mc_init_interrupts(pdev, port);
+ ret = mc_init_interrupts(pdev, &port->plda);
if (ret)
return ret;
@@ -1059,6 +1067,7 @@ static int mc_host_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
void __iomem *bridge_base_addr;
+ struct plda_pcie_rp *plda;
int ret;
u32 val;
@@ -1066,7 +1075,8 @@ static int mc_host_probe(struct platform_device *pdev)
if (!port)
return -ENOMEM;
- port->dev = dev;
+ plda = &port->plda;
+ plda->dev = dev;
port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(port->axi_base_addr))
@@ -1075,7 +1085,7 @@ static int mc_host_probe(struct platform_device *pdev)
mc_disable_interrupts(port);
bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
- port->bridge_addr = bridge_base_addr;
+ plda->bridge_addr = bridge_base_addr;
/* Allow enabling MSI by disabling MSI-X */
val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
@@ -1087,10 +1097,10 @@ static int mc_host_probe(struct platform_device *pdev)
val &= NUM_MSI_MSGS_MASK;
val >>= NUM_MSI_MSGS_SHIFT;
- port->msi.num_vectors = 1 << val;
+ plda->msi.num_vectors = 1 << val;
/* Pick vector address from design */
- port->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR);
+ plda->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR);
ret = mc_pcie_init_clks(dev);
if (ret) {
--
2.17.1
If other vendor do not select PCI_HOST_COMMON, the driver data is not
struct pci_host_bridge.
Move calling platform_get_drvdata() to mc_platform_init().
Signed-off-by: Minda Chen <[email protected]>
Reviewed-by: Conor Dooley <[email protected]>
---
drivers/pci/controller/plda/pcie-microchip-host.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 4877d130ee4c..31ca8d44ee2a 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -876,11 +876,10 @@ static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
}
-static int plda_pcie_setup_iomems(struct platform_device *pdev,
+static int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
struct plda_pcie_rp *port)
{
void __iomem *bridge_base_addr = port->bridge_addr;
- struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
struct resource_entry *entry;
u64 pci_addr;
u32 index = 1;
@@ -1018,6 +1017,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
{
struct device *dev = cfg->parent;
struct platform_device *pdev = to_platform_device(dev);
+ struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
void __iomem *bridge_base_addr =
port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
int ret;
@@ -1031,7 +1031,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
mc_pcie_enable_msi(port, cfg->win);
/* Configure non-config space outbound ranges */
- ret = plda_pcie_setup_iomems(pdev, &port->plda);
+ ret = plda_pcie_setup_iomems(bridge, &port->plda);
if (ret)
return ret;
--
2.17.1
Move setup functions to common pcie-plda-host.c. So these two functions
can be re-used.
Signed-off-by: Minda Chen <[email protected]>
Reviewed-by: Conor Dooley <[email protected]>
---
drivers/pci/controller/plda/Kconfig | 4 +
drivers/pci/controller/plda/Makefile | 1 +
.../pci/controller/plda/pcie-microchip-host.c | 59 --------------
drivers/pci/controller/plda/pcie-plda-host.c | 80 +++++++++++++++++++
drivers/pci/controller/plda/pcie-plda.h | 5 ++
5 files changed, 90 insertions(+), 59 deletions(-)
create mode 100644 drivers/pci/controller/plda/pcie-plda-host.c
diff --git a/drivers/pci/controller/plda/Kconfig b/drivers/pci/controller/plda/Kconfig
index 5cb3be4fc98c..e54a82ee94f5 100644
--- a/drivers/pci/controller/plda/Kconfig
+++ b/drivers/pci/controller/plda/Kconfig
@@ -3,10 +3,14 @@
menu "PLDA-based PCIe controllers"
depends on PCI
+config PCIE_PLDA_HOST
+ bool
+
config PCIE_MICROCHIP_HOST
tristate "Microchip AXI PCIe controller"
depends on PCI_MSI && OF
select PCI_HOST_COMMON
+ select PCIE_PLDA_HOST
help
Say Y here if you want kernel to support the Microchip AXI PCIe
Host Bridge driver.
diff --git a/drivers/pci/controller/plda/Makefile b/drivers/pci/controller/plda/Makefile
index e1a265cbf91c..4340ab007f44 100644
--- a/drivers/pci/controller/plda/Makefile
+++ b/drivers/pci/controller/plda/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PCIE_PLDA_HOST) += pcie-plda-host.o
obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 31ca8d44ee2a..2e79bcc7c0a5 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -838,65 +838,6 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
return mc_allocate_msi_domains(port);
}
-static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
- phys_addr_t axi_addr, phys_addr_t pci_addr,
- size_t size)
-{
- u32 atr_sz = ilog2(size) - 1;
- u32 val;
-
- if (index == 0)
- val = PCIE_CONFIG_INTERFACE;
- else
- val = PCIE_TX_RX_INTERFACE;
-
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
- ATR0_AXI4_SLV0_TRSL_PARAM);
-
- val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
- ATR_IMPL_ENABLE;
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
- ATR0_AXI4_SLV0_SRCADDR_PARAM);
-
- val = upper_32_bits(axi_addr);
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
- ATR0_AXI4_SLV0_SRC_ADDR);
-
- val = lower_32_bits(pci_addr);
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
- ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
-
- val = upper_32_bits(pci_addr);
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
- ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
-
- val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
- val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
- writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
- writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
-}
-
-static int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
- struct plda_pcie_rp *port)
-{
- void __iomem *bridge_base_addr = port->bridge_addr;
- struct resource_entry *entry;
- u64 pci_addr;
- u32 index = 1;
-
- resource_list_for_each_entry(entry, &bridge->windows) {
- if (resource_type(entry->res) == IORESOURCE_MEM) {
- pci_addr = entry->res->start - entry->offset;
- plda_pcie_setup_window(bridge_base_addr, index,
- entry->res->start, pci_addr,
- resource_size(entry->res));
- index++;
- }
- }
-
- return 0;
-}
-
static inline void mc_clear_secs(struct mc_pcie *port)
{
void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
new file mode 100644
index 000000000000..19131181897f
--- /dev/null
+++ b/drivers/pci/controller/plda/pcie-plda-host.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PLDA PCIe XpressRich host controller driver
+ *
+ * Copyright (C) 2023 Microchip Co. Ltd
+ *
+ * Author: Daire McNamara <[email protected]>
+ */
+
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/pci_regs.h>
+#include <linux/pci-ecam.h>
+#include <linux/platform_device.h>
+
+#include "pcie-plda.h"
+
+void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
+ phys_addr_t axi_addr, phys_addr_t pci_addr,
+ size_t size)
+{
+ u32 atr_sz = ilog2(size) - 1;
+ u32 val;
+
+ if (index == 0)
+ val = PCIE_CONFIG_INTERFACE;
+ else
+ val = PCIE_TX_RX_INTERFACE;
+
+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ ATR0_AXI4_SLV0_TRSL_PARAM);
+
+ val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
+ ATR_IMPL_ENABLE;
+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ ATR0_AXI4_SLV0_SRCADDR_PARAM);
+
+ val = upper_32_bits(axi_addr);
+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ ATR0_AXI4_SLV0_SRC_ADDR);
+
+ val = lower_32_bits(pci_addr);
+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
+
+ val = upper_32_bits(pci_addr);
+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
+
+ val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
+ val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
+ writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
+ writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
+}
+EXPORT_SYMBOL_GPL(plda_pcie_setup_window);
+
+int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
+ struct plda_pcie_rp *port)
+{
+ void __iomem *bridge_base_addr = port->bridge_addr;
+ struct resource_entry *entry;
+ u64 pci_addr;
+ u32 index = 1;
+
+ resource_list_for_each_entry(entry, &bridge->windows) {
+ if (resource_type(entry->res) == IORESOURCE_MEM) {
+ pci_addr = entry->res->start - entry->offset;
+ plda_pcie_setup_window(bridge_base_addr, index,
+ entry->res->start, pci_addr,
+ resource_size(entry->res));
+ index++;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index 363fcbbaf6ec..3deefd35fa5a 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -120,4 +120,9 @@ struct plda_pcie_rp {
void __iomem *bridge_addr;
};
+void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
+ phys_addr_t axi_addr, phys_addr_t pci_addr,
+ size_t size);
+int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
+ struct plda_pcie_rp *port);
#endif
--
2.17.1
PolarFire implements specific PCIe interrupts except PLDA local interrupt.
For lack of MSI controller, these interrupts have to be added to global
event field. PolarFire PCIe driver also register additional interrupt
symbol name.
PolarFire PCIe contain total 28 interrupts event while PLDA contain 13
local interrupts event, interrupt to event num mapping is different.
So add a callback function to support different IRQ register function.
Also Add PLDA default handler function, which will be moved to pcie-
plda-host.c in moving codes patch.
Signed-off-by: Minda Chen <[email protected]>
Acked-by: Conor Dooley <[email protected]>
---
.../pci/controller/plda/pcie-microchip-host.c | 31 ++++++++++++++++---
drivers/pci/controller/plda/pcie-plda.h | 5 +++
2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 7b3f4f74745d..624e4e2e97d3 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -643,6 +643,11 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t plda_event_handler(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
static void plda_handle_event(struct irq_desc *desc)
{
struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
@@ -804,6 +809,17 @@ static int mc_pcie_init_clks(struct device *dev)
return 0;
}
+static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
+ int event)
+{
+ return devm_request_irq(plda->dev, event_irq, mc_event_handler,
+ 0, event_cause[event].sym, plda);
+}
+
+static const struct plda_event mc_event = {
+ .request_event_irq = mc_request_event_irq,
+};
+
static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
{
struct device *dev = port->dev;
@@ -905,7 +921,9 @@ static void mc_disable_interrupts(struct mc_pcie *port)
writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
}
-static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
+static int plda_init_interrupts(struct platform_device *pdev,
+ struct plda_pcie_rp *port,
+ const struct plda_event *event)
{
struct device *dev = &pdev->dev;
int irq;
@@ -929,8 +947,13 @@ static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_r
return -ENXIO;
}
- ret = devm_request_irq(dev, event_irq, mc_event_handler,
- 0, event_cause[i].sym, port);
+ if (event->request_event_irq)
+ ret = event->request_event_irq(port, event_irq, i);
+ else
+ ret = devm_request_irq(dev, event_irq,
+ plda_event_handler,
+ 0, NULL, port);
+
if (ret) {
dev_err(dev, "failed to request IRQ %d\n", event_irq);
return ret;
@@ -984,7 +1007,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
return ret;
/* Address translation is up; safe to enable interrupts */
- ret = plda_init_interrupts(pdev, &port->plda);
+ ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
if (ret)
return ret;
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index e3d35cef9894..28ed1374e1de 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -121,6 +121,11 @@ struct plda_pcie_rp {
int num_events;
};
+struct plda_event {
+ int (*request_event_irq)(struct plda_pcie_rp *pcie,
+ int event_irq, int event);
+};
+
void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
phys_addr_t axi_addr, phys_addr_t pci_addr,
size_t size);
--
2.17.1
Add PLDA host plda_pcie_host_init()/plda_pcie_host_deinit() and map bus
function. So vendor can use it to init PLDA PCIe host core.
Add struct plda_event instance to init PCIe interrupt.
Signed-off-by: Minda Chen <[email protected]>
Reviewed-by: Mason Huo <[email protected]>
---
drivers/pci/controller/plda/pcie-plda-host.c | 134 +++++++++++++++++--
drivers/pci/controller/plda/pcie-plda.h | 21 +++
2 files changed, 142 insertions(+), 13 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
index 3cba58a37093..53a9bef353a3 100644
--- a/drivers/pci/controller/plda/pcie-plda-host.c
+++ b/drivers/pci/controller/plda/pcie-plda-host.c
@@ -3,6 +3,7 @@
* PLDA PCIe XpressRich host controller driver
*
* Copyright (C) 2023 Microchip Co. Ltd
+ * StarFive Co. Ltd
*
* Author: Daire McNamara <[email protected]>
*/
@@ -18,6 +19,15 @@
#include "pcie-plda.h"
+void __iomem *plda_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where)
+{
+ struct plda_pcie_rp *pcie = bus->sysdata;
+
+ return pcie->config_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
+}
+EXPORT_SYMBOL_GPL(plda_pcie_map_bus);
+
static void plda_handle_msi(struct irq_desc *desc)
{
struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
@@ -375,6 +385,11 @@ static const struct irq_domain_ops plda_event_domain_ops = {
.map = plda_pcie_event_map,
};
+static const struct plda_event plda_default_event = {
+ .intx_event = EVENT_PM_MSI_INT_INTX,
+ .msi_event = EVENT_PM_MSI_INT_MSI
+};
+
static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
{
struct device *dev = port->dev;
@@ -421,8 +436,7 @@ int plda_init_interrupts(struct platform_device *pdev,
const struct plda_event *event)
{
struct device *dev = &pdev->dev;
- int irq;
- int i, intx_irq, msi_irq, event_irq;
+ int i, event_irq;
int ret;
if (!port->event_ops)
@@ -437,8 +451,8 @@ int plda_init_interrupts(struct platform_device *pdev,
return ret;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ port->irq = platform_get_irq(pdev, 0);
+ if (port->irq < 0)
return -ENODEV;
for (i = 0; i < port->num_events; i++) {
@@ -461,26 +475,26 @@ int plda_init_interrupts(struct platform_device *pdev,
}
}
- intx_irq = irq_create_mapping(port->event_domain,
- event->intx_event);
- if (!intx_irq) {
+ port->intx_irq = irq_create_mapping(port->event_domain,
+ event->intx_event);
+ if (!port->intx_irq) {
dev_err(dev, "failed to map INTx interrupt\n");
return -ENXIO;
}
/* Plug the INTx chained handler */
- irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
+ irq_set_chained_handler_and_data(port->intx_irq, plda_handle_intx, port);
- msi_irq = irq_create_mapping(port->event_domain,
- event->msi_event);
- if (!msi_irq)
+ port->msi_irq = irq_create_mapping(port->event_domain,
+ event->msi_event);
+ if (!port->msi_irq)
return -ENXIO;
/* Plug the MSI chained handler */
- irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
+ irq_set_chained_handler_and_data(port->msi_irq, plda_handle_msi, port);
/* Plug the main event chained handler */
- irq_set_chained_handler_and_data(irq, plda_handle_event, port);
+ irq_set_chained_handler_and_data(port->irq, plda_handle_event, port);
return 0;
}
@@ -546,3 +560,97 @@ int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
return 0;
}
EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
+
+static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie)
+{
+ irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
+ irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL);
+ irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL);
+
+ irq_domain_remove(pcie->msi.msi_domain);
+ irq_domain_remove(pcie->msi.dev_domain);
+
+ irq_domain_remove(pcie->intx_domain);
+ irq_domain_remove(pcie->event_domain);
+}
+
+int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops)
+{
+ struct device *dev = port->dev;
+ struct pci_host_bridge *bridge;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *cfg_res;
+ int ret;
+
+ pdev = to_platform_device(dev);
+
+ port->bridge_addr =
+ devm_platform_ioremap_resource_byname(pdev, "apb");
+
+ if (IS_ERR(port->bridge_addr))
+ return dev_err_probe(dev, PTR_ERR(port->bridge_addr),
+ "failed to map reg memory\n");
+
+ cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+ if (!cfg_res)
+ return dev_err_probe(dev, -ENODEV,
+ "failed to get config memory\n");
+
+ port->config_base = devm_ioremap_resource(dev, cfg_res);
+ if (IS_ERR(port->config_base))
+ return dev_err_probe(dev, PTR_ERR(port->config_base),
+ "failed to map config memory\n");
+
+ bridge = devm_pci_alloc_host_bridge(dev, 0);
+ if (!bridge)
+ return dev_err_probe(dev, -ENOMEM,
+ "failed to alloc bridge\n");
+
+ if (port->host_ops && port->host_ops->host_init) {
+ ret = port->host_ops->host_init(port);
+ if (ret)
+ return ret;
+ }
+
+ port->bridge = bridge;
+ plda_pcie_setup_window(port->bridge_addr, 0, cfg_res->start, 0,
+ resource_size(cfg_res));
+ plda_pcie_setup_iomems(bridge, port);
+ plda_set_default_msi(&port->msi);
+ ret = plda_init_interrupts(pdev, port, &plda_default_event);
+ if (ret)
+ goto err_host;
+
+ /* Set default bus ops */
+ bridge->ops = ops;
+ bridge->sysdata = port;
+
+ ret = pci_host_probe(bridge);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "failed to probe pci host\n");
+ goto err_probe;
+ }
+
+ return ret;
+
+err_probe:
+ plda_pcie_irq_domain_deinit(port);
+err_host:
+ if (port->host_ops && port->host_ops->host_deinit)
+ port->host_ops->host_deinit(port);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(plda_pcie_host_init);
+
+void plda_pcie_host_deinit(struct plda_pcie_rp *port)
+{
+ pci_stop_root_bus(port->bridge->bus);
+ pci_remove_root_bus(port->bridge->bus);
+
+ plda_pcie_irq_domain_deinit(port);
+
+ if (port->host_ops && port->host_ops->host_deinit)
+ port->host_ops->host_deinit(port);
+}
+EXPORT_SYMBOL_GPL(plda_pcie_host_deinit);
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index fecef389d6cc..fd2e464552a9 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -136,6 +136,11 @@ struct plda_event_ops {
u32 (*get_events)(struct plda_pcie_rp *pcie);
};
+struct plda_pcie_host_ops {
+ int (*host_init)(struct plda_pcie_rp *pcie);
+ void (*host_deinit)(struct plda_pcie_rp *pcie);
+};
+
struct plda_msi {
struct mutex lock; /* Protect used bitmap */
struct irq_domain *msi_domain;
@@ -147,13 +152,19 @@ struct plda_msi {
struct plda_pcie_rp {
struct device *dev;
+ struct pci_host_bridge *bridge;
struct irq_domain *intx_domain;
struct irq_domain *event_domain;
raw_spinlock_t lock;
struct plda_msi msi;
const struct plda_event_ops *event_ops;
const struct irq_chip *event_irq_chip;
+ const struct plda_pcie_host_ops *host_ops;
void __iomem *bridge_addr;
+ void __iomem *config_base;
+ int irq;
+ int msi_irq;
+ int intx_irq;
int num_events;
};
@@ -164,6 +175,8 @@ struct plda_event {
int msi_event;
};
+void __iomem *plda_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where);
int plda_init_interrupts(struct platform_device *pdev,
struct plda_pcie_rp *port,
const struct plda_event *event);
@@ -172,4 +185,12 @@ void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
size_t size);
int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
struct plda_pcie_rp *port);
+int plda_pcie_host_init(struct plda_pcie_rp *pcie, struct pci_ops *ops);
+void plda_pcie_host_deinit(struct plda_pcie_rp *pcie);
+
+static inline void plda_set_default_msi(struct plda_msi *msi)
+{
+ msi->vector_phy = IMSI_ADDR;
+ msi->num_vectors = PLDA_MAX_NUM_MSI_IRQS;
+}
#endif
--
2.17.1
Add StarFive JH7110 SoC PCIe controller dt-bindings. JH7110 using PLDA
XpressRICH PCIe host controller IP.
Signed-off-by: Minda Chen <[email protected]>
Reviewed-by: Hal Feng <[email protected]>
Reviewed-by: Conor Dooley <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../bindings/pci/starfive,jh7110-pcie.yaml | 120 ++++++++++++++++++
1 file changed, 120 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
diff --git a/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml b/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
new file mode 100644
index 000000000000..67151aaa3948
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
@@ -0,0 +1,120 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/starfive,jh7110-pcie.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JH7110 PCIe host controller
+
+maintainers:
+ - Kevin Xie <[email protected]>
+
+allOf:
+ - $ref: plda,xpressrich3-axi-common.yaml#
+
+properties:
+ compatible:
+ const: starfive,jh7110-pcie
+
+ clocks:
+ items:
+ - description: NOC bus clock
+ - description: Transport layer clock
+ - description: AXI MST0 clock
+ - description: APB clock
+
+ clock-names:
+ items:
+ - const: noc
+ - const: tl
+ - const: axi_mst0
+ - const: apb
+
+ resets:
+ items:
+ - description: AXI MST0 reset
+ - description: AXI SLAVE0 reset
+ - description: AXI SLAVE reset
+ - description: PCIE BRIDGE reset
+ - description: PCIE CORE reset
+ - description: PCIE APB reset
+
+ reset-names:
+ items:
+ - const: mst0
+ - const: slv0
+ - const: slv
+ - const: brg
+ - const: core
+ - const: apb
+
+ starfive,stg-syscon:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description:
+ The phandle to System Register Controller syscon node.
+
+ perst-gpios:
+ description: GPIO controlled connection to PERST# signal
+ maxItems: 1
+
+ phys:
+ description:
+ Specified PHY is attached to PCIe controller.
+ maxItems: 1
+
+required:
+ - clocks
+ - resets
+ - starfive,stg-syscon
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pcie@940000000 {
+ compatible = "starfive,jh7110-pcie";
+ reg = <0x9 0x40000000 0x0 0x10000000>,
+ <0x0 0x2b000000 0x0 0x1000000>;
+ reg-names = "cfg", "apb";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ device_type = "pci";
+ ranges = <0x82000000 0x0 0x30000000 0x0 0x30000000 0x0 0x08000000>,
+ <0xc3000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>;
+ starfive,stg-syscon = <&stg_syscon>;
+ bus-range = <0x0 0xff>;
+ interrupt-parent = <&plic>;
+ interrupts = <56>;
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc0 0x1>,
+ <0x0 0x0 0x0 0x2 &pcie_intc0 0x2>,
+ <0x0 0x0 0x0 0x3 &pcie_intc0 0x3>,
+ <0x0 0x0 0x0 0x4 &pcie_intc0 0x4>;
+ msi-controller;
+ clocks = <&syscrg 86>,
+ <&stgcrg 10>,
+ <&stgcrg 8>,
+ <&stgcrg 9>;
+ clock-names = "noc", "tl", "axi_mst0", "apb";
+ resets = <&stgcrg 11>,
+ <&stgcrg 12>,
+ <&stgcrg 13>,
+ <&stgcrg 14>,
+ <&stgcrg 15>,
+ <&stgcrg 16>;
+ perst-gpios = <&gpios 26 GPIO_ACTIVE_LOW>;
+ phys = <&pciephy0>;
+
+ pcie_intc0: interrupt-controller {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ };
+ };
+ };
--
2.17.1
Rename two setup functions to plda prefix. Prepare to re-use these two
setup function.
For two setup functions names are similar, rename mc_pcie_setup_windows()
to plda_pcie_setup_iomems().
Signed-off-by: Minda Chen <[email protected]>
Reviewed-by: Conor Dooley <[email protected]>
---
.../pci/controller/plda/pcie-microchip-host.c | 24 +++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 261147a0a446..4877d130ee4c 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -838,9 +838,9 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
return mc_allocate_msi_domains(port);
}
-static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
- phys_addr_t axi_addr, phys_addr_t pci_addr,
- size_t size)
+static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
+ phys_addr_t axi_addr, phys_addr_t pci_addr,
+ size_t size)
{
u32 atr_sz = ilog2(size) - 1;
u32 val;
@@ -876,8 +876,8 @@ static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
}
-static int mc_pcie_setup_windows(struct platform_device *pdev,
- struct plda_pcie_rp *port)
+static int plda_pcie_setup_iomems(struct platform_device *pdev,
+ struct plda_pcie_rp *port)
{
void __iomem *bridge_base_addr = port->bridge_addr;
struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
@@ -888,9 +888,9 @@ static int mc_pcie_setup_windows(struct platform_device *pdev,
resource_list_for_each_entry(entry, &bridge->windows) {
if (resource_type(entry->res) == IORESOURCE_MEM) {
pci_addr = entry->res->start - entry->offset;
- mc_pcie_setup_window(bridge_base_addr, index,
- entry->res->start, pci_addr,
- resource_size(entry->res));
+ plda_pcie_setup_window(bridge_base_addr, index,
+ entry->res->start, pci_addr,
+ resource_size(entry->res));
index++;
}
}
@@ -1023,15 +1023,15 @@ static int mc_platform_init(struct pci_config_window *cfg)
int ret;
/* Configure address translation table 0 for PCIe config space */
- mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
- cfg->res.start,
- resource_size(&cfg->res));
+ plda_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
+ cfg->res.start,
+ resource_size(&cfg->res));
/* Need some fixups in config space */
mc_pcie_enable_msi(port, cfg->win);
/* Configure non-config space outbound ranges */
- ret = mc_pcie_setup_windows(pdev, &port->plda);
+ ret = plda_pcie_setup_iomems(pdev, &port->plda);
if (ret)
return ret;
--
2.17.1
The event num is different in other platform. For re-using interrupt
process codes, replace macros with variable.
Signed-off-by: Minda Chen <[email protected]>
Reviewed-by: Conor Dooley <[email protected]>
---
drivers/pci/controller/plda/pcie-microchip-host.c | 8 +++++---
drivers/pci/controller/plda/pcie-plda.h | 1 +
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 506e6eeadc76..7b3f4f74745d 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -654,7 +654,7 @@ static void plda_handle_event(struct irq_desc *desc)
events = mc_get_events(port);
- for_each_set_bit(bit, &events, NUM_EVENTS)
+ for_each_set_bit(bit, &events, port->num_events)
generic_handle_domain_irq(port->event_domain, bit);
chained_irq_exit(chip, desc);
@@ -817,7 +817,8 @@ static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
return -EINVAL;
}
- port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
+ port->event_domain = irq_domain_add_linear(pcie_intc_node,
+ port->num_events,
&plda_event_domain_ops,
port);
if (!port->event_domain) {
@@ -921,7 +922,7 @@ static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_r
if (irq < 0)
return -ENODEV;
- for (i = 0; i < NUM_EVENTS; i++) {
+ for (i = 0; i < port->num_events; i++) {
event_irq = irq_create_mapping(port->event_domain, i);
if (!event_irq) {
dev_err(dev, "failed to map hwirq %d\n", i);
@@ -1013,6 +1014,7 @@ static int mc_host_probe(struct platform_device *pdev)
bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
plda->bridge_addr = bridge_base_addr;
+ plda->num_events = NUM_EVENTS;
/* Allow enabling MSI by disabling MSI-X */
val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index 3deefd35fa5a..e3d35cef9894 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -118,6 +118,7 @@ struct plda_pcie_rp {
raw_spinlock_t lock;
struct plda_msi msi;
void __iomem *bridge_addr;
+ int num_events;
};
void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
--
2.17.1
PolarFire PCIE event IRQs includes PLDA local interrupts and PolarFire
their own IRQs. PolarFire PCIe event irq_chip ops using an event_desc to
unify different IRQ register addresses. On PLDA sides, PLDA irqchip codes
only require to set PLDA local interrupt register. So the PLDA irqchip ops
codes can not be extracted from PolarFire codes.
To support PLDA its own event IRQ process, implements PLDA irqchip ops and
add event irqchip field to struct pcie_plda_rp.
Signed-off-by: Minda Chen <[email protected]>
---
.../pci/controller/plda/pcie-microchip-host.c | 65 ++++++++++++++++++-
drivers/pci/controller/plda/pcie-plda.h | 3 +
2 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index fd0d92c3d03f..ff40c1622173 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -771,6 +771,63 @@ static struct irq_chip mc_event_irq_chip = {
.irq_unmask = mc_unmask_event_irq,
};
+static u32 plda_hwirq_to_mask(int hwirq)
+{
+ u32 mask;
+
+ if (hwirq < EVENT_PM_MSI_INT_INTX)
+ mask = BIT(hwirq + A_ATR_EVT_POST_ERR_SHIFT);
+ else if (hwirq == EVENT_PM_MSI_INT_INTX)
+ mask = PM_MSI_INT_INTX_MASK;
+ else
+ mask = BIT(hwirq + PM_MSI_TO_MASK_OFFSET);
+
+ return mask;
+}
+
+static void plda_ack_event_irq(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+
+ writel_relaxed(plda_hwirq_to_mask(data->hwirq),
+ port->bridge_addr + ISTATUS_LOCAL);
+}
+
+static void plda_mask_event_irq(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ u32 mask, val;
+
+ mask = plda_hwirq_to_mask(data->hwirq);
+
+ raw_spin_lock(&port->lock);
+ val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
+ val &= ~mask;
+ writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
+ raw_spin_unlock(&port->lock);
+}
+
+static void plda_unmask_event_irq(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ u32 mask, val;
+
+ mask = plda_hwirq_to_mask(data->hwirq);
+
+ raw_spin_lock(&port->lock);
+ val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
+ val |= mask;
+ writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
+ raw_spin_unlock(&port->lock);
+}
+
+static struct irq_chip plda_event_irq_chip = {
+ .name = "PLDA PCIe EVENT",
+ .irq_ack = plda_ack_event_irq,
+ .irq_mask = plda_mask_event_irq,
+ .irq_unmask = plda_unmask_event_irq,
+};
+
static const struct plda_event_ops plda_event_ops = {
.get_events = plda_get_events,
};
@@ -778,7 +835,9 @@ static const struct plda_event_ops plda_event_ops = {
static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hwirq)
{
- irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
+ struct plda_pcie_rp *port = (void *)domain->host_data;
+
+ irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
irq_set_chip_data(irq, domain->host_data);
return 0;
@@ -963,6 +1022,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
if (!port->event_ops)
port->event_ops = &plda_event_ops;
+ if (!port->event_irq_chip)
+ port->event_irq_chip = &plda_event_irq_chip;
+
ret = plda_pcie_init_irq_domains(port);
if (ret) {
dev_err(dev, "failed creating IRQ domains\n");
@@ -1040,6 +1102,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
return ret;
port->plda.event_ops = &mc_event_ops;
+ port->plda.event_irq_chip = &mc_event_irq_chip;
/* Address translation is up; safe to enable interrupts */
ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index dd8bc2750bfc..24ac50c458dc 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -128,6 +128,8 @@
* DMA end : reserved for vendor implement
*/
+#define PM_MSI_TO_MASK_OFFSET 19
+
struct plda_pcie_rp;
struct plda_event_ops {
@@ -150,6 +152,7 @@ struct plda_pcie_rp {
raw_spinlock_t lock;
struct plda_msi msi;
const struct plda_event_ops *event_ops;
+ const struct irq_chip *event_irq_chip;
void __iomem *bridge_addr;
int num_events;
};
--
2.17.1
Rename mc_* to plda_* for IRQ functions and related IRQ domain ops data
instances.
MSI, INTx interrupt codes and IRQ init codes are all can be re-used.
- function rename list:
mc_allocate_msi_domains() --> plda_allocate_msi_domains()
mc_init_interrupts() --> plda_init_interrupts()
mc_pcie_init_irq_domain() --> plda_pcie_init_irq_domains()
mc_handle_event() --> plda_handle_event()
get_events() --> mc_get_events()
MSI interrupts related functions and IRQ domain
(primary function is mc_handle_msi()):
mc_handle_msi() --> plda_handle_msi()
INTx interrupts related functions and IRQ domain
(primary function is mc_handle_intx()):
mc_handle_intx() --> plda_handle_intx()
Signed-off-by: Minda Chen <[email protected]>
Acked-by: Conor Dooley <[email protected]>
---
.../pci/controller/plda/pcie-microchip-host.c | 112 +++++++++---------
1 file changed, 59 insertions(+), 53 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 2e79bcc7c0a5..506e6eeadc76 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -318,7 +318,7 @@ static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
}
-static void mc_handle_msi(struct irq_desc *desc)
+static void plda_handle_msi(struct irq_desc *desc)
{
struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -333,7 +333,8 @@ static void mc_handle_msi(struct irq_desc *desc)
status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
if (status & PM_MSI_INT_MSI_MASK) {
- writel_relaxed(status & PM_MSI_INT_MSI_MASK, bridge_base_addr + ISTATUS_LOCAL);
+ writel_relaxed(status & PM_MSI_INT_MSI_MASK,
+ bridge_base_addr + ISTATUS_LOCAL);
status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
for_each_set_bit(bit, &status, msi->num_vectors) {
ret = generic_handle_domain_irq(msi->dev_domain, bit);
@@ -346,7 +347,7 @@ static void mc_handle_msi(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
-static void mc_msi_bottom_irq_ack(struct irq_data *data)
+static void plda_msi_bottom_irq_ack(struct irq_data *data)
{
struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
void __iomem *bridge_base_addr = port->bridge_addr;
@@ -355,7 +356,7 @@ static void mc_msi_bottom_irq_ack(struct irq_data *data)
writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
}
-static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
phys_addr_t addr = port->msi.vector_phy;
@@ -368,21 +369,23 @@ static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
(int)data->hwirq, msg->address_hi, msg->address_lo);
}
-static int mc_msi_set_affinity(struct irq_data *irq_data,
- const struct cpumask *mask, bool force)
+static int plda_msi_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
{
return -EINVAL;
}
-static struct irq_chip mc_msi_bottom_irq_chip = {
- .name = "Microchip MSI",
- .irq_ack = mc_msi_bottom_irq_ack,
- .irq_compose_msi_msg = mc_compose_msi_msg,
- .irq_set_affinity = mc_msi_set_affinity,
+static struct irq_chip plda_msi_bottom_irq_chip = {
+ .name = "PLDA MSI",
+ .irq_ack = plda_msi_bottom_irq_ack,
+ .irq_compose_msi_msg = plda_compose_msi_msg,
+ .irq_set_affinity = plda_msi_set_affinity,
};
-static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
- unsigned int nr_irqs, void *args)
+static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs,
+ void *args)
{
struct plda_pcie_rp *port = domain->host_data;
struct plda_msi *msi = &port->msi;
@@ -397,7 +400,7 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
set_bit(bit, msi->used);
- irq_domain_set_info(domain, virq, bit, &mc_msi_bottom_irq_chip,
+ irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
domain->host_data, handle_edge_irq, NULL, NULL);
mutex_unlock(&msi->lock);
@@ -405,8 +408,9 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
return 0;
}
-static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
- unsigned int nr_irqs)
+static void plda_irq_msi_domain_free(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs)
{
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
@@ -423,24 +427,24 @@ static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
}
static const struct irq_domain_ops msi_domain_ops = {
- .alloc = mc_irq_msi_domain_alloc,
- .free = mc_irq_msi_domain_free,
+ .alloc = plda_irq_msi_domain_alloc,
+ .free = plda_irq_msi_domain_free,
};
-static struct irq_chip mc_msi_irq_chip = {
- .name = "Microchip PCIe MSI",
+static struct irq_chip plda_msi_irq_chip = {
+ .name = "PLDA PCIe MSI",
.irq_ack = irq_chip_ack_parent,
.irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
};
-static struct msi_domain_info mc_msi_domain_info = {
+static struct msi_domain_info plda_msi_domain_info = {
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
MSI_FLAG_PCI_MSIX),
- .chip = &mc_msi_irq_chip,
+ .chip = &plda_msi_irq_chip,
};
-static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
+static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
{
struct device *dev = port->dev;
struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
@@ -455,7 +459,8 @@ static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
return -ENOMEM;
}
- msi->msi_domain = pci_msi_create_irq_domain(fwnode, &mc_msi_domain_info,
+ msi->msi_domain = pci_msi_create_irq_domain(fwnode,
+ &plda_msi_domain_info,
msi->dev_domain);
if (!msi->msi_domain) {
dev_err(dev, "failed to create MSI domain\n");
@@ -466,7 +471,7 @@ static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
return 0;
}
-static void mc_handle_intx(struct irq_desc *desc)
+static void plda_handle_intx(struct irq_desc *desc)
{
struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -493,7 +498,7 @@ static void mc_handle_intx(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
-static void mc_ack_intx_irq(struct irq_data *data)
+static void plda_ack_intx_irq(struct irq_data *data)
{
struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
void __iomem *bridge_base_addr = port->bridge_addr;
@@ -502,7 +507,7 @@ static void mc_ack_intx_irq(struct irq_data *data)
writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
}
-static void mc_mask_intx_irq(struct irq_data *data)
+static void plda_mask_intx_irq(struct irq_data *data)
{
struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
void __iomem *bridge_base_addr = port->bridge_addr;
@@ -517,7 +522,7 @@ static void mc_mask_intx_irq(struct irq_data *data)
raw_spin_unlock_irqrestore(&port->lock, flags);
}
-static void mc_unmask_intx_irq(struct irq_data *data)
+static void plda_unmask_intx_irq(struct irq_data *data)
{
struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
void __iomem *bridge_base_addr = port->bridge_addr;
@@ -532,24 +537,24 @@ static void mc_unmask_intx_irq(struct irq_data *data)
raw_spin_unlock_irqrestore(&port->lock, flags);
}
-static struct irq_chip mc_intx_irq_chip = {
- .name = "Microchip PCIe INTx",
- .irq_ack = mc_ack_intx_irq,
- .irq_mask = mc_mask_intx_irq,
- .irq_unmask = mc_unmask_intx_irq,
+static struct irq_chip plda_intx_irq_chip = {
+ .name = "PLDA PCIe INTx",
+ .irq_ack = plda_ack_intx_irq,
+ .irq_mask = plda_mask_intx_irq,
+ .irq_unmask = plda_unmask_intx_irq,
};
-static int mc_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
+static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
{
- irq_set_chip_and_handler(irq, &mc_intx_irq_chip, handle_level_irq);
+ irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
irq_set_chip_data(irq, domain->host_data);
return 0;
}
static const struct irq_domain_ops intx_domain_ops = {
- .map = mc_pcie_intx_map,
+ .map = plda_pcie_intx_map,
};
static inline u32 reg_to_event(u32 reg, struct event_map field)
@@ -609,7 +614,7 @@ static u32 local_events(struct mc_pcie *port)
return val;
}
-static u32 get_events(struct plda_pcie_rp *port)
+static u32 mc_get_events(struct plda_pcie_rp *port)
{
struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
u32 events = 0;
@@ -638,7 +643,7 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void mc_handle_event(struct irq_desc *desc)
+static void plda_handle_event(struct irq_desc *desc)
{
struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
unsigned long events;
@@ -647,7 +652,7 @@ static void mc_handle_event(struct irq_desc *desc)
chained_irq_enter(chip, desc);
- events = get_events(port);
+ events = mc_get_events(port);
for_each_set_bit(bit, &events, NUM_EVENTS)
generic_handle_domain_irq(port->event_domain, bit);
@@ -741,8 +746,8 @@ static struct irq_chip mc_event_irq_chip = {
.irq_unmask = mc_unmask_event_irq,
};
-static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
+static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
{
irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
irq_set_chip_data(irq, domain->host_data);
@@ -750,8 +755,8 @@ static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
return 0;
}
-static const struct irq_domain_ops event_domain_ops = {
- .map = mc_pcie_event_map,
+static const struct irq_domain_ops plda_event_domain_ops = {
+ .map = plda_pcie_event_map,
};
static inline void mc_pcie_deinit_clk(void *data)
@@ -799,7 +804,7 @@ static int mc_pcie_init_clks(struct device *dev)
return 0;
}
-static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
+static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
{
struct device *dev = port->dev;
struct device_node *node = dev->of_node;
@@ -813,7 +818,8 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
}
port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
- &event_domain_ops, port);
+ &plda_event_domain_ops,
+ port);
if (!port->event_domain) {
dev_err(dev, "failed to get event domain\n");
of_node_put(pcie_intc_node);
@@ -835,7 +841,7 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
of_node_put(pcie_intc_node);
raw_spin_lock_init(&port->lock);
- return mc_allocate_msi_domains(port);
+ return plda_allocate_msi_domains(port);
}
static inline void mc_clear_secs(struct mc_pcie *port)
@@ -898,14 +904,14 @@ static void mc_disable_interrupts(struct mc_pcie *port)
writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
}
-static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
+static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
{
struct device *dev = &pdev->dev;
int irq;
int i, intx_irq, msi_irq, event_irq;
int ret;
- ret = mc_pcie_init_irq_domains(port);
+ ret = plda_pcie_init_irq_domains(port);
if (ret) {
dev_err(dev, "failed creating IRQ domains\n");
return ret;
@@ -938,7 +944,7 @@ static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp
}
/* Plug the INTx chained handler */
- irq_set_chained_handler_and_data(intx_irq, mc_handle_intx, port);
+ irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
msi_irq = irq_create_mapping(port->event_domain,
EVENT_LOCAL_PM_MSI_INT_MSI);
@@ -946,10 +952,10 @@ static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp
return -ENXIO;
/* Plug the MSI chained handler */
- irq_set_chained_handler_and_data(msi_irq, mc_handle_msi, port);
+ irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
/* Plug the main event chained handler */
- irq_set_chained_handler_and_data(irq, mc_handle_event, port);
+ irq_set_chained_handler_and_data(irq, plda_handle_event, port);
return 0;
}
@@ -977,7 +983,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
return ret;
/* Address translation is up; safe to enable interrupts */
- ret = mc_init_interrupts(pdev, &port->plda);
+ ret = plda_init_interrupts(pdev, &port->plda);
if (ret)
return ret;
--
2.17.1
From: Kevin Xie <[email protected]>
Add the PCIE_RESET_CONFIG_DEVICE_WAIT_MS macro to define the minimum
waiting time between exit from a conventional reset and sending the
first configuration request to the device.
As described in PCI base specification r6.0, section 6.6.1 <Conventional
Reset>, there are two different use cases of the value:
- "With a Downstream Port that does not support Link speeds greater
than 5.0 GT/s, software must wait a minimum of 100 ms following exit
from a Conventional Reset before sending a Configuration Request to
the device immediately below that Port."
- "With a Downstream Port that supports Link speeds greater than
5.0 GT/s, software must wait a minimum of 100 ms after Link training
completes before sending a Configuration Request to the device
immediately below that Port."
Signed-off-by: Kevin Xie <[email protected]>
Reviewed-by: Mason Huo <[email protected]>
---
drivers/pci/pci.h | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 5ecbcf041179..06f1f1eb878c 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -22,6 +22,22 @@
*/
#define PCIE_PME_TO_L2_TIMEOUT_US 10000
+/*
+ * As described in PCI base specification r6.0, section 6.6.1 <Conventional
+ * Reset>, there are two different use cases of the value:
+ *
+ * - "With a Downstream Port that does not support Link speeds greater
+ * than 5.0 GT/s, software must wait a minimum of 100 ms following exit
+ * from a Conventional Reset before sending a Configuration Request to
+ * the device immediately below that Port."
+ *
+ * - "With a Downstream Port that supports Link speeds greater than
+ * 5.0 GT/s, software must wait a minimum of 100 ms after Link training
+ * completes before sending a Configuration Request to the device
+ * immediately below that Port."
+ */
+#define PCIE_RESET_CONFIG_DEVICE_WAIT_MS 100
+
extern const unsigned char pcie_link_speed[];
extern bool pci_early_dump;
--
2.17.1
Move IRQ related functions to pcie-plda-host.c for re-use these codes.
Now Refactoring codes complete.
Including MSI, INTx, event interrupts and IRQ init functions.
Signed-off-by: Minda Chen <[email protected]>
Acked-by: Conor Dooley <[email protected]>
---
.../pci/controller/plda/pcie-microchip-host.c | 467 -----------------
drivers/pci/controller/plda/pcie-plda-host.c | 468 ++++++++++++++++++
drivers/pci/controller/plda/pcie-plda.h | 3 +
3 files changed, 471 insertions(+), 467 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index ff40c1622173..22312decdcff 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -318,245 +318,6 @@ static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
}
-static void plda_handle_msi(struct irq_desc *desc)
-{
- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
- struct irq_chip *chip = irq_desc_get_chip(desc);
- struct device *dev = port->dev;
- struct plda_msi *msi = &port->msi;
- void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long status;
- u32 bit;
- int ret;
-
- chained_irq_enter(chip, desc);
-
- status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
- if (status & PM_MSI_INT_MSI_MASK) {
- writel_relaxed(status & PM_MSI_INT_MSI_MASK,
- bridge_base_addr + ISTATUS_LOCAL);
- status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
- for_each_set_bit(bit, &status, msi->num_vectors) {
- ret = generic_handle_domain_irq(msi->dev_domain, bit);
- if (ret)
- dev_err_ratelimited(dev, "bad MSI IRQ %d\n",
- bit);
- }
- }
-
- chained_irq_exit(chip, desc);
-}
-
-static void plda_msi_bottom_irq_ack(struct irq_data *data)
-{
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
- u32 bitpos = data->hwirq;
-
- writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
-}
-
-static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-{
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- phys_addr_t addr = port->msi.vector_phy;
-
- msg->address_lo = lower_32_bits(addr);
- msg->address_hi = upper_32_bits(addr);
- msg->data = data->hwirq;
-
- dev_dbg(port->dev, "msi#%x address_hi %#x address_lo %#x\n",
- (int)data->hwirq, msg->address_hi, msg->address_lo);
-}
-
-static int plda_msi_set_affinity(struct irq_data *irq_data,
- const struct cpumask *mask, bool force)
-{
- return -EINVAL;
-}
-
-static struct irq_chip plda_msi_bottom_irq_chip = {
- .name = "PLDA MSI",
- .irq_ack = plda_msi_bottom_irq_ack,
- .irq_compose_msi_msg = plda_compose_msi_msg,
- .irq_set_affinity = plda_msi_set_affinity,
-};
-
-static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
- unsigned int virq,
- unsigned int nr_irqs,
- void *args)
-{
- struct plda_pcie_rp *port = domain->host_data;
- struct plda_msi *msi = &port->msi;
- unsigned long bit;
-
- mutex_lock(&msi->lock);
- bit = find_first_zero_bit(msi->used, msi->num_vectors);
- if (bit >= msi->num_vectors) {
- mutex_unlock(&msi->lock);
- return -ENOSPC;
- }
-
- set_bit(bit, msi->used);
-
- irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
- domain->host_data, handle_edge_irq, NULL, NULL);
-
- mutex_unlock(&msi->lock);
-
- return 0;
-}
-
-static void plda_irq_msi_domain_free(struct irq_domain *domain,
- unsigned int virq,
- unsigned int nr_irqs)
-{
- struct irq_data *d = irq_domain_get_irq_data(domain, virq);
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
- struct plda_msi *msi = &port->msi;
-
- mutex_lock(&msi->lock);
-
- if (test_bit(d->hwirq, msi->used))
- __clear_bit(d->hwirq, msi->used);
- else
- dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq);
-
- mutex_unlock(&msi->lock);
-}
-
-static const struct irq_domain_ops msi_domain_ops = {
- .alloc = plda_irq_msi_domain_alloc,
- .free = plda_irq_msi_domain_free,
-};
-
-static struct irq_chip plda_msi_irq_chip = {
- .name = "PLDA PCIe MSI",
- .irq_ack = irq_chip_ack_parent,
- .irq_mask = pci_msi_mask_irq,
- .irq_unmask = pci_msi_unmask_irq,
-};
-
-static struct msi_domain_info plda_msi_domain_info = {
- .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
- MSI_FLAG_PCI_MSIX),
- .chip = &plda_msi_irq_chip,
-};
-
-static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
-{
- struct device *dev = port->dev;
- struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
- struct plda_msi *msi = &port->msi;
-
- mutex_init(&port->msi.lock);
-
- msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors,
- &msi_domain_ops, port);
- if (!msi->dev_domain) {
- dev_err(dev, "failed to create IRQ domain\n");
- return -ENOMEM;
- }
-
- msi->msi_domain = pci_msi_create_irq_domain(fwnode,
- &plda_msi_domain_info,
- msi->dev_domain);
- if (!msi->msi_domain) {
- dev_err(dev, "failed to create MSI domain\n");
- irq_domain_remove(msi->dev_domain);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void plda_handle_intx(struct irq_desc *desc)
-{
- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
- struct irq_chip *chip = irq_desc_get_chip(desc);
- struct device *dev = port->dev;
- void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long status;
- u32 bit;
- int ret;
-
- chained_irq_enter(chip, desc);
-
- status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
- if (status & PM_MSI_INT_INTX_MASK) {
- status &= PM_MSI_INT_INTX_MASK;
- status >>= PM_MSI_INT_INTX_SHIFT;
- for_each_set_bit(bit, &status, PCI_NUM_INTX) {
- ret = generic_handle_domain_irq(port->intx_domain, bit);
- if (ret)
- dev_err_ratelimited(dev, "bad INTx IRQ %d\n",
- bit);
- }
- }
-
- chained_irq_exit(chip, desc);
-}
-
-static void plda_ack_intx_irq(struct irq_data *data)
-{
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-
- writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
-}
-
-static void plda_mask_intx_irq(struct irq_data *data)
-{
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long flags;
- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
- u32 val;
-
- raw_spin_lock_irqsave(&port->lock, flags);
- val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
- val &= ~mask;
- writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
- raw_spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void plda_unmask_intx_irq(struct irq_data *data)
-{
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long flags;
- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
- u32 val;
-
- raw_spin_lock_irqsave(&port->lock, flags);
- val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
- val |= mask;
- writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
- raw_spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static struct irq_chip plda_intx_irq_chip = {
- .name = "PLDA PCIe INTx",
- .irq_ack = plda_ack_intx_irq,
- .irq_mask = plda_mask_intx_irq,
- .irq_unmask = plda_unmask_intx_irq,
-};
-
-static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
- irq_set_chip_data(irq, domain->host_data);
-
- return 0;
-}
-
-static const struct irq_domain_ops intx_domain_ops = {
- .map = plda_pcie_intx_map,
-};
-
static inline u32 reg_to_event(u32 reg, struct event_map field)
{
return (reg & field.reg_mask) ? BIT(field.event_bit) : 0;
@@ -627,26 +388,6 @@ static u32 mc_get_events(struct plda_pcie_rp *port)
return events;
}
-static u32 plda_get_events(struct plda_pcie_rp *port)
-{
- u32 events, val, origin;
-
- origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
-
- /* Error events and doorbell events */
- events = (origin & ERROR_AND_DOORBELL_MASK) >> A_ATR_EVT_POST_ERR_SHIFT;
-
- /* INTx events */
- if (origin & PM_MSI_INT_INTX_MASK)
- events |= BIT(EVENT_PM_MSI_INT_INTX);
-
- /* MSI event and sys events */
- val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
- events |= val << EVENT_PM_MSI_INT_MSI;
-
- return events;
-}
-
static irqreturn_t mc_event_handler(int irq, void *dev_id)
{
struct plda_pcie_rp *port = dev_id;
@@ -663,28 +404,6 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static irqreturn_t plda_event_handler(int irq, void *dev_id)
-{
- return IRQ_HANDLED;
-}
-
-static void plda_handle_event(struct irq_desc *desc)
-{
- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
- unsigned long events;
- u32 bit;
- struct irq_chip *chip = irq_desc_get_chip(desc);
-
- chained_irq_enter(chip, desc);
-
- events = port->event_ops->get_events(port);
-
- for_each_set_bit(bit, &events, port->num_events)
- generic_handle_domain_irq(port->event_domain, bit);
-
- chained_irq_exit(chip, desc);
-}
-
static void mc_ack_event_irq(struct irq_data *data)
{
struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
@@ -771,82 +490,6 @@ static struct irq_chip mc_event_irq_chip = {
.irq_unmask = mc_unmask_event_irq,
};
-static u32 plda_hwirq_to_mask(int hwirq)
-{
- u32 mask;
-
- if (hwirq < EVENT_PM_MSI_INT_INTX)
- mask = BIT(hwirq + A_ATR_EVT_POST_ERR_SHIFT);
- else if (hwirq == EVENT_PM_MSI_INT_INTX)
- mask = PM_MSI_INT_INTX_MASK;
- else
- mask = BIT(hwirq + PM_MSI_TO_MASK_OFFSET);
-
- return mask;
-}
-
-static void plda_ack_event_irq(struct irq_data *data)
-{
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-
- writel_relaxed(plda_hwirq_to_mask(data->hwirq),
- port->bridge_addr + ISTATUS_LOCAL);
-}
-
-static void plda_mask_event_irq(struct irq_data *data)
-{
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- u32 mask, val;
-
- mask = plda_hwirq_to_mask(data->hwirq);
-
- raw_spin_lock(&port->lock);
- val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
- val &= ~mask;
- writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
- raw_spin_unlock(&port->lock);
-}
-
-static void plda_unmask_event_irq(struct irq_data *data)
-{
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- u32 mask, val;
-
- mask = plda_hwirq_to_mask(data->hwirq);
-
- raw_spin_lock(&port->lock);
- val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
- val |= mask;
- writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
- raw_spin_unlock(&port->lock);
-}
-
-static struct irq_chip plda_event_irq_chip = {
- .name = "PLDA PCIe EVENT",
- .irq_ack = plda_ack_event_irq,
- .irq_mask = plda_mask_event_irq,
- .irq_unmask = plda_unmask_event_irq,
-};
-
-static const struct plda_event_ops plda_event_ops = {
- .get_events = plda_get_events,
-};
-
-static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct plda_pcie_rp *port = (void *)domain->host_data;
-
- irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
- irq_set_chip_data(irq, domain->host_data);
-
- return 0;
-}
-
-static const struct irq_domain_ops plda_event_domain_ops = {
- .map = plda_pcie_event_map,
-};
-
static inline void mc_pcie_deinit_clk(void *data)
{
struct clk *clk = data;
@@ -909,47 +552,6 @@ static const struct plda_event mc_event = {
.msi_event = EVENT_LOCAL_PM_MSI_INT_MSI,
};
-static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
-{
- struct device *dev = port->dev;
- struct device_node *node = dev->of_node;
- struct device_node *pcie_intc_node;
-
- /* Setup INTx */
- pcie_intc_node = of_get_next_child(node, NULL);
- if (!pcie_intc_node) {
- dev_err(dev, "failed to find PCIe Intc node\n");
- return -EINVAL;
- }
-
- port->event_domain = irq_domain_add_linear(pcie_intc_node,
- port->num_events,
- &plda_event_domain_ops,
- port);
- if (!port->event_domain) {
- dev_err(dev, "failed to get event domain\n");
- of_node_put(pcie_intc_node);
- return -ENOMEM;
- }
-
- irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS);
-
- port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
- &intx_domain_ops, port);
- if (!port->intx_domain) {
- dev_err(dev, "failed to get an INTx IRQ domain\n");
- of_node_put(pcie_intc_node);
- return -ENOMEM;
- }
-
- irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
-
- of_node_put(pcie_intc_node);
- raw_spin_lock_init(&port->lock);
-
- return plda_allocate_msi_domains(port);
-}
-
static inline void mc_clear_secs(struct mc_pcie *port)
{
void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
@@ -1010,75 +612,6 @@ static void mc_disable_interrupts(struct mc_pcie *port)
writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
}
-static int plda_init_interrupts(struct platform_device *pdev,
- struct plda_pcie_rp *port,
- const struct plda_event *event)
-{
- struct device *dev = &pdev->dev;
- int irq;
- int i, intx_irq, msi_irq, event_irq;
- int ret;
-
- if (!port->event_ops)
- port->event_ops = &plda_event_ops;
-
- if (!port->event_irq_chip)
- port->event_irq_chip = &plda_event_irq_chip;
-
- ret = plda_pcie_init_irq_domains(port);
- if (ret) {
- dev_err(dev, "failed creating IRQ domains\n");
- return ret;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return -ENODEV;
-
- for (i = 0; i < port->num_events; i++) {
- event_irq = irq_create_mapping(port->event_domain, i);
- if (!event_irq) {
- dev_err(dev, "failed to map hwirq %d\n", i);
- return -ENXIO;
- }
-
- if (event->request_event_irq)
- ret = event->request_event_irq(port, event_irq, i);
- else
- ret = devm_request_irq(dev, event_irq,
- plda_event_handler,
- 0, NULL, port);
-
- if (ret) {
- dev_err(dev, "failed to request IRQ %d\n", event_irq);
- return ret;
- }
- }
-
- intx_irq = irq_create_mapping(port->event_domain,
- event->intx_event);
- if (!intx_irq) {
- dev_err(dev, "failed to map INTx interrupt\n");
- return -ENXIO;
- }
-
- /* Plug the INTx chained handler */
- irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
-
- msi_irq = irq_create_mapping(port->event_domain,
- event->msi_event);
- if (!msi_irq)
- return -ENXIO;
-
- /* Plug the MSI chained handler */
- irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
-
- /* Plug the main event chained handler */
- irq_set_chained_handler_and_data(irq, plda_handle_event, port);
-
- return 0;
-}
-
static int mc_platform_init(struct pci_config_window *cfg)
{
struct device *dev = cfg->parent;
diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
index 19131181897f..3cba58a37093 100644
--- a/drivers/pci/controller/plda/pcie-plda-host.c
+++ b/drivers/pci/controller/plda/pcie-plda-host.c
@@ -18,6 +18,474 @@
#include "pcie-plda.h"
+static void plda_handle_msi(struct irq_desc *desc)
+{
+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct device *dev = port->dev;
+ struct plda_msi *msi = &port->msi;
+ void __iomem *bridge_base_addr = port->bridge_addr;
+ unsigned long status;
+ u32 bit;
+ int ret;
+
+ chained_irq_enter(chip, desc);
+
+ status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
+ if (status & PM_MSI_INT_MSI_MASK) {
+ writel_relaxed(status & PM_MSI_INT_MSI_MASK,
+ bridge_base_addr + ISTATUS_LOCAL);
+ status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
+ for_each_set_bit(bit, &status, msi->num_vectors) {
+ ret = generic_handle_domain_irq(msi->dev_domain, bit);
+ if (ret)
+ dev_err_ratelimited(dev, "bad MSI IRQ %d\n",
+ bit);
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void plda_msi_bottom_irq_ack(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ void __iomem *bridge_base_addr = port->bridge_addr;
+ u32 bitpos = data->hwirq;
+
+ writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
+}
+
+static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ phys_addr_t addr = port->msi.vector_phy;
+
+ msg->address_lo = lower_32_bits(addr);
+ msg->address_hi = upper_32_bits(addr);
+ msg->data = data->hwirq;
+
+ dev_dbg(port->dev, "msi#%x address_hi %#x address_lo %#x\n",
+ (int)data->hwirq, msg->address_hi, msg->address_lo);
+}
+
+static int plda_msi_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
+{
+ return -EINVAL;
+}
+
+static struct irq_chip plda_msi_bottom_irq_chip = {
+ .name = "PLDA MSI",
+ .irq_ack = plda_msi_bottom_irq_ack,
+ .irq_compose_msi_msg = plda_compose_msi_msg,
+ .irq_set_affinity = plda_msi_set_affinity,
+};
+
+static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs,
+ void *args)
+{
+ struct plda_pcie_rp *port = domain->host_data;
+ struct plda_msi *msi = &port->msi;
+ unsigned long bit;
+
+ mutex_lock(&msi->lock);
+ bit = find_first_zero_bit(msi->used, msi->num_vectors);
+ if (bit >= msi->num_vectors) {
+ mutex_unlock(&msi->lock);
+ return -ENOSPC;
+ }
+
+ set_bit(bit, msi->used);
+
+ irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
+ domain->host_data, handle_edge_irq, NULL, NULL);
+
+ mutex_unlock(&msi->lock);
+
+ return 0;
+}
+
+static void plda_irq_msi_domain_free(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
+ struct plda_msi *msi = &port->msi;
+
+ mutex_lock(&msi->lock);
+
+ if (test_bit(d->hwirq, msi->used))
+ __clear_bit(d->hwirq, msi->used);
+ else
+ dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq);
+
+ mutex_unlock(&msi->lock);
+}
+
+static const struct irq_domain_ops msi_domain_ops = {
+ .alloc = plda_irq_msi_domain_alloc,
+ .free = plda_irq_msi_domain_free,
+};
+
+static struct irq_chip plda_msi_irq_chip = {
+ .name = "PLDA PCIe MSI",
+ .irq_ack = irq_chip_ack_parent,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
+};
+
+static struct msi_domain_info plda_msi_domain_info = {
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_PCI_MSIX),
+ .chip = &plda_msi_irq_chip,
+};
+
+static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
+{
+ struct device *dev = port->dev;
+ struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
+ struct plda_msi *msi = &port->msi;
+
+ mutex_init(&port->msi.lock);
+
+ msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors,
+ &msi_domain_ops, port);
+ if (!msi->dev_domain) {
+ dev_err(dev, "failed to create IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ msi->msi_domain = pci_msi_create_irq_domain(fwnode,
+ &plda_msi_domain_info,
+ msi->dev_domain);
+ if (!msi->msi_domain) {
+ dev_err(dev, "failed to create MSI domain\n");
+ irq_domain_remove(msi->dev_domain);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void plda_handle_intx(struct irq_desc *desc)
+{
+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct device *dev = port->dev;
+ void __iomem *bridge_base_addr = port->bridge_addr;
+ unsigned long status;
+ u32 bit;
+ int ret;
+
+ chained_irq_enter(chip, desc);
+
+ status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
+ if (status & PM_MSI_INT_INTX_MASK) {
+ status &= PM_MSI_INT_INTX_MASK;
+ status >>= PM_MSI_INT_INTX_SHIFT;
+ for_each_set_bit(bit, &status, PCI_NUM_INTX) {
+ ret = generic_handle_domain_irq(port->intx_domain, bit);
+ if (ret)
+ dev_err_ratelimited(dev, "bad INTx IRQ %d\n",
+ bit);
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void plda_ack_intx_irq(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ void __iomem *bridge_base_addr = port->bridge_addr;
+ u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
+
+ writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
+}
+
+static void plda_mask_intx_irq(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ void __iomem *bridge_base_addr = port->bridge_addr;
+ unsigned long flags;
+ u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
+ u32 val;
+
+ raw_spin_lock_irqsave(&port->lock, flags);
+ val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
+ val &= ~mask;
+ writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
+ raw_spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void plda_unmask_intx_irq(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ void __iomem *bridge_base_addr = port->bridge_addr;
+ unsigned long flags;
+ u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
+ u32 val;
+
+ raw_spin_lock_irqsave(&port->lock, flags);
+ val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
+ val |= mask;
+ writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
+ raw_spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static struct irq_chip plda_intx_irq_chip = {
+ .name = "PLDA PCIe INTx",
+ .irq_ack = plda_ack_intx_irq,
+ .irq_mask = plda_mask_intx_irq,
+ .irq_unmask = plda_unmask_intx_irq,
+};
+
+static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
+ irq_set_chip_data(irq, domain->host_data);
+
+ return 0;
+}
+
+static const struct irq_domain_ops intx_domain_ops = {
+ .map = plda_pcie_intx_map,
+};
+
+static u32 plda_get_events(struct plda_pcie_rp *port)
+{
+ u32 events, val, origin;
+
+ origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
+
+ /* Error events and doorbell events */
+ events = (origin & ERROR_AND_DOORBELL_MASK) >> A_ATR_EVT_POST_ERR_SHIFT;
+
+ /* INTx events */
+ if (origin & PM_MSI_INT_INTX_MASK)
+ events |= BIT(EVENT_PM_MSI_INT_INTX);
+
+ /* MSI event and sys events */
+ val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
+ events |= val << EVENT_PM_MSI_INT_MSI;
+
+ return events;
+}
+
+static irqreturn_t plda_event_handler(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+static void plda_handle_event(struct irq_desc *desc)
+{
+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
+ unsigned long events;
+ u32 bit;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+
+ events = port->event_ops->get_events(port);
+
+ for_each_set_bit(bit, &events, port->num_events)
+ generic_handle_domain_irq(port->event_domain, bit);
+
+ chained_irq_exit(chip, desc);
+}
+
+static u32 plda_hwirq_to_mask(int hwirq)
+{
+ u32 mask;
+
+ if (hwirq < EVENT_PM_MSI_INT_INTX)
+ mask = BIT(hwirq + A_ATR_EVT_POST_ERR_SHIFT);
+ else if (hwirq == EVENT_PM_MSI_INT_INTX)
+ mask = PM_MSI_INT_INTX_MASK;
+ else
+ mask = BIT(hwirq + PM_MSI_TO_MASK_OFFSET);
+
+ return mask;
+}
+
+static void plda_ack_event_irq(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+
+ writel_relaxed(plda_hwirq_to_mask(data->hwirq),
+ port->bridge_addr + ISTATUS_LOCAL);
+}
+
+static void plda_mask_event_irq(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ u32 mask, val;
+
+ mask = plda_hwirq_to_mask(data->hwirq);
+
+ raw_spin_lock(&port->lock);
+ val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
+ val &= ~mask;
+ writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
+ raw_spin_unlock(&port->lock);
+}
+
+static void plda_unmask_event_irq(struct irq_data *data)
+{
+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
+ u32 mask, val;
+
+ mask = plda_hwirq_to_mask(data->hwirq);
+
+ raw_spin_lock(&port->lock);
+ val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
+ val |= mask;
+ writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
+ raw_spin_unlock(&port->lock);
+}
+
+static struct irq_chip plda_event_irq_chip = {
+ .name = "PLDA PCIe EVENT",
+ .irq_ack = plda_ack_event_irq,
+ .irq_mask = plda_mask_event_irq,
+ .irq_unmask = plda_unmask_event_irq,
+};
+
+static const struct plda_event_ops plda_event_ops = {
+ .get_events = plda_get_events,
+};
+
+static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct plda_pcie_rp *port = (void *)domain->host_data;
+
+ irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
+ irq_set_chip_data(irq, domain->host_data);
+
+ return 0;
+}
+
+static const struct irq_domain_ops plda_event_domain_ops = {
+ .map = plda_pcie_event_map,
+};
+
+static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
+{
+ struct device *dev = port->dev;
+ struct device_node *node = dev->of_node;
+ struct device_node *pcie_intc_node;
+
+ /* Setup INTx */
+ pcie_intc_node = of_get_next_child(node, NULL);
+ if (!pcie_intc_node) {
+ dev_err(dev, "failed to find PCIe Intc node\n");
+ return -EINVAL;
+ }
+
+ port->event_domain = irq_domain_add_linear(pcie_intc_node,
+ port->num_events,
+ &plda_event_domain_ops,
+ port);
+ if (!port->event_domain) {
+ dev_err(dev, "failed to get event domain\n");
+ of_node_put(pcie_intc_node);
+ return -ENOMEM;
+ }
+
+ irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS);
+
+ port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
+ &intx_domain_ops, port);
+ if (!port->intx_domain) {
+ dev_err(dev, "failed to get an INTx IRQ domain\n");
+ of_node_put(pcie_intc_node);
+ return -ENOMEM;
+ }
+
+ irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
+
+ of_node_put(pcie_intc_node);
+ raw_spin_lock_init(&port->lock);
+
+ return plda_allocate_msi_domains(port);
+}
+
+int plda_init_interrupts(struct platform_device *pdev,
+ struct plda_pcie_rp *port,
+ const struct plda_event *event)
+{
+ struct device *dev = &pdev->dev;
+ int irq;
+ int i, intx_irq, msi_irq, event_irq;
+ int ret;
+
+ if (!port->event_ops)
+ port->event_ops = &plda_event_ops;
+
+ if (!port->event_irq_chip)
+ port->event_irq_chip = &plda_event_irq_chip;
+
+ ret = plda_pcie_init_irq_domains(port);
+ if (ret) {
+ dev_err(dev, "failed creating IRQ domains\n");
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENODEV;
+
+ for (i = 0; i < port->num_events; i++) {
+ event_irq = irq_create_mapping(port->event_domain, i);
+ if (!event_irq) {
+ dev_err(dev, "failed to map hwirq %d\n", i);
+ return -ENXIO;
+ }
+
+ if (event->request_event_irq)
+ ret = event->request_event_irq(port, event_irq, i);
+ else
+ ret = devm_request_irq(dev, event_irq,
+ plda_event_handler,
+ 0, NULL, port);
+
+ if (ret) {
+ dev_err(dev, "failed to request IRQ %d\n", event_irq);
+ return ret;
+ }
+ }
+
+ intx_irq = irq_create_mapping(port->event_domain,
+ event->intx_event);
+ if (!intx_irq) {
+ dev_err(dev, "failed to map INTx interrupt\n");
+ return -ENXIO;
+ }
+
+ /* Plug the INTx chained handler */
+ irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
+
+ msi_irq = irq_create_mapping(port->event_domain,
+ event->msi_event);
+ if (!msi_irq)
+ return -ENXIO;
+
+ /* Plug the MSI chained handler */
+ irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
+
+ /* Plug the main event chained handler */
+ irq_set_chained_handler_and_data(irq, plda_handle_event, port);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(plda_init_interrupts);
+
void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
phys_addr_t axi_addr, phys_addr_t pci_addr,
size_t size)
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index 24ac50c458dc..fecef389d6cc 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -164,6 +164,9 @@ struct plda_event {
int msi_event;
};
+int plda_init_interrupts(struct platform_device *pdev,
+ struct plda_pcie_rp *port,
+ const struct plda_event *event);
void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
phys_addr_t axi_addr, phys_addr_t pci_addr,
size_t size);
--
2.17.1
Add PCIe dts configuraion for JH7110 SoC platform.
Signed-off-by: Minda Chen <[email protected]>
Reviewed-by: Hal Feng <[email protected]>
---
.../jh7110-starfive-visionfive-2.dtsi | 64 ++++++++++++++
arch/riscv/boot/dts/starfive/jh7110.dtsi | 86 +++++++++++++++++++
2 files changed, 150 insertions(+)
diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
index b89e9791efa7..2f8056d6f817 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
@@ -287,6 +287,22 @@
status = "okay";
};
+&pcie0 {
+ perst-gpios = <&sysgpio 26 GPIO_ACTIVE_LOW>;
+ phys = <&pciephy0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie0_pins>;
+ status = "okay";
+};
+
+&pcie1 {
+ perst-gpios = <&sysgpio 28 GPIO_ACTIVE_LOW>;
+ phys = <&pciephy1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie1_pins>;
+ status = "okay";
+};
+
&qspi {
#address-cells = <1>;
#size-cells = <0>;
@@ -513,6 +529,54 @@
};
};
+ pcie0_pins: pcie0-0 {
+ clkreq-pins {
+ pinmux = <GPIOMUX(27, GPOUT_LOW,
+ GPOEN_DISABLE,
+ GPI_NONE)>;
+ bias-pull-down;
+ drive-strength = <2>;
+ input-enable;
+ input-schmitt-disable;
+ slew-rate = <0>;
+ };
+
+ wake-pins {
+ pinmux = <GPIOMUX(32, GPOUT_LOW,
+ GPOEN_DISABLE,
+ GPI_NONE)>;
+ bias-pull-up;
+ drive-strength = <2>;
+ input-enable;
+ input-schmitt-disable;
+ slew-rate = <0>;
+ };
+ };
+
+ pcie1_pins: pcie1-0 {
+ clkreq-pins {
+ pinmux = <GPIOMUX(29, GPOUT_LOW,
+ GPOEN_DISABLE,
+ GPI_NONE)>;
+ bias-pull-down;
+ drive-strength = <2>;
+ input-enable;
+ input-schmitt-disable;
+ slew-rate = <0>;
+ };
+
+ wake-pins {
+ pinmux = <GPIOMUX(21, GPOUT_LOW,
+ GPOEN_DISABLE,
+ GPI_NONE)>;
+ bias-pull-up;
+ drive-strength = <2>;
+ input-enable;
+ input-schmitt-disable;
+ slew-rate = <0>;
+ };
+ };
+
spi0_pins: spi0-0 {
mosi-pins {
pinmux = <GPIOMUX(52, GPOUT_SYS_SPI0_TXD,
diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
index 45213cdf50dc..dfa2f94ed5b2 100644
--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
@@ -1138,5 +1138,91 @@
#reset-cells = <1>;
power-domains = <&pwrc JH7110_PD_VOUT>;
};
+
+ pcie0: pcie@940000000 {
+ compatible = "starfive,jh7110-pcie";
+ reg = <0x9 0x40000000 0x0 0x1000000>,
+ <0x0 0x2b000000 0x0 0x100000>;
+ reg-names = "cfg", "apb";
+ linux,pci-domain = <0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges = <0x82000000 0x0 0x30000000 0x0 0x30000000 0x0 0x08000000>,
+ <0xc3000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>;
+ interrupts = <56>;
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc0 0x1>,
+ <0x0 0x0 0x0 0x2 &pcie_intc0 0x2>,
+ <0x0 0x0 0x0 0x3 &pcie_intc0 0x3>,
+ <0x0 0x0 0x0 0x4 &pcie_intc0 0x4>;
+ msi-controller;
+ device_type = "pci";
+ starfive,stg-syscon = <&stg_syscon>;
+ bus-range = <0x0 0xff>;
+ clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>,
+ <&stgcrg JH7110_STGCLK_PCIE0_TL>,
+ <&stgcrg JH7110_STGCLK_PCIE0_AXI_MST0>,
+ <&stgcrg JH7110_STGCLK_PCIE0_APB>;
+ clock-names = "noc", "tl", "axi_mst0", "apb";
+ resets = <&stgcrg JH7110_STGRST_PCIE0_AXI_MST0>,
+ <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV0>,
+ <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV>,
+ <&stgcrg JH7110_STGRST_PCIE0_BRG>,
+ <&stgcrg JH7110_STGRST_PCIE0_CORE>,
+ <&stgcrg JH7110_STGRST_PCIE0_APB>;
+ reset-names = "mst0", "slv0", "slv", "brg",
+ "core", "apb";
+ status = "disabled";
+
+ pcie_intc0: interrupt-controller {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ };
+ };
+
+ pcie1: pcie@9c0000000 {
+ compatible = "starfive,jh7110-pcie";
+ reg = <0x9 0xc0000000 0x0 0x1000000>,
+ <0x0 0x2c000000 0x0 0x100000>;
+ reg-names = "cfg", "apb";
+ linux,pci-domain = <1>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges = <0x82000000 0x0 0x38000000 0x0 0x38000000 0x0 0x08000000>,
+ <0xc3000000 0x9 0x80000000 0x9 0x80000000 0x0 0x40000000>;
+ interrupts = <57>;
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc1 0x1>,
+ <0x0 0x0 0x0 0x2 &pcie_intc1 0x2>,
+ <0x0 0x0 0x0 0x3 &pcie_intc1 0x3>,
+ <0x0 0x0 0x0 0x4 &pcie_intc1 0x4>;
+ msi-controller;
+ device_type = "pci";
+ starfive,stg-syscon = <&stg_syscon>;
+ bus-range = <0x0 0xff>;
+ clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>,
+ <&stgcrg JH7110_STGCLK_PCIE1_TL>,
+ <&stgcrg JH7110_STGCLK_PCIE1_AXI_MST0>,
+ <&stgcrg JH7110_STGCLK_PCIE1_APB>;
+ clock-names = "noc", "tl", "axi_mst0", "apb";
+ resets = <&stgcrg JH7110_STGRST_PCIE1_AXI_MST0>,
+ <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV0>,
+ <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV>,
+ <&stgcrg JH7110_STGRST_PCIE1_BRG>,
+ <&stgcrg JH7110_STGRST_PCIE1_CORE>,
+ <&stgcrg JH7110_STGRST_PCIE1_APB>;
+ reset-names = "mst0", "slv0", "slv", "brg",
+ "core", "apb";
+ status = "disabled";
+
+ pcie_intc1: interrupt-controller {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ };
+ };
};
};
--
2.17.1
Add StarFive JH7110 SoC PCIe controller platform driver codes, JH7110
with PLDA host PCIe core.
Signed-off-by: Minda Chen <[email protected]>
Co-developed-by: Kevin Xie <[email protected]>
Reviewed-by: Mason Huo <[email protected]>
---
MAINTAINERS | 7 +
drivers/pci/controller/plda/Kconfig | 12 +
drivers/pci/controller/plda/Makefile | 1 +
drivers/pci/controller/plda/pcie-plda.h | 71 ++-
drivers/pci/controller/plda/pcie-starfive.c | 462 ++++++++++++++++++++
5 files changed, 552 insertions(+), 1 deletion(-)
create mode 100644 drivers/pci/controller/plda/pcie-starfive.c
diff --git a/MAINTAINERS b/MAINTAINERS
index a034ef4cce93..7578ad250339 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16874,6 +16874,13 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/socionext,uniphier-pcie*
F: drivers/pci/controller/dwc/pcie-uniphier*
+PCIE DRIVER FOR STARFIVE JH71x0
+M: Kevin Xie <[email protected]>
+L: [email protected]
+S: Maintained
+F: Documentation/devicetree/bindings/pci/starfive*
+F: drivers/pci/controller/plda/pcie-starfive.c
+
PCIE DRIVER FOR ST SPEAR13XX
M: Pratyush Anand <[email protected]>
L: [email protected]
diff --git a/drivers/pci/controller/plda/Kconfig b/drivers/pci/controller/plda/Kconfig
index e54a82ee94f5..c0e14146d7e4 100644
--- a/drivers/pci/controller/plda/Kconfig
+++ b/drivers/pci/controller/plda/Kconfig
@@ -15,4 +15,16 @@ config PCIE_MICROCHIP_HOST
Say Y here if you want kernel to support the Microchip AXI PCIe
Host Bridge driver.
+config PCIE_STARFIVE_HOST
+ tristate "StarFive PCIe host controller"
+ depends on PCI_MSI && OF
+ depends on ARCH_STARFIVE || COMPILE_TEST
+ select PCIE_PLDA_HOST
+ help
+ Say Y here if you want to support the StarFive PCIe controller in
+ host mode. StarFive PCIe controller uses PLDA PCIe core.
+
+ If you choose to build this driver as module it will be dynamically
+ linked and module will be called pcie-starfive.ko.
+
endmenu
diff --git a/drivers/pci/controller/plda/Makefile b/drivers/pci/controller/plda/Makefile
index 4340ab007f44..0ac6851bed48 100644
--- a/drivers/pci/controller/plda/Makefile
+++ b/drivers/pci/controller/plda/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PCIE_PLDA_HOST) += pcie-plda-host.o
obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
+obj-$(CONFIG_PCIE_STARFIVE_HOST) += pcie-starfive.o
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index fd2e464552a9..e03e681c93d2 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -10,10 +10,20 @@
#define PLDA_MAX_NUM_MSI_IRQS 32
/* PCIe Bridge Phy Regs */
+#define GEN_SETTINGS 0x80
+#define RP_ENABLE 1
+#define PCIE_PCI_IDS_DW1 0x9c
+#define IDS_CLASS_CODE_SHIFT 16
+#define REVISION_ID_MASK GENMASK(7, 0)
+#define CLASS_CODE_ID_MASK GENMASK(31, 8)
#define PCIE_PCI_IRQ_DW0 0xa8
#define MSIX_CAP_MASK BIT(31)
#define NUM_MSI_MSGS_MASK GENMASK(6, 4)
#define NUM_MSI_MSGS_SHIFT 4
+#define PCI_MISC 0xb4
+#define PHY_FUNCTION_DIS BIT(15)
+#define PCIE_WINROM 0xfc
+#define PREF_MEM_WIN_64_SUPPORT BIT(3)
#define IMASK_LOCAL 0x180
#define DMA_END_ENGINE_0_MASK 0x00000000u
@@ -66,6 +76,8 @@
#define ISTATUS_HOST 0x18c
#define IMSI_ADDR 0x190
#define ISTATUS_MSI 0x194
+#define PMSG_SUPPORT_RX 0x3f0
+#define PMSG_LTR_SUPPORT BIT(2)
/* PCIe Master table init defines */
#define ATR0_PCIE_WIN0_SRCADDR_PARAM 0x600u
@@ -87,6 +99,8 @@
#define PCIE_TX_RX_INTERFACE 0x00000000u
#define PCIE_CONFIG_INTERFACE 0x00000001u
+#define CONFIG_SPACE_ADDR_OFFSET 0x1000u
+
#define ATR_ENTRY_SIZE 32
#define EVENT_A_ATR_EVT_POST_ERR 0
@@ -193,4 +207,59 @@ static inline void plda_set_default_msi(struct plda_msi *msi)
msi->vector_phy = IMSI_ADDR;
msi->num_vectors = PLDA_MAX_NUM_MSI_IRQS;
}
-#endif
+
+static inline void plda_pcie_enable_root_port(struct plda_pcie_rp *plda)
+{
+ u32 value;
+
+ value = readl_relaxed(plda->bridge_addr + GEN_SETTINGS);
+ value |= RP_ENABLE;
+ writel_relaxed(value, plda->bridge_addr + GEN_SETTINGS);
+}
+
+static inline void plda_pcie_set_standard_class(struct plda_pcie_rp *plda)
+{
+ u32 value;
+
+ /* set class code and reserve revision id */
+ value = readl_relaxed(plda->bridge_addr + PCIE_PCI_IDS_DW1);
+ value &= REVISION_ID_MASK;
+ value |= (PCI_CLASS_BRIDGE_PCI << IDS_CLASS_CODE_SHIFT);
+ writel_relaxed(value, plda->bridge_addr + PCIE_PCI_IDS_DW1);
+}
+
+static inline void plda_pcie_set_pref_win_64bit(struct plda_pcie_rp *plda)
+{
+ u32 value;
+
+ value = readl_relaxed(plda->bridge_addr + PCIE_WINROM);
+ value |= PREF_MEM_WIN_64_SUPPORT;
+ writel_relaxed(value, plda->bridge_addr + PCIE_WINROM);
+}
+
+static inline void plda_pcie_disable_ltr(struct plda_pcie_rp *plda)
+{
+ u32 value;
+
+ value = readl_relaxed(plda->bridge_addr + PMSG_SUPPORT_RX);
+ value &= ~PMSG_LTR_SUPPORT;
+ writel_relaxed(value, plda->bridge_addr + PMSG_SUPPORT_RX);
+}
+
+static inline void plda_pcie_disable_func(struct plda_pcie_rp *plda)
+{
+ u32 value;
+
+ value = readl_relaxed(plda->bridge_addr + PCI_MISC);
+ value |= PHY_FUNCTION_DIS;
+ writel_relaxed(value, plda->bridge_addr + PCI_MISC);
+}
+
+static inline void plda_pcie_write_rc_bar(struct plda_pcie_rp *plda, u64 val)
+{
+ void __iomem *addr = plda->bridge_addr + CONFIG_SPACE_ADDR_OFFSET;
+
+ writel_relaxed(lower_32_bits(val), addr + PCI_BASE_ADDRESS_0);
+ writel_relaxed(upper_32_bits(val), addr + PCI_BASE_ADDRESS_1);
+}
+#endif /* _PCIE_PLDA_H */
diff --git a/drivers/pci/controller/plda/pcie-starfive.c b/drivers/pci/controller/plda/pcie-starfive.c
new file mode 100644
index 000000000000..441c4f5133eb
--- /dev/null
+++ b/drivers/pci/controller/plda/pcie-starfive.c
@@ -0,0 +1,462 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCIe host controller driver for StarFive JH7110 Soc.
+ *
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include "../../pci.h"
+
+#include "pcie-plda.h"
+
+#define PCIE_FUNC_NUM 4
+
+/* system control */
+#define STG_SYSCON_PCIE0_BASE 0x48
+#define STG_SYSCON_PCIE1_BASE 0x1f8
+
+#define STG_SYSCON_AR_OFFSET 0x78
+#define STG_SYSCON_AXI4_SLVL_AR_MASK GENMASK(22, 8)
+#define STG_SYSCON_AXI4_SLVL_PHY_AR(x) FIELD_PREP(GENMASK(20, 17), x)
+#define STG_SYSCON_AW_OFFSET 0x7c
+#define STG_SYSCON_AXI4_SLVL_AW_MASK GENMASK(14, 0)
+#define STG_SYSCON_AXI4_SLVL_PHY_AW(x) FIELD_PREP(GENMASK(12, 9), x)
+#define STG_SYSCON_CLKREQ BIT(22)
+#define STG_SYSCON_CKREF_SRC_MASK GENMASK(19, 18)
+#define STG_SYSCON_RP_NEP_OFFSET 0xe8
+#define STG_SYSCON_K_RP_NEP BIT(8)
+#define STG_SYSCON_LNKSTA_OFFSET 0x170
+#define DATA_LINK_ACTIVE BIT(5)
+
+/* Parameters for the waiting for link up routine */
+#define LINK_WAIT_MAX_RETRIES 10
+#define LINK_WAIT_USLEEP_MIN 90000
+#define LINK_WAIT_USLEEP_MAX 100000
+
+struct starfive_jh7110_pcie {
+ struct plda_pcie_rp plda;
+ struct reset_control *resets;
+ struct clk_bulk_data *clks;
+ struct regmap *reg_syscon;
+ struct gpio_desc *power_gpio;
+ struct gpio_desc *reset_gpio;
+ struct phy *phy;
+
+ unsigned int stg_pcie_base;
+ int num_clks;
+};
+
+/*
+ * The BAR0/1 of bridge should be hidden during enumeration to
+ * avoid the sizing and resource allocation by PCIe core.
+ */
+static bool starfive_pcie_hide_rc_bar(struct pci_bus *bus, unsigned int devfn,
+ int offset)
+{
+ if (pci_is_root_bus(bus) && !devfn &&
+ (offset == PCI_BASE_ADDRESS_0 || offset == PCI_BASE_ADDRESS_1))
+ return true;
+
+ return false;
+}
+
+static int starfive_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ if (starfive_pcie_hide_rc_bar(bus, devfn, where))
+ return PCIBIOS_SUCCESSFUL;
+
+ return pci_generic_config_write(bus, devfn, where, size, value);
+}
+
+static int starfive_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ if (starfive_pcie_hide_rc_bar(bus, devfn, where)) {
+ *value = 0;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ return pci_generic_config_read(bus, devfn, where, size, value);
+}
+
+static int starfive_pcie_parse_dt(struct starfive_jh7110_pcie *pcie,
+ struct device *dev)
+{
+ int domain_nr;
+
+ pcie->num_clks = devm_clk_bulk_get_all(dev, &pcie->clks);
+ if (pcie->num_clks < 0)
+ return dev_err_probe(dev, pcie->num_clks,
+ "failed to get pcie clocks\n");
+
+ pcie->resets = devm_reset_control_array_get_exclusive(dev);
+ if (IS_ERR(pcie->resets))
+ return dev_err_probe(dev, PTR_ERR(pcie->resets),
+ "failed to get pcie resets");
+
+ pcie->reg_syscon =
+ syscon_regmap_lookup_by_phandle(dev->of_node,
+ "starfive,stg-syscon");
+
+ if (IS_ERR(pcie->reg_syscon))
+ return dev_err_probe(dev, PTR_ERR(pcie->reg_syscon),
+ "failed to parse starfive,stg-syscon\n");
+
+ pcie->phy = devm_phy_optional_get(dev, NULL);
+ if (IS_ERR(pcie->phy))
+ return dev_err_probe(dev, PTR_ERR(pcie->phy),
+ "failed to get pcie phy\n");
+
+ domain_nr = of_get_pci_domain_nr(dev->of_node);
+
+ if (domain_nr < 0 || domain_nr > 1)
+ return dev_err_probe(dev, -ENODEV,
+ "failed to get valid pcie domain\n");
+
+ if (domain_nr == 0)
+ pcie->stg_pcie_base = STG_SYSCON_PCIE0_BASE;
+ else
+ pcie->stg_pcie_base = STG_SYSCON_PCIE1_BASE;
+
+ pcie->reset_gpio = devm_gpiod_get_optional(dev, "perst",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(pcie->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(pcie->reset_gpio),
+ "failed to get perst-gpio\n");
+
+ pcie->power_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(pcie->power_gpio))
+ return dev_err_probe(dev, PTR_ERR(pcie->power_gpio),
+ "failed to get power-gpio\n");
+
+ return 0;
+}
+
+static struct pci_ops starfive_pcie_ops = {
+ .map_bus = plda_pcie_map_bus,
+ .read = starfive_pcie_config_read,
+ .write = starfive_pcie_config_write,
+};
+
+static int starfive_pcie_clk_rst_init(struct starfive_jh7110_pcie *pcie)
+{
+ struct device *dev = pcie->plda.dev;
+ int ret;
+
+ ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable clocks\n");
+
+ ret = reset_control_deassert(pcie->resets);
+ if (ret) {
+ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
+ dev_err_probe(dev, ret, "failed to deassert resets\n");
+ }
+
+ return ret;
+}
+
+static void starfive_pcie_clk_rst_deinit(struct starfive_jh7110_pcie *pcie)
+{
+ reset_control_assert(pcie->resets);
+ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
+}
+
+static bool starfive_pcie_link_up(struct plda_pcie_rp *plda)
+{
+ struct starfive_jh7110_pcie *pcie =
+ container_of(plda, struct starfive_jh7110_pcie, plda);
+ int ret;
+ u32 stg_reg_val;
+
+ ret = regmap_read(pcie->reg_syscon,
+ pcie->stg_pcie_base + STG_SYSCON_LNKSTA_OFFSET,
+ &stg_reg_val);
+ if (ret) {
+ dev_err(pcie->plda.dev, "failed to read link status\n");
+ return false;
+ }
+
+ return !!(stg_reg_val & DATA_LINK_ACTIVE);
+}
+
+static int starfive_pcie_host_wait_for_link(struct starfive_jh7110_pcie *pcie)
+{
+ int retries;
+
+ /* Check if the link is up or not */
+ for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+ if (starfive_pcie_link_up(&pcie->plda)) {
+ dev_info(pcie->plda.dev, "port link up\n");
+ return 0;
+ }
+ usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int starfive_pcie_enable_phy(struct device *dev,
+ struct starfive_jh7110_pcie *pcie)
+{
+ int ret;
+
+ if (!pcie->phy)
+ return 0;
+
+ ret = phy_init(pcie->phy);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to initialize pcie phy\n");
+
+ ret = phy_set_mode(pcie->phy, PHY_MODE_PCIE);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to set pcie mode\n");
+ goto err_phy_on;
+ }
+
+ ret = phy_power_on(pcie->phy);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to power on pcie phy\n");
+ goto err_phy_on;
+ }
+
+ return 0;
+
+err_phy_on:
+ phy_exit(pcie->phy);
+ return ret;
+}
+
+static void starfive_pcie_disable_phy(struct starfive_jh7110_pcie *pcie)
+{
+ phy_power_off(pcie->phy);
+ phy_exit(pcie->phy);
+}
+
+static void starfive_pcie_host_deinit(struct plda_pcie_rp *plda)
+{
+ struct starfive_jh7110_pcie *pcie =
+ container_of(plda, struct starfive_jh7110_pcie, plda);
+
+ starfive_pcie_clk_rst_deinit(pcie);
+ if (pcie->power_gpio)
+ gpiod_set_value_cansleep(pcie->power_gpio, 0);
+ starfive_pcie_disable_phy(pcie);
+}
+
+static int starfive_pcie_host_init(struct plda_pcie_rp *plda)
+{
+ struct starfive_jh7110_pcie *pcie =
+ container_of(plda, struct starfive_jh7110_pcie, plda);
+ struct device *dev = plda->dev;
+ int ret;
+ int i;
+
+ ret = starfive_pcie_enable_phy(dev, pcie);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(pcie->reg_syscon,
+ pcie->stg_pcie_base + STG_SYSCON_RP_NEP_OFFSET,
+ STG_SYSCON_K_RP_NEP, STG_SYSCON_K_RP_NEP);
+
+ regmap_update_bits(pcie->reg_syscon,
+ pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
+ STG_SYSCON_CKREF_SRC_MASK,
+ FIELD_PREP(STG_SYSCON_CKREF_SRC_MASK, 2));
+
+ regmap_update_bits(pcie->reg_syscon,
+ pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
+ STG_SYSCON_CLKREQ, STG_SYSCON_CLKREQ);
+
+ ret = starfive_pcie_clk_rst_init(pcie);
+ if (ret)
+ return ret;
+
+ if (pcie->power_gpio)
+ gpiod_set_value_cansleep(pcie->power_gpio, 1);
+
+ if (pcie->reset_gpio)
+ gpiod_set_value_cansleep(pcie->reset_gpio, 1);
+
+ /* Disable physical functions except #0 */
+ for (i = 1; i < PCIE_FUNC_NUM; i++) {
+ regmap_update_bits(pcie->reg_syscon,
+ pcie->stg_pcie_base + STG_SYSCON_AR_OFFSET,
+ STG_SYSCON_AXI4_SLVL_AR_MASK,
+ STG_SYSCON_AXI4_SLVL_PHY_AR(i));
+
+ regmap_update_bits(pcie->reg_syscon,
+ pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
+ STG_SYSCON_AXI4_SLVL_AW_MASK,
+ STG_SYSCON_AXI4_SLVL_PHY_AW(i));
+
+ plda_pcie_disable_func(plda);
+ }
+
+ regmap_update_bits(pcie->reg_syscon,
+ pcie->stg_pcie_base + STG_SYSCON_AR_OFFSET,
+ STG_SYSCON_AXI4_SLVL_AR_MASK, 0);
+ regmap_update_bits(pcie->reg_syscon,
+ pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
+ STG_SYSCON_AXI4_SLVL_AW_MASK, 0);
+
+ plda_pcie_enable_root_port(plda);
+ plda_pcie_write_rc_bar(plda, 0);
+
+ /* PCIe PCI Standard Configuration Identification Settings. */
+ plda_pcie_set_standard_class(plda);
+
+ /*
+ * The LTR message forwarding of PCIe Message Reception was set by core
+ * as default, but the forward id & addr are also need to be reset.
+ * If we do not disable LTR message forwarding here, or set a legal
+ * forwarding address, the kernel will get stuck after the driver probe.
+ * To workaround, disable the LTR message forwarding support on
+ * PCIe Message Reception.
+ */
+ plda_pcie_disable_ltr(plda);
+
+ /* Prefetchable memory window 64-bit addressing support */
+ plda_pcie_set_pref_win_64bit(plda);
+
+ /*
+ * Ensure that PERST has been asserted for at least 100 ms,
+ * the sleep value is T_PVPERL from PCIe CEM spec r2.0 (Table 2-4)
+ */
+ msleep(100);
+ if (pcie->reset_gpio)
+ gpiod_set_value_cansleep(pcie->reset_gpio, 0);
+
+ /*
+ * With a Downstream Port (<=5GT/s), software must wait a minimum
+ * of 100ms following exit from a conventional reset before
+ * sending a configuration request to the device.
+ */
+ msleep(PCIE_RESET_CONFIG_DEVICE_WAIT_MS);
+
+ if (starfive_pcie_host_wait_for_link(pcie))
+ dev_info(dev, "port link down\n");
+
+ return 0;
+}
+
+static const struct plda_pcie_host_ops sf_host_ops = {
+ .host_init = starfive_pcie_host_init,
+ .host_deinit = starfive_pcie_host_deinit,
+};
+
+static int starfive_pcie_probe(struct platform_device *pdev)
+{
+ struct starfive_jh7110_pcie *pcie;
+ struct device *dev = &pdev->dev;
+ struct plda_pcie_rp *plda;
+ int ret;
+
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ plda = &pcie->plda;
+ plda->dev = dev;
+
+ ret = starfive_pcie_parse_dt(pcie, dev);
+ if (ret)
+ return ret;
+
+ plda->host_ops = &sf_host_ops;
+ plda->num_events = NUM_PLDA_EVENTS;
+ ret = plda_pcie_host_init(&pcie->plda, &starfive_pcie_ops);
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ platform_set_drvdata(pdev, pcie);
+
+ return 0;
+}
+
+static void starfive_pcie_remove(struct platform_device *pdev)
+{
+ struct starfive_jh7110_pcie *pcie = platform_get_drvdata(pdev);
+
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ plda_pcie_host_deinit(&pcie->plda);
+ platform_set_drvdata(pdev, NULL);
+}
+
+static int starfive_pcie_suspend_noirq(struct device *dev)
+{
+ struct starfive_jh7110_pcie *pcie = dev_get_drvdata(dev);
+
+ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
+ starfive_pcie_disable_phy(pcie);
+
+ return 0;
+}
+
+static int starfive_pcie_resume_noirq(struct device *dev)
+{
+ struct starfive_jh7110_pcie *pcie = dev_get_drvdata(dev);
+ int ret;
+
+ ret = starfive_pcie_enable_phy(dev, pcie);
+ if (ret)
+ return ret;
+
+ ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks\n");
+ starfive_pcie_disable_phy(pcie);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops starfive_pcie_pm_ops = {
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(starfive_pcie_suspend_noirq,
+ starfive_pcie_resume_noirq)
+};
+
+static const struct of_device_id starfive_pcie_of_match[] = {
+ { .compatible = "starfive,jh7110-pcie", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, starfive_pcie_of_match);
+
+static struct platform_driver starfive_pcie_driver = {
+ .driver = {
+ .name = "pcie-starfive",
+ .of_match_table = of_match_ptr(starfive_pcie_of_match),
+ .pm = pm_sleep_ptr(&starfive_pcie_pm_ops),
+ },
+ .probe = starfive_pcie_probe,
+ .remove_new = starfive_pcie_remove,
+};
+module_platform_driver(starfive_pcie_driver);
+
+MODULE_DESCRIPTION("StarFive JH7110 PCIe host driver");
+MODULE_LICENSE("GPL v2");
--
2.17.1
PolarFire implements its own PCIe interrupts, additional to the regular
PCIe interrupts, due to lack of an MSI controller, so the interrupt to
event number mapping is different to the PLDA local interrupts,
necessitating a custom get_events() implementation.
plda_get_events() adds interrupt register to PLDA local event num mapping
codes except DMA engine interrupt events. The DMA engine interrupt events
are implemented by vendors.
Signed-off-by: Minda Chen <[email protected]>
Acked-by: Conor Dooley <[email protected]>
---
.../pci/controller/plda/pcie-microchip-host.c | 35 ++++++++++++++++++-
drivers/pci/controller/plda/pcie-plda.h | 33 +++++++++++++++++
2 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 00250781b11c..fd0d92c3d03f 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -627,6 +627,26 @@ static u32 mc_get_events(struct plda_pcie_rp *port)
return events;
}
+static u32 plda_get_events(struct plda_pcie_rp *port)
+{
+ u32 events, val, origin;
+
+ origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
+
+ /* Error events and doorbell events */
+ events = (origin & ERROR_AND_DOORBELL_MASK) >> A_ATR_EVT_POST_ERR_SHIFT;
+
+ /* INTx events */
+ if (origin & PM_MSI_INT_INTX_MASK)
+ events |= BIT(EVENT_PM_MSI_INT_INTX);
+
+ /* MSI event and sys events */
+ val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
+ events |= val << EVENT_PM_MSI_INT_MSI;
+
+ return events;
+}
+
static irqreturn_t mc_event_handler(int irq, void *dev_id)
{
struct plda_pcie_rp *port = dev_id;
@@ -657,7 +677,7 @@ static void plda_handle_event(struct irq_desc *desc)
chained_irq_enter(chip, desc);
- events = mc_get_events(port);
+ events = port->event_ops->get_events(port);
for_each_set_bit(bit, &events, port->num_events)
generic_handle_domain_irq(port->event_domain, bit);
@@ -751,6 +771,10 @@ static struct irq_chip mc_event_irq_chip = {
.irq_unmask = mc_unmask_event_irq,
};
+static const struct plda_event_ops plda_event_ops = {
+ .get_events = plda_get_events,
+};
+
static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hwirq)
{
@@ -816,6 +840,10 @@ static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
0, event_cause[event].sym, plda);
}
+static const struct plda_event_ops mc_event_ops = {
+ .get_events = mc_get_events,
+};
+
static const struct plda_event mc_event = {
.request_event_irq = mc_request_event_irq,
.intx_event = EVENT_LOCAL_PM_MSI_INT_INTX,
@@ -932,6 +960,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
int i, intx_irq, msi_irq, event_irq;
int ret;
+ if (!port->event_ops)
+ port->event_ops = &plda_event_ops;
+
ret = plda_pcie_init_irq_domains(port);
if (ret) {
dev_err(dev, "failed creating IRQ domains\n");
@@ -1008,6 +1039,8 @@ static int mc_platform_init(struct pci_config_window *cfg)
if (ret)
return ret;
+ port->plda.event_ops = &mc_event_ops;
+
/* Address translation is up; safe to enable interrupts */
ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
if (ret)
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index fba7343f9a96..dd8bc2750bfc 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -40,6 +40,7 @@
#define P_ATR_EVT_DISCARD_ERR_SHIFT 22
#define P_ATR_EVT_DOORBELL_MASK 0x00000000u
#define P_ATR_EVT_DOORBELL_SHIFT 23
+#define ERROR_AND_DOORBELL_MASK GENMASK(23, 16)
#define PM_MSI_INT_INTA_MASK 0x01000000u
#define PM_MSI_INT_INTA_SHIFT 24
#define PM_MSI_INT_INTB_MASK 0x02000000u
@@ -58,6 +59,7 @@
#define PM_MSI_INT_EVENTS_SHIFT 30
#define PM_MSI_INT_SYS_ERR_MASK 0x80000000u
#define PM_MSI_INT_SYS_ERR_SHIFT 31
+#define SYS_AND_MSI_MASK GENMASK(31, 28)
#define NUM_LOCAL_EVENTS 15
#define ISTATUS_LOCAL 0x184
#define IMASK_HOST 0x188
@@ -102,6 +104,36 @@
#define EVENT_PM_MSI_INT_SYS_ERR 12
#define NUM_PLDA_EVENTS 13
+/*
+ * PLDA local interrupt register
+ *
+ * 31 27 23 15 7 0
+ * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
+ * |12|11|10|9| intx |7|6|5|4|3|2|1|0| DMA error | DMA end |
+ * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
+ * 0: AXI post error
+ * 1: AXI fetch error
+ * 2: AXI discard error
+ * 3: AXI doorbell
+ * 4: PCIe post error
+ * 5: PCIe fetch error
+ * 6: PCIe discard error
+ * 7: PCIe doorbell
+ * 8: 4 INTx interruts
+ * 9: MSI interrupt
+ * 10: AER event
+ * 11: PM/LTR/Hotplug
+ * 12: System error
+ * DMA error : reserved for vendor implement
+ * DMA end : reserved for vendor implement
+ */
+
+struct plda_pcie_rp;
+
+struct plda_event_ops {
+ u32 (*get_events)(struct plda_pcie_rp *pcie);
+};
+
struct plda_msi {
struct mutex lock; /* Protect used bitmap */
struct irq_domain *msi_domain;
@@ -117,6 +149,7 @@ struct plda_pcie_rp {
struct irq_domain *event_domain;
raw_spinlock_t lock;
struct plda_msi msi;
+ const struct plda_event_ops *event_ops;
void __iomem *bridge_addr;
int num_events;
};
--
2.17.1
The INTx and MSI interrupt event num is different in Microchip and
StarFive platform.
Signed-off-by: Minda Chen <[email protected]>
Acked-by: Conor Dooley <[email protected]>
---
drivers/pci/controller/plda/pcie-microchip-host.c | 6 ++++--
drivers/pci/controller/plda/pcie-plda.h | 2 ++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
index 624e4e2e97d3..00250781b11c 100644
--- a/drivers/pci/controller/plda/pcie-microchip-host.c
+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
@@ -818,6 +818,8 @@ static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
static const struct plda_event mc_event = {
.request_event_irq = mc_request_event_irq,
+ .intx_event = EVENT_LOCAL_PM_MSI_INT_INTX,
+ .msi_event = EVENT_LOCAL_PM_MSI_INT_MSI,
};
static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
@@ -961,7 +963,7 @@ static int plda_init_interrupts(struct platform_device *pdev,
}
intx_irq = irq_create_mapping(port->event_domain,
- EVENT_LOCAL_PM_MSI_INT_INTX);
+ event->intx_event);
if (!intx_irq) {
dev_err(dev, "failed to map INTx interrupt\n");
return -ENXIO;
@@ -971,7 +973,7 @@ static int plda_init_interrupts(struct platform_device *pdev,
irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
msi_irq = irq_create_mapping(port->event_domain,
- EVENT_LOCAL_PM_MSI_INT_MSI);
+ event->msi_event);
if (!msi_irq)
return -ENXIO;
diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
index 28ed1374e1de..fba7343f9a96 100644
--- a/drivers/pci/controller/plda/pcie-plda.h
+++ b/drivers/pci/controller/plda/pcie-plda.h
@@ -124,6 +124,8 @@ struct plda_pcie_rp {
struct plda_event {
int (*request_event_irq)(struct plda_pcie_rp *pcie,
int event_irq, int event);
+ int intx_event;
+ int msi_event;
};
void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
--
2.17.1
On 2023/12/14 15:28, Minda Chen wrote:
> PolarFire PCIE event IRQs includes PLDA local interrupts and PolarFire
> their own IRQs. PolarFire PCIe event irq_chip ops using an event_desc to
> unify different IRQ register addresses. On PLDA sides, PLDA irqchip codes
> only require to set PLDA local interrupt register. So the PLDA irqchip ops
> codes can not be extracted from PolarFire codes.
>
> To support PLDA its own event IRQ process, implements PLDA irqchip ops and
> add event irqchip field to struct pcie_plda_rp.
>
> Signed-off-by: Minda Chen <[email protected]>
> ---
> .../pci/controller/plda/pcie-microchip-host.c | 65 ++++++++++++++++++-
> drivers/pci/controller/plda/pcie-plda.h | 3 +
> 2 files changed, 67 insertions(+), 1 deletion(-)
>
Hi Conor
Could you take time to review this patch? For I using event irq chip instead of event ops and the whole patch have been changed. I think it's better
And I added the implementation of PLDA event irqchip and make it easier to claim the necessity of the modification.
If you approve this, I will add back the review tag. Thanks
Hi Lorenzo
Have you reviewed this patch? Does the commit message and the codes are can be approved ?Thanks
> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
> index fd0d92c3d03f..ff40c1622173 100644
> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
> @@ -771,6 +771,63 @@ static struct irq_chip mc_event_irq_chip = {
> .irq_unmask = mc_unmask_event_irq,
> };
> > +static u32 plda_hwirq_to_mask(int hwirq)
> +{
> + u32 mask;
> +
> + if (hwirq < EVENT_PM_MSI_INT_INTX)
> + mask = BIT(hwirq + A_ATR_EVT_POST_ERR_SHIFT);
> + else if (hwirq == EVENT_PM_MSI_INT_INTX)
> + mask = PM_MSI_INT_INTX_MASK;
> + else
> + mask = BIT(hwirq + PM_MSI_TO_MASK_OFFSET);
> +
> + return mask;
> +}
> +
> +static void plda_ack_event_irq(struct irq_data *data)
> +{
> + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> +
> + writel_relaxed(plda_hwirq_to_mask(data->hwirq),
> + port->bridge_addr + ISTATUS_LOCAL);
> +}
> +
> +static void plda_mask_event_irq(struct irq_data *data)
> +{
> + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> + u32 mask, val;
> +
> + mask = plda_hwirq_to_mask(data->hwirq);
> +
> + raw_spin_lock(&port->lock);
> + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
> + val &= ~mask;
> + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
> + raw_spin_unlock(&port->lock);
> +}
> +
> +static void plda_unmask_event_irq(struct irq_data *data)
> +{
> + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> + u32 mask, val;
> +
> + mask = plda_hwirq_to_mask(data->hwirq);
> +
> + raw_spin_lock(&port->lock);
> + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
> + val |= mask;
> + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
> + raw_spin_unlock(&port->lock);
> +}
> +
> +static struct irq_chip plda_event_irq_chip = {
> + .name = "PLDA PCIe EVENT",
> + .irq_ack = plda_ack_event_irq,
> + .irq_mask = plda_mask_event_irq,
> + .irq_unmask = plda_unmask_event_irq,
> +};
> +
> static const struct plda_event_ops plda_event_ops = {
> .get_events = plda_get_events,
> };
> @@ -778,7 +835,9 @@ static const struct plda_event_ops plda_event_ops = {
> static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
> irq_hw_number_t hwirq)
> {
> - irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
> + struct plda_pcie_rp *port = (void *)domain->host_data;
> +
> + irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
> irq_set_chip_data(irq, domain->host_data);
>
> return 0;
> @@ -963,6 +1022,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
> if (!port->event_ops)
> port->event_ops = &plda_event_ops;
>
> + if (!port->event_irq_chip)
> + port->event_irq_chip = &plda_event_irq_chip;
> +
> ret = plda_pcie_init_irq_domains(port);
> if (ret) {
> dev_err(dev, "failed creating IRQ domains\n");
> @@ -1040,6 +1102,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
> return ret;
>
> port->plda.event_ops = &mc_event_ops;
> + port->plda.event_irq_chip = &mc_event_irq_chip;
>
> /* Address translation is up; safe to enable interrupts */
> ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
> diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
> index dd8bc2750bfc..24ac50c458dc 100644
> --- a/drivers/pci/controller/plda/pcie-plda.h
> +++ b/drivers/pci/controller/plda/pcie-plda.h
> @@ -128,6 +128,8 @@
> * DMA end : reserved for vendor implement
> */
>
> +#define PM_MSI_TO_MASK_OFFSET 19
> +
> struct plda_pcie_rp;
>
> struct plda_event_ops {
> @@ -150,6 +152,7 @@ struct plda_pcie_rp {
> raw_spinlock_t lock;
> struct plda_msi msi;
> const struct plda_event_ops *event_ops;
> + const struct irq_chip *event_irq_chip;
> void __iomem *bridge_addr;
> int num_events;
> };
On Thu, Dec 21, 2023 at 06:56:22PM +0800, Minda Chen wrote:
>
>
> On 2023/12/14 15:28, Minda Chen wrote:
> > PolarFire PCIE event IRQs includes PLDA local interrupts and PolarFire
> > their own IRQs. PolarFire PCIe event irq_chip ops using an event_desc to
> > unify different IRQ register addresses. On PLDA sides, PLDA irqchip codes
> > only require to set PLDA local interrupt register. So the PLDA irqchip ops
> > codes can not be extracted from PolarFire codes.
> >
> > To support PLDA its own event IRQ process, implements PLDA irqchip ops and
> > add event irqchip field to struct pcie_plda_rp.
> >
> > Signed-off-by: Minda Chen <[email protected]>
> > ---
> > .../pci/controller/plda/pcie-microchip-host.c | 65 ++++++++++++++++++-
> > drivers/pci/controller/plda/pcie-plda.h | 3 +
> > 2 files changed, 67 insertions(+), 1 deletion(-)
> >
> Hi Conor
> Could you take time to review this patch? For I using event irq chip instead of event ops and the whole patch have been changed. I think it's better
> And I added the implementation of PLDA event irqchip and make it easier to claim the necessity of the modification.
> If you approve this, I will add back the review tag. Thanks
>
> Hi Lorenzo
> Have you reviewed this patch? Does the commit message and the codes are can be approved ?Thanks
>
Please wrap the lines at 75 columns in length.
I have not reviewed but I am still struggling to understand the
commit log, I apologise, I can try to review the series and figure
out what the patch is doing but I would appreciate if commits logs
could be made easier to parse.
Thanks,
Lorenzo
> > diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
> > index fd0d92c3d03f..ff40c1622173 100644
> > --- a/drivers/pci/controller/plda/pcie-microchip-host.c
> > +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
> > @@ -771,6 +771,63 @@ static struct irq_chip mc_event_irq_chip = {
> > .irq_unmask = mc_unmask_event_irq,
> > };
> > > +static u32 plda_hwirq_to_mask(int hwirq)
> > +{
> > + u32 mask;
> > +
> > + if (hwirq < EVENT_PM_MSI_INT_INTX)
> > + mask = BIT(hwirq + A_ATR_EVT_POST_ERR_SHIFT);
> > + else if (hwirq == EVENT_PM_MSI_INT_INTX)
> > + mask = PM_MSI_INT_INTX_MASK;
> > + else
> > + mask = BIT(hwirq + PM_MSI_TO_MASK_OFFSET);
> > +
> > + return mask;
> > +}
> > +
> > +static void plda_ack_event_irq(struct irq_data *data)
> > +{
> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> > +
> > + writel_relaxed(plda_hwirq_to_mask(data->hwirq),
> > + port->bridge_addr + ISTATUS_LOCAL);
> > +}
> > +
> > +static void plda_mask_event_irq(struct irq_data *data)
> > +{
> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> > + u32 mask, val;
> > +
> > + mask = plda_hwirq_to_mask(data->hwirq);
> > +
> > + raw_spin_lock(&port->lock);
> > + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
> > + val &= ~mask;
> > + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
> > + raw_spin_unlock(&port->lock);
> > +}
> > +
> > +static void plda_unmask_event_irq(struct irq_data *data)
> > +{
> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> > + u32 mask, val;
> > +
> > + mask = plda_hwirq_to_mask(data->hwirq);
> > +
> > + raw_spin_lock(&port->lock);
> > + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
> > + val |= mask;
> > + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
> > + raw_spin_unlock(&port->lock);
> > +}
> > +
> > +static struct irq_chip plda_event_irq_chip = {
> > + .name = "PLDA PCIe EVENT",
> > + .irq_ack = plda_ack_event_irq,
> > + .irq_mask = plda_mask_event_irq,
> > + .irq_unmask = plda_unmask_event_irq,
> > +};
> > +
> > static const struct plda_event_ops plda_event_ops = {
> > .get_events = plda_get_events,
> > };
> > @@ -778,7 +835,9 @@ static const struct plda_event_ops plda_event_ops = {
> > static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
> > irq_hw_number_t hwirq)
> > {
> > - irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
> > + struct plda_pcie_rp *port = (void *)domain->host_data;
> > +
> > + irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
> > irq_set_chip_data(irq, domain->host_data);
> >
> > return 0;
> > @@ -963,6 +1022,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
> > if (!port->event_ops)
> > port->event_ops = &plda_event_ops;
> >
> > + if (!port->event_irq_chip)
> > + port->event_irq_chip = &plda_event_irq_chip;
> > +
> > ret = plda_pcie_init_irq_domains(port);
> > if (ret) {
> > dev_err(dev, "failed creating IRQ domains\n");
> > @@ -1040,6 +1102,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
> > return ret;
> >
> > port->plda.event_ops = &mc_event_ops;
> > + port->plda.event_irq_chip = &mc_event_irq_chip;
> >
> > /* Address translation is up; safe to enable interrupts */
> > ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
> > diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
> > index dd8bc2750bfc..24ac50c458dc 100644
> > --- a/drivers/pci/controller/plda/pcie-plda.h
> > +++ b/drivers/pci/controller/plda/pcie-plda.h
> > @@ -128,6 +128,8 @@
> > * DMA end : reserved for vendor implement
> > */
> >
> > +#define PM_MSI_TO_MASK_OFFSET 19
> > +
> > struct plda_pcie_rp;
> >
> > struct plda_event_ops {
> > @@ -150,6 +152,7 @@ struct plda_pcie_rp {
> > raw_spinlock_t lock;
> > struct plda_msi msi;
> > const struct plda_event_ops *event_ops;
> > + const struct irq_chip *event_irq_chip;
> > void __iomem *bridge_addr;
> > int num_events;
> > };
On 2023/12/21 23:32, Lorenzo Pieralisi wrote:
> On Thu, Dec 21, 2023 at 06:56:22PM +0800, Minda Chen wrote:
>>
>>
>> On 2023/12/14 15:28, Minda Chen wrote:
>> > PolarFire PCIE event IRQs includes PLDA local interrupts and PolarFire
>> > their own IRQs. PolarFire PCIe event irq_chip ops using an event_desc to
>> > unify different IRQ register addresses. On PLDA sides, PLDA irqchip codes
>> > only require to set PLDA local interrupt register. So the PLDA irqchip ops
>> > codes can not be extracted from PolarFire codes.
>> >
>> > To support PLDA its own event IRQ process, implements PLDA irqchip ops and
>> > add event irqchip field to struct pcie_plda_rp.
>> >
>> > Signed-off-by: Minda Chen <[email protected]>
>> > ---
>> > .../pci/controller/plda/pcie-microchip-host.c | 65 ++++++++++++++++++-
>> > drivers/pci/controller/plda/pcie-plda.h | 3 +
>> > 2 files changed, 67 insertions(+), 1 deletion(-)
>> >
>> Hi Conor
>> Could you take time to review this patch? For I using event irq chip instead of event ops and the whole patch have been changed. I think it's better
>> And I added the implementation of PLDA event irqchip and make it easier to claim the necessity of the modification.
>> If you approve this, I will add back the review tag. Thanks
>>
>> Hi Lorenzo
>> Have you reviewed this patch? Does the commit message and the codes are can be approved ?Thanks
>>
>
> Please wrap the lines at 75 columns in length.
>
OK
> I have not reviewed but I am still struggling to understand the
> commit log, I apologise, I can try to review the series and figure
> out what the patch is doing but I would appreciate if commits logs
> could be made easier to parse.
>
> Thanks,
> Lorenzo
>
The commit message it is not good.
I draw a graph about the PCIe global event interrupt domain
(related to patch 10- 16).
Actually all these interrupts patches are for extracting the common
PLDA codes to pcie-plda-host.c and do not change microchip's codes logic.
+----------------------------------------------------------+
| microchip Global event interrupt domain |
+-----------------------------------+-----------+----------+
| | microchip | PLDA |
| | event num |(StarFive)|
| | |event num |
+-----------------------------------+-----------+----------+
| | 0 | |
| | | |
(mc pcie |microchip platform event interrupt | | |
int line) | | | |
------------| | | |
| |10 | |
+-----------------------------------+-----------+----------+
| PLDA host DMA interrupt |11 | |
| (int number is not fixed, defined | | |
| by vendor) |14 | |
+--+-----------------------------------+---------- +----------+-+
| | PLDA event interrupt |15 |0 | |
| | (int number is fixed) | | | |
---------|--| | | | |
(Starfive| | | | | |
pcie int | | +------------------+ | | | |
line) | | |INTx event domain | | | | |
| | +------------------+ | | | |
| | | | | |
| | +------------------+ | | | |
| | |MSI event domain | | | | |
| | +------------------+ | | | |
| | |27 |12 | |
| +---------------------------------+-+-----------+----------+ |
| extract PLDA event part to common PLDA file. |
+---------------------------------------------------------------+
>> > diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
>> > index fd0d92c3d03f..ff40c1622173 100644
>> > --- a/drivers/pci/controller/plda/pcie-microchip-host.c
>> > +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
>> > @@ -771,6 +771,63 @@ static struct irq_chip mc_event_irq_chip = {
>> > .irq_unmask = mc_unmask_event_irq,
>> > };
>> > > +static u32 plda_hwirq_to_mask(int hwirq)
>> > +{
>> > + u32 mask;
>> > +
>> > + if (hwirq < EVENT_PM_MSI_INT_INTX)
>> > + mask = BIT(hwirq + A_ATR_EVT_POST_ERR_SHIFT);
>> > + else if (hwirq == EVENT_PM_MSI_INT_INTX)
>> > + mask = PM_MSI_INT_INTX_MASK;
>> > + else
>> > + mask = BIT(hwirq + PM_MSI_TO_MASK_OFFSET);
>> > +
>> > + return mask;
>> > +}
>> > +
>> > +static void plda_ack_event_irq(struct irq_data *data)
>> > +{
>> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> > +
>> > + writel_relaxed(plda_hwirq_to_mask(data->hwirq),
>> > + port->bridge_addr + ISTATUS_LOCAL);
>> > +}
>> > +
>> > +static void plda_mask_event_irq(struct irq_data *data)
>> > +{
>> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> > + u32 mask, val;
>> > +
>> > + mask = plda_hwirq_to_mask(data->hwirq);
>> > +
>> > + raw_spin_lock(&port->lock);
>> > + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
>> > + val &= ~mask;
>> > + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
>> > + raw_spin_unlock(&port->lock);
>> > +}
>> > +
>> > +static void plda_unmask_event_irq(struct irq_data *data)
>> > +{
>> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> > + u32 mask, val;
>> > +
>> > + mask = plda_hwirq_to_mask(data->hwirq);
>> > +
>> > + raw_spin_lock(&port->lock);
>> > + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
>> > + val |= mask;
>> > + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
>> > + raw_spin_unlock(&port->lock);
>> > +}
>> > +
>> > +static struct irq_chip plda_event_irq_chip = {
>> > + .name = "PLDA PCIe EVENT",
>> > + .irq_ack = plda_ack_event_irq,
>> > + .irq_mask = plda_mask_event_irq,
>> > + .irq_unmask = plda_unmask_event_irq,
>> > +};
>> > +
>> > static const struct plda_event_ops plda_event_ops = {
>> > .get_events = plda_get_events,
>> > };
>> > @@ -778,7 +835,9 @@ static const struct plda_event_ops plda_event_ops = {
>> > static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
>> > irq_hw_number_t hwirq)
>> > {
>> > - irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
>> > + struct plda_pcie_rp *port = (void *)domain->host_data;
>> > +
>> > + irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
>> > irq_set_chip_data(irq, domain->host_data);
>> >
>> > return 0;
>> > @@ -963,6 +1022,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
>> > if (!port->event_ops)
>> > port->event_ops = &plda_event_ops;
>> >
>> > + if (!port->event_irq_chip)
>> > + port->event_irq_chip = &plda_event_irq_chip;
>> > +
>> > ret = plda_pcie_init_irq_domains(port);
>> > if (ret) {
>> > dev_err(dev, "failed creating IRQ domains\n");
>> > @@ -1040,6 +1102,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
>> > return ret;
>> >
>> > port->plda.event_ops = &mc_event_ops;
>> > + port->plda.event_irq_chip = &mc_event_irq_chip;
>> >
>> > /* Address translation is up; safe to enable interrupts */
>> > ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
>> > diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
>> > index dd8bc2750bfc..24ac50c458dc 100644
>> > --- a/drivers/pci/controller/plda/pcie-plda.h
>> > +++ b/drivers/pci/controller/plda/pcie-plda.h
>> > @@ -128,6 +128,8 @@
>> > * DMA end : reserved for vendor implement
>> > */
>> >
>> > +#define PM_MSI_TO_MASK_OFFSET 19
>> > +
>> > struct plda_pcie_rp;
>> >
>> > struct plda_event_ops {
>> > @@ -150,6 +152,7 @@ struct plda_pcie_rp {
>> > raw_spinlock_t lock;
>> > struct plda_msi msi;
>> > const struct plda_event_ops *event_ops;
>> > + const struct irq_chip *event_irq_chip;
>> > void __iomem *bridge_addr;
>> > int num_events;
>> > };
[+Thomas]
On Fri, Dec 22, 2023 at 07:18:48PM +0800, Minda Chen wrote:
>
>
> On 2023/12/21 23:32, Lorenzo Pieralisi wrote:
> > On Thu, Dec 21, 2023 at 06:56:22PM +0800, Minda Chen wrote:
> >>
> >>
> >> On 2023/12/14 15:28, Minda Chen wrote:
> >> > PolarFire PCIE event IRQs includes PLDA local interrupts and PolarFire
> >> > their own IRQs. PolarFire PCIe event irq_chip ops using an event_desc to
> >> > unify different IRQ register addresses. On PLDA sides, PLDA irqchip codes
> >> > only require to set PLDA local interrupt register. So the PLDA irqchip ops
> >> > codes can not be extracted from PolarFire codes.
> >> >
> >> > To support PLDA its own event IRQ process, implements PLDA irqchip ops and
> >> > add event irqchip field to struct pcie_plda_rp.
> >> >
> >> > Signed-off-by: Minda Chen <[email protected]>
> >> > ---
> >> > .../pci/controller/plda/pcie-microchip-host.c | 65 ++++++++++++++++++-
> >> > drivers/pci/controller/plda/pcie-plda.h | 3 +
> >> > 2 files changed, 67 insertions(+), 1 deletion(-)
> >> >
> >> Hi Conor
> >> Could you take time to review this patch? For I using event irq chip instead of event ops and the whole patch have been changed. I think it's better
> >> And I added the implementation of PLDA event irqchip and make it easier to claim the necessity of the modification.
> >> If you approve this, I will add back the review tag. Thanks
> >>
> >> Hi Lorenzo
> >> Have you reviewed this patch? Does the commit message and the codes are can be approved ?Thanks
> >>
> >
> > Please wrap the lines at 75 columns in length.
> >
> OK
> > I have not reviewed but I am still struggling to understand the
> > commit log, I apologise, I can try to review the series and figure
> > out what the patch is doing but I would appreciate if commits logs
> > could be made easier to parse.
> >
> > Thanks,
> > Lorenzo
> >
>
> The commit message it is not good.
>
> I draw a graph about the PCIe global event interrupt domain
> (related to patch 10- 16).
> Actually all these interrupts patches are for extracting the common
> PLDA codes to pcie-plda-host.c and do not change microchip's codes logic.
s/codes/code (please apply this to the the full series)
I will have a look at the code but I can't rewrite the commit log myself
(it does not scale I am afraid), as it stands I don't understand it and
that's a problem, I am sorry but that's important.
I added Thomas (you should CC him for irqchip [only] changes) if he
has time to review these irqchip changes to make sure they are proper.
Thanks,
Lorenzo
> +----------------------------------------------------------+
> | microchip Global event interrupt domain |
> +-----------------------------------+-----------+----------+
> | | microchip | PLDA |
> | | event num |(StarFive)|
> | | |event num |
> +-----------------------------------+-----------+----------+
> | | 0 | |
> | | | |
> (mc pcie |microchip platform event interrupt | | |
> int line) | | | |
> ------------| | | |
> | |10 | |
> +-----------------------------------+-----------+----------+
> | PLDA host DMA interrupt |11 | |
> | (int number is not fixed, defined | | |
> | by vendor) |14 | |
> +--+-----------------------------------+---------- +----------+-+
> | | PLDA event interrupt |15 |0 | |
> | | (int number is fixed) | | | |
> ---------|--| | | | |
> (Starfive| | | | | |
> pcie int | | +------------------+ | | | |
> line) | | |INTx event domain | | | | |
> | | +------------------+ | | | |
> | | | | | |
> | | +------------------+ | | | |
> | | |MSI event domain | | | | |
> | | +------------------+ | | | |
> | | |27 |12 | |
> | +---------------------------------+-+-----------+----------+ |
> | extract PLDA event part to common PLDA file. |
> +---------------------------------------------------------------+
>
>
> >> > diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
> >> > index fd0d92c3d03f..ff40c1622173 100644
> >> > --- a/drivers/pci/controller/plda/pcie-microchip-host.c
> >> > +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
> >> > @@ -771,6 +771,63 @@ static struct irq_chip mc_event_irq_chip = {
> >> > .irq_unmask = mc_unmask_event_irq,
> >> > };
> >> > > +static u32 plda_hwirq_to_mask(int hwirq)
> >> > +{
> >> > + u32 mask;
> >> > +
> >> > + if (hwirq < EVENT_PM_MSI_INT_INTX)
> >> > + mask = BIT(hwirq + A_ATR_EVT_POST_ERR_SHIFT);
> >> > + else if (hwirq == EVENT_PM_MSI_INT_INTX)
> >> > + mask = PM_MSI_INT_INTX_MASK;
> >> > + else
> >> > + mask = BIT(hwirq + PM_MSI_TO_MASK_OFFSET);
> >> > +
> >> > + return mask;
> >> > +}
> >> > +
> >> > +static void plda_ack_event_irq(struct irq_data *data)
> >> > +{
> >> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> >> > +
> >> > + writel_relaxed(plda_hwirq_to_mask(data->hwirq),
> >> > + port->bridge_addr + ISTATUS_LOCAL);
> >> > +}
> >> > +
> >> > +static void plda_mask_event_irq(struct irq_data *data)
> >> > +{
> >> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> >> > + u32 mask, val;
> >> > +
> >> > + mask = plda_hwirq_to_mask(data->hwirq);
> >> > +
> >> > + raw_spin_lock(&port->lock);
> >> > + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
> >> > + val &= ~mask;
> >> > + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
> >> > + raw_spin_unlock(&port->lock);
> >> > +}
> >> > +
> >> > +static void plda_unmask_event_irq(struct irq_data *data)
> >> > +{
> >> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> >> > + u32 mask, val;
> >> > +
> >> > + mask = plda_hwirq_to_mask(data->hwirq);
> >> > +
> >> > + raw_spin_lock(&port->lock);
> >> > + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
> >> > + val |= mask;
> >> > + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
> >> > + raw_spin_unlock(&port->lock);
> >> > +}
> >> > +
> >> > +static struct irq_chip plda_event_irq_chip = {
> >> > + .name = "PLDA PCIe EVENT",
> >> > + .irq_ack = plda_ack_event_irq,
> >> > + .irq_mask = plda_mask_event_irq,
> >> > + .irq_unmask = plda_unmask_event_irq,
> >> > +};
> >> > +
> >> > static const struct plda_event_ops plda_event_ops = {
> >> > .get_events = plda_get_events,
> >> > };
> >> > @@ -778,7 +835,9 @@ static const struct plda_event_ops plda_event_ops = {
> >> > static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
> >> > irq_hw_number_t hwirq)
> >> > {
> >> > - irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
> >> > + struct plda_pcie_rp *port = (void *)domain->host_data;
> >> > +
> >> > + irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
> >> > irq_set_chip_data(irq, domain->host_data);
> >> >
> >> > return 0;
> >> > @@ -963,6 +1022,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
> >> > if (!port->event_ops)
> >> > port->event_ops = &plda_event_ops;
> >> >
> >> > + if (!port->event_irq_chip)
> >> > + port->event_irq_chip = &plda_event_irq_chip;
> >> > +
> >> > ret = plda_pcie_init_irq_domains(port);
> >> > if (ret) {
> >> > dev_err(dev, "failed creating IRQ domains\n");
> >> > @@ -1040,6 +1102,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
> >> > return ret;
> >> >
> >> > port->plda.event_ops = &mc_event_ops;
> >> > + port->plda.event_irq_chip = &mc_event_irq_chip;
> >> >
> >> > /* Address translation is up; safe to enable interrupts */
> >> > ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
> >> > diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
> >> > index dd8bc2750bfc..24ac50c458dc 100644
> >> > --- a/drivers/pci/controller/plda/pcie-plda.h
> >> > +++ b/drivers/pci/controller/plda/pcie-plda.h
> >> > @@ -128,6 +128,8 @@
> >> > * DMA end : reserved for vendor implement
> >> > */
> >> >
> >> > +#define PM_MSI_TO_MASK_OFFSET 19
> >> > +
> >> > struct plda_pcie_rp;
> >> >
> >> > struct plda_event_ops {
> >> > @@ -150,6 +152,7 @@ struct plda_pcie_rp {
> >> > raw_spinlock_t lock;
> >> > struct plda_msi msi;
> >> > const struct plda_event_ops *event_ops;
> >> > + const struct irq_chip *event_irq_chip;
> >> > void __iomem *bridge_addr;
> >> > int num_events;
> >> > };
On Thu, Dec 14, 2023 at 03:28:27PM +0800, Minda Chen wrote:
> Move setup functions to common pcie-plda-host.c. So these two functions
> can be re-used.
>
> Signed-off-by: Minda Chen <[email protected]>
> Reviewed-by: Conor Dooley <[email protected]>
> ---
> drivers/pci/controller/plda/Kconfig | 4 +
> drivers/pci/controller/plda/Makefile | 1 +
> .../pci/controller/plda/pcie-microchip-host.c | 59 --------------
> drivers/pci/controller/plda/pcie-plda-host.c | 80 +++++++++++++++++++
> drivers/pci/controller/plda/pcie-plda.h | 5 ++
> 5 files changed, 90 insertions(+), 59 deletions(-)
> create mode 100644 drivers/pci/controller/plda/pcie-plda-host.c
>
> diff --git a/drivers/pci/controller/plda/Kconfig b/drivers/pci/controller/plda/Kconfig
> index 5cb3be4fc98c..e54a82ee94f5 100644
> --- a/drivers/pci/controller/plda/Kconfig
> +++ b/drivers/pci/controller/plda/Kconfig
> @@ -3,10 +3,14 @@
> menu "PLDA-based PCIe controllers"
> depends on PCI
>
> +config PCIE_PLDA_HOST
> + bool
> +
> config PCIE_MICROCHIP_HOST
> tristate "Microchip AXI PCIe controller"
> depends on PCI_MSI && OF
> select PCI_HOST_COMMON
> + select PCIE_PLDA_HOST
> help
> Say Y here if you want kernel to support the Microchip AXI PCIe
> Host Bridge driver.
> diff --git a/drivers/pci/controller/plda/Makefile b/drivers/pci/controller/plda/Makefile
> index e1a265cbf91c..4340ab007f44 100644
> --- a/drivers/pci/controller/plda/Makefile
> +++ b/drivers/pci/controller/plda/Makefile
> @@ -1,2 +1,3 @@
> # SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_PCIE_PLDA_HOST) += pcie-plda-host.o
> obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
> index 31ca8d44ee2a..2e79bcc7c0a5 100644
> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
> @@ -838,65 +838,6 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
> return mc_allocate_msi_domains(port);
> }
>
> -static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
> - phys_addr_t axi_addr, phys_addr_t pci_addr,
> - size_t size)
> -{
> - u32 atr_sz = ilog2(size) - 1;
> - u32 val;
> -
> - if (index == 0)
> - val = PCIE_CONFIG_INTERFACE;
> - else
> - val = PCIE_TX_RX_INTERFACE;
> -
> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> - ATR0_AXI4_SLV0_TRSL_PARAM);
> -
> - val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
> - ATR_IMPL_ENABLE;
> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> - ATR0_AXI4_SLV0_SRCADDR_PARAM);
> -
> - val = upper_32_bits(axi_addr);
> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> - ATR0_AXI4_SLV0_SRC_ADDR);
> -
> - val = lower_32_bits(pci_addr);
> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> - ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
> -
> - val = upper_32_bits(pci_addr);
> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> - ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
> -
> - val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
> - val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
> - writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
> - writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
> -}
> -
> -static int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
> - struct plda_pcie_rp *port)
> -{
> - void __iomem *bridge_base_addr = port->bridge_addr;
> - struct resource_entry *entry;
> - u64 pci_addr;
> - u32 index = 1;
> -
> - resource_list_for_each_entry(entry, &bridge->windows) {
> - if (resource_type(entry->res) == IORESOURCE_MEM) {
> - pci_addr = entry->res->start - entry->offset;
> - plda_pcie_setup_window(bridge_base_addr, index,
> - entry->res->start, pci_addr,
> - resource_size(entry->res));
> - index++;
> - }
> - }
> -
> - return 0;
> -}
> -
> static inline void mc_clear_secs(struct mc_pcie *port)
> {
> void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
> diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
> new file mode 100644
> index 000000000000..19131181897f
> --- /dev/null
> +++ b/drivers/pci/controller/plda/pcie-plda-host.c
> @@ -0,0 +1,80 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PLDA PCIe XpressRich host controller driver
> + *
> + * Copyright (C) 2023 Microchip Co. Ltd
> + *
> + * Author: Daire McNamara <[email protected]>
> + */
> +
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/msi.h>
> +#include <linux/of_address.h>
> +#include <linux/of_pci.h>
> +#include <linux/pci_regs.h>
> +#include <linux/pci-ecam.h>
> +#include <linux/platform_device.h>
Do you really require these headers ? Not in this patch,
in later patches and that's why every header should be
added when it is really needed.
Lorenzo
> +
> +#include "pcie-plda.h"
> +
> +void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
> + phys_addr_t axi_addr, phys_addr_t pci_addr,
> + size_t size)
> +{
> + u32 atr_sz = ilog2(size) - 1;
> + u32 val;
> +
> + if (index == 0)
> + val = PCIE_CONFIG_INTERFACE;
> + else
> + val = PCIE_TX_RX_INTERFACE;
> +
> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> + ATR0_AXI4_SLV0_TRSL_PARAM);
> +
> + val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
> + ATR_IMPL_ENABLE;
> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> + ATR0_AXI4_SLV0_SRCADDR_PARAM);
> +
> + val = upper_32_bits(axi_addr);
> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> + ATR0_AXI4_SLV0_SRC_ADDR);
> +
> + val = lower_32_bits(pci_addr);
> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> + ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
> +
> + val = upper_32_bits(pci_addr);
> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
> + ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
> +
> + val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
> + val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
> + writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
> + writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
> +}
> +EXPORT_SYMBOL_GPL(plda_pcie_setup_window);
> +
> +int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
> + struct plda_pcie_rp *port)
> +{
> + void __iomem *bridge_base_addr = port->bridge_addr;
> + struct resource_entry *entry;
> + u64 pci_addr;
> + u32 index = 1;
> +
> + resource_list_for_each_entry(entry, &bridge->windows) {
> + if (resource_type(entry->res) == IORESOURCE_MEM) {
> + pci_addr = entry->res->start - entry->offset;
> + plda_pcie_setup_window(bridge_base_addr, index,
> + entry->res->start, pci_addr,
> + resource_size(entry->res));
> + index++;
> + }
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
> diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
> index 363fcbbaf6ec..3deefd35fa5a 100644
> --- a/drivers/pci/controller/plda/pcie-plda.h
> +++ b/drivers/pci/controller/plda/pcie-plda.h
> @@ -120,4 +120,9 @@ struct plda_pcie_rp {
> void __iomem *bridge_addr;
> };
>
> +void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
> + phys_addr_t axi_addr, phys_addr_t pci_addr,
> + size_t size);
> +int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
> + struct plda_pcie_rp *port);
> #endif
> --
> 2.17.1
>
On Thu, Dec 14, 2023 at 03:28:28PM +0800, Minda Chen wrote:
> Rename mc_* to plda_* for IRQ functions and related IRQ domain ops data
> instances.
>
> MSI, INTx interrupt codes and IRQ init codes are all can be re-used.
s/codes/code
>
> - function rename list:
> mc_allocate_msi_domains() --> plda_allocate_msi_domains()
> mc_init_interrupts() --> plda_init_interrupts()
> mc_pcie_init_irq_domain() --> plda_pcie_init_irq_domains()
> mc_handle_event() --> plda_handle_event()
> get_events() --> mc_get_events()
>
> MSI interrupts related functions and IRQ domain
> (primary function is mc_handle_msi()):
> mc_handle_msi() --> plda_handle_msi()
> INTx interrupts related functions and IRQ domain
> (primary function is mc_handle_intx()):
> mc_handle_intx() --> plda_handle_intx()
We can read the code you are changing, there is no need to
add it to the commit log, especially because it is a trivial
rename here.
> Signed-off-by: Minda Chen <[email protected]>
> Acked-by: Conor Dooley <[email protected]>
> ---
> .../pci/controller/plda/pcie-microchip-host.c | 112 +++++++++---------
> 1 file changed, 59 insertions(+), 53 deletions(-)
>
> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
> index 2e79bcc7c0a5..506e6eeadc76 100644
> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
> @@ -318,7 +318,7 @@ static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
> ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
> }
>
> -static void mc_handle_msi(struct irq_desc *desc)
> +static void plda_handle_msi(struct irq_desc *desc)
> {
> struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
> struct irq_chip *chip = irq_desc_get_chip(desc);
> @@ -333,7 +333,8 @@ static void mc_handle_msi(struct irq_desc *desc)
>
> status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
> if (status & PM_MSI_INT_MSI_MASK) {
> - writel_relaxed(status & PM_MSI_INT_MSI_MASK, bridge_base_addr + ISTATUS_LOCAL);
> + writel_relaxed(status & PM_MSI_INT_MSI_MASK,
> + bridge_base_addr + ISTATUS_LOCAL);
Unrelated change (I suspect checkpatch nudged you to make it; it
is tempting but it does not belong in this patch).
Lorenzo
> status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
> for_each_set_bit(bit, &status, msi->num_vectors) {
> ret = generic_handle_domain_irq(msi->dev_domain, bit);
> @@ -346,7 +347,7 @@ static void mc_handle_msi(struct irq_desc *desc)
> chained_irq_exit(chip, desc);
> }
>
> -static void mc_msi_bottom_irq_ack(struct irq_data *data)
> +static void plda_msi_bottom_irq_ack(struct irq_data *data)
> {
> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> void __iomem *bridge_base_addr = port->bridge_addr;
> @@ -355,7 +356,7 @@ static void mc_msi_bottom_irq_ack(struct irq_data *data)
> writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
> }
>
> -static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
> +static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
> {
> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> phys_addr_t addr = port->msi.vector_phy;
> @@ -368,21 +369,23 @@ static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
> (int)data->hwirq, msg->address_hi, msg->address_lo);
> }
>
> -static int mc_msi_set_affinity(struct irq_data *irq_data,
> - const struct cpumask *mask, bool force)
> +static int plda_msi_set_affinity(struct irq_data *irq_data,
> + const struct cpumask *mask, bool force)
> {
> return -EINVAL;
> }
>
> -static struct irq_chip mc_msi_bottom_irq_chip = {
> - .name = "Microchip MSI",
> - .irq_ack = mc_msi_bottom_irq_ack,
> - .irq_compose_msi_msg = mc_compose_msi_msg,
> - .irq_set_affinity = mc_msi_set_affinity,
> +static struct irq_chip plda_msi_bottom_irq_chip = {
> + .name = "PLDA MSI",
> + .irq_ack = plda_msi_bottom_irq_ack,
> + .irq_compose_msi_msg = plda_compose_msi_msg,
> + .irq_set_affinity = plda_msi_set_affinity,
> };
>
> -static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
> - unsigned int nr_irqs, void *args)
> +static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
> + unsigned int virq,
> + unsigned int nr_irqs,
> + void *args)
> {
> struct plda_pcie_rp *port = domain->host_data;
> struct plda_msi *msi = &port->msi;
> @@ -397,7 +400,7 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
>
> set_bit(bit, msi->used);
>
> - irq_domain_set_info(domain, virq, bit, &mc_msi_bottom_irq_chip,
> + irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
> domain->host_data, handle_edge_irq, NULL, NULL);
>
> mutex_unlock(&msi->lock);
> @@ -405,8 +408,9 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
> return 0;
> }
>
> -static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
> - unsigned int nr_irqs)
> +static void plda_irq_msi_domain_free(struct irq_domain *domain,
> + unsigned int virq,
> + unsigned int nr_irqs)
> {
> struct irq_data *d = irq_domain_get_irq_data(domain, virq);
> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
> @@ -423,24 +427,24 @@ static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
> }
>
> static const struct irq_domain_ops msi_domain_ops = {
> - .alloc = mc_irq_msi_domain_alloc,
> - .free = mc_irq_msi_domain_free,
> + .alloc = plda_irq_msi_domain_alloc,
> + .free = plda_irq_msi_domain_free,
> };
>
> -static struct irq_chip mc_msi_irq_chip = {
> - .name = "Microchip PCIe MSI",
> +static struct irq_chip plda_msi_irq_chip = {
> + .name = "PLDA PCIe MSI",
> .irq_ack = irq_chip_ack_parent,
> .irq_mask = pci_msi_mask_irq,
> .irq_unmask = pci_msi_unmask_irq,
> };
>
> -static struct msi_domain_info mc_msi_domain_info = {
> +static struct msi_domain_info plda_msi_domain_info = {
> .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
> MSI_FLAG_PCI_MSIX),
> - .chip = &mc_msi_irq_chip,
> + .chip = &plda_msi_irq_chip,
> };
>
> -static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
> +static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
> {
> struct device *dev = port->dev;
> struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
> @@ -455,7 +459,8 @@ static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
> return -ENOMEM;
> }
>
> - msi->msi_domain = pci_msi_create_irq_domain(fwnode, &mc_msi_domain_info,
> + msi->msi_domain = pci_msi_create_irq_domain(fwnode,
> + &plda_msi_domain_info,
> msi->dev_domain);
> if (!msi->msi_domain) {
> dev_err(dev, "failed to create MSI domain\n");
> @@ -466,7 +471,7 @@ static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
> return 0;
> }
>
> -static void mc_handle_intx(struct irq_desc *desc)
> +static void plda_handle_intx(struct irq_desc *desc)
> {
> struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
> struct irq_chip *chip = irq_desc_get_chip(desc);
> @@ -493,7 +498,7 @@ static void mc_handle_intx(struct irq_desc *desc)
> chained_irq_exit(chip, desc);
> }
>
> -static void mc_ack_intx_irq(struct irq_data *data)
> +static void plda_ack_intx_irq(struct irq_data *data)
> {
> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> void __iomem *bridge_base_addr = port->bridge_addr;
> @@ -502,7 +507,7 @@ static void mc_ack_intx_irq(struct irq_data *data)
> writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
> }
>
> -static void mc_mask_intx_irq(struct irq_data *data)
> +static void plda_mask_intx_irq(struct irq_data *data)
> {
> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> void __iomem *bridge_base_addr = port->bridge_addr;
> @@ -517,7 +522,7 @@ static void mc_mask_intx_irq(struct irq_data *data)
> raw_spin_unlock_irqrestore(&port->lock, flags);
> }
>
> -static void mc_unmask_intx_irq(struct irq_data *data)
> +static void plda_unmask_intx_irq(struct irq_data *data)
> {
> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
> void __iomem *bridge_base_addr = port->bridge_addr;
> @@ -532,24 +537,24 @@ static void mc_unmask_intx_irq(struct irq_data *data)
> raw_spin_unlock_irqrestore(&port->lock, flags);
> }
>
> -static struct irq_chip mc_intx_irq_chip = {
> - .name = "Microchip PCIe INTx",
> - .irq_ack = mc_ack_intx_irq,
> - .irq_mask = mc_mask_intx_irq,
> - .irq_unmask = mc_unmask_intx_irq,
> +static struct irq_chip plda_intx_irq_chip = {
> + .name = "PLDA PCIe INTx",
> + .irq_ack = plda_ack_intx_irq,
> + .irq_mask = plda_mask_intx_irq,
> + .irq_unmask = plda_unmask_intx_irq,
> };
>
> -static int mc_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
> - irq_hw_number_t hwirq)
> +static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
> + irq_hw_number_t hwirq)
> {
> - irq_set_chip_and_handler(irq, &mc_intx_irq_chip, handle_level_irq);
> + irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
> irq_set_chip_data(irq, domain->host_data);
>
> return 0;
> }
>
> static const struct irq_domain_ops intx_domain_ops = {
> - .map = mc_pcie_intx_map,
> + .map = plda_pcie_intx_map,
> };
>
> static inline u32 reg_to_event(u32 reg, struct event_map field)
> @@ -609,7 +614,7 @@ static u32 local_events(struct mc_pcie *port)
> return val;
> }
>
> -static u32 get_events(struct plda_pcie_rp *port)
> +static u32 mc_get_events(struct plda_pcie_rp *port)
> {
> struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
> u32 events = 0;
> @@ -638,7 +643,7 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
> return IRQ_HANDLED;
> }
>
> -static void mc_handle_event(struct irq_desc *desc)
> +static void plda_handle_event(struct irq_desc *desc)
> {
> struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
> unsigned long events;
> @@ -647,7 +652,7 @@ static void mc_handle_event(struct irq_desc *desc)
>
> chained_irq_enter(chip, desc);
>
> - events = get_events(port);
> + events = mc_get_events(port);
>
> for_each_set_bit(bit, &events, NUM_EVENTS)
> generic_handle_domain_irq(port->event_domain, bit);
> @@ -741,8 +746,8 @@ static struct irq_chip mc_event_irq_chip = {
> .irq_unmask = mc_unmask_event_irq,
> };
>
> -static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
> - irq_hw_number_t hwirq)
> +static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
> + irq_hw_number_t hwirq)
> {
> irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
> irq_set_chip_data(irq, domain->host_data);
> @@ -750,8 +755,8 @@ static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
> return 0;
> }
>
> -static const struct irq_domain_ops event_domain_ops = {
> - .map = mc_pcie_event_map,
> +static const struct irq_domain_ops plda_event_domain_ops = {
> + .map = plda_pcie_event_map,
> };
>
> static inline void mc_pcie_deinit_clk(void *data)
> @@ -799,7 +804,7 @@ static int mc_pcie_init_clks(struct device *dev)
> return 0;
> }
>
> -static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
> +static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
> {
> struct device *dev = port->dev;
> struct device_node *node = dev->of_node;
> @@ -813,7 +818,8 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
> }
>
> port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
> - &event_domain_ops, port);
> + &plda_event_domain_ops,
> + port);
> if (!port->event_domain) {
> dev_err(dev, "failed to get event domain\n");
> of_node_put(pcie_intc_node);
> @@ -835,7 +841,7 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
> of_node_put(pcie_intc_node);
> raw_spin_lock_init(&port->lock);
>
> - return mc_allocate_msi_domains(port);
> + return plda_allocate_msi_domains(port);
> }
>
> static inline void mc_clear_secs(struct mc_pcie *port)
> @@ -898,14 +904,14 @@ static void mc_disable_interrupts(struct mc_pcie *port)
> writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
> }
>
> -static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
> +static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
> {
> struct device *dev = &pdev->dev;
> int irq;
> int i, intx_irq, msi_irq, event_irq;
> int ret;
>
> - ret = mc_pcie_init_irq_domains(port);
> + ret = plda_pcie_init_irq_domains(port);
> if (ret) {
> dev_err(dev, "failed creating IRQ domains\n");
> return ret;
> @@ -938,7 +944,7 @@ static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp
> }
>
> /* Plug the INTx chained handler */
> - irq_set_chained_handler_and_data(intx_irq, mc_handle_intx, port);
> + irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
>
> msi_irq = irq_create_mapping(port->event_domain,
> EVENT_LOCAL_PM_MSI_INT_MSI);
> @@ -946,10 +952,10 @@ static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp
> return -ENXIO;
>
> /* Plug the MSI chained handler */
> - irq_set_chained_handler_and_data(msi_irq, mc_handle_msi, port);
> + irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
>
> /* Plug the main event chained handler */
> - irq_set_chained_handler_and_data(irq, mc_handle_event, port);
> + irq_set_chained_handler_and_data(irq, plda_handle_event, port);
>
> return 0;
> }
> @@ -977,7 +983,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
> return ret;
>
> /* Address translation is up; safe to enable interrupts */
> - ret = mc_init_interrupts(pdev, &port->plda);
> + ret = plda_init_interrupts(pdev, &port->plda);
> if (ret)
> return ret;
>
> --
> 2.17.1
>
On Thu, Dec 14, 2023 at 03:28:29PM +0800, Minda Chen wrote:
> The event num is different in other platform. For re-using interrupt
> process codes, replace macros with variable.
"The number of events is different across platforms. In order to
share interrupt processing code, add a variable that defines the
number of events so that it can be set per-platform instead of
hardcoding it".
Lorenzo
>
> Signed-off-by: Minda Chen <[email protected]>
> Reviewed-by: Conor Dooley <[email protected]>
> ---
> drivers/pci/controller/plda/pcie-microchip-host.c | 8 +++++---
> drivers/pci/controller/plda/pcie-plda.h | 1 +
> 2 files changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
> index 506e6eeadc76..7b3f4f74745d 100644
> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
> @@ -654,7 +654,7 @@ static void plda_handle_event(struct irq_desc *desc)
>
> events = mc_get_events(port);
>
> - for_each_set_bit(bit, &events, NUM_EVENTS)
> + for_each_set_bit(bit, &events, port->num_events)
> generic_handle_domain_irq(port->event_domain, bit);
>
> chained_irq_exit(chip, desc);
> @@ -817,7 +817,8 @@ static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
> return -EINVAL;
> }
>
> - port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
> + port->event_domain = irq_domain_add_linear(pcie_intc_node,
> + port->num_events,
> &plda_event_domain_ops,
> port);
> if (!port->event_domain) {
> @@ -921,7 +922,7 @@ static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_r
> if (irq < 0)
> return -ENODEV;
>
> - for (i = 0; i < NUM_EVENTS; i++) {
> + for (i = 0; i < port->num_events; i++) {
> event_irq = irq_create_mapping(port->event_domain, i);
> if (!event_irq) {
> dev_err(dev, "failed to map hwirq %d\n", i);
> @@ -1013,6 +1014,7 @@ static int mc_host_probe(struct platform_device *pdev)
>
> bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
> plda->bridge_addr = bridge_base_addr;
> + plda->num_events = NUM_EVENTS;
>
> /* Allow enabling MSI by disabling MSI-X */
> val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
> diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
> index 3deefd35fa5a..e3d35cef9894 100644
> --- a/drivers/pci/controller/plda/pcie-plda.h
> +++ b/drivers/pci/controller/plda/pcie-plda.h
> @@ -118,6 +118,7 @@ struct plda_pcie_rp {
> raw_spinlock_t lock;
> struct plda_msi msi;
> void __iomem *bridge_addr;
> + int num_events;
> };
>
> void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
> --
> 2.17.1
>
On Thu, Dec 14, 2023 at 03:28:30PM +0800, Minda Chen wrote:
> PolarFire implements specific PCIe interrupts except PLDA local interrupt.
Please explain to me what you want to say here.
> For lack of MSI controller, these interrupts have to be added to global
> event field. PolarFire PCIe driver also register additional interrupt
> symbol name.
And here.
> PolarFire PCIe contain total 28 interrupts event while PLDA contain 13
> local interrupts event, interrupt to event num mapping is different.
It "is different" in different platforms ? Is that correct ?
> So add a callback function to support different IRQ register function.
> Also Add PLDA default handler function, which will be moved to pcie-
> plda-host.c in moving codes patch.
As I said before, a patch is a single self-contained change, don't
refer to other patches, they may or may not be merged or even exist
by the time this one hits mainline.
Lorenzo
> Signed-off-by: Minda Chen <[email protected]>
> Acked-by: Conor Dooley <[email protected]>
> ---
> .../pci/controller/plda/pcie-microchip-host.c | 31 ++++++++++++++++---
> drivers/pci/controller/plda/pcie-plda.h | 5 +++
> 2 files changed, 32 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
> index 7b3f4f74745d..624e4e2e97d3 100644
> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
> @@ -643,6 +643,11 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
> return IRQ_HANDLED;
> }
>
> +static irqreturn_t plda_event_handler(int irq, void *dev_id)
> +{
> + return IRQ_HANDLED;
> +}
> +
> static void plda_handle_event(struct irq_desc *desc)
> {
> struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
> @@ -804,6 +809,17 @@ static int mc_pcie_init_clks(struct device *dev)
> return 0;
> }
>
> +static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
> + int event)
> +{
> + return devm_request_irq(plda->dev, event_irq, mc_event_handler,
> + 0, event_cause[event].sym, plda);
> +}
> +
> +static const struct plda_event mc_event = {
> + .request_event_irq = mc_request_event_irq,
> +};
> +
> static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
> {
> struct device *dev = port->dev;
> @@ -905,7 +921,9 @@ static void mc_disable_interrupts(struct mc_pcie *port)
> writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
> }
>
> -static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
> +static int plda_init_interrupts(struct platform_device *pdev,
> + struct plda_pcie_rp *port,
> + const struct plda_event *event)
> {
> struct device *dev = &pdev->dev;
> int irq;
> @@ -929,8 +947,13 @@ static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_r
> return -ENXIO;
> }
>
> - ret = devm_request_irq(dev, event_irq, mc_event_handler,
> - 0, event_cause[i].sym, port);
> + if (event->request_event_irq)
> + ret = event->request_event_irq(port, event_irq, i);
> + else
> + ret = devm_request_irq(dev, event_irq,
> + plda_event_handler,
> + 0, NULL, port);
> +
> if (ret) {
> dev_err(dev, "failed to request IRQ %d\n", event_irq);
> return ret;
> @@ -984,7 +1007,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
> return ret;
>
> /* Address translation is up; safe to enable interrupts */
> - ret = plda_init_interrupts(pdev, &port->plda);
> + ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
> if (ret)
> return ret;
>
> diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
> index e3d35cef9894..28ed1374e1de 100644
> --- a/drivers/pci/controller/plda/pcie-plda.h
> +++ b/drivers/pci/controller/plda/pcie-plda.h
> @@ -121,6 +121,11 @@ struct plda_pcie_rp {
> int num_events;
> };
>
> +struct plda_event {
> + int (*request_event_irq)(struct plda_pcie_rp *pcie,
> + int event_irq, int event);
> +};
> +
> void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
> phys_addr_t axi_addr, phys_addr_t pci_addr,
> size_t size);
> --
> 2.17.1
>
On Thu, Dec 14, 2023 at 03:28:37PM +0800, Minda Chen wrote:
> From: Kevin Xie <[email protected]>
>
> Add the PCIE_RESET_CONFIG_DEVICE_WAIT_MS macro to define the minimum
> waiting time between exit from a conventional reset and sending the
> first configuration request to the device.
>
> As described in PCI base specification r6.0, section 6.6.1 <Conventional
> Reset>, there are two different use cases of the value:
>
> - "With a Downstream Port that does not support Link speeds greater
> than 5.0 GT/s, software must wait a minimum of 100 ms following exit
> from a Conventional Reset before sending a Configuration Request to
> the device immediately below that Port."
>
> - "With a Downstream Port that supports Link speeds greater than
> 5.0 GT/s, software must wait a minimum of 100 ms after Link training
> completes before sending a Configuration Request to the device
> immediately below that Port."
>
> Signed-off-by: Kevin Xie <[email protected]>
> Reviewed-by: Mason Huo <[email protected]>
> ---
> drivers/pci/pci.h | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
This needs Bjorn's ack.
Thanks,
Lorenzo
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 5ecbcf041179..06f1f1eb878c 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -22,6 +22,22 @@
> */
> #define PCIE_PME_TO_L2_TIMEOUT_US 10000
>
> +/*
> + * As described in PCI base specification r6.0, section 6.6.1 <Conventional
> + * Reset>, there are two different use cases of the value:
> + *
> + * - "With a Downstream Port that does not support Link speeds greater
> + * than 5.0 GT/s, software must wait a minimum of 100 ms following exit
> + * from a Conventional Reset before sending a Configuration Request to
> + * the device immediately below that Port."
> + *
> + * - "With a Downstream Port that supports Link speeds greater than
> + * 5.0 GT/s, software must wait a minimum of 100 ms after Link training
> + * completes before sending a Configuration Request to the device
> + * immediately below that Port."
> + */
> +#define PCIE_RESET_CONFIG_DEVICE_WAIT_MS 100
> +
> extern const unsigned char pcie_link_speed[];
> extern bool pci_early_dump;
>
> --
> 2.17.1
>
On Thu, Dec 14, 2023 at 03:28:32PM +0800, Minda Chen wrote:
> PolarFire implements its own PCIe interrupts, additional to the regular
> PCIe interrupts, due to lack of an MSI controller, so the interrupt to
> event number mapping is different to the PLDA local interrupts,
I am sorry I don't understand what you mean here.
"its own PCIe interrupts" ?
"regular PCIe interrupts" ?
"PLDA local interrupts" ?
Can you spell out what those are referring to please ?
Thanks,
Lorenzo
> necessitating a custom get_events() implementation.
>
> plda_get_events() adds interrupt register to PLDA local event num mapping
> codes except DMA engine interrupt events. The DMA engine interrupt events
> are implemented by vendors.
>
> Signed-off-by: Minda Chen <[email protected]>
> Acked-by: Conor Dooley <[email protected]>
> ---
> .../pci/controller/plda/pcie-microchip-host.c | 35 ++++++++++++++++++-
> drivers/pci/controller/plda/pcie-plda.h | 33 +++++++++++++++++
> 2 files changed, 67 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
> index 00250781b11c..fd0d92c3d03f 100644
> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
> @@ -627,6 +627,26 @@ static u32 mc_get_events(struct plda_pcie_rp *port)
> return events;
> }
>
> +static u32 plda_get_events(struct plda_pcie_rp *port)
> +{
> + u32 events, val, origin;
> +
> + origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
> +
> + /* Error events and doorbell events */
> + events = (origin & ERROR_AND_DOORBELL_MASK) >> A_ATR_EVT_POST_ERR_SHIFT;
> +
> + /* INTx events */
> + if (origin & PM_MSI_INT_INTX_MASK)
> + events |= BIT(EVENT_PM_MSI_INT_INTX);
> +
> + /* MSI event and sys events */
> + val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
> + events |= val << EVENT_PM_MSI_INT_MSI;
> +
> + return events;
> +}
> +
> static irqreturn_t mc_event_handler(int irq, void *dev_id)
> {
> struct plda_pcie_rp *port = dev_id;
> @@ -657,7 +677,7 @@ static void plda_handle_event(struct irq_desc *desc)
>
> chained_irq_enter(chip, desc);
>
> - events = mc_get_events(port);
> + events = port->event_ops->get_events(port);
>
> for_each_set_bit(bit, &events, port->num_events)
> generic_handle_domain_irq(port->event_domain, bit);
> @@ -751,6 +771,10 @@ static struct irq_chip mc_event_irq_chip = {
> .irq_unmask = mc_unmask_event_irq,
> };
>
> +static const struct plda_event_ops plda_event_ops = {
> + .get_events = plda_get_events,
> +};
> +
> static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
> irq_hw_number_t hwirq)
> {
> @@ -816,6 +840,10 @@ static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
> 0, event_cause[event].sym, plda);
> }
>
> +static const struct plda_event_ops mc_event_ops = {
> + .get_events = mc_get_events,
> +};
> +
> static const struct plda_event mc_event = {
> .request_event_irq = mc_request_event_irq,
> .intx_event = EVENT_LOCAL_PM_MSI_INT_INTX,
> @@ -932,6 +960,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
> int i, intx_irq, msi_irq, event_irq;
> int ret;
>
> + if (!port->event_ops)
> + port->event_ops = &plda_event_ops;
> +
> ret = plda_pcie_init_irq_domains(port);
> if (ret) {
> dev_err(dev, "failed creating IRQ domains\n");
> @@ -1008,6 +1039,8 @@ static int mc_platform_init(struct pci_config_window *cfg)
> if (ret)
> return ret;
>
> + port->plda.event_ops = &mc_event_ops;
> +
> /* Address translation is up; safe to enable interrupts */
> ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
> if (ret)
> diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
> index fba7343f9a96..dd8bc2750bfc 100644
> --- a/drivers/pci/controller/plda/pcie-plda.h
> +++ b/drivers/pci/controller/plda/pcie-plda.h
> @@ -40,6 +40,7 @@
> #define P_ATR_EVT_DISCARD_ERR_SHIFT 22
> #define P_ATR_EVT_DOORBELL_MASK 0x00000000u
> #define P_ATR_EVT_DOORBELL_SHIFT 23
> +#define ERROR_AND_DOORBELL_MASK GENMASK(23, 16)
> #define PM_MSI_INT_INTA_MASK 0x01000000u
> #define PM_MSI_INT_INTA_SHIFT 24
> #define PM_MSI_INT_INTB_MASK 0x02000000u
> @@ -58,6 +59,7 @@
> #define PM_MSI_INT_EVENTS_SHIFT 30
> #define PM_MSI_INT_SYS_ERR_MASK 0x80000000u
> #define PM_MSI_INT_SYS_ERR_SHIFT 31
> +#define SYS_AND_MSI_MASK GENMASK(31, 28)
> #define NUM_LOCAL_EVENTS 15
> #define ISTATUS_LOCAL 0x184
> #define IMASK_HOST 0x188
> @@ -102,6 +104,36 @@
> #define EVENT_PM_MSI_INT_SYS_ERR 12
> #define NUM_PLDA_EVENTS 13
>
> +/*
> + * PLDA local interrupt register
> + *
> + * 31 27 23 15 7 0
> + * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
> + * |12|11|10|9| intx |7|6|5|4|3|2|1|0| DMA error | DMA end |
> + * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
> + * 0: AXI post error
> + * 1: AXI fetch error
> + * 2: AXI discard error
> + * 3: AXI doorbell
> + * 4: PCIe post error
> + * 5: PCIe fetch error
> + * 6: PCIe discard error
> + * 7: PCIe doorbell
> + * 8: 4 INTx interruts
> + * 9: MSI interrupt
> + * 10: AER event
> + * 11: PM/LTR/Hotplug
> + * 12: System error
> + * DMA error : reserved for vendor implement
> + * DMA end : reserved for vendor implement
> + */
> +
> +struct plda_pcie_rp;
> +
> +struct plda_event_ops {
> + u32 (*get_events)(struct plda_pcie_rp *pcie);
> +};
> +
> struct plda_msi {
> struct mutex lock; /* Protect used bitmap */
> struct irq_domain *msi_domain;
> @@ -117,6 +149,7 @@ struct plda_pcie_rp {
> struct irq_domain *event_domain;
> raw_spinlock_t lock;
> struct plda_msi msi;
> + const struct plda_event_ops *event_ops;
> void __iomem *bridge_addr;
> int num_events;
> };
> --
> 2.17.1
>
On Thu, Dec 14, 2023 at 03:28:37PM +0800, Minda Chen wrote:
> From: Kevin Xie <[email protected]>
>
> Add the PCIE_RESET_CONFIG_DEVICE_WAIT_MS macro to define the minimum
> waiting time between exit from a conventional reset and sending the
> first configuration request to the device.
>
> As described in PCI base specification r6.0, section 6.6.1 <Conventional
> Reset>, there are two different use cases of the value:
>
> - "With a Downstream Port that does not support Link speeds greater
> than 5.0 GT/s, software must wait a minimum of 100 ms following exit
> from a Conventional Reset before sending a Configuration Request to
> the device immediately below that Port."
>
> - "With a Downstream Port that supports Link speeds greater than
> 5.0 GT/s, software must wait a minimum of 100 ms after Link training
> completes before sending a Configuration Request to the device
> immediately below that Port."
>
> Signed-off-by: Kevin Xie <[email protected]>
> Reviewed-by: Mason Huo <[email protected]>
Acked-by: Bjorn Helgaas <[email protected]>
> ---
> drivers/pci/pci.h | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 5ecbcf041179..06f1f1eb878c 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -22,6 +22,22 @@
> */
> #define PCIE_PME_TO_L2_TIMEOUT_US 10000
>
> +/*
> + * As described in PCI base specification r6.0, section 6.6.1 <Conventional
> + * Reset>, there are two different use cases of the value:
> + *
> + * - "With a Downstream Port that does not support Link speeds greater
> + * than 5.0 GT/s, software must wait a minimum of 100 ms following exit
> + * from a Conventional Reset before sending a Configuration Request to
> + * the device immediately below that Port."
> + *
> + * - "With a Downstream Port that supports Link speeds greater than
> + * 5.0 GT/s, software must wait a minimum of 100 ms after Link training
> + * completes before sending a Configuration Request to the device
> + * immediately below that Port."
> + */
> +#define PCIE_RESET_CONFIG_DEVICE_WAIT_MS 100
> +
> extern const unsigned char pcie_link_speed[];
> extern bool pci_early_dump;
>
> --
> 2.17.1
>
On 2023/12/27 23:49, Lorenzo Pieralisi wrote:
> On Thu, Dec 14, 2023 at 03:28:27PM +0800, Minda Chen wrote:
>> Move setup functions to common pcie-plda-host.c. So these two functions
>> can be re-used.
>>
>> Signed-off-by: Minda Chen <[email protected]>
>> Reviewed-by: Conor Dooley <[email protected]>
>> ---
>> drivers/pci/controller/plda/Kconfig | 4 +
>> drivers/pci/controller/plda/Makefile | 1 +
>> .../pci/controller/plda/pcie-microchip-host.c | 59 --------------
>> drivers/pci/controller/plda/pcie-plda-host.c | 80 +++++++++++++++++++
>> drivers/pci/controller/plda/pcie-plda.h | 5 ++
>> 5 files changed, 90 insertions(+), 59 deletions(-)
>> create mode 100644 drivers/pci/controller/plda/pcie-plda-host.c
>>
>> diff --git a/drivers/pci/controller/plda/Kconfig b/drivers/pci/controller/plda/Kconfig
>> index 5cb3be4fc98c..e54a82ee94f5 100644
>> --- a/drivers/pci/controller/plda/Kconfig
>> +++ b/drivers/pci/controller/plda/Kconfig
>> @@ -3,10 +3,14 @@
>> menu "PLDA-based PCIe controllers"
>> depends on PCI
>>
>> +config PCIE_PLDA_HOST
>> + bool
>> +
>> config PCIE_MICROCHIP_HOST
>> tristate "Microchip AXI PCIe controller"
>> depends on PCI_MSI && OF
>> select PCI_HOST_COMMON
>> + select PCIE_PLDA_HOST
>> help
>> Say Y here if you want kernel to support the Microchip AXI PCIe
>> Host Bridge driver.
>> diff --git a/drivers/pci/controller/plda/Makefile b/drivers/pci/controller/plda/Makefile
>> index e1a265cbf91c..4340ab007f44 100644
>> --- a/drivers/pci/controller/plda/Makefile
>> +++ b/drivers/pci/controller/plda/Makefile
>> @@ -1,2 +1,3 @@
>> # SPDX-License-Identifier: GPL-2.0
>> +obj-$(CONFIG_PCIE_PLDA_HOST) += pcie-plda-host.o
>> obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
>> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
>> index 31ca8d44ee2a..2e79bcc7c0a5 100644
>> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
>> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
>> @@ -838,65 +838,6 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
>> return mc_allocate_msi_domains(port);
>> }
>>
>> -static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
>> - phys_addr_t axi_addr, phys_addr_t pci_addr,
>> - size_t size)
>> -{
>> - u32 atr_sz = ilog2(size) - 1;
>> - u32 val;
>> -
>> - if (index == 0)
>> - val = PCIE_CONFIG_INTERFACE;
>> - else
>> - val = PCIE_TX_RX_INTERFACE;
>> -
>> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> - ATR0_AXI4_SLV0_TRSL_PARAM);
>> -
>> - val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
>> - ATR_IMPL_ENABLE;
>> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> - ATR0_AXI4_SLV0_SRCADDR_PARAM);
>> -
>> - val = upper_32_bits(axi_addr);
>> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> - ATR0_AXI4_SLV0_SRC_ADDR);
>> -
>> - val = lower_32_bits(pci_addr);
>> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> - ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
>> -
>> - val = upper_32_bits(pci_addr);
>> - writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> - ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
>> -
>> - val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
>> - val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
>> - writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
>> - writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
>> -}
>> -
>> -static int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
>> - struct plda_pcie_rp *port)
>> -{
>> - void __iomem *bridge_base_addr = port->bridge_addr;
>> - struct resource_entry *entry;
>> - u64 pci_addr;
>> - u32 index = 1;
>> -
>> - resource_list_for_each_entry(entry, &bridge->windows) {
>> - if (resource_type(entry->res) == IORESOURCE_MEM) {
>> - pci_addr = entry->res->start - entry->offset;
>> - plda_pcie_setup_window(bridge_base_addr, index,
>> - entry->res->start, pci_addr,
>> - resource_size(entry->res));
>> - index++;
>> - }
>> - }
>> -
>> - return 0;
>> -}
>> -
>> static inline void mc_clear_secs(struct mc_pcie *port)
>> {
>> void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
>> diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
>> new file mode 100644
>> index 000000000000..19131181897f
>> --- /dev/null
>> +++ b/drivers/pci/controller/plda/pcie-plda-host.c
>> @@ -0,0 +1,80 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * PLDA PCIe XpressRich host controller driver
>> + *
>> + * Copyright (C) 2023 Microchip Co. Ltd
>> + *
>> + * Author: Daire McNamara <[email protected]>
>> + */
>> +
>> +#include <linux/irqchip/chained_irq.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/msi.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_pci.h>
>> +#include <linux/pci_regs.h>
>> +#include <linux/pci-ecam.h>
>> +#include <linux/platform_device.h>
>
> Do you really require these headers ? Not in this patch,
> in later patches and that's why every header should be
> added when it is really needed.
>
> Lorenzo
>
OK, I will change this. thanks.
>> +
>> +#include "pcie-plda.h"
>> +
>> +void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
>> + phys_addr_t axi_addr, phys_addr_t pci_addr,
>> + size_t size)
>> +{
>> + u32 atr_sz = ilog2(size) - 1;
>> + u32 val;
>> +
>> + if (index == 0)
>> + val = PCIE_CONFIG_INTERFACE;
>> + else
>> + val = PCIE_TX_RX_INTERFACE;
>> +
>> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> + ATR0_AXI4_SLV0_TRSL_PARAM);
>> +
>> + val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
>> + ATR_IMPL_ENABLE;
>> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> + ATR0_AXI4_SLV0_SRCADDR_PARAM);
>> +
>> + val = upper_32_bits(axi_addr);
>> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> + ATR0_AXI4_SLV0_SRC_ADDR);
>> +
>> + val = lower_32_bits(pci_addr);
>> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> + ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
>> +
>> + val = upper_32_bits(pci_addr);
>> + writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
>> + ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
>> +
>> + val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
>> + val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
>> + writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
>> + writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
>> +}
>> +EXPORT_SYMBOL_GPL(plda_pcie_setup_window);
>> +
>> +int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
>> + struct plda_pcie_rp *port)
>> +{
>> + void __iomem *bridge_base_addr = port->bridge_addr;
>> + struct resource_entry *entry;
>> + u64 pci_addr;
>> + u32 index = 1;
>> +
>> + resource_list_for_each_entry(entry, &bridge->windows) {
>> + if (resource_type(entry->res) == IORESOURCE_MEM) {
>> + pci_addr = entry->res->start - entry->offset;
>> + plda_pcie_setup_window(bridge_base_addr, index,
>> + entry->res->start, pci_addr,
>> + resource_size(entry->res));
>> + index++;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
>> diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
>> index 363fcbbaf6ec..3deefd35fa5a 100644
>> --- a/drivers/pci/controller/plda/pcie-plda.h
>> +++ b/drivers/pci/controller/plda/pcie-plda.h
>> @@ -120,4 +120,9 @@ struct plda_pcie_rp {
>> void __iomem *bridge_addr;
>> };
>>
>> +void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
>> + phys_addr_t axi_addr, phys_addr_t pci_addr,
>> + size_t size);
>> +int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
>> + struct plda_pcie_rp *port);
>> #endif
>> --
>> 2.17.1
>>
On 2023/12/28 0:31, Lorenzo Pieralisi wrote:
> On Thu, Dec 14, 2023 at 03:28:32PM +0800, Minda Chen wrote:
>> PolarFire implements its own PCIe interrupts, additional to the regular
>> PCIe interrupts, due to lack of an MSI controller, so the interrupt to
>> event number mapping is different to the PLDA local interrupts,
>
> I am sorry I don't understand what you mean here.
>
> "its own PCIe interrupts" ?
>
> "regular PCIe interrupts" ?
>
> "PLDA local interrupts" ?
>
> Can you spell out what those are referring to please ?
>
> Thanks,
> Lorenzo
>
"its own PCIe interrupts" ?
PolarFire SoC PCIe implement 11 interrupt in their platform.
(can be found in pcie-microchip-host.c:87)
#define EVENT_PCIE_L2_EXIT 0
#define EVENT_PCIE_HOTRST_EXIT 1
#define EVENT_PCIE_DLUP_EXIT 2
#define EVENT_SEC_TX_RAM_SEC_ERR 3
#define EVENT_SEC_RX_RAM_SEC_ERR 4
#define EVENT_SEC_PCIE2AXI_RAM_SEC_ERR 5
#define EVENT_SEC_AXI2PCIE_RAM_SEC_ERR 6
#define EVENT_DED_TX_RAM_DED_ERR 7
#define EVENT_DED_RX_RAM_DED_ERR 8
#define EVENT_DED_PCIE2AXI_RAM_DED_ERR 9
#define EVENT_DED_AXI2PCIE_RAM_DED_ERR 10
"regular PCIe interrupts" ?
"PLDA local interrupts" ?
Actually they are the same. I will change this.
PLDA interrupt register graph in this patch.
>> necessitating a custom get_events() implementation.
>>
>> plda_get_events() adds interrupt register to PLDA local event num mapping
>> codes except DMA engine interrupt events. The DMA engine interrupt events
>> are implemented by vendors.
>>
>> Signed-off-by: Minda Chen <[email protected]>
>> Acked-by: Conor Dooley <[email protected]>
>> ---
>> .../pci/controller/plda/pcie-microchip-host.c | 35 ++++++++++++++++++-
>> drivers/pci/controller/plda/pcie-plda.h | 33 +++++++++++++++++
>> 2 files changed, 67 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
>> index 00250781b11c..fd0d92c3d03f 100644
>> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
>> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
>> @@ -627,6 +627,26 @@ static u32 mc_get_events(struct plda_pcie_rp *port)
>> return events;
>> }
>>
>> +static u32 plda_get_events(struct plda_pcie_rp *port)
>> +{
>> + u32 events, val, origin;
>> +
>> + origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
>> +
>> + /* Error events and doorbell events */
>> + events = (origin & ERROR_AND_DOORBELL_MASK) >> A_ATR_EVT_POST_ERR_SHIFT;
>> +
>> + /* INTx events */
>> + if (origin & PM_MSI_INT_INTX_MASK)
>> + events |= BIT(EVENT_PM_MSI_INT_INTX);
>> +
>> + /* MSI event and sys events */
>> + val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
>> + events |= val << EVENT_PM_MSI_INT_MSI;
>> +
>> + return events;
>> +}
>> +
>> static irqreturn_t mc_event_handler(int irq, void *dev_id)
>> {
>> struct plda_pcie_rp *port = dev_id;
>> @@ -657,7 +677,7 @@ static void plda_handle_event(struct irq_desc *desc)
>>
>> chained_irq_enter(chip, desc);
>>
>> - events = mc_get_events(port);
>> + events = port->event_ops->get_events(port);
>>
>> for_each_set_bit(bit, &events, port->num_events)
>> generic_handle_domain_irq(port->event_domain, bit);
>> @@ -751,6 +771,10 @@ static struct irq_chip mc_event_irq_chip = {
>> .irq_unmask = mc_unmask_event_irq,
>> };
>>
>> +static const struct plda_event_ops plda_event_ops = {
>> + .get_events = plda_get_events,
>> +};
>> +
>> static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
>> irq_hw_number_t hwirq)
>> {
>> @@ -816,6 +840,10 @@ static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
>> 0, event_cause[event].sym, plda);
>> }
>>
>> +static const struct plda_event_ops mc_event_ops = {
>> + .get_events = mc_get_events,
>> +};
>> +
>> static const struct plda_event mc_event = {
>> .request_event_irq = mc_request_event_irq,
>> .intx_event = EVENT_LOCAL_PM_MSI_INT_INTX,
>> @@ -932,6 +960,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
>> int i, intx_irq, msi_irq, event_irq;
>> int ret;
>>
>> + if (!port->event_ops)
>> + port->event_ops = &plda_event_ops;
>> +
>> ret = plda_pcie_init_irq_domains(port);
>> if (ret) {
>> dev_err(dev, "failed creating IRQ domains\n");
>> @@ -1008,6 +1039,8 @@ static int mc_platform_init(struct pci_config_window *cfg)
>> if (ret)
>> return ret;
>>
>> + port->plda.event_ops = &mc_event_ops;
>> +
>> /* Address translation is up; safe to enable interrupts */
>> ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
>> if (ret)
>> diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
>> index fba7343f9a96..dd8bc2750bfc 100644
>> --- a/drivers/pci/controller/plda/pcie-plda.h
>> +++ b/drivers/pci/controller/plda/pcie-plda.h
>> @@ -40,6 +40,7 @@
>> #define P_ATR_EVT_DISCARD_ERR_SHIFT 22
>> #define P_ATR_EVT_DOORBELL_MASK 0x00000000u
>> #define P_ATR_EVT_DOORBELL_SHIFT 23
>> +#define ERROR_AND_DOORBELL_MASK GENMASK(23, 16)
>> #define PM_MSI_INT_INTA_MASK 0x01000000u
>> #define PM_MSI_INT_INTA_SHIFT 24
>> #define PM_MSI_INT_INTB_MASK 0x02000000u
>> @@ -58,6 +59,7 @@
>> #define PM_MSI_INT_EVENTS_SHIFT 30
>> #define PM_MSI_INT_SYS_ERR_MASK 0x80000000u
>> #define PM_MSI_INT_SYS_ERR_SHIFT 31
>> +#define SYS_AND_MSI_MASK GENMASK(31, 28)
>> #define NUM_LOCAL_EVENTS 15
>> #define ISTATUS_LOCAL 0x184
>> #define IMASK_HOST 0x188
>> @@ -102,6 +104,36 @@
>> #define EVENT_PM_MSI_INT_SYS_ERR 12
>> #define NUM_PLDA_EVENTS 13
>>
>> +/*
>> + * PLDA local interrupt register
>> + *
>> + * 31 27 23 15 7 0
>> + * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
>> + * |12|11|10|9| intx |7|6|5|4|3|2|1|0| DMA error | DMA end |
>> + * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
>> + * 0: AXI post error
>> + * 1: AXI fetch error
>> + * 2: AXI discard error
>> + * 3: AXI doorbell
>> + * 4: PCIe post error
>> + * 5: PCIe fetch error
>> + * 6: PCIe discard error
>> + * 7: PCIe doorbell
>> + * 8: 4 INTx interruts
>> + * 9: MSI interrupt
>> + * 10: AER event
>> + * 11: PM/LTR/Hotplug
>> + * 12: System error
>> + * DMA error : reserved for vendor implement
>> + * DMA end : reserved for vendor implement
>> + */
"PLDA local interrupts" ?
They are all the PLDA PCIe interrupts .
>> +
>> +struct plda_pcie_rp;
>> +
>> +struct plda_event_ops {
>> + u32 (*get_events)(struct plda_pcie_rp *pcie);
>> +};
>> +
>> struct plda_msi {
>> struct mutex lock; /* Protect used bitmap */
>> struct irq_domain *msi_domain;
>> @@ -117,6 +149,7 @@ struct plda_pcie_rp {
>> struct irq_domain *event_domain;
>> raw_spinlock_t lock;
>> struct plda_msi msi;
>> + const struct plda_event_ops *event_ops;
>> void __iomem *bridge_addr;
>> int num_events;
>> };
>> --
>> 2.17.1
>>
On 2023/12/27 20:43, Lorenzo Pieralisi wrote:
> [+Thomas]
>
> On Fri, Dec 22, 2023 at 07:18:48PM +0800, Minda Chen wrote:
>>
>>
>> On 2023/12/21 23:32, Lorenzo Pieralisi wrote:
>> > On Thu, Dec 21, 2023 at 06:56:22PM +0800, Minda Chen wrote:
>> >>
>> >>
>> >> On 2023/12/14 15:28, Minda Chen wrote:
>> >> > PolarFire PCIE event IRQs includes PLDA local interrupts and PolarFire
>> >> > their own IRQs. PolarFire PCIe event irq_chip ops using an event_desc to
>> >> > unify different IRQ register addresses. On PLDA sides, PLDA irqchip codes
>> >> > only require to set PLDA local interrupt register. So the PLDA irqchip ops
>> >> > codes can not be extracted from PolarFire codes.
>> >> >
>> >> > To support PLDA its own event IRQ process, implements PLDA irqchip ops and
>> >> > add event irqchip field to struct pcie_plda_rp.
>> >> >
>> >> > Signed-off-by: Minda Chen <[email protected]>
>> >> > ---
>> >> > .../pci/controller/plda/pcie-microchip-host.c | 65 ++++++++++++++++++-
>> >> > drivers/pci/controller/plda/pcie-plda.h | 3 +
>> >> > 2 files changed, 67 insertions(+), 1 deletion(-)
>> >> >
>> >> Hi Conor
>> >> Could you take time to review this patch? For I using event irq chip instead of event ops and the whole patch have been changed. I think it's better
>> >> And I added the implementation of PLDA event irqchip and make it easier to claim the necessity of the modification.
>> >> If you approve this, I will add back the review tag. Thanks
>> >>
>> >> Hi Lorenzo
>> >> Have you reviewed this patch? Does the commit message and the codes are can be approved ?Thanks
>> >>
>> >
>> > Please wrap the lines at 75 columns in length.
>> >
>> OK
>> > I have not reviewed but I am still struggling to understand the
>> > commit log, I apologise, I can try to review the series and figure
>> > out what the patch is doing but I would appreciate if commits logs
>> > could be made easier to parse.
>> >
>> > Thanks,
>> > Lorenzo
>> >
>>
>> The commit message it is not good.
>>
>> I draw a graph about the PCIe global event interrupt domain
>> (related to patch 10- 16).
>> Actually all these interrupts patches are for extracting the common
>> PLDA codes to pcie-plda-host.c and do not change microchip's codes logic.
>
> s/codes/code (please apply this to the the full series)
>
> I will have a look at the code but I can't rewrite the commit log myself
> (it does not scale I am afraid), as it stands I don't understand it and
> that's a problem, I am sorry but that's important.
>
> I added Thomas (you should CC him for irqchip [only] changes) if he
> has time to review these irqchip changes to make sure they are proper.
>
> Thanks,
> Lorenzo
>
The interrupt irq_chip ops includes ack/mask/unmask. These ops are for
writing the correct register. Microchip Implement their PCIe interrupts
and require to write their registers. So the irq_chip ops are different.
(List below are the microchip interrupt register base and status/mask
register offset. In pcie-microchip-host.c:130)
#define PCIE_EVENT(x) \
.base = MC_PCIE_CTRL_ADDR, \
.offset = PCIE_EVENT_INT, \
.mask_offset = PCIE_EVENT_INT, \
.mask_high = 1, \
.mask = PCIE_EVENT_INT_ ## x ## _INT, \
.enb_mask = PCIE_EVENT_INT_ENB_MASK
#define SEC_EVENT(x) \
.base = MC_PCIE_CTRL_ADDR, \
.offset = SEC_ERROR_INT, \
.mask_offset = SEC_ERROR_INT_MASK, \
.mask = SEC_ERROR_INT_ ## x ## _INT, \
.mask_high = 1, \
.enb_mask = 0
#define DED_EVENT(x) \
.base = MC_PCIE_CTRL_ADDR, \
.offset = DED_ERROR_INT, \
.mask_offset = DED_ERROR_INT_MASK, \
.mask_high = 1, \
.mask = DED_ERROR_INT_ ## x ## _INT, \
.enb_mask = 0
>> +----------------------------------------------------------+
>> | microchip Global event interrupt domain |
>> +-----------------------------------+-----------+----------+
>> | | microchip | PLDA |
>> | | event num |(StarFive)|
>> | | |event num |
>> +-----------------------------------+-----------+----------+
>> | | 0 | |
>> | | | |
>> (mc pcie |microchip platform event interrupt | | |
>> int line) | | | |
>> ------------| | | |
>> | |10 | |
>> +-----------------------------------+-----------+----------+
>> | PLDA host DMA interrupt |11 | |
>> | (int number is not fixed, defined | | |
>> | by vendor) |14 | |
>> +--+-----------------------------------+---------- +----------+-+
>> | | PLDA event interrupt |15 |0 | |
>> | | (int number is fixed) | | | |
>> ---------|--| | | | |
>> (Starfive| | | | | |
>> pcie int | | +------------------+ | | | |
>> line) | | |INTx event domain | | | | |
>> | | +------------------+ | | | |
>> | | | | | |
>> | | +------------------+ | | | |
>> | | |MSI event domain | | | | |
>> | | +------------------+ | | | |
>> | | |27 |12 | |
>> | +---------------------------------+-+-----------+----------+ |
>> | extract PLDA event part to common PLDA file. |
>> +---------------------------------------------------------------+
>>
>>
>> >> > diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
>> >> > index fd0d92c3d03f..ff40c1622173 100644
>> >> > --- a/drivers/pci/controller/plda/pcie-microchip-host.c
>> >> > +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
>> >> > @@ -771,6 +771,63 @@ static struct irq_chip mc_event_irq_chip = {
>> >> > .irq_unmask = mc_unmask_event_irq,
>> >> > };
>> >> > > +static u32 plda_hwirq_to_mask(int hwirq)
>> >> > +{
>> >> > + u32 mask;
>> >> > +
>> >> > + if (hwirq < EVENT_PM_MSI_INT_INTX)
>> >> > + mask = BIT(hwirq + A_ATR_EVT_POST_ERR_SHIFT);
>> >> > + else if (hwirq == EVENT_PM_MSI_INT_INTX)
>> >> > + mask = PM_MSI_INT_INTX_MASK;
>> >> > + else
>> >> > + mask = BIT(hwirq + PM_MSI_TO_MASK_OFFSET);
>> >> > +
>> >> > + return mask;
>> >> > +}
>> >> > +
>> >> > +static void plda_ack_event_irq(struct irq_data *data)
>> >> > +{
>> >> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> >> > +
>> >> > + writel_relaxed(plda_hwirq_to_mask(data->hwirq),
>> >> > + port->bridge_addr + ISTATUS_LOCAL);
>> >> > +}
>> >> > +
>> >> > +static void plda_mask_event_irq(struct irq_data *data)
>> >> > +{
>> >> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> >> > + u32 mask, val;
>> >> > +
>> >> > + mask = plda_hwirq_to_mask(data->hwirq);
>> >> > +
>> >> > + raw_spin_lock(&port->lock);
>> >> > + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
>> >> > + val &= ~mask;
>> >> > + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
>> >> > + raw_spin_unlock(&port->lock);
>> >> > +}
>> >> > +
>> >> > +static void plda_unmask_event_irq(struct irq_data *data)
>> >> > +{
>> >> > + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> >> > + u32 mask, val;
>> >> > +
>> >> > + mask = plda_hwirq_to_mask(data->hwirq);
>> >> > +
>> >> > + raw_spin_lock(&port->lock);
>> >> > + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
>> >> > + val |= mask;
>> >> > + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
>> >> > + raw_spin_unlock(&port->lock);
>> >> > +}
>> >> > +
>> >> > +static struct irq_chip plda_event_irq_chip = {
>> >> > + .name = "PLDA PCIe EVENT",
>> >> > + .irq_ack = plda_ack_event_irq,
>> >> > + .irq_mask = plda_mask_event_irq,
>> >> > + .irq_unmask = plda_unmask_event_irq,
>> >> > +};
>> >> > +
>> >> > static const struct plda_event_ops plda_event_ops = {
>> >> > .get_events = plda_get_events,
>> >> > };
>> >> > @@ -778,7 +835,9 @@ static const struct plda_event_ops plda_event_ops = {
>> >> > static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
>> >> > irq_hw_number_t hwirq)
>> >> > {
>> >> > - irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
>> >> > + struct plda_pcie_rp *port = (void *)domain->host_data;
>> >> > +
>> >> > + irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
>> >> > irq_set_chip_data(irq, domain->host_data);
>> >> >
>> >> > return 0;
>> >> > @@ -963,6 +1022,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
>> >> > if (!port->event_ops)
>> >> > port->event_ops = &plda_event_ops;
>> >> >
>> >> > + if (!port->event_irq_chip)
>> >> > + port->event_irq_chip = &plda_event_irq_chip;
>> >> > +
>> >> > ret = plda_pcie_init_irq_domains(port);
>> >> > if (ret) {
>> >> > dev_err(dev, "failed creating IRQ domains\n");
>> >> > @@ -1040,6 +1102,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
>> >> > return ret;
>> >> >
>> >> > port->plda.event_ops = &mc_event_ops;
>> >> > + port->plda.event_irq_chip = &mc_event_irq_chip;
>> >> >
>> >> > /* Address translation is up; safe to enable interrupts */
>> >> > ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
>> >> > diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
>> >> > index dd8bc2750bfc..24ac50c458dc 100644
>> >> > --- a/drivers/pci/controller/plda/pcie-plda.h
>> >> > +++ b/drivers/pci/controller/plda/pcie-plda.h
>> >> > @@ -128,6 +128,8 @@
>> >> > * DMA end : reserved for vendor implement
>> >> > */
>> >> >
>> >> > +#define PM_MSI_TO_MASK_OFFSET 19
>> >> > +
>> >> > struct plda_pcie_rp;
>> >> >
>> >> > struct plda_event_ops {
>> >> > @@ -150,6 +152,7 @@ struct plda_pcie_rp {
>> >> > raw_spinlock_t lock;
>> >> > struct plda_msi msi;
>> >> > const struct plda_event_ops *event_ops;
>> >> > + const struct irq_chip *event_irq_chip;
>> >> > void __iomem *bridge_addr;
>> >> > int num_events;
>> >> > };
On 2023/12/28 0:01, Lorenzo Pieralisi wrote:
> On Thu, Dec 14, 2023 at 03:28:30PM +0800, Minda Chen wrote:
>> PolarFire implements specific PCIe interrupts except PLDA local interrupt.
>
> Please explain to me what you want to say here.
> >> For lack of MSI controller, these interrupts have to be added to global
>> event field. PolarFire PCIe driver also register additional interrupt
>> symbol name.
>
> And here.
>
The sentence mean architecture should have an advance interrupt
controller can support MSI interrupt and these new added interrupts should
be added to MSI interrupt. (Like ARM GIC high level version)
Maybe this commit message should be deleted. The commit message should claim
why add request_event_irq() callback function.
Add this callback function is for vendor register the interrupt handler and
the name of new added PCIe interrupts.
"new added PCIe interrupts" is mean microchip new added interrupt.
#define EVENT_PCIE_L2_EXIT 0
#define EVENT_PCIE_HOTRST_EXIT 1
#define EVENT_PCIE_DLUP_EXIT 2
#define EVENT_SEC_TX_RAM_SEC_ERR 3
#define EVENT_SEC_RX_RAM_SEC_ERR 4
#define EVENT_SEC_PCIE2AXI_RAM_SEC_ERR 5
#define EVENT_SEC_AXI2PCIE_RAM_SEC_ERR 6
#define EVENT_DED_TX_RAM_DED_ERR 7
#define EVENT_DED_RX_RAM_DED_ERR 8
#define EVENT_DED_PCIE2AXI_RAM_DED_ERR 9
#define EVENT_DED_AXI2PCIE_RAM_DED_ERR 10
>> PolarFire PCIe contain total 28 interrupts event while PLDA contain 13
>> local interrupts event, interrupt to event num mapping is different.
>
> It "is different" in different platforms ? Is that correct ?
>
yes
>> So add a callback function to support different IRQ register function.
>> Also Add PLDA default handler function, which will be moved to pcie-
>> plda-host.c in moving codes patch.
>
> As I said before, a patch is a single self-contained change, don't
> refer to other patches, they may or may not be merged or even exist
> by the time this one hits mainline.
>
> Lorenzo
>
OK. I will delete the "which will be moved to pcie-plda-host.c in
moving codes patch" and change the commit message.
>> Signed-off-by: Minda Chen <[email protected]>
>> Acked-by: Conor Dooley <[email protected]>
>> ---
>> .../pci/controller/plda/pcie-microchip-host.c | 31 ++++++++++++++++---
>> drivers/pci/controller/plda/pcie-plda.h | 5 +++
>> 2 files changed, 32 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
>> index 7b3f4f74745d..624e4e2e97d3 100644
>> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
>> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
>> @@ -643,6 +643,11 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
>> return IRQ_HANDLED;
>> }
>>
>> +static irqreturn_t plda_event_handler(int irq, void *dev_id)
>> +{
>> + return IRQ_HANDLED;
>> +}
>> +
>> static void plda_handle_event(struct irq_desc *desc)
>> {
>> struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
>> @@ -804,6 +809,17 @@ static int mc_pcie_init_clks(struct device *dev)
>> return 0;
>> }
>>
>> +static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
>> + int event)
>> +{
>> + return devm_request_irq(plda->dev, event_irq, mc_event_handler,
>> + 0, event_cause[event].sym, plda);
>> +}
>> +
>> +static const struct plda_event mc_event = {
>> + .request_event_irq = mc_request_event_irq,
>> +};
>> +
>> static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
>> {
>> struct device *dev = port->dev;
>> @@ -905,7 +921,9 @@ static void mc_disable_interrupts(struct mc_pcie *port)
>> writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
>> }
>>
>> -static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
>> +static int plda_init_interrupts(struct platform_device *pdev,
>> + struct plda_pcie_rp *port,
>> + const struct plda_event *event)
>> {
>> struct device *dev = &pdev->dev;
>> int irq;
>> @@ -929,8 +947,13 @@ static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_r
>> return -ENXIO;
>> }
>>
>> - ret = devm_request_irq(dev, event_irq, mc_event_handler,
>> - 0, event_cause[i].sym, port);
>> + if (event->request_event_irq)
>> + ret = event->request_event_irq(port, event_irq, i);
>> + else
>> + ret = devm_request_irq(dev, event_irq,
>> + plda_event_handler,
>> + 0, NULL, port);
>> +
>> if (ret) {
>> dev_err(dev, "failed to request IRQ %d\n", event_irq);
>> return ret;
>> @@ -984,7 +1007,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
>> return ret;
>>
>> /* Address translation is up; safe to enable interrupts */
>> - ret = plda_init_interrupts(pdev, &port->plda);
>> + ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
>> if (ret)
>> return ret;
>>
>> diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
>> index e3d35cef9894..28ed1374e1de 100644
>> --- a/drivers/pci/controller/plda/pcie-plda.h
>> +++ b/drivers/pci/controller/plda/pcie-plda.h
>> @@ -121,6 +121,11 @@ struct plda_pcie_rp {
>> int num_events;
>> };
>>
>> +struct plda_event {
>> + int (*request_event_irq)(struct plda_pcie_rp *pcie,
>> + int event_irq, int event);
>> +};
>> +
>> void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
>> phys_addr_t axi_addr, phys_addr_t pci_addr,
>> size_t size);
>> --
>> 2.17.1
>>
On 2023/12/27 23:55, Lorenzo Pieralisi wrote:
> On Thu, Dec 14, 2023 at 03:28:29PM +0800, Minda Chen wrote:
>> The event num is different in other platform. For re-using interrupt
>> process codes, replace macros with variable.
>
> "The number of events is different across platforms. In order to
> share interrupt processing code, add a variable that defines the
> number of events so that it can be set per-platform instead of
> hardcoding it".
>
> Lorenzo
>
Thanks for reviewing. Happy new year!
All the maintainers:
Happy new year!
>>
>> Signed-off-by: Minda Chen <[email protected]>
>> Reviewed-by: Conor Dooley <[email protected]>
>> ---
>> drivers/pci/controller/plda/pcie-microchip-host.c | 8 +++++---
>> drivers/pci/controller/plda/pcie-plda.h | 1 +
>> 2 files changed, 6 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
>> index 506e6eeadc76..7b3f4f74745d 100644
>> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
>> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
>> @@ -654,7 +654,7 @@ static void plda_handle_event(struct irq_desc *desc)
>>
>> events = mc_get_events(port);
>>
>> - for_each_set_bit(bit, &events, NUM_EVENTS)
>> + for_each_set_bit(bit, &events, port->num_events)
>> generic_handle_domain_irq(port->event_domain, bit);
>>
>> chained_irq_exit(chip, desc);
>> @@ -817,7 +817,8 @@ static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
>> return -EINVAL;
>> }
>>
>> - port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
>> + port->event_domain = irq_domain_add_linear(pcie_intc_node,
>> + port->num_events,
>> &plda_event_domain_ops,
>> port);
>> if (!port->event_domain) {
>> @@ -921,7 +922,7 @@ static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_r
>> if (irq < 0)
>> return -ENODEV;
>>
>> - for (i = 0; i < NUM_EVENTS; i++) {
>> + for (i = 0; i < port->num_events; i++) {
>> event_irq = irq_create_mapping(port->event_domain, i);
>> if (!event_irq) {
>> dev_err(dev, "failed to map hwirq %d\n", i);
>> @@ -1013,6 +1014,7 @@ static int mc_host_probe(struct platform_device *pdev)
>>
>> bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
>> plda->bridge_addr = bridge_base_addr;
>> + plda->num_events = NUM_EVENTS;
>>
>> /* Allow enabling MSI by disabling MSI-X */
>> val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
>> diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
>> index 3deefd35fa5a..e3d35cef9894 100644
>> --- a/drivers/pci/controller/plda/pcie-plda.h
>> +++ b/drivers/pci/controller/plda/pcie-plda.h
>> @@ -118,6 +118,7 @@ struct plda_pcie_rp {
>> raw_spinlock_t lock;
>> struct plda_msi msi;
>> void __iomem *bridge_addr;
>> + int num_events;
>> };
>>
>> void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
>> --
>> 2.17.1
>>
On 2023/12/27 23:52, Lorenzo Pieralisi wrote:
> On Thu, Dec 14, 2023 at 03:28:28PM +0800, Minda Chen wrote:
>> Rename mc_* to plda_* for IRQ functions and related IRQ domain ops data
>> instances.
>>
>> MSI, INTx interrupt codes and IRQ init codes are all can be re-used.
>
> s/codes/code
>
ack.
>>
>> - function rename list:
>> mc_allocate_msi_domains() --> plda_allocate_msi_domains()
>> mc_init_interrupts() --> plda_init_interrupts()
>> mc_pcie_init_irq_domain() --> plda_pcie_init_irq_domains()
>> mc_handle_event() --> plda_handle_event()
>> get_events() --> mc_get_events()
>>
>> MSI interrupts related functions and IRQ domain
>> (primary function is mc_handle_msi()):
>> mc_handle_msi() --> plda_handle_msi()
>> INTx interrupts related functions and IRQ domain
>> (primary function is mc_handle_intx()):
>> mc_handle_intx() --> plda_handle_intx()
>
> We can read the code you are changing, there is no need to
> add it to the commit log, especially because it is a trivial
> rename here.
>
OK, Thanks
>> Signed-off-by: Minda Chen <[email protected]>
>> Acked-by: Conor Dooley <[email protected]>
>> ---
>> .../pci/controller/plda/pcie-microchip-host.c | 112 +++++++++---------
>> 1 file changed, 59 insertions(+), 53 deletions(-)
>>
>> diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
>> index 2e79bcc7c0a5..506e6eeadc76 100644
>> --- a/drivers/pci/controller/plda/pcie-microchip-host.c
>> +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
>> @@ -318,7 +318,7 @@ static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
>> ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
>> }
>>
>> -static void mc_handle_msi(struct irq_desc *desc)
>> +static void plda_handle_msi(struct irq_desc *desc)
>> {
>> struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
>> struct irq_chip *chip = irq_desc_get_chip(desc);
>> @@ -333,7 +333,8 @@ static void mc_handle_msi(struct irq_desc *desc)
>>
>> status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
>> if (status & PM_MSI_INT_MSI_MASK) {
>> - writel_relaxed(status & PM_MSI_INT_MSI_MASK, bridge_base_addr + ISTATUS_LOCAL);
>> + writel_relaxed(status & PM_MSI_INT_MSI_MASK,
>> + bridge_base_addr + ISTATUS_LOCAL);
>
> Unrelated change (I suspect checkpatch nudged you to make it; it
> is tempting but it does not belong in this patch).
>
> Lorenzo
>
>> status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
>> for_each_set_bit(bit, &status, msi->num_vectors) {
>> ret = generic_handle_domain_irq(msi->dev_domain, bit);
>> @@ -346,7 +347,7 @@ static void mc_handle_msi(struct irq_desc *desc)
>> chained_irq_exit(chip, desc);
>> }
>>
>> -static void mc_msi_bottom_irq_ack(struct irq_data *data)
>> +static void plda_msi_bottom_irq_ack(struct irq_data *data)
>> {
>> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> void __iomem *bridge_base_addr = port->bridge_addr;
>> @@ -355,7 +356,7 @@ static void mc_msi_bottom_irq_ack(struct irq_data *data)
>> writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
>> }
>>
>> -static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
>> +static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
>> {
>> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> phys_addr_t addr = port->msi.vector_phy;
>> @@ -368,21 +369,23 @@ static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
>> (int)data->hwirq, msg->address_hi, msg->address_lo);
>> }
>>
>> -static int mc_msi_set_affinity(struct irq_data *irq_data,
>> - const struct cpumask *mask, bool force)
>> +static int plda_msi_set_affinity(struct irq_data *irq_data,
>> + const struct cpumask *mask, bool force)
>> {
>> return -EINVAL;
>> }
>>
>> -static struct irq_chip mc_msi_bottom_irq_chip = {
>> - .name = "Microchip MSI",
>> - .irq_ack = mc_msi_bottom_irq_ack,
>> - .irq_compose_msi_msg = mc_compose_msi_msg,
>> - .irq_set_affinity = mc_msi_set_affinity,
>> +static struct irq_chip plda_msi_bottom_irq_chip = {
>> + .name = "PLDA MSI",
>> + .irq_ack = plda_msi_bottom_irq_ack,
>> + .irq_compose_msi_msg = plda_compose_msi_msg,
>> + .irq_set_affinity = plda_msi_set_affinity,
>> };
>>
>> -static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
>> - unsigned int nr_irqs, void *args)
>> +static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
>> + unsigned int virq,
>> + unsigned int nr_irqs,
>> + void *args)
>> {
>> struct plda_pcie_rp *port = domain->host_data;
>> struct plda_msi *msi = &port->msi;
>> @@ -397,7 +400,7 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
>>
>> set_bit(bit, msi->used);
>>
>> - irq_domain_set_info(domain, virq, bit, &mc_msi_bottom_irq_chip,
>> + irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
>> domain->host_data, handle_edge_irq, NULL, NULL);
>>
>> mutex_unlock(&msi->lock);
>> @@ -405,8 +408,9 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
>> return 0;
>> }
>>
>> -static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
>> - unsigned int nr_irqs)
>> +static void plda_irq_msi_domain_free(struct irq_domain *domain,
>> + unsigned int virq,
>> + unsigned int nr_irqs)
>> {
>> struct irq_data *d = irq_domain_get_irq_data(domain, virq);
>> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
>> @@ -423,24 +427,24 @@ static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
>> }
>>
>> static const struct irq_domain_ops msi_domain_ops = {
>> - .alloc = mc_irq_msi_domain_alloc,
>> - .free = mc_irq_msi_domain_free,
>> + .alloc = plda_irq_msi_domain_alloc,
>> + .free = plda_irq_msi_domain_free,
>> };
>>
>> -static struct irq_chip mc_msi_irq_chip = {
>> - .name = "Microchip PCIe MSI",
>> +static struct irq_chip plda_msi_irq_chip = {
>> + .name = "PLDA PCIe MSI",
>> .irq_ack = irq_chip_ack_parent,
>> .irq_mask = pci_msi_mask_irq,
>> .irq_unmask = pci_msi_unmask_irq,
>> };
>>
>> -static struct msi_domain_info mc_msi_domain_info = {
>> +static struct msi_domain_info plda_msi_domain_info = {
>> .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
>> MSI_FLAG_PCI_MSIX),
>> - .chip = &mc_msi_irq_chip,
>> + .chip = &plda_msi_irq_chip,
>> };
>>
>> -static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
>> +static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
>> {
>> struct device *dev = port->dev;
>> struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
>> @@ -455,7 +459,8 @@ static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
>> return -ENOMEM;
>> }
>>
>> - msi->msi_domain = pci_msi_create_irq_domain(fwnode, &mc_msi_domain_info,
>> + msi->msi_domain = pci_msi_create_irq_domain(fwnode,
>> + &plda_msi_domain_info,
>> msi->dev_domain);
>> if (!msi->msi_domain) {
>> dev_err(dev, "failed to create MSI domain\n");
>> @@ -466,7 +471,7 @@ static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
>> return 0;
>> }
>>
>> -static void mc_handle_intx(struct irq_desc *desc)
>> +static void plda_handle_intx(struct irq_desc *desc)
>> {
>> struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
>> struct irq_chip *chip = irq_desc_get_chip(desc);
>> @@ -493,7 +498,7 @@ static void mc_handle_intx(struct irq_desc *desc)
>> chained_irq_exit(chip, desc);
>> }
>>
>> -static void mc_ack_intx_irq(struct irq_data *data)
>> +static void plda_ack_intx_irq(struct irq_data *data)
>> {
>> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> void __iomem *bridge_base_addr = port->bridge_addr;
>> @@ -502,7 +507,7 @@ static void mc_ack_intx_irq(struct irq_data *data)
>> writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
>> }
>>
>> -static void mc_mask_intx_irq(struct irq_data *data)
>> +static void plda_mask_intx_irq(struct irq_data *data)
>> {
>> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> void __iomem *bridge_base_addr = port->bridge_addr;
>> @@ -517,7 +522,7 @@ static void mc_mask_intx_irq(struct irq_data *data)
>> raw_spin_unlock_irqrestore(&port->lock, flags);
>> }
>>
>> -static void mc_unmask_intx_irq(struct irq_data *data)
>> +static void plda_unmask_intx_irq(struct irq_data *data)
>> {
>> struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
>> void __iomem *bridge_base_addr = port->bridge_addr;
>> @@ -532,24 +537,24 @@ static void mc_unmask_intx_irq(struct irq_data *data)
>> raw_spin_unlock_irqrestore(&port->lock, flags);
>> }
>>
>> -static struct irq_chip mc_intx_irq_chip = {
>> - .name = "Microchip PCIe INTx",
>> - .irq_ack = mc_ack_intx_irq,
>> - .irq_mask = mc_mask_intx_irq,
>> - .irq_unmask = mc_unmask_intx_irq,
>> +static struct irq_chip plda_intx_irq_chip = {
>> + .name = "PLDA PCIe INTx",
>> + .irq_ack = plda_ack_intx_irq,
>> + .irq_mask = plda_mask_intx_irq,
>> + .irq_unmask = plda_unmask_intx_irq,
>> };
>>
>> -static int mc_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
>> - irq_hw_number_t hwirq)
>> +static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
>> + irq_hw_number_t hwirq)
>> {
>> - irq_set_chip_and_handler(irq, &mc_intx_irq_chip, handle_level_irq);
>> + irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
>> irq_set_chip_data(irq, domain->host_data);
>>
>> return 0;
>> }
>>
>> static const struct irq_domain_ops intx_domain_ops = {
>> - .map = mc_pcie_intx_map,
>> + .map = plda_pcie_intx_map,
>> };
>>
>> static inline u32 reg_to_event(u32 reg, struct event_map field)
>> @@ -609,7 +614,7 @@ static u32 local_events(struct mc_pcie *port)
>> return val;
>> }
>>
>> -static u32 get_events(struct plda_pcie_rp *port)
>> +static u32 mc_get_events(struct plda_pcie_rp *port)
>> {
>> struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
>> u32 events = 0;
>> @@ -638,7 +643,7 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
>> return IRQ_HANDLED;
>> }
>>
>> -static void mc_handle_event(struct irq_desc *desc)
>> +static void plda_handle_event(struct irq_desc *desc)
>> {
>> struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
>> unsigned long events;
>> @@ -647,7 +652,7 @@ static void mc_handle_event(struct irq_desc *desc)
>>
>> chained_irq_enter(chip, desc);
>>
>> - events = get_events(port);
>> + events = mc_get_events(port);
>>
>> for_each_set_bit(bit, &events, NUM_EVENTS)
>> generic_handle_domain_irq(port->event_domain, bit);
>> @@ -741,8 +746,8 @@ static struct irq_chip mc_event_irq_chip = {
>> .irq_unmask = mc_unmask_event_irq,
>> };
>>
>> -static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
>> - irq_hw_number_t hwirq)
>> +static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
>> + irq_hw_number_t hwirq)
>> {
>> irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
>> irq_set_chip_data(irq, domain->host_data);
>> @@ -750,8 +755,8 @@ static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
>> return 0;
>> }
>>
>> -static const struct irq_domain_ops event_domain_ops = {
>> - .map = mc_pcie_event_map,
>> +static const struct irq_domain_ops plda_event_domain_ops = {
>> + .map = plda_pcie_event_map,
>> };
>>
>> static inline void mc_pcie_deinit_clk(void *data)
>> @@ -799,7 +804,7 @@ static int mc_pcie_init_clks(struct device *dev)
>> return 0;
>> }
>>
>> -static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
>> +static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
>> {
>> struct device *dev = port->dev;
>> struct device_node *node = dev->of_node;
>> @@ -813,7 +818,8 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
>> }
>>
>> port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
>> - &event_domain_ops, port);
>> + &plda_event_domain_ops,
>> + port);
>> if (!port->event_domain) {
>> dev_err(dev, "failed to get event domain\n");
>> of_node_put(pcie_intc_node);
>> @@ -835,7 +841,7 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
>> of_node_put(pcie_intc_node);
>> raw_spin_lock_init(&port->lock);
>>
>> - return mc_allocate_msi_domains(port);
>> + return plda_allocate_msi_domains(port);
>> }
>>
>> static inline void mc_clear_secs(struct mc_pcie *port)
>> @@ -898,14 +904,14 @@ static void mc_disable_interrupts(struct mc_pcie *port)
>> writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
>> }
>>
>> -static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
>> +static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
>> {
>> struct device *dev = &pdev->dev;
>> int irq;
>> int i, intx_irq, msi_irq, event_irq;
>> int ret;
>>
>> - ret = mc_pcie_init_irq_domains(port);
>> + ret = plda_pcie_init_irq_domains(port);
>> if (ret) {
>> dev_err(dev, "failed creating IRQ domains\n");
>> return ret;
>> @@ -938,7 +944,7 @@ static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp
>> }
>>
>> /* Plug the INTx chained handler */
>> - irq_set_chained_handler_and_data(intx_irq, mc_handle_intx, port);
>> + irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
>>
>> msi_irq = irq_create_mapping(port->event_domain,
>> EVENT_LOCAL_PM_MSI_INT_MSI);
>> @@ -946,10 +952,10 @@ static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp
>> return -ENXIO;
>>
>> /* Plug the MSI chained handler */
>> - irq_set_chained_handler_and_data(msi_irq, mc_handle_msi, port);
>> + irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
>>
>> /* Plug the main event chained handler */
>> - irq_set_chained_handler_and_data(irq, mc_handle_event, port);
>> + irq_set_chained_handler_and_data(irq, plda_handle_event, port);
>>
>> return 0;
>> }
>> @@ -977,7 +983,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
>> return ret;
>>
>> /* Address translation is up; safe to enable interrupts */
>> - ret = mc_init_interrupts(pdev, &port->plda);
>> + ret = plda_init_interrupts(pdev, &port->plda);
>> if (ret)
>> return ret;
>>
>> --
>> 2.17.1
>>
Minda Chen <[email protected]> writes:
> This patchset final purpose is add PCIe driver for StarFive JH7110 SoC.
> JH7110 using PLDA XpressRICH PCIe IP. Microchip PolarFire Using the
> same IP and have commit their codes, which are mixed with PLDA
> controller codes and Microchip platform codes.
Thank you for this series.
I tested this on a VisionFive v2 board, and it seems to probe and find my
M.2 NVMe SSD, but then gets timeouts when trying to use the NVMe
(e.g. 'blkid' command)
Kernel logs below.
Kevin
[ 15.131094] pcie-starfive 9c0000000.pcie: host bridge /soc/pcie@9c0000000 ranges:
[ 15.138637] pcie-starfive 9c0000000.pcie: MEM 0x0038000000..0x003fffffff -> 0x0038000000
[ 15.147180] pcie-starfive 9c0000000.pcie: MEM 0x0980000000..0x09bfffffff -> 0x0980000000
[ 15.368040] pcie-starfive 9c0000000.pcie: port link up
[ 15.374219] pcie-starfive 9c0000000.pcie: PCI host bridge to bus 0001:00
[ 15.380944] pci_bus 0001:00: root bus resource [bus 00-ff]
[ 15.386443] pci_bus 0001:00: root bus resource [mem 0x38000000-0x3fffffff]
[ 15.393330] pci_bus 0001:00: root bus resource [mem 0x980000000-0x9bfffffff pref]
[ 15.400882] pci 0001:00:00.0: [1556:1111] type 01 class 0x060400
[ 15.407165] pci 0001:00:00.0: supports D1 D2
[ 15.411447] pci 0001:00:00.0: PME# supported from D0 D1 D2 D3hot D3cold
[ 15.419964] pci 0001:00:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
[ 15.428245] pci 0001:01:00.0: [126f:2263] type 00 class 0x010802
[ 15.434331] pci 0001:01:00.0: reg 0x10: [mem 0x00000000-0x00003fff 64bit]
[ 15.441578] pci 0001:01:00.0: 4.000 Gb/s available PCIe bandwidth, limited by 5.0 GT/s PCIe x1 link at 0001:00:00.0 (capable of 31.504 Gb/s with 8
.0 GT/s PCIe x4 link)
[ 15.456910] pci_bus 0001:01: busn_res: [bus 01-ff] end is updated to 01
[ 15.463553] pci 0001:00:00.0: BAR 8: assigned [mem 0x38000000-0x380fffff]
[ 15.470352] pci 0001:01:00.0: BAR 0: assigned [mem 0x38000000-0x38003fff 64bit]
[ 15.477699] pci 0001:00:00.0: PCI bridge to [bus 01]
[ 15.482686] pci 0001:00:00.0: bridge window [mem 0x38000000-0x380fffff]
[ 15.489632] pcieport 0001:00:00.0: enabling device (0000 -> 0002)
[ 15.496038] pcieport 0001:00:00.0: PME: Signaling with IRQ 56
[ 15.502472] usb 1-1: new high-speed USB device number 2 using xhci_hcd
[ 15.509755] usb usb2-port2: over-current condition
[ 15.515883] nvme nvme0: pci function 0001:01:00.0
[ 15.520615] nvme 0001:01:00.0: enabling device (0000 -> 0002)
[ 15.532685] nvme nvme0: allocated 64 MiB host memory buffer.
[ 15.550070] nvme nvme0: 4/0/0 default/read/poll queues
[ 15.562992] nvme nvme0: Ignoring bogus Namespace Identifiers
[ 15.663327] hub 1-1:1.0: USB hub found
[ 15.667320] hub 1-1:1.0: 4 ports detected
[ 46.064052] nvme nvme0: I/O 424 QID 3 timeout, completion polled
[ 76.784046] nvme nvme0: I/O 425 (I/O Cmd) QID 3 timeout, aborting
[ 76.790179] nvme nvme0: I/O 426 (I/O Cmd) QID 3 timeout, aborting
[ 76.796294] nvme nvme0: I/O 427 (I/O Cmd) QID 3 timeout, aborting
[ 76.802411] nvme nvme0: I/O 428 (I/O Cmd) QID 3 timeout, aborting
[ 76.808525] nvme nvme0: I/O 429 (I/O Cmd) QID 3 timeout, aborting
> Minda Chen <[email protected]> writes:
>
> > This patchset final purpose is add PCIe driver for StarFive JH7110 SoC.
> > JH7110 using PLDA XpressRICH PCIe IP. Microchip PolarFire Using the
> > same IP and have commit their codes, which are mixed with PLDA
> > controller codes and Microchip platform codes.
>
> Thank you for this series.
>
> I tested this on a VisionFive v2 board, and it seems to probe and find my
> M.2 NVMe SSD, but then gets timeouts when trying to use the NVMe (e.g.
> 'blkid' command)
>
Hi, Kevin:
Could you please provide the manufacturer and model of the M.2 NVMe SSD
you tested?
> Kernel logs below.
>
> Kevin
>
> [ 15.131094] pcie-starfive 9c0000000.pcie: host bridge
> /soc/pcie@9c0000000 ranges:
> [ 15.138637] pcie-starfive 9c0000000.pcie: MEM
> 0x0038000000..0x003fffffff -> 0x0038000000
> [ 15.147180] pcie-starfive 9c0000000.pcie: MEM
> 0x0980000000..0x09bfffffff -> 0x0980000000
> [ 15.368040] pcie-starfive 9c0000000.pcie: port link up
> [ 15.374219] pcie-starfive 9c0000000.pcie: PCI host bridge to bus 0001:00
> [ 15.380944] pci_bus 0001:00: root bus resource [bus 00-ff]
> [ 15.386443] pci_bus 0001:00: root bus resource [mem
> 0x38000000-0x3fffffff]
> [ 15.393330] pci_bus 0001:00: root bus resource [mem
> 0x980000000-0x9bfffffff pref]
> [ 15.400882] pci 0001:00:00.0: [1556:1111] type 01 class 0x060400
> [ 15.407165] pci 0001:00:00.0: supports D1 D2
> [ 15.411447] pci 0001:00:00.0: PME# supported from D0 D1 D2 D3hot
> D3cold
> [ 15.419964] pci 0001:00:00.0: bridge configuration invalid ([bus 00-00]),
> reconfiguring
> [ 15.428245] pci 0001:01:00.0: [126f:2263] type 00 class 0x010802
> [ 15.434331] pci 0001:01:00.0: reg 0x10: [mem 0x00000000-0x00003fff
> 64bit]
> [ 15.441578] pci 0001:01:00.0: 4.000 Gb/s available PCIe bandwidth,
> limited by 5.0 GT/s PCIe x1 link at 0001:00:00.0 (capable of 31.504 Gb/s with
> 8
> .0 GT/s PCIe x4 link)
> [ 15.456910] pci_bus 0001:01: busn_res: [bus 01-ff] end is updated to 01
> [ 15.463553] pci 0001:00:00.0: BAR 8: assigned [mem
> 0x38000000-0x380fffff]
> [ 15.470352] pci 0001:01:00.0: BAR 0: assigned [mem
> 0x38000000-0x38003fff 64bit]
> [ 15.477699] pci 0001:00:00.0: PCI bridge to [bus 01]
> [ 15.482686] pci 0001:00:00.0: bridge window [mem
> 0x38000000-0x380fffff]
> [ 15.489632] pcieport 0001:00:00.0: enabling device (0000 -> 0002)
> [ 15.496038] pcieport 0001:00:00.0: PME: Signaling with IRQ 56
> [ 15.502472] usb 1-1: new high-speed USB device number 2 using xhci_hcd
> [ 15.509755] usb usb2-port2: over-current condition
> [ 15.515883] nvme nvme0: pci function 0001:01:00.0
> [ 15.520615] nvme 0001:01:00.0: enabling device (0000 -> 0002)
> [ 15.532685] nvme nvme0: allocated 64 MiB host memory buffer.
> [ 15.550070] nvme nvme0: 4/0/0 default/read/poll queues
> [ 15.562992] nvme nvme0: Ignoring bogus Namespace Identifiers
> [ 15.663327] hub 1-1:1.0: USB hub found
> [ 15.667320] hub 1-1:1.0: 4 ports detected
>
> [ 46.064052] nvme nvme0: I/O 424 QID 3 timeout, completion polled
>
> [ 76.784046] nvme nvme0: I/O 425 (I/O Cmd) QID 3 timeout, aborting
> [ 76.790179] nvme nvme0: I/O 426 (I/O Cmd) QID 3 timeout, aborting
> [ 76.796294] nvme nvme0: I/O 427 (I/O Cmd) QID 3 timeout, aborting
> [ 76.802411] nvme nvme0: I/O 428 (I/O Cmd) QID 3 timeout, aborting
> [ 76.808525] nvme nvme0: I/O 429 (I/O Cmd) QID 3 timeout, aborting
Kevin Xie <[email protected]> writes:
>> Minda Chen <[email protected]> writes:
>>
>> > This patchset final purpose is add PCIe driver for StarFive JH7110 SoC.
>> > JH7110 using PLDA XpressRICH PCIe IP. Microchip PolarFire Using the
>> > same IP and have commit their codes, which are mixed with PLDA
>> > controller codes and Microchip platform codes.
>>
>> Thank you for this series.
>>
>> I tested this on a VisionFive v2 board, and it seems to probe and find my
>> M.2 NVMe SSD, but then gets timeouts when trying to use the NVMe (e.g.
>> 'blkid' command)
>>
>
> Hi, Kevin:
> Could you please provide the manufacturer and model of the M.2 NVMe SSD
> you tested?
I have a 256 Gb Silicon Power P34A60 M.2 NVMe SSD (part number: sp256gbp34a60m28)
Also for reference, I tested the same SSD on another arm platform
(Khadas VIM3) and it works fine.
Kevin
> Kevin Xie <[email protected]> writes:
>
> >> Minda Chen <[email protected]> writes:
> >>
> >> > This patchset final purpose is add PCIe driver for StarFive JH7110 SoC.
> >> > JH7110 using PLDA XpressRICH PCIe IP. Microchip PolarFire Using the
> >> > same IP and have commit their codes, which are mixed with PLDA
> >> > controller codes and Microchip platform codes.
> >>
> >> Thank you for this series.
> >>
> >> I tested this on a VisionFive v2 board, and it seems to probe and
> >> find my
> >> M.2 NVMe SSD, but then gets timeouts when trying to use the NVMe (e.g.
> >> 'blkid' command)
> >>
> >
> > Hi, Kevin:
> > Could you please provide the manufacturer and model of the M.2 NVMe
> > SSD you tested?
>
> I have a 256 Gb Silicon Power P34A60 M.2 NVMe SSD (part number:
> sp256gbp34a60m28)
>
Thanks, Kevin, we will buy one to test.
Before doing this refactoring, we encountered the same bug with Kingston M.2 SSD,
and we workaround the problem with the below patch, please have a try:
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 507bc149046d..5be37f1ee150 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1059,6 +1059,16 @@ static inline int nvme_poll_cq(struct nvme_queue *nvmeq,
{
int found = 0;
+ /*
+ * In some cases, such as JH7110 SoC working with Kingston SSD,
+ * the CQE status may update a little bit later than the MSI,
+ * which cause an IRQ handle missing.
+ * As a workaround, here we will check the status first, and wait
+ * 1us if we get nothing.
+ */
+ if (!nvme_cqe_pending(nvmeq))
+ udelay(1);
+
while (nvme_cqe_pending(nvmeq)) {
found++;
/*
> Also for reference, I tested the same SSD on another arm platform (Khadas
> VIM3) and it works fine.
>
> Kevin
Hi, Bjorn:
Do you have any idea about the late CQE phase update condition as mentioned
in the patch comments above?
This is an issue that occurs with a small probability on individual devices in our
platform.
Thus, I suggest the refactoring patch set should go forward.
Later we will try to find a more formal solution instead, and send a new patch.
Kevin Xie wrote:
> > Kevin Xie <[email protected]> writes:
> >
> > >> Minda Chen <[email protected]> writes:
> > >>
> > >> > This patchset final purpose is add PCIe driver for StarFive JH7110 SoC.
> > >> > JH7110 using PLDA XpressRICH PCIe IP. Microchip PolarFire Using the
> > >> > same IP and have commit their codes, which are mixed with PLDA
> > >> > controller codes and Microchip platform codes.
> > >>
> > >> Thank you for this series.
> > >>
> > >> I tested this on a VisionFive v2 board, and it seems to probe and
> > >> find my
> > >> M.2 NVMe SSD, but then gets timeouts when trying to use the NVMe (e.g.
> > >> 'blkid' command)
> > >>
> > >
> > > Hi, Kevin:
> > > Could you please provide the manufacturer and model of the M.2 NVMe
> > > SSD you tested?
> >
> > I have a 256 Gb Silicon Power P34A60 M.2 NVMe SSD (part number:
> > sp256gbp34a60m28)
> >
> Thanks, Kevin, we will buy one to test.
>
> Before doing this refactoring, we encountered the same bug with Kingston M.2 SSD,
> and we workaround the problem with the below patch, please have a try:
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 507bc149046d..5be37f1ee150 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -1059,6 +1059,16 @@ static inline int nvme_poll_cq(struct nvme_queue *nvmeq,
> {
> int found = 0;
>
> + /*
> + * In some cases, such as JH7110 SoC working with Kingston SSD,
> + * the CQE status may update a little bit later than the MSI,
> + * which cause an IRQ handle missing.
> + * As a workaround, here we will check the status first, and wait
> + * 1us if we get nothing.
> + */
> + if (!nvme_cqe_pending(nvmeq))
> + udelay(1);
> +
> while (nvme_cqe_pending(nvmeq)) {
> found++;
> /*
>
Hi Kevin,
Thanks, this fixes the same problem on my WD Blue SN570 250GB.
Before this patch I found that CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y fixed the
problem, but it's now clear that this only slowed my kernel enough that this
wouldn't trigger as often.
/Emil
> > Also for reference, I tested the same SSD on another arm platform (Khadas
> > VIM3) and it works fine.
> >
> > Kevin
>
> Hi, Bjorn:
> Do you have any idea about the late CQE phase update condition as mentioned
> in the patch comments above?
> This is an issue that occurs with a small probability on individual devices in our
> platform.
> Thus, I suggest the refactoring patch set should go forward.
> Later we will try to find a more formal solution instead, and send a new patch.
> _______________________________________________
> linux-riscv mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-riscv