[v6,08/19] PCI: plda: Add event interrupt codes and IRQ domain ops
Commit Message
For PolarFire implements non-PLDA local interrupt events, most of
event interrupt process codes can not be re-used. PLDA implements
new codes and IRQ domain ops like PolarFire.
plda_get_events() adds a new IRQ num to event num mapping codes for
PLDA local event except DMA engine interrupt events. The DMA engine
interrupt events are implemented by vendors.
Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
---
drivers/pci/controller/plda/pcie-plda-host.c | 99 ++++++++++++++++++++
drivers/pci/controller/plda/pcie-plda.h | 33 +++++++
2 files changed, 132 insertions(+)
Comments
On Fri, Sep 15, 2023 at 06:22:32PM +0800, Minda Chen wrote:
> For PolarFire implements non-PLDA local interrupt events, most of
> event interrupt process codes can not be re-used. PLDA implements
> new codes and IRQ domain ops like PolarFire.
>
> plda_get_events() adds a new IRQ num to event num mapping codes for
> PLDA local event except DMA engine interrupt events. The DMA engine
> interrupt events are implemented by vendors.
>
> Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
Perhaps not important as they will go away in the next patch, but for
this patch the riscv patchwork stuff noticed:
drivers/pci/controller/plda/pcie-plda-host.c:114:36: warning: unused variable 'plda_evt_dom_ops' [-Wunused-const-variable]
drivers/pci/controller/plda/pcie-plda-host.c:118:36: warning: unused variable 'plda_event_ops' [-Wunused-const-variable]
Cheers,
Conor.
> ---
> drivers/pci/controller/plda/pcie-plda-host.c | 99 ++++++++++++++++++++
> drivers/pci/controller/plda/pcie-plda.h | 33 +++++++
> 2 files changed, 132 insertions(+)
>
> diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
> index f0c7636f1f64..f29ff0f00dda 100644
> --- a/drivers/pci/controller/plda/pcie-plda-host.c
> +++ b/drivers/pci/controller/plda/pcie-plda-host.c
> @@ -20,6 +20,105 @@
>
> #include "pcie-plda.h"
>
> +irqreturn_t plda_event_handler(int irq, void *dev_id)
> +{
> + return IRQ_HANDLED;
> +}
> +
> +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 >> A_ATR_EVT_POST_ERR_SHIFT) & 0xff;
> +
> + /* INTx events */
> + if (origin & PM_MSI_INT_INTX_MASK)
> + events |= BIT(EVENT_PM_MSI_INT_INTX);
> +
> + /* MSI event and sys events */
> + val = (origin >> PM_MSI_INT_MSI_SHIFT) & 0xf;
> + events |= val << EVENT_PM_MSI_INT_MSI;
> +
> + return events;
> +}
> +
> +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 int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
> + irq_hw_number_t hwirq)
> +{
> + irq_set_chip_and_handler(irq, &plda_event_irq_chip, handle_level_irq);
> + irq_set_chip_data(irq, domain->host_data);
> +
> + return 0;
> +}
> +
> +static const struct irq_domain_ops plda_evt_dom_ops = {
> + .map = plda_pcie_event_map,
> +};
> +
> +static const struct plda_event_ops plda_event_ops = {
> + .get_events = plda_get_events,
> +};
> +
> 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 3deefd35fa5a..32a913d4101f 100644
> --- a/drivers/pci/controller/plda/pcie-plda.h
> +++ b/drivers/pci/controller/plda/pcie-plda.h
> @@ -102,6 +102,38 @@
> #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
> + */
> +
> +#define PM_MSI_TO_MASK_OFFSET 19
> +
> +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;
> @@ -120,6 +152,7 @@ struct plda_pcie_rp {
> void __iomem *bridge_addr;
> };
>
> +irqreturn_t plda_event_handler(int irq, void *dev_id);
> 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 Sat, Sep 16, 2023 at 01:11:29AM +0100, Conor Dooley wrote:
> On Fri, Sep 15, 2023 at 06:22:32PM +0800, Minda Chen wrote:
> > For PolarFire implements non-PLDA local interrupt events, most of
> > event interrupt process codes can not be re-used. PLDA implements
> > new codes and IRQ domain ops like PolarFire.
> >
> > plda_get_events() adds a new IRQ num to event num mapping codes for
> > PLDA local event except DMA engine interrupt events. The DMA engine
> > interrupt events are implemented by vendors.
> >
> > Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
>
> Perhaps not important as they will go away in the next patch, but for
> this patch the riscv patchwork stuff noticed:
> drivers/pci/controller/plda/pcie-plda-host.c:114:36: warning: unused variable 'plda_evt_dom_ops' [-Wunused-const-variable]
> drivers/pci/controller/plda/pcie-plda-host.c:118:36: warning: unused variable 'plda_event_ops' [-Wunused-const-variable]
Details like this *are* important because fixing them makes the
individual patches more readable, thanks for noticing!
Bjorn
On 2023/9/21 23:08, Bjorn Helgaas wrote:
> On Sat, Sep 16, 2023 at 01:11:29AM +0100, Conor Dooley wrote:
>> On Fri, Sep 15, 2023 at 06:22:32PM +0800, Minda Chen wrote:
>> > For PolarFire implements non-PLDA local interrupt events, most of
>> > event interrupt process codes can not be re-used. PLDA implements
>> > new codes and IRQ domain ops like PolarFire.
>> >
>> > plda_get_events() adds a new IRQ num to event num mapping codes for
>> > PLDA local event except DMA engine interrupt events. The DMA engine
>> > interrupt events are implemented by vendors.
>> >
>> > Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
>>
>> Perhaps not important as they will go away in the next patch, but for
>> this patch the riscv patchwork stuff noticed:
>> drivers/pci/controller/plda/pcie-plda-host.c:114:36: warning: unused variable 'plda_evt_dom_ops' [-Wunused-const-variable]
>> drivers/pci/controller/plda/pcie-plda-host.c:118:36: warning: unused variable 'plda_event_ops' [-Wunused-const-variable]
>
> Details like this *are* important because fixing them makes the
> individual patches more readable, thanks for noticing!
>
> Bjorn
OK, I will solve this.
@@ -20,6 +20,105 @@
#include "pcie-plda.h"
+irqreturn_t plda_event_handler(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+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 >> A_ATR_EVT_POST_ERR_SHIFT) & 0xff;
+
+ /* INTx events */
+ if (origin & PM_MSI_INT_INTX_MASK)
+ events |= BIT(EVENT_PM_MSI_INT_INTX);
+
+ /* MSI event and sys events */
+ val = (origin >> PM_MSI_INT_MSI_SHIFT) & 0xf;
+ events |= val << EVENT_PM_MSI_INT_MSI;
+
+ return events;
+}
+
+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 int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_and_handler(irq, &plda_event_irq_chip, handle_level_irq);
+ irq_set_chip_data(irq, domain->host_data);
+
+ return 0;
+}
+
+static const struct irq_domain_ops plda_evt_dom_ops = {
+ .map = plda_pcie_event_map,
+};
+
+static const struct plda_event_ops plda_event_ops = {
+ .get_events = plda_get_events,
+};
+
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)
@@ -102,6 +102,38 @@
#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
+ */
+
+#define PM_MSI_TO_MASK_OFFSET 19
+
+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;
@@ -120,6 +152,7 @@ struct plda_pcie_rp {
void __iomem *bridge_addr;
};
+irqreturn_t plda_event_handler(int irq, void *dev_id);
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);