From bf98b035b17e3b77eb3a5d9f1f49a80f2490f611 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Thu, 28 Nov 2013 20:34:22 +0800 Subject: input: hi6421: allocate input_dev before request_irq input_allocate_device() need be called before request_irq(). input_dev is used in irq handler. Once request_irq() is called, there is a possibility that the interrupt may happen and then the irq handler will be called. Signed-off-by: Guodong Xu --- drivers/input/misc/hi6421_pwrkey.c | 41 ++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/input/misc/hi6421_pwrkey.c b/drivers/input/misc/hi6421_pwrkey.c index 7b2098d1fe2b..31d0145fc688 100644 --- a/drivers/input/misc/hi6421_pwrkey.c +++ b/drivers/input/misc/hi6421_pwrkey.c @@ -56,22 +56,36 @@ static int hi6421_onkey_probe(struct platform_device *pdev) info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; + + info->idev = input_allocate_device(); + if (!info->idev) { + dev_err(&pdev->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + info->idev->name = "hi6421_on"; + info->idev->phys = "hi6421_on/input0"; + info->idev->dev.parent = &pdev->dev; + info->idev->evbit[0] = BIT_MASK(EV_KEY); + __set_bit(KEY_POWER, info->idev->keybit); + info->irq[0] = platform_get_irq_byname(pdev, "down"); - if (info->irq[0] < 0) - return -ENOENT; + if (info->irq[0] < 0) { + ret = -ENOENT; + goto err_irq0; + } ret = request_irq(info->irq[0], hi6421_onkey_handler, IRQF_DISABLED, "down", info); if (ret < 0) - return ret; + goto err_irq0; info->irq[1] = platform_get_irq_byname(pdev, "up"); if (info->irq[1] < 0) { ret = -ENOENT; - goto err; + goto err_irq1; } ret = request_irq(info->irq[1], hi6421_onkey_handler, IRQF_DISABLED, "up", info); if (ret < 0) - goto err; + goto err_irq1; info->irq[2] = platform_get_irq_byname(pdev, "hold 1s"); if (info->irq[2] < 0) { ret = -ENOENT; @@ -91,17 +105,6 @@ static int hi6421_onkey_probe(struct platform_device *pdev) if (ret < 0) goto err_irq3; - info->idev = input_allocate_device(); - if (!info->idev) { - dev_err(&pdev->dev, "Failed to allocate input device\n"); - goto err_alloc; - } - info->idev->name = "hi6421_on"; - info->idev->phys = "hi6421_on/input0"; - info->idev->dev.parent = &pdev->dev; - info->idev->evbit[0] = BIT_MASK(EV_KEY); - __set_bit(KEY_POWER, info->idev->keybit); - ret = input_register_device(info->idev); if (ret) { dev_err(&pdev->dev, "Can't register input device: %d\n", ret); @@ -111,15 +114,15 @@ static int hi6421_onkey_probe(struct platform_device *pdev) platform_set_drvdata(pdev, info); return ret; err_reg: - input_free_device(info->idev); -err_alloc: free_irq(info->irq[3], info); err_irq3: free_irq(info->irq[2], info); err_irq2: free_irq(info->irq[1], info); -err: +err_irq1: free_irq(info->irq[0], info); +err_irq0: + input_free_device(info->idev); return ret; } -- cgit v1.2.3 From f4a5a15699a9cd15abfc423463a7ed6922d03633 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Fri, 29 Nov 2013 13:40:46 +0800 Subject: rtc: rtc-hi6421: rtc_device_register should be called before devm_request_irq info->rtc and info->pmic are used in hi6421_rtc_handler. They need to be initialized before devm_request_irq is called. Use devm_ version of 'rtc_device_register' Signed-off-by: Guodong Xu --- drivers/rtc/rtc-hi6421.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-hi6421.c b/drivers/rtc/rtc-hi6421.c index 14e27b96e0ef..50ec3911861b 100644 --- a/drivers/rtc/rtc-hi6421.c +++ b/drivers/rtc/rtc-hi6421.c @@ -214,29 +214,27 @@ static int hi6421_rtc_probe(struct platform_device *pdev) if (info->irq < 0) return -ENOENT; - ret = devm_request_irq(&pdev->dev, info->irq, hi6421_rtc_handler, - IRQF_DISABLED, "alarm", info); - if (ret < 0) - return ret; info->pmic = dev_get_drvdata(pdev->dev.parent); platform_set_drvdata(pdev, info); /* enable RTC device */ hi6421_pmic_write(info->pmic, REG_RTCCTRL, 1); - info->rtc = rtc_device_register(pdev->name, &pdev->dev, - &hi6421_rtc_ops, - THIS_MODULE); + info->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &hi6421_rtc_ops, THIS_MODULE); if (IS_ERR(info->rtc)) return PTR_ERR(info->rtc); + + ret = devm_request_irq(&pdev->dev, info->irq, hi6421_rtc_handler, + IRQF_DISABLED, "alarm", info); + if (ret < 0) + return ret; + return 0; } static int hi6421_rtc_remove(struct platform_device *pdev) { - struct hi6421_rtc_info *info = platform_get_drvdata(pdev); - - rtc_device_unregister(info->rtc); return 0; } -- cgit v1.2.3 From 56f092a1bc6311932c42d02ed84f2c304e1e64cb Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Fri, 29 Nov 2013 16:00:56 +0800 Subject: mfd: hi6421: calling irq_create_mapping in irq handler can cause failure 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 --- drivers/mfd/hi6421-pmic-core.c | 12 ++++++++++-- 1 file 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); -- cgit v1.2.3