/PLDM

Open-source PLDM communication between the HOST (UEFI firmware) and BMC

Primary LanguageC

Description

This repository contains a solution for the PLDM communication between the HOST (UEFI firmware) and BMC, with both implemented via open-source components:

  • The HOST (UEFI firmware) part is based one the edk2 and edk2-platforms code,
  • The BMC part is based on the openbmc distribution.

The PLDM communication is provided via MCTP over KCS transport.

HOST (UEFI firmware) configuration

The current edk2-platfroms repository has a ManagebilityPkg that can be used to add support for the PLDM communication based on the MCTP over KCS transport. The modules in the ManagebilityPkg can be used for different scenarios, so we have to configure them in the way that is needed for us:

  • PLDM based on MCTP
  • MCTP based on KCS

This can be done with the following configuration in the DSC file:

[Components]
  ManageabilityPkg/Universal/PldmProtocol/Dxe/PldmProtocolDxe.inf {
    <LibraryClasses>
      ManageabilityTransportLib|ManageabilityPkg/Library/ManageabilityTransportMctpLib/Dxe/DxeManageabilityTransportMctp.inf
  }

  ManageabilityPkg/Universal/MctpProtocol/Dxe/MctpProtocolDxe.inf {
    <LibraryClasses>
      ManageabilityTransportLib|ManageabilityPkg/Library/ManageabilityTransportKcsLib/Dxe/DxeManageabilityTransportKcs.inf
  }

For the successfull compilation we would also need to add a ManageabilityTransportHelperLib library:

[LibraryClasses]
  ManageabilityTransportHelperLib|ManageabilityPkg/Library/BaseManageabilityTransportHelperLib/BaseManageabilityTransportHelper.inf

And configure some PCDs:

[PcdsFixedAtBuild]
  gManageabilityPkgTokenSpaceGuid.PcdMctpSourceEndpointId|9
  gManageabilityPkgTokenSpaceGuid.PcdMctpDestinationEndpointId|8
  gManageabilityPkgTokenSpaceGuid.PcdMctpKcsBaseAddress|0xca8

Couple of words about PCDs:

BMC configuration

The MCTP communication on the BMC side is based on the kernel net mctp driver (info).

Currently there is no support for the MCTP over KCS binding (current bindings), but the repository contains patches for the kernel to add the necessary driver.

Configuration

For the kernel-based MCTP stack it is necessary to add the following include to your machine configuration file:

require conf/distro/include/pldm.inc

Patches

Since currently there is no MCTP-over-KCS binding driver we need to add some patches to the kernel:

Add all of these patches to your OpenBMC distibution via a standard recipe override mechanics.

Kconfig

The pldm.inc file that we've included earlier would add the kernel configuration options from the meta-phosphor/recipes-kernel/linux/mctp/mctp.cfg file. So we need to add our driver to this Kconfig fragment:

diff --git a/meta-phosphor/recipes-kernel/linux/mctp/mctp.cfg b/meta-phosphor/recipes-kernel/linux/mctp/mctp.cfg
index 26f3c4157e..f73d55ffc9 100644
--- a/meta-phosphor/recipes-kernel/linux/mctp/mctp.cfg
+++ b/meta-phosphor/recipes-kernel/linux/mctp/mctp.cfg
@@ -1,3 +1,4 @@
 CONFIG_MCTP=y
 CONFIG_MCTP_SERIAL=y
 CONFIG_MCTP_TRANSPORT_I2C=y
+CONFIG_MCTP_TRANSPORT_KCS=y

DTS

To the board DTS file we need to add a KCS channel with the enabled interrupt.

For example here is a configuration that I add to my DTS:

&kcs2 {
       status = "okay";
       aspeed,lpc-io-reg = <0xCA8 0xCA9>;
       aspeed,lpc-interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
};

It is perfectly normal to have another KCS channel enabled in the system. For example on my board I also have kcs3 for the IPMI communication:

&kcs3 {
	status = "okay";
	aspeed,lpc-io-reg = <0xCA2>;
};

Keep in mind that kcs channels have some constraints about IO settings.

For example here are constraints for the IO port values (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/char/ipmi/kcs_bmc_aspeed.c?h=v6.5#n210):

/*
 * We note D for Data, and C for Cmd/Status, default rules are
 *
 * 1. Only the D address is given:
 *   A. KCS1/KCS2 (D/C: X/X+4)
 *      D/C: CA0h/CA4h
 *      D/C: CA8h/CACh
 *   B. KCS3 (D/C: XX2/XX3h)
 *      D/C: CA2h/CA3h
 *   C. KCS4 (D/C: X/X+1)
 *      D/C: CA4h/CA5h
 *
 * 2. Both the D/C addresses are given:
 *   A. KCS1/KCS2/KCS4 (D/C: X/Y)
 *      D/C: CA0h/CA1h
 *      D/C: CA8h/CA9h
 *      D/C: CA4h/CA5h
 *   B. KCS3 (D/C: XX2/XX3h)
 *      D/C: CA2h/CA3h

There is also SIRQ constraint for the KCS1 channel that it can only use SIRQ1 or SIRQ12 (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/char/ipmi/kcs_bmc_aspeed.c?h=v6.5#n172)

Packages

Add the following package to your image:

pldm

Configuring mctpkcs2 interface

Since mctp is a network device, before performing actual communication you have to open the interface and setup address and routing. Offcourse you can always do this manually by executing these commands on the running BMC system:

$ mctp addr add 8 dev mctpkcs2
$ mctp route add 9 via mctpkcs2
$ ifconfig mctpkcs2 up

But it would be better to write these commands in a systemd service that would be executed on every system start. You can find example of a recipe that adds such unit to the system in the recipes-support folder.

Building and flashing

After all of the above steps are applied you need to build OpenBMC image and flash it to the target device.

Now you are ready to test MCTP communication from the HOST via the PldmMessage UEFI application.

Test application

The repository contains a simple application for the UEFI shell (PldmMessage), that utilizes EDKII_MCTP_PROTOCOL to send GetPLDMTypes (0x04) command

BMC handling for this command is located here.

Putting everything together

Now when everything is in place, launch PldmMessage.efi from the UEFI shell. Here is the expected output:

FS0:\> PldmMessage.efi
MCTP protocol version 256
PldmRequestBuffer[0]=0x95
PldmRequestBuffer[1]=0x00
PldmRequestBuffer[2]=0x04
PldmResponse[0]=0x1D
PldmResponse[1]=0x00
PldmResponse[2]=0x00
PldmResponse[3]=0x00
PldmResponse[4]=0x00
PldmResponse[5]=0x00
PldmResponse[6]=0x00
PldmResponse[7]=0x00

If communication is stuck

The UEFI and mctpkcs code are currently under development, so if you've encountered a situation with a broken KCS state machine, you can always reboot MCTP network interface on the BMC side with the following commands:

$ ifconfig mctpkcs2 down
$ ifconfig mctpkcs2 up