blob: 9b8aa45667e2d796b0177efe8a4e966bcba6a88c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glasscceee552016-02-29 15:25:55 -07002/*
3 * Copyright (C) 2016 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glasscceee552016-02-29 15:25:55 -07005 */
6
Patrick Delaunay81313352021-04-27 11:02:19 +02007#define LOG_CATEGORY UCLASS_BLK
8
Simon Glasscceee552016-02-29 15:25:55 -07009#include <blk.h>
10#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070012#include <malloc.h>
Simon Glass655306c2020-05-10 11:39:58 -060013#include <part.h>
Simon Glasscceee552016-02-29 15:25:55 -070014#include <dm/device-internal.h>
15#include <dm/lists.h>
Stefan Roeseef58a902017-11-29 16:46:42 +010016#include <dm/uclass-internal.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070017#include <linux/err.h>
Simon Glasscceee552016-02-29 15:25:55 -070018
Marek Vasutddfa0882023-08-14 01:46:48 +020019#define blk_get_ops(dev) ((struct blk_ops *)(dev)->driver->ops)
20
Simon Glass95e6e032022-08-11 19:34:57 -060021static struct {
22 enum uclass_id id;
23 const char *name;
Simon Glassfada3f92022-09-17 09:00:09 -060024} uclass_idname_str[] = {
Simon Glassdbfa32c2022-08-11 19:34:59 -060025 { UCLASS_IDE, "ide" },
26 { UCLASS_SCSI, "scsi" },
27 { UCLASS_USB, "usb" },
28 { UCLASS_MMC, "mmc" },
29 { UCLASS_AHCI, "sata" },
Simon Glasse57f8d42022-10-29 19:47:17 -060030 { UCLASS_HOST, "host" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060031 { UCLASS_NVME, "nvme" },
Abdellatif El Khlifi857360c2023-04-17 10:11:52 +010032 { UCLASS_NVMXIP, "nvmxip" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060033 { UCLASS_EFI_MEDIA, "efi" },
34 { UCLASS_EFI_LOADER, "efiloader" },
35 { UCLASS_VIRTIO, "virtio" },
36 { UCLASS_PVBLOCK, "pvblock" },
Tobias Waldekranz4f76dd32023-02-16 16:33:49 +010037 { UCLASS_BLKMAP, "blkmap" },
Johan Jonker7a657e02023-10-18 16:00:40 +020038 { UCLASS_RKMTD, "rkmtd" },
Alexey Romanov8e1fd2e2024-07-18 08:46:05 +030039 { UCLASS_MTD, "mtd" },
Simon Glass4131ad52016-05-01 11:36:08 -060040};
41
Simon Glassfada3f92022-09-17 09:00:09 -060042static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
Simon Glass4131ad52016-05-01 11:36:08 -060043{
44 int i;
45
Simon Glassfada3f92022-09-17 09:00:09 -060046 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
47 if (!strcmp(uclass_idname, uclass_idname_str[i].name))
48 return uclass_idname_str[i].id;
Simon Glass4131ad52016-05-01 11:36:08 -060049 }
50
Simon Glassdbfa32c2022-08-11 19:34:59 -060051 return UCLASS_INVALID;
Simon Glass4131ad52016-05-01 11:36:08 -060052}
53
Simon Glassfada3f92022-09-17 09:00:09 -060054static enum uclass_id conv_uclass_id(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -060055{
Simon Glassdbfa32c2022-08-11 19:34:59 -060056 /*
57 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
58 * for USB storage devices, so need to return this as the uclass to
59 * use for USB. In fact USB_UCLASS is for USB controllers, not
60 * peripherals.
61 *
62 * The name of the UCLASS_MASS_STORAGE uclass driver is
63 * "usb_mass_storage", but we want to use "usb" in things like the
64 * 'part list' command and when showing interfaces.
65 *
66 * So for now we have this one-way conversion.
67 *
68 * The fix for this is possibly to:
69 * - rename UCLASS_MASS_STORAGE name to "usb"
70 * - rename UCLASS_USB name to "usb_ctlr"
71 * - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
72 */
Simon Glassfada3f92022-09-17 09:00:09 -060073 if (uclass_id == UCLASS_USB)
Simon Glassdbfa32c2022-08-11 19:34:59 -060074 return UCLASS_MASS_STORAGE;
Simon Glassfada3f92022-09-17 09:00:09 -060075 return uclass_id;
Simon Glass4131ad52016-05-01 11:36:08 -060076}
77
Simon Glassfada3f92022-09-17 09:00:09 -060078const char *blk_get_uclass_name(enum uclass_id uclass_id)
Simon Glass85af5a42017-07-29 11:34:53 -060079{
Simon Glass95e6e032022-08-11 19:34:57 -060080 int i;
81
Simon Glassfada3f92022-09-17 09:00:09 -060082 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
83 if (uclass_idname_str[i].id == uclass_id)
84 return uclass_idname_str[i].name;
Simon Glass95e6e032022-08-11 19:34:57 -060085 }
86
87 return "(none)";
Simon Glass85af5a42017-07-29 11:34:53 -060088}
89
Simon Glassfada3f92022-09-17 09:00:09 -060090struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -060091{
92 struct blk_desc *desc;
93 struct udevice *dev;
94 int ret;
95
Simon Glassfada3f92022-09-17 09:00:09 -060096 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass4131ad52016-05-01 11:36:08 -060097 if (ret)
98 return NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -070099 desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600100
101 return desc;
102}
103
104/*
105 * This function is complicated with driver model. We look up the interface
106 * name in a local table. This gives us an interface type which we can match
107 * against the uclass of the block device's parent.
108 */
Simon Glassfada3f92022-09-17 09:00:09 -0600109struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600110{
111 enum uclass_id uclass_id;
Simon Glass57b3d2e2022-08-11 19:35:01 -0600112 enum uclass_id type;
Simon Glass4131ad52016-05-01 11:36:08 -0600113 struct udevice *dev;
114 struct uclass *uc;
115 int ret;
116
Simon Glassfada3f92022-09-17 09:00:09 -0600117 type = uclass_name_to_iftype(uclass_idname);
Simon Glassdbfa32c2022-08-11 19:34:59 -0600118 if (type == UCLASS_INVALID) {
Simon Glass4131ad52016-05-01 11:36:08 -0600119 debug("%s: Unknown interface type '%s'\n", __func__,
Simon Glassfada3f92022-09-17 09:00:09 -0600120 uclass_idname);
Simon Glass4131ad52016-05-01 11:36:08 -0600121 return NULL;
122 }
Simon Glassfada3f92022-09-17 09:00:09 -0600123 uclass_id = conv_uclass_id(type);
Simon Glass4131ad52016-05-01 11:36:08 -0600124 if (uclass_id == UCLASS_INVALID) {
125 debug("%s: Unknown uclass for interface type'\n",
Simon Glassfada3f92022-09-17 09:00:09 -0600126 blk_get_uclass_name(type));
Simon Glass4131ad52016-05-01 11:36:08 -0600127 return NULL;
128 }
129
130 ret = uclass_get(UCLASS_BLK, &uc);
131 if (ret)
132 return NULL;
133 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700134 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600135
Simon Glassfada3f92022-09-17 09:00:09 -0600136 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
137 type, devnum, dev->name, desc->uclass_id, desc->devnum);
Simon Glass4131ad52016-05-01 11:36:08 -0600138 if (desc->devnum != devnum)
139 continue;
140
141 /* Find out the parent device uclass */
142 if (device_get_uclass_id(dev->parent) != uclass_id) {
143 debug("%s: parent uclass %d, this dev %d\n", __func__,
144 device_get_uclass_id(dev->parent), uclass_id);
145 continue;
146 }
147
148 if (device_probe(dev))
149 return NULL;
150
151 debug("%s: Device desc %p\n", __func__, desc);
152 return desc;
153 }
154 debug("%s: No device found\n", __func__);
155
156 return NULL;
157}
158
159/**
Tien Fong Chee10378522018-07-06 16:26:36 +0800160 * blk_get_by_device() - Get the block device descriptor for the given device
161 * @dev: Instance of a storage device
162 *
163 * Return: With block device descriptor on success , NULL if there is no such
164 * block device.
165 */
166struct blk_desc *blk_get_by_device(struct udevice *dev)
167{
Simon Glasscfd72932019-09-25 08:55:56 -0600168 struct udevice *child_dev;
Tien Fong Chee10378522018-07-06 16:26:36 +0800169
Simon Glasscfd72932019-09-25 08:55:56 -0600170 device_foreach_child(child_dev, dev) {
Tien Fong Chee10378522018-07-06 16:26:36 +0800171 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
172 continue;
173
Simon Glass71fa5b42020-12-03 16:55:18 -0700174 return dev_get_uclass_plat(child_dev);
Tien Fong Chee10378522018-07-06 16:26:36 +0800175 }
176
177 debug("%s: No block device found\n", __func__);
178
179 return NULL;
180}
181
Bin Meng9efc2452023-09-26 16:43:41 +0800182int blk_get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
Simon Glass4131ad52016-05-01 11:36:08 -0600183{
184 bool found_more = false;
185 struct udevice *dev;
186 struct uclass *uc;
187 int ret;
188
189 *descp = NULL;
190 ret = uclass_get(UCLASS_BLK, &uc);
191 if (ret)
192 return ret;
193 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700194 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600195
Simon Glassfada3f92022-09-17 09:00:09 -0600196 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
197 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
198 if (desc->uclass_id == uclass_id) {
Simon Glass4131ad52016-05-01 11:36:08 -0600199 if (desc->devnum == devnum) {
200 ret = device_probe(dev);
201 if (ret)
202 return ret;
203
Michal Simekf438b6b2016-11-16 17:37:42 +0100204 *descp = desc;
205 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600206 } else if (desc->devnum > devnum) {
207 found_more = true;
208 }
209 }
210 }
211
212 return found_more ? -ENOENT : -ENODEV;
213}
214
Simon Glassfada3f92022-09-17 09:00:09 -0600215int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
Simon Glass13c2c292016-05-01 13:52:30 -0600216{
217 struct udevice *dev;
218 int ret;
219
Simon Glassfada3f92022-09-17 09:00:09 -0600220 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass13c2c292016-05-01 13:52:30 -0600221 if (ret)
222 return ret;
223
developerf50d8d12019-08-27 15:32:18 +0800224 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600225}
226
Simon Glassfada3f92022-09-17 09:00:09 -0600227int blk_list_part(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600228{
229 struct blk_desc *desc;
230 int devnum, ok;
231 int ret;
232
233 for (ok = 0, devnum = 0;; ++devnum) {
Bin Meng9efc2452023-09-26 16:43:41 +0800234 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600235 if (ret == -ENODEV)
236 break;
237 else if (ret)
238 continue;
239 if (desc->part_type != PART_TYPE_UNKNOWN) {
240 ++ok;
241 if (devnum)
242 putc('\n');
243 part_print(desc);
244 }
245 }
246 if (!ok)
247 return -ENODEV;
248
249 return 0;
250}
251
Simon Glassfada3f92022-09-17 09:00:09 -0600252int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600253{
254 struct blk_desc *desc;
255 int ret;
256
Bin Meng9efc2452023-09-26 16:43:41 +0800257 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600258 if (ret)
259 return ret;
260 if (desc->type == DEV_TYPE_UNKNOWN)
261 return -ENOENT;
262 part_print(desc);
263
264 return 0;
265}
266
Simon Glassfada3f92022-09-17 09:00:09 -0600267void blk_list_devices(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600268{
269 struct blk_desc *desc;
270 int ret;
271 int i;
272
273 for (i = 0;; ++i) {
Bin Meng9efc2452023-09-26 16:43:41 +0800274 ret = blk_get_desc(uclass_id, i, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600275 if (ret == -ENODEV)
276 break;
277 else if (ret)
278 continue;
279 if (desc->type == DEV_TYPE_UNKNOWN)
280 continue; /* list only known devices */
281 printf("Device %d: ", i);
282 dev_print(desc);
283 }
284}
285
Simon Glassfada3f92022-09-17 09:00:09 -0600286int blk_print_device_num(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600287{
288 struct blk_desc *desc;
289 int ret;
290
Bin Meng9efc2452023-09-26 16:43:41 +0800291 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600292 if (ret)
293 return ret;
294 printf("\nIDE device %d: ", devnum);
295 dev_print(desc);
296
297 return 0;
298}
299
Simon Glassfada3f92022-09-17 09:00:09 -0600300int blk_show_device(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600301{
302 struct blk_desc *desc;
303 int ret;
304
305 printf("\nDevice %d: ", devnum);
Bin Meng9efc2452023-09-26 16:43:41 +0800306 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600307 if (ret == -ENODEV || ret == -ENOENT) {
308 printf("unknown device\n");
309 return -ENODEV;
310 }
311 if (ret)
312 return ret;
313 dev_print(desc);
314
315 if (desc->type == DEV_TYPE_UNKNOWN)
316 return -ENOENT;
317
318 return 0;
319}
320
Simon Glass13c2c292016-05-01 13:52:30 -0600321int blk_select_hwpart(struct udevice *dev, int hwpart)
322{
323 const struct blk_ops *ops = blk_get_ops(dev);
324
325 if (!ops)
326 return -ENOSYS;
327 if (!ops->select_hwpart)
328 return 0;
329
330 return ops->select_hwpart(dev, hwpart);
331}
332
333int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
334{
developerf50d8d12019-08-27 15:32:18 +0800335 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600336}
337
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200338static int _blk_next_device(int uclass_id, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700339{
340 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200341 int ret = 0;
342
343 for (; *devp; uclass_find_next_device(devp)) {
344 desc = dev_get_uclass_plat(*devp);
345 if (desc->uclass_id == uclass_id) {
346 ret = device_probe(*devp);
347 if (!ret)
348 return 0;
349 }
350 }
Simon Glasscceee552016-02-29 15:25:55 -0700351
Simon Glasscceee552016-02-29 15:25:55 -0700352 if (ret)
353 return ret;
Simon Glasscceee552016-02-29 15:25:55 -0700354
355 return -ENODEV;
356}
357
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200358int blk_first_device(int uclass_id, struct udevice **devp)
359{
360 uclass_find_first_device(UCLASS_BLK, devp);
361
362 return _blk_next_device(uclass_id, devp);
363}
364
Simon Glasscceee552016-02-29 15:25:55 -0700365int blk_next_device(struct udevice **devp)
366{
367 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200368 int uclass_id;
Simon Glasscceee552016-02-29 15:25:55 -0700369
Simon Glass71fa5b42020-12-03 16:55:18 -0700370 desc = dev_get_uclass_plat(*devp);
Simon Glassfada3f92022-09-17 09:00:09 -0600371 uclass_id = desc->uclass_id;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200372 uclass_find_next_device(devp);
373
374 return _blk_next_device(uclass_id, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700375}
376
Simon Glassfada3f92022-09-17 09:00:09 -0600377int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700378{
379 struct uclass *uc;
380 struct udevice *dev;
381 int ret;
382
383 ret = uclass_get(UCLASS_BLK, &uc);
384 if (ret)
385 return ret;
386 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700387 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700388
Simon Glassfada3f92022-09-17 09:00:09 -0600389 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
390 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
391 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
Simon Glasscceee552016-02-29 15:25:55 -0700392 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600393 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700394 }
395 }
396
397 return -ENODEV;
398}
399
Simon Glassfada3f92022-09-17 09:00:09 -0600400int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glassd5d4c102017-04-23 20:02:05 -0600401{
402 int ret;
403
Simon Glassfada3f92022-09-17 09:00:09 -0600404 ret = blk_find_device(uclass_id, devnum, devp);
Simon Glassd5d4c102017-04-23 20:02:05 -0600405 if (ret)
406 return ret;
407
408 return device_probe(*devp);
409}
410
Marek Vasut847e24f2023-08-14 01:49:59 +0200411struct blk_bounce_buffer {
412 struct udevice *dev;
413 struct bounce_buffer state;
414};
415
416static int blk_buffer_aligned(struct bounce_buffer *state)
417{
418#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
419 struct blk_bounce_buffer *bbstate =
420 container_of(state, struct blk_bounce_buffer, state);
421 struct udevice *dev = bbstate->dev;
422 const struct blk_ops *ops = blk_get_ops(dev);
423
424 if (ops->buffer_aligned)
425 return ops->buffer_aligned(dev, state);
426#endif /* CONFIG_BOUNCE_BUFFER */
427
428 return 1; /* Default, any buffer is OK */
429}
430
Simon Glass18861002022-10-20 18:22:54 -0600431long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700432{
Simon Glass18861002022-10-20 18:22:54 -0600433 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700434 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700435 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700436
437 if (!ops->read)
438 return -ENOSYS;
439
Simon Glass18861002022-10-20 18:22:54 -0600440 if (blkcache_read(desc->uclass_id, desc->devnum,
441 start, blkcnt, desc->blksz, buf))
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700442 return blkcnt;
Marek Vasut847e24f2023-08-14 01:49:59 +0200443
Johan Jonker10a986c2023-10-18 16:01:10 +0200444 if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && desc->bb) {
Marek Vasut847e24f2023-08-14 01:49:59 +0200445 struct blk_bounce_buffer bbstate = { .dev = dev };
446 int ret;
447
448 ret = bounce_buffer_start_extalign(&bbstate.state, buf,
449 blkcnt * desc->blksz,
450 GEN_BB_WRITE, desc->blksz,
451 blk_buffer_aligned);
452 if (ret)
453 return ret;
454
455 blks_read = ops->read(dev, start, blkcnt, bbstate.state.bounce_buffer);
456
457 bounce_buffer_stop(&bbstate.state);
458 } else {
459 blks_read = ops->read(dev, start, blkcnt, buf);
460 }
461
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700462 if (blks_read == blkcnt)
Simon Glass18861002022-10-20 18:22:54 -0600463 blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
464 desc->blksz, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700465
466 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700467}
468
Simon Glass18861002022-10-20 18:22:54 -0600469long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
470 const void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700471{
Simon Glass18861002022-10-20 18:22:54 -0600472 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700473 const struct blk_ops *ops = blk_get_ops(dev);
Marek Vasut847e24f2023-08-14 01:49:59 +0200474 long blks_written;
Simon Glasscceee552016-02-29 15:25:55 -0700475
476 if (!ops->write)
477 return -ENOSYS;
478
Simon Glass18861002022-10-20 18:22:54 -0600479 blkcache_invalidate(desc->uclass_id, desc->devnum);
480
Johan Jonker10a986c2023-10-18 16:01:10 +0200481 if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && desc->bb) {
Marek Vasut847e24f2023-08-14 01:49:59 +0200482 struct blk_bounce_buffer bbstate = { .dev = dev };
483 int ret;
484
485 ret = bounce_buffer_start_extalign(&bbstate.state, (void *)buf,
486 blkcnt * desc->blksz,
487 GEN_BB_READ, desc->blksz,
488 blk_buffer_aligned);
489 if (ret)
490 return ret;
491
492 blks_written = ops->write(dev, start, blkcnt,
493 bbstate.state.bounce_buffer);
494
495 bounce_buffer_stop(&bbstate.state);
496 } else {
497 blks_written = ops->write(dev, start, blkcnt, buf);
498 }
499
500 return blks_written;
Simon Glasscceee552016-02-29 15:25:55 -0700501}
502
Simon Glass18861002022-10-20 18:22:54 -0600503long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
Simon Glasscceee552016-02-29 15:25:55 -0700504{
Simon Glass18861002022-10-20 18:22:54 -0600505 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700506 const struct blk_ops *ops = blk_get_ops(dev);
507
508 if (!ops->erase)
509 return -ENOSYS;
510
Simon Glass18861002022-10-20 18:22:54 -0600511 blkcache_invalidate(desc->uclass_id, desc->devnum);
512
Simon Glasscceee552016-02-29 15:25:55 -0700513 return ops->erase(dev, start, blkcnt);
514}
515
Simon Glass18861002022-10-20 18:22:54 -0600516ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
517 void *buffer)
518{
519 return blk_read(desc->bdev, start, blkcnt, buffer);
520}
521
522ulong blk_dwrite(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
523 const void *buffer)
524{
525 return blk_write(desc->bdev, start, blkcnt, buffer);
526}
527
528ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
529{
530 return blk_erase(desc->bdev, start, blkcnt);
531}
532
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600533int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
Simon Glass4f269132017-05-27 11:37:17 -0600534{
535 struct udevice *dev;
Simon Glass4f269132017-05-27 11:37:17 -0600536
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600537 if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) {
Simon Glass4f269132017-05-27 11:37:17 -0600538 debug("%s: No block device found for parent '%s'\n", __func__,
539 parent->name);
540 return -ENODEV;
541 }
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600542 *devp = dev;
543
544 return 0;
545}
546
547int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
548{
549 struct udevice *dev;
550 int ret;
551
552 ret = blk_find_from_parent(parent, &dev);
553 if (ret)
554 return ret;
Simon Glass4f269132017-05-27 11:37:17 -0600555 ret = device_probe(dev);
556 if (ret)
557 return ret;
558 *devp = dev;
559
560 return 0;
561}
562
Simon Glassf3086cf2022-04-24 23:31:03 -0600563const char *blk_get_devtype(struct udevice *dev)
564{
565 struct udevice *parent = dev_get_parent(dev);
566
567 return uclass_get_name(device_get_uclass_id(parent));
568};
569
Simon Glassfada3f92022-09-17 09:00:09 -0600570int blk_find_max_devnum(enum uclass_id uclass_id)
Simon Glassd089ba32016-05-01 11:36:28 -0600571{
572 struct udevice *dev;
573 int max_devnum = -ENODEV;
574 struct uclass *uc;
575 int ret;
576
577 ret = uclass_get(UCLASS_BLK, &uc);
578 if (ret)
579 return ret;
580 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700581 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600582
Simon Glassfada3f92022-09-17 09:00:09 -0600583 if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
Simon Glassd089ba32016-05-01 11:36:28 -0600584 max_devnum = desc->devnum;
585 }
586
587 return max_devnum;
588}
589
Simon Glassfada3f92022-09-17 09:00:09 -0600590int blk_next_free_devnum(enum uclass_id uclass_id)
Simon Glassdbc38612017-04-23 20:02:06 -0600591{
592 int ret;
593
Simon Glassfada3f92022-09-17 09:00:09 -0600594 ret = blk_find_max_devnum(uclass_id);
Simon Glassdbc38612017-04-23 20:02:06 -0600595 if (ret == -ENODEV)
596 return 0;
597 if (ret < 0)
598 return ret;
599
600 return ret + 1;
601}
602
Simon Glassfc7a7442021-07-05 16:32:59 -0600603static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
604{
605 const struct blk_desc *desc = dev_get_uclass_plat(dev);
606 enum blk_flag_t flags;
607
608 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
609
610 return flags & req_flags ? 0 : 1;
611}
612
Simon Glass8e61f932022-02-28 12:08:35 -0700613int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
614{
615 int ret;
616
617 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
618 *devp && !blk_flags_check(*devp, flags);
619 ret = uclass_find_next_device(devp))
620 return 0;
621
622 return -ENODEV;
623}
624
625int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
626{
627 int ret;
628
629 for (ret = uclass_find_next_device(devp);
630 *devp && !blk_flags_check(*devp, flags);
631 ret = uclass_find_next_device(devp))
632 return 0;
633
634 return -ENODEV;
635}
636
Simon Glassfc7a7442021-07-05 16:32:59 -0600637int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
638{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200639 for (uclass_first_device(UCLASS_BLK, devp);
640 *devp;
641 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600642 if (!blk_flags_check(*devp, flags))
643 return 0;
644 }
645
646 return -ENODEV;
647}
648
649int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
650{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200651 for (uclass_next_device(devp);
652 *devp;
653 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600654 if (!blk_flags_check(*devp, flags))
655 return 0;
656 }
657
658 return -ENODEV;
659}
660
661int blk_count_devices(enum blk_flag_t flag)
662{
663 struct udevice *dev;
664 int count = 0;
665
666 blk_foreach_probe(flag, dev)
667 count++;
668
669 return count;
670}
671
Simon Glassfada3f92022-09-17 09:00:09 -0600672static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
Simon Glasse4fef742017-04-23 20:02:07 -0600673{
674 struct udevice *dev;
675 struct uclass *uc;
676 int ret;
677
678 ret = uclass_get(UCLASS_BLK, &uc);
679 if (ret)
680 return ret;
681 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700682 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600683
Simon Glassfada3f92022-09-17 09:00:09 -0600684 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
685 int next = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600686
687 if (next < 0)
688 return next;
689 desc->devnum = next;
690 return 0;
691 }
692 }
693
694 return -ENOENT;
695}
696
Simon Glasscceee552016-02-29 15:25:55 -0700697int blk_create_device(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600698 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200699 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700700{
701 struct blk_desc *desc;
702 struct udevice *dev;
703 int ret;
704
Simon Glassd089ba32016-05-01 11:36:28 -0600705 if (devnum == -1) {
Simon Glassfada3f92022-09-17 09:00:09 -0600706 devnum = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600707 } else {
Simon Glassfada3f92022-09-17 09:00:09 -0600708 ret = blk_claim_devnum(uclass_id, devnum);
Simon Glasse4fef742017-04-23 20:02:07 -0600709 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600710 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600711 }
Simon Glasse4fef742017-04-23 20:02:07 -0600712 if (devnum < 0)
713 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600714 ret = device_bind_driver(parent, drv_name, name, &dev);
715 if (ret)
716 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700717 desc = dev_get_uclass_plat(dev);
Simon Glassfada3f92022-09-17 09:00:09 -0600718 desc->uclass_id = uclass_id;
Simon Glass77f7fb82016-05-01 13:52:22 -0600719 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200720 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200721 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600722 desc->part_type = PART_TYPE_UNKNOWN;
723 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700724 desc->devnum = devnum;
725 *devp = dev;
726
727 return 0;
728}
729
Simon Glass966b6952016-05-01 11:36:29 -0600730int blk_create_devicef(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600731 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200732 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600733{
734 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600735 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600736
737 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
738 str = strdup(dev_name);
739 if (!str)
740 return -ENOMEM;
741
Simon Glassfada3f92022-09-17 09:00:09 -0600742 ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200743 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600744 if (ret) {
745 free(str);
746 return ret;
747 }
748 device_set_name_alloced(*devp);
749
Simon Glass44505972017-07-29 11:34:59 -0600750 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600751}
752
AKASHI Takahiro3e32dbe2021-12-10 15:49:29 +0900753int blk_probe_or_unbind(struct udevice *dev)
754{
755 int ret;
756
757 ret = device_probe(dev);
758 if (ret) {
759 log_debug("probing %s failed\n", dev->name);
760 device_unbind(dev);
761 }
762
763 return ret;
764}
765
Simon Glassfada3f92022-09-17 09:00:09 -0600766int blk_unbind_all(int uclass_id)
Simon Glasscceee552016-02-29 15:25:55 -0700767{
768 struct uclass *uc;
769 struct udevice *dev, *next;
770 int ret;
771
772 ret = uclass_get(UCLASS_BLK, &uc);
773 if (ret)
774 return ret;
775 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700776 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700777
Simon Glassfada3f92022-09-17 09:00:09 -0600778 if (desc->uclass_id == uclass_id) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100779 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700780 if (ret)
781 return ret;
782 ret = device_unbind(dev);
783 if (ret)
784 return ret;
785 }
786 }
787
788 return 0;
789}
790
Marek Vasut14fafef2023-08-14 01:46:47 +0200791static int part_create_block_devices(struct udevice *blk_dev)
792{
793 int part, count;
794 struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
795 struct disk_partition info;
796 struct disk_part *part_data;
797 char devname[32];
798 struct udevice *dev;
799 int ret;
800
801 if (!CONFIG_IS_ENABLED(PARTITIONS) || !blk_enabled())
802 return 0;
803
804 if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
805 return 0;
806
807 /* Add devices for each partition */
808 for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
809 if (part_get_info(desc, part, &info))
810 continue;
811 snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
812 part);
813
814 ret = device_bind_driver(blk_dev, "blk_partition",
815 strdup(devname), &dev);
816 if (ret)
817 return ret;
818
819 part_data = dev_get_uclass_plat(dev);
820 part_data->partnum = part;
821 part_data->gpt_part_info = info;
822 count++;
823
824 ret = device_probe(dev);
825 if (ret) {
826 debug("Can't probe\n");
827 count--;
828 device_unbind(dev);
829
830 continue;
831 }
832 }
833 debug("%s: %d partitions found in %s\n", __func__, count,
834 blk_dev->name);
835
836 return 0;
837}
838
Bin Mengcbc3da82018-10-15 02:21:07 -0700839static int blk_post_probe(struct udevice *dev)
840{
Simon Glassf5ac3032022-08-11 19:34:45 -0600841 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700842 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700843
Ovidiu Panait76160a02020-07-24 14:12:21 +0300844 part_init(desc);
AKASHI Takahiro358e6c72022-04-19 10:05:10 +0900845
846 if (desc->part_type != PART_TYPE_UNKNOWN &&
847 part_create_block_devices(dev))
848 debug("*** creating partitions failed\n");
Ovidiu Panait76160a02020-07-24 14:12:21 +0300849 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700850
851 return 0;
852}
853
Simon Glasscceee552016-02-29 15:25:55 -0700854UCLASS_DRIVER(blk) = {
855 .id = UCLASS_BLK,
856 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700857 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700858 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700859};