• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   This driver is used to manage SD/MMC PCI host controllers which are compliance
3   with SD Host Controller Simplified Specification version 3.00.
4 
5   It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
6 
7   Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
8   Copyright (C) 2016 Marvell International Ltd. All rigths reserved.<BR>
9 
10   This program and the accompanying materials
11   are licensed and made available under the terms and conditions of the BSD License
12   which accompanies this distribution.  The full text of the license may be found at
13   http://opensource.org/licenses/bsd-license.php
14 
15   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 
18 **/
19 
20 #include "SdMmcPciHcDxe.h"
21 #include "XenonSdhci.h"
22 
23 //
24 // Driver Global Variables
25 //
26 EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = {
27   SdMmcPciHcDriverBindingSupported,
28   SdMmcPciHcDriverBindingStart,
29   SdMmcPciHcDriverBindingStop,
30   0x10,
31   NULL,
32   NULL
33 };
34 
35 //
36 // Template for SD/MMC host controller private data.
37 //
38 SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate = {
39   SD_MMC_HC_PRIVATE_SIGNATURE,      // Signature
40   NULL,                             // ControllerHandle
41   NULL,                             // PciIo
42   {                                 // PassThru
43     sizeof (UINT32),
44     SdMmcPassThruPassThru,
45     SdMmcPassThruGetNextSlot,
46     SdMmcPassThruBuildDevicePath,
47     SdMmcPassThruGetSlotNumber,
48     SdMmcPassThruResetDevice
49   },
50   0,                                // PciAttributes
51   0,                                // PreviousSlot
52   NULL,                             // TimerEvent
53   NULL,                             // ConnectEvent
54                                     // Queue
55   INITIALIZE_LIST_HEAD_VARIABLE (gSdMmcPciHcTemplate.Queue),
56   {                                 // Slot
57     {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0},
58     {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}
59   },
60   {                                 // Capability
61     {0},
62   },
63   {                                 // MaxCurrent
64     0,
65   },
66   0                                 // ControllerVersion
67 };
68 
69 SD_DEVICE_PATH    mSdDpTemplate = {
70   {
71     MESSAGING_DEVICE_PATH,
72     MSG_SD_DP,
73     {
74       (UINT8) (sizeof (SD_DEVICE_PATH)),
75       (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)
76     }
77   },
78   0
79 };
80 
81 EMMC_DEVICE_PATH    mEmmcDpTemplate = {
82   {
83     MESSAGING_DEVICE_PATH,
84     MSG_EMMC_DP,
85     {
86       (UINT8) (sizeof (EMMC_DEVICE_PATH)),
87       (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)
88     }
89   },
90   0
91 };
92 
93 //
94 // Prioritized function list to detect card type.
95 // User could add other card detection logic here.
96 //
97 CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = {
98   EmmcIdentification,
99   SdCardIdentification,
100   NULL
101 };
102 
103 /**
104   The entry point for SD host controller driver, used to install this driver on the ImageHandle.
105 
106   @param[in]  ImageHandle   The firmware allocated handle for this driver image.
107   @param[in]  SystemTable   Pointer to the EFI system table.
108 
109   @retval EFI_SUCCESS   Driver loaded.
110   @retval other         Driver not loaded.
111 
112 **/
113 EFI_STATUS
114 EFIAPI
InitializeSdMmcPciHcDxe(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)115 InitializeSdMmcPciHcDxe (
116   IN EFI_HANDLE        ImageHandle,
117   IN EFI_SYSTEM_TABLE  *SystemTable
118   )
119 {
120   EFI_STATUS           Status;
121 
122   Status = EfiLibInstallDriverBindingComponentName2 (
123              ImageHandle,
124              SystemTable,
125              &gSdMmcPciHcDriverBinding,
126              ImageHandle,
127              &gSdMmcPciHcComponentName,
128              &gSdMmcPciHcComponentName2
129              );
130   ASSERT_EFI_ERROR (Status);
131 
132   return Status;
133 }
134 
135 /**
136   Call back function when the timer event is signaled.
137 
138   @param[in]  Event     The Event this notify function registered to.
139   @param[in]  Context   Pointer to the context data registered to the
140                         Event.
141 
142 **/
143 VOID
144 EFIAPI
ProcessAsyncTaskList(IN EFI_EVENT Event,IN VOID * Context)145 ProcessAsyncTaskList (
146   IN EFI_EVENT          Event,
147   IN VOID*              Context
148   )
149 {
150   SD_MMC_HC_PRIVATE_DATA              *Private;
151   LIST_ENTRY                          *Link;
152   SD_MMC_HC_TRB                       *Trb;
153   EFI_STATUS                          Status;
154   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
155   BOOLEAN                             InfiniteWait;
156   EFI_EVENT                           TrbEvent;
157 
158   Private = (SD_MMC_HC_PRIVATE_DATA*)Context;
159 
160   //
161   // Check if the first entry in the async I/O queue is done or not.
162   //
163   Status = EFI_SUCCESS;
164   Trb    = NULL;
165   Link   = GetFirstNode (&Private->Queue);
166   if (!IsNull (&Private->Queue, Link)) {
167     Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
168     if (!Private->Slot[Trb->Slot].MediaPresent) {
169       Status = EFI_NO_MEDIA;
170       goto Done;
171     }
172     if (!Trb->Started) {
173       //
174       // Check whether the cmd/data line is ready for transfer.
175       //
176       Status = SdMmcCheckTrbEnv (Private, Trb);
177       if (!EFI_ERROR (Status)) {
178         Trb->Started = TRUE;
179         Status = SdMmcExecTrb (Private, Trb);
180         if (EFI_ERROR (Status)) {
181           goto Done;
182         }
183       } else {
184         goto Done;
185       }
186     }
187     Status = SdMmcCheckTrbResult (Private, Trb);
188   }
189 
190 Done:
191   if ((Trb != NULL) && (Status == EFI_NOT_READY)) {
192     Packet = Trb->Packet;
193     if (Packet->Timeout == 0) {
194       InfiniteWait = TRUE;
195     } else {
196       InfiniteWait = FALSE;
197     }
198     if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {
199       RemoveEntryList (Link);
200       Trb->Packet->TransactionStatus = EFI_TIMEOUT;
201       TrbEvent = Trb->Event;
202       SdMmcFreeTrb (Trb);
203       DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent));
204       gBS->SignalEvent (TrbEvent);
205       return;
206     }
207   }
208   if ((Trb != NULL) && (Status != EFI_NOT_READY)) {
209     RemoveEntryList (Link);
210     Trb->Packet->TransactionStatus = Status;
211     TrbEvent = Trb->Event;
212     SdMmcFreeTrb (Trb);
213     DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p with %r\n", TrbEvent, Status));
214     gBS->SignalEvent (TrbEvent);
215   }
216   return;
217 }
218 
219 /**
220   Sd removable device enumeration callback function when the timer event is signaled.
221 
222   @param[in]  Event     The Event this notify function registered to.
223   @param[in]  Context   Pointer to the context data registered to the
224                         Event.
225 
226 **/
227 VOID
228 EFIAPI
SdMmcPciHcEnumerateDevice(IN EFI_EVENT Event,IN VOID * Context)229 SdMmcPciHcEnumerateDevice (
230   IN EFI_EVENT          Event,
231   IN VOID*              Context
232   )
233 {
234   SD_MMC_HC_PRIVATE_DATA              *Private;
235   EFI_STATUS                          Status;
236   UINT8                               Slot;
237   BOOLEAN                             MediaPresent;
238   UINT32                              RoutineNum;
239   CARD_TYPE_DETECT_ROUTINE            *Routine;
240   UINTN                               Index;
241   LIST_ENTRY                          *Link;
242   LIST_ENTRY                          *NextLink;
243   SD_MMC_HC_TRB                       *Trb;
244   EFI_TPL                             OldTpl;
245 
246   Private = (SD_MMC_HC_PRIVATE_DATA*)Context;
247 
248   for (Slot = 0; Slot < SD_MMC_HC_MAX_SLOT; Slot++) {
249     if ((Private->Slot[Slot].Enable) && (Private->Slot[Slot].SlotType == RemovableSlot)) {
250       Status = SdMmcHcCardDetect (Private->PciIo, Slot, &MediaPresent);
251       if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {
252         DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo));
253         Private->Slot[Slot].MediaPresent = FALSE;
254         Private->Slot[Slot].Initialized  = FALSE;
255         //
256         // Signal all async task events at the slot with EFI_NO_MEDIA status.
257         //
258         OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
259         for (Link = GetFirstNode (&Private->Queue);
260              !IsNull (&Private->Queue, Link);
261              Link = NextLink) {
262           NextLink = GetNextNode (&Private->Queue, Link);
263           Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
264           if (Trb->Slot == Slot) {
265             RemoveEntryList (Link);
266             Trb->Packet->TransactionStatus = EFI_NO_MEDIA;
267             gBS->SignalEvent (Trb->Event);
268             SdMmcFreeTrb (Trb);
269           }
270         }
271         gBS->RestoreTPL (OldTpl);
272         //
273         // Notify the upper layer the connect state change through ReinstallProtocolInterface.
274         //
275         gBS->ReinstallProtocolInterface (
276               Private->ControllerHandle,
277               &gEfiSdMmcPassThruProtocolGuid,
278               &Private->PassThru,
279               &Private->PassThru
280               );
281       }
282       if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) {
283         DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo));
284         //
285         // Reset the specified slot of the SD/MMC Pci Host Controller
286         //
287         Status = SdMmcHcReset (Private->PciIo, Slot);
288         if (EFI_ERROR (Status)) {
289           continue;
290         }
291         //
292         // Reinitialize slot and restart identification process for the new attached device
293         //
294         Status = SdMmcHcInitHost (Private->PciIo, Slot, Private->Capability[Slot]);
295         if (EFI_ERROR (Status)) {
296           continue;
297         }
298 
299         Private->Slot[Slot].MediaPresent = TRUE;
300         Private->Slot[Slot].Initialized  = TRUE;
301         RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
302         for (Index = 0; Index < RoutineNum; Index++) {
303           Routine = &mCardTypeDetectRoutineTable[Index];
304           if (*Routine != NULL) {
305             Status = (*Routine) (Private, Slot);
306             if (!EFI_ERROR (Status)) {
307               break;
308             }
309           }
310         }
311         //
312         // This card doesn't get initialized correctly.
313         //
314         if (Index == RoutineNum) {
315           Private->Slot[Slot].Initialized = FALSE;
316         }
317 
318         //
319         // Notify the upper layer the connect state change through ReinstallProtocolInterface.
320         //
321         gBS->ReinstallProtocolInterface (
322                Private->ControllerHandle,
323                &gEfiSdMmcPassThruProtocolGuid,
324                &Private->PassThru,
325                &Private->PassThru
326                );
327       }
328     }
329   }
330 
331   return;
332 }
333 /**
334   Tests to see if this driver supports a given controller. If a child device is provided,
335   it further tests to see if this driver supports creating a handle for the specified child device.
336 
337   This function checks to see if the driver specified by This supports the device specified by
338   ControllerHandle. Drivers will typically use the device path attached to
339   ControllerHandle and/or the services from the bus I/O abstraction attached to
340   ControllerHandle to determine if the driver supports ControllerHandle. This function
341   may be called many times during platform initialization. In order to reduce boot times, the tests
342   performed by this function must be very small, and take as little time as possible to execute. This
343   function must not change the state of any hardware devices, and this function must be aware that the
344   device specified by ControllerHandle may already be managed by the same driver or a
345   different driver. This function must match its calls to AllocatePages() with FreePages(),
346   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
347   Since ControllerHandle may have been previously started by the same driver, if a protocol is
348   already in the opened state, then it must not be closed with CloseProtocol(). This is required
349   to guarantee the state of ControllerHandle is not modified by this function.
350 
351   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
352   @param[in]  ControllerHandle     The handle of the controller to test. This handle
353                                    must support a protocol interface that supplies
354                                    an I/O abstraction to the driver.
355   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
356                                    parameter is ignored by device drivers, and is optional for bus
357                                    drivers. For bus drivers, if this parameter is not NULL, then
358                                    the bus driver must determine if the bus controller specified
359                                    by ControllerHandle and the child controller specified
360                                    by RemainingDevicePath are both supported by this
361                                    bus driver.
362 
363   @retval EFI_SUCCESS              The device specified by ControllerHandle and
364                                    RemainingDevicePath is supported by the driver specified by This.
365   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
366                                    RemainingDevicePath is already being managed by the driver
367                                    specified by This.
368   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
369                                    RemainingDevicePath is already being managed by a different
370                                    driver or an application that requires exclusive access.
371                                    Currently not implemented.
372   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
373                                    RemainingDevicePath is not supported by the driver specified by This.
374 **/
375 EFI_STATUS
376 EFIAPI
SdMmcPciHcDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)377 SdMmcPciHcDriverBindingSupported (
378   IN EFI_DRIVER_BINDING_PROTOCOL *This,
379   IN EFI_HANDLE                  Controller,
380   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
381   )
382 {
383   EFI_STATUS                Status;
384   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
385   EFI_PCI_IO_PROTOCOL       *PciIo;
386   PCI_TYPE00                PciData;
387 
388   PciIo            = NULL;
389   ParentDevicePath = NULL;
390 
391   //
392   // SdPciHcDxe is a device driver, and should ingore the
393   // "RemainingDevicePath" according to EFI spec.
394   //
395   Status = gBS->OpenProtocol (
396                   Controller,
397                   &gEfiDevicePathProtocolGuid,
398                   (VOID *) &ParentDevicePath,
399                   This->DriverBindingHandle,
400                   Controller,
401                   EFI_OPEN_PROTOCOL_BY_DRIVER
402                   );
403   if (EFI_ERROR (Status)) {
404     //
405     // EFI_ALREADY_STARTED is also an error.
406     //
407     return Status;
408   }
409   //
410   // Close the protocol because we don't use it here.
411   //
412   gBS->CloseProtocol (
413         Controller,
414         &gEfiDevicePathProtocolGuid,
415         This->DriverBindingHandle,
416         Controller
417         );
418 
419   //
420   // Now test the EfiPciIoProtocol.
421   //
422   Status = gBS->OpenProtocol (
423                   Controller,
424                   &gEfiPciIoProtocolGuid,
425                   (VOID **) &PciIo,
426                   This->DriverBindingHandle,
427                   Controller,
428                   EFI_OPEN_PROTOCOL_BY_DRIVER
429                   );
430   if (EFI_ERROR (Status)) {
431     return Status;
432   }
433 
434   //
435   // Now further check the PCI header: Base class (offset 0x08) and
436   // Sub Class (offset 0x05). This controller should be an SD/MMC PCI
437   // Host Controller.
438   //
439   Status = PciIo->Pci.Read (
440                         PciIo,
441                         EfiPciIoWidthUint8,
442                         0,
443                         sizeof (PciData),
444                         &PciData
445                         );
446   if (EFI_ERROR (Status)) {
447     gBS->CloseProtocol (
448           Controller,
449           &gEfiPciIoProtocolGuid,
450           This->DriverBindingHandle,
451           Controller
452           );
453     return EFI_UNSUPPORTED;
454   }
455   //
456   // Since we already got the PciData, we can close protocol to avoid to carry it
457   // on for multiple exit points.
458   //
459   gBS->CloseProtocol (
460         Controller,
461         &gEfiPciIoProtocolGuid,
462         This->DriverBindingHandle,
463         Controller
464         );
465 
466   //
467   // Examine SD PCI Host Controller PCI Configuration table fields.
468   //
469   if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_SYSTEM_PERIPHERAL) &&
470       (PciData.Hdr.ClassCode[1] == PCI_SUBCLASS_SD_HOST_CONTROLLER) &&
471       ((PciData.Hdr.ClassCode[0] == 0x00) || (PciData.Hdr.ClassCode[0] == 0x01))) {
472     return EFI_SUCCESS;
473   }
474 
475   return EFI_UNSUPPORTED;
476 }
477 
478 /**
479   Starts a device controller or a bus controller.
480 
481   The Start() function is designed to be invoked from the EFI boot service ConnectController().
482   As a result, much of the error checking on the parameters to Start() has been moved into this
483   common boot service. It is legal to call Start() from other locations,
484   but the following calling restrictions must be followed or the system behavior will not be deterministic.
485   1. ControllerHandle must be a valid EFI_HANDLE.
486   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
487      EFI_DEVICE_PATH_PROTOCOL.
488   3. Prior to calling Start(), the Supported() function for the driver specified by This must
489      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
490 
491   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
492   @param[in]  ControllerHandle     The handle of the controller to start. This handle
493                                    must support a protocol interface that supplies
494                                    an I/O abstraction to the driver.
495   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
496                                    parameter is ignored by device drivers, and is optional for bus
497                                    drivers. For a bus driver, if this parameter is NULL, then handles
498                                    for all the children of Controller are created by this driver.
499                                    If this parameter is not NULL and the first Device Path Node is
500                                    not the End of Device Path Node, then only the handle for the
501                                    child device specified by the first Device Path Node of
502                                    RemainingDevicePath is created by this driver.
503                                    If the first Device Path Node of RemainingDevicePath is
504                                    the End of Device Path Node, no child handle is created by this
505                                    driver.
506 
507   @retval EFI_SUCCESS              The device was started.
508   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
509   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
510   @retval Others                   The driver failded to start the device.
511 
512 **/
513 EFI_STATUS
514 EFIAPI
SdMmcPciHcDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)515 SdMmcPciHcDriverBindingStart (
516   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
517   IN EFI_HANDLE                      Controller,
518   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
519   )
520 {
521   EFI_STATUS                      Status;
522   SD_MMC_HC_PRIVATE_DATA          *Private;
523   EFI_PCI_IO_PROTOCOL             *PciIo;
524   UINT64                          Supports;
525   UINT64                          PciAttributes;
526   UINT8                           Slot;
527   UINT8                           Index;
528   CARD_TYPE_DETECT_ROUTINE        *Routine;
529   UINT32                          RoutineNum;
530   BOOLEAN                         Support64BitDma;
531 
532   DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: Start\n"));
533 
534   //
535   // Open PCI I/O Protocol and save pointer to open protocol
536   // in private data area.
537   //
538   PciIo  = NULL;
539   Status = gBS->OpenProtocol (
540                   Controller,
541                   &gEfiPciIoProtocolGuid,
542                   (VOID **) &PciIo,
543                   This->DriverBindingHandle,
544                   Controller,
545                   EFI_OPEN_PROTOCOL_BY_DRIVER
546                   );
547   if (EFI_ERROR (Status)) {
548     return Status;
549   }
550 
551   //
552   // Enable the SD Host Controller MMIO space
553   //
554   Private = NULL;
555   Status  = PciIo->Attributes (
556                      PciIo,
557                      EfiPciIoAttributeOperationGet,
558                      0,
559                      &PciAttributes
560                      );
561 
562   if (EFI_ERROR (Status)) {
563     goto Done;
564   }
565 
566   Status = PciIo->Attributes (
567                     PciIo,
568                     EfiPciIoAttributeOperationSupported,
569                     0,
570                     &Supports
571                     );
572 
573   if (!EFI_ERROR (Status)) {
574     Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
575     Status    = PciIo->Attributes (
576                          PciIo,
577                          EfiPciIoAttributeOperationEnable,
578                          Supports,
579                          NULL
580                          );
581   } else {
582     goto Done;
583   }
584 
585   Private = AllocateCopyPool (sizeof (SD_MMC_HC_PRIVATE_DATA), &gSdMmcPciHcTemplate);
586   if (Private == NULL) {
587     Status = EFI_OUT_OF_RESOURCES;
588     goto Done;
589   }
590 
591   Private->ControllerHandle = Controller;
592   Private->PciIo            = PciIo;
593   Private->PciAttributes    = PciAttributes;
594   InitializeListHead (&Private->Queue);
595 
596   Support64BitDma = TRUE;
597 
598   //
599   // There is only one slot 0 on Xenon
600   //
601   Slot = 0;
602   Private->Slot[Slot].Enable = TRUE;
603 
604   Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]);
605   if (EFI_ERROR (Status)) {
606     return Status;
607   }
608 
609   Support64BitDma &= Private->Capability[Slot].SysBus64;
610 
611   //
612   // Override capabilities structure - only 4 Bit width bus is supported
613   // by HW and also force using SDR25 mode
614   //
615   Private->Capability[Slot].Sdr104 = 0;
616   Private->Capability[Slot].Ddr50 = 0;
617   Private->Capability[Slot].Sdr50 = 0;
618   Private->Capability[Slot].BusWidth8 = 0;
619 
620   if (Private->Capability[Slot].BaseClkFreq == 0) {
621     Private->Capability[Slot].BaseClkFreq = 0xff;
622   }
623 
624   DumpCapabilityReg (Slot, &Private->Capability[Slot]);
625 
626   Status = SdMmcHcGetMaxCurrent (PciIo, Slot, &Private->MaxCurrent[Slot]);
627   if (EFI_ERROR (Status)) {
628     return Status;
629   }
630 
631   Private->Slot[Slot].SlotType = Private->Capability[Slot].SlotType;
632   if ((Private->Slot[Slot].SlotType != RemovableSlot) && (Private->Slot[Slot].SlotType != EmbeddedSlot)) {
633     DEBUG ((DEBUG_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType));
634     return EFI_D_ERROR;
635   }
636 
637   //
638   // Perform Xenon-specific init sequence
639   //
640   XenonInit (Private);
641 
642   //
643   // Initialize HC timeout control
644   //
645   Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot);
646   if (EFI_ERROR (Status)) {
647     return Status;
648   }
649 
650   Private->Slot[Slot].MediaPresent = TRUE;
651   Private->Slot[Slot].Initialized  = TRUE;
652   RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
653   for (Index = 0; Index < RoutineNum; Index++) {
654     Routine = &mCardTypeDetectRoutineTable[Index];
655     if (*Routine != NULL) {
656       Status = (*Routine) (Private, Slot);
657       if (!EFI_ERROR (Status)) {
658         break;
659       }
660     }
661   }
662   //
663   // This card doesn't get initialized correctly.
664   //
665   if (Index == RoutineNum) {
666     Private->Slot[Slot].Initialized = FALSE;
667   }
668 
669   //
670   // Enable 64-bit DMA support in the PCI layer if this controller
671   // supports it.
672   //
673   if (Support64BitDma) {
674     Status = PciIo->Attributes (
675                       PciIo,
676                       EfiPciIoAttributeOperationEnable,
677                       EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
678                       NULL
679                       );
680     if (EFI_ERROR (Status)) {
681       DEBUG ((DEBUG_WARN, "SdMmcPciHcDriverBindingStart: failed to enable 64-bit DMA (%r)\n", Status));
682     }
683   }
684 
685   //
686   // Start the asynchronous I/O monitor
687   //
688   Status = gBS->CreateEvent (
689                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
690                   TPL_NOTIFY,
691                   ProcessAsyncTaskList,
692                   Private,
693                   &Private->TimerEvent
694                   );
695   if (EFI_ERROR (Status)) {
696     goto Done;
697   }
698 
699   Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, SD_MMC_HC_ASYNC_TIMER);
700   if (EFI_ERROR (Status)) {
701     goto Done;
702   }
703 
704   //
705   // Start the Sd removable device connection enumeration
706   //
707   Status = gBS->CreateEvent (
708                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
709                   TPL_CALLBACK,
710                   SdMmcPciHcEnumerateDevice,
711                   Private,
712                   &Private->ConnectEvent
713                   );
714   if (EFI_ERROR (Status)) {
715     goto Done;
716   }
717 
718   Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, SD_MMC_HC_ENUM_TIMER);
719   if (EFI_ERROR (Status)) {
720     goto Done;
721   }
722 
723   Status = gBS->InstallMultipleProtocolInterfaces (
724                   &Controller,
725                   &gEfiSdMmcPassThruProtocolGuid,
726                   &(Private->PassThru),
727                   NULL
728                   );
729 
730   DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: %r End on %x\n", Status, Controller));
731 
732 Done:
733   if (EFI_ERROR (Status)) {
734     if ((Private != NULL) && (Private->PciAttributes != 0)) {
735       //
736       // Restore original PCI attributes
737       //
738       PciIo->Attributes (
739                PciIo,
740                EfiPciIoAttributeOperationSet,
741                Private->PciAttributes,
742                NULL
743                );
744     }
745     gBS->CloseProtocol (
746           Controller,
747           &gEfiPciIoProtocolGuid,
748           This->DriverBindingHandle,
749           Controller
750           );
751 
752     if ((Private != NULL) && (Private->TimerEvent != NULL)) {
753       gBS->CloseEvent (Private->TimerEvent);
754     }
755 
756     if ((Private != NULL) && (Private->ConnectEvent != NULL)) {
757       gBS->CloseEvent (Private->ConnectEvent);
758     }
759 
760     if (Private != NULL) {
761       FreePool (Private);
762     }
763   }
764 
765   return Status;
766 }
767 
768 /**
769   Stops a device controller or a bus controller.
770 
771   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
772   As a result, much of the error checking on the parameters to Stop() has been moved
773   into this common boot service. It is legal to call Stop() from other locations,
774   but the following calling restrictions must be followed or the system behavior will not be deterministic.
775   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
776      same driver's Start() function.
777   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
778      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
779      Start() function, and the Start() function must have called OpenProtocol() on
780      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
781 
782   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
783   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
784                                 support a bus specific I/O protocol for the driver
785                                 to use to stop the device.
786   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
787   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
788                                 if NumberOfChildren is 0.
789 
790   @retval EFI_SUCCESS           The device was stopped.
791   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
792 
793 **/
794 EFI_STATUS
795 EFIAPI
SdMmcPciHcDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)796 SdMmcPciHcDriverBindingStop (
797   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
798   IN  EFI_HANDLE                      Controller,
799   IN  UINTN                           NumberOfChildren,
800   IN  EFI_HANDLE                      *ChildHandleBuffer
801   )
802 {
803   EFI_STATUS                          Status;
804   EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;
805   SD_MMC_HC_PRIVATE_DATA              *Private;
806   EFI_PCI_IO_PROTOCOL                 *PciIo;
807   LIST_ENTRY                          *Link;
808   LIST_ENTRY                          *NextLink;
809   SD_MMC_HC_TRB                       *Trb;
810 
811   DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: Start\n"));
812 
813   Status = gBS->OpenProtocol (
814                   Controller,
815                   &gEfiSdMmcPassThruProtocolGuid,
816                   (VOID**) &PassThru,
817                   This->DriverBindingHandle,
818                   Controller,
819                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
820                   );
821   if (EFI_ERROR (Status)) {
822     return Status;
823   }
824 
825   Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
826   //
827   // Close Non-Blocking timer and free Task list.
828   //
829   if (Private->TimerEvent != NULL) {
830     gBS->CloseEvent (Private->TimerEvent);
831     Private->TimerEvent = NULL;
832   }
833   if (Private->ConnectEvent != NULL) {
834     gBS->CloseEvent (Private->ConnectEvent);
835     Private->ConnectEvent = NULL;
836   }
837   //
838   // As the timer is closed, there is no needs to use TPL lock to
839   // protect the critical region "queue".
840   //
841   for (Link = GetFirstNode (&Private->Queue);
842        !IsNull (&Private->Queue, Link);
843        Link = NextLink) {
844     NextLink = GetNextNode (&Private->Queue, Link);
845     RemoveEntryList (Link);
846     Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
847     Trb->Packet->TransactionStatus = EFI_ABORTED;
848     gBS->SignalEvent (Trb->Event);
849     SdMmcFreeTrb (Trb);
850   }
851 
852   //
853   // Uninstall Block I/O protocol from the device handle
854   //
855   Status = gBS->UninstallProtocolInterface (
856                   Controller,
857                   &gEfiSdMmcPassThruProtocolGuid,
858                   &(Private->PassThru)
859                   );
860 
861   if (EFI_ERROR (Status)) {
862     return Status;
863   }
864 
865   gBS->CloseProtocol (
866          Controller,
867          &gEfiPciIoProtocolGuid,
868          This->DriverBindingHandle,
869          Controller
870          );
871   //
872   // Restore original PCI attributes
873   //
874   PciIo  = Private->PciIo;
875   Status = PciIo->Attributes (
876                     PciIo,
877                     EfiPciIoAttributeOperationSet,
878                     Private->PciAttributes,
879                     NULL
880                     );
881   ASSERT_EFI_ERROR (Status);
882 
883   FreePool (Private);
884 
885   DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: End with %r\n", Status));
886 
887   return Status;
888 }
889 
890 /**
891   Sends SD command to an SD card that is attached to the SD controller.
892 
893   The PassThru() function sends the SD command specified by Packet to the SD card
894   specified by Slot.
895 
896   If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
897 
898   If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
899 
900   If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER
901   is returned.
902 
903   If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
904   EFI_INVALID_PARAMETER is returned.
905 
906   @param[in]     This           A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
907   @param[in]     Slot           The slot number of the SD card to send the command to.
908   @param[in,out] Packet         A pointer to the SD command data structure.
909   @param[in]     Event          If Event is NULL, blocking I/O is performed. If Event is
910                                 not NULL, then nonblocking I/O is performed, and Event
911                                 will be signaled when the Packet completes.
912 
913   @retval EFI_SUCCESS           The SD Command Packet was sent by the host.
914   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SD
915                                 command Packet.
916   @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
917   @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
918                                 OutDataBuffer are NULL.
919   @retval EFI_NO_MEDIA          SD Device not present in the Slot.
920   @retval EFI_UNSUPPORTED       The command described by the SD Command Packet is not
921                                 supported by the host controller.
922   @retval EFI_BAD_BUFFER_SIZE   The InTransferLength or OutTransferLength exceeds the
923                                 limit supported by SD card ( i.e. if the number of bytes
924                                 exceed the Last LBA).
925 
926 **/
927 EFI_STATUS
928 EFIAPI
SdMmcPassThruPassThru(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN UINT8 Slot,IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET * Packet,IN EFI_EVENT Event OPTIONAL)929 SdMmcPassThruPassThru (
930   IN     EFI_SD_MMC_PASS_THRU_PROTOCOL         *This,
931   IN     UINT8                                 Slot,
932   IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   *Packet,
933   IN     EFI_EVENT                             Event    OPTIONAL
934   )
935 {
936   EFI_STATUS                      Status;
937   SD_MMC_HC_PRIVATE_DATA          *Private;
938   SD_MMC_HC_TRB                   *Trb;
939   EFI_TPL                         OldTpl;
940 
941   if ((This == NULL) || (Packet == NULL)) {
942     return EFI_INVALID_PARAMETER;
943   }
944 
945   if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) {
946     return EFI_INVALID_PARAMETER;
947   }
948 
949   if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
950     return EFI_INVALID_PARAMETER;
951   }
952 
953   if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
954     return EFI_INVALID_PARAMETER;
955   }
956 
957   Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
958 
959   if (!Private->Slot[Slot].Enable) {
960     return EFI_INVALID_PARAMETER;
961   }
962 
963   if (!Private->Slot[Slot].MediaPresent) {
964     return EFI_NO_MEDIA;
965   }
966 
967   if (!Private->Slot[Slot].Initialized) {
968     return EFI_DEVICE_ERROR;
969   }
970 
971   Trb = SdMmcCreateTrb (Private, Slot, Packet, Event);
972   if (Trb == NULL) {
973     return EFI_OUT_OF_RESOURCES;
974   }
975   //
976   // Immediately return for async I/O.
977   //
978   if (Event != NULL) {
979     return EFI_SUCCESS;
980   }
981 
982   //
983   // Wait async I/O list is empty before execute sync I/O operation.
984   //
985   while (TRUE) {
986     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
987     if (IsListEmpty (&Private->Queue)) {
988       gBS->RestoreTPL (OldTpl);
989       break;
990     }
991     gBS->RestoreTPL (OldTpl);
992   }
993 
994   Status = SdMmcWaitTrbEnv (Private, Trb);
995   if (EFI_ERROR (Status)) {
996     goto Done;
997   }
998 
999   Status = SdMmcExecTrb (Private, Trb);
1000   if (EFI_ERROR (Status)) {
1001     goto Done;
1002   }
1003 
1004   Status = SdMmcWaitTrbResult (Private, Trb);
1005   if (EFI_ERROR (Status)) {
1006     goto Done;
1007   }
1008 
1009 Done:
1010   if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {
1011     FreePages (Trb->AdmaDesc, Trb->AdmaPages);
1012   }
1013 
1014   if (Trb != NULL) {
1015     FreePool (Trb);
1016   }
1017 
1018   return Status;
1019 }
1020 
1021 /**
1022   Used to retrieve next slot numbers supported by the SD controller. The function
1023   returns information about all available slots (populated or not-populated).
1024 
1025   The GetNextSlot() function retrieves the next slot number on an SD controller.
1026   If on input Slot is 0xFF, then the slot number of the first slot on the SD controller
1027   is returned.
1028 
1029   If Slot is a slot number that was returned on a previous call to GetNextSlot(), then
1030   the slot number of the next slot on the SD controller is returned.
1031 
1032   If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),
1033   EFI_INVALID_PARAMETER is returned.
1034 
1035   If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND
1036   is returned.
1037 
1038   @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
1039   @param[in,out] Slot           On input, a pointer to a slot number on the SD controller.
1040                                 On output, a pointer to the next slot number on the SD controller.
1041                                 An input value of 0xFF retrieves the first slot number on the SD
1042                                 controller.
1043 
1044   @retval EFI_SUCCESS           The next slot number on the SD controller was returned in Slot.
1045   @retval EFI_NOT_FOUND         There are no more slots on this SD controller.
1046   @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call
1047                                 to GetNextSlot().
1048 
1049 **/
1050 EFI_STATUS
1051 EFIAPI
SdMmcPassThruGetNextSlot(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN OUT UINT8 * Slot)1052 SdMmcPassThruGetNextSlot (
1053   IN     EFI_SD_MMC_PASS_THRU_PROTOCOL        *This,
1054   IN OUT UINT8                                *Slot
1055   )
1056 {
1057   SD_MMC_HC_PRIVATE_DATA          *Private;
1058   UINT8                           Index;
1059 
1060   if ((This == NULL) || (Slot == NULL)) {
1061     return EFI_INVALID_PARAMETER;
1062   }
1063 
1064   Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
1065 
1066   if (*Slot == 0xFF) {
1067     for (Index = 0; Index < SD_MMC_HC_MAX_SLOT; Index++) {
1068       if (Private->Slot[Index].Enable) {
1069         *Slot = Index;
1070         Private->PreviousSlot = Index;
1071         return EFI_SUCCESS;
1072       }
1073     }
1074     return EFI_NOT_FOUND;
1075   } else if (*Slot == Private->PreviousSlot) {
1076     for (Index = *Slot + 1; Index < SD_MMC_HC_MAX_SLOT; Index++) {
1077       if (Private->Slot[Index].Enable) {
1078         *Slot = Index;
1079         Private->PreviousSlot = Index;
1080         return EFI_SUCCESS;
1081       }
1082     }
1083     return EFI_NOT_FOUND;
1084   } else {
1085     return EFI_INVALID_PARAMETER;
1086   }
1087 }
1088 
1089 /**
1090   Used to allocate and build a device path node for an SD card on the SD controller.
1091 
1092   The BuildDevicePath() function allocates and builds a single device node for the SD
1093   card specified by Slot.
1094 
1095   If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND
1096   is returned.
1097 
1098   If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
1099 
1100   If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES
1101   is returned.
1102 
1103   Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
1104   DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is
1105   returned.
1106 
1107   @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
1108   @param[in]     Slot           Specifies the slot number of the SD card for which a device
1109                                 path node is to be allocated and built.
1110   @param[in,out] DevicePath     A pointer to a single device path node that describes the SD
1111                                 card specified by Slot. This function is responsible for
1112                                 allocating the buffer DevicePath with the boot service
1113                                 AllocatePool(). It is the caller's responsibility to free
1114                                 DevicePath when the caller is finished with DevicePath.
1115 
1116   @retval EFI_SUCCESS           The device path node that describes the SD card specified by
1117                                 Slot was allocated and returned in DevicePath.
1118   @retval EFI_NOT_FOUND         The SD card specified by Slot does not exist on the SD controller.
1119   @retval EFI_INVALID_PARAMETER DevicePath is NULL.
1120   @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate DevicePath.
1121 
1122 **/
1123 EFI_STATUS
1124 EFIAPI
SdMmcPassThruBuildDevicePath(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN UINT8 Slot,IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)1125 SdMmcPassThruBuildDevicePath (
1126   IN     EFI_SD_MMC_PASS_THRU_PROTOCOL       *This,
1127   IN     UINT8                               Slot,
1128   IN OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
1129   )
1130 {
1131   SD_MMC_HC_PRIVATE_DATA          *Private;
1132   SD_DEVICE_PATH                  *SdNode;
1133   EMMC_DEVICE_PATH                *EmmcNode;
1134 
1135   if ((This == NULL) || (DevicePath == NULL) || (Slot >= SD_MMC_HC_MAX_SLOT)) {
1136     return EFI_INVALID_PARAMETER;
1137   }
1138 
1139   Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
1140 
1141   if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {
1142     return EFI_NOT_FOUND;
1143   }
1144 
1145   if (Private->Slot[Slot].CardType == SdCardType) {
1146     SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate);
1147     if (SdNode == NULL) {
1148       return EFI_OUT_OF_RESOURCES;
1149     }
1150     SdNode->SlotNumber = Slot;
1151 
1152     *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;
1153   } else if (Private->Slot[Slot].CardType == EmmcCardType) {
1154     EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate);
1155     if (EmmcNode == NULL) {
1156       return EFI_OUT_OF_RESOURCES;
1157     }
1158     EmmcNode->SlotNumber = Slot;
1159 
1160     *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;
1161   } else {
1162     //
1163     // Currently we only support SD and EMMC two device nodes.
1164     //
1165     return EFI_NOT_FOUND;
1166   }
1167 
1168   return EFI_SUCCESS;
1169 }
1170 
1171 /**
1172   This function retrieves an SD card slot number based on the input device path.
1173 
1174   The GetSlotNumber() function retrieves slot number for the SD card specified by
1175   the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.
1176 
1177   If DevicePath is not a device path node type that the SD Pass Thru driver supports,
1178   EFI_UNSUPPORTED is returned.
1179 
1180   @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
1181   @param[in]  DevicePath        A pointer to the device path node that describes a SD
1182                                 card on the SD controller.
1183   @param[out] Slot              On return, points to the slot number of an SD card on
1184                                 the SD controller.
1185 
1186   @retval EFI_SUCCESS           SD card slot number is returned in Slot.
1187   @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
1188   @retval EFI_UNSUPPORTED       DevicePath is not a device path node type that the SD
1189                                 Pass Thru driver supports.
1190 
1191 **/
1192 EFI_STATUS
1193 EFIAPI
SdMmcPassThruGetSlotNumber(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT UINT8 * Slot)1194 SdMmcPassThruGetSlotNumber (
1195   IN  EFI_SD_MMC_PASS_THRU_PROTOCOL          *This,
1196   IN  EFI_DEVICE_PATH_PROTOCOL               *DevicePath,
1197   OUT UINT8                                  *Slot
1198   )
1199 {
1200   SD_MMC_HC_PRIVATE_DATA          *Private;
1201   SD_DEVICE_PATH                  *SdNode;
1202   EMMC_DEVICE_PATH                *EmmcNode;
1203   UINT8                           SlotNumber;
1204 
1205   if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {
1206     return EFI_INVALID_PARAMETER;
1207   }
1208 
1209   Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
1210 
1211   //
1212   // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH
1213   //
1214   if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
1215       ((DevicePath->SubType != MSG_SD_DP) &&
1216        (DevicePath->SubType != MSG_EMMC_DP)) ||
1217       (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||
1218       (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) {
1219     return EFI_UNSUPPORTED;
1220   }
1221 
1222   if (DevicePath->SubType == MSG_SD_DP) {
1223     SdNode = (SD_DEVICE_PATH *) DevicePath;
1224     SlotNumber = SdNode->SlotNumber;
1225   } else {
1226     EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;
1227     SlotNumber = EmmcNode->SlotNumber;
1228   }
1229 
1230   if (SlotNumber >= SD_MMC_HC_MAX_SLOT) {
1231     return EFI_NOT_FOUND;
1232   }
1233 
1234   if (Private->Slot[SlotNumber].Enable) {
1235     *Slot = SlotNumber;
1236     return EFI_SUCCESS;
1237   } else {
1238     return EFI_NOT_FOUND;
1239   }
1240 }
1241 
1242 /**
1243   Resets an SD card that is connected to the SD controller.
1244 
1245   The ResetDevice() function resets the SD card specified by Slot.
1246 
1247   If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is
1248   returned.
1249 
1250   If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER
1251   is returned.
1252 
1253   If the device reset operation is completed, EFI_SUCCESS is returned.
1254 
1255   @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
1256   @param[in]  Slot              Specifies the slot number of the SD card to be reset.
1257 
1258   @retval EFI_SUCCESS           The SD card specified by Slot was reset.
1259   @retval EFI_UNSUPPORTED       The SD controller does not support a device reset operation.
1260   @retval EFI_INVALID_PARAMETER Slot number is invalid.
1261   @retval EFI_NO_MEDIA          SD Device not present in the Slot.
1262   @retval EFI_DEVICE_ERROR      The reset command failed due to a device error
1263 
1264 **/
1265 EFI_STATUS
1266 EFIAPI
SdMmcPassThruResetDevice(IN EFI_SD_MMC_PASS_THRU_PROTOCOL * This,IN UINT8 Slot)1267 SdMmcPassThruResetDevice (
1268   IN EFI_SD_MMC_PASS_THRU_PROTOCOL           *This,
1269   IN UINT8                                   Slot
1270   )
1271 {
1272   SD_MMC_HC_PRIVATE_DATA          *Private;
1273   LIST_ENTRY                      *Link;
1274   LIST_ENTRY                      *NextLink;
1275   SD_MMC_HC_TRB                   *Trb;
1276   EFI_TPL                         OldTpl;
1277 
1278   if (This == NULL) {
1279     return EFI_INVALID_PARAMETER;
1280   }
1281 
1282   Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
1283 
1284   if (!Private->Slot[Slot].Enable) {
1285     return EFI_INVALID_PARAMETER;
1286   }
1287 
1288   if (!Private->Slot[Slot].MediaPresent) {
1289     return EFI_NO_MEDIA;
1290   }
1291 
1292   if (!Private->Slot[Slot].Initialized) {
1293     return EFI_DEVICE_ERROR;
1294   }
1295   //
1296   // Free all async I/O requests in the queue
1297   //
1298   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1299 
1300   for (Link = GetFirstNode (&Private->Queue);
1301        !IsNull (&Private->Queue, Link);
1302        Link = NextLink) {
1303     NextLink = GetNextNode (&Private->Queue, Link);
1304     RemoveEntryList (Link);
1305     Trb = SD_MMC_HC_TRB_FROM_THIS (Link);
1306     Trb->Packet->TransactionStatus = EFI_ABORTED;
1307     gBS->SignalEvent (Trb->Event);
1308     SdMmcFreeTrb (Trb);
1309   }
1310 
1311   gBS->RestoreTPL (OldTpl);
1312 
1313   return EFI_SUCCESS;
1314 }
1315 
1316