From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754214AbbCIKTV (ORCPT ); Mon, 9 Mar 2015 06:19:21 -0400 Received: from metis.ext.pengutronix.de ([92.198.50.35]:57697 "EHLO metis.ext.pengutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754163AbbCIKTQ (ORCPT ); Mon, 9 Mar 2015 06:19:16 -0400 From: Markus Pargmann To: Ingo Flaschberger Cc: linux-kernel@vger.kernel.org, Markus Pargmann , Subject: [PATCH] w1: gpio: Fix problematic platform_data usage Date: Mon, 9 Mar 2015 11:18:58 +0100 Message-Id: <1425896338-31928-1-git-send-email-mpa@pengutronix.de> X-Mailer: git-send-email 2.1.4 In-Reply-To: <54F8445B.10805@gmail.com> References: <54F8445B.10805@gmail.com> X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: mpa@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-kernel@vger.kernel.org Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org pdev->dev.platform_data should not be overwritten by a driver. This patch fixes this issue by not using platform_get_pdata to get pdata. The DT routine can then simply return a pdata struct with those information. Without this patch the platform_data may be freed twice, by devres and the driver framework. Reported-by: Ingo Flaschberger Cc: Signed-off-by: Markus Pargmann --- Hi, Could you please try this patch? This essentially does not store anything to platform_data anymore so it should hopefully fix your issue. Best Regards, Markus drivers/w1/masters/w1-gpio.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index b99a932ad901..63e7b1d2785f 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -75,15 +75,18 @@ static struct of_device_id w1_gpio_dt_ids[] = { MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); #endif -static int w1_gpio_probe_dt(struct platform_device *pdev) +static struct w1_gpio_platform_data *w1_gpio_probe_dt(struct platform_device *pdev) { struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *np = pdev->dev.of_node; int gpio; + if (pdata) + return pdata; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) - return -ENOMEM; + return ERR_PTR(-ENOMEM); if (of_get_property(np, "linux,open-drain", NULL)) pdata->is_open_drain = 1; @@ -95,19 +98,17 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) "Failed to parse gpio property for data pin (%d)\n", gpio); - return gpio; + return ERR_PTR(gpio); } pdata->pin = gpio; gpio = of_get_gpio(np, 1); if (gpio == -EPROBE_DEFER) - return gpio; + return ERR_PTR(gpio); /* ignore other errors as the pullup gpio is optional */ pdata->ext_pullup_enable_pin = gpio; - pdev->dev.platform_data = pdata; - - return 0; + return pdata; } static int w1_gpio_probe(struct platform_device *pdev) @@ -116,17 +117,16 @@ static int w1_gpio_probe(struct platform_device *pdev) struct w1_gpio_platform_data *pdata; int err; - if (of_have_populated_dt()) { - err = w1_gpio_probe_dt(pdev); - if (err < 0) - return err; - } - - pdata = dev_get_platdata(&pdev->dev); + if (of_have_populated_dt()) + pdata = w1_gpio_probe_dt(pdev); + else + pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "No configuration data\n"); - return -ENXIO; + if (IS_ERR_OR_NULL(pdata)) { + dev_err(&pdev->dev, "No configuration data or configuration failed\n"); + if (!pdata) + return -ENXIO; + return PTR_ERR(pdata); } master = devm_kzalloc(&pdev->dev, sizeof(struct w1_bus_master), @@ -185,7 +185,7 @@ static int w1_gpio_probe(struct platform_device *pdev) static int w1_gpio_remove(struct platform_device *pdev) { struct w1_bus_master *master = platform_get_drvdata(pdev); - struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct w1_gpio_platform_data *pdata = master->data; if (pdata->enable_external_pullup) pdata->enable_external_pullup(0); @@ -202,7 +202,8 @@ static int w1_gpio_remove(struct platform_device *pdev) static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state) { - struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct w1_bus_master *master = platform_get_drvdata(pdev); + struct w1_gpio_platform_data *pdata = master->data; if (pdata->enable_external_pullup) pdata->enable_external_pullup(0); @@ -212,7 +213,8 @@ static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state) static int w1_gpio_resume(struct platform_device *pdev) { - struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct w1_bus_master *master = platform_get_drvdata(pdev); + struct w1_gpio_platform_data *pdata = master->data; if (pdata->enable_external_pullup) pdata->enable_external_pullup(1); -- 2.1.4