Coverage Report

Created: 2026-04-21 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
Line
Count
Source
1
/** @file
2
Usb Hub Request Support In PEI Phase
3
4
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5
6
SPDX-License-Identifier: BSD-2-Clause-Patent
7
8
**/
9
10
#include "UsbPeim.h"
11
#include "HubPeim.h"
12
#include "PeiUsbLib.h"
13
14
/**
15
  Get a given hub port status.
16
17
  @param  PeiServices   General-purpose services that are available to every PEIM.
18
  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
19
  @param  Port          Usb hub port number (starting from 1).
20
  @param  PortStatus    Current Hub port status and change status.
21
22
  @retval EFI_SUCCESS       Port status is obtained successfully.
23
  @retval EFI_DEVICE_ERROR  Cannot get the port status due to a hardware error.
24
  @retval Others            Other failure occurs.
25
26
**/
27
EFI_STATUS
28
PeiHubGetPortStatus (
29
  IN  EFI_PEI_SERVICES  **PeiServices,
30
  IN  PEI_USB_IO_PPI    *UsbIoPpi,
31
  IN  UINT8             Port,
32
  OUT UINT32            *PortStatus
33
  )
34
0
{
35
0
  EFI_USB_DEVICE_REQUEST  DeviceRequest;
36
37
0
  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
38
39
  //
40
  // Fill Device request packet
41
  //
42
0
  DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE;
43
0
  DeviceRequest.Request     = USB_HUB_GET_PORT_STATUS;
44
0
  DeviceRequest.Index       = Port;
45
0
  DeviceRequest.Length      = (UINT16)sizeof (UINT32);
46
47
0
  return UsbIoPpi->UsbControlTransfer (
48
0
                     PeiServices,
49
0
                     UsbIoPpi,
50
0
                     &DeviceRequest,
51
0
                     EfiUsbDataIn,
52
0
                     PcdGet32 (PcdUsbTransferTimeoutValue),
53
0
                     PortStatus,
54
0
                     sizeof (UINT32)
55
0
                     );
56
0
}
57
58
/**
59
  Set specified feature to a given hub port.
60
61
  @param  PeiServices   General-purpose services that are available to every PEIM.
62
  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
63
  @param  Port          Usb hub port number (starting from 1).
64
  @param  Value         New feature value.
65
66
  @retval EFI_SUCCESS       Port feature is set successfully.
67
  @retval EFI_DEVICE_ERROR  Cannot set the port feature due to a hardware error.
68
  @retval Others            Other failure occurs.
69
70
**/
71
EFI_STATUS
72
PeiHubSetPortFeature (
73
  IN EFI_PEI_SERVICES  **PeiServices,
74
  IN PEI_USB_IO_PPI    *UsbIoPpi,
75
  IN UINT8             Port,
76
  IN UINT8             Value
77
  )
78
0
{
79
0
  EFI_USB_DEVICE_REQUEST  DeviceRequest;
80
81
0
  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
82
83
  //
84
  // Fill Device request packet
85
  //
86
0
  DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE;
87
0
  DeviceRequest.Request     = USB_HUB_SET_PORT_FEATURE;
88
0
  DeviceRequest.Value       = Value;
89
0
  DeviceRequest.Index       = Port;
90
91
0
  return UsbIoPpi->UsbControlTransfer (
92
0
                     PeiServices,
93
0
                     UsbIoPpi,
94
0
                     &DeviceRequest,
95
0
                     EfiUsbNoData,
96
0
                     PcdGet32 (PcdUsbTransferTimeoutValue),
97
0
                     NULL,
98
0
                     0
99
0
                     );
100
0
}
101
102
/**
103
  Clear specified feature on a given hub port.
104
105
  @param  PeiServices   General-purpose services that are available to every PEIM.
106
  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
107
  @param  Port          Usb hub port number (starting from 1).
108
  @param  Value         Feature value that will be cleared from the hub port.
109
110
  @retval EFI_SUCCESS       Port feature is cleared successfully.
111
  @retval EFI_DEVICE_ERROR  Cannot clear the port feature due to a hardware error.
112
  @retval Others            Other failure occurs.
113
114
**/
115
EFI_STATUS
116
PeiHubClearPortFeature (
117
  IN EFI_PEI_SERVICES  **PeiServices,
118
  IN PEI_USB_IO_PPI    *UsbIoPpi,
119
  IN UINT8             Port,
120
  IN UINT8             Value
121
  )
122
0
{
123
0
  EFI_USB_DEVICE_REQUEST  DeviceRequest;
124
125
0
  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
126
127
  //
128
  // Fill Device request packet
129
  //
130
0
  DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE;
131
0
  DeviceRequest.Request     = USB_HUB_CLEAR_FEATURE_PORT;
132
0
  DeviceRequest.Value       = Value;
133
0
  DeviceRequest.Index       = Port;
134
135
0
  return UsbIoPpi->UsbControlTransfer (
136
0
                     PeiServices,
137
0
                     UsbIoPpi,
138
0
                     &DeviceRequest,
139
0
                     EfiUsbNoData,
140
0
                     PcdGet32 (PcdUsbTransferTimeoutValue),
141
0
                     NULL,
142
0
                     0
143
0
                     );
144
0
}
145
146
/**
147
  Get a given hub status.
148
149
  @param  PeiServices   General-purpose services that are available to every PEIM.
150
  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
151
  @param  HubStatus     Current Hub status and change status.
152
153
  @retval EFI_SUCCESS       Hub status is obtained successfully.
154
  @retval EFI_DEVICE_ERROR  Cannot get the hub status due to a hardware error.
155
  @retval Others            Other failure occurs.
156
157
**/
158
EFI_STATUS
159
PeiHubGetHubStatus (
160
  IN  EFI_PEI_SERVICES  **PeiServices,
161
  IN  PEI_USB_IO_PPI    *UsbIoPpi,
162
  OUT UINT32            *HubStatus
163
  )
164
0
{
165
0
  EFI_USB_DEVICE_REQUEST  DeviceRequest;
166
167
0
  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
168
169
  //
170
  // Fill Device request packet
171
  //
172
0
  DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE;
173
0
  DeviceRequest.Request     = USB_HUB_GET_HUB_STATUS;
174
0
  DeviceRequest.Length      = (UINT16)sizeof (UINT32);
175
176
0
  return UsbIoPpi->UsbControlTransfer (
177
0
                     PeiServices,
178
0
                     UsbIoPpi,
179
0
                     &DeviceRequest,
180
0
                     EfiUsbDataIn,
181
0
                     PcdGet32 (PcdUsbTransferTimeoutValue),
182
0
                     HubStatus,
183
0
                     sizeof (UINT32)
184
0
                     );
185
0
}
186
187
/**
188
  Clear specified feature on a given hub.
189
190
  @param  PeiServices   General-purpose services that are available to every PEIM.
191
  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
192
  @param  Value         Feature value that will be cleared from the hub port.
193
194
  @retval EFI_SUCCESS       Hub feature is cleared successfully.
195
  @retval EFI_DEVICE_ERROR  Cannot clear the hub feature due to a hardware error.
196
  @retval Others            Other failure occurs.
197
198
**/
199
EFI_STATUS
200
PeiHubClearHubFeature (
201
  IN EFI_PEI_SERVICES  **PeiServices,
202
  IN PEI_USB_IO_PPI    *UsbIoPpi,
203
  IN UINT8             Value
204
  )
205
0
{
206
0
  EFI_USB_DEVICE_REQUEST  DeviceRequest;
207
208
0
  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));
209
210
  //
211
  // Fill Device request packet
212
  //
213
0
  DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE;
214
0
  DeviceRequest.Request     = USB_HUB_CLEAR_FEATURE;
215
0
  DeviceRequest.Value       = Value;
216
217
0
  return UsbIoPpi->UsbControlTransfer (
218
0
                     PeiServices,
219
0
                     UsbIoPpi,
220
0
                     &DeviceRequest,
221
0
                     EfiUsbNoData,
222
0
                     PcdGet32 (PcdUsbTransferTimeoutValue),
223
0
                     NULL,
224
0
                     0
225
0
                     );
226
0
}
227
228
/**
229
  Get a given (SuperSpeed) hub descriptor.
230
231
  @param  PeiServices    General-purpose services that are available to every PEIM.
232
  @param  PeiUsbDevice   Indicates the hub controller device.
233
  @param  UsbIoPpi       Indicates the PEI_USB_IO_PPI instance.
234
  @param  DescriptorSize The length of Hub Descriptor buffer.
235
  @param  HubDescriptor  Caller allocated buffer to store the hub descriptor if
236
                         successfully returned.
237
238
  @retval EFI_SUCCESS       Hub descriptor is obtained successfully.
239
  @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.
240
  @retval Others            Other failure occurs.
241
242
**/
243
EFI_STATUS
244
PeiGetHubDescriptor (
245
  IN  EFI_PEI_SERVICES        **PeiServices,
246
  IN  PEI_USB_DEVICE          *PeiUsbDevice,
247
  IN  PEI_USB_IO_PPI          *UsbIoPpi,
248
  IN  UINTN                   DescriptorSize,
249
  OUT EFI_USB_HUB_DESCRIPTOR  *HubDescriptor
250
  )
251
0
{
252
0
  EFI_USB_DEVICE_REQUEST  DevReq;
253
0
  UINT8                   DescType;
254
255
0
  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
256
257
0
  DescType = (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) ?
258
0
             USB_DT_SUPERSPEED_HUB :
259
0
             USB_DT_HUB;
260
261
  //
262
  // Fill Device request packet
263
  //
264
0
  DevReq.RequestType = USB_RT_HUB | 0x80;
265
0
  DevReq.Request     = USB_HUB_GET_DESCRIPTOR;
266
0
  DevReq.Value       = (UINT16)(DescType << 8);
267
0
  DevReq.Length      = (UINT16)DescriptorSize;
268
269
0
  return UsbIoPpi->UsbControlTransfer (
270
0
                     PeiServices,
271
0
                     UsbIoPpi,
272
0
                     &DevReq,
273
0
                     EfiUsbDataIn,
274
0
                     PcdGet32 (PcdUsbTransferTimeoutValue),
275
0
                     HubDescriptor,
276
0
                     (UINT16)DescriptorSize
277
0
                     );
278
0
}
279
280
/**
281
  Read the whole usb hub descriptor. It is necessary
282
  to do it in two steps because hub descriptor is of
283
  variable length.
284
285
  @param  PeiServices       General-purpose services that are available to every PEIM.
286
  @param  PeiUsbDevice      Indicates the hub controller device.
287
  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.
288
  @param  HubDescriptor     Caller allocated buffer to store the hub descriptor if
289
                            successfully returned.
290
291
  @retval EFI_SUCCESS       Hub descriptor is obtained successfully.
292
  @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.
293
  @retval Others            Other failure occurs.
294
295
**/
296
EFI_STATUS
297
PeiUsbHubReadDesc (
298
  IN EFI_PEI_SERVICES         **PeiServices,
299
  IN PEI_USB_DEVICE           *PeiUsbDevice,
300
  IN PEI_USB_IO_PPI           *UsbIoPpi,
301
  OUT EFI_USB_HUB_DESCRIPTOR  *HubDescriptor
302
  )
303
0
{
304
0
  EFI_STATUS  Status;
305
306
  //
307
  // First get the hub descriptor length
308
  //
309
0
  Status = PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, 2, HubDescriptor);
310
311
0
  if (EFI_ERROR (Status)) {
312
0
    return Status;
313
0
  }
314
315
  //
316
  // Get the whole hub descriptor
317
  //
318
0
  return PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, HubDescriptor->Length, HubDescriptor);
319
0
}
320
321
/**
322
  USB hub control transfer to set the hub depth.
323
324
  @param  PeiServices       General-purpose services that are available to every PEIM.
325
  @param  PeiUsbDevice      Indicates the hub controller device.
326
  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.
327
328
  @retval EFI_SUCCESS       Depth of the hub is set.
329
  @retval Others            Failed to set the depth.
330
331
**/
332
EFI_STATUS
333
PeiUsbHubCtrlSetHubDepth (
334
  IN EFI_PEI_SERVICES  **PeiServices,
335
  IN PEI_USB_DEVICE    *PeiUsbDevice,
336
  IN PEI_USB_IO_PPI    *UsbIoPpi
337
  )
338
0
{
339
0
  EFI_USB_DEVICE_REQUEST  DevReq;
340
341
0
  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
342
343
  //
344
  // Fill Device request packet
345
  //
346
0
  DevReq.RequestType = USB_RT_HUB;
347
0
  DevReq.Request     = USB_HUB_REQ_SET_DEPTH;
348
0
  DevReq.Value       = PeiUsbDevice->Tier;
349
0
  DevReq.Length      = 0;
350
351
0
  return UsbIoPpi->UsbControlTransfer (
352
0
                     PeiServices,
353
0
                     UsbIoPpi,
354
0
                     &DevReq,
355
0
                     EfiUsbNoData,
356
0
                     PcdGet32 (PcdUsbTransferTimeoutValue),
357
0
                     NULL,
358
0
                     0
359
0
                     );
360
0
}
361
362
/**
363
  Configure a given hub.
364
365
  @param  PeiServices    General-purpose services that are available to every PEIM.
366
  @param  PeiUsbDevice   Indicating the hub controller device that will be configured
367
368
  @retval EFI_SUCCESS       Hub configuration is done successfully.
369
  @retval EFI_DEVICE_ERROR  Cannot configure the hub due to a hardware error.
370
371
**/
372
EFI_STATUS
373
PeiDoHubConfig (
374
  IN EFI_PEI_SERVICES  **PeiServices,
375
  IN PEI_USB_DEVICE    *PeiUsbDevice
376
  )
377
0
{
378
0
  UINT8                   HubDescBuffer[256];
379
0
  EFI_USB_HUB_DESCRIPTOR  *HubDescriptor;
380
0
  EFI_STATUS              Status;
381
0
  EFI_USB_HUB_STATUS      HubStatus;
382
0
  UINTN                   Index;
383
0
  PEI_USB_IO_PPI          *UsbIoPpi;
384
385
0
  UsbIoPpi = &PeiUsbDevice->UsbIoPpi;
386
387
  //
388
  // The length field of descriptor is UINT8 type, so the buffer
389
  // with 256 bytes is enough to hold the descriptor data.
390
  //
391
0
  HubDescriptor = (EFI_USB_HUB_DESCRIPTOR *)HubDescBuffer;
392
393
  //
394
  // Get the hub descriptor
395
  //
396
0
  Status = PeiUsbHubReadDesc (
397
0
             PeiServices,
398
0
             PeiUsbDevice,
399
0
             UsbIoPpi,
400
0
             HubDescriptor
401
0
             );
402
0
  if (EFI_ERROR (Status)) {
403
0
    return EFI_DEVICE_ERROR;
404
0
  }
405
406
0
  PeiUsbDevice->DownStreamPortNo = HubDescriptor->NbrPorts;
407
408
0
  if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) {
409
0
    DEBUG ((DEBUG_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier));
410
0
    PeiUsbHubCtrlSetHubDepth (
411
0
      PeiServices,
412
0
      PeiUsbDevice,
413
0
      UsbIoPpi
414
0
      );
415
0
  } else {
416
    //
417
    //  Power all the hub ports
418
    //
419
0
    for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {
420
0
      Status = PeiHubSetPortFeature (
421
0
                 PeiServices,
422
0
                 UsbIoPpi,
423
0
                 (UINT8)(Index + 1),
424
0
                 EfiUsbPortPower
425
0
                 );
426
0
      if (EFI_ERROR (Status)) {
427
0
        DEBUG ((DEBUG_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index));
428
0
        continue;
429
0
      }
430
0
    }
431
432
0
    DEBUG ((DEBUG_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor->PwrOn2PwrGood));
433
0
    if (HubDescriptor->PwrOn2PwrGood > 0) {
434
0
      MicroSecondDelay (HubDescriptor->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
435
0
    }
436
437
    //
438
    // Clear Hub Status Change
439
    //
440
0
    Status = PeiHubGetHubStatus (
441
0
               PeiServices,
442
0
               UsbIoPpi,
443
0
               (UINT32 *)&HubStatus
444
0
               );
445
0
    if (EFI_ERROR (Status)) {
446
0
      return EFI_DEVICE_ERROR;
447
0
    } else {
448
      //
449
      // Hub power supply change happens
450
      //
451
0
      if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {
452
0
        PeiHubClearHubFeature (
453
0
          PeiServices,
454
0
          UsbIoPpi,
455
0
          C_HUB_LOCAL_POWER
456
0
          );
457
0
      }
458
459
      //
460
      // Hub change overcurrent happens
461
      //
462
0
      if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {
463
0
        PeiHubClearHubFeature (
464
0
          PeiServices,
465
0
          UsbIoPpi,
466
0
          C_HUB_OVER_CURRENT
467
0
          );
468
0
      }
469
0
    }
470
0
  }
471
472
0
  return EFI_SUCCESS;
473
0
}
474
475
/**
476
  Send reset signal over the given root hub port.
477
478
  @param  PeiServices    General-purpose services that are available to every PEIM.
479
  @param  UsbIoPpi       Indicates the PEI_USB_IO_PPI instance.
480
  @param  PortNum        Usb hub port number (starting from 1).
481
482
**/
483
VOID
484
PeiResetHubPort (
485
  IN EFI_PEI_SERVICES  **PeiServices,
486
  IN PEI_USB_IO_PPI    *UsbIoPpi,
487
  IN UINT8             PortNum
488
  )
489
0
{
490
0
  EFI_STATUS           Status;
491
0
  UINTN                Index;
492
0
  EFI_USB_PORT_STATUS  HubPortStatus;
493
494
0
  MicroSecondDelay (100 * 1000);
495
496
  //
497
  // reset root port
498
  //
499
0
  PeiHubSetPortFeature (
500
0
    PeiServices,
501
0
    UsbIoPpi,
502
0
    PortNum,
503
0
    EfiUsbPortReset
504
0
    );
505
506
  //
507
  // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
508
  // section 7.1.7.5 for timing requirements.
509
  //
510
0
  MicroSecondDelay (USB_SET_PORT_RESET_STALL);
511
512
  //
513
  // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
514
  //
515
0
  ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS));
516
517
0
  for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
518
0
    Status = PeiHubGetPortStatus (
519
0
               PeiServices,
520
0
               UsbIoPpi,
521
0
               PortNum,
522
0
               (UINT32 *)&HubPortStatus
523
0
               );
524
525
0
    if (EFI_ERROR (Status)) {
526
0
      return;
527
0
    }
528
529
0
    if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
530
0
      break;
531
0
    }
532
533
0
    MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);
534
0
  }
535
536
0
  if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
537
0
    DEBUG ((DEBUG_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum));
538
0
    return;
539
0
  }
540
541
  //
542
  // clear reset change root port
543
  //
544
0
  PeiHubClearPortFeature (
545
0
    PeiServices,
546
0
    UsbIoPpi,
547
0
    PortNum,
548
0
    EfiUsbPortResetChange
549
0
    );
550
551
0
  MicroSecondDelay (1 * 1000);
552
553
0
  PeiHubClearPortFeature (
554
0
    PeiServices,
555
0
    UsbIoPpi,
556
0
    PortNum,
557
0
    EfiUsbPortConnectChange
558
0
    );
559
560
  //
561
  // Set port enable
562
  //
563
0
  PeiHubSetPortFeature (
564
0
    PeiServices,
565
0
    UsbIoPpi,
566
0
    PortNum,
567
0
    EfiUsbPortEnable
568
0
    );
569
570
  //
571
  // Clear any change status
572
  //
573
574
0
  PeiHubClearPortFeature (
575
0
    PeiServices,
576
0
    UsbIoPpi,
577
0
    PortNum,
578
0
    EfiUsbPortEnableChange
579
0
    );
580
581
0
  MicroSecondDelay (10 * 1000);
582
583
0
  return;
584
0
}