From: Leif Lindholm <leif.lindholm@linaro.org>
To: Daniil Egranov <daniil.egranov@arm.com>
Cc: edk2-devel@lists.01.org, ryan.harkin@linaro.org
Subject: Re: [PATCH v3] ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe: Set Marvell Yukon MAC address
Date: Wed, 4 Jan 2017 15:12:39 +0000 [thread overview]
Message-ID: <20170104151238.GI16872@bivouac.eciton.net> (raw)
In-Reply-To: <1481680569-89827-1-git-send-email-daniil.egranov@arm.com>
On Tue, Dec 13, 2016 at 07:56:09PM -0600, Daniil Egranov wrote:
> Changed code structure per Leif Lindholm's request
Needs a commit message describing what the patch does.
>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Daniil Egranov <daniil.egranov@arm.com>
> ---
> Changelog:
>
> v2
> Corrected style issues and code structure.
>
> v1
> The patch reads a valid MAC address form the Juno IOFPGA registers
> and pushes it into onboard Marvell Yukon NIC.
>
> .../ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c | 270 +++++++++++++++++++++
> .../Drivers/ArmJunoDxe/ArmJunoDxeInternal.h | 13 +
> 2 files changed, 283 insertions(+)
>
> diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
> index b97f044..bc3a433 100644
> --- a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
> +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
> @@ -15,7 +15,9 @@
> #include "ArmJunoDxeInternal.h"
> #include <ArmPlatform.h>
>
> +#include <IndustryStandard/Pci.h>
> #include <Protocol/DevicePathFromText.h>
> +#include <Protocol/PciIo.h>
> #include <Protocol/PciRootBridgeIo.h>
>
> #include <Guid/EventGroup.h>
> @@ -69,6 +71,271 @@ STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath = {
> EFI_EVENT mAcpiRegistration = NULL;
>
> /**
> + This function reads PCI ID of the controller.
> +
> + @param[in] PciIo PCI IO protocol handle
> + @param[in] PciId Looking for specified PCI ID Vendor/Device
> +**/
> +STATIC
> +EFI_STATUS
> +ReadMarvellYoukonPciId (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT32 PciId
> + )
> +{
> + UINT32 DevicePciId;
> + EFI_STATUS Status;
> +
> + Status = PciIo->Pci.Read (
> + PciIo,
> + EfiPciIoWidthUint32,
> + PCI_VENDOR_ID_OFFSET,
> + 1,
> + &DevicePciId);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if (DevicePciId != PciId) {
> + return EFI_NOT_FOUND;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function searches for Marvell Yukon NIC on the Juno
> + platform and returns PCI IO protocol handle for the controller.
> +
> + @param[out] PciIo PCI IO protocol handle
> +**/
> +STATIC
> +EFI_STATUS
> +GetMarvellYukonPciIoProtocol (
> + OUT EFI_PCI_IO_PROTOCOL **PciIo
> + )
> +{
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + UINTN HIndex;
> + EFI_STATUS Status;
> +
> + Status = gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiPciIoProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer);
> + if (EFI_ERROR (Status)) {
> + return (Status);
> + }
> +
> + for (HIndex = 0; HIndex < HandleCount; ++HIndex) {
> + Status = gBS->OpenProtocol (
> + HandleBuffer[HIndex],
> + &gEfiPciIoProtocolGuid,
> + (VOID **) PciIo,
> + NULL,
> + NULL,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> +
> + Status = ReadMarvellYoukonPciId (*PciIo, JUNO_MARVELL_YUKON_ID);
> + if (EFI_ERROR (Status)) {
> + // According to UEFI Spec 2.6 for EFI_BOOT_SERVICES.OpenProtocol():
> + // when protocol was opened with EFI_OPEN_PROTOCOL_GET_PROTOCOL attribute,
> + // the caller is not required to close the protocol interface with
> + // EFI_BOOT_SERVICES.CloseProtocol().
I stand corrected.
But the comment could be a lot less verbose here.
It may be useful to say
// PciIo opened with GET_PROTOCOL, CloseProtocol not required
if you want to keep confused reviewers like me on the right track.
... but I would probably rather put that comment with the OpenProtocol
line, skip the redundant continue and do
if (Status == EFI_SUCCESS) {
break;
}
> + continue;
> + } else {
> + break;
> + }
> + }
> +
> + gBS->FreePool (HandleBuffer);
> +
> + return Status;
> +}
> +
> +/**
> + This function restore the original controller attributes and free resources
> +
> + @param[in] PciIo PCI IO protocol handle
> + @param[in] PciAttr PCI controller attributes.
> + @param[in] AcpiResDescriptor ACPI 2.0 resource descriptors for the BAR
> +**/
> +STATIC
> +VOID
> +FreePciResources (
This function is called
"Free Resources"...
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT64 PciAttr,
...but takes a parameter called "PCI Attributes" and calls
OperationSet, so the function name is misleading. This restores the
state before GetPciResources (which is also a misleading name).
Can we call it RestorePciDev()?
> + IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiResDescriptor
> + )
> +{
> + // According to UEFI Spec 2.6 for EFI_BOOT_SERVICES.OpenProtocol():
> + // when protocol was opened with EFI_OPEN_PROTOCOL_GET_PROTOCOL attribute,
> + // the caller is not required to close the protocol interface with
> + // EFI_BOOT_SERVICES.CloseProtocol().
Again, could be less verbose here.
> +
> + PciIo->Attributes (
> + PciIo,
> + EfiPciIoAttributeOperationSet,
> + PciAttr,
> + NULL
> + );
> +
> + if (AcpiResDescriptor != NULL) {
> + gBS->FreePool (AcpiResDescriptor);
> + }
> +}
> +
> +/**
> + This function provides PCI MMIO base address, old PCI controller attributes
> + and ACPI resource descriptors for the BAR.
> +
> + @param[in] PciIo PCI IO protocol handle
> + @param[out] PciRegBase PCI base MMIO address
> + @param[out] OldPciAttr Old PCI controller attributes.
> + @param[out] AcpiResDescriptor ACPI 2.0 resource descriptors for the BAR
> +**/
> +STATIC
> +EFI_STATUS
> +GetPciResources (
This function is called GetPci Resources, but also saves and modifies
the PCI controller attributes. This is somewhat semantically
misleading, so how about renaming it InitPciDev()?
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + OUT UINT32 *PciRegBase,
> + OUT UINT64 *OldPciAttr,
> + OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **AcpiResDescriptor
> + )
> +{
> + UINT64 AttrSupports;
> + EFI_STATUS Status;
> +
For documentation purpose (i.e., worth being a bit verbose in code for
ARM Ltd. platforms since we know it is likely to be used as
reference), I suggest a few comments.
// Get controller's current attributes
> + Status = PciIo->Attributes (
> + PciIo,
> + EfiPciIoAttributeOperationGet,
> + 0,
> + OldPciAttr);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
// Fetch supported attributes
> + Status = PciIo->Attributes (
> + PciIo,
> + EfiPciIoAttributeOperationSupported,
> + 0,
> + &AttrSupports);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
// Enable all supported attributes
> + AttrSupports &= EFI_PCI_DEVICE_ENABLE;
> + Status = PciIo->Attributes (
> + PciIo,
> + EfiPciIoAttributeOperationEnable,
> + AttrSupports,
> + NULL);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = PciIo->GetBarAttributes (PciIo, 0, &AttrSupports, (VOID**)AcpiResDescriptor);
Could this change from being BAR 0 if core enumeration code changed?
If not, please change to PCI_BAR_IDX0.
The code never calls SetBarAttributes, and Supports is an optional
parameter that can be NULL. It would be more clear if it was.
> + if (EFI_ERROR (Status)) {
> + FreePciResources (PciIo, *OldPciAttr, NULL);
> + return Status;
> + }
> +
> + if ((*AcpiResDescriptor)->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR &&
> + (*AcpiResDescriptor)->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM &&
> + !((*AcpiResDescriptor)->SpecificFlag & ACPI_SPECFLAG_PREFETCHABLE)) {
The above test is unreadble unless I already know what the test is
intended to discern. This is why I proposed wrapping it into a helper
function with a descriptive name. In this form it still needs a
comment explaining what the test is trying to prove that this address
range is.
Now, companion reading the code together with the specification, it
says "The configuration of a BAR of a PCI Controller is described with
one or more QWORD Address Space Descriptors followed by an End Tag.".
How do we know we have only one descriptor, or we only care about the
first one, and how do we know that can't change?
So, to summarize, this seems to check that:
- We can read BAR 0 attributes.
- BAR 0 resources contain at least one QWORD Address Space Descriptor.
- The first of these refers to something memory mapped.
- That it is not (ARM terminology) Normal memory.
Now this all sounds like a plausible way of finding the configuration
space for the on-board Yukon chip, but what is needed is an
explanation for how we know these things are all true and
unchangeable.
My vote would still be for a helper function
If the above assumptions are correct, I propose:
STATIC
EFI_STATUS
BarIsDeviceMemory (
IN EFI_PCI_IO_PROTOCOL *PciIo,
OUT UINT32 *PciRegBase
)
Including the call to GetBarAttributes, and since there does not
appear to be any further use of the Attributes, they can be freed
directly after the check.
No further comments, and I do appreciate the substantial rework (and
the amount of learning it has meant for me around the PciIo protocol,
which I had been steadfastly dodging so far).
I can fold all of these in before committing, but I would still need:
- A commit message.
- The statement of why the 4 checks are safe.
Regards,
Leif
> + *PciRegBase = (*AcpiResDescriptor)->AddrRangeMin;
> + } else {
> + FreePciResources (PciIo, *OldPciAttr, *AcpiResDescriptor);
> + EFI_ACPI_ADDRESS_SPAStatus = EFI_UNSUPPORTED;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + This function reads MAC address from IOFPGA and writes it to Marvell Yukon NIC
> +
> + @param[in] PciRegBase PCI base MMIO address
> +**/
> +STATIC
> +EFI_STATUS
> +WriteMacAddress (
> + IN UINT32 PciRegBase
> + )
> +{
> + UINT32 MacHigh;
> + UINT32 MacLow;
> +
> + // Read MAC address from IOFPGA
> + MacHigh= MmioRead32 (ARM_JUNO_SYS_PCIGBE_H);
> + MacLow = MmioRead32 (ARM_JUNO_SYS_PCIGBE_L);
> +
> + // Set software reset control register to protect from deactivation
> + // the config write state
> + MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR);
> +
> + // Convert to Marvell MAC Address register format
> + MacHigh = SwapBytes32 ((MacHigh & 0xFFFF) << 16 |
> + (MacLow & 0xFFFF0000) >> 16);
> + MacLow = SwapBytes32 (MacLow) >> 16;
> +
> + // Set MAC Address
> + MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_ENABLE);
> + MmioWrite32 (PciRegBase + R_MAC, MacHigh);
> + MmioWrite32 (PciRegBase + R_MAC_MAINT, MacHigh);
> + MmioWrite32 (PciRegBase + R_MAC + R_MAC_LOW, MacLow);
> + MmioWrite32 (PciRegBase + R_MAC_MAINT + R_MAC_LOW, MacLow);
> + MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_DISABLE);
> +
> + // Initiate device reset
> + MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_SET);
> + MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + The function reads MAC address from Juno IOFPGA registers and writes it
> + into Marvell Yukon NIC.
> +**/
> +STATIC
> +EFI_STATUS
> +ArmJunoSetNicMacAddress ()
> +{
> +
> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiResDescriptor;
> + UINT64 OldPciAttr;
> + EFI_PCI_IO_PROTOCOL* PciIo;
> + UINT32 PciRegBase;
> + EFI_STATUS Status;
> +
> + Status = GetMarvellYukonPciIoProtocol (&PciIo);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = GetPciResources (PciIo, &PciRegBase, &OldPciAttr, &AcpiResDescriptor);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = WriteMacAddress (PciRegBase);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + FreePciResources (PciIo, OldPciAttr, AcpiResDescriptor);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> Notification function of the event defined as belonging to the
> EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in
> the entry point of the driver.
> @@ -106,6 +373,9 @@ OnEndOfDxe (
>
> Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE);
> ASSERT_EFI_ERROR (Status);
> +
> + Status = ArmJunoSetNicMacAddress ();
> + ASSERT_EFI_ERROR (Status);
> }
>
> STATIC
> diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h
> index 662c413..df02770 100644
> --- a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h
> +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h
> @@ -29,6 +29,19 @@
>
> #include <IndustryStandard/Acpi.h>
>
> +#define ACPI_SPECFLAG_PREFETCHABLE 0x06
> +#define JUNO_MARVELL_YUKON_ID 0x438011AB /* Juno Marvell PCI Dev ID */
> +#define TST_CFG_WRITE_ENABLE 0x02 /* Enable Config Write */
> +#define TST_CFG_WRITE_DISABLE 0x00 /* Disable Config Write */
> +#define CS_RESET_CLR 0x02 /* SW Reset Clear */
> +#define CS_RESET_SET 0x00 /* SW Reset Set */
> +#define R_CONTROL_STATUS 0x0004 /* Control/Status Register */
> +#define R_MAC 0x0100 /* MAC Address */
> +#define R_MAC_MAINT 0x0110 /* MAC Address Maintenance */
> +#define R_MAC_LOW 0x04 /* MAC Address Low Register Offset */
> +#define R_TST_CTRL_1 0x0158 /* Test Control Register 1 */
> +
> +
> EFI_STATUS
> PciEmulationEntryPoint (
> VOID
> --
> 2.7.4
>
prev parent reply other threads:[~2017-01-04 15:12 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-12-14 1:56 [PATCH v3] ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe: Set Marvell Yukon MAC address Daniil Egranov
2017-01-04 15:12 ` Leif Lindholm [this message]
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=20170104151238.GI16872@bivouac.eciton.net \
--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