aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValentin Rothberg <Valentin.Rothberg@lip6.fr>2015-02-16 11:32:48 -0500
committerSebastian Reichel <sre@kernel.org>2015-03-07 14:32:22 -0500
commit02232be7a2bf6e2dd5e4a6c3a81470a09ecc7fdd (patch)
treeed27aec75fa383838a7451eea1a57fa3e3c7ff7f
parent5a5bf49088f4c92f36786a2e4c20e17f715f0827 (diff)
ab8500_fg.c: only request threaded IRQs when necessary
All 5 IRQ handlers of the driver are requested as threaded interrupt handlers. However, only 1 handler can block. The remaining 4 handlers defer the actual handling to a workqueue. Hence, 4 of 5 IRQ handlers have a considerable overhead, since they are executed in a kernel thread to schedule another kernel thread (workqueue). This change splits up the 5 interrupt handlers into top halves (_th) and bottom halves (_bh) and resolves the aforementioned overhead by only requesting threaded interrupts (i.e., bottom halves) when necessary. Signed-off-by: Valentin Rothberg <Valentin.Rothberg@lip6.fr> Signed-off-by: Sebastian Reichel <sre@kernel.org>
-rw-r--r--drivers/power/ab8500_fg.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 40344e01df80..d30387bc4c21 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -3055,11 +3055,14 @@ static int ab8500_fg_remove(struct platform_device *pdev)
3055} 3055}
3056 3056
3057/* ab8500 fg driver interrupts and their respective isr */ 3057/* ab8500 fg driver interrupts and their respective isr */
3058static struct ab8500_fg_interrupts ab8500_fg_irq[] = { 3058static struct ab8500_fg_interrupts ab8500_fg_irq_th[] = {
3059 {"NCONV_ACCU", ab8500_fg_cc_convend_handler}, 3059 {"NCONV_ACCU", ab8500_fg_cc_convend_handler},
3060 {"BATT_OVV", ab8500_fg_batt_ovv_handler}, 3060 {"BATT_OVV", ab8500_fg_batt_ovv_handler},
3061 {"LOW_BAT_F", ab8500_fg_lowbatf_handler}, 3061 {"LOW_BAT_F", ab8500_fg_lowbatf_handler},
3062 {"CC_INT_CALIB", ab8500_fg_cc_int_calib_handler}, 3062 {"CC_INT_CALIB", ab8500_fg_cc_int_calib_handler},
3063};
3064
3065static struct ab8500_fg_interrupts ab8500_fg_irq_bh[] = {
3063 {"CCEOC", ab8500_fg_cc_data_end_handler}, 3066 {"CCEOC", ab8500_fg_cc_data_end_handler},
3064}; 3067};
3065 3068
@@ -3187,21 +3190,36 @@ static int ab8500_fg_probe(struct platform_device *pdev)
3187 init_completion(&di->ab8500_fg_started); 3190 init_completion(&di->ab8500_fg_started);
3188 init_completion(&di->ab8500_fg_complete); 3191 init_completion(&di->ab8500_fg_complete);
3189 3192
3190 /* Register interrupts */ 3193 /* Register primary interrupt handlers */
3191 for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) { 3194 for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq_th); i++) {
3192 irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name); 3195 irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name);
3193 ret = request_threaded_irq(irq, NULL, ab8500_fg_irq[i].isr, 3196 ret = request_irq(irq, ab8500_fg_irq_th[i].isr,
3194 IRQF_SHARED | IRQF_NO_SUSPEND, 3197 IRQF_SHARED | IRQF_NO_SUSPEND,
3195 ab8500_fg_irq[i].name, di); 3198 ab8500_fg_irq_th[i].name, di);
3196 3199
3197 if (ret != 0) { 3200 if (ret != 0) {
3198 dev_err(di->dev, "failed to request %s IRQ %d: %d\n" 3201 dev_err(di->dev, "failed to request %s IRQ %d: %d\n",
3199 , ab8500_fg_irq[i].name, irq, ret); 3202 ab8500_fg_irq_th[i].name, irq, ret);
3200 goto free_irq; 3203 goto free_irq;
3201 } 3204 }
3202 dev_dbg(di->dev, "Requested %s IRQ %d: %d\n", 3205 dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
3203 ab8500_fg_irq[i].name, irq, ret); 3206 ab8500_fg_irq_th[i].name, irq, ret);
3204 } 3207 }
3208
3209 /* Register threaded interrupt handler */
3210 irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name);
3211 ret = request_threaded_irq(irq, NULL, ab8500_fg_irq_bh[0].isr,
3212 IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
3213 ab8500_fg_irq_bh[0].name, di);
3214
3215 if (ret != 0) {
3216 dev_err(di->dev, "failed to request %s IRQ %d: %d\n",
3217 ab8500_fg_irq_bh[0].name, irq, ret);
3218 goto free_irq;
3219 }
3220 dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
3221 ab8500_fg_irq_bh[0].name, irq, ret);
3222
3205 di->irq = platform_get_irq_byname(pdev, "CCEOC"); 3223 di->irq = platform_get_irq_byname(pdev, "CCEOC");
3206 disable_irq(di->irq); 3224 disable_irq(di->irq);
3207 di->nbr_cceoc_irq_cnt = 0; 3225 di->nbr_cceoc_irq_cnt = 0;
@@ -3238,11 +3256,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
3238free_irq: 3256free_irq:
3239 power_supply_unregister(&di->fg_psy); 3257 power_supply_unregister(&di->fg_psy);
3240 3258
3241 /* We also have to free all successfully registered irqs */ 3259 /* We also have to free all registered irqs */
3242 for (i = i - 1; i >= 0; i--) { 3260 for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq_th); i++) {
3243 irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name); 3261 irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name);
3244 free_irq(irq, di); 3262 free_irq(irq, di);
3245 } 3263 }
3264 irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name);
3265 free_irq(irq, di);
3246free_inst_curr_wq: 3266free_inst_curr_wq:
3247 destroy_workqueue(di->fg_wq); 3267 destroy_workqueue(di->fg_wq);
3248 return ret; 3268 return ret;