diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 0a9d746a0fe0a..469f3cbfd6b05 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -476,10 +476,22 @@ static struct platform_device *gpio_mockup_pdevs[GPIO_MOCKUP_MAX_GC]; static void gpio_mockup_unregister_pdevs(void) { + struct software_node *swnode; int i; - for (i = 0; i < GPIO_MOCKUP_MAX_GC; i++) + for (i = 0; i < GPIO_MOCKUP_MAX_GC; i++) { + swnode = to_software_node(gpio_mockup_pdevs[i].dev.fwnode); + + /* + * Note. The software node must be unregistered before the + * device to prevent the device_remove_properties() call in + * device_del() from causing ref count underflow. + */ + software_node_unregister(swnode); platform_device_unregister(gpio_mockup_pdevs[i]); + property_entries_free(swnode->properties); + kfree(swnode); + } } static __init char **gpio_mockup_make_line_names(const char *label, @@ -508,9 +520,11 @@ static int __init gpio_mockup_register_chip(int idx) struct property_entry properties[GPIO_MOCKUP_MAX_PROP]; struct platform_device_info pdevinfo; struct platform_device *pdev; + struct software_node *swnode; char **line_names = NULL; char chip_label[32]; int prop = 0, base; + int ret = -ENOMEM; u16 ngpio; memset(properties, 0, sizeof(properties)); @@ -536,20 +550,47 @@ static int __init gpio_mockup_register_chip(int idx) "gpio-line-names", line_names, ngpio); } + swnode = kzalloc(sizeof(*swnode), GFP_KERNEL); + if (!swnode) + goto err_free_line_names; + + swnode->properties = property_entry_dup(properties); + if (!swnode->properties) + goto err_free_swnode; + + ret = software_node_register(swnode); + if (ret) + goto err_free_properties; + pdevinfo.name = "gpio-mockup"; pdevinfo.id = idx; - pdevinfo.properties = properties; + pdevinfo.fwnode = software_node_fwnode(swnode); pdev = platform_device_register_full(&pdevinfo); kfree_strarray(line_names, ngpio); if (IS_ERR(pdev)) { pr_err("error registering device"); - return PTR_ERR(pdev); + ret = PTR_ERR(pdev); + goto err_unregister_swnode; } gpio_mockup_pdevs[idx] = pdev; return 0; + +err_unregister_swnode: + software_node_unregister(swnode); + +err_free_properties: + property_entries_free(swnode->properties); + +err_free_swnode: + kfree(swnode); + +err_free_line_names: + kfree_strarray(line_names, ngpio); + + return ret; } static int __init gpio_mockup_init(void)