Merge branch 'master' of git://git.denx.de/u-boot-spi
[oweals/u-boot.git] / lib / efi_driver / efi_uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  Uclass for EFI drivers
4  *
5  *  Copyright (c) 2017 Heinrich Schuchardt
6  *
7  * For each EFI driver the uclass
8  * - creates a handle
9  * - installs the driver binding protocol
10  *
11  * The uclass provides the bind, start, and stop entry points for the driver
12  * binding protocol.
13  *
14  * In bind() and stop() it checks if the controller implements the protocol
15  * supported by the EFI driver. In the start() function it calls the bind()
16  * function of the EFI driver. In the stop() function it destroys the child
17  * controllers.
18  */
19
20 #include <efi_driver.h>
21
22 /**
23  * check_node_type() - check node type
24  *
25  * We do not support partitions as controller handles.
26  *
27  * @handle:     handle to be checked
28  * Return:      status code
29  */
30 static efi_status_t check_node_type(efi_handle_t handle)
31 {
32         efi_status_t r, ret = EFI_SUCCESS;
33         const struct efi_device_path *dp;
34
35         /* Open the device path protocol */
36         r = EFI_CALL(systab.boottime->open_protocol(
37                         handle, &efi_guid_device_path, (void **)&dp,
38                         NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
39         if (r == EFI_SUCCESS && dp) {
40                 /* Get the last node */
41                 const struct efi_device_path *node = efi_dp_last_node(dp);
42                 /* We do not support partitions as controller */
43                 if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
44                         ret = EFI_UNSUPPORTED;
45         }
46         return ret;
47 }
48
49 /**
50  * efi_uc_supported() - check if the driver supports the controller
51  *
52  * @this:                       driver binding protocol
53  * @controller_handle:          handle of the controller
54  * @remaining_device_path:      path specifying the child controller
55  * Return:                      status code
56  */
57 static efi_status_t EFIAPI efi_uc_supported(
58                 struct efi_driver_binding_protocol *this,
59                 efi_handle_t controller_handle,
60                 struct efi_device_path *remaining_device_path)
61 {
62         efi_status_t r, ret;
63         void *interface;
64         struct efi_driver_binding_extended_protocol *bp =
65                         (struct efi_driver_binding_extended_protocol *)this;
66
67         EFI_ENTRY("%p, %p, %ls", this, controller_handle,
68                   efi_dp_str(remaining_device_path));
69
70         ret = EFI_CALL(systab.boottime->open_protocol(
71                         controller_handle, bp->ops->protocol,
72                         &interface, this->driver_binding_handle,
73                         controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
74         switch (ret) {
75         case EFI_ACCESS_DENIED:
76         case EFI_ALREADY_STARTED:
77                 goto out;
78         case EFI_SUCCESS:
79                 break;
80         default:
81                 ret = EFI_UNSUPPORTED;
82                 goto out;
83         }
84
85         ret = check_node_type(controller_handle);
86
87         r = EFI_CALL(systab.boottime->close_protocol(
88                                 controller_handle, bp->ops->protocol,
89                                 this->driver_binding_handle,
90                                 controller_handle));
91         if (r != EFI_SUCCESS)
92                 ret = EFI_UNSUPPORTED;
93 out:
94         return EFI_EXIT(ret);
95 }
96
97 /**
98  * efi_uc_start() - create child controllers and attach driver
99  *
100  * @this:                       driver binding protocol
101  * @controller_handle:          handle of the controller
102  * @remaining_device_path:      path specifying the child controller
103  * Return:                      status code
104  */
105 static efi_status_t EFIAPI efi_uc_start(
106                 struct efi_driver_binding_protocol *this,
107                 efi_handle_t controller_handle,
108                 struct efi_device_path *remaining_device_path)
109 {
110         efi_status_t r, ret;
111         void *interface = NULL;
112         struct efi_driver_binding_extended_protocol *bp =
113                         (struct efi_driver_binding_extended_protocol *)this;
114
115         EFI_ENTRY("%p, %pUl, %ls", this, controller_handle,
116                   efi_dp_str(remaining_device_path));
117
118         /* Attach driver to controller */
119         ret = EFI_CALL(systab.boottime->open_protocol(
120                         controller_handle, bp->ops->protocol,
121                         &interface, this->driver_binding_handle,
122                         controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
123         switch (ret) {
124         case EFI_ACCESS_DENIED:
125         case EFI_ALREADY_STARTED:
126                 goto out;
127         case EFI_SUCCESS:
128                 break;
129         default:
130                 ret =  EFI_UNSUPPORTED;
131                 goto out;
132         }
133         ret = check_node_type(controller_handle);
134         if (ret != EFI_SUCCESS) {
135                 r = EFI_CALL(systab.boottime->close_protocol(
136                                 controller_handle, bp->ops->protocol,
137                                 this->driver_binding_handle,
138                                 controller_handle));
139                 if (r != EFI_SUCCESS)
140                         EFI_PRINT("Failure to close handle\n");
141                 goto out;
142         }
143
144         /* TODO: driver specific stuff */
145         bp->ops->bind(controller_handle, interface);
146
147 out:
148         return EFI_EXIT(ret);
149 }
150
151 /**
152  * disconnect_child() - remove a single child controller from the parent
153  *                      controller
154  *
155  * @controller_handle:  parent controller
156  * @child_handle:       child controller
157  * Return:              status code
158  */
159 static efi_status_t disconnect_child(efi_handle_t controller_handle,
160                                      efi_handle_t child_handle)
161 {
162         efi_status_t ret;
163         efi_guid_t *guid_controller = NULL;
164         efi_guid_t *guid_child_controller = NULL;
165
166         ret = EFI_CALL(systab.boottime->close_protocol(
167                                 controller_handle, guid_controller,
168                                 child_handle, child_handle));
169         if (ret != EFI_SUCCESS) {
170                 EFI_PRINT("Cannot close protocol\n");
171                 return ret;
172         }
173         ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
174                                 child_handle, guid_child_controller, NULL));
175         if (ret != EFI_SUCCESS) {
176                 EFI_PRINT("Cannot uninstall protocol interface\n");
177                 return ret;
178         }
179         return ret;
180 }
181
182 /**
183  * efi_uc_stop() - Remove child controllers and disconnect the controller
184  *
185  * @this:                       driver binding protocol
186  * @controller_handle:          handle of the controller
187  * @number_of_children:         number of child controllers to remove
188  * @child_handle_buffer:        handles of the child controllers to remove
189  * Return:                      status code
190  */
191 static efi_status_t EFIAPI efi_uc_stop(
192                 struct efi_driver_binding_protocol *this,
193                 efi_handle_t controller_handle,
194                 size_t number_of_children,
195                 efi_handle_t *child_handle_buffer)
196 {
197         efi_status_t ret;
198         efi_uintn_t count;
199         struct efi_open_protocol_info_entry *entry_buffer;
200         efi_guid_t *guid_controller = NULL;
201
202         EFI_ENTRY("%p, %pUl, %zu, %p", this, controller_handle,
203                   number_of_children, child_handle_buffer);
204
205         /* Destroy provided child controllers */
206         if (number_of_children) {
207                 efi_uintn_t i;
208
209                 for (i = 0; i < number_of_children; ++i) {
210                         ret = disconnect_child(controller_handle,
211                                                child_handle_buffer[i]);
212                         if (ret != EFI_SUCCESS)
213                                 return ret;
214                 }
215                 return EFI_SUCCESS;
216         }
217
218         /* Destroy all children */
219         ret = EFI_CALL(systab.boottime->open_protocol_information(
220                                         controller_handle, guid_controller,
221                                         &entry_buffer, &count));
222         if (ret != EFI_SUCCESS)
223                 goto out;
224         while (count) {
225                 if (entry_buffer[--count].attributes &
226                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
227                         ret = disconnect_child(
228                                         controller_handle,
229                                         entry_buffer[count].agent_handle);
230                         if (ret != EFI_SUCCESS)
231                                 goto out;
232                 }
233         }
234         ret = EFI_CALL(systab.boottime->free_pool(entry_buffer));
235         if (ret != EFI_SUCCESS)
236                 printf("%s(%u) %s: ERROR: Cannot free pool\n",
237                        __FILE__, __LINE__, __func__);
238
239         /* Detach driver from controller */
240         ret = EFI_CALL(systab.boottime->close_protocol(
241                         controller_handle, guid_controller,
242                         this->driver_binding_handle, controller_handle));
243 out:
244         return EFI_EXIT(ret);
245 }
246
247 /**
248  * efi_add_driver() - add driver
249  *
250  * @drv:                driver to add
251  * Return:              status code
252  */
253 static efi_status_t efi_add_driver(struct driver *drv)
254 {
255         efi_status_t ret;
256         const struct efi_driver_ops *ops = drv->ops;
257         struct efi_driver_binding_extended_protocol *bp;
258
259         debug("EFI: Adding driver '%s'\n", drv->name);
260         if (!ops->protocol) {
261                 printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
262                        drv->name);
263                 return EFI_INVALID_PARAMETER;
264         }
265         bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
266         if (!bp)
267                 return EFI_OUT_OF_RESOURCES;
268
269         bp->bp.supported = efi_uc_supported;
270         bp->bp.start = efi_uc_start;
271         bp->bp.stop = efi_uc_stop;
272         bp->bp.version = 0xffffffff;
273         bp->ops = drv->ops;
274
275         ret = efi_create_handle(&bp->bp.driver_binding_handle);
276         if (ret != EFI_SUCCESS) {
277                 free(bp);
278                 goto out;
279         }
280         bp->bp.image_handle = bp->bp.driver_binding_handle;
281         ret = efi_add_protocol(bp->bp.driver_binding_handle,
282                                &efi_guid_driver_binding_protocol, bp);
283         if (ret != EFI_SUCCESS) {
284                 efi_delete_handle(bp->bp.driver_binding_handle);
285                 free(bp);
286                 goto out;
287         }
288 out:
289         return ret;
290 }
291
292 /**
293  * efi_driver_init() - initialize the EFI drivers
294  *
295  * Called by efi_init_obj_list().
296  *
297  * Return:      0 = success, any other value will stop further execution
298  */
299 efi_status_t efi_driver_init(void)
300 {
301         struct driver *drv;
302         efi_status_t ret = EFI_SUCCESS;
303
304         /* Save 'gd' pointer */
305         efi_save_gd();
306
307         debug("EFI: Initializing EFI driver framework\n");
308         for (drv = ll_entry_start(struct driver, driver);
309              drv < ll_entry_end(struct driver, driver); ++drv) {
310                 if (drv->id == UCLASS_EFI) {
311                         ret = efi_add_driver(drv);
312                         if (ret != EFI_SUCCESS) {
313                                 printf("EFI: ERROR: failed to add driver %s\n",
314                                        drv->name);
315                                 break;
316                         }
317                 }
318         }
319         return ret;
320 }
321
322 /**
323  * efi_uc_init() - initialize the EFI uclass
324  *
325  * @class:      the EFI uclass
326  * Return:      0 = success
327  */
328 static int efi_uc_init(struct uclass *class)
329 {
330         printf("EFI: Initializing UCLASS_EFI\n");
331         return 0;
332 }
333
334 /**
335  * efi_uc_destroy() - destroy the EFI uclass
336  *
337  * @class:      the EFI uclass
338  * Return:      0 = success
339  */
340 static int efi_uc_destroy(struct uclass *class)
341 {
342         printf("Destroying  UCLASS_EFI\n");
343         return 0;
344 }
345
346 UCLASS_DRIVER(efi) = {
347         .name           = "efi",
348         .id             = UCLASS_EFI,
349         .init           = efi_uc_init,
350         .destroy        = efi_uc_destroy,
351 };