aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ipa/ipa_interrupt.c107
-rw-r--r--drivers/net/ipa/ipa_interrupt.h48
-rw-r--r--drivers/net/ipa/ipa_power.c19
-rw-r--r--drivers/net/ipa/ipa_power.h12
-rw-r--r--drivers/net/ipa/ipa_uc.c21
-rw-r--r--drivers/net/ipa/ipa_uc.h8
6 files changed, 101 insertions, 114 deletions
diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c
index d458a35839cc..fd982cec8068 100644
--- a/drivers/net/ipa/ipa_interrupt.c
+++ b/drivers/net/ipa/ipa_interrupt.c
@@ -26,6 +26,8 @@
#include "ipa.h"
#include "ipa_reg.h"
#include "ipa_endpoint.h"
+#include "ipa_power.h"
+#include "ipa_uc.h"
#include "ipa_interrupt.h"
/**
@@ -33,47 +35,47 @@
* @ipa: IPA pointer
* @irq: Linux IRQ number used for IPA interrupts
* @enabled: Mask indicating which interrupts are enabled
- * @handler: Array of handlers indexed by IPA interrupt ID
*/
struct ipa_interrupt {
struct ipa *ipa;
u32 irq;
u32 enabled;
- ipa_irq_handler_t handler[IPA_IRQ_COUNT];
};
-/* Returns true if the interrupt type is associated with the microcontroller */
-static bool ipa_interrupt_uc(struct ipa_interrupt *interrupt, u32 irq_id)
-{
- return irq_id == IPA_IRQ_UC_0 || irq_id == IPA_IRQ_UC_1;
-}
-
/* Process a particular interrupt type that has been received */
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;
const struct ipa_reg *reg;
u32 mask = BIT(irq_id);
u32 offset;
- /* For microcontroller interrupts, clear the interrupt right away,
- * "to avoid clearing unhandled interrupts."
- */
reg = ipa_reg(ipa, IPA_IRQ_CLR);
offset = ipa_reg_offset(reg);
- if (uc_irq)
- iowrite32(mask, ipa->reg_virt + offset);
-
- if (irq_id < IPA_IRQ_COUNT && interrupt->handler[irq_id])
- interrupt->handler[irq_id](interrupt->ipa, irq_id);
- /* Clearing the SUSPEND_TX interrupt also clears the register
- * that tells us which suspended endpoint(s) caused the interrupt,
- * so defer clearing until after the handler has been called.
- */
- if (!uc_irq)
+ switch (irq_id) {
+ case IPA_IRQ_UC_0:
+ case IPA_IRQ_UC_1:
+ /* For microcontroller interrupts, clear the interrupt right
+ * away, "to avoid clearing unhandled interrupts."
+ */
+ iowrite32(mask, ipa->reg_virt + offset);
+ ipa_uc_interrupt_handler(ipa, irq_id);
+ break;
+
+ case IPA_IRQ_TX_SUSPEND:
+ /* Clearing the SUSPEND_TX interrupt also clears the
+ * register that tells us which suspended endpoint(s)
+ * caused the interrupt, so defer clearing until after
+ * the handler has been called.
+ */
+ ipa_power_suspend_handler(ipa, irq_id);
+ fallthrough;
+
+ default: /* Silently ignore (and clear) any other condition */
iowrite32(mask, ipa->reg_virt + offset);
+ break;
+ }
}
/* IPA IRQ handler is threaded */
@@ -127,6 +129,29 @@ out_power_put:
return IRQ_HANDLED;
}
+static void ipa_interrupt_enabled_update(struct ipa *ipa)
+{
+ const struct ipa_reg *reg = ipa_reg(ipa, IPA_IRQ_EN);
+
+ iowrite32(ipa->interrupt->enabled, ipa->reg_virt + ipa_reg_offset(reg));
+}
+
+/* Enable an IPA interrupt type */
+void ipa_interrupt_enable(struct ipa *ipa, enum ipa_irq_id ipa_irq)
+{
+ /* Update the IPA interrupt mask to enable it */
+ ipa->interrupt->enabled |= BIT(ipa_irq);
+ ipa_interrupt_enabled_update(ipa);
+}
+
+/* Disable an IPA interrupt type */
+void ipa_interrupt_disable(struct ipa *ipa, enum ipa_irq_id ipa_irq)
+{
+ /* Update the IPA interrupt mask to disable it */
+ ipa->interrupt->enabled &= ~BIT(ipa_irq);
+ ipa_interrupt_enabled_update(ipa);
+}
+
/* Common function used to enable/disable TX_SUSPEND for an endpoint */
static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt,
u32 endpoint_id, bool enable)
@@ -200,44 +225,6 @@ void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt)
ipa_interrupt_process(interrupt, IPA_IRQ_TX_SUSPEND);
}
-/* Add a handler for an IPA interrupt */
-void ipa_interrupt_add(struct ipa_interrupt *interrupt,
- enum ipa_irq_id ipa_irq, ipa_irq_handler_t handler)
-{
- struct ipa *ipa = interrupt->ipa;
- const struct ipa_reg *reg;
-
- if (WARN_ON(ipa_irq >= IPA_IRQ_COUNT))
- return;
-
- interrupt->handler[ipa_irq] = handler;
-
- /* Update the IPA interrupt mask to enable it */
- interrupt->enabled |= BIT(ipa_irq);
-
- reg = ipa_reg(ipa, IPA_IRQ_EN);
- iowrite32(interrupt->enabled, ipa->reg_virt + ipa_reg_offset(reg));
-}
-
-/* Remove the handler for an IPA interrupt type */
-void
-ipa_interrupt_remove(struct ipa_interrupt *interrupt, enum ipa_irq_id ipa_irq)
-{
- struct ipa *ipa = interrupt->ipa;
- const struct ipa_reg *reg;
-
- if (WARN_ON(ipa_irq >= IPA_IRQ_COUNT))
- return;
-
- /* Update the IPA interrupt mask to disable it */
- interrupt->enabled &= ~BIT(ipa_irq);
-
- reg = ipa_reg(ipa, IPA_IRQ_EN);
- iowrite32(interrupt->enabled, ipa->reg_virt + ipa_reg_offset(reg));
-
- interrupt->handler[ipa_irq] = NULL;
-}
-
/* Configure the IPA interrupt framework */
struct ipa_interrupt *ipa_interrupt_config(struct ipa *ipa)
{
diff --git a/drivers/net/ipa/ipa_interrupt.h b/drivers/net/ipa/ipa_interrupt.h
index f31fd9965fdc..764a65e6b503 100644
--- a/drivers/net/ipa/ipa_interrupt.h
+++ b/drivers/net/ipa/ipa_interrupt.h
@@ -11,39 +11,7 @@
struct ipa;
struct ipa_interrupt;
-
-/**
- * typedef ipa_irq_handler_t - IPA interrupt handler function type
- * @ipa: IPA pointer
- * @irq_id: interrupt type
- *
- * Callback function registered by ipa_interrupt_add() to handle a specific
- * IPA interrupt type
- */
-typedef void (*ipa_irq_handler_t)(struct ipa *ipa, enum ipa_irq_id irq_id);
-
-/**
- * ipa_interrupt_add() - Register a handler for an IPA interrupt type
- * @interrupt: IPA interrupt structure
- * @irq_id: IPA interrupt type
- * @handler: Handler function for the interrupt
- *
- * Add a handler for an IPA interrupt and enable it. IPA interrupt
- * handlers are run in threaded interrupt context, so are allowed to
- * block.
- */
-void ipa_interrupt_add(struct ipa_interrupt *interrupt, enum ipa_irq_id irq_id,
- ipa_irq_handler_t handler);
-
-/**
- * ipa_interrupt_remove() - Remove the handler for an IPA interrupt type
- * @interrupt: IPA interrupt structure
- * @irq_id: IPA interrupt type
- *
- * Remove an IPA interrupt handler and disable it.
- */
-void ipa_interrupt_remove(struct ipa_interrupt *interrupt,
- enum ipa_irq_id irq_id);
+enum ipa_irq_id;
/**
* ipa_interrupt_suspend_enable - Enable TX_SUSPEND for an endpoint
@@ -86,6 +54,20 @@ void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt);
void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt);
/**
+ * ipa_interrupt_enable() - Enable an IPA interrupt type
+ * @ipa: IPA pointer
+ * @ipa_irq: IPA interrupt ID
+ */
+void ipa_interrupt_enable(struct ipa *ipa, enum ipa_irq_id ipa_irq);
+
+/**
+ * ipa_interrupt_disable() - Disable an IPA interrupt type
+ * @ipa: IPA pointer
+ * @ipa_irq: IPA interrupt ID
+ */
+void ipa_interrupt_disable(struct ipa *ipa, enum ipa_irq_id ipa_irq);
+
+/**
* ipa_interrupt_config() - Configure the IPA interrupt framework
* @ipa: IPA pointer
*
diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c
index 8420f93128a2..a282512ebd2d 100644
--- a/drivers/net/ipa/ipa_power.c
+++ b/drivers/net/ipa/ipa_power.c
@@ -202,17 +202,7 @@ u32 ipa_core_clock_rate(struct ipa *ipa)
return ipa->power ? (u32)clk_get_rate(ipa->power->core) : 0;
}
-/**
- * ipa_suspend_handler() - Handle the suspend IPA interrupt
- * @ipa: IPA pointer
- * @irq_id: IPA interrupt type (unused)
- *
- * If an RX endpoint is suspended, and the IPA has a packet destined for
- * that endpoint, the IPA generates a SUSPEND interrupt to inform the AP
- * that it should resume the endpoint. If we get one of these interrupts
- * we just wake up the system.
- */
-static void ipa_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
+void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
{
/* To handle an IPA interrupt we will have resumed the hardware
* just to handle the interrupt, so we're done. If we are in a
@@ -335,12 +325,11 @@ int ipa_power_setup(struct ipa *ipa)
{
int ret;
- ipa_interrupt_add(ipa->interrupt, IPA_IRQ_TX_SUSPEND,
- ipa_suspend_handler);
+ ipa_interrupt_enable(ipa, IPA_IRQ_TX_SUSPEND);
ret = device_init_wakeup(&ipa->pdev->dev, true);
if (ret)
- ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND);
+ ipa_interrupt_disable(ipa, IPA_IRQ_TX_SUSPEND);
return ret;
}
@@ -348,7 +337,7 @@ int ipa_power_setup(struct ipa *ipa)
void ipa_power_teardown(struct ipa *ipa)
{
(void)device_init_wakeup(&ipa->pdev->dev, false);
- ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND);
+ ipa_interrupt_disable(ipa, IPA_IRQ_TX_SUSPEND);
}
/* Initialize IPA power management */
diff --git a/drivers/net/ipa/ipa_power.h b/drivers/net/ipa/ipa_power.h
index 896f052e51a1..3a4c59ea1222 100644
--- a/drivers/net/ipa/ipa_power.h
+++ b/drivers/net/ipa/ipa_power.h
@@ -10,6 +10,7 @@ struct device;
struct ipa;
struct ipa_power_data;
+enum ipa_irq_id;
/* IPA device power management function block */
extern const struct dev_pm_ops ipa_pm_ops;
@@ -48,6 +49,17 @@ void ipa_power_modem_queue_active(struct ipa *ipa);
void ipa_power_retention(struct ipa *ipa, bool enable);
/**
+ * ipa_power_suspend_handler() - Handler for SUSPEND IPA interrupts
+ * @ipa: IPA pointer
+ * @irq_id: IPA interrupt ID (unused)
+ *
+ * If an RX endpoint is suspended, and the IPA has a packet destined for
+ * that endpoint, the IPA generates a SUSPEND interrupt to inform the AP
+ * that it should resume the endpoint.
+ */
+void ipa_power_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id);
+
+/**
* ipa_power_setup() - Set up IPA power management
* @ipa: IPA pointer
*
diff --git a/drivers/net/ipa/ipa_uc.c b/drivers/net/ipa/ipa_uc.c
index f0ee47281015..cb8a76a75f21 100644
--- a/drivers/net/ipa/ipa_uc.c
+++ b/drivers/net/ipa/ipa_uc.c
@@ -124,7 +124,7 @@ static struct ipa_uc_mem_area *ipa_uc_shared(struct ipa *ipa)
}
/* Microcontroller event IPA interrupt handler */
-static void ipa_uc_event_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
+static void ipa_uc_event_handler(struct ipa *ipa)
{
struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa);
struct device *dev = &ipa->pdev->dev;
@@ -138,7 +138,7 @@ static void ipa_uc_event_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
}
/* Microcontroller response IPA interrupt handler */
-static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
+static void ipa_uc_response_hdlr(struct ipa *ipa)
{
struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa);
struct device *dev = &ipa->pdev->dev;
@@ -170,13 +170,22 @@ static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
}
}
+void ipa_uc_interrupt_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
+{
+ /* Silently ignore anything unrecognized */
+ if (irq_id == IPA_IRQ_UC_0)
+ ipa_uc_event_handler(ipa);
+ else if (irq_id == IPA_IRQ_UC_1)
+ ipa_uc_response_hdlr(ipa);
+}
+
/* Configure the IPA microcontroller subsystem */
void ipa_uc_config(struct ipa *ipa)
{
ipa->uc_powered = false;
ipa->uc_loaded = false;
- ipa_interrupt_add(ipa->interrupt, IPA_IRQ_UC_0, ipa_uc_event_handler);
- ipa_interrupt_add(ipa->interrupt, IPA_IRQ_UC_1, ipa_uc_response_hdlr);
+ ipa_interrupt_enable(ipa, IPA_IRQ_UC_0);
+ ipa_interrupt_enable(ipa, IPA_IRQ_UC_1);
}
/* Inverse of ipa_uc_config() */
@@ -184,8 +193,8 @@ void ipa_uc_deconfig(struct ipa *ipa)
{
struct device *dev = &ipa->pdev->dev;
- ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1);
- ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0);
+ ipa_interrupt_disable(ipa, IPA_IRQ_UC_1);
+ ipa_interrupt_disable(ipa, IPA_IRQ_UC_0);
if (ipa->uc_loaded)
ipa_power_retention(ipa, false);
diff --git a/drivers/net/ipa/ipa_uc.h b/drivers/net/ipa/ipa_uc.h
index 8514096e6f36..85aa0df818c2 100644
--- a/drivers/net/ipa/ipa_uc.h
+++ b/drivers/net/ipa/ipa_uc.h
@@ -7,6 +7,14 @@
#define _IPA_UC_H_
struct ipa;
+enum ipa_irq_id;
+
+/**
+ * ipa_uc_interrupt_handler() - Handler for microcontroller IPA interrupts
+ * @ipa: IPA pointer
+ * @irq_id: IPA interrupt ID
+ */
+void ipa_uc_interrupt_handler(struct ipa *ipa, enum ipa_irq_id irq_id);
/**
* ipa_uc_config() - Configure the IPA microcontroller subsystem