diff options
author | Guodong Xu <guodong.xu@linaro.org> | 2013-11-29 16:00:56 +0800 |
---|---|---|
committer | Guodong Xu <guodong.xu@linaro.org> | 2013-11-29 16:00:56 +0800 |
commit | 56f092a1bc6311932c42d02ed84f2c304e1e64cb (patch) | |
tree | 18f76675f99371963363e490cbaf7bce960056f8 | |
parent | f4a5a15699a9cd15abfc423463a7ed6922d03633 (diff) |
mfd: hi6421: calling irq_create_mapping in irq handler can cause failuretracking-hilt-regulator-1129
irq_create_mapping() is called in hi6421's irq handler. When irq_create_mapping
returns at irq_find_mapping, it is safe. However, when a mapping doesn't exist
and it needs to allocate a irq_desc, the call path is like below, failing at
mutex_lock().
hi6421_irq_handler()
|-> hi6421_to_irq()
|-> irq_create_mapping()
|-> irq_alloc_desc_from()
|-> __irq_alloc_descs()
|-> mutex_lock(&sparse_irq_lock);
The solution is to call irq_create_mapping for each of HI6421_NR_IRQ at _probe
time. And use irq_find_mapping in irq handler.
Signed-off-by: Guodong Xu <guodong.xu@linaro.org>
-rw-r--r-- | drivers/mfd/hi6421-pmic-core.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c index b2d7c4e82bd2..1ef6d4e16172 100644 --- a/drivers/mfd/hi6421-pmic-core.c +++ b/drivers/mfd/hi6421-pmic-core.c @@ -107,7 +107,7 @@ EXPORT_SYMBOL(hi6421_pmic_rmw); static int hi6421_to_irq(struct hi6421_pmic *pmic, unsigned offset) { - return irq_create_mapping(pmic->domain, offset); + return irq_find_mapping(pmic->domain, offset); } static irqreturn_t hi6421_irq_handler(int irq, void *data) @@ -196,7 +196,7 @@ static int hi6421_pmic_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct hi6421_pmic *pmic = NULL; enum of_gpio_flags flags; - int ret; + int i, ret; pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) { @@ -253,6 +253,14 @@ static int hi6421_pmic_probe(struct platform_device *pdev) if (!pmic->domain) return -ENODEV; + for (i = 0; i < HI6421_NR_IRQ; i++) { + ret = irq_create_mapping(pmic->domain, i); + if (ret == NO_IRQ) { + dev_err(dev, "failed mapping hwirq %d\n", i); + return -ENOMEM; + } + } + ret = request_threaded_irq(pmic->irq, hi6421_irq_handler, NULL, IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND, "pmic", pmic); |