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
>>
next prev parent 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