Add VLAN support.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / MnpDxe / MnpDriver.c
1 /** @file
2 Implementation of driver entry point and driver binding protocol.
3
4 Copyright (c) 2005 - 2009, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions
7 of the BSD License which accompanies this distribution. The full
8 text of the license may be found at<BR>
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "MnpDriver.h"
17 #include "MnpImpl.h"
18 #include "MnpVlan.h"
19
20 EFI_DRIVER_BINDING_PROTOCOL gMnpDriverBinding = {
21 MnpDriverBindingSupported,
22 MnpDriverBindingStart,
23 MnpDriverBindingStop,
24 0xa,
25 NULL,
26 NULL
27 };
28
29 /**
30 Test to see if this driver supports ControllerHandle. This service
31 is called by the EFI boot service ConnectController(). In
32 order to make drivers as small as possible, there are a few calling
33 restrictions for this service. ConnectController() must
34 follow these calling restrictions. If any other agent wishes to call
35 Supported() it must also follow these calling restrictions.
36
37 @param[in] This Protocol instance pointer.
38 @param[in] ControllerHandle Handle of device to test.
39 @param[in] RemainingDevicePath Optional parameter use to pick a specific
40 child device to start.
41
42 @retval EFI_SUCCESS This driver supports this device.
43 @retval EFI_ALREADY_STARTED This driver is already running on this device.
44 @retval Others This driver does not support this device.
45
46 **/
47 EFI_STATUS
48 EFIAPI
49 MnpDriverBindingSupported (
50 IN EFI_DRIVER_BINDING_PROTOCOL *This,
51 IN EFI_HANDLE ControllerHandle,
52 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
53 )
54 {
55 EFI_STATUS Status;
56 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
57
58 //
59 // Test to open the Simple Network protocol BY_DRIVER.
60 //
61 Status = gBS->OpenProtocol (
62 ControllerHandle,
63 &gEfiSimpleNetworkProtocolGuid,
64 (VOID **) &Snp,
65 This->DriverBindingHandle,
66 ControllerHandle,
67 EFI_OPEN_PROTOCOL_BY_DRIVER
68 );
69 if (EFI_ERROR (Status)) {
70 return Status;
71 }
72
73 //
74 // Close the openned SNP protocol.
75 //
76 gBS->CloseProtocol (
77 ControllerHandle,
78 &gEfiSimpleNetworkProtocolGuid,
79 This->DriverBindingHandle,
80 ControllerHandle
81 );
82
83 return EFI_SUCCESS;
84 }
85
86
87 /**
88 Start this driver on ControllerHandle. This service is called by the
89 EFI boot service ConnectController(). In order to make drivers as small
90 as possible, there are a few calling restrictions for this service.
91 ConnectController() must follow these calling restrictions. If any other
92 agent wishes to call Start() it must also follow these calling restrictions.
93
94 @param[in] This Protocol instance pointer.
95 @param[in] ControllerHandle Handle of device to bind driver to.
96 @param[in] RemainingDevicePath Optional parameter use to pick a specific
97 child device to start.
98
99 @retval EFI_SUCCESS This driver is added to ControllerHandle.
100 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
101 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for Mnp Service Data.
102 @retval Others This driver does not support this device.
103
104 **/
105 EFI_STATUS
106 EFIAPI
107 MnpDriverBindingStart (
108 IN EFI_DRIVER_BINDING_PROTOCOL *This,
109 IN EFI_HANDLE ControllerHandle,
110 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
111 )
112 {
113 EFI_STATUS Status;
114 MNP_SERVICE_DATA *MnpServiceData;
115 MNP_DEVICE_DATA *MnpDeviceData;
116 LIST_ENTRY *Entry;
117 VLAN_TCI *VlanVariable;
118 UINTN NumberOfVlan;
119 UINTN Index;
120
121 VlanVariable = NULL;
122
123 //
124 // Initialize the Mnp Device Data
125 //
126 MnpDeviceData = AllocateZeroPool (sizeof (MNP_DEVICE_DATA));
127 if (MnpDeviceData == NULL) {
128 DEBUG ((EFI_D_ERROR, "MnpDriverBindingStart(): Failed to allocate the Mnp Device Data.\n"));
129
130 return EFI_OUT_OF_RESOURCES;
131 }
132
133 Status = MnpInitializeDeviceData (MnpDeviceData, This->DriverBindingHandle, ControllerHandle);
134 if (EFI_ERROR (Status)) {
135 DEBUG ((EFI_D_ERROR, "MnpDriverBindingStart: MnpInitializeDeviceData failed, %r.\n", Status));
136
137 FreePool (MnpDeviceData);
138 return Status;
139 }
140
141 //
142 // Check whether NIC driver has already produced VlanConfig protocol
143 //
144 Status = gBS->OpenProtocol (
145 ControllerHandle,
146 &gEfiVlanConfigProtocolGuid,
147 NULL,
148 This->DriverBindingHandle,
149 ControllerHandle,
150 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
151 );
152 if (!EFI_ERROR (Status)) {
153 //
154 // NIC hardware already implement VLAN,
155 // no need to provide software VLAN implementation in MNP driver
156 //
157 MnpDeviceData->NumberOfVlan = 0;
158 ZeroMem (&MnpDeviceData->VlanConfig, sizeof (EFI_VLAN_CONFIG_PROTOCOL));
159 MnpServiceData = MnpCreateServiceData (MnpDeviceData, 0, 0);
160 Status = (MnpServiceData != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
161 goto Exit;
162 }
163
164 //
165 // Install VLAN Config Protocol
166 //
167 Status = gBS->InstallMultipleProtocolInterfaces (
168 &ControllerHandle,
169 &gEfiVlanConfigProtocolGuid,
170 &MnpDeviceData->VlanConfig,
171 NULL
172 );
173 if (EFI_ERROR (Status)) {
174 goto Exit;
175 }
176
177 //
178 // Get current VLAN configuration from EFI Variable
179 //
180 NumberOfVlan = 0;
181 Status = MnpGetVlanVariable (MnpDeviceData, &NumberOfVlan, &VlanVariable);
182 if (EFI_ERROR (Status)) {
183 //
184 // No VLAN is set, create a default MNP service data for untagged frame
185 //
186 MnpDeviceData->NumberOfVlan = 0;
187 MnpServiceData = MnpCreateServiceData (MnpDeviceData, 0, 0);
188 Status = (MnpServiceData != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
189 goto Exit;
190 }
191
192 //
193 // Create MNP service data for each VLAN
194 //
195 MnpDeviceData->NumberOfVlan = NumberOfVlan;
196 for (Index = 0; Index < NumberOfVlan; Index++) {
197 MnpServiceData = MnpCreateServiceData (
198 MnpDeviceData,
199 VlanVariable[Index].Bits.Vid,
200 (UINT8) VlanVariable[Index].Bits.Priority
201 );
202
203 if (MnpServiceData == NULL) {
204 Status = EFI_OUT_OF_RESOURCES;
205
206 goto Exit;
207 }
208 }
209
210 Exit:
211 if (VlanVariable != NULL) {
212 FreePool (VlanVariable);
213 }
214
215 if (EFI_ERROR (Status)) {
216 //
217 // Destroy all MNP service data
218 //
219 while (!IsListEmpty (&MnpDeviceData->ServiceList)) {
220 Entry = GetFirstNode (&MnpDeviceData->ServiceList);
221 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
222 MnpDestroyServiceData (MnpServiceData);
223 }
224
225 //
226 // Uninstall the VLAN Config Protocol if any
227 //
228 if (MnpDeviceData->VlanConfig.Set != NULL) {
229 gBS->UninstallMultipleProtocolInterfaces (
230 MnpDeviceData->ControllerHandle,
231 &gEfiVlanConfigProtocolGuid,
232 &MnpDeviceData->VlanConfig,
233 NULL
234 );
235 }
236
237 //
238 // Destroy Mnp Device Data
239 //
240 MnpDestroyDeviceData (MnpDeviceData, This->DriverBindingHandle);
241 FreePool (MnpDeviceData);
242 }
243
244 return Status;
245 }
246
247 /**
248 Stop this driver on ControllerHandle. This service is called by the
249 EFI boot service DisconnectController(). In order to make drivers as
250 small as possible, there are a few calling restrictions for this service.
251 DisconnectController() must follow these calling restrictions. If any other
252 agent wishes to call Stop() it must also follow these calling restrictions.
253
254 @param[in] This Protocol instance pointer.
255 @param[in] ControllerHandle Handle of device to stop driver on.
256 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If
257 number of children is zero stop the entire
258 bus driver.
259 @param[in] ChildHandleBuffer List of Child Handles to Stop.
260
261 @retval EFI_SUCCESS This driver is removed ControllerHandle.
262 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
263
264 **/
265 EFI_STATUS
266 EFIAPI
267 MnpDriverBindingStop (
268 IN EFI_DRIVER_BINDING_PROTOCOL *This,
269 IN EFI_HANDLE ControllerHandle,
270 IN UINTN NumberOfChildren,
271 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
272 )
273 {
274 EFI_STATUS Status;
275 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
276 EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
277 MNP_DEVICE_DATA *MnpDeviceData;
278 MNP_SERVICE_DATA *MnpServiceData;
279 BOOLEAN AllChildrenStopped;
280 LIST_ENTRY *Entry;
281
282 //
283 // Try to retrieve MNP service binding protocol from the ControllerHandle
284 //
285 Status = gBS->OpenProtocol (
286 ControllerHandle,
287 &gEfiManagedNetworkServiceBindingProtocolGuid,
288 (VOID **) &ServiceBinding,
289 This->DriverBindingHandle,
290 ControllerHandle,
291 EFI_OPEN_PROTOCOL_GET_PROTOCOL
292 );
293 if (EFI_ERROR (Status)) {
294 //
295 // Retrieve VLAN Config Protocol from the ControllerHandle
296 //
297 Status = gBS->OpenProtocol (
298 ControllerHandle,
299 &gEfiVlanConfigProtocolGuid,
300 (VOID **) &VlanConfig,
301 This->DriverBindingHandle,
302 ControllerHandle,
303 EFI_OPEN_PROTOCOL_GET_PROTOCOL
304 );
305 if (EFI_ERROR (Status)) {
306 DEBUG ((EFI_D_ERROR, "MnpDriverBindingStop: try to stop unknown Controller.\n"));
307 return EFI_DEVICE_ERROR;
308 }
309
310 MnpDeviceData = MNP_DEVICE_DATA_FROM_THIS (VlanConfig);
311 } else {
312 MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (ServiceBinding);
313 MnpDeviceData = MnpServiceData->MnpDeviceData;
314 }
315
316 if (NumberOfChildren == 0) {
317 //
318 // Destroy all MNP service data
319 //
320 while (!IsListEmpty (&MnpDeviceData->ServiceList)) {
321 Entry = GetFirstNode (&MnpDeviceData->ServiceList);
322 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
323 MnpDestroyServiceData (MnpServiceData);
324 }
325
326 //
327 // Uninstall the VLAN Config Protocol if any
328 //
329 if (MnpDeviceData->VlanConfig.Set != NULL) {
330 gBS->UninstallMultipleProtocolInterfaces (
331 MnpDeviceData->ControllerHandle,
332 &gEfiVlanConfigProtocolGuid,
333 &MnpDeviceData->VlanConfig,
334 NULL
335 );
336 }
337
338 //
339 // Destroy the Mnp device data
340 //
341 MnpDestroyDeviceData (MnpDeviceData, This->DriverBindingHandle);
342 FreePool (MnpDeviceData);
343
344 return EFI_SUCCESS;
345 }
346
347 //
348 // Stop all MNP child
349 //
350 AllChildrenStopped = TRUE;
351 NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {
352 MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);
353
354 Status = MnpDestroyServiceChild (MnpServiceData);
355 if (EFI_ERROR (Status)) {
356 AllChildrenStopped = FALSE;
357 }
358 }
359
360 if (!AllChildrenStopped) {
361 return EFI_DEVICE_ERROR;
362 }
363
364 return EFI_SUCCESS;
365 }
366
367
368 /**
369 Creates a child handle with a set of I/O services.
370
371 @param[in] This Protocol instance pointer.
372 @param[in, out] ChildHandle Pointer to the handle of the child to create. If
373 it is NULL, then a new handle is created. If
374 it is not NULL, then the I/O services are added
375 to the existing child handle.
376
377 @retval EFI_SUCCES The protocol was added to ChildHandle.
378 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
379 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to
380 create the child.
381 @retval Others The child handle was not created.
382
383 **/
384 EFI_STATUS
385 EFIAPI
386 MnpServiceBindingCreateChild (
387 IN EFI_SERVICE_BINDING_PROTOCOL *This,
388 IN OUT EFI_HANDLE *ChildHandle
389 )
390 {
391 EFI_STATUS Status;
392 MNP_SERVICE_DATA *MnpServiceData;
393 MNP_INSTANCE_DATA *Instance;
394 VOID *MnpSb;
395 EFI_TPL OldTpl;
396
397 if ((This == NULL) || (ChildHandle == NULL)) {
398 return EFI_INVALID_PARAMETER;
399 }
400
401 MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This);
402
403 //
404 // Allocate buffer for the new instance.
405 //
406 Instance = AllocateZeroPool (sizeof (MNP_INSTANCE_DATA));
407 if (Instance == NULL) {
408 DEBUG ((EFI_D_ERROR, "MnpServiceBindingCreateChild: Faild to allocate memory for the new instance.\n"));
409
410 return EFI_OUT_OF_RESOURCES;
411 }
412
413 //
414 // Init the instance data.
415 //
416 MnpInitializeInstanceData (MnpServiceData, Instance);
417
418 Status = gBS->InstallMultipleProtocolInterfaces (
419 ChildHandle,
420 &gEfiManagedNetworkProtocolGuid,
421 &Instance->ManagedNetwork,
422 NULL
423 );
424 if (EFI_ERROR (Status)) {
425 DEBUG (
426 (EFI_D_ERROR,
427 "MnpServiceBindingCreateChild: Failed to install the MNP protocol, %r.\n",
428 Status)
429 );
430
431 goto ErrorExit;
432 }
433
434 //
435 // Save the instance's childhandle.
436 //
437 Instance->Handle = *ChildHandle;
438
439 Status = gBS->OpenProtocol (
440 MnpServiceData->ServiceHandle,
441 &gEfiManagedNetworkServiceBindingProtocolGuid,
442 (VOID **) &MnpSb,
443 gMnpDriverBinding.DriverBindingHandle,
444 Instance->Handle,
445 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
446 );
447 if (EFI_ERROR (Status)) {
448 goto ErrorExit;
449 }
450
451 //
452 // Add the child instance into ChildrenList.
453 //
454 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
455
456 InsertTailList (&MnpServiceData->ChildrenList, &Instance->InstEntry);
457 MnpServiceData->ChildrenNumber++;
458
459 gBS->RestoreTPL (OldTpl);
460
461 ErrorExit:
462
463 if (EFI_ERROR (Status)) {
464
465 if (Instance->Handle != NULL) {
466
467 gBS->UninstallMultipleProtocolInterfaces (
468 &gEfiManagedNetworkProtocolGuid,
469 &Instance->ManagedNetwork,
470 NULL
471 );
472 }
473
474 FreePool (Instance);
475 }
476
477 return Status;
478 }
479
480
481 /**
482 Destroys a child handle with a set of I/O services.
483
484 The DestroyChild() function does the opposite of CreateChild(). It removes a
485 protocol that was installed by CreateChild() from ChildHandle. If the removed
486 protocol is the last protocol on ChildHandle, then ChildHandle is destroyed.
487
488 @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL
489 instance.
490 @param[in] ChildHandle Handle of the child to destroy.
491
492 @retval EFI_SUCCES The protocol was removed from ChildHandle.
493 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that
494 is being removed.
495 @retval EFI_INVALID_PARAMETER ChildHandle is not a valid UEFI handle.
496 @retval EFI_ACCESS_DENIED The protocol could not be removed from the
497 ChildHandle because its services are being
498 used.
499 @retval Others The child handle was not destroyed.
500
501 **/
502 EFI_STATUS
503 EFIAPI
504 MnpServiceBindingDestroyChild (
505 IN EFI_SERVICE_BINDING_PROTOCOL *This,
506 IN EFI_HANDLE ChildHandle
507 )
508 {
509 EFI_STATUS Status;
510 MNP_SERVICE_DATA *MnpServiceData;
511 EFI_MANAGED_NETWORK_PROTOCOL *ManagedNetwork;
512 MNP_INSTANCE_DATA *Instance;
513 EFI_TPL OldTpl;
514
515 if ((This == NULL) || (ChildHandle == NULL)) {
516 return EFI_INVALID_PARAMETER;
517 }
518
519 MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This);
520
521 //
522 // Try to retrieve ManagedNetwork Protocol from ChildHandle.
523 //
524 Status = gBS->OpenProtocol (
525 ChildHandle,
526 &gEfiManagedNetworkProtocolGuid,
527 (VOID **) &ManagedNetwork,
528 gMnpDriverBinding.DriverBindingHandle,
529 ChildHandle,
530 EFI_OPEN_PROTOCOL_GET_PROTOCOL
531 );
532 if (EFI_ERROR (Status)) {
533 return EFI_UNSUPPORTED;
534 }
535
536 Instance = MNP_INSTANCE_DATA_FROM_THIS (ManagedNetwork);
537
538 //
539 // MnpServiceBindingDestroyChild may be called twice: first called by
540 // MnpServiceBindingStop, second called by uninstalling the MNP protocol
541 // in this ChildHandle. Use destroyed to make sure the resource clean code
542 // will only excecute once.
543 //
544 if (Instance->Destroyed) {
545 return EFI_SUCCESS;
546 }
547
548 Instance->Destroyed = TRUE;
549
550 //
551 // Close the Simple Network protocol.
552 //
553 gBS->CloseProtocol (
554 MnpServiceData->ServiceHandle,
555 &gEfiManagedNetworkServiceBindingProtocolGuid,
556 MnpServiceData->MnpDeviceData->ImageHandle,
557 ChildHandle
558 );
559
560 //
561 // Uninstall the ManagedNetwork protocol.
562 //
563 Status = gBS->UninstallMultipleProtocolInterfaces (
564 ChildHandle,
565 &gEfiManagedNetworkProtocolGuid,
566 &Instance->ManagedNetwork,
567 NULL
568 );
569 if (EFI_ERROR (Status)) {
570 DEBUG (
571 (EFI_D_ERROR,
572 "MnpServiceBindingDestroyChild: Failed to uninstall the ManagedNetwork protocol, %r.\n",
573 Status)
574 );
575
576 Instance->Destroyed = FALSE;
577 return Status;
578 }
579
580 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
581
582 //
583 // Reset the configuration.
584 //
585 ManagedNetwork->Configure (ManagedNetwork, NULL);
586
587 //
588 // Try to flush the RcvdPacketQueue.
589 //
590 MnpFlushRcvdDataQueue (Instance);
591
592 //
593 // Clean the RxTokenMap.
594 //
595 NetMapClean (&Instance->RxTokenMap);
596
597 //
598 // Remove this instance from the ChildrenList.
599 //
600 RemoveEntryList (&Instance->InstEntry);
601 MnpServiceData->ChildrenNumber--;
602
603 gBS->RestoreTPL (OldTpl);
604
605 FreePool (Instance);
606
607 return Status;
608 }
609
610 /**
611 The entry point for Mnp driver which installs the driver binding and component
612 name protocol on its ImageHandle.
613
614 @param[in] ImageHandle The image handle of the driver.
615 @param[in] SystemTable The system table.
616
617 @retval EFI_SUCCES The driver binding and component name protocols are
618 successfully installed.
619 @retval Others Other errors as indicated.
620
621 **/
622 EFI_STATUS
623 EFIAPI
624 MnpDriverEntryPoint (
625 IN EFI_HANDLE ImageHandle,
626 IN EFI_SYSTEM_TABLE *SystemTable
627 )
628 {
629 return EfiLibInstallDriverBindingComponentName2 (
630 ImageHandle,
631 SystemTable,
632 &gMnpDriverBinding,
633 ImageHandle,
634 &gMnpComponentName,
635 &gMnpComponentName2
636 );
637 }