From: Russell King (Oracle) <rmk+kernel@xxxxxxxxxxxxxxx> [ Upstream commit ab3428cfd9aa2f3463ee4b2909b5bb2193bd0c4a ] The i.MX6 CPU frequency driver sometimes fails to register at boot time due to nvmem_cell_read_u32() sporadically returning -ENOENT. This happens because there is a window where __nvmem_device_get() in of_nvmem_cell_get() is able to return the nvmem device, but as cells have been setup, nvmem_find_cell_entry_by_node() returns NULL. The occurs because the nvmem core registration code violates one of the fundamental principles of kernel programming: do not publish data structures before their setup is complete. Fix this by making nvmem core code conform with this principle. Fixes: eace75cfdcf7 ("nvmem: Add a simple NVMEM framework for nvmem providers") Cc: stable@xxxxxxxxxxxxxxx Signed-off-by: Russell King (Oracle) <rmk+kernel@xxxxxxxxxxxxxxx> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxx> Link: https://lore.kernel.org/r/20230127104015.23839-7-srinivas.kandagatla@xxxxxxxxxx Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> --- drivers/nvmem/core.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index f06b65f0d410b..6a74e38746057 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -827,22 +827,16 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->dev.groups = nvmem_dev_groups; #endif - dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); - - rval = device_add(&nvmem->dev); - if (rval) - goto err_put_device; - if (nvmem->nkeepout) { rval = nvmem_validate_keepouts(nvmem); if (rval) - goto err_device_del; + goto err_put_device; } if (config->compat) { rval = nvmem_sysfs_setup_compat(nvmem, config); if (rval) - goto err_device_del; + goto err_put_device; } if (config->cells) { @@ -859,6 +853,12 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) if (rval) goto err_remove_cells; + dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); + + rval = device_add(&nvmem->dev); + if (rval) + goto err_remove_cells; + blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); return nvmem; @@ -867,8 +867,6 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem_device_remove_all_cells(nvmem); if (config->compat) nvmem_sysfs_remove_compat(nvmem, config); -err_device_del: - device_del(&nvmem->dev); err_put_device: put_device(&nvmem->dev); -- 2.39.0