diff options
| author | Valentin Rothberg <Valentin.Rothberg@lip6.fr> | 2015-02-16 11:32:48 -0500 |
|---|---|---|
| committer | Sebastian Reichel <sre@kernel.org> | 2015-03-07 14:32:22 -0500 |
| commit | 02232be7a2bf6e2dd5e4a6c3a81470a09ecc7fdd (patch) | |
| tree | ed27aec75fa383838a7451eea1a57fa3e3c7ff7f /drivers/power | |
| parent | 5a5bf49088f4c92f36786a2e4c20e17f715f0827 (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>
Diffstat (limited to 'drivers/power')
| -rw-r--r-- | drivers/power/ab8500_fg.c | 46 |
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 */ |
| 3058 | static struct ab8500_fg_interrupts ab8500_fg_irq[] = { | 3058 | static 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 | |||
| 3065 | static 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) | |||
| 3238 | free_irq: | 3256 | free_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); | ||
| 3246 | free_inst_curr_wq: | 3266 | free_inst_curr_wq: |
| 3247 | destroy_workqueue(di->fg_wq); | 3267 | destroy_workqueue(di->fg_wq); |
| 3248 | return ret; | 3268 | return ret; |
