Message ID | 1393581710-17754-4-git-send-email-k.kozlowski@samsung.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, Feb 28, 2014 at 11:01:50AM +0100, Krzysztof Kozlowski wrote: > Add __initconst to 'regulator_desc' array with supported regulators. > During probe choose how many and which regulators will be supported > according to device ID. Then copy the 'regulator_desc' array to > allocated memory so the regulator core can use it. Applied, thanks.
Hi, On Mon, 2014-03-03 at 10:09 +0800, Mark Brown wrote: > On Fri, Feb 28, 2014 at 11:01:50AM +0100, Krzysztof Kozlowski wrote: > > Add __initconst to 'regulator_desc' array with supported regulators. > > During probe choose how many and which regulators will be supported > > according to device ID. Then copy the 'regulator_desc' array to > > allocated memory so the regulator core can use it. > > Applied, thanks. Thanks! Unfortunately I wonder now whether it was a good idea to mark the regulator_desc array as __initconst. I've seen the warning from kbuild test robot: -------- >> WARNING: vmlinux.o(.text+0xf0faab): Section mismatch in reference from the function s2mps11_pmic_probe() to the variable .init.rodata:s2mps11_regulators The function s2mps11_pmic_probe() references the variable __initconst s2mps11_regulators. This is often because s2mps11_pmic_probe lacks a __initconst annotation or the annotation of s2mps11_regulators is wrong. -------- I have two ideas for fixing this: 1. The s2mps11_pmic_probe() could be marked with __init and platform_driver_probe() should be used. Unfortunately this does not work because the driver is registered and probed a little later after s2mps11_pmic_init() when I2C bus driver is probed. During that time the drv->probe() is actually NULL. 2. The s2mps11_pmic_probe() won't be marked as __init and could copy the regulator_desc (__initconst) array to local static variable. This way if it would be called twice the mentioned array __initconst won't be dereferenced. Unfortunately this won't remove the warning. Any ideas for solving this? Best regards, Krzysztof -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
> > Hi, > > On Mon, 2014-03-03 at 10:09 +0800, Mark Brown wrote: > > On Fri, Feb 28, 2014 at 11:01:50AM +0100, Krzysztof Kozlowski wrote: > > > Add __initconst to 'regulator_desc' array with supported regulators. > > > During probe choose how many and which regulators will be supported > > > according to device ID. Then copy the 'regulator_desc' array to > > > allocated memory so the regulator core can use it. > > > > Applied, thanks. > > Thanks! Unfortunately I wonder now whether it was a good idea to mark > the regulator_desc array as __initconst. I've seen the warning from > kbuild test robot: > -------- > >> WARNING: vmlinux.o(.text+0xf0faab): Section mismatch in reference > from the function s2mps11_pmic_probe() to the > variable .init.rodata:s2mps11_regulators > The function s2mps11_pmic_probe() references > the variable __initconst s2mps11_regulators. > This is often because s2mps11_pmic_probe lacks a __initconst > annotation or the annotation of s2mps11_regulators is wrong. > -------- > > I have two ideas for fixing this: > 1. The s2mps11_pmic_probe() could be marked with __init and > platform_driver_probe() should be used. Unfortunately this does not work > because the driver is registered and probed a little later after > s2mps11_pmic_init() when I2C bus driver is probed. During that time the > drv->probe() is actually NULL. > > 2. The s2mps11_pmic_probe() won't be marked as __init and could copy the > regulator_desc (__initconst) array to local static variable. This way if > it would be called twice the mentioned array __initconst won't be > dereferenced. Unfortunately this won't remove the warning. > > Any ideas for solving this? I sent a patch removing the __initconst. From my point of view these two patches can be squashed, so effectively only choosing number of supported regulators is introduced (as it was in my original patch from 11th of February). Best regards, Krzysztof -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 189038aecbf5..ca66fc56fa58 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -25,9 +25,8 @@ #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/s2mps11.h> -#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators) - struct s2mps11_info { + unsigned int rdev_num; int ramp_delay2; int ramp_delay34; int ramp_delay5; @@ -343,7 +342,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -static const struct regulator_desc regulators[] = { +static const struct regulator_desc s2mps11_regulators[] __initconst = { regulator_desc_ldo2(1), regulator_desc_ldo1(2), regulator_desc_ldo1(3), @@ -394,21 +393,62 @@ static const struct regulator_desc regulators[] = { regulator_desc_buck10, }; +/* + * Allocates memory under 'regulators' pointer and copies there array + * of regulator_desc for given device. + * + * Returns number of regulators or negative ERRNO on error. + */ +static int __init +s2mps11_pmic_init_regulators_desc(struct platform_device *pdev, + struct regulator_desc **regulators) +{ + const struct regulator_desc *regulators_init; + enum sec_device_type dev_type; + int rdev_num; + + dev_type = platform_get_device_id(pdev)->driver_data; + switch (dev_type) { + case S2MPS11X: + rdev_num = ARRAY_SIZE(s2mps11_regulators); + regulators_init = s2mps11_regulators; + break; + default: + dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type); + return -EINVAL; + }; + + *regulators = devm_kzalloc(&pdev->dev, + sizeof(**regulators) * rdev_num, GFP_KERNEL); + if (!*regulators) + return -ENOMEM; + + memcpy(*regulators, regulators_init, sizeof(**regulators) * rdev_num); + + return rdev_num; +} + static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); - struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX]; + struct sec_platform_data *pdata = iodev->pdata; + struct of_regulator_match *rdata = NULL; struct device_node *reg_np = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; - int i, ret; + int i, ret = 0; + struct regulator_desc *regulators = NULL; + int rdev_num; s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info), GFP_KERNEL); if (!s2mps11) return -ENOMEM; + rdev_num = s2mps11_pmic_init_regulators_desc(pdev, ®ulators); + if (rdev_num < 0) + return rdev_num; + if (!iodev->dev->of_node) { if (pdata) { goto common_reg; @@ -419,24 +459,30 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) } } - for (i = 0; i < S2MPS11_REGULATOR_CNT; i++) + rdata = kzalloc(sizeof(*rdata) * rdev_num, GFP_KERNEL); + if (!rdata) + return -ENOMEM; + + for (i = 0; i < rdev_num; i++) rdata[i].name = regulators[i].name; reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators"); if (!reg_np) { dev_err(&pdev->dev, "could not find regulators sub-node\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } - of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX); + of_regulator_match(&pdev->dev, reg_np, rdata, rdev_num); common_reg: platform_set_drvdata(pdev, s2mps11); + s2mps11->rdev_num = rdev_num; config.dev = &pdev->dev; config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; - for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { + for (i = 0; i < rdev_num; i++) { struct regulator_dev *regulator; if (!reg_np) { @@ -453,15 +499,18 @@ common_reg: ret = PTR_ERR(regulator); dev_err(&pdev->dev, "regulator init failed for %d\n", i); - return ret; + goto out; } } - return 0; +out: + kfree(rdata); + + return ret; } static const struct platform_device_id s2mps11_pmic_id[] = { - { "s2mps11-pmic", 0}, + { "s2mps11-pmic", S2MPS11X}, { }, }; MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);