diff options
-rw-r--r-- | drivers/net/ipa/ipa_interrupt.c | 107 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_interrupt.h | 48 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_power.c | 19 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_power.h | 12 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_uc.c | 21 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_uc.h | 8 |
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 |