On 04/06/16 18:15, Ard Biesheuvel wrote:
> Instead of relying on VirtFdtDxe to populate the GIC related PCDs, move
> this handling to our implementation of ArmGicArchLib, and retrieve the
> required DT info using the new FDT client protocol.
>
> This removes one of the reasons we need to load VirtFdtDxe first using
> an 'A PRIORI' declaration in the platform FDF.
>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Ard Biesheuvel <ard.biesheu...@linaro.org>
> ---
>  ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.c   | 84 
> ++++++++++++++++++--
>  ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf | 15 +++-
>  2 files changed, 92 insertions(+), 7 deletions(-)

Urgh.

I guess the conversion (together with the next patch) should be
"straightforward". However, before I try to validate the code movement,
I have a small and a big question.

(21) small one: what do you need <libfdt.h>, FdtLib, and (consequently)
EmbeddedPkg/EmbeddedPkg.dec for?

... Nevermind, coming back from the source code below, I understand.
I'll make a suggestion down there. Consider (21) a no-op.

(22) The big question is this: how can I determine where this library
instance is used?

Namely, before the conversion, PcdGic*Base would be set only once (in
VirtFdtDxe). That means two things: (a) it is set *for sure*, for any
DXE driver that might want to look at the PCDs, plus (b) the PCDs are
not set more than once.

I can't see how this conversion guarantees either.

Let's start with question (b). (Breaking (b) is not a catastrophe, but
it's ugly.)

I tried to round up users of the lib class ArmGicArchLib. I found two
client INF files:

- ArmPkg/Drivers/ArmGic/ArmGicLib.inf
- ArmPkg/Drivers/ArmGic/ArmGicSecLib.inf

These are themselves library instances (with MODULE_TYPE=SEC, WTF?) So,
I guess I have to find the clients of the lib class ArmGicLib. They are:

- ArmPkg/Application/LinuxLoader/LinuxLoader.inf

  We use this in our ARM (32-bit) builds. It means whenever this app is
  run, it will re-set the PCDs. :/ ... Although, it looks like the
  application only depends on ArmGicLib in the AARCH64 case, precisely
  which architecture we don't build the application for. Okay,
  ultimately, but confusing...

- ArmPkg/Drivers/ArmGic/ArmGicDxe.inf

  I guess this is our main target. This one is therefore certainly
  correct to set the PCDs.

- ArmPlatformPkg/ArmVExpressPkg/ArmVExpressDxe/ArmFvpDxe.inf

  We never include this driver. Okay.

- ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf
- ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf
- ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf

  What the heck, all of these library instances are for class
  ArmGicArchLib, which is what I started out with! We actually use the
  last one (this patch modifies exactly it); it creates a circular
  library dependency between ArmGicLib and ArmGicArchLib. Sweet $DEITY.

  Anyway, since I started out tracking down ArmGicArchLib, and we don't
  use the first two of the above, they don't add new things to follow.

- ArmPlatformPkg/Library/DebugSecExtraActionLib/DebugSecExtraActionLib.inf

  We have a library class resolution to this, in "ArmVirt.dsc.inc", for
  ArmPlatformSecExtraActionLib. That's a dead-end, thankfully; grepping
  for the lib class, only
  
"ArmPlatformPkg/ArmVExpressPkg/Library/ArmVExpressSecLibCTA9x4/ArmVExpressSecLib.inf"
  depends on it, which I can't imagine we use. The resolution should be
  dropped from "ArmVirtPkg/ArmVirt.dsc.inc", probably.

- ArmPlatformPkg/PrePeiCore/PrePeiCoreMPCore.inf
- ArmPlatformPkg/PrePi/PeiMPCore.inf

  These are SEC modules, and we don't use them. Okay.

So, ultimately, the only user of this library instance is
"ArmPkg/Drivers/ArmGic/ArmGicDxe.inf". ... Indeed, checking the build
report file for ArmVirtQemu (AARCH64), I find ArmVirtGicArchLib (and
ArmGicLib too) only under "ArmPkg/Drivers/ArmGic/ArmGicDxe.inf".

Question (22)(b) is therefore cleared; the PCDs in question will only be
set once, when "ArmPkg/Drivers/ArmGic/ArmGicDxe.inf" is dispatched.


Let's see (22)(a): can anything consume these PCDs before
"ArmPkg/Drivers/ArmGic/ArmGicDxe.inf" sets them?

- ArmPkg/Application/LinuxLoader/LinuxLoader.inf

  Same as above: uses the PCDs only on AARCH64, when we don't build it.

- ArmPkg/Drivers/ArmGic/ArmGicDxe.inf

  The library sets the PCDs for it in time.

- 
ArmPlatformPkg/ArmVExpressPkg/Library/ArmVExpressSecLibRTSM/ArmVExpressSecLib.inf

  We don't use this (it wants the PCDs as Fixed, anyway).

- ArmPlatformPkg/Library/DebugSecExtraActionLib/DebugSecExtraActionLib.inf
- ArmPlatformPkg/PrePeiCore/PrePeiCoreMPCore.inf
- ArmPlatformPkg/PrePi/PeiMPCore.inf

  Ditto for these three.

Alright! It was exhausting to verify it (you could have written it up
too... :)), but the conversion seems safe. Ultimately, as (22), I'll
make this request:

(22) please document in the commit message, that in all our builds, only
"ArmPkg/Drivers/ArmGic/ArmGicDxe.inf" links against this library, and
only "ArmPkg/Drivers/ArmGic/ArmGicDxe.inf" consumes the PCDs.

... This is actually a "standard requirement" for the rest of the
plugin-like patches, more or less. Do you think (knowing the rest of the
series) that it might make sense for you to post a v2 after my comments
thus far? Mainly, this "usage analysis" is exhausting, and for the rest
of the series, I'd prefer to validate yours, not construct mine. :)

Anyway, let's see the rest of this patch (INF file moved to the top --
can you perhaps adopt a diff-order file, for formatting the patches?):

> diff --git a/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf 
> b/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf
> index c85b2d44d856..57086242de1f 100644
> --- a/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf
> +++ b/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf
> @@ -18,7 +18,7 @@ [Defines]
>    INF_VERSION                    = 0x00010005
>    BASE_NAME                      = ArmVirtGicArchLib
>    FILE_GUID                      = 87b0dc84-4661-4deb-a789-97977ff636ed
> -  MODULE_TYPE                    = BASE
> +  MODULE_TYPE                    = DXE_DRIVER

(23) I don't think it's necessary. You use neither ImageHandle nor
SystemTable below. The client type restriction (on the LIBRARY_CLASS
line below) suffices.

>    VERSION_STRING                 = 1.0
>    LIBRARY_CLASS                  = ArmGicArchLib|DXE_DRIVER UEFI_DRIVER 
> UEFI_APPLICATION
>    CONSTRUCTOR                    = ArmVirtGicArchLibConstructor
> @@ -30,11 +30,22 @@ [LibraryClasses]
>    PcdLib
>    DebugLib
>    ArmGicLib
> +  UefiBootServicesTableLib
> +  FdtLib
>
>  [Packages]
>    MdePkg/MdePkg.dec
>    ArmPkg/ArmPkg.dec
>    ArmVirtPkg/ArmVirtPkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +
> +[Protocols]
> +  gFdtClientProtocolGuid
>
>  [Pcd]
> -  gArmVirtTokenSpaceGuid.PcdArmGicRevision
> +  gArmTokenSpaceGuid.PcdGicDistributorBase
> +  gArmTokenSpaceGuid.PcdGicRedistributorsBase
> +  gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase
> +
> +[Depex]
> +  gFdtClientProtocolGuid
>

Looks okay (modulo (21) above).

> diff --git a/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.c 
> b/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.c
> index 732860cadfe6..686622228831 100644
> --- a/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.c
> +++ b/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.c
> @@ -1,7 +1,7 @@
>  /** @file
>    ArmGicArchLib library class implementation for DT based virt platforms
>
> -  Copyright (c) 2015, Linaro Ltd. All rights reserved.<BR>
> +  Copyright (c) 2015 - 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
> @@ -19,21 +19,83 @@
>  #include <Library/ArmGicArchLib.h>
>  #include <Library/PcdLib.h>
>  #include <Library/DebugLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <libfdt.h>
> +
> +#include <Protocol/FdtClient.h>
>
>  STATIC ARM_GIC_ARCH_REVISION        mGicArchRevision;
>
> -RETURN_STATUS
> +EFI_STATUS
>  EFIAPI
>  ArmVirtGicArchLibConstructor (
> -  VOID
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
>    )
>  {
> -  UINT32  IccSre;
> +  UINT32                IccSre;
> +  FDT_CLIENT_PROTOCOL   *FdtClient;
> +  CONST VOID            *Reg;
> +  UINTN                 RegElemSize, RegSize;
> +  UINTN                 GicRevision;
> +  EFI_STATUS            Status;
> +  UINT64                DistBase, CpuBase, RedistBase;
>
> -  switch (PcdGet32 (PcdArmGicRevision)) {
> +  Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL, (VOID 
> **)&FdtClient);

(24) This line is too long.

Can you double-check the series that added lines don't exceed 79
characters? (I think "BaseTools/Scripts/PatchCheck.py" might help you
verify this -- see a7e173b07a1e.) I guess I shouldn't obsess about code
that is moved, but code you write genuinely for this work shouldn't be
too wide.

> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }

(25) Given the DepEx, you might want to replace this with an
ASSERT_EFI_ERROR(). Up to you.

> +
> +  GicRevision = 2;
> +  Status = FdtClient->FindCompatibleNodeReg (FdtClient,
> +                                             "arm,cortex-a15-gic",
> +                                             &Reg,
> +                                             &RegElemSize,
> +                                             &RegSize);

(26) The indentation of the arguments is not correct; they should be
aligned with "FindCompatibleNodeReg", plus one or two spaces.

Can you re-check the series for such indentation problems?

> +  if (Status == EFI_NOT_FOUND) {
> +    GicRevision = 3;
> +    Status = FdtClient->FindCompatibleNodeReg (FdtClient,
> +                                               "arm,gic-v3",
> +                                               &Reg,
> +                                               &RegElemSize,
> +                                               &RegSize);
> +  }
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  switch (GicRevision) {
>
>    case 3:
>      //
> +    // The GIC v3 DT binding describes a series of at least 3 physical (base
> +    // addresses, size) pairs: the distributor interface (GICD), at least one
> +    // redistributor region (GICR) containing dedicated redistributor
> +    // interfaces for all individual CPUs, and the CPU interface (GICC).
> +    // Under virtualization, we assume that the first redistributor region
> +    // listed covers the boot CPU. Also, our GICv3 driver only supports the
> +    // system register CPU interface, so we can safely ignore the MMIO 
> version
> +    // which is listed after the sequence of redistributor interfaces.
> +    // This means we are only interested in the first two memory regions
> +    // supplied, and ignore everything else.
> +    //
> +    ASSERT (RegSize >= 32);
> +
> +    // RegProp[0..1] == { GICD base, GICD size }
> +    DistBase = fdt64_to_cpu (((UINT64 *)Reg)[0]);

Sigh. So this is the answer to (21). Here's another proposal then:

(27) can we perhaps dispense with the byte order conversion helpers from
libfdt? I mean, it is annoying to include the FDT library *just* for
this, when we have our shiny new protocol ready, for the rest of the
device tree massaging. So the idea is:

- If (knowing the rest of the series) you deem that libfdt is frequently
  needed in addition to the new protocol *because* we frequently
  manipulate the DTB beyond the capabilities of the new protocol (and in
  a way that is hard to extract into the protocol), then sure, libfdt
  and the protocol should co-exist in client code, and I have nothing
  against fdt64_to_cpu()

- OTOH, if we mostly (only?) include LibFdt on top of the new protocol,
  in the rest of the series too, because we can't live without
  fdt64_to_cpu() and friends, then I suggest to remove the LibFdt
  dependency, and exploit that FDT internals are always big-endian,
  while UEFI is always little-endian. Therefore, use the SwapBytes64()
  function (and friends) directly, from BaseLib.

What do you think?

> +    ASSERT (DistBase < MAX_UINT32);
> +
> +    // RegProp[2..3] == { GICR base, GICR size }
> +    RedistBase = fdt64_to_cpu (((UINT64 *)Reg)[2]);
> +    ASSERT (RedistBase < MAX_UINT32);
> +
> +    PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
> +    PcdSet32 (PcdGicRedistributorsBase, (UINT32)RedistBase);
> +
> +    DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",
> +      DistBase, RedistBase));
> +
> +    //
>      // The default implementation of ArmGicArchLib is responsible for 
> enabling
>      // the system register interface on the GICv3 if one is found. So let's 
> do
>      // the same here.
> @@ -55,6 +117,18 @@ ArmVirtGicArchLibConstructor (
>      break;
>
>    case 2:
> +    ASSERT (RegSize == 32);
> +
> +    DistBase = fdt64_to_cpu (((UINT64 *)Reg)[0]);
> +    CpuBase  = fdt64_to_cpu (((UINT64 *)Reg)[2]);
> +    ASSERT (DistBase < MAX_UINT32);
> +    ASSERT (CpuBase < MAX_UINT32);
> +
> +    PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
> +    PcdSet32 (PcdGicInterruptInterfaceBase, (UINT32)CpuBase);
> +
> +    DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));
> +
>      mGicArchRevision = ARM_GIC_ARCH_REVISION_2;
>      break;
>

This looks good to me (with the above remarks in mind).

Thanks!
Laszlo

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to