net: ipa: support IPA interrupt addresses for IPA v4.7
authorAlex Elder <elder@linaro.org>
Thu, 25 Mar 2021 14:44:34 +0000 (09:44 -0500)
committerDavid S. Miller <davem@davemloft.net>
Fri, 26 Mar 2021 00:22:30 +0000 (17:22 -0700)
Starting with IPA v4.7, registers related to IPA interrupts are
located at a fixed offset 0x1000 above than the addresses used for
earlier versions.  Define and use functions to provide the offset to
use for these registers based on IPA version.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ipa/ipa_interrupt.c
drivers/net/ipa/ipa_reg.h
drivers/net/ipa/ipa_uc.c

index 61dd760..c46df0b 100644 (file)
@@ -54,12 +54,14 @@ static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id)
        bool uc_irq = ipa_interrupt_uc(interrupt, irq_id);
        struct ipa *ipa = interrupt->ipa;
        u32 mask = BIT(irq_id);
+       u32 offset;
 
        /* For microcontroller interrupts, clear the interrupt right away,
         * "to avoid clearing unhandled interrupts."
         */
+       offset = ipa_reg_irq_clr_offset(ipa->version);
        if (uc_irq)
-               iowrite32(mask, ipa->reg_virt + IPA_REG_IRQ_CLR_OFFSET);
+               iowrite32(mask, ipa->reg_virt + offset);
 
        if (irq_id < IPA_IRQ_COUNT && interrupt->handler[irq_id])
                interrupt->handler[irq_id](interrupt->ipa, irq_id);
@@ -69,7 +71,7 @@ static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id)
         * so defer clearing until after the handler has been called.
         */
        if (!uc_irq)
-               iowrite32(mask, ipa->reg_virt + IPA_REG_IRQ_CLR_OFFSET);
+               iowrite32(mask, ipa->reg_virt + offset);
 }
 
 /* Process all IPA interrupt types that have been signaled */
@@ -77,13 +79,15 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt)
 {
        struct ipa *ipa = interrupt->ipa;
        u32 enabled = interrupt->enabled;
+       u32 offset;
        u32 mask;
 
        /* The status register indicates which conditions are present,
         * including conditions whose interrupt is not enabled.  Handle
         * only the enabled ones.
         */
-       mask = ioread32(ipa->reg_virt + IPA_REG_IRQ_STTS_OFFSET);
+       offset = ipa_reg_irq_stts_offset(ipa->version);
+       mask = ioread32(ipa->reg_virt + offset);
        while ((mask &= enabled)) {
                do {
                        u32 irq_id = __ffs(mask);
@@ -92,7 +96,7 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt)
 
                        ipa_interrupt_process(interrupt, irq_id);
                } while (mask);
-               mask = ioread32(ipa->reg_virt + IPA_REG_IRQ_STTS_OFFSET);
+               mask = ioread32(ipa->reg_virt + offset);
        }
 }
 
@@ -115,14 +119,17 @@ static irqreturn_t ipa_isr(int irq, void *dev_id)
 {
        struct ipa_interrupt *interrupt = dev_id;
        struct ipa *ipa = interrupt->ipa;
+       u32 offset;
        u32 mask;
 
-       mask = ioread32(ipa->reg_virt + IPA_REG_IRQ_STTS_OFFSET);
+       offset = ipa_reg_irq_stts_offset(ipa->version);
+       mask = ioread32(ipa->reg_virt + offset);
        if (mask & interrupt->enabled)
                return IRQ_WAKE_THREAD;
 
        /* Nothing in the mask was supposed to cause an interrupt */
-       iowrite32(mask, ipa->reg_virt + IPA_REG_IRQ_CLR_OFFSET);
+       offset = ipa_reg_irq_clr_offset(ipa->version);
+       iowrite32(mask, ipa->reg_virt + offset);
 
        dev_err(&ipa->pdev->dev, "%s: unexpected interrupt, mask 0x%08x\n",
                __func__, mask);
@@ -136,15 +143,22 @@ static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt,
 {
        struct ipa *ipa = interrupt->ipa;
        u32 mask = BIT(endpoint_id);
+       u32 offset;
        u32 val;
 
        /* assert(mask & ipa->available); */
-       val = ioread32(ipa->reg_virt + IPA_REG_IRQ_SUSPEND_EN_OFFSET);
+
+       /* IPA version 3.0 does not support TX_SUSPEND interrupt control */
+       if (ipa->version == IPA_VERSION_3_0)
+               return;
+
+       offset = ipa_reg_irq_suspend_en_offset(ipa->version);
+       val = ioread32(ipa->reg_virt + offset);
        if (enable)
                val |= mask;
        else
                val &= ~mask;
-       iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_SUSPEND_EN_OFFSET);
+       iowrite32(val, ipa->reg_virt + offset);
 }
 
 /* Enable TX_SUSPEND for an endpoint */
@@ -165,10 +179,18 @@ ipa_interrupt_suspend_disable(struct ipa_interrupt *interrupt, u32 endpoint_id)
 void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt)
 {
        struct ipa *ipa = interrupt->ipa;
+       u32 offset;
        u32 val;
 
-       val = ioread32(ipa->reg_virt + IPA_REG_IRQ_SUSPEND_INFO_OFFSET);
-       iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_SUSPEND_CLR_OFFSET);
+       offset = ipa_reg_irq_suspend_info_offset(ipa->version);
+       val = ioread32(ipa->reg_virt + offset);
+
+       /* SUSPEND interrupt status isn't cleared on IPA version 3.0 */
+       if (ipa->version == IPA_VERSION_3_0)
+               return;
+
+       offset = ipa_reg_irq_suspend_clr_offset(ipa->version);
+       iowrite32(val, ipa->reg_virt + offset);
 }
 
 /* Simulate arrival of an IPA TX_SUSPEND interrupt */
@@ -182,13 +204,15 @@ void ipa_interrupt_add(struct ipa_interrupt *interrupt,
                       enum ipa_irq_id ipa_irq, ipa_irq_handler_t handler)
 {
        struct ipa *ipa = interrupt->ipa;
+       u32 offset;
 
        /* assert(ipa_irq < IPA_IRQ_COUNT); */
        interrupt->handler[ipa_irq] = handler;
 
        /* Update the IPA interrupt mask to enable it */
        interrupt->enabled |= BIT(ipa_irq);
-       iowrite32(interrupt->enabled, ipa->reg_virt + IPA_REG_IRQ_EN_OFFSET);
+       offset = ipa_reg_irq_en_offset(ipa->version);
+       iowrite32(interrupt->enabled, ipa->reg_virt + offset);
 }
 
 /* Remove the handler for an IPA interrupt type */
@@ -196,11 +220,13 @@ void
 ipa_interrupt_remove(struct ipa_interrupt *interrupt, enum ipa_irq_id ipa_irq)
 {
        struct ipa *ipa = interrupt->ipa;
+       u32 offset;
 
        /* assert(ipa_irq < IPA_IRQ_COUNT); */
        /* Update the IPA interrupt mask to disable it */
        interrupt->enabled &= ~BIT(ipa_irq);
-       iowrite32(interrupt->enabled, ipa->reg_virt + IPA_REG_IRQ_EN_OFFSET);
+       offset = ipa_reg_irq_en_offset(ipa->version);
+       iowrite32(interrupt->enabled, ipa->reg_virt + offset);
 
        interrupt->handler[ipa_irq] = NULL;
 }
@@ -211,6 +237,7 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
        struct device *dev = &ipa->pdev->dev;
        struct ipa_interrupt *interrupt;
        unsigned int irq;
+       u32 offset;
        int ret;
 
        ret = platform_get_irq_byname(ipa->pdev, "ipa");
@@ -228,7 +255,8 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
        interrupt->irq = irq;
 
        /* Start with all IPA interrupts disabled */
-       iowrite32(0, ipa->reg_virt + IPA_REG_IRQ_EN_OFFSET);
+       offset = ipa_reg_irq_en_offset(ipa->version);
+       iowrite32(0, ipa->reg_virt + offset);
 
        ret = request_threaded_irq(irq, ipa_isr, ipa_isr_thread, IRQF_ONESHOT,
                                   "ipa", interrupt);
index 8a654cc..8820e08 100644 (file)
@@ -717,20 +717,46 @@ enum ipa_seq_rep_type {
 #define ROUTER_HASH_MSK_METADATA_FMASK         GENMASK(22, 22)
 #define IPA_REG_ENDP_ROUTER_HASH_MSK_ALL       GENMASK(22, 16)
 
-#define IPA_REG_IRQ_STTS_OFFSET        \
-                               IPA_REG_IRQ_STTS_EE_N_OFFSET(GSI_EE_AP)
-#define IPA_REG_IRQ_STTS_EE_N_OFFSET(ee) \
-                                       (0x00003008 + 0x1000 * (ee))
-
-#define IPA_REG_IRQ_EN_OFFSET \
-                               IPA_REG_IRQ_EN_EE_N_OFFSET(GSI_EE_AP)
-#define IPA_REG_IRQ_EN_EE_N_OFFSET(ee) \
-                                       (0x0000300c + 0x1000 * (ee))
-
-#define IPA_REG_IRQ_CLR_OFFSET \
-                               IPA_REG_IRQ_CLR_EE_N_OFFSET(GSI_EE_AP)
-#define IPA_REG_IRQ_CLR_EE_N_OFFSET(ee) \
-                                       (0x00003010 + 0x1000 * (ee))
+static inline u32 ipa_reg_irq_stts_ee_n_offset(enum ipa_version version,
+                                              u32 ee)
+{
+       if (version < IPA_VERSION_4_9)
+               return 0x00003008 + 0x1000 * ee;
+
+       return 0x00004008 + 0x1000 * ee;
+}
+
+static inline u32 ipa_reg_irq_stts_offset(enum ipa_version version)
+{
+       return ipa_reg_irq_stts_ee_n_offset(version, GSI_EE_AP);
+}
+
+static inline u32 ipa_reg_irq_en_ee_n_offset(enum ipa_version version, u32 ee)
+{
+       if (version < IPA_VERSION_4_9)
+               return 0x0000300c + 0x1000 * ee;
+
+       return 0x0000400c + 0x1000 * ee;
+}
+
+static inline u32 ipa_reg_irq_en_offset(enum ipa_version version)
+{
+       return ipa_reg_irq_en_ee_n_offset(version, GSI_EE_AP);
+}
+
+static inline u32 ipa_reg_irq_clr_ee_n_offset(enum ipa_version version, u32 ee)
+{
+       if (version < IPA_VERSION_4_9)
+               return 0x00003010 + 0x1000 * ee;
+
+       return 0x00004010 + 0x1000 * ee;
+}
+
+static inline u32 ipa_reg_irq_clr_offset(enum ipa_version version)
+{
+       return ipa_reg_irq_clr_ee_n_offset(version, GSI_EE_AP);
+}
+
 /**
  * enum ipa_irq_id - Bit positions representing type of IPA IRQ
  * @IPA_IRQ_UC_0:      Microcontroller event interrupt
@@ -806,32 +832,75 @@ enum ipa_irq_id {
        IPA_IRQ_COUNT,                          /* Last; not an id */
 };
 
-#define IPA_REG_IRQ_UC_OFFSET \
-                               IPA_REG_IRQ_UC_EE_N_OFFSET(GSI_EE_AP)
-#define IPA_REG_IRQ_UC_EE_N_OFFSET(ee) \
-                                       (0x0000301c + 0x1000 * (ee))
+static inline u32 ipa_reg_irq_uc_ee_n_offset(enum ipa_version version, u32 ee)
+{
+       if (version < IPA_VERSION_4_9)
+               return 0x0000301c + 0x1000 * ee;
+
+       return 0x0000401c + 0x1000 * ee;
+}
+
+static inline u32 ipa_reg_irq_uc_offset(enum ipa_version version)
+{
+       return ipa_reg_irq_uc_ee_n_offset(version, GSI_EE_AP);
+}
+
 #define UC_INTR_FMASK                          GENMASK(0, 0)
 
 /* ipa->available defines the valid bits in the SUSPEND_INFO register */
-#define IPA_REG_IRQ_SUSPEND_INFO_OFFSET \
-                               IPA_REG_IRQ_SUSPEND_INFO_EE_N_OFFSET(GSI_EE_AP)
-/* This register is at (0x00003098 + 0x1000 * (ee)) for IPA v3.0 */
-#define IPA_REG_IRQ_SUSPEND_INFO_EE_N_OFFSET(ee) \
-                                       (0x00003030 + 0x1000 * (ee))
-
-/* ipa->available defines the valid bits in the IRQ_SUSPEND_EN register */
-/* This register is present for IPA v3.1+ */
-#define IPA_REG_IRQ_SUSPEND_EN_OFFSET \
-                               IPA_REG_IRQ_SUSPEND_EN_EE_N_OFFSET(GSI_EE_AP)
-#define IPA_REG_IRQ_SUSPEND_EN_EE_N_OFFSET(ee) \
-                                       (0x00003034 + 0x1000 * (ee))
-
-/* ipa->available defines the valid bits in the IRQ_SUSPEND_CLR register */
-/* This register is present for IPA v3.1+ */
-#define IPA_REG_IRQ_SUSPEND_CLR_OFFSET \
-                               IPA_REG_IRQ_SUSPEND_CLR_EE_N_OFFSET(GSI_EE_AP)
-#define IPA_REG_IRQ_SUSPEND_CLR_EE_N_OFFSET(ee) \
-                                       (0x00003038 + 0x1000 * (ee))
+static inline u32
+ipa_reg_irq_suspend_info_ee_n_offset(enum ipa_version version, u32 ee)
+{
+       if (version == IPA_VERSION_3_0)
+               return 0x00003098 + 0x1000 * ee;
+
+       if (version < IPA_VERSION_4_9)
+               return 0x00003030 + 0x1000 * ee;
+
+       return 0x00004030 + 0x1000 * ee;
+}
+
+static inline u32
+ipa_reg_irq_suspend_info_offset(enum ipa_version version)
+{
+       return ipa_reg_irq_suspend_info_ee_n_offset(version, GSI_EE_AP);
+}
+
+/* ipa->available defines the valid bits in the SUSPEND_EN register */
+static inline u32
+ipa_reg_irq_suspend_en_ee_n_offset(enum ipa_version version, u32 ee)
+{
+       /* assert(version != IPA_VERSION_3_0); */
+
+       if (version < IPA_VERSION_4_9)
+               return 0x00003034 + 0x1000 * ee;
+
+       return 0x00004034 + 0x1000 * ee;
+}
+
+static inline u32
+ipa_reg_irq_suspend_en_offset(enum ipa_version version)
+{
+       return ipa_reg_irq_suspend_en_ee_n_offset(version, GSI_EE_AP);
+}
+
+/* ipa->available defines the valid bits in the SUSPEND_CLR register */
+static inline u32
+ipa_reg_irq_suspend_clr_ee_n_offset(enum ipa_version version, u32 ee)
+{
+       /* assert(version != IPA_VERSION_3_0); */
+
+       if (version < IPA_VERSION_4_9)
+               return 0x00003038 + 0x1000 * ee;
+
+       return 0x00004038 + 0x1000 * ee;
+}
+
+static inline u32
+ipa_reg_irq_suspend_clr_offset(enum ipa_version version)
+{
+       return ipa_reg_irq_suspend_clr_ee_n_offset(version, GSI_EE_AP);
+}
 
 int ipa_reg_init(struct ipa *ipa);
 void ipa_reg_exit(struct ipa *ipa);
index dee58a6..2756363 100644 (file)
@@ -192,6 +192,7 @@ void ipa_uc_teardown(struct ipa *ipa)
 static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param)
 {
        struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa);
+       u32 offset;
        u32 val;
 
        /* Fill in the command data */
@@ -203,8 +204,8 @@ static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param)
 
        /* Use an interrupt to tell the microcontroller the command is ready */
        val = u32_encode_bits(1, UC_INTR_FMASK);
-
-       iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_UC_OFFSET);
+       offset = ipa_reg_irq_uc_offset(ipa->version);
+       iowrite32(val, ipa->reg_virt + offset);
 }
 
 /* Tell the microcontroller the AP is shutting down */