123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763 |
- From fc29fd821d9ac2ae3d32a722fac39ce874efb883 Mon Sep 17 00:00:00 2001
- From: Miquel Raynal <[email protected]>
- Date: Fri, 15 Dec 2023 11:15:32 +0000
- Subject: [PATCH] nvmem: core: Rework layouts to become regular devices
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- Current layout support was initially written without modules support in
- mind. When the requirement for module support rose, the existing base
- was improved to adopt modularization support, but kind of a design flaw
- was introduced. With the existing implementation, when a storage device
- registers into NVMEM, the core tries to hook a layout (if any) and
- populates its cells immediately. This means, if the hardware description
- expects a layout to be hooked up, but no driver was provided for that,
- the storage medium will fail to probe and try later from
- scratch. Even if we consider that the hardware description shall be
- correct, we could still probe the storage device (especially if it
- contains the rootfs).
- One way to overcome this situation is to consider the layouts as
- devices, and leverage the native notifier mechanism. When a new NVMEM
- device is registered, we can populate its nvmem-layout child, if any,
- and wait for the matching to be done in order to get the cells (the
- waiting can be easily done with the NVMEM notifiers). If the layout
- driver is compiled as a module, it should automatically be loaded. This
- way, there is no strong order to enforce, any NVMEM device creation
- or NVMEM layout driver insertion will be observed as a new event which
- may lead to the creation of additional cells, without disturbing the
- probes with costly (and sometimes endless) deferrals.
- In order to achieve that goal we create a new bus for the nvmem-layouts
- with minimal logic to match nvmem-layout devices with nvmem-layout
- drivers. All this infrastructure code is created in the layouts.c file.
- Signed-off-by: Miquel Raynal <[email protected]>
- Tested-by: Rafał Miłecki <[email protected]>
- Signed-off-by: Srinivas Kandagatla <[email protected]>
- Link: https://lore.kernel.org/r/[email protected]
- Signed-off-by: Greg Kroah-Hartman <[email protected]>
- ---
- drivers/nvmem/Kconfig | 1 +
- drivers/nvmem/Makefile | 2 +
- drivers/nvmem/core.c | 170 ++++++++++----------------
- drivers/nvmem/internals.h | 21 ++++
- drivers/nvmem/layouts.c | 201 +++++++++++++++++++++++++++++++
- drivers/nvmem/layouts/Kconfig | 8 ++
- drivers/nvmem/layouts/onie-tlv.c | 24 +++-
- drivers/nvmem/layouts/sl28vpd.c | 24 +++-
- include/linux/nvmem-provider.h | 38 +++---
- 9 files changed, 354 insertions(+), 135 deletions(-)
- create mode 100644 drivers/nvmem/layouts.c
- --- a/drivers/nvmem/Kconfig
- +++ b/drivers/nvmem/Kconfig
- @@ -1,6 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0-only
- menuconfig NVMEM
- bool "NVMEM Support"
- + imply NVMEM_LAYOUTS
- help
- Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES...
-
- --- a/drivers/nvmem/Makefile
- +++ b/drivers/nvmem/Makefile
- @@ -5,6 +5,8 @@
-
- obj-$(CONFIG_NVMEM) += nvmem_core.o
- nvmem_core-y := core.o
- +obj-$(CONFIG_NVMEM_LAYOUTS) += nvmem_layouts.o
- +nvmem_layouts-y := layouts.o
- obj-y += layouts/
-
- # Devices
- --- a/drivers/nvmem/core.c
- +++ b/drivers/nvmem/core.c
- @@ -55,9 +55,6 @@ static LIST_HEAD(nvmem_lookup_list);
-
- static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
-
- -static DEFINE_SPINLOCK(nvmem_layout_lock);
- -static LIST_HEAD(nvmem_layouts);
- -
- static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
- void *val, size_t bytes)
- {
- @@ -740,97 +737,22 @@ static int nvmem_add_cells_from_fixed_la
- return err;
- }
-
- -int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner)
- +int nvmem_layout_register(struct nvmem_layout *layout)
- {
- - layout->owner = owner;
- -
- - spin_lock(&nvmem_layout_lock);
- - list_add(&layout->node, &nvmem_layouts);
- - spin_unlock(&nvmem_layout_lock);
- -
- - blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_ADD, layout);
- + if (!layout->add_cells)
- + return -EINVAL;
-
- - return 0;
- + /* Populate the cells */
- + return layout->add_cells(&layout->nvmem->dev, layout->nvmem);
- }
- -EXPORT_SYMBOL_GPL(__nvmem_layout_register);
- +EXPORT_SYMBOL_GPL(nvmem_layout_register);
-
- void nvmem_layout_unregister(struct nvmem_layout *layout)
- {
- - blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_REMOVE, layout);
- -
- - spin_lock(&nvmem_layout_lock);
- - list_del(&layout->node);
- - spin_unlock(&nvmem_layout_lock);
- + /* Keep the API even with an empty stub in case we need it later */
- }
- EXPORT_SYMBOL_GPL(nvmem_layout_unregister);
-
- -static struct nvmem_layout *nvmem_layout_get(struct nvmem_device *nvmem)
- -{
- - struct device_node *layout_np;
- - struct nvmem_layout *l, *layout = ERR_PTR(-EPROBE_DEFER);
- -
- - layout_np = of_nvmem_layout_get_container(nvmem);
- - if (!layout_np)
- - return NULL;
- -
- - /* Fixed layouts don't have a matching driver */
- - if (of_device_is_compatible(layout_np, "fixed-layout")) {
- - of_node_put(layout_np);
- - return NULL;
- - }
- -
- - /*
- - * In case the nvmem device was built-in while the layout was built as a
- - * module, we shall manually request the layout driver loading otherwise
- - * we'll never have any match.
- - */
- - of_request_module(layout_np);
- -
- - spin_lock(&nvmem_layout_lock);
- -
- - list_for_each_entry(l, &nvmem_layouts, node) {
- - if (of_match_node(l->of_match_table, layout_np)) {
- - if (try_module_get(l->owner))
- - layout = l;
- -
- - break;
- - }
- - }
- -
- - spin_unlock(&nvmem_layout_lock);
- - of_node_put(layout_np);
- -
- - return layout;
- -}
- -
- -static void nvmem_layout_put(struct nvmem_layout *layout)
- -{
- - if (layout)
- - module_put(layout->owner);
- -}
- -
- -static int nvmem_add_cells_from_layout(struct nvmem_device *nvmem)
- -{
- - struct nvmem_layout *layout = nvmem->layout;
- - int ret;
- -
- - if (layout && layout->add_cells) {
- - ret = layout->add_cells(&nvmem->dev, nvmem);
- - if (ret)
- - return ret;
- - }
- -
- - return 0;
- -}
- -
- -#if IS_ENABLED(CONFIG_OF)
- -struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
- -{
- - return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
- -}
- -EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
- -#endif
- -
- const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem,
- struct nvmem_layout *layout)
- {
- @@ -838,7 +760,7 @@ const void *nvmem_layout_get_match_data(
- const struct of_device_id *match;
-
- layout_np = of_nvmem_layout_get_container(nvmem);
- - match = of_match_node(layout->of_match_table, layout_np);
- + match = of_match_node(layout->dev.driver->of_match_table, layout_np);
-
- return match ? match->data : NULL;
- }
- @@ -950,19 +872,6 @@ struct nvmem_device *nvmem_register(cons
- goto err_put_device;
- }
-
- - /*
- - * If the driver supplied a layout by config->layout, the module
- - * pointer will be NULL and nvmem_layout_put() will be a noop.
- - */
- - nvmem->layout = config->layout ?: nvmem_layout_get(nvmem);
- - if (IS_ERR(nvmem->layout)) {
- - rval = PTR_ERR(nvmem->layout);
- - nvmem->layout = NULL;
- -
- - if (rval == -EPROBE_DEFER)
- - goto err_teardown_compat;
- - }
- -
- if (config->cells) {
- rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
- if (rval)
- @@ -983,24 +892,24 @@ struct nvmem_device *nvmem_register(cons
- if (rval)
- goto err_remove_cells;
-
- - rval = nvmem_add_cells_from_layout(nvmem);
- - 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;
-
- + rval = nvmem_populate_layout(nvmem);
- + if (rval)
- + goto err_remove_dev;
- +
- blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
-
- return nvmem;
-
- +err_remove_dev:
- + device_del(&nvmem->dev);
- err_remove_cells:
- nvmem_device_remove_all_cells(nvmem);
- - nvmem_layout_put(nvmem->layout);
- -err_teardown_compat:
- if (config->compat)
- nvmem_sysfs_remove_compat(nvmem, config);
- err_put_device:
- @@ -1022,7 +931,7 @@ static void nvmem_device_release(struct
- device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
-
- nvmem_device_remove_all_cells(nvmem);
- - nvmem_layout_put(nvmem->layout);
- + nvmem_destroy_layout(nvmem);
- device_unregister(&nvmem->dev);
- }
-
- @@ -1324,6 +1233,12 @@ nvmem_cell_get_from_lookup(struct device
- return cell;
- }
-
- +static void nvmem_layout_module_put(struct nvmem_device *nvmem)
- +{
- + if (nvmem->layout && nvmem->layout->dev.driver)
- + module_put(nvmem->layout->dev.driver->owner);
- +}
- +
- #if IS_ENABLED(CONFIG_OF)
- static struct nvmem_cell_entry *
- nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np)
- @@ -1342,6 +1257,18 @@ nvmem_find_cell_entry_by_node(struct nvm
- return cell;
- }
-
- +static int nvmem_layout_module_get_optional(struct nvmem_device *nvmem)
- +{
- + if (!nvmem->layout)
- + return 0;
- +
- + if (!nvmem->layout->dev.driver ||
- + !try_module_get(nvmem->layout->dev.driver->owner))
- + return -EPROBE_DEFER;
- +
- + return 0;
- +}
- +
- /**
- * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
- *
- @@ -1404,16 +1331,29 @@ struct nvmem_cell *of_nvmem_cell_get(str
- return ERR_CAST(nvmem);
- }
-
- + ret = nvmem_layout_module_get_optional(nvmem);
- + if (ret) {
- + of_node_put(cell_np);
- + __nvmem_device_put(nvmem);
- + return ERR_PTR(ret);
- + }
- +
- cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np);
- of_node_put(cell_np);
- if (!cell_entry) {
- __nvmem_device_put(nvmem);
- - return ERR_PTR(-ENOENT);
- + nvmem_layout_module_put(nvmem);
- + if (nvmem->layout)
- + return ERR_PTR(-EPROBE_DEFER);
- + else
- + return ERR_PTR(-ENOENT);
- }
-
- cell = nvmem_create_cell(cell_entry, id, cell_index);
- - if (IS_ERR(cell))
- + if (IS_ERR(cell)) {
- __nvmem_device_put(nvmem);
- + nvmem_layout_module_put(nvmem);
- + }
-
- return cell;
- }
- @@ -1527,6 +1467,7 @@ void nvmem_cell_put(struct nvmem_cell *c
-
- kfree(cell);
- __nvmem_device_put(nvmem);
- + nvmem_layout_module_put(nvmem);
- }
- EXPORT_SYMBOL_GPL(nvmem_cell_put);
-
- @@ -2104,11 +2045,22 @@ EXPORT_SYMBOL_GPL(nvmem_dev_name);
-
- static int __init nvmem_init(void)
- {
- - return bus_register(&nvmem_bus_type);
- + int ret;
- +
- + ret = bus_register(&nvmem_bus_type);
- + if (ret)
- + return ret;
- +
- + ret = nvmem_layout_bus_register();
- + if (ret)
- + bus_unregister(&nvmem_bus_type);
- +
- + return ret;
- }
-
- static void __exit nvmem_exit(void)
- {
- + nvmem_layout_bus_unregister();
- bus_unregister(&nvmem_bus_type);
- }
-
- --- a/drivers/nvmem/internals.h
- +++ b/drivers/nvmem/internals.h
- @@ -34,4 +34,25 @@ struct nvmem_device {
- void *priv;
- };
-
- +#if IS_ENABLED(CONFIG_OF)
- +int nvmem_layout_bus_register(void);
- +void nvmem_layout_bus_unregister(void);
- +int nvmem_populate_layout(struct nvmem_device *nvmem);
- +void nvmem_destroy_layout(struct nvmem_device *nvmem);
- +#else /* CONFIG_OF */
- +static inline int nvmem_layout_bus_register(void)
- +{
- + return 0;
- +}
- +
- +static inline void nvmem_layout_bus_unregister(void) {}
- +
- +static inline int nvmem_populate_layout(struct nvmem_device *nvmem)
- +{
- + return 0;
- +}
- +
- +static inline void nvmem_destroy_layout(struct nvmem_device *nvmem) { }
- +#endif /* CONFIG_OF */
- +
- #endif /* ifndef _LINUX_NVMEM_INTERNALS_H */
- --- /dev/null
- +++ b/drivers/nvmem/layouts.c
- @@ -0,0 +1,201 @@
- +// SPDX-License-Identifier: GPL-2.0
- +/*
- + * NVMEM layout bus handling
- + *
- + * Copyright (C) 2023 Bootlin
- + * Author: Miquel Raynal <[email protected]
- + */
- +
- +#include <linux/device.h>
- +#include <linux/dma-mapping.h>
- +#include <linux/nvmem-consumer.h>
- +#include <linux/nvmem-provider.h>
- +#include <linux/of.h>
- +#include <linux/of_device.h>
- +#include <linux/of_irq.h>
- +
- +#include "internals.h"
- +
- +#define to_nvmem_layout_driver(drv) \
- + (container_of((drv), struct nvmem_layout_driver, driver))
- +#define to_nvmem_layout_device(_dev) \
- + container_of((_dev), struct nvmem_layout, dev)
- +
- +static int nvmem_layout_bus_match(struct device *dev, struct device_driver *drv)
- +{
- + return of_driver_match_device(dev, drv);
- +}
- +
- +static int nvmem_layout_bus_probe(struct device *dev)
- +{
- + struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
- + struct nvmem_layout *layout = to_nvmem_layout_device(dev);
- +
- + if (!drv->probe || !drv->remove)
- + return -EINVAL;
- +
- + return drv->probe(layout);
- +}
- +
- +static void nvmem_layout_bus_remove(struct device *dev)
- +{
- + struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
- + struct nvmem_layout *layout = to_nvmem_layout_device(dev);
- +
- + return drv->remove(layout);
- +}
- +
- +static struct bus_type nvmem_layout_bus_type = {
- + .name = "nvmem-layout",
- + .match = nvmem_layout_bus_match,
- + .probe = nvmem_layout_bus_probe,
- + .remove = nvmem_layout_bus_remove,
- +};
- +
- +int nvmem_layout_driver_register(struct nvmem_layout_driver *drv)
- +{
- + drv->driver.bus = &nvmem_layout_bus_type;
- +
- + return driver_register(&drv->driver);
- +}
- +EXPORT_SYMBOL_GPL(nvmem_layout_driver_register);
- +
- +void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv)
- +{
- + driver_unregister(&drv->driver);
- +}
- +EXPORT_SYMBOL_GPL(nvmem_layout_driver_unregister);
- +
- +static void nvmem_layout_release_device(struct device *dev)
- +{
- + struct nvmem_layout *layout = to_nvmem_layout_device(dev);
- +
- + of_node_put(layout->dev.of_node);
- + kfree(layout);
- +}
- +
- +static int nvmem_layout_create_device(struct nvmem_device *nvmem,
- + struct device_node *np)
- +{
- + struct nvmem_layout *layout;
- + struct device *dev;
- + int ret;
- +
- + layout = kzalloc(sizeof(*layout), GFP_KERNEL);
- + if (!layout)
- + return -ENOMEM;
- +
- + /* Create a bidirectional link */
- + layout->nvmem = nvmem;
- + nvmem->layout = layout;
- +
- + /* Device model registration */
- + dev = &layout->dev;
- + device_initialize(dev);
- + dev->parent = &nvmem->dev;
- + dev->bus = &nvmem_layout_bus_type;
- + dev->release = nvmem_layout_release_device;
- + dev->coherent_dma_mask = DMA_BIT_MASK(32);
- + dev->dma_mask = &dev->coherent_dma_mask;
- + device_set_node(dev, of_fwnode_handle(of_node_get(np)));
- + of_device_make_bus_id(dev);
- + of_msi_configure(dev, dev->of_node);
- +
- + ret = device_add(dev);
- + if (ret) {
- + put_device(dev);
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +static const struct of_device_id of_nvmem_layout_skip_table[] = {
- + { .compatible = "fixed-layout", },
- + {}
- +};
- +
- +static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
- + struct device_node *layout_dn)
- +{
- + int ret;
- +
- + /* Make sure it has a compatible property */
- + if (!of_get_property(layout_dn, "compatible", NULL)) {
- + pr_debug("%s() - skipping %pOF, no compatible prop\n",
- + __func__, layout_dn);
- + return 0;
- + }
- +
- + /* Fixed layouts are parsed manually somewhere else for now */
- + if (of_match_node(of_nvmem_layout_skip_table, layout_dn)) {
- + pr_debug("%s() - skipping %pOF node\n", __func__, layout_dn);
- + return 0;
- + }
- +
- + if (of_node_check_flag(layout_dn, OF_POPULATED_BUS)) {
- + pr_debug("%s() - skipping %pOF, already populated\n",
- + __func__, layout_dn);
- +
- + return 0;
- + }
- +
- + /* NVMEM layout buses expect only a single device representing the layout */
- + ret = nvmem_layout_create_device(nvmem, layout_dn);
- + if (ret)
- + return ret;
- +
- + of_node_set_flag(layout_dn, OF_POPULATED_BUS);
- +
- + return 0;
- +}
- +
- +struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
- +{
- + return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
- +}
- +EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
- +
- +/*
- + * Returns the number of devices populated, 0 if the operation was not relevant
- + * for this nvmem device, an error code otherwise.
- + */
- +int nvmem_populate_layout(struct nvmem_device *nvmem)
- +{
- + struct device_node *layout_dn;
- + int ret;
- +
- + layout_dn = of_nvmem_layout_get_container(nvmem);
- + if (!layout_dn)
- + return 0;
- +
- + /* Populate the layout device */
- + device_links_supplier_sync_state_pause();
- + ret = nvmem_layout_bus_populate(nvmem, layout_dn);
- + device_links_supplier_sync_state_resume();
- +
- + of_node_put(layout_dn);
- + return ret;
- +}
- +
- +void nvmem_destroy_layout(struct nvmem_device *nvmem)
- +{
- + struct device *dev;
- +
- + if (!nvmem->layout)
- + return;
- +
- + dev = &nvmem->layout->dev;
- + of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
- + device_unregister(dev);
- +}
- +
- +int nvmem_layout_bus_register(void)
- +{
- + return bus_register(&nvmem_layout_bus_type);
- +}
- +
- +void nvmem_layout_bus_unregister(void)
- +{
- + bus_unregister(&nvmem_layout_bus_type);
- +}
- --- a/drivers/nvmem/layouts/Kconfig
- +++ b/drivers/nvmem/layouts/Kconfig
- @@ -1,5 +1,11 @@
- # SPDX-License-Identifier: GPL-2.0
-
- +config NVMEM_LAYOUTS
- + bool
- + depends on OF
- +
- +if NVMEM_LAYOUTS
- +
- menu "Layout Types"
-
- config NVMEM_LAYOUT_SL28_VPD
- @@ -21,3 +27,5 @@ config NVMEM_LAYOUT_ONIE_TLV
- If unsure, say N.
-
- endmenu
- +
- +endif
- --- a/drivers/nvmem/layouts/onie-tlv.c
- +++ b/drivers/nvmem/layouts/onie-tlv.c
- @@ -225,16 +225,32 @@ static int onie_tlv_parse_table(struct d
- return 0;
- }
-
- +static int onie_tlv_probe(struct nvmem_layout *layout)
- +{
- + layout->add_cells = onie_tlv_parse_table;
- +
- + return nvmem_layout_register(layout);
- +}
- +
- +static void onie_tlv_remove(struct nvmem_layout *layout)
- +{
- + nvmem_layout_unregister(layout);
- +}
- +
- static const struct of_device_id onie_tlv_of_match_table[] = {
- { .compatible = "onie,tlv-layout", },
- {},
- };
- MODULE_DEVICE_TABLE(of, onie_tlv_of_match_table);
-
- -static struct nvmem_layout onie_tlv_layout = {
- - .name = "ONIE tlv layout",
- - .of_match_table = onie_tlv_of_match_table,
- - .add_cells = onie_tlv_parse_table,
- +static struct nvmem_layout_driver onie_tlv_layout = {
- + .driver = {
- + .owner = THIS_MODULE,
- + .name = "onie-tlv-layout",
- + .of_match_table = onie_tlv_of_match_table,
- + },
- + .probe = onie_tlv_probe,
- + .remove = onie_tlv_remove,
- };
- module_nvmem_layout_driver(onie_tlv_layout);
-
- --- a/drivers/nvmem/layouts/sl28vpd.c
- +++ b/drivers/nvmem/layouts/sl28vpd.c
- @@ -134,16 +134,32 @@ static int sl28vpd_add_cells(struct devi
- return 0;
- }
-
- +static int sl28vpd_probe(struct nvmem_layout *layout)
- +{
- + layout->add_cells = sl28vpd_add_cells;
- +
- + return nvmem_layout_register(layout);
- +}
- +
- +static void sl28vpd_remove(struct nvmem_layout *layout)
- +{
- + nvmem_layout_unregister(layout);
- +}
- +
- static const struct of_device_id sl28vpd_of_match_table[] = {
- { .compatible = "kontron,sl28-vpd" },
- {},
- };
- MODULE_DEVICE_TABLE(of, sl28vpd_of_match_table);
-
- -static struct nvmem_layout sl28vpd_layout = {
- - .name = "sl28-vpd",
- - .of_match_table = sl28vpd_of_match_table,
- - .add_cells = sl28vpd_add_cells,
- +static struct nvmem_layout_driver sl28vpd_layout = {
- + .driver = {
- + .owner = THIS_MODULE,
- + .name = "kontron-sl28vpd-layout",
- + .of_match_table = sl28vpd_of_match_table,
- + },
- + .probe = sl28vpd_probe,
- + .remove = sl28vpd_remove,
- };
- module_nvmem_layout_driver(sl28vpd_layout);
-
- --- a/include/linux/nvmem-provider.h
- +++ b/include/linux/nvmem-provider.h
- @@ -9,6 +9,7 @@
- #ifndef _LINUX_NVMEM_PROVIDER_H
- #define _LINUX_NVMEM_PROVIDER_H
-
- +#include <linux/device.h>
- #include <linux/device/driver.h>
- #include <linux/err.h>
- #include <linux/errno.h>
- @@ -158,12 +159,11 @@ struct nvmem_cell_table {
- /**
- * struct nvmem_layout - NVMEM layout definitions
- *
- - * @name: Layout name.
- - * @of_match_table: Open firmware match table.
- - * @add_cells: Called to populate the layout using
- - * nvmem_add_one_cell().
- - * @owner: Pointer to struct module.
- - * @node: List node.
- + * @dev: Device-model layout device.
- + * @nvmem: The underlying NVMEM device
- + * @add_cells: Will be called if a nvmem device is found which
- + * has this layout. The function will add layout
- + * specific cells with nvmem_add_one_cell().
- *
- * A nvmem device can hold a well defined structure which can just be
- * evaluated during runtime. For example a TLV list, or a list of "name=val"
- @@ -171,13 +171,15 @@ struct nvmem_cell_table {
- * cells.
- */
- struct nvmem_layout {
- - const char *name;
- - const struct of_device_id *of_match_table;
- + struct device dev;
- + struct nvmem_device *nvmem;
- int (*add_cells)(struct device *dev, struct nvmem_device *nvmem);
- +};
-
- - /* private */
- - struct module *owner;
- - struct list_head node;
- +struct nvmem_layout_driver {
- + struct device_driver driver;
- + int (*probe)(struct nvmem_layout *layout);
- + void (*remove)(struct nvmem_layout *layout);
- };
-
- #if IS_ENABLED(CONFIG_NVMEM)
- @@ -194,11 +196,15 @@ void nvmem_del_cell_table(struct nvmem_c
- int nvmem_add_one_cell(struct nvmem_device *nvmem,
- const struct nvmem_cell_info *info);
-
- -int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner);
- -#define nvmem_layout_register(layout) \
- - __nvmem_layout_register(layout, THIS_MODULE)
- +int nvmem_layout_register(struct nvmem_layout *layout);
- void nvmem_layout_unregister(struct nvmem_layout *layout);
-
- +int nvmem_layout_driver_register(struct nvmem_layout_driver *drv);
- +void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv);
- +#define module_nvmem_layout_driver(__nvmem_layout_driver) \
- + module_driver(__nvmem_layout_driver, nvmem_layout_driver_register, \
- + nvmem_layout_driver_unregister)
- +
- const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem,
- struct nvmem_layout *layout);
-
- @@ -262,8 +268,4 @@ static inline struct device_node *of_nvm
-
- #endif /* CONFIG_NVMEM && CONFIG_OF */
-
- -#define module_nvmem_layout_driver(__layout_driver) \
- - module_driver(__layout_driver, nvmem_layout_register, \
- - nvmem_layout_unregister)
- -
- #endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
|