blob: 512c952f4d7af7becdda51a7dd4b86e1cc46abc5 [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" },
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
Bin Meng9efc2452023-09-26 16:43:41 +0800181int blk_get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
Simon Glass4131ad52016-05-01 11:36:08 -0600182{
183 bool found_more = false;
184 struct udevice *dev;
185 struct uclass *uc;
186 int ret;
187
188 *descp = NULL;
189 ret = uclass_get(UCLASS_BLK, &uc);
190 if (ret)
191 return ret;
192 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700193 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600194
Simon Glassfada3f92022-09-17 09:00:09 -0600195 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
196 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
197 if (desc->uclass_id == uclass_id) {
Simon Glass4131ad52016-05-01 11:36:08 -0600198 if (desc->devnum == devnum) {
199 ret = device_probe(dev);
200 if (ret)
201 return ret;
202
Michal Simekf438b6b2016-11-16 17:37:42 +0100203 *descp = desc;
204 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600205 } else if (desc->devnum > devnum) {
206 found_more = true;
207 }
208 }
209 }
210
211 return found_more ? -ENOENT : -ENODEV;
212}
213
Simon Glassfada3f92022-09-17 09:00:09 -0600214int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
Simon Glass13c2c292016-05-01 13:52:30 -0600215{
216 struct udevice *dev;
217 int ret;
218
Simon Glassfada3f92022-09-17 09:00:09 -0600219 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass13c2c292016-05-01 13:52:30 -0600220 if (ret)
221 return ret;
222
developerf50d8d12019-08-27 15:32:18 +0800223 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600224}
225
Simon Glassfada3f92022-09-17 09:00:09 -0600226int blk_list_part(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600227{
228 struct blk_desc *desc;
229 int devnum, ok;
230 int ret;
231
232 for (ok = 0, devnum = 0;; ++devnum) {
Bin Meng9efc2452023-09-26 16:43:41 +0800233 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600234 if (ret == -ENODEV)
235 break;
236 else if (ret)
237 continue;
238 if (desc->part_type != PART_TYPE_UNKNOWN) {
239 ++ok;
240 if (devnum)
241 putc('\n');
242 part_print(desc);
243 }
244 }
245 if (!ok)
246 return -ENODEV;
247
248 return 0;
249}
250
Simon Glassfada3f92022-09-17 09:00:09 -0600251int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600252{
253 struct blk_desc *desc;
254 int ret;
255
Bin Meng9efc2452023-09-26 16:43:41 +0800256 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600257 if (ret)
258 return ret;
259 if (desc->type == DEV_TYPE_UNKNOWN)
260 return -ENOENT;
261 part_print(desc);
262
263 return 0;
264}
265
Simon Glassfada3f92022-09-17 09:00:09 -0600266void blk_list_devices(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600267{
268 struct blk_desc *desc;
269 int ret;
270 int i;
271
272 for (i = 0;; ++i) {
Bin Meng9efc2452023-09-26 16:43:41 +0800273 ret = blk_get_desc(uclass_id, i, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600274 if (ret == -ENODEV)
275 break;
276 else if (ret)
277 continue;
278 if (desc->type == DEV_TYPE_UNKNOWN)
279 continue; /* list only known devices */
280 printf("Device %d: ", i);
281 dev_print(desc);
282 }
283}
284
Simon Glassfada3f92022-09-17 09:00:09 -0600285int blk_print_device_num(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600286{
287 struct blk_desc *desc;
288 int ret;
289
Bin Meng9efc2452023-09-26 16:43:41 +0800290 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600291 if (ret)
292 return ret;
293 printf("\nIDE device %d: ", devnum);
294 dev_print(desc);
295
296 return 0;
297}
298
Simon Glassfada3f92022-09-17 09:00:09 -0600299int blk_show_device(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600300{
301 struct blk_desc *desc;
302 int ret;
303
304 printf("\nDevice %d: ", devnum);
Bin Meng9efc2452023-09-26 16:43:41 +0800305 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600306 if (ret == -ENODEV || ret == -ENOENT) {
307 printf("unknown device\n");
308 return -ENODEV;
309 }
310 if (ret)
311 return ret;
312 dev_print(desc);
313
314 if (desc->type == DEV_TYPE_UNKNOWN)
315 return -ENOENT;
316
317 return 0;
318}
319
Simon Glass13c2c292016-05-01 13:52:30 -0600320int blk_select_hwpart(struct udevice *dev, int hwpart)
321{
322 const struct blk_ops *ops = blk_get_ops(dev);
323
324 if (!ops)
325 return -ENOSYS;
326 if (!ops->select_hwpart)
327 return 0;
328
329 return ops->select_hwpart(dev, hwpart);
330}
331
332int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
333{
developerf50d8d12019-08-27 15:32:18 +0800334 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600335}
336
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200337static int _blk_next_device(int uclass_id, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700338{
339 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200340 int ret = 0;
341
342 for (; *devp; uclass_find_next_device(devp)) {
343 desc = dev_get_uclass_plat(*devp);
344 if (desc->uclass_id == uclass_id) {
345 ret = device_probe(*devp);
346 if (!ret)
347 return 0;
348 }
349 }
Simon Glasscceee552016-02-29 15:25:55 -0700350
Simon Glasscceee552016-02-29 15:25:55 -0700351 if (ret)
352 return ret;
Simon Glasscceee552016-02-29 15:25:55 -0700353
354 return -ENODEV;
355}
356
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200357int blk_first_device(int uclass_id, struct udevice **devp)
358{
359 uclass_find_first_device(UCLASS_BLK, devp);
360
361 return _blk_next_device(uclass_id, devp);
362}
363
Simon Glasscceee552016-02-29 15:25:55 -0700364int blk_next_device(struct udevice **devp)
365{
366 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200367 int uclass_id;
Simon Glasscceee552016-02-29 15:25:55 -0700368
Simon Glass71fa5b42020-12-03 16:55:18 -0700369 desc = dev_get_uclass_plat(*devp);
Simon Glassfada3f92022-09-17 09:00:09 -0600370 uclass_id = desc->uclass_id;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200371 uclass_find_next_device(devp);
372
373 return _blk_next_device(uclass_id, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700374}
375
Simon Glassfada3f92022-09-17 09:00:09 -0600376int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700377{
378 struct uclass *uc;
379 struct udevice *dev;
380 int ret;
381
382 ret = uclass_get(UCLASS_BLK, &uc);
383 if (ret)
384 return ret;
385 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700386 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700387
Simon Glassfada3f92022-09-17 09:00:09 -0600388 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
389 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
390 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
Simon Glasscceee552016-02-29 15:25:55 -0700391 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600392 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700393 }
394 }
395
396 return -ENODEV;
397}
398
Simon Glassfada3f92022-09-17 09:00:09 -0600399int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glassd5d4c102017-04-23 20:02:05 -0600400{
401 int ret;
402
Simon Glassfada3f92022-09-17 09:00:09 -0600403 ret = blk_find_device(uclass_id, devnum, devp);
Simon Glassd5d4c102017-04-23 20:02:05 -0600404 if (ret)
405 return ret;
406
407 return device_probe(*devp);
408}
409
Marek Vasut847e24f2023-08-14 01:49:59 +0200410struct blk_bounce_buffer {
411 struct udevice *dev;
412 struct bounce_buffer state;
413};
414
415static int blk_buffer_aligned(struct bounce_buffer *state)
416{
417#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
418 struct blk_bounce_buffer *bbstate =
419 container_of(state, struct blk_bounce_buffer, state);
420 struct udevice *dev = bbstate->dev;
421 const struct blk_ops *ops = blk_get_ops(dev);
422
423 if (ops->buffer_aligned)
424 return ops->buffer_aligned(dev, state);
425#endif /* CONFIG_BOUNCE_BUFFER */
426
427 return 1; /* Default, any buffer is OK */
428}
429
Simon Glass18861002022-10-20 18:22:54 -0600430long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700431{
Simon Glass18861002022-10-20 18:22:54 -0600432 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700433 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700434 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700435
436 if (!ops->read)
437 return -ENOSYS;
438
Simon Glass18861002022-10-20 18:22:54 -0600439 if (blkcache_read(desc->uclass_id, desc->devnum,
440 start, blkcnt, desc->blksz, buf))
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700441 return blkcnt;
Marek Vasut847e24f2023-08-14 01:49:59 +0200442
Johan Jonker10a986c2023-10-18 16:01:10 +0200443 if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && desc->bb) {
Marek Vasut847e24f2023-08-14 01:49:59 +0200444 struct blk_bounce_buffer bbstate = { .dev = dev };
445 int ret;
446
447 ret = bounce_buffer_start_extalign(&bbstate.state, buf,
448 blkcnt * desc->blksz,
449 GEN_BB_WRITE, desc->blksz,
450 blk_buffer_aligned);
451 if (ret)
452 return ret;
453
454 blks_read = ops->read(dev, start, blkcnt, bbstate.state.bounce_buffer);
455
456 bounce_buffer_stop(&bbstate.state);
457 } else {
458 blks_read = ops->read(dev, start, blkcnt, buf);
459 }
460
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700461 if (blks_read == blkcnt)
Simon Glass18861002022-10-20 18:22:54 -0600462 blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
463 desc->blksz, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700464
465 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700466}
467
Simon Glass18861002022-10-20 18:22:54 -0600468long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
469 const 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);
Marek Vasut847e24f2023-08-14 01:49:59 +0200473 long blks_written;
Simon Glasscceee552016-02-29 15:25:55 -0700474
475 if (!ops->write)
476 return -ENOSYS;
477
Simon Glass18861002022-10-20 18:22:54 -0600478 blkcache_invalidate(desc->uclass_id, desc->devnum);
479
Johan Jonker10a986c2023-10-18 16:01:10 +0200480 if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && desc->bb) {
Marek Vasut847e24f2023-08-14 01:49:59 +0200481 struct blk_bounce_buffer bbstate = { .dev = dev };
482 int ret;
483
484 ret = bounce_buffer_start_extalign(&bbstate.state, (void *)buf,
485 blkcnt * desc->blksz,
486 GEN_BB_READ, desc->blksz,
487 blk_buffer_aligned);
488 if (ret)
489 return ret;
490
491 blks_written = ops->write(dev, start, blkcnt,
492 bbstate.state.bounce_buffer);
493
494 bounce_buffer_stop(&bbstate.state);
495 } else {
496 blks_written = ops->write(dev, start, blkcnt, buf);
497 }
498
499 return blks_written;
Simon Glasscceee552016-02-29 15:25:55 -0700500}
501
Simon Glass18861002022-10-20 18:22:54 -0600502long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
Simon Glasscceee552016-02-29 15:25:55 -0700503{
Simon Glass18861002022-10-20 18:22:54 -0600504 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700505 const struct blk_ops *ops = blk_get_ops(dev);
506
507 if (!ops->erase)
508 return -ENOSYS;
509
Simon Glass18861002022-10-20 18:22:54 -0600510 blkcache_invalidate(desc->uclass_id, desc->devnum);
511
Simon Glasscceee552016-02-29 15:25:55 -0700512 return ops->erase(dev, start, blkcnt);
513}
514
Simon Glass18861002022-10-20 18:22:54 -0600515ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
516 void *buffer)
517{
518 return blk_read(desc->bdev, start, blkcnt, buffer);
519}
520
521ulong blk_dwrite(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
522 const void *buffer)
523{
524 return blk_write(desc->bdev, start, blkcnt, buffer);
525}
526
527ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
528{
529 return blk_erase(desc->bdev, start, blkcnt);
530}
531
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600532int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
Simon Glass4f269132017-05-27 11:37:17 -0600533{
534 struct udevice *dev;
Simon Glass4f269132017-05-27 11:37:17 -0600535
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600536 if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) {
Simon Glass4f269132017-05-27 11:37:17 -0600537 debug("%s: No block device found for parent '%s'\n", __func__,
538 parent->name);
539 return -ENODEV;
540 }
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600541 *devp = dev;
542
543 return 0;
544}
545
546int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
547{
548 struct udevice *dev;
549 int ret;
550
551 ret = blk_find_from_parent(parent, &dev);
552 if (ret)
553 return ret;
Simon Glass4f269132017-05-27 11:37:17 -0600554 ret = device_probe(dev);
555 if (ret)
556 return ret;
557 *devp = dev;
558
559 return 0;
560}
561
Simon Glassf3086cf2022-04-24 23:31:03 -0600562const char *blk_get_devtype(struct udevice *dev)
563{
564 struct udevice *parent = dev_get_parent(dev);
565
566 return uclass_get_name(device_get_uclass_id(parent));
567};
568
Simon Glassfada3f92022-09-17 09:00:09 -0600569int blk_find_max_devnum(enum uclass_id uclass_id)
Simon Glassd089ba32016-05-01 11:36:28 -0600570{
571 struct udevice *dev;
572 int max_devnum = -ENODEV;
573 struct uclass *uc;
574 int ret;
575
576 ret = uclass_get(UCLASS_BLK, &uc);
577 if (ret)
578 return ret;
579 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700580 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600581
Simon Glassfada3f92022-09-17 09:00:09 -0600582 if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
Simon Glassd089ba32016-05-01 11:36:28 -0600583 max_devnum = desc->devnum;
584 }
585
586 return max_devnum;
587}
588
Simon Glassfada3f92022-09-17 09:00:09 -0600589int blk_next_free_devnum(enum uclass_id uclass_id)
Simon Glassdbc38612017-04-23 20:02:06 -0600590{
591 int ret;
592
Simon Glassfada3f92022-09-17 09:00:09 -0600593 ret = blk_find_max_devnum(uclass_id);
Simon Glassdbc38612017-04-23 20:02:06 -0600594 if (ret == -ENODEV)
595 return 0;
596 if (ret < 0)
597 return ret;
598
599 return ret + 1;
600}
601
Simon Glassfc7a7442021-07-05 16:32:59 -0600602static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
603{
604 const struct blk_desc *desc = dev_get_uclass_plat(dev);
605 enum blk_flag_t flags;
606
607 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
608
609 return flags & req_flags ? 0 : 1;
610}
611
Simon Glass8e61f932022-02-28 12:08:35 -0700612int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
613{
614 int ret;
615
616 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
617 *devp && !blk_flags_check(*devp, flags);
618 ret = uclass_find_next_device(devp))
619 return 0;
620
621 return -ENODEV;
622}
623
624int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
625{
626 int ret;
627
628 for (ret = uclass_find_next_device(devp);
629 *devp && !blk_flags_check(*devp, flags);
630 ret = uclass_find_next_device(devp))
631 return 0;
632
633 return -ENODEV;
634}
635
Simon Glassfc7a7442021-07-05 16:32:59 -0600636int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
637{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200638 for (uclass_first_device(UCLASS_BLK, devp);
639 *devp;
640 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600641 if (!blk_flags_check(*devp, flags))
642 return 0;
643 }
644
645 return -ENODEV;
646}
647
648int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
649{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200650 for (uclass_next_device(devp);
651 *devp;
652 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600653 if (!blk_flags_check(*devp, flags))
654 return 0;
655 }
656
657 return -ENODEV;
658}
659
660int blk_count_devices(enum blk_flag_t flag)
661{
662 struct udevice *dev;
663 int count = 0;
664
665 blk_foreach_probe(flag, dev)
666 count++;
667
668 return count;
669}
670
Simon Glassfada3f92022-09-17 09:00:09 -0600671static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
Simon Glasse4fef742017-04-23 20:02:07 -0600672{
673 struct udevice *dev;
674 struct uclass *uc;
675 int ret;
676
677 ret = uclass_get(UCLASS_BLK, &uc);
678 if (ret)
679 return ret;
680 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700681 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600682
Simon Glassfada3f92022-09-17 09:00:09 -0600683 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
684 int next = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600685
686 if (next < 0)
687 return next;
688 desc->devnum = next;
689 return 0;
690 }
691 }
692
693 return -ENOENT;
694}
695
Simon Glasscceee552016-02-29 15:25:55 -0700696int blk_create_device(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600697 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200698 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700699{
700 struct blk_desc *desc;
701 struct udevice *dev;
702 int ret;
703
Simon Glassd089ba32016-05-01 11:36:28 -0600704 if (devnum == -1) {
Simon Glassfada3f92022-09-17 09:00:09 -0600705 devnum = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600706 } else {
Simon Glassfada3f92022-09-17 09:00:09 -0600707 ret = blk_claim_devnum(uclass_id, devnum);
Simon Glasse4fef742017-04-23 20:02:07 -0600708 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600709 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600710 }
Simon Glasse4fef742017-04-23 20:02:07 -0600711 if (devnum < 0)
712 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600713 ret = device_bind_driver(parent, drv_name, name, &dev);
714 if (ret)
715 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700716 desc = dev_get_uclass_plat(dev);
Simon Glassfada3f92022-09-17 09:00:09 -0600717 desc->uclass_id = uclass_id;
Simon Glass77f7fb82016-05-01 13:52:22 -0600718 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200719 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200720 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600721 desc->part_type = PART_TYPE_UNKNOWN;
722 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700723 desc->devnum = devnum;
724 *devp = dev;
725
726 return 0;
727}
728
Simon Glass966b6952016-05-01 11:36:29 -0600729int blk_create_devicef(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600730 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200731 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600732{
733 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600734 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600735
736 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
737 str = strdup(dev_name);
738 if (!str)
739 return -ENOMEM;
740
Simon Glassfada3f92022-09-17 09:00:09 -0600741 ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200742 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600743 if (ret) {
744 free(str);
745 return ret;
746 }
747 device_set_name_alloced(*devp);
748
Simon Glass44505972017-07-29 11:34:59 -0600749 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600750}
751
AKASHI Takahiro3e32dbe2021-12-10 15:49:29 +0900752int blk_probe_or_unbind(struct udevice *dev)
753{
754 int ret;
755
756 ret = device_probe(dev);
757 if (ret) {
758 log_debug("probing %s failed\n", dev->name);
759 device_unbind(dev);
760 }
761
762 return ret;
763}
764
Simon Glassfada3f92022-09-17 09:00:09 -0600765int blk_unbind_all(int uclass_id)
Simon Glasscceee552016-02-29 15:25:55 -0700766{
767 struct uclass *uc;
768 struct udevice *dev, *next;
769 int ret;
770
771 ret = uclass_get(UCLASS_BLK, &uc);
772 if (ret)
773 return ret;
774 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700775 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700776
Simon Glassfada3f92022-09-17 09:00:09 -0600777 if (desc->uclass_id == uclass_id) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100778 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700779 if (ret)
780 return ret;
781 ret = device_unbind(dev);
782 if (ret)
783 return ret;
784 }
785 }
786
787 return 0;
788}
789
Marek Vasut14fafef2023-08-14 01:46:47 +0200790static int part_create_block_devices(struct udevice *blk_dev)
791{
792 int part, count;
793 struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
794 struct disk_partition info;
795 struct disk_part *part_data;
796 char devname[32];
797 struct udevice *dev;
798 int ret;
799
800 if (!CONFIG_IS_ENABLED(PARTITIONS) || !blk_enabled())
801 return 0;
802
803 if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
804 return 0;
805
806 /* Add devices for each partition */
807 for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
808 if (part_get_info(desc, part, &info))
809 continue;
810 snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
811 part);
812
813 ret = device_bind_driver(blk_dev, "blk_partition",
814 strdup(devname), &dev);
815 if (ret)
816 return ret;
817
818 part_data = dev_get_uclass_plat(dev);
819 part_data->partnum = part;
820 part_data->gpt_part_info = info;
821 count++;
822
823 ret = device_probe(dev);
824 if (ret) {
825 debug("Can't probe\n");
826 count--;
827 device_unbind(dev);
828
829 continue;
830 }
831 }
832 debug("%s: %d partitions found in %s\n", __func__, count,
833 blk_dev->name);
834
835 return 0;
836}
837
Bin Mengcbc3da82018-10-15 02:21:07 -0700838static int blk_post_probe(struct udevice *dev)
839{
Simon Glassf5ac3032022-08-11 19:34:45 -0600840 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700841 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700842
Ovidiu Panait76160a02020-07-24 14:12:21 +0300843 part_init(desc);
AKASHI Takahiro358e6c72022-04-19 10:05:10 +0900844
845 if (desc->part_type != PART_TYPE_UNKNOWN &&
846 part_create_block_devices(dev))
847 debug("*** creating partitions failed\n");
Ovidiu Panait76160a02020-07-24 14:12:21 +0300848 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700849
850 return 0;
851}
852
Simon Glasscceee552016-02-29 15:25:55 -0700853UCLASS_DRIVER(blk) = {
854 .id = UCLASS_BLK,
855 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700856 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700857 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700858};