]>
Commit | Line | Data |
---|---|---|
201417d7 SG |
1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
2 | /* | |
3 | * Copyright 2021 Google LLC | |
4 | * Written by Simon Glass <[email protected]> | |
5 | */ | |
6 | ||
7 | #ifndef __bootdev_h | |
8 | #define __bootdev_h | |
9 | ||
e62714ca | 10 | #include <dm/uclass-id.h> |
201417d7 SG |
11 | #include <linux/list.h> |
12 | ||
13 | struct bootflow; | |
14 | struct bootflow_iter; | |
bd90b092 | 15 | struct bootstd_priv; |
201417d7 SG |
16 | struct udevice; |
17 | ||
18 | /** | |
19 | * enum bootdev_prio_t - priority of each bootdev | |
20 | * | |
21 | * These values are associated with each bootdev and set up by the driver. | |
22 | * | |
23 | * Smallest value is the highest priority. By default, bootdevs are scanned from | |
24 | * highest to lowest priority | |
eacc2611 SG |
25 | * |
26 | * BOOTDEVP_0_NONE: Invalid value, do not use | |
27 | * @BOOTDEVP_6_PRE_SCAN: Scan bootdevs with this priority always, before | |
28 | * starting any bootflow scan | |
29 | * @BOOTDEVP_2_INTERNAL_FAST: Internal devices which don't need scanning and | |
30 | * generally very quick to access, e.g. less than 100ms | |
31 | * @BOOTDEVP_3_INTERNAL_SLOW: Internal devices which don't need scanning but | |
32 | * take a significant fraction of a second to access | |
33 | * @BOOTDEVP_4_SCAN_FAST: Extenal devices which need scanning or bus | |
34 | * enumeration to find, but this enumeration happens quickly, typically under | |
35 | * 100ms | |
36 | * @BOOTDEVP_5_SCAN_SLOW: Extenal devices which need scanning or bus | |
37 | * enumeration to find. The enumeration takes significant fraction of a second | |
38 | * to complete | |
39 | * @BOOTDEVP_6_NET_BASE: Basic network devices which are quickly and easily | |
40 | * available. Typically used for an internal Ethernet device | |
41 | * @BOOTDEVP_7_NET_FALLBACK: Secondary network devices which require extra time | |
42 | * to start up, or are less desirable. Typically used for secondary Ethernet | |
43 | * devices. Note that USB ethernet devices are found during USB enumeration, | |
44 | * so do not use this priority | |
201417d7 SG |
45 | */ |
46 | enum bootdev_prio_t { | |
eacc2611 SG |
47 | BOOTDEVP_0_NONE, |
48 | BOOTDEVP_1_PRE_SCAN, | |
49 | BOOTDEVP_2_INTERNAL_FAST, | |
50 | BOOTDEVP_3_INTERNAL_SLOW, | |
51 | BOOTDEVP_4_SCAN_FAST, | |
52 | BOOTDEVP_5_SCAN_SLOW, | |
53 | BOOTDEVP_6_NET_BASE, | |
54 | BOOTDEVP_7_NET_FALLBACK, | |
201417d7 SG |
55 | |
56 | BOOTDEVP_COUNT, | |
57 | }; | |
58 | ||
bd90b092 SG |
59 | struct bootdev_hunter; |
60 | ||
61 | /** | |
62 | * bootdev_hunter_func - function to probe for bootdevs of a given type | |
63 | * | |
64 | * This should hunt around for bootdevs of the given type, binding them as it | |
65 | * finds them. This may involve bus enumeration, etc. | |
66 | * | |
67 | * @info: Info structure describing this hunter | |
68 | * @show: true to show information from the hunter | |
ee2ce292 | 69 | * Returns: 0 if OK, -ENOENT on device not found, otherwise -ve on error |
bd90b092 SG |
70 | */ |
71 | typedef int (*bootdev_hunter_func)(struct bootdev_hunter *info, bool show); | |
72 | ||
73 | /** | |
74 | * struct bootdev_hunter - information about how to hunt for bootdevs | |
75 | * | |
76 | * @prio: Scanning priority of this hunter | |
77 | * @uclass: Uclass ID for the media associated with this bootdev | |
78 | * @drv: bootdev driver for the things found by this hunter | |
79 | * @hunt: Function to call to hunt for bootdevs of this type (NULL if none) | |
80 | * | |
81 | * Some bootdevs are not visible until other devices are enumerated. For | |
82 | * example, USB bootdevs only appear when the USB bus is enumerated. | |
83 | * | |
84 | * On the other hand, we don't always want to enumerate all the buses just to | |
85 | * find the first valid bootdev. Ideally we want to work through them in | |
86 | * priority order, so that the fastest bootdevs are discovered first. | |
87 | * | |
88 | * This struct holds information about the bootdev so we can determine the probe | |
89 | * order and how to hunt for bootdevs of this type | |
90 | */ | |
91 | struct bootdev_hunter { | |
92 | enum bootdev_prio_t prio; | |
93 | enum uclass_id uclass; | |
94 | struct driver *drv; | |
95 | bootdev_hunter_func hunt; | |
96 | }; | |
97 | ||
98 | /* declare a new bootdev hunter */ | |
99 | #define BOOTDEV_HUNTER(__name) \ | |
100 | ll_entry_declare(struct bootdev_hunter, __name, bootdev_hunter) | |
101 | ||
102 | /* access a bootdev hunter by name */ | |
103 | #define BOOTDEV_HUNTER_GET(__name) \ | |
104 | ll_entry_get(struct bootdev_hunter, __name, bootdev_hunter) | |
105 | ||
201417d7 SG |
106 | /** |
107 | * struct bootdev_uc_plat - uclass information about a bootdev | |
108 | * | |
109 | * This is attached to each device in the bootdev uclass and accessible via | |
110 | * dev_get_uclass_plat(dev) | |
111 | * | |
112 | * @bootflows: List of available bootflows for this bootdev | |
113 | * @piro: Priority of this bootdev | |
114 | */ | |
115 | struct bootdev_uc_plat { | |
116 | struct list_head bootflow_head; | |
117 | enum bootdev_prio_t prio; | |
118 | }; | |
119 | ||
120 | /** struct bootdev_ops - Operations for the bootdev uclass */ | |
121 | struct bootdev_ops { | |
122 | /** | |
b85fc8db SG |
123 | * get_bootflow() - get a bootflow (optional) |
124 | * | |
125 | * If this is NULL then the default implementaton is used, which is | |
126 | * default_get_bootflow() | |
201417d7 SG |
127 | * |
128 | * @dev: Bootflow device to check | |
129 | * @iter: Provides current dev, part, method to get. Should update | |
130 | * max_part if there is a partition table. Should update state, | |
131 | * subdir, fname, buf, size according to progress | |
132 | * @bflow: Updated bootflow if found | |
133 | * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this | |
134 | * device, -ENOSYS if this device doesn't support bootflows, | |
135 | * other -ve value on other error | |
136 | */ | |
137 | int (*get_bootflow)(struct udevice *dev, struct bootflow_iter *iter, | |
138 | struct bootflow *bflow); | |
139 | }; | |
140 | ||
141 | #define bootdev_get_ops(dev) ((struct bootdev_ops *)(dev)->driver->ops) | |
142 | ||
143 | /** | |
144 | * bootdev_get_bootflow() - get a bootflow | |
145 | * | |
146 | * @dev: Bootflow device to check | |
147 | * @iter: Provides current part, method to get | |
148 | * @bflow: Returns bootflow if found | |
149 | * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this device, | |
150 | * -ENOSYS if this device doesn't support bootflows, other -ve value on | |
151 | * other error | |
152 | */ | |
153 | int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, | |
154 | struct bootflow *bflow); | |
155 | ||
156 | /** | |
157 | * bootdev_bind() - Bind a new named bootdev device | |
158 | * | |
159 | * @parent: Parent of the new device | |
160 | * @drv_name: Driver name to use for the bootdev device | |
161 | * @name: Name for the device (parent name is prepended) | |
162 | * @devp: the new device (which has not been probed) | |
163 | */ | |
164 | int bootdev_bind(struct udevice *parent, const char *drv_name, const char *name, | |
165 | struct udevice **devp); | |
166 | ||
167 | /** | |
168 | * bootdev_find_in_blk() - Find a bootdev in a block device | |
169 | * | |
170 | * @dev: Bootflow device associated with this block device | |
171 | * @blk: Block device to search | |
172 | * @iter: Provides current dev, part, method to get. Should update | |
173 | * max_part if there is a partition table | |
174 | * @bflow: On entry, provides information about the partition and device to | |
175 | * check. On exit, returns bootflow if found | |
176 | * Return: 0 if found, -ESHUTDOWN if no more bootflows, other -ve on error | |
177 | */ | |
178 | int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, | |
179 | struct bootflow_iter *iter, struct bootflow *bflow); | |
180 | ||
181 | /** | |
182 | * bootdev_list() - List all available bootdevs | |
183 | * | |
184 | * @probe: true to probe devices, false to leave them as is | |
185 | */ | |
186 | void bootdev_list(bool probe); | |
187 | ||
188 | /** | |
189 | * bootdev_clear_bootflows() - Clear bootflows from a bootdev | |
190 | * | |
191 | * Each bootdev maintains a list of discovered bootflows. This provides a | |
192 | * way to clear it. These bootflows are removed from the global list too. | |
193 | * | |
194 | * @dev: bootdev device to update | |
195 | */ | |
196 | void bootdev_clear_bootflows(struct udevice *dev); | |
197 | ||
198 | /** | |
199 | * bootdev_add_bootflow() - Add a bootflow to the bootdev's list | |
200 | * | |
201 | * All fields in @bflow must be set up. Note that @bflow->dev is used to add the | |
202 | * bootflow to that device. | |
203 | * | |
4de979f6 | 204 | * @dev: Bootdev device to add to |
201417d7 SG |
205 | * @bflow: Bootflow to add. Note that fields within bflow must be allocated |
206 | * since this function takes over ownership of these. This functions makes | |
207 | * a copy of @bflow itself (without allocating its fields again), so the | |
208 | * caller must dispose of the memory used by the @bflow pointer itself | |
209 | * Return: 0 if OK, -ENOMEM if out of memory | |
210 | */ | |
211 | int bootdev_add_bootflow(struct bootflow *bflow); | |
212 | ||
213 | /** | |
214 | * bootdev_first_bootflow() - Get the first bootflow from a bootdev | |
215 | * | |
216 | * Returns the first bootflow attached to a bootdev | |
217 | * | |
218 | * @dev: bootdev device | |
219 | * @bflowp: Returns a pointer to the bootflow | |
220 | * Return: 0 if found, -ENOENT if there are no bootflows | |
221 | */ | |
222 | int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp); | |
223 | ||
224 | /** | |
225 | * bootdev_next_bootflow() - Get the next bootflow from a bootdev | |
226 | * | |
227 | * Returns the next bootflow attached to a bootdev | |
228 | * | |
229 | * @bflowp: On entry, the last bootflow returned , e.g. from | |
230 | * bootdev_first_bootflow() | |
231 | * Return: 0 if found, -ENOENT if there are no more bootflows | |
232 | */ | |
233 | int bootdev_next_bootflow(struct bootflow **bflowp); | |
234 | ||
235 | /** | |
236 | * bootdev_find_by_label() - Look up a bootdev by label | |
237 | * | |
238 | * Each bootdev has a label which contains the media-uclass name and a number, | |
239 | * e.g. 'mmc2'. This looks up the label and returns the associated bootdev | |
240 | * | |
241 | * The lookup is performed based on the media device's sequence number. So for | |
242 | * 'mmc2' this looks for a device in UCLASS_MMC with a dev_seq() of 2. | |
243 | * | |
244 | * @label: Label to look up (e.g. "mmc1" or "mmc0") | |
245 | * @devp: Returns the bootdev device found, or NULL if none (note it does not | |
246 | * return the media device, but its bootdev child) | |
d9f48579 SG |
247 | * @method_flagsp: If non-NULL, returns any flags implied by the label |
248 | * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails | |
201417d7 | 249 | * Return: 0 if OK, -EINVAL if the uclass is not supported by this board, |
d9f48579 | 250 | * -ENOENT if there is no device with that number |
201417d7 | 251 | */ |
d9f48579 SG |
252 | int bootdev_find_by_label(const char *label, struct udevice **devp, |
253 | int *method_flagsp); | |
201417d7 SG |
254 | |
255 | /** | |
256 | * bootdev_find_by_any() - Find a bootdev by name, label or sequence | |
257 | * | |
258 | * @name: name (e.g. "mmc2.bootdev"), label ("mmc2"), or sequence ("2") to find | |
259 | * @devp: returns the device found, on success | |
d9f48579 SG |
260 | * @method_flagsp: If non-NULL, returns any flags implied by the label |
261 | * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails | |
1736b4af | 262 | * Return: 0 if OK, -EPFNOSUPPORT if the uclass is not supported by this board, |
d9f48579 | 263 | * -ENOENT if there is no device with that number |
201417d7 | 264 | */ |
d9f48579 SG |
265 | int bootdev_find_by_any(const char *name, struct udevice **devp, |
266 | int *method_flagsp); | |
201417d7 SG |
267 | |
268 | /** | |
47aedc29 | 269 | * bootdev_setup_iter() - Set up iteration through bootdevs |
201417d7 | 270 | * |
91943ff7 SG |
271 | * This sets up the an interation, based on the provided device or label. If |
272 | * neither is provided, the iteration is based on the priority of each bootdev, | |
273 | * the * bootdev-order property in the bootstd node (or the boot_targets env | |
274 | * var). | |
201417d7 SG |
275 | * |
276 | * @iter: Iterator to update with the order | |
91943ff7 | 277 | * @label: label to scan, or NULL to scan all |
201417d7 SG |
278 | * @devp: On entry, *devp is NULL to scan all, otherwise this is the (single) |
279 | * device to scan. Returns the first device to use, which is the passed-in | |
280 | * @devp if it was non-NULL | |
47aedc29 SG |
281 | * @method_flagsp: If non-NULL, returns any flags implied by the label |
282 | * (enum bootflow_meth_flags_t), 0 if none | |
201417d7 SG |
283 | * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve |
284 | * on other error | |
285 | */ | |
91943ff7 SG |
286 | int bootdev_setup_iter(struct bootflow_iter *iter, const char *label, |
287 | struct udevice **devp, int *method_flagsp); | |
201417d7 | 288 | |
bd90b092 SG |
289 | /** |
290 | * bootdev_list_hunters() - List the available bootdev hunters | |
291 | * | |
292 | * These provide a way to find new bootdevs by enumerating buses, etc. This | |
293 | * function lists the available hunters | |
294 | * | |
295 | * @std: Pointer to bootstd private info | |
296 | */ | |
297 | void bootdev_list_hunters(struct bootstd_priv *std); | |
298 | ||
c7b63d50 SG |
299 | /** |
300 | * bootdev_hunt() - Hunt for bootdevs matching a particular spec | |
301 | * | |
302 | * This runs the selected hunter (or all if @spec is NULL) to try to find new | |
303 | * bootdevs. | |
304 | * | |
305 | * @spec: Spec to match, e.g. "mmc0", or NULL for any. If provided, this must | |
306 | * match a uclass name so that the hunter can be determined. Any trailing number | |
307 | * is ignored | |
308 | * @show: true to show each hunter before using it | |
309 | * Returns: 0 if OK, -ve on error | |
310 | */ | |
311 | int bootdev_hunt(const char *spec, bool show); | |
312 | ||
79a7d4a6 SG |
313 | /** |
314 | * bootdev_hunt_prio() - Hunt for bootdevs of a particular priority | |
315 | * | |
316 | * This runs all hunters which can find bootdevs of the given priority. | |
317 | * | |
318 | * @prio: Priority to use | |
319 | * @show: true to show each hunter as it is used | |
320 | * Returns: 0 if OK, -ve on error | |
321 | */ | |
322 | int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show); | |
323 | ||
1b1d36ec SG |
324 | /** |
325 | * bootdev_unhunt() - Mark a device as needing to be hunted again | |
326 | * | |
327 | * @id: uclass ID to update | |
328 | * Return: 0 if done, -EALREADY if already in this state, -ENOENT if no hunter | |
329 | * found for that uclass | |
330 | */ | |
331 | int bootdev_unhunt(enum uclass_id id); | |
332 | ||
66e3dce7 SG |
333 | /** |
334 | * bootdev_hunt_and_find_by_label() - Hunt for bootdevs by label | |
335 | * | |
336 | * Runs the hunter for the label, then tries to find the bootdev, possible | |
337 | * created by the hunter | |
338 | * | |
339 | * @label: Label to look up (e.g. "mmc1" or "mmc0") | |
340 | * @devp: Returns the bootdev device found, or NULL if none (note it does not | |
341 | * return the media device, but its bootdev child) | |
342 | * @method_flagsp: If non-NULL, returns any flags implied by the label | |
343 | * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails | |
344 | * Return: 0 if OK, -EINVAL if the uclass is not supported by this board, | |
345 | * -ENOENT if there is no device with that number | |
346 | */ | |
347 | int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp, | |
348 | int *method_flagsp); | |
349 | ||
e4b69489 SG |
350 | /** |
351 | * bootdev_next_label() - Move to the next bootdev in the label sequence | |
352 | * | |
353 | * Looks through the remaining labels until it finds one that matches a bootdev. | |
354 | * Bootdev scanners are used as needed. For example a label "mmc1" results in | |
355 | * running the "mmc" bootdrv. | |
356 | * | |
357 | * @iter: Interation info, containing iter->cur_label | |
358 | * @devp: New bootdev found, if any was found | |
359 | * @method_flagsp: If non-NULL, returns any flags implied by the label | |
360 | * (enum bootflow_meth_flags_t), 0 if none | |
361 | * Returns 0 if OK, -ENODEV if no bootdev was found | |
362 | */ | |
363 | int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp, | |
364 | int *method_flagsp); | |
365 | ||
43e89a30 SG |
366 | /** |
367 | * bootdev_next_prio() - Find the next bootdev in priority order | |
368 | * | |
369 | * This moves @devp to the next bootdev with the current priority. If there is | |
370 | * none, then it moves to the next priority and scans for new bootdevs there. | |
371 | * | |
372 | * @iter: Interation info, containing iter->cur_prio | |
373 | * @devp: On entry this is the previous bootdev that was considered. On exit | |
374 | * this is the new bootdev, if any was found | |
375 | * Returns 0 on success (*devp is updated), -ENODEV if there are no more | |
376 | * bootdevs at any priority | |
377 | */ | |
378 | int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp); | |
379 | ||
201417d7 SG |
380 | #if CONFIG_IS_ENABLED(BOOTSTD) |
381 | /** | |
3a2cb96e SG |
382 | * bootdev_setup_for_dev() - Bind a new bootdev device (deprecated) |
383 | * | |
d7d78576 | 384 | * Please use bootdev_setup_for_sibling_blk() instead since it supports multiple |
3a2cb96e | 385 | * (child) block devices for each media device. |
201417d7 SG |
386 | * |
387 | * Creates a bootdev device as a child of @parent. This should be called from | |
388 | * the driver's bind() method or its uclass' post_bind() method. | |
389 | * | |
390 | * If a child bootdev already exists, this function does nothing | |
391 | * | |
392 | * @parent: Parent device (e.g. MMC or Ethernet) | |
393 | * @drv_name: Name of bootdev driver to bind | |
394 | * Return: 0 if OK, -ve on error | |
395 | */ | |
396 | int bootdev_setup_for_dev(struct udevice *parent, const char *drv_name); | |
397 | ||
71b1ae4d | 398 | #if CONFIG_IS_ENABLED(BOOTSTD) |
201417d7 | 399 | /** |
d7d78576 | 400 | * bootdev_setup_for_sibling_blk() - Bind a new bootdev device for a blk device |
201417d7 SG |
401 | * |
402 | * Creates a bootdev device as a sibling of @blk. This should be called from | |
403 | * the driver's bind() method or its uclass' post_bind() method, at the same | |
404 | * time as the bould device is bound | |
405 | * | |
406 | * If a device of the same name already exists, this function does nothing | |
407 | * | |
408 | * @parent: Parent device (e.g. MMC or Ethernet) | |
409 | * @drv_name: Name of bootdev driver to bind | |
410 | * Return: 0 if OK, -ve on error | |
411 | */ | |
d7d78576 | 412 | int bootdev_setup_for_sibling_blk(struct udevice *blk, const char *drv_name); |
71b1ae4d SG |
413 | #else |
414 | static int bootdev_setup_for_sibling_blk(struct udevice *blk, | |
415 | const char *drv_name) | |
416 | { | |
417 | return 0; | |
418 | } | |
419 | #endif | |
201417d7 SG |
420 | |
421 | /** | |
422 | * bootdev_get_sibling_blk() - Locate the block device for a bootdev | |
423 | * | |
424 | * @dev: bootdev to check | |
425 | * @blkp: returns associated block device | |
426 | * Return: 0 if OK, -EINVAL if @dev is not a bootdev device, other -ve on other | |
427 | * error | |
428 | */ | |
429 | int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp); | |
430 | ||
431 | /** | |
432 | * bootdev_unbind_dev() - Unbind a bootdev device | |
433 | * | |
434 | * Remove and unbind a bootdev device which is a child of @parent. This should | |
435 | * be called from the driver's unbind() method or its uclass' post_bind() | |
436 | * method. | |
437 | * | |
438 | * @parent: Parent device (e.g. MMC or Ethernet) | |
439 | * Return: 0 if OK, -ve on error | |
440 | */ | |
441 | int bootdev_unbind_dev(struct udevice *parent); | |
442 | #else | |
443 | static inline int bootdev_setup_for_dev(struct udevice *parent, | |
444 | const char *drv_name) | |
445 | { | |
446 | return 0; | |
447 | } | |
448 | ||
d7d78576 SG |
449 | static inline int bootdev_setup_for_sibling_blk(struct udevice *blk, |
450 | const char *drv_name) | |
201417d7 SG |
451 | { |
452 | return 0; | |
453 | } | |
454 | ||
455 | static inline int bootdev_unbind_dev(struct udevice *parent) | |
456 | { | |
457 | return 0; | |
458 | } | |
459 | #endif | |
460 | ||
461 | #endif |