public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
To: "Ni, Ruiyu" <ruiyu.ni@intel.com>
Cc: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
	"Gao, Liming" <liming.gao@intel.com>,
	 "Kinney, Michael D" <michael.d.kinney@intel.com>,
	"afish@apple.com" <afish@apple.com>,
	"mw@semihalf.com" <mw@semihalf.com>,
	"leif.lindholm@linaro.org" <leif.lindholm@linaro.org>
Subject: Re: [PATCH v3 3/5] MdeModulePkg: implement generic PCI I/O driver for non-discoverable devices
Date: Thu, 24 Nov 2016 18:14:28 +0000	[thread overview]
Message-ID: <CAKv+Gu_dUDBQsszpyksV9bQ2sAMYUN9StEDPuxgMFnYvcnXp5Q@mail.gmail.com> (raw)
In-Reply-To: <CAKv+Gu91SCK-H=jjK=i0ULeHaXjREsZhamhsM+hJH5kzqyR4Hw@mail.gmail.com>

Ray, I still need some help understanding how you think this is supposed to work

Thanks,
Ard.


On 18 November 2016 at 12:30, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> On 17 November 2016 at 03:29, Ni, Ruiyu <ruiyu.ni@intel.com> wrote:
[...]
>>> +//
>>> +// Get the resource associated with BAR number 'BarIndex'. This takes
>>> +into // account that 64-bit resource use up 2 BAR slots, which means
>>> +that BAR // n + 1 is reported as not found if BAR n refers to a 64-bit resource.
>>> +//
>>> +STATIC
>>> +EFI_STATUS
>>> +GetBarResource (
>>> +  IN  NON_DISCOVERABLE_PCI_DEVICE         *Dev,
>>> +  IN  UINT8                               BarIndex,
>>> +  OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   **Descriptor
>>> +  )
>>> +{
>>> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
>>> +
>>> +  if (BarIndex < Dev->BarOffset) {
>>> +    return EFI_NOT_FOUND;
>>> +  }
>>> +
>>> +  BarIndex -= Dev->BarOffset;
>>> +
>>> +  for (Desc = Dev->Device->Resources;
>>> +       Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
>>> +       Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
>>> +
>>> +    if (BarIndex == 0) {
>>> +      *Descriptor = Desc;
>>> +      return EFI_SUCCESS;
>>> +    }
>>> +
>>> +    if (Desc->AddrSpaceGranularity == 64) {
>>> +      if (BarIndex == 1) {
>>> +        break;
>>> +      }
>>> +      BarIndex -= 2;
>>
>> 1. I think we only need to decrease *one* from BarIndex instead of two,
>> even for 64bit BAR.
>> I remember MdeModulePkg/PciBusDxe ever had a bug to treat 64bit
>> BAR as 2 logic BARs but it should have fixed long ago.
>>
>
> Right. So does that mean BarIndex '2' refers to BARs 4 and 5 if we
> have 3 64-bit BARs in total?
>
>>> +    } else {
>>> +      BarIndex -= 1;
>>> +    }
>>> +  }
>>> +  return EFI_NOT_FOUND;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoPollMem (
>>> +  IN  EFI_PCI_IO_PROTOCOL         *This,
>>> +  IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,
>>> +  IN  UINT8                       BarIndex,
>>> +  IN  UINT64                      Offset,
>>> +  IN  UINT64                      Mask,
>>> +  IN  UINT64                      Value,
>>> +  IN  UINT64                      Delay,
>>> +  OUT UINT64                      *Result
>>> +  )
>>> +{
>>> +  ASSERT (FALSE);
>>> +  return EFI_UNSUPPORTED;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoPollIo (
>>> +  IN  EFI_PCI_IO_PROTOCOL         *This,
>>> +  IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,
>>> +  IN  UINT8                       BarIndex,
>>> +  IN  UINT64                      Offset,
>>> +  IN  UINT64                      Mask,
>>> +  IN  UINT64                      Value,
>>> +  IN  UINT64                      Delay,
>>> +  OUT UINT64                      *Result
>>> +  )
>>> +{
>>> +  ASSERT (FALSE);
>>> +  return EFI_UNSUPPORTED;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoMemRW (
>>> +  IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,
>>> +  IN  UINTN                       Count,
>>> +  IN  UINTN                       DstStride,
>>> +  IN  VOID                        *Dst,
>>> +  IN  UINTN                       SrcStride,
>>> +  OUT CONST VOID                  *Src
>>> +  )
>>> +{
>>> +  volatile UINT8             *Dst8;
>>> +  volatile UINT16            *Dst16;
>>> +  volatile UINT32            *Dst32;
>>> +  volatile CONST UINT8       *Src8;
>>> +  volatile CONST UINT16      *Src16;
>>> +  volatile CONST UINT32      *Src32;
>>> +
>>> +  //
>>> +  // Loop for each iteration and move the data  //  switch (Width &
>>> + 0x3) {  case EfiPciWidthUint8:
>>> +    Dst8 = (UINT8 *)Dst;
>>> +    Src8 = (UINT8 *)Src;
>>> +    for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {
>>> +      *Dst8 = *Src8;
>>> +    }
>>> +    break;
>>> +  case EfiPciWidthUint16:
>>> +    Dst16 = (UINT16 *)Dst;
>>> +    Src16 = (UINT16 *)Src;
>>> +    for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {
>>> +      *Dst16 = *Src16;
>>> +    }
>>> +    break;
>>> +  case EfiPciWidthUint32:
>>> +    Dst32 = (UINT32 *)Dst;
>>> +    Src32 = (UINT32 *)Src;
>>> +    for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {
>>> +      *Dst32 = *Src32;
>>> +    }
>>> +    break;
>>> +  default:
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  return EFI_SUCCESS;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoMemRead (
>>> +  IN     EFI_PCI_IO_PROTOCOL          *This,
>>> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
>>> +  IN     UINT8                        BarIndex,
>>> +  IN     UINT64                       Offset,
>>> +  IN     UINTN                        Count,
>>> +  IN OUT VOID                         *Buffer
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE         *Dev;
>>> +  UINTN                               AlignMask;
>>> +  VOID                                *Address;
>>> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
>>> +  EFI_STATUS                          Status;
>>> +
>>> +  if (Buffer == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
>>> +
>>> +  //
>>> +  // Only allow accesses to the BARs we emulate  //  Status =
>>> + GetBarResource (Dev, BarIndex, &Desc);  if (EFI_ERROR (Status)) {
>>> +    return Status;
>>> +  }
>>> +
>>> +  if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
>>> +    return EFI_UNSUPPORTED;
>>> +  }
>>> +
>>> +  Address = (VOID *)((UINTN)Desc->AddrRangeMin + Offset);  AlignMask =
>>> + (1 << (Width & 0x03)) - 1;  if ((UINTN)Address & AlignMask) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  switch (Width) {
>>> +  case EfiPciWidthUint8:
>>> +  case EfiPciWidthUint16:
>>> +  case EfiPciWidthUint32:
>>> +  case EfiPciWidthUint64:
>>> +    return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);
>>> +
>>> +  case EfiPciWidthFifoUint8:
>>> +  case EfiPciWidthFifoUint16:
>>> +  case EfiPciWidthFifoUint32:
>>> +  case EfiPciWidthFifoUint64:
>>> +    return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);
>>> +
>>> +  case EfiPciWidthFillUint8:
>>> +  case EfiPciWidthFillUint16:
>>> +  case EfiPciWidthFillUint32:
>>> +  case EfiPciWidthFillUint64:
>>> +    return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);
>>> +
>>> +  default:
>>> +    break;
>>> +  }
>>> +  return EFI_INVALID_PARAMETER;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoMemWrite (
>>> +  IN     EFI_PCI_IO_PROTOCOL          *This,
>>> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
>>> +  IN     UINT8                        BarIndex,
>>> +  IN     UINT64                       Offset,
>>> +  IN     UINTN                        Count,
>>> +  IN OUT VOID                         *Buffer
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE         *Dev;
>>> +  UINTN                               AlignMask;
>>> +  VOID                                *Address;
>>> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
>>> +  EFI_STATUS                          Status;
>>> +
>>> +  if (Buffer == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
>>> +
>>> +  //
>>> +  // Only allow accesses to the BARs we emulate  //  Status =
>>> + GetBarResource (Dev, BarIndex, &Desc);  if (EFI_ERROR (Status)) {
>>> +    return Status;
>>> +  }
>>> +
>>> +  if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
>>> +    return EFI_UNSUPPORTED;
>>> +  }
>>> +
>>> +  Address = (VOID *)((UINTN)Desc->AddrRangeMin + Offset);  AlignMask =
>>> + (1 << (Width & 0x03)) - 1;  if ((UINTN)Address & AlignMask) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  switch (Width) {
>>> +  case EfiPciWidthUint8:
>>> +  case EfiPciWidthUint16:
>>> +  case EfiPciWidthUint32:
>>> +  case EfiPciWidthUint64:
>>> +    return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);
>>> +
>>> +  case EfiPciWidthFifoUint8:
>>> +  case EfiPciWidthFifoUint16:
>>> +  case EfiPciWidthFifoUint32:
>>> +  case EfiPciWidthFifoUint64:
>>> +    return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);
>>> +
>>> +  case EfiPciWidthFillUint8:
>>> +  case EfiPciWidthFillUint16:
>>> +  case EfiPciWidthFillUint32:
>>> +  case EfiPciWidthFillUint64:
>>> +    return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);
>>> +
>>> +  default:
>>> +    break;
>>> +  }
>>> +  return EFI_INVALID_PARAMETER;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoIoRead (
>>> +  IN EFI_PCI_IO_PROTOCOL              *This,
>>> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
>>> +  IN     UINT8                        BarIndex,
>>> +  IN     UINT64                       Offset,
>>> +  IN     UINTN                        Count,
>>> +  IN OUT VOID                         *Buffer
>>> +  )
>>> +{
>>> +  ASSERT (FALSE);
>>> +  return EFI_UNSUPPORTED;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoIoWrite (
>>> +  IN     EFI_PCI_IO_PROTOCOL          *This,
>>> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
>>> +  IN     UINT8                        BarIndex,
>>> +  IN     UINT64                       Offset,
>>> +  IN     UINTN                        Count,
>>> +  IN OUT VOID                         *Buffer
>>> +  )
>>> +{
>>> +  ASSERT (FALSE);
>>> +  return EFI_UNSUPPORTED;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoPciRead (
>>> +  IN     EFI_PCI_IO_PROTOCOL        *This,
>>> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
>>> +  IN     UINT32                     Offset,
>>> +  IN     UINTN                      Count,
>>> +  IN OUT VOID                       *Buffer
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE   *Dev;
>>> +  UINTN                         Length;
>>> +
>>> +  if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
>>> +  Length = Count << ((UINTN)Width & 0x3);
>>> +
>>> +  if (Offset + Length > sizeof (Dev->ConfigSpace)) {
>>> +    return EFI_UNSUPPORTED;
>>> +  }
>>> +
>>> +  return PciIoMemRW (Width, Count, 1, Buffer, 1,
>>> +           (UINT8 *)&Dev->ConfigSpace + Offset); }
>>> +
>>> +//
>>> +// taken from MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h
>>> +//
>>> +#define SD_MMC_HC_SLOT_OFFSET         0x40
>>> +
>>> +typedef struct {
>>> +  UINT8    FirstBar:3;        // bit 0:2
>>> +  UINT8    Reserved:1;        // bit 3
>>> +  UINT8    SlotNum:3;         // bit 4:6
>>> +  UINT8    Reserved1:1;       // bit 7
>>> +} SD_MMC_HC_SLOT_INFO;
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoPciReadSdhci (
>>> +  IN     EFI_PCI_IO_PROTOCOL        *This,
>>> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
>>> +  IN     UINT32                     Offset,
>>> +  IN     UINTN                      Count,
>>> +  IN OUT VOID                       *Buffer
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE   *Dev;
>>> +  UINTN                         Length;
>>> +  SD_MMC_HC_SLOT_INFO           *SlotInfo;
>>> +
>>> +  if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
>>> +  Length = Count << ((UINTN)Width & 0x3);
>>> +
>>> +  //
>>> +  // The SDHCI driver reads beyond the 64-byte PCI config space to read
>>> + // the number of slots and the BAR offset. So allow that  //  if
>>> + (Offset == SD_MMC_HC_SLOT_OFFSET && Length == 1) {
>>> +    SlotInfo = Buffer;
>>> +
>>> +    SlotInfo->FirstBar = Dev->BarOffset;
>>> +    SlotInfo->SlotNum = Dev->BarCount - 1;
>>
>> 2. It's a little bit tricky to hook the SDHCI access.
>> We need to make this driver generic enough and stable
>> for future possible requirements.
>> We now see the needs for SDHCI access. We may have other similar needs.
>> Can we pass such information from NonDiscoverredPciDevice?
>> The information like array of <Offset, Uint8Value> can be included in the protocol.
>> Just my rough idea. Feel free to reject it.
>>
>
> Well, this is another side effect of the design decision of folding
> SDHCI support into a SDHCI-PCI driver.
>
> For other host controller interfaces, there is always a 1:1
> relationship between a PCI device and a ?HCI device. However, for
> SDHCI, the correct way to implement this on the driver side would have
> been to implement a SDHCI-PCI bus driver that allocates a SHDCI device
> handle for each slot on the PCI device. That would allow the SDHCI
> *driver* to only worry about a single device, and there would be no
> need for this hack.
>
> In the first iteration of this series, I did not have this since there
> was a 1:1 relationship between non-discoverable devices and PCI
> drivers, but due to the move to ACPI resource descriptors, this is
> different now.
>
>
>>> +
>>> +    return EFI_SUCCESS;
>>> +  }
>>> +
>>> +  if (Offset + Length > sizeof (Dev->ConfigSpace)) {
>>> +    return EFI_UNSUPPORTED;
>>> +  }
>>> +
>>> +  return PciIoMemRW (Width, Count, 1, Buffer, 1,
>>> +           (UINT8 *)&Dev->ConfigSpace + Offset); }
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoPciWrite (
>>> +  IN EFI_PCI_IO_PROTOCOL              *This,
>>> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
>>> +  IN     UINT32                       Offset,
>>> +  IN     UINTN                        Count,
>>> +  IN OUT VOID                         *Buffer
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE   *Dev;
>>> +  VOID                          *Address;
>>> +
>>> +  if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
>>> +  Address = (UINT8 *)&Dev->ConfigSpace + Offset;
>>> +
>>> +  if (Offset + Count * (1UL << (Width & 0x3)) > sizeof (Dev->ConfigSpace)) {
>>> +    return EFI_UNSUPPORTED;
>>> +  }
>>> +
>>> +  return PciIoMemRW (Width, Count, 1, Address, 1, Buffer); }
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoCopyMem (
>>> +  IN EFI_PCI_IO_PROTOCOL              *This,
>>> +  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
>>> +  IN     UINT8                        DestBarIndex,
>>> +  IN     UINT64                       DestOffset,
>>> +  IN     UINT8                        SrcBarIndex,
>>> +  IN     UINT64                       SrcOffset,
>>> +  IN     UINTN                        Count
>>> +  )
>>> +{
>>> +  ASSERT (FALSE);
>>> +  return EFI_UNSUPPORTED;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +CoherentPciIoMap (
>>> +  IN     EFI_PCI_IO_PROTOCOL            *This,
>>> +  IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
>>> +  IN     VOID                           *HostAddress,
>>> +  IN OUT UINTN                          *NumberOfBytes,
>>> +  OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
>>> +  OUT    VOID                           **Mapping
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE           *Dev;
>>> +  EFI_STATUS                            Status;
>>> +  NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
>>> +
>>> +  //
>>> +  // If HostAddress exceeds 4 GB, and this device does not support
>>> + 64-bit DMA  // addressing, we need to allocate a bounce buffer and copy
>>> over the data.
>>> +  //
>>> +  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
>>> +  if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) ==
>>> 0 &&
>>> +      (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {
>>> +
>>> +    //
>>> +    // Bounce buffering is not possible for consistent mappings
>>> +    //
>>> +    if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
>>> +      return EFI_UNSUPPORTED;
>>> +    }
>>> +
>>> +    MapInfo = AllocatePool (sizeof *MapInfo);
>>> +    if (MapInfo == NULL) {
>>> +      return EFI_OUT_OF_RESOURCES;
>>> +    }
>>> +
>>> +    MapInfo->AllocAddress = MAX_UINT32;
>>> +    MapInfo->HostAddress = HostAddress;
>>> +    MapInfo->Operation = Operation;
>>> +    MapInfo->NumberOfBytes = *NumberOfBytes;
>>> +
>>> +    Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,
>>> +                    EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
>>> +                    &MapInfo->AllocAddress);
>>> +    if (EFI_ERROR (Status)) {
>>> +      //
>>> +      // If we fail here, it is likely because the system has no memory below
>>> +      // 4 GB to begin with. There is not much we can do about that other than
>>> +      // fail the map request.
>>> +      //
>>> +      FreePool (MapInfo);
>>> +      return EFI_DEVICE_ERROR;
>>> +    }
>>> +    if (Operation == EfiPciIoOperationBusMasterRead) {
>>> +      gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress,
>>> +             *NumberOfBytes);
>>> +    }
>>> +    *DeviceAddress = MapInfo->AllocAddress;
>>> +    *Mapping = MapInfo;
>>> +  } else {
>>> +    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
>>> +    *Mapping = NULL;
>>> +  }
>>> +  return EFI_SUCCESS;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +CoherentPciIoUnmap (
>>> +  IN  EFI_PCI_IO_PROTOCOL          *This,
>>> +  IN  VOID                         *Mapping
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
>>> +
>>> +  MapInfo = Mapping;
>>> +  if (MapInfo != NULL) {
>>> +    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
>>> +      gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo-
>>> >AllocAddress,
>>> +             MapInfo->NumberOfBytes);
>>> +    }
>>> +    gBS->FreePages (MapInfo->AllocAddress,
>>> +           EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes));
>>> +    FreePool (MapInfo);
>>> +  }
>>> +  return EFI_SUCCESS;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +CoherentPciIoAllocateBuffer (
>>> +  IN  EFI_PCI_IO_PROTOCOL         *This,
>>> +  IN  EFI_ALLOCATE_TYPE           Type,
>>> +  IN  EFI_MEMORY_TYPE             MemoryType,
>>> +  IN  UINTN                       Pages,
>>> +  OUT VOID                        **HostAddress,
>>> +  IN  UINT64                      Attributes
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE       *Dev;
>>> +  EFI_PHYSICAL_ADDRESS              AllocAddress;
>>> +  EFI_ALLOCATE_TYPE                 AllocType;
>>> +  EFI_STATUS                        Status;
>>> +
>>> +  if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
>>> +                      EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) {
>>> +    return EFI_UNSUPPORTED;
>>> +  }
>>> +
>>> +  //
>>> +  // Allocate below 4 GB if the dual address cycle attribute has not
>>> + // been set. If the system has no memory available below 4 GB, there
>>> + // is little we can do except propagate the error.
>>> +  //
>>> +  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
>>> +  if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) ==
>>> 0) {
>>> +    AllocAddress = MAX_UINT32;
>>
>> 3. better to use BASE_4GB -1.
>>
>>> +    AllocType = AllocateMaxAddress;
>>> +  } else {
>>> +    AllocType = AllocateAnyPages;
>>> +  }
>>> +
>>> +  Status = gBS->AllocatePages (AllocType, MemoryType, Pages,
>>> +&AllocAddress);
>>> +  if (!EFI_ERROR (Status)) {
>>> +    *HostAddress = (VOID *)(UINTN)AllocAddress;
>>> +  }
>>> +  return Status;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +CoherentPciIoFreeBuffer (
>>> +  IN  EFI_PCI_IO_PROTOCOL         *This,
>>> +  IN  UINTN                       Pages,
>>> +  IN  VOID                        *HostAddress
>>> +  )
>>> +{
>>> +  FreePages (HostAddress, Pages);
>>> +  return EFI_SUCCESS;
>>> +}
>>> +
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoFlush (
>>> +  IN EFI_PCI_IO_PROTOCOL          *This
>>> +  )
>>> +{
>>> +  return EFI_SUCCESS;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoGetLocation (
>>> +  IN   EFI_PCI_IO_PROTOCOL  *This,
>>> +  OUT  UINTN                *SegmentNumber,
>>> +  OUT  UINTN                *BusNumber,
>>> +  OUT  UINTN                *DeviceNumber,
>>> +  OUT  UINTN                *FunctionNumber
>>> +  )
>>> +{
>>> +  if (SegmentNumber == NULL ||
>>> +      BusNumber == NULL ||
>>> +      DeviceNumber == NULL ||
>>> +      FunctionNumber == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  *SegmentNumber  = 0;
>>> +  *BusNumber      = 0xff;
>>> +  *DeviceNumber   = 0;
>>> +  *FunctionNumber = 0;
>>> +
>>> +  return EFI_SUCCESS;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoAttributes (
>>> +  IN  EFI_PCI_IO_PROTOCOL                      *This,
>>> +  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
>>> +  IN  UINT64                                   Attributes,
>>> +  OUT UINT64                                   *Result OPTIONAL
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE   *Dev;
>>> +  BOOLEAN                       Enable;
>>> +
>>> +  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
>>> +
>>> +  Enable = FALSE;
>>> +  switch (Operation) {
>>> +  case EfiPciIoAttributeOperationGet:
>>> +    if (Result == NULL) {
>>> +      return EFI_INVALID_PARAMETER;
>>> +    }
>>> +    *Result = Dev->Attributes;
>>> +    break;
>>> +
>>> +  case EfiPciIoAttributeOperationSupported:
>>> +    if (Result == NULL) {
>>> +      return EFI_INVALID_PARAMETER;
>>> +    }
>>> +    *Result = EFI_PCI_DEVICE_ENABLE |
>>> EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
>>> +    break;
>>> +
>>> +  case EfiPciIoAttributeOperationEnable:
>>> +    Attributes |= Dev->Attributes;
>>> +  case EfiPciIoAttributeOperationSet:
>>> +    Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) !=
>>> 0;
>>> +    Dev->Attributes = Attributes;
>>> +    break;
>>> +
>>> +  case EfiPciIoAttributeOperationDisable:
>>> +    Dev->Attributes &= ~Attributes;
>>> +    break;
>>> +
>>> +  default:
>>> +    return EFI_INVALID_PARAMETER;
>>> +  };
>>> +
>>> +  //
>>> +  // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform
>>> +  // the device specific initialization now.
>>> +  //
>>> +  if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {
>>> +    Dev->Device->Initialize (Dev->Device);
>>> +    Dev->Enabled = TRUE;
>>> +  }
>>> +  return EFI_SUCCESS;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoGetBarAttributes (
>>> +  IN EFI_PCI_IO_PROTOCOL             *This,
>>> +  IN  UINT8                          BarIndex,
>>> +  OUT UINT64                         *Supports OPTIONAL,
>>> +  OUT VOID                           **Resources OPTIONAL
>>> +  )
>>> +{
>>> +  NON_DISCOVERABLE_PCI_DEVICE       *Dev;
>>> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor, *BarDesc;
>>> +  EFI_ACPI_END_TAG_DESCRIPTOR       *End;
>>> +  EFI_STATUS                        Status;
>>> +
>>> +  if (Supports == NULL && Resources == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
>>> +
>>> +  Status = GetBarResource (Dev, BarIndex, &BarDesc);  if (EFI_ERROR
>>> + (Status)) {
>>> +    return Status;
>>> +  }
>>> +
>>> +  //
>>> +  // Don't expose any configurable attributes for our emulated BAR  //
>>> + if (Supports != NULL) {
>>> +    *Supports = 0;
>>> +  }
>>> +
>>> +  if (Resources != NULL) {
>>> +    Descriptor = AllocatePool (sizeof
>>> (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
>>> +                               sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
>>> +    if (Descriptor == NULL) {
>>> +      return EFI_OUT_OF_RESOURCES;
>>> +    }
>>> +
>>> +    CopyMem (Descriptor, BarDesc, sizeof *Descriptor);
>>> +
>>> +    End           = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
>>> +    End->Desc     = ACPI_END_TAG_DESCRIPTOR;
>>> +    End->Checksum = 0;
>>> +
>>> +    *Resources = Descriptor;
>>> +  }
>>> +  return EFI_SUCCESS;
>>> +}
>>> +
>>> +STATIC
>>> +EFI_STATUS
>>> +PciIoSetBarAttributes (
>>> +  IN     EFI_PCI_IO_PROTOCOL          *This,
>>> +  IN     UINT64                       Attributes,
>>> +  IN     UINT8                        BarIndex,
>>> +  IN OUT UINT64                       *Offset,
>>> +  IN OUT UINT64                       *Length
>>> +  )
>>> +{
>>> +  ASSERT (FALSE);
>>> +  return EFI_UNSUPPORTED;
>>> +}
>>> +
>>> +STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate = {
>>> +  PciIoPollMem,
>>> +  PciIoPollIo,
>>> +  { PciIoMemRead, PciIoMemWrite },
>>> +  { PciIoIoRead,  PciIoIoWrite },
>>> +  { PciIoPciRead, PciIoPciWrite },
>>> +  PciIoCopyMem,
>>> +  CoherentPciIoMap,
>>> +  CoherentPciIoUnmap,
>>> +  CoherentPciIoAllocateBuffer,
>>> +  CoherentPciIoFreeBuffer,
>>> +  PciIoFlush,
>>> +  PciIoGetLocation,
>>> +  PciIoAttributes,
>>> +  PciIoGetBarAttributes,
>>> +  PciIoSetBarAttributes,
>>> +  0,
>>> +  0
>>> +};
>>> +
>>> +VOID
>>> +InitializePciIoProtocol (
>>> +  NON_DISCOVERABLE_PCI_DEVICE     *Dev
>>> +  )
>>> +{
>>> +  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
>>> +  INTN                                Idx;
>>> +
>>> +  InitializeListHead (&Dev->UncachedAllocationList);
>>> +
>>> +  Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;
>>> + Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;
>>> +
>>> +  // Copy protocol structure
>>> +  CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
>>> +
>>> +  switch (Dev->Device->Type) {
>>> +  case NonDiscoverableDeviceTypeOhci:
>>> +    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
>>> +    Dev->BarOffset = 0;
>>> +    break;
>>> +
>>> +  case NonDiscoverableDeviceTypeUhci:
>>> +    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
>>> +    Dev->BarOffset = 0;
>>> +    break;
>>> +
>>> +  case NonDiscoverableDeviceTypeEhci:
>>> +    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
>>> +    Dev->BarOffset = 0;
>>> +    break;
>>> +
>>> +  case NonDiscoverableDeviceTypeXhci:
>>> +    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
>>> +    Dev->BarOffset = 0;
>>> +    break;
>>> +
>>> +  case NonDiscoverableDeviceTypeAhci:
>>> +    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[1] =
>>> PCI_CLASS_MASS_STORAGE_SATADPA;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
>>> +    Dev->BarOffset = 5;
>>> +    break;
>>> +
>>> +  case NonDiscoverableDeviceTypeSdhci:
>>> +    Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
>>> +    Dev->ConfigSpace.Hdr.ClassCode[1] =
>>> PCI_SUBCLASS_SD_HOST_CONTROLLER;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;
>>> +    Dev->BarOffset = 0;
>>> +
>>> +    //
>>> +    // Use the special config space accessor so that the SDHCI driver
>>> +    // is able to retrieve the number of slots and the BAR offset
>>> +    //
>>> +    Dev->PciIo.Pci.Read = PciIoPciReadSdhci;
>>> +    break;
>>> +
>>> +  case NonDiscoverableDeviceTypeUfs:
>>> +    Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
>>> +    Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;
>>> +    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
>>> +    Dev->BarOffset = 0;
>>> +    break;
>>> +
>>> +  case NonDiscoverableDeviceTypeNvme:
>>> +    Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI
>>> +    Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; //
>>> PCI_CLASS_MASS_STORAGE_NVM
>>> +    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
>>> +    Dev->BarOffset = 0;
>>> +
>>> +  default:
>>> +    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);  }
>>> +
>>> +  //
>>> +  // Iterate over the resources to populate the virtual BARs  //  Idx =
>>> + Dev->BarOffset;  for (Desc = Dev->Device->Resources, Dev->BarCount =
>>> + 0;
>>> +       Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
>>> +       Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
>>> +
>>> +    ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);
>>> +    ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);
>>> +
>>> +    if (Idx >= PCI_MAX_BARS ||
>>> +        (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) {
>>> +      DEBUG ((DEBUG_ERROR,
>>> +        "%a: resource count exceeds number of emulated BARs\n",
>>> +        __FUNCTION__));
>>> +      ASSERT (FALSE);
>>> +      break;
>>> +    }
>>> +
>>> +    Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;
>>> +    Dev->BarCount++;
>>> +
>>> +    if (Desc->AddrSpaceGranularity == 64) {
>>> +      Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;
>>> +      Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)(Desc-
>>> >AddrRangeMin >> 32);
>>> +    }
>>> +  }
>>> +}
>>> diff --git
>>> a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverable
>>> PciDeviceIo.h
>>> b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverable
>>> PciDeviceIo.h
>>> new file mode 100644
>>> index 000000000000..bc0a3d3258f9
>>> --- /dev/null
>>> +++
>>> b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverable
>>> Pc
>>> +++ iDeviceIo.h
>>> @@ -0,0 +1,84 @@
>>> +/** @file
>>> +
>>> +  Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>
>>> +
>>> +  This program and the accompanying materials are licensed and made
>>> + available  under the terms and conditions of the BSD License which
>>> + accompanies this  distribution. The full text of the license may be
>>> + found at  http://opensource.org/licenses/bsd-license.php
>>> +
>>> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
>>> BASIS,
>>> + WITHOUT  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
>>> EXPRESS OR IMPLIED.
>>> +
>>> +**/
>>> +
>>> +#ifndef __NON_DISCOVERABLE_PCI_DEVICE_IO_H__
>>> +#define __NON_DISCOVERABLE_PCI_DEVICE_IO_H__
>>> +
>>> +#include <Library/BaseMemoryLib.h>
>>> +#include <Library/DebugLib.h>
>>> +#include <Library/MemoryAllocationLib.h> #include
>>> +<Library/UefiBootServicesTableLib.h>
>>> +#include <Library/UefiLib.h>
>>> +
>>> +#include <IndustryStandard/Pci.h>
>>> +
>>> +#include <Protocol/ComponentName.h>
>>> +#include <Protocol/NonDiscoverableDevice.h>
>>> +#include <Protocol/PciIo.h>
>>> +
>>> +#define NON_DISCOVERABLE_PCI_DEVICE_SIG SIGNATURE_32 ('P', 'P', 'I',
>>> +'D')
>>> +
>>> +#define NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(PciIoPointer) \
>>> +        CR (PciIoPointer, NON_DISCOVERABLE_PCI_DEVICE, PciIo, \
>>> +            NON_DISCOVERABLE_PCI_DEVICE_SIG)
>>> +
>>> +#define PCI_ID_VENDOR_UNKNOWN         0xffff
>>> +#define PCI_ID_DEVICE_DONTCARE        0x0000
>>> +
>>> +#define PCI_MAX_BARS                  6
>>> +
>>> +typedef struct {
>>> +  UINT32                    Signature;
>>> +  //
>>> +  // The bound non-discoverable device protocol instance
>>> +  //
>>> +  NON_DISCOVERABLE_DEVICE   *Device;
>>> +  //
>>> +  // The exposed PCI I/O protocol instance.
>>> +  //
>>> +  EFI_PCI_IO_PROTOCOL       PciIo;
>>> +  //
>>> +  // The emulated PCI config space of the device. Only the minimally
>>> +required
>>> +  // items are assigned.
>>> +  //
>>> +  PCI_TYPE00                ConfigSpace;
>>> +  //
>>> +  // The first virtual BAR to assign based on the resources described
>>> +  // by the non-discoverable device.
>>> +  //
>>> +  UINT32                    BarOffset;
>>> +  //
>>> +  // The number of virtual BARs we expose based on the number of
>>> +  // resources
>>> +  //
>>> +  UINT32                    BarCount;
>>> +  //
>>> +  // The PCI I/O attributes for this device
>>> +  //
>>> +  UINT64                    Attributes;
>>> +  //
>>> +  // Whether this device has been enabled
>>> +  //
>>> +  BOOLEAN                   Enabled;
>>> +} NON_DISCOVERABLE_PCI_DEVICE;
>>> +
>>> +VOID
>>> +InitializePciIoProtocol (
>>> +  NON_DISCOVERABLE_PCI_DEVICE     *Device
>>> +  );
>>> +
>>> +extern EFI_COMPONENT_NAME_PROTOCOL gComponentName; extern
>>> +EFI_COMPONENT_NAME2_PROTOCOL gComponentName2;
>>> +
>>> +#endif
>>> diff --git a/MdeModulePkg/MdeModulePkg.dsc
>>> b/MdeModulePkg/MdeModulePkg.dsc index 43421d610ede..aac05408599d
>>> 100644
>>> --- a/MdeModulePkg/MdeModulePkg.dsc
>>> +++ b/MdeModulePkg/MdeModulePkg.dsc
>>> @@ -260,6 +260,7 @@ [Components]
>>>    MdeModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
>>>    MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf
>>>    MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf
>>> +
>>> +
>>> MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePci
>>> Dev
>>> + iceDxe.inf
>>>
>>>    MdeModulePkg/Core/Dxe/DxeMain.inf {
>>>      <LibraryClasses>
>>> --
>>> 2.7.4
>>


  reply	other threads:[~2016-11-24 18:14 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-16 16:59 [PATCH v3 0/5] MdeModulePkg: add support for non-discoverable devices Ard Biesheuvel
2016-11-16 16:59 ` [PATCH v3 1/5] MdeModulePkg: introduce non-discoverable device protocol Ard Biesheuvel
2016-11-16 17:48   ` Leif Lindholm
2016-11-17  2:53     ` Ni, Ruiyu
2016-11-17  6:07       ` Ard Biesheuvel
2016-11-17  7:52         ` Ni, Ruiyu
2016-11-17 10:43           ` Ard Biesheuvel
2016-11-18  2:11             ` Ni, Ruiyu
2016-11-18  4:59               ` Ard Biesheuvel
2016-11-18  5:24                 ` Tian, Feng
2016-11-18  6:57                   ` Ard Biesheuvel
2016-11-18  8:39                     ` Tian, Feng
2016-11-18  8:52                       ` Ard Biesheuvel
2016-11-18  6:13                 ` Ni, Ruiyu
2016-11-18  7:04                   ` Ard Biesheuvel
2016-11-18 13:39                     ` Ni, Ruiyu
2016-11-18 13:50                       ` Ard Biesheuvel
2016-11-25 15:21                         ` Ard Biesheuvel
2016-11-16 16:59 ` [PATCH v3 2/5] MdeModule: introduce helper library to register non-discoverable devices Ard Biesheuvel
2016-11-16 16:59 ` [PATCH v3 3/5] MdeModulePkg: implement generic PCI I/O driver for " Ard Biesheuvel
2016-11-17  3:29   ` Ni, Ruiyu
2016-11-18 12:30     ` Ard Biesheuvel
2016-11-24 18:14       ` Ard Biesheuvel [this message]
2016-11-16 16:59 ` [PATCH v3 4/5] MdeModulePkg/NonDiscoverablePciDeviceDxe: add support for non-coherent DMA Ard Biesheuvel
2016-11-16 16:59 ` [PATCH v3 5/5] Omap35xxPkg/PciEmulation: port to new non-discoverable device infrastructure Ard Biesheuvel
2016-11-17  4:36 ` [PATCH v3 0/5] MdeModulePkg: add support for non-discoverable devices Marcin Wojtas
2016-11-23 14:31   ` Marcin Wojtas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAKv+Gu_dUDBQsszpyksV9bQ2sAMYUN9StEDPuxgMFnYvcnXp5Q@mail.gmail.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox