Loading drivers/platform/msm/ipa/ipa_v2/ipa_interrupts.c +70 −21 Original line number Diff line number Diff line Loading @@ -13,9 +13,11 @@ #include "ipa_i.h" #define INTERRUPT_WORKQUEUE_NAME "ipa_interrupt_wq" #define IPA_IRQ_NUM_MAX 32 struct ipa_interrupt_info { ipa_irq_handler_t handler; enum ipa_irq_type interrupt; void *private_data; bool deferred_flag; }; Loading @@ -28,13 +30,35 @@ struct ipa_interrupt_work_wrap { void *interrupt_data; }; static struct ipa_interrupt_info ipa_interrupt_to_cb[IPA_IRQ_MAX]; static struct ipa_interrupt_info ipa_interrupt_to_cb[IPA_IRQ_NUM_MAX]; static struct workqueue_struct *ipa_interrupt_wq; static u32 ipa_ee; static void ipa_interrupt_defer(struct work_struct *work); static DECLARE_WORK(ipa_interrupt_defer_work, ipa_interrupt_defer); static int ipa2_irq_mapping[IPA_IRQ_MAX] = { [IPA_BAD_SNOC_ACCESS_IRQ] = 0, [IPA_EOT_COAL_IRQ] = 1, [IPA_UC_IRQ_0] = 2, [IPA_UC_IRQ_1] = 3, [IPA_UC_IRQ_2] = 4, [IPA_UC_IRQ_3] = 5, [IPA_UC_IN_Q_NOT_EMPTY_IRQ] = 6, [IPA_UC_RX_CMD_Q_NOT_FULL_IRQ] = 7, [IPA_UC_TX_CMD_Q_NOT_FULL_IRQ] = 8, [IPA_UC_TO_PROC_ACK_Q_NOT_FULL_IRQ] = 9, [IPA_PROC_TO_UC_ACK_Q_NOT_EMPTY_IRQ] = 10, [IPA_RX_ERR_IRQ] = 11, [IPA_DEAGGR_ERR_IRQ] = 12, [IPA_TX_ERR_IRQ] = 13, [IPA_STEP_MODE_IRQ] = 14, [IPA_PROC_ERR_IRQ] = 15, [IPA_TX_SUSPEND_IRQ] = 16, [IPA_TX_HOLB_DROP_IRQ] = 17, [IPA_BAM_IDLE_IRQ] = 18, }; static void deferred_interrupt_work(struct work_struct *work) { struct ipa_interrupt_work_wrap *work_data = Loading @@ -61,7 +85,7 @@ static bool is_valid_ep(u32 ep_suspend_data) return false; } static int handle_interrupt(enum ipa_irq_type interrupt) static int handle_interrupt(int irq_num) { struct ipa_interrupt_info interrupt_info; struct ipa_interrupt_work_wrap *work_data; Loading @@ -70,14 +94,14 @@ static int handle_interrupt(enum ipa_irq_type interrupt) struct ipa_tx_suspend_irq_data *suspend_interrupt_data = NULL; int res; interrupt_info = ipa_interrupt_to_cb[interrupt]; interrupt_info = ipa_interrupt_to_cb[irq_num]; if (interrupt_info.handler == NULL) { IPAERR("A callback function wasn't set for interrupt type %d\n", interrupt); IPAERR("A callback function wasn't set for interrupt num %d\n", irq_num); return -EINVAL; } switch (interrupt) { switch (interrupt_info.interrupt) { case IPA_TX_SUSPEND_IRQ: suspend_data = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_SUSPEND_INFO_EE_n_ADDR(ipa_ee)); Loading Loading @@ -107,13 +131,14 @@ static int handle_interrupt(enum ipa_irq_type interrupt) } INIT_WORK(&work_data->interrupt_work, deferred_interrupt_work); work_data->handler = interrupt_info.handler; work_data->interrupt = interrupt; work_data->interrupt = interrupt_info.interrupt; work_data->private_data = interrupt_info.private_data; work_data->interrupt_data = interrupt_data; queue_work(ipa_interrupt_wq, &work_data->interrupt_work); } else { interrupt_info.handler(interrupt, interrupt_info.private_data, interrupt_info.handler(interrupt_info.interrupt, interrupt_info.private_data, interrupt_data); kfree(interrupt_data); } Loading @@ -136,7 +161,7 @@ static void ipa_process_interrupts(void) reg = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_STTS_EE_n_ADDR(ipa_ee)); while (en & reg) { bmsk = 1; for (i = 0; i < IPA_IRQ_MAX; i++) { for (i = 0; i < IPA_IRQ_NUM_MAX; i++) { if (en & reg & bmsk) handle_interrupt(i); bmsk = bmsk << 1; Loading Loading @@ -198,19 +223,30 @@ int ipa2_add_interrupt_handler(enum ipa_irq_type interrupt, { u32 val; u32 bmsk; int irq_num; IPADBG("in ipa2_add_interrupt_handler\n"); if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { IPAERR("invalid interrupt number %d\n", interrupt); return -EINVAL; } ipa_interrupt_to_cb[interrupt].deferred_flag = deferred_flag; ipa_interrupt_to_cb[interrupt].handler = handler; ipa_interrupt_to_cb[interrupt].private_data = private_data; irq_num = ipa2_irq_mapping[interrupt]; if (irq_num < 0 || irq_num >= IPA_IRQ_NUM_MAX) { IPAERR("interrupt %d not supported\n", interrupt); WARN_ON(1); return -EFAULT; } ipa_interrupt_to_cb[irq_num].deferred_flag = deferred_flag; ipa_interrupt_to_cb[irq_num].handler = handler; ipa_interrupt_to_cb[irq_num].private_data = private_data; ipa_interrupt_to_cb[irq_num].interrupt = interrupt; val = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); IPADBG("read IPA_IRQ_EN_EE_n_ADDR register. reg = %d\n", val); bmsk = 1<<interrupt; bmsk = 1 << irq_num; val |= bmsk; ipa_write_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee), val); IPADBG("wrote IPA_IRQ_EN_EE_n_ADDR register. reg = %d\n", val); Loading @@ -227,16 +263,28 @@ int ipa2_remove_interrupt_handler(enum ipa_irq_type interrupt) { u32 val; u32 bmsk; int irq_num; if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { IPAERR("invalid interrupt number %d\n", interrupt); return -EINVAL; } ipa_interrupt_to_cb[interrupt].deferred_flag = false; ipa_interrupt_to_cb[interrupt].handler = NULL; ipa_interrupt_to_cb[interrupt].private_data = NULL; irq_num = ipa2_irq_mapping[interrupt]; if (irq_num < 0 || irq_num >= IPA_IRQ_NUM_MAX) { IPAERR("interrupt %d not supported\n", interrupt); WARN_ON(1); return -EFAULT; } ipa_interrupt_to_cb[irq_num].deferred_flag = false; ipa_interrupt_to_cb[irq_num].handler = NULL; ipa_interrupt_to_cb[irq_num].private_data = NULL; ipa_interrupt_to_cb[irq_num].interrupt = -1; val = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); bmsk = 1<<interrupt; bmsk = 1 << irq_num; val &= ~bmsk; ipa_write_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee), val); Loading @@ -261,10 +309,11 @@ int ipa_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev) int res = 0; ipa_ee = ee; for (idx = 0; idx < IPA_IRQ_MAX; idx++) { for (idx = 0; idx < IPA_IRQ_NUM_MAX; idx++) { ipa_interrupt_to_cb[idx].deferred_flag = false; ipa_interrupt_to_cb[idx].handler = NULL; ipa_interrupt_to_cb[idx].private_data = NULL; ipa_interrupt_to_cb[idx].interrupt = -1; } ipa_interrupt_wq = create_singlethread_workqueue( Loading drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c +78 −23 Original line number Diff line number Diff line Loading @@ -14,9 +14,11 @@ #define INTERRUPT_WORKQUEUE_NAME "ipa_interrupt_wq" #define DIS_SUSPEND_INTERRUPT_TIMEOUT 5 #define IPA_IRQ_NUM_MAX 32 struct ipa3_interrupt_info { ipa_irq_handler_t handler; enum ipa_irq_type interrupt; void *private_data; bool deferred_flag; }; Loading @@ -29,7 +31,7 @@ struct ipa3_interrupt_work_wrap { void *interrupt_data; }; static struct ipa3_interrupt_info ipa_interrupt_to_cb[IPA_IRQ_MAX]; static struct ipa3_interrupt_info ipa_interrupt_to_cb[IPA_IRQ_NUM_MAX]; static struct workqueue_struct *ipa_interrupt_wq; static u32 ipa_ee; Loading @@ -40,6 +42,27 @@ static DECLARE_DELAYED_WORK(dwork_en_suspend_int, static spinlock_t suspend_wa_lock; static void ipa3_process_interrupts(void); static int ipa3_irq_mapping[IPA_IRQ_MAX] = { [IPA_UC_TX_CMD_Q_NOT_FULL_IRQ] = -1, [IPA_UC_TO_PROC_ACK_Q_NOT_FULL_IRQ] = -1, [IPA_BAD_SNOC_ACCESS_IRQ] = 0, [IPA_EOT_COAL_IRQ] = 1, [IPA_UC_IRQ_0] = 2, [IPA_UC_IRQ_1] = 3, [IPA_UC_IRQ_2] = 4, [IPA_UC_IRQ_3] = 5, [IPA_UC_IN_Q_NOT_EMPTY_IRQ] = 6, [IPA_UC_RX_CMD_Q_NOT_FULL_IRQ] = 7, [IPA_PROC_TO_UC_ACK_Q_NOT_EMPTY_IRQ] = 8, [IPA_RX_ERR_IRQ] = 9, [IPA_DEAGGR_ERR_IRQ] = 10, [IPA_TX_ERR_IRQ] = 11, [IPA_STEP_MODE_IRQ] = 12, [IPA_PROC_ERR_IRQ] = 13, [IPA_TX_SUSPEND_IRQ] = 14, [IPA_TX_HOLB_DROP_IRQ] = 15, [IPA_BAM_IDLE_IRQ] = 16, }; static void ipa3_interrupt_defer(struct work_struct *work); static DECLARE_WORK(ipa3_interrupt_defer_work, ipa3_interrupt_defer); Loading Loading @@ -70,7 +93,7 @@ static bool ipa3_is_valid_ep(u32 ep_suspend_data) return false; } static int ipa3_handle_interrupt(enum ipa_irq_type interrupt) static int ipa3_handle_interrupt(int irq_num) { struct ipa3_interrupt_info interrupt_info; struct ipa3_interrupt_work_wrap *work_data; Loading @@ -79,14 +102,14 @@ static int ipa3_handle_interrupt(enum ipa_irq_type interrupt) struct ipa_tx_suspend_irq_data *suspend_interrupt_data = NULL; int res; interrupt_info = ipa_interrupt_to_cb[interrupt]; interrupt_info = ipa_interrupt_to_cb[irq_num]; if (interrupt_info.handler == NULL) { IPAERR("A callback function wasn't set for interrupt type %d\n", interrupt); IPAERR("A callback function wasn't set for interrupt num %d\n", irq_num); return -EINVAL; } switch (interrupt) { switch (interrupt_info.interrupt) { case IPA_TX_SUSPEND_IRQ: IPADBG("processing TX_SUSPEND interrupt work-around\n"); ipa3_tx_suspend_interrupt_wa(); Loading Loading @@ -119,13 +142,14 @@ static int ipa3_handle_interrupt(enum ipa_irq_type interrupt) INIT_WORK(&work_data->interrupt_work, ipa3_deferred_interrupt_work); work_data->handler = interrupt_info.handler; work_data->interrupt = interrupt; work_data->interrupt = interrupt_info.interrupt; work_data->private_data = interrupt_info.private_data; work_data->interrupt_data = interrupt_data; queue_work(ipa_interrupt_wq, &work_data->interrupt_work); } else { interrupt_info.handler(interrupt, interrupt_info.private_data, interrupt_info.handler(interrupt_info.interrupt, interrupt_info.private_data, interrupt_data); kfree(interrupt_data); } Loading @@ -141,14 +165,18 @@ static void ipa3_enable_tx_suspend_wa(struct work_struct *work) { u32 en; u32 suspend_bmask; int irq_num; IPADBG("Enter\n"); irq_num = ipa3_irq_mapping[IPA_TX_SUSPEND_IRQ]; BUG_ON(irq_num == -1); /* make sure ipa hw is clocked on*/ ipa3_inc_client_enable_clks(); en = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); suspend_bmask = 1 << IPA_TX_SUSPEND_IRQ; suspend_bmask = 1 << irq_num; /*enable TX_SUSPEND_IRQ*/ en |= suspend_bmask; IPADBG("enable TX_SUSPEND_IRQ, IPA_IRQ_EN_EE reg, write val = %u\n" Loading @@ -164,12 +192,15 @@ static void ipa3_tx_suspend_interrupt_wa(void) { u32 val; u32 suspend_bmask; int irq_num; IPADBG("Enter\n"); irq_num = ipa3_irq_mapping[IPA_TX_SUSPEND_IRQ]; BUG_ON(irq_num == -1); /*disable TX_SUSPEND_IRQ*/ val = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); suspend_bmask = 1 << IPA_TX_SUSPEND_IRQ; suspend_bmask = 1 << irq_num; val &= ~suspend_bmask; IPADBG("Disabling TX_SUSPEND_IRQ, write val: %u to IPA_IRQ_EN_EE reg\n", val); Loading Loading @@ -197,7 +228,7 @@ static void ipa3_process_interrupts(void) reg = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_STTS_EE_n_ADDR(ipa_ee)); while (en & reg) { bmsk = 1; for (i = 0; i < IPA_IRQ_MAX; i++) { for (i = 0; i < IPA_IRQ_NUM_MAX; i++) { if (en & reg & bmsk) ipa3_handle_interrupt(i); bmsk = bmsk << 1; Loading Loading @@ -268,19 +299,30 @@ int ipa3_add_interrupt_handler(enum ipa_irq_type interrupt, { u32 val; u32 bmsk; int irq_num; IPADBG("in ipa3_add_interrupt_handler\n"); if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { IPAERR("invalid interrupt number %d\n", interrupt); return -EINVAL; } ipa_interrupt_to_cb[interrupt].deferred_flag = deferred_flag; ipa_interrupt_to_cb[interrupt].handler = handler; ipa_interrupt_to_cb[interrupt].private_data = private_data; irq_num = ipa3_irq_mapping[interrupt]; if (irq_num < 0 || irq_num >= IPA_IRQ_NUM_MAX) { IPAERR("interrupt %d not supported\n", interrupt); WARN_ON(1); return -EFAULT; } ipa_interrupt_to_cb[irq_num].deferred_flag = deferred_flag; ipa_interrupt_to_cb[irq_num].handler = handler; ipa_interrupt_to_cb[irq_num].private_data = private_data; ipa_interrupt_to_cb[irq_num].interrupt = interrupt; val = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); IPADBG("read IPA_IRQ_EN_EE_n_ADDR register. reg = %d\n", val); bmsk = 1<<interrupt; bmsk = 1 << irq_num; val |= bmsk; ipa_write_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee), val); IPADBG("wrote IPA_IRQ_EN_EE_n_ADDR register. reg = %d\n", val); Loading @@ -297,16 +339,28 @@ int ipa3_remove_interrupt_handler(enum ipa_irq_type interrupt) { u32 val; u32 bmsk; int irq_num; if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { IPAERR("invalid interrupt number %d\n", interrupt); return -EINVAL; } ipa_interrupt_to_cb[interrupt].deferred_flag = false; ipa_interrupt_to_cb[interrupt].handler = NULL; ipa_interrupt_to_cb[interrupt].private_data = NULL; irq_num = ipa3_irq_mapping[interrupt]; if (irq_num < 0 || irq_num >= IPA_IRQ_NUM_MAX) { IPAERR("interrupt %d not supported\n", interrupt); WARN_ON(1); return -EFAULT; } ipa_interrupt_to_cb[irq_num].deferred_flag = false; ipa_interrupt_to_cb[irq_num].handler = NULL; ipa_interrupt_to_cb[irq_num].private_data = NULL; ipa_interrupt_to_cb[irq_num].interrupt = -1; val = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); bmsk = 1<<interrupt; bmsk = 1 << irq_num; val &= ~bmsk; ipa_write_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee), val); Loading @@ -331,10 +385,11 @@ int ipa3_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev) int res = 0; ipa_ee = ee; for (idx = 0; idx < IPA_IRQ_MAX; idx++) { for (idx = 0; idx < IPA_IRQ_NUM_MAX; idx++) { ipa_interrupt_to_cb[idx].deferred_flag = false; ipa_interrupt_to_cb[idx].handler = NULL; ipa_interrupt_to_cb[idx].private_data = NULL; ipa_interrupt_to_cb[idx].interrupt = -1; } ipa_interrupt_wq = create_singlethread_workqueue( Loading include/linux/ipa.h +12 −4 Original line number Diff line number Diff line Loading @@ -696,8 +696,14 @@ struct ipa_rx_data { dma_addr_t dma_addr; }; /** * enum ipa_irq_type - IPA Interrupt Type * Used to register handlers for IPA interrupts * * Below enum is a logical mapping and not the actual interrupt bit in HW */ enum ipa_irq_type { IPA_BAD_SNOC_ACCESS_IRQ = 0, IPA_BAD_SNOC_ACCESS_IRQ, IPA_EOT_COAL_IRQ, IPA_UC_IRQ_0, IPA_UC_IRQ_1, Loading @@ -705,15 +711,17 @@ enum ipa_irq_type { IPA_UC_IRQ_3, IPA_UC_IN_Q_NOT_EMPTY_IRQ, IPA_UC_RX_CMD_Q_NOT_FULL_IRQ, IPA_UC_TX_CMD_Q_NOT_FULL_IRQ, IPA_UC_TO_PROC_ACK_Q_NOT_FULL_IRQ, IPA_PROC_TO_UC_ACK_Q_NOT_EMPTY_IRQ, IPA_RX_ERR_IRQ, IPA_DEAGGR_ERR_IRQ, IPA_TX_ERR_IRQ, IPA_STEP_MODE_IRQ, IPA_PROC_ERR_IRQ, IPA_TX_SUSPEND_IRQ = 14, IPA_TX_HOLB_DROP_IRQ = 15, IPA_BAM_IDLE_IRQ = 16, IPA_TX_SUSPEND_IRQ, IPA_TX_HOLB_DROP_IRQ, IPA_BAM_IDLE_IRQ, IPA_IRQ_MAX }; Loading Loading
drivers/platform/msm/ipa/ipa_v2/ipa_interrupts.c +70 −21 Original line number Diff line number Diff line Loading @@ -13,9 +13,11 @@ #include "ipa_i.h" #define INTERRUPT_WORKQUEUE_NAME "ipa_interrupt_wq" #define IPA_IRQ_NUM_MAX 32 struct ipa_interrupt_info { ipa_irq_handler_t handler; enum ipa_irq_type interrupt; void *private_data; bool deferred_flag; }; Loading @@ -28,13 +30,35 @@ struct ipa_interrupt_work_wrap { void *interrupt_data; }; static struct ipa_interrupt_info ipa_interrupt_to_cb[IPA_IRQ_MAX]; static struct ipa_interrupt_info ipa_interrupt_to_cb[IPA_IRQ_NUM_MAX]; static struct workqueue_struct *ipa_interrupt_wq; static u32 ipa_ee; static void ipa_interrupt_defer(struct work_struct *work); static DECLARE_WORK(ipa_interrupt_defer_work, ipa_interrupt_defer); static int ipa2_irq_mapping[IPA_IRQ_MAX] = { [IPA_BAD_SNOC_ACCESS_IRQ] = 0, [IPA_EOT_COAL_IRQ] = 1, [IPA_UC_IRQ_0] = 2, [IPA_UC_IRQ_1] = 3, [IPA_UC_IRQ_2] = 4, [IPA_UC_IRQ_3] = 5, [IPA_UC_IN_Q_NOT_EMPTY_IRQ] = 6, [IPA_UC_RX_CMD_Q_NOT_FULL_IRQ] = 7, [IPA_UC_TX_CMD_Q_NOT_FULL_IRQ] = 8, [IPA_UC_TO_PROC_ACK_Q_NOT_FULL_IRQ] = 9, [IPA_PROC_TO_UC_ACK_Q_NOT_EMPTY_IRQ] = 10, [IPA_RX_ERR_IRQ] = 11, [IPA_DEAGGR_ERR_IRQ] = 12, [IPA_TX_ERR_IRQ] = 13, [IPA_STEP_MODE_IRQ] = 14, [IPA_PROC_ERR_IRQ] = 15, [IPA_TX_SUSPEND_IRQ] = 16, [IPA_TX_HOLB_DROP_IRQ] = 17, [IPA_BAM_IDLE_IRQ] = 18, }; static void deferred_interrupt_work(struct work_struct *work) { struct ipa_interrupt_work_wrap *work_data = Loading @@ -61,7 +85,7 @@ static bool is_valid_ep(u32 ep_suspend_data) return false; } static int handle_interrupt(enum ipa_irq_type interrupt) static int handle_interrupt(int irq_num) { struct ipa_interrupt_info interrupt_info; struct ipa_interrupt_work_wrap *work_data; Loading @@ -70,14 +94,14 @@ static int handle_interrupt(enum ipa_irq_type interrupt) struct ipa_tx_suspend_irq_data *suspend_interrupt_data = NULL; int res; interrupt_info = ipa_interrupt_to_cb[interrupt]; interrupt_info = ipa_interrupt_to_cb[irq_num]; if (interrupt_info.handler == NULL) { IPAERR("A callback function wasn't set for interrupt type %d\n", interrupt); IPAERR("A callback function wasn't set for interrupt num %d\n", irq_num); return -EINVAL; } switch (interrupt) { switch (interrupt_info.interrupt) { case IPA_TX_SUSPEND_IRQ: suspend_data = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_SUSPEND_INFO_EE_n_ADDR(ipa_ee)); Loading Loading @@ -107,13 +131,14 @@ static int handle_interrupt(enum ipa_irq_type interrupt) } INIT_WORK(&work_data->interrupt_work, deferred_interrupt_work); work_data->handler = interrupt_info.handler; work_data->interrupt = interrupt; work_data->interrupt = interrupt_info.interrupt; work_data->private_data = interrupt_info.private_data; work_data->interrupt_data = interrupt_data; queue_work(ipa_interrupt_wq, &work_data->interrupt_work); } else { interrupt_info.handler(interrupt, interrupt_info.private_data, interrupt_info.handler(interrupt_info.interrupt, interrupt_info.private_data, interrupt_data); kfree(interrupt_data); } Loading @@ -136,7 +161,7 @@ static void ipa_process_interrupts(void) reg = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_STTS_EE_n_ADDR(ipa_ee)); while (en & reg) { bmsk = 1; for (i = 0; i < IPA_IRQ_MAX; i++) { for (i = 0; i < IPA_IRQ_NUM_MAX; i++) { if (en & reg & bmsk) handle_interrupt(i); bmsk = bmsk << 1; Loading Loading @@ -198,19 +223,30 @@ int ipa2_add_interrupt_handler(enum ipa_irq_type interrupt, { u32 val; u32 bmsk; int irq_num; IPADBG("in ipa2_add_interrupt_handler\n"); if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { IPAERR("invalid interrupt number %d\n", interrupt); return -EINVAL; } ipa_interrupt_to_cb[interrupt].deferred_flag = deferred_flag; ipa_interrupt_to_cb[interrupt].handler = handler; ipa_interrupt_to_cb[interrupt].private_data = private_data; irq_num = ipa2_irq_mapping[interrupt]; if (irq_num < 0 || irq_num >= IPA_IRQ_NUM_MAX) { IPAERR("interrupt %d not supported\n", interrupt); WARN_ON(1); return -EFAULT; } ipa_interrupt_to_cb[irq_num].deferred_flag = deferred_flag; ipa_interrupt_to_cb[irq_num].handler = handler; ipa_interrupt_to_cb[irq_num].private_data = private_data; ipa_interrupt_to_cb[irq_num].interrupt = interrupt; val = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); IPADBG("read IPA_IRQ_EN_EE_n_ADDR register. reg = %d\n", val); bmsk = 1<<interrupt; bmsk = 1 << irq_num; val |= bmsk; ipa_write_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee), val); IPADBG("wrote IPA_IRQ_EN_EE_n_ADDR register. reg = %d\n", val); Loading @@ -227,16 +263,28 @@ int ipa2_remove_interrupt_handler(enum ipa_irq_type interrupt) { u32 val; u32 bmsk; int irq_num; if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { IPAERR("invalid interrupt number %d\n", interrupt); return -EINVAL; } ipa_interrupt_to_cb[interrupt].deferred_flag = false; ipa_interrupt_to_cb[interrupt].handler = NULL; ipa_interrupt_to_cb[interrupt].private_data = NULL; irq_num = ipa2_irq_mapping[interrupt]; if (irq_num < 0 || irq_num >= IPA_IRQ_NUM_MAX) { IPAERR("interrupt %d not supported\n", interrupt); WARN_ON(1); return -EFAULT; } ipa_interrupt_to_cb[irq_num].deferred_flag = false; ipa_interrupt_to_cb[irq_num].handler = NULL; ipa_interrupt_to_cb[irq_num].private_data = NULL; ipa_interrupt_to_cb[irq_num].interrupt = -1; val = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); bmsk = 1<<interrupt; bmsk = 1 << irq_num; val &= ~bmsk; ipa_write_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee), val); Loading @@ -261,10 +309,11 @@ int ipa_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev) int res = 0; ipa_ee = ee; for (idx = 0; idx < IPA_IRQ_MAX; idx++) { for (idx = 0; idx < IPA_IRQ_NUM_MAX; idx++) { ipa_interrupt_to_cb[idx].deferred_flag = false; ipa_interrupt_to_cb[idx].handler = NULL; ipa_interrupt_to_cb[idx].private_data = NULL; ipa_interrupt_to_cb[idx].interrupt = -1; } ipa_interrupt_wq = create_singlethread_workqueue( Loading
drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c +78 −23 Original line number Diff line number Diff line Loading @@ -14,9 +14,11 @@ #define INTERRUPT_WORKQUEUE_NAME "ipa_interrupt_wq" #define DIS_SUSPEND_INTERRUPT_TIMEOUT 5 #define IPA_IRQ_NUM_MAX 32 struct ipa3_interrupt_info { ipa_irq_handler_t handler; enum ipa_irq_type interrupt; void *private_data; bool deferred_flag; }; Loading @@ -29,7 +31,7 @@ struct ipa3_interrupt_work_wrap { void *interrupt_data; }; static struct ipa3_interrupt_info ipa_interrupt_to_cb[IPA_IRQ_MAX]; static struct ipa3_interrupt_info ipa_interrupt_to_cb[IPA_IRQ_NUM_MAX]; static struct workqueue_struct *ipa_interrupt_wq; static u32 ipa_ee; Loading @@ -40,6 +42,27 @@ static DECLARE_DELAYED_WORK(dwork_en_suspend_int, static spinlock_t suspend_wa_lock; static void ipa3_process_interrupts(void); static int ipa3_irq_mapping[IPA_IRQ_MAX] = { [IPA_UC_TX_CMD_Q_NOT_FULL_IRQ] = -1, [IPA_UC_TO_PROC_ACK_Q_NOT_FULL_IRQ] = -1, [IPA_BAD_SNOC_ACCESS_IRQ] = 0, [IPA_EOT_COAL_IRQ] = 1, [IPA_UC_IRQ_0] = 2, [IPA_UC_IRQ_1] = 3, [IPA_UC_IRQ_2] = 4, [IPA_UC_IRQ_3] = 5, [IPA_UC_IN_Q_NOT_EMPTY_IRQ] = 6, [IPA_UC_RX_CMD_Q_NOT_FULL_IRQ] = 7, [IPA_PROC_TO_UC_ACK_Q_NOT_EMPTY_IRQ] = 8, [IPA_RX_ERR_IRQ] = 9, [IPA_DEAGGR_ERR_IRQ] = 10, [IPA_TX_ERR_IRQ] = 11, [IPA_STEP_MODE_IRQ] = 12, [IPA_PROC_ERR_IRQ] = 13, [IPA_TX_SUSPEND_IRQ] = 14, [IPA_TX_HOLB_DROP_IRQ] = 15, [IPA_BAM_IDLE_IRQ] = 16, }; static void ipa3_interrupt_defer(struct work_struct *work); static DECLARE_WORK(ipa3_interrupt_defer_work, ipa3_interrupt_defer); Loading Loading @@ -70,7 +93,7 @@ static bool ipa3_is_valid_ep(u32 ep_suspend_data) return false; } static int ipa3_handle_interrupt(enum ipa_irq_type interrupt) static int ipa3_handle_interrupt(int irq_num) { struct ipa3_interrupt_info interrupt_info; struct ipa3_interrupt_work_wrap *work_data; Loading @@ -79,14 +102,14 @@ static int ipa3_handle_interrupt(enum ipa_irq_type interrupt) struct ipa_tx_suspend_irq_data *suspend_interrupt_data = NULL; int res; interrupt_info = ipa_interrupt_to_cb[interrupt]; interrupt_info = ipa_interrupt_to_cb[irq_num]; if (interrupt_info.handler == NULL) { IPAERR("A callback function wasn't set for interrupt type %d\n", interrupt); IPAERR("A callback function wasn't set for interrupt num %d\n", irq_num); return -EINVAL; } switch (interrupt) { switch (interrupt_info.interrupt) { case IPA_TX_SUSPEND_IRQ: IPADBG("processing TX_SUSPEND interrupt work-around\n"); ipa3_tx_suspend_interrupt_wa(); Loading Loading @@ -119,13 +142,14 @@ static int ipa3_handle_interrupt(enum ipa_irq_type interrupt) INIT_WORK(&work_data->interrupt_work, ipa3_deferred_interrupt_work); work_data->handler = interrupt_info.handler; work_data->interrupt = interrupt; work_data->interrupt = interrupt_info.interrupt; work_data->private_data = interrupt_info.private_data; work_data->interrupt_data = interrupt_data; queue_work(ipa_interrupt_wq, &work_data->interrupt_work); } else { interrupt_info.handler(interrupt, interrupt_info.private_data, interrupt_info.handler(interrupt_info.interrupt, interrupt_info.private_data, interrupt_data); kfree(interrupt_data); } Loading @@ -141,14 +165,18 @@ static void ipa3_enable_tx_suspend_wa(struct work_struct *work) { u32 en; u32 suspend_bmask; int irq_num; IPADBG("Enter\n"); irq_num = ipa3_irq_mapping[IPA_TX_SUSPEND_IRQ]; BUG_ON(irq_num == -1); /* make sure ipa hw is clocked on*/ ipa3_inc_client_enable_clks(); en = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); suspend_bmask = 1 << IPA_TX_SUSPEND_IRQ; suspend_bmask = 1 << irq_num; /*enable TX_SUSPEND_IRQ*/ en |= suspend_bmask; IPADBG("enable TX_SUSPEND_IRQ, IPA_IRQ_EN_EE reg, write val = %u\n" Loading @@ -164,12 +192,15 @@ static void ipa3_tx_suspend_interrupt_wa(void) { u32 val; u32 suspend_bmask; int irq_num; IPADBG("Enter\n"); irq_num = ipa3_irq_mapping[IPA_TX_SUSPEND_IRQ]; BUG_ON(irq_num == -1); /*disable TX_SUSPEND_IRQ*/ val = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); suspend_bmask = 1 << IPA_TX_SUSPEND_IRQ; suspend_bmask = 1 << irq_num; val &= ~suspend_bmask; IPADBG("Disabling TX_SUSPEND_IRQ, write val: %u to IPA_IRQ_EN_EE reg\n", val); Loading Loading @@ -197,7 +228,7 @@ static void ipa3_process_interrupts(void) reg = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_STTS_EE_n_ADDR(ipa_ee)); while (en & reg) { bmsk = 1; for (i = 0; i < IPA_IRQ_MAX; i++) { for (i = 0; i < IPA_IRQ_NUM_MAX; i++) { if (en & reg & bmsk) ipa3_handle_interrupt(i); bmsk = bmsk << 1; Loading Loading @@ -268,19 +299,30 @@ int ipa3_add_interrupt_handler(enum ipa_irq_type interrupt, { u32 val; u32 bmsk; int irq_num; IPADBG("in ipa3_add_interrupt_handler\n"); if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { IPAERR("invalid interrupt number %d\n", interrupt); return -EINVAL; } ipa_interrupt_to_cb[interrupt].deferred_flag = deferred_flag; ipa_interrupt_to_cb[interrupt].handler = handler; ipa_interrupt_to_cb[interrupt].private_data = private_data; irq_num = ipa3_irq_mapping[interrupt]; if (irq_num < 0 || irq_num >= IPA_IRQ_NUM_MAX) { IPAERR("interrupt %d not supported\n", interrupt); WARN_ON(1); return -EFAULT; } ipa_interrupt_to_cb[irq_num].deferred_flag = deferred_flag; ipa_interrupt_to_cb[irq_num].handler = handler; ipa_interrupt_to_cb[irq_num].private_data = private_data; ipa_interrupt_to_cb[irq_num].interrupt = interrupt; val = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); IPADBG("read IPA_IRQ_EN_EE_n_ADDR register. reg = %d\n", val); bmsk = 1<<interrupt; bmsk = 1 << irq_num; val |= bmsk; ipa_write_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee), val); IPADBG("wrote IPA_IRQ_EN_EE_n_ADDR register. reg = %d\n", val); Loading @@ -297,16 +339,28 @@ int ipa3_remove_interrupt_handler(enum ipa_irq_type interrupt) { u32 val; u32 bmsk; int irq_num; if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { if (interrupt < IPA_BAD_SNOC_ACCESS_IRQ || interrupt >= IPA_IRQ_MAX) { IPAERR("invalid interrupt number %d\n", interrupt); return -EINVAL; } ipa_interrupt_to_cb[interrupt].deferred_flag = false; ipa_interrupt_to_cb[interrupt].handler = NULL; ipa_interrupt_to_cb[interrupt].private_data = NULL; irq_num = ipa3_irq_mapping[interrupt]; if (irq_num < 0 || irq_num >= IPA_IRQ_NUM_MAX) { IPAERR("interrupt %d not supported\n", interrupt); WARN_ON(1); return -EFAULT; } ipa_interrupt_to_cb[irq_num].deferred_flag = false; ipa_interrupt_to_cb[irq_num].handler = NULL; ipa_interrupt_to_cb[irq_num].private_data = NULL; ipa_interrupt_to_cb[irq_num].interrupt = -1; val = ipa_read_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); bmsk = 1<<interrupt; bmsk = 1 << irq_num; val &= ~bmsk; ipa_write_reg(ipa3_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee), val); Loading @@ -331,10 +385,11 @@ int ipa3_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev) int res = 0; ipa_ee = ee; for (idx = 0; idx < IPA_IRQ_MAX; idx++) { for (idx = 0; idx < IPA_IRQ_NUM_MAX; idx++) { ipa_interrupt_to_cb[idx].deferred_flag = false; ipa_interrupt_to_cb[idx].handler = NULL; ipa_interrupt_to_cb[idx].private_data = NULL; ipa_interrupt_to_cb[idx].interrupt = -1; } ipa_interrupt_wq = create_singlethread_workqueue( Loading
include/linux/ipa.h +12 −4 Original line number Diff line number Diff line Loading @@ -696,8 +696,14 @@ struct ipa_rx_data { dma_addr_t dma_addr; }; /** * enum ipa_irq_type - IPA Interrupt Type * Used to register handlers for IPA interrupts * * Below enum is a logical mapping and not the actual interrupt bit in HW */ enum ipa_irq_type { IPA_BAD_SNOC_ACCESS_IRQ = 0, IPA_BAD_SNOC_ACCESS_IRQ, IPA_EOT_COAL_IRQ, IPA_UC_IRQ_0, IPA_UC_IRQ_1, Loading @@ -705,15 +711,17 @@ enum ipa_irq_type { IPA_UC_IRQ_3, IPA_UC_IN_Q_NOT_EMPTY_IRQ, IPA_UC_RX_CMD_Q_NOT_FULL_IRQ, IPA_UC_TX_CMD_Q_NOT_FULL_IRQ, IPA_UC_TO_PROC_ACK_Q_NOT_FULL_IRQ, IPA_PROC_TO_UC_ACK_Q_NOT_EMPTY_IRQ, IPA_RX_ERR_IRQ, IPA_DEAGGR_ERR_IRQ, IPA_TX_ERR_IRQ, IPA_STEP_MODE_IRQ, IPA_PROC_ERR_IRQ, IPA_TX_SUSPEND_IRQ = 14, IPA_TX_HOLB_DROP_IRQ = 15, IPA_BAM_IDLE_IRQ = 16, IPA_TX_SUSPEND_IRQ, IPA_TX_HOLB_DROP_IRQ, IPA_BAM_IDLE_IRQ, IPA_IRQ_MAX }; Loading