blob: 885513893f6f4003d4c567900ec4273b02a7acac [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 <common.h>
10#include <blk.h>
11#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070013#include <malloc.h>
Simon Glass655306c2020-05-10 11:39:58 -060014#include <part.h>
Simon Glasscceee552016-02-29 15:25:55 -070015#include <dm/device-internal.h>
16#include <dm/lists.h>
Stefan Roeseef58a902017-11-29 16:46:42 +010017#include <dm/uclass-internal.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <linux/err.h>
Simon Glasscceee552016-02-29 15:25:55 -070019
Marek Vasutddfa0882023-08-14 01:46:48 +020020#define blk_get_ops(dev) ((struct blk_ops *)(dev)->driver->ops)
21
Simon Glass95e6e032022-08-11 19:34:57 -060022static struct {
23 enum uclass_id id;
24 const char *name;
Simon Glassfada3f92022-09-17 09:00:09 -060025} uclass_idname_str[] = {
Simon Glassdbfa32c2022-08-11 19:34:59 -060026 { UCLASS_IDE, "ide" },
27 { UCLASS_SCSI, "scsi" },
28 { UCLASS_USB, "usb" },
29 { UCLASS_MMC, "mmc" },
30 { UCLASS_AHCI, "sata" },
Simon Glasse57f8d42022-10-29 19:47:17 -060031 { UCLASS_HOST, "host" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060032 { UCLASS_NVME, "nvme" },
Abdellatif El Khlifi857360c2023-04-17 10:11:52 +010033 { UCLASS_NVMXIP, "nvmxip" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060034 { UCLASS_EFI_MEDIA, "efi" },
35 { UCLASS_EFI_LOADER, "efiloader" },
36 { UCLASS_VIRTIO, "virtio" },
37 { UCLASS_PVBLOCK, "pvblock" },
Tobias Waldekranz4f76dd32023-02-16 16:33:49 +010038 { UCLASS_BLKMAP, "blkmap" },
Simon Glass4131ad52016-05-01 11:36:08 -060039};
40
Simon Glassfada3f92022-09-17 09:00:09 -060041static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
Simon Glass4131ad52016-05-01 11:36:08 -060042{
43 int i;
44
Simon Glassfada3f92022-09-17 09:00:09 -060045 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
46 if (!strcmp(uclass_idname, uclass_idname_str[i].name))
47 return uclass_idname_str[i].id;
Simon Glass4131ad52016-05-01 11:36:08 -060048 }
49
Simon Glassdbfa32c2022-08-11 19:34:59 -060050 return UCLASS_INVALID;
Simon Glass4131ad52016-05-01 11:36:08 -060051}
52
Simon Glassfada3f92022-09-17 09:00:09 -060053static enum uclass_id conv_uclass_id(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -060054{
Simon Glassdbfa32c2022-08-11 19:34:59 -060055 /*
56 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
57 * for USB storage devices, so need to return this as the uclass to
58 * use for USB. In fact USB_UCLASS is for USB controllers, not
59 * peripherals.
60 *
61 * The name of the UCLASS_MASS_STORAGE uclass driver is
62 * "usb_mass_storage", but we want to use "usb" in things like the
63 * 'part list' command and when showing interfaces.
64 *
65 * So for now we have this one-way conversion.
66 *
67 * The fix for this is possibly to:
68 * - rename UCLASS_MASS_STORAGE name to "usb"
69 * - rename UCLASS_USB name to "usb_ctlr"
70 * - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
71 */
Simon Glassfada3f92022-09-17 09:00:09 -060072 if (uclass_id == UCLASS_USB)
Simon Glassdbfa32c2022-08-11 19:34:59 -060073 return UCLASS_MASS_STORAGE;
Simon Glassfada3f92022-09-17 09:00:09 -060074 return uclass_id;
Simon Glass4131ad52016-05-01 11:36:08 -060075}
76
Simon Glassfada3f92022-09-17 09:00:09 -060077const char *blk_get_uclass_name(enum uclass_id uclass_id)
Simon Glass85af5a42017-07-29 11:34:53 -060078{
Simon Glass95e6e032022-08-11 19:34:57 -060079 int i;
80
Simon Glassfada3f92022-09-17 09:00:09 -060081 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
82 if (uclass_idname_str[i].id == uclass_id)
83 return uclass_idname_str[i].name;
Simon Glass95e6e032022-08-11 19:34:57 -060084 }
85
86 return "(none)";
Simon Glass85af5a42017-07-29 11:34:53 -060087}
88
Simon Glassfada3f92022-09-17 09:00:09 -060089struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -060090{
91 struct blk_desc *desc;
92 struct udevice *dev;
93 int ret;
94
Simon Glassfada3f92022-09-17 09:00:09 -060095 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass4131ad52016-05-01 11:36:08 -060096 if (ret)
97 return NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -070098 desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -060099
100 return desc;
101}
102
103/*
104 * This function is complicated with driver model. We look up the interface
105 * name in a local table. This gives us an interface type which we can match
106 * against the uclass of the block device's parent.
107 */
Simon Glassfada3f92022-09-17 09:00:09 -0600108struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600109{
110 enum uclass_id uclass_id;
Simon Glass57b3d2e2022-08-11 19:35:01 -0600111 enum uclass_id type;
Simon Glass4131ad52016-05-01 11:36:08 -0600112 struct udevice *dev;
113 struct uclass *uc;
114 int ret;
115
Simon Glassfada3f92022-09-17 09:00:09 -0600116 type = uclass_name_to_iftype(uclass_idname);
Simon Glassdbfa32c2022-08-11 19:34:59 -0600117 if (type == UCLASS_INVALID) {
Simon Glass4131ad52016-05-01 11:36:08 -0600118 debug("%s: Unknown interface type '%s'\n", __func__,
Simon Glassfada3f92022-09-17 09:00:09 -0600119 uclass_idname);
Simon Glass4131ad52016-05-01 11:36:08 -0600120 return NULL;
121 }
Simon Glassfada3f92022-09-17 09:00:09 -0600122 uclass_id = conv_uclass_id(type);
Simon Glass4131ad52016-05-01 11:36:08 -0600123 if (uclass_id == UCLASS_INVALID) {
124 debug("%s: Unknown uclass for interface type'\n",
Simon Glassfada3f92022-09-17 09:00:09 -0600125 blk_get_uclass_name(type));
Simon Glass4131ad52016-05-01 11:36:08 -0600126 return NULL;
127 }
128
129 ret = uclass_get(UCLASS_BLK, &uc);
130 if (ret)
131 return NULL;
132 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700133 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600134
Simon Glassfada3f92022-09-17 09:00:09 -0600135 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
136 type, devnum, dev->name, desc->uclass_id, desc->devnum);
Simon Glass4131ad52016-05-01 11:36:08 -0600137 if (desc->devnum != devnum)
138 continue;
139
140 /* Find out the parent device uclass */
141 if (device_get_uclass_id(dev->parent) != uclass_id) {
142 debug("%s: parent uclass %d, this dev %d\n", __func__,
143 device_get_uclass_id(dev->parent), uclass_id);
144 continue;
145 }
146
147 if (device_probe(dev))
148 return NULL;
149
150 debug("%s: Device desc %p\n", __func__, desc);
151 return desc;
152 }
153 debug("%s: No device found\n", __func__);
154
155 return NULL;
156}
157
158/**
Tien Fong Chee10378522018-07-06 16:26:36 +0800159 * blk_get_by_device() - Get the block device descriptor for the given device
160 * @dev: Instance of a storage device
161 *
162 * Return: With block device descriptor on success , NULL if there is no such
163 * block device.
164 */
165struct blk_desc *blk_get_by_device(struct udevice *dev)
166{
Simon Glasscfd72932019-09-25 08:55:56 -0600167 struct udevice *child_dev;
Tien Fong Chee10378522018-07-06 16:26:36 +0800168
Simon Glasscfd72932019-09-25 08:55:56 -0600169 device_foreach_child(child_dev, dev) {
Tien Fong Chee10378522018-07-06 16:26:36 +0800170 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
171 continue;
172
Simon Glass71fa5b42020-12-03 16:55:18 -0700173 return dev_get_uclass_plat(child_dev);
Tien Fong Chee10378522018-07-06 16:26:36 +0800174 }
175
176 debug("%s: No block device found\n", __func__);
177
178 return NULL;
179}
180
181/**
Simon Glass4131ad52016-05-01 11:36:08 -0600182 * get_desc() - Get the block device descriptor for the given device number
183 *
Simon Glassfada3f92022-09-17 09:00:09 -0600184 * @uclass_id: Interface type
Simon Glass4131ad52016-05-01 11:36:08 -0600185 * @devnum: Device number (0 = first)
186 * @descp: Returns block device descriptor on success
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100187 * Return: 0 on success, -ENODEV if there is no such device and no device
Simon Glass4131ad52016-05-01 11:36:08 -0600188 * with a higher device number, -ENOENT if there is no such device but there
189 * is one with a higher number, or other -ve on other error.
190 */
Simon Glassfada3f92022-09-17 09:00:09 -0600191static int get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
Simon Glass4131ad52016-05-01 11:36:08 -0600192{
193 bool found_more = false;
194 struct udevice *dev;
195 struct uclass *uc;
196 int ret;
197
198 *descp = NULL;
199 ret = uclass_get(UCLASS_BLK, &uc);
200 if (ret)
201 return ret;
202 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700203 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600204
Simon Glassfada3f92022-09-17 09:00:09 -0600205 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
206 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
207 if (desc->uclass_id == uclass_id) {
Simon Glass4131ad52016-05-01 11:36:08 -0600208 if (desc->devnum == devnum) {
209 ret = device_probe(dev);
210 if (ret)
211 return ret;
212
Michal Simekf438b6b2016-11-16 17:37:42 +0100213 *descp = desc;
214 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600215 } else if (desc->devnum > devnum) {
216 found_more = true;
217 }
218 }
219 }
220
221 return found_more ? -ENOENT : -ENODEV;
222}
223
Simon Glassfada3f92022-09-17 09:00:09 -0600224int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
Simon Glass13c2c292016-05-01 13:52:30 -0600225{
226 struct udevice *dev;
227 int ret;
228
Simon Glassfada3f92022-09-17 09:00:09 -0600229 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass13c2c292016-05-01 13:52:30 -0600230 if (ret)
231 return ret;
232
developerf50d8d12019-08-27 15:32:18 +0800233 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600234}
235
Simon Glassfada3f92022-09-17 09:00:09 -0600236int blk_list_part(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600237{
238 struct blk_desc *desc;
239 int devnum, ok;
240 int ret;
241
242 for (ok = 0, devnum = 0;; ++devnum) {
Simon Glassfada3f92022-09-17 09:00:09 -0600243 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600244 if (ret == -ENODEV)
245 break;
246 else if (ret)
247 continue;
248 if (desc->part_type != PART_TYPE_UNKNOWN) {
249 ++ok;
250 if (devnum)
251 putc('\n');
252 part_print(desc);
253 }
254 }
255 if (!ok)
256 return -ENODEV;
257
258 return 0;
259}
260
Simon Glassfada3f92022-09-17 09:00:09 -0600261int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600262{
263 struct blk_desc *desc;
264 int ret;
265
Simon Glassfada3f92022-09-17 09:00:09 -0600266 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600267 if (ret)
268 return ret;
269 if (desc->type == DEV_TYPE_UNKNOWN)
270 return -ENOENT;
271 part_print(desc);
272
273 return 0;
274}
275
Simon Glassfada3f92022-09-17 09:00:09 -0600276void blk_list_devices(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600277{
278 struct blk_desc *desc;
279 int ret;
280 int i;
281
282 for (i = 0;; ++i) {
Simon Glassfada3f92022-09-17 09:00:09 -0600283 ret = get_desc(uclass_id, i, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600284 if (ret == -ENODEV)
285 break;
286 else if (ret)
287 continue;
288 if (desc->type == DEV_TYPE_UNKNOWN)
289 continue; /* list only known devices */
290 printf("Device %d: ", i);
291 dev_print(desc);
292 }
293}
294
Simon Glassfada3f92022-09-17 09:00:09 -0600295int blk_print_device_num(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600296{
297 struct blk_desc *desc;
298 int ret;
299
Simon Glassfada3f92022-09-17 09:00:09 -0600300 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600301 if (ret)
302 return ret;
303 printf("\nIDE device %d: ", devnum);
304 dev_print(desc);
305
306 return 0;
307}
308
Simon Glassfada3f92022-09-17 09:00:09 -0600309int blk_show_device(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600310{
311 struct blk_desc *desc;
312 int ret;
313
314 printf("\nDevice %d: ", devnum);
Simon Glassfada3f92022-09-17 09:00:09 -0600315 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600316 if (ret == -ENODEV || ret == -ENOENT) {
317 printf("unknown device\n");
318 return -ENODEV;
319 }
320 if (ret)
321 return ret;
322 dev_print(desc);
323
324 if (desc->type == DEV_TYPE_UNKNOWN)
325 return -ENOENT;
326
327 return 0;
328}
329
Simon Glassfada3f92022-09-17 09:00:09 -0600330ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600331 lbaint_t blkcnt, void *buffer)
332{
333 struct blk_desc *desc;
334 ulong n;
335 int ret;
336
Simon Glassfada3f92022-09-17 09:00:09 -0600337 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600338 if (ret)
339 return ret;
340 n = blk_dread(desc, start, blkcnt, buffer);
341 if (IS_ERR_VALUE(n))
342 return n;
343
Simon Glass4131ad52016-05-01 11:36:08 -0600344 return n;
345}
346
Simon Glassfada3f92022-09-17 09:00:09 -0600347ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600348 lbaint_t blkcnt, const void *buffer)
349{
350 struct blk_desc *desc;
351 int ret;
352
Simon Glassfada3f92022-09-17 09:00:09 -0600353 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600354 if (ret)
355 return ret;
356 return blk_dwrite(desc, start, blkcnt, buffer);
357}
358
Simon Glass13c2c292016-05-01 13:52:30 -0600359int blk_select_hwpart(struct udevice *dev, int hwpart)
360{
361 const struct blk_ops *ops = blk_get_ops(dev);
362
363 if (!ops)
364 return -ENOSYS;
365 if (!ops->select_hwpart)
366 return 0;
367
368 return ops->select_hwpart(dev, hwpart);
369}
370
371int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
372{
developerf50d8d12019-08-27 15:32:18 +0800373 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600374}
375
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200376static int _blk_next_device(int uclass_id, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700377{
378 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200379 int ret = 0;
380
381 for (; *devp; uclass_find_next_device(devp)) {
382 desc = dev_get_uclass_plat(*devp);
383 if (desc->uclass_id == uclass_id) {
384 ret = device_probe(*devp);
385 if (!ret)
386 return 0;
387 }
388 }
Simon Glasscceee552016-02-29 15:25:55 -0700389
Simon Glasscceee552016-02-29 15:25:55 -0700390 if (ret)
391 return ret;
Simon Glasscceee552016-02-29 15:25:55 -0700392
393 return -ENODEV;
394}
395
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200396int blk_first_device(int uclass_id, struct udevice **devp)
397{
398 uclass_find_first_device(UCLASS_BLK, devp);
399
400 return _blk_next_device(uclass_id, devp);
401}
402
Simon Glasscceee552016-02-29 15:25:55 -0700403int blk_next_device(struct udevice **devp)
404{
405 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200406 int uclass_id;
Simon Glasscceee552016-02-29 15:25:55 -0700407
Simon Glass71fa5b42020-12-03 16:55:18 -0700408 desc = dev_get_uclass_plat(*devp);
Simon Glassfada3f92022-09-17 09:00:09 -0600409 uclass_id = desc->uclass_id;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200410 uclass_find_next_device(devp);
411
412 return _blk_next_device(uclass_id, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700413}
414
Simon Glassfada3f92022-09-17 09:00:09 -0600415int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700416{
417 struct uclass *uc;
418 struct udevice *dev;
419 int ret;
420
421 ret = uclass_get(UCLASS_BLK, &uc);
422 if (ret)
423 return ret;
424 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700425 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700426
Simon Glassfada3f92022-09-17 09:00:09 -0600427 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
428 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
429 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
Simon Glasscceee552016-02-29 15:25:55 -0700430 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600431 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700432 }
433 }
434
435 return -ENODEV;
436}
437
Simon Glassfada3f92022-09-17 09:00:09 -0600438int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glassd5d4c102017-04-23 20:02:05 -0600439{
440 int ret;
441
Simon Glassfada3f92022-09-17 09:00:09 -0600442 ret = blk_find_device(uclass_id, devnum, devp);
Simon Glassd5d4c102017-04-23 20:02:05 -0600443 if (ret)
444 return ret;
445
446 return device_probe(*devp);
447}
448
Marek Vasut847e24f2023-08-14 01:49:59 +0200449struct blk_bounce_buffer {
450 struct udevice *dev;
451 struct bounce_buffer state;
452};
453
454static int blk_buffer_aligned(struct bounce_buffer *state)
455{
456#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
457 struct blk_bounce_buffer *bbstate =
458 container_of(state, struct blk_bounce_buffer, state);
459 struct udevice *dev = bbstate->dev;
460 const struct blk_ops *ops = blk_get_ops(dev);
461
462 if (ops->buffer_aligned)
463 return ops->buffer_aligned(dev, state);
464#endif /* CONFIG_BOUNCE_BUFFER */
465
466 return 1; /* Default, any buffer is OK */
467}
468
Simon Glass18861002022-10-20 18:22:54 -0600469long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700470{
Simon Glass18861002022-10-20 18:22:54 -0600471 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700472 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700473 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700474
475 if (!ops->read)
476 return -ENOSYS;
477
Simon Glass18861002022-10-20 18:22:54 -0600478 if (blkcache_read(desc->uclass_id, desc->devnum,
479 start, blkcnt, desc->blksz, buf))
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700480 return blkcnt;
Marek Vasut847e24f2023-08-14 01:49:59 +0200481
482 if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
483 struct blk_bounce_buffer bbstate = { .dev = dev };
484 int ret;
485
486 ret = bounce_buffer_start_extalign(&bbstate.state, buf,
487 blkcnt * desc->blksz,
488 GEN_BB_WRITE, desc->blksz,
489 blk_buffer_aligned);
490 if (ret)
491 return ret;
492
493 blks_read = ops->read(dev, start, blkcnt, bbstate.state.bounce_buffer);
494
495 bounce_buffer_stop(&bbstate.state);
496 } else {
497 blks_read = ops->read(dev, start, blkcnt, buf);
498 }
499
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700500 if (blks_read == blkcnt)
Simon Glass18861002022-10-20 18:22:54 -0600501 blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
502 desc->blksz, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700503
504 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700505}
506
Simon Glass18861002022-10-20 18:22:54 -0600507long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
508 const void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700509{
Simon Glass18861002022-10-20 18:22:54 -0600510 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700511 const struct blk_ops *ops = blk_get_ops(dev);
Marek Vasut847e24f2023-08-14 01:49:59 +0200512 long blks_written;
Simon Glasscceee552016-02-29 15:25:55 -0700513
514 if (!ops->write)
515 return -ENOSYS;
516
Simon Glass18861002022-10-20 18:22:54 -0600517 blkcache_invalidate(desc->uclass_id, desc->devnum);
518
Marek Vasut847e24f2023-08-14 01:49:59 +0200519 if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
520 struct blk_bounce_buffer bbstate = { .dev = dev };
521 int ret;
522
523 ret = bounce_buffer_start_extalign(&bbstate.state, (void *)buf,
524 blkcnt * desc->blksz,
525 GEN_BB_READ, desc->blksz,
526 blk_buffer_aligned);
527 if (ret)
528 return ret;
529
530 blks_written = ops->write(dev, start, blkcnt,
531 bbstate.state.bounce_buffer);
532
533 bounce_buffer_stop(&bbstate.state);
534 } else {
535 blks_written = ops->write(dev, start, blkcnt, buf);
536 }
537
538 return blks_written;
Simon Glasscceee552016-02-29 15:25:55 -0700539}
540
Simon Glass18861002022-10-20 18:22:54 -0600541long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
Simon Glasscceee552016-02-29 15:25:55 -0700542{
Simon Glass18861002022-10-20 18:22:54 -0600543 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700544 const struct blk_ops *ops = blk_get_ops(dev);
545
546 if (!ops->erase)
547 return -ENOSYS;
548
Simon Glass18861002022-10-20 18:22:54 -0600549 blkcache_invalidate(desc->uclass_id, desc->devnum);
550
Simon Glasscceee552016-02-29 15:25:55 -0700551 return ops->erase(dev, start, blkcnt);
552}
553
Simon Glass18861002022-10-20 18:22:54 -0600554ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
555 void *buffer)
556{
557 return blk_read(desc->bdev, start, blkcnt, buffer);
558}
559
560ulong blk_dwrite(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
561 const void *buffer)
562{
563 return blk_write(desc->bdev, start, blkcnt, buffer);
564}
565
566ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
567{
568 return blk_erase(desc->bdev, start, blkcnt);
569}
570
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600571int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
Simon Glass4f269132017-05-27 11:37:17 -0600572{
573 struct udevice *dev;
Simon Glass4f269132017-05-27 11:37:17 -0600574
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600575 if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) {
Simon Glass4f269132017-05-27 11:37:17 -0600576 debug("%s: No block device found for parent '%s'\n", __func__,
577 parent->name);
578 return -ENODEV;
579 }
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600580 *devp = dev;
581
582 return 0;
583}
584
585int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
586{
587 struct udevice *dev;
588 int ret;
589
590 ret = blk_find_from_parent(parent, &dev);
591 if (ret)
592 return ret;
Simon Glass4f269132017-05-27 11:37:17 -0600593 ret = device_probe(dev);
594 if (ret)
595 return ret;
596 *devp = dev;
597
598 return 0;
599}
600
Simon Glassf3086cf2022-04-24 23:31:03 -0600601const char *blk_get_devtype(struct udevice *dev)
602{
603 struct udevice *parent = dev_get_parent(dev);
604
605 return uclass_get_name(device_get_uclass_id(parent));
606};
607
Simon Glassfada3f92022-09-17 09:00:09 -0600608int blk_find_max_devnum(enum uclass_id uclass_id)
Simon Glassd089ba32016-05-01 11:36:28 -0600609{
610 struct udevice *dev;
611 int max_devnum = -ENODEV;
612 struct uclass *uc;
613 int ret;
614
615 ret = uclass_get(UCLASS_BLK, &uc);
616 if (ret)
617 return ret;
618 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700619 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600620
Simon Glassfada3f92022-09-17 09:00:09 -0600621 if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
Simon Glassd089ba32016-05-01 11:36:28 -0600622 max_devnum = desc->devnum;
623 }
624
625 return max_devnum;
626}
627
Simon Glassfada3f92022-09-17 09:00:09 -0600628int blk_next_free_devnum(enum uclass_id uclass_id)
Simon Glassdbc38612017-04-23 20:02:06 -0600629{
630 int ret;
631
Simon Glassfada3f92022-09-17 09:00:09 -0600632 ret = blk_find_max_devnum(uclass_id);
Simon Glassdbc38612017-04-23 20:02:06 -0600633 if (ret == -ENODEV)
634 return 0;
635 if (ret < 0)
636 return ret;
637
638 return ret + 1;
639}
640
Simon Glassfc7a7442021-07-05 16:32:59 -0600641static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
642{
643 const struct blk_desc *desc = dev_get_uclass_plat(dev);
644 enum blk_flag_t flags;
645
646 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
647
648 return flags & req_flags ? 0 : 1;
649}
650
Simon Glass8e61f932022-02-28 12:08:35 -0700651int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
652{
653 int ret;
654
655 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
656 *devp && !blk_flags_check(*devp, flags);
657 ret = uclass_find_next_device(devp))
658 return 0;
659
660 return -ENODEV;
661}
662
663int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
664{
665 int ret;
666
667 for (ret = uclass_find_next_device(devp);
668 *devp && !blk_flags_check(*devp, flags);
669 ret = uclass_find_next_device(devp))
670 return 0;
671
672 return -ENODEV;
673}
674
Simon Glassfc7a7442021-07-05 16:32:59 -0600675int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
676{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200677 for (uclass_first_device(UCLASS_BLK, devp);
678 *devp;
679 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600680 if (!blk_flags_check(*devp, flags))
681 return 0;
682 }
683
684 return -ENODEV;
685}
686
687int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
688{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200689 for (uclass_next_device(devp);
690 *devp;
691 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600692 if (!blk_flags_check(*devp, flags))
693 return 0;
694 }
695
696 return -ENODEV;
697}
698
699int blk_count_devices(enum blk_flag_t flag)
700{
701 struct udevice *dev;
702 int count = 0;
703
704 blk_foreach_probe(flag, dev)
705 count++;
706
707 return count;
708}
709
Simon Glassfada3f92022-09-17 09:00:09 -0600710static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
Simon Glasse4fef742017-04-23 20:02:07 -0600711{
712 struct udevice *dev;
713 struct uclass *uc;
714 int ret;
715
716 ret = uclass_get(UCLASS_BLK, &uc);
717 if (ret)
718 return ret;
719 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700720 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600721
Simon Glassfada3f92022-09-17 09:00:09 -0600722 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
723 int next = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600724
725 if (next < 0)
726 return next;
727 desc->devnum = next;
728 return 0;
729 }
730 }
731
732 return -ENOENT;
733}
734
Simon Glasscceee552016-02-29 15:25:55 -0700735int blk_create_device(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600736 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200737 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700738{
739 struct blk_desc *desc;
740 struct udevice *dev;
741 int ret;
742
Simon Glassd089ba32016-05-01 11:36:28 -0600743 if (devnum == -1) {
Simon Glassfada3f92022-09-17 09:00:09 -0600744 devnum = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600745 } else {
Simon Glassfada3f92022-09-17 09:00:09 -0600746 ret = blk_claim_devnum(uclass_id, devnum);
Simon Glasse4fef742017-04-23 20:02:07 -0600747 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600748 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600749 }
Simon Glasse4fef742017-04-23 20:02:07 -0600750 if (devnum < 0)
751 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600752 ret = device_bind_driver(parent, drv_name, name, &dev);
753 if (ret)
754 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700755 desc = dev_get_uclass_plat(dev);
Simon Glassfada3f92022-09-17 09:00:09 -0600756 desc->uclass_id = uclass_id;
Simon Glass77f7fb82016-05-01 13:52:22 -0600757 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200758 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200759 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600760 desc->part_type = PART_TYPE_UNKNOWN;
761 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700762 desc->devnum = devnum;
763 *devp = dev;
764
765 return 0;
766}
767
Simon Glass966b6952016-05-01 11:36:29 -0600768int blk_create_devicef(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600769 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200770 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600771{
772 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600773 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600774
775 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
776 str = strdup(dev_name);
777 if (!str)
778 return -ENOMEM;
779
Simon Glassfada3f92022-09-17 09:00:09 -0600780 ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200781 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600782 if (ret) {
783 free(str);
784 return ret;
785 }
786 device_set_name_alloced(*devp);
787
Simon Glass44505972017-07-29 11:34:59 -0600788 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600789}
790
AKASHI Takahiro3e32dbe2021-12-10 15:49:29 +0900791int blk_probe_or_unbind(struct udevice *dev)
792{
793 int ret;
794
795 ret = device_probe(dev);
796 if (ret) {
797 log_debug("probing %s failed\n", dev->name);
798 device_unbind(dev);
799 }
800
801 return ret;
802}
803
Simon Glassfada3f92022-09-17 09:00:09 -0600804int blk_unbind_all(int uclass_id)
Simon Glasscceee552016-02-29 15:25:55 -0700805{
806 struct uclass *uc;
807 struct udevice *dev, *next;
808 int ret;
809
810 ret = uclass_get(UCLASS_BLK, &uc);
811 if (ret)
812 return ret;
813 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700814 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700815
Simon Glassfada3f92022-09-17 09:00:09 -0600816 if (desc->uclass_id == uclass_id) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100817 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700818 if (ret)
819 return ret;
820 ret = device_unbind(dev);
821 if (ret)
822 return ret;
823 }
824 }
825
826 return 0;
827}
828
Marek Vasut14fafef2023-08-14 01:46:47 +0200829static int part_create_block_devices(struct udevice *blk_dev)
830{
831 int part, count;
832 struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
833 struct disk_partition info;
834 struct disk_part *part_data;
835 char devname[32];
836 struct udevice *dev;
837 int ret;
838
839 if (!CONFIG_IS_ENABLED(PARTITIONS) || !blk_enabled())
840 return 0;
841
842 if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
843 return 0;
844
845 /* Add devices for each partition */
846 for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
847 if (part_get_info(desc, part, &info))
848 continue;
849 snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
850 part);
851
852 ret = device_bind_driver(blk_dev, "blk_partition",
853 strdup(devname), &dev);
854 if (ret)
855 return ret;
856
857 part_data = dev_get_uclass_plat(dev);
858 part_data->partnum = part;
859 part_data->gpt_part_info = info;
860 count++;
861
862 ret = device_probe(dev);
863 if (ret) {
864 debug("Can't probe\n");
865 count--;
866 device_unbind(dev);
867
868 continue;
869 }
870 }
871 debug("%s: %d partitions found in %s\n", __func__, count,
872 blk_dev->name);
873
874 return 0;
875}
876
Bin Mengcbc3da82018-10-15 02:21:07 -0700877static int blk_post_probe(struct udevice *dev)
878{
Simon Glassf5ac3032022-08-11 19:34:45 -0600879 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700880 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700881
Ovidiu Panait76160a02020-07-24 14:12:21 +0300882 part_init(desc);
AKASHI Takahiro358e6c72022-04-19 10:05:10 +0900883
884 if (desc->part_type != PART_TYPE_UNKNOWN &&
885 part_create_block_devices(dev))
886 debug("*** creating partitions failed\n");
Ovidiu Panait76160a02020-07-24 14:12:21 +0300887 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700888
889 return 0;
890}
891
Simon Glasscceee552016-02-29 15:25:55 -0700892UCLASS_DRIVER(blk) = {
893 .id = UCLASS_BLK,
894 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700895 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700896 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700897};