1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org>
6 /* UBI NVMEM provider */
8 #include <linux/nvmem-provider.h>
10 /* List of all NVMEM devices */
11 static LIST_HEAD(nvmem_devices
);
12 static DEFINE_MUTEX(devices_mutex
);
15 struct nvmem_device
*nvmem
;
19 struct list_head list
;
22 static int ubi_nvmem_reg_read(void *priv
, unsigned int from
,
23 void *val
, size_t bytes
)
25 size_t to_read
, bytes_left
= bytes
;
26 struct ubi_nvmem
*unv
= priv
;
27 struct ubi_volume_desc
*desc
;
32 desc
= ubi_open_volume(unv
->ubi_num
, unv
->vol_id
, UBI_READONLY
);
36 offs
= from
% unv
->usable_leb_size
;
37 lnum
= from
/ unv
->usable_leb_size
;
39 to_read
= unv
->usable_leb_size
- offs
;
41 if (to_read
> bytes_left
)
44 err
= ubi_read(desc
, lnum
, val
, offs
, to_read
);
50 bytes_left
-= to_read
;
53 ubi_close_volume(desc
);
61 static int ubi_nvmem_add(struct ubi_volume_info
*vi
)
63 struct device_node
*np
= dev_of_node(vi
->dev
);
64 struct nvmem_config config
= {};
65 struct ubi_nvmem
*unv
;
71 if (!of_get_child_by_name(np
, "nvmem-layout"))
74 if (WARN_ON_ONCE(vi
->usable_leb_size
<= 0) ||
75 WARN_ON_ONCE(vi
->size
<= 0))
78 unv
= kzalloc(sizeof(struct ubi_nvmem
), GFP_KERNEL
);
82 config
.id
= NVMEM_DEVID_NONE
;
84 config
.name
= dev_name(vi
->dev
);
85 config
.owner
= THIS_MODULE
;
87 config
.reg_read
= ubi_nvmem_reg_read
;
88 config
.size
= vi
->usable_leb_size
* vi
->size
;
91 config
.read_only
= true;
92 config
.root_only
= true;
93 config
.ignore_wp
= true;
96 unv
->ubi_num
= vi
->ubi_num
;
97 unv
->vol_id
= vi
->vol_id
;
98 unv
->usable_leb_size
= vi
->usable_leb_size
;
99 unv
->nvmem
= nvmem_register(&config
);
100 if (IS_ERR(unv
->nvmem
)) {
101 ret
= dev_err_probe(vi
->dev
, PTR_ERR(unv
->nvmem
),
102 "Failed to register NVMEM device\n");
107 mutex_lock(&devices_mutex
);
108 list_add_tail(&unv
->list
, &nvmem_devices
);
109 mutex_unlock(&devices_mutex
);
114 static void ubi_nvmem_remove(struct ubi_volume_info
*vi
)
116 struct ubi_nvmem
*unv_c
, *unv
= NULL
;
118 mutex_lock(&devices_mutex
);
119 list_for_each_entry(unv_c
, &nvmem_devices
, list
)
120 if (unv_c
->ubi_num
== vi
->ubi_num
&& unv_c
->vol_id
== vi
->vol_id
) {
126 mutex_unlock(&devices_mutex
);
130 list_del(&unv
->list
);
131 mutex_unlock(&devices_mutex
);
132 nvmem_unregister(unv
->nvmem
);
137 * nvmem_notify - UBI notification handler.
138 * @nb: registered notifier block
139 * @l: notification type
140 * @ns_ptr: pointer to the &struct ubi_notification object
142 static int nvmem_notify(struct notifier_block
*nb
, unsigned long l
,
145 struct ubi_notification
*nt
= ns_ptr
;
148 case UBI_VOLUME_RESIZED
:
149 ubi_nvmem_remove(&nt
->vi
);
151 case UBI_VOLUME_ADDED
:
152 ubi_nvmem_add(&nt
->vi
);
154 case UBI_VOLUME_SHUTDOWN
:
155 ubi_nvmem_remove(&nt
->vi
);
163 static struct notifier_block nvmem_notifier
= {
164 .notifier_call
= nvmem_notify
,
167 static int __init
ubi_nvmem_init(void)
169 return ubi_register_volume_notifier(&nvmem_notifier
, 0);
172 static void __exit
ubi_nvmem_exit(void)
174 struct ubi_nvmem
*unv
, *tmp
;
176 mutex_lock(&devices_mutex
);
177 list_for_each_entry_safe(unv
, tmp
, &nvmem_devices
, list
) {
178 nvmem_unregister(unv
->nvmem
);
179 list_del(&unv
->list
);
182 mutex_unlock(&devices_mutex
);
184 ubi_unregister_volume_notifier(&nvmem_notifier
);
187 module_init(ubi_nvmem_init
);
188 module_exit(ubi_nvmem_exit
);
189 MODULE_DESCRIPTION("NVMEM layer over UBI volumes");
190 MODULE_AUTHOR("Daniel Golle");
191 MODULE_LICENSE("GPL");