summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch')
-rw-r--r--meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch330
1 files changed, 330 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch b/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch
new file mode 100644
index 000000000..ce160e137
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch
@@ -0,0 +1,330 @@
+From 7bbaf8f4c268f9df195a84486caf3c22e21db59e Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Tue, 21 May 2019 00:19:16 +0530
+Subject: [PATCH] IPMI command handler implementation in uboot
+
+IPMI command handler implemtation in uBoot.
+Implemented IPMI commands:
+ 1) Get Device ID
+ 2) Get Self Test Result
+
+Tested By:
+Ran the above IPMI command Via KCS channel
+and got proper response.
+- Get Device ID
+ Req: ipmitool raw 6 1
+ Res: 23 00 82 03 02 00 57 01 00 7b 00 00 00 00 00
+- Get Self Test Results
+ Req: ipmitool raw 6 4
+ Res: 56 00
+
+Change-Id: I18b205bc45c34f7c4ef16adc29fa5bd494624ceb
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+
+---
+ board/aspeed/ast-g5/Makefile | 1 +
+ board/aspeed/ast-g5/ast-g5-kcs.c | 77 ++++++++++---------
+ board/aspeed/ast-g5/ipmi-handler.c | 118 +++++++++++++++++++++++++++++
+ board/aspeed/ast-g5/ipmi-handler.h | 40 ++++++++++
+ 4 files changed, 202 insertions(+), 34 deletions(-)
+ create mode 100644 board/aspeed/ast-g5/ipmi-handler.c
+ create mode 100644 board/aspeed/ast-g5/ipmi-handler.h
+
+diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile
+index 05972b9d17..f28fcfe61c 100644
+--- a/board/aspeed/ast-g5/Makefile
++++ b/board/aspeed/ast-g5/Makefile
+@@ -5,3 +5,4 @@ obj-y += ast-g5-irq.o
+ obj-y += ast-g5-gpio.o
+ obj-y += ast-g5-timer.o
+ obj-y += ast-g5-kcs.o
++obj-y += ipmi-handler.o
+diff --git a/board/aspeed/ast-g5/ast-g5-kcs.c b/board/aspeed/ast-g5/ast-g5-kcs.c
+index 7bff26f9db..98bf69ba85 100644
+--- a/board/aspeed/ast-g5/ast-g5-kcs.c
++++ b/board/aspeed/ast-g5/ast-g5-kcs.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0
+ // Copyright (c) 2018-2019 Intel Corporation
+
+-#include "ast-g5-kcs.h"
++#include "ipmi-handler.h"
+
+ #ifdef DEBUG_KCS_ENABLED
+ #define DBG_KCS printf
+@@ -9,11 +9,6 @@
+ #define DBG_KCS(...)
+ #endif
+
+-/* TODO: Move to IPMI file. */
+-#define IPMI_CC_OK 0x00
+-#define IPMI_CC_INVALID 0xC1
+-#define IPMI_CC_UNSPECIFIED 0xFF
+-
+ #define KCS_CHANNEL_NO_3 3
+
+ static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 };
+@@ -103,6 +98,7 @@ static void init_kcs_packet(u16 channel_num)
+ static void process_kcs_request(u16 channel_num)
+ {
+ struct kcs_packet *kcs_pkt = NULL;
++ struct ipmi_cmd_data ipmi_data;
+ int i;
+
+ kcs_pkt = get_kcs_packet(channel_num);
+@@ -117,37 +113,49 @@ static void process_kcs_request(u16 channel_num)
+ DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]);
+ DBG_KCS("\n");
+ #endif
++ u8 req_lun = kcs_pkt->data_in[0] & 0x03; /* LUN[1:0] */
++ ipmi_data.net_fun = (kcs_pkt->data_in[0] >> 2); /* netfn[7:2] */
++ ipmi_data.cmd = kcs_pkt->data_in[1]; /* cmd */
++ /* We support only BMC LUN 00h */
++ if (req_lun != LUN_BMC) {
++ kcs_pkt->data_out[0] =
++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun);
++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */
++ kcs_pkt->data_out[2] = IPMI_CC_INVALID_CMD_LUN; /* CC code */
++ kcs_pkt->data_out_len = 3;
++ goto done;
++ }
+
+- /*
+- * TODO: Move it to IPMI Command Handler
+- * Below code is added for timebeing till
+- * we implement the IPMI command handler.
+- */
+- kcs_pkt->data_out[0] = kcs_pkt->data_in[0]; /* netfn */
+- kcs_pkt->data_out[1] = kcs_pkt->data_in[1]; /* cmd */
+- kcs_pkt->data_out[2] = IPMI_CC_OK; /* cc */
+-
+- if (((kcs_pkt->data_in[0] >> 2) == 0x06) &&
+- (kcs_pkt->data_in[1] == 0x01)) {
+- /* Get Device ID */
+- u8 device_id[15] = { 0x23, 0x00, 0x12, 0x03, 0x02,
+- 0xBF, 0x57, 0x01, 0x00, 0x7B,
+- 0x00, 0x00, 0x00, 0x00, 0x00 };
+- for (i = 0; i < 15; i++)
+- kcs_pkt->data_out[i + 3] = device_id[i];
+- kcs_pkt->data_out_len = 18;
+- } else if (((kcs_pkt->data_in[0] >> 2) == 0x06) &&
+- (kcs_pkt->data_in[1] == 0x04)) {
+- /* Get Self Test Results */
+- kcs_pkt->data_out[3] = 0x56;
+- kcs_pkt->data_out[4] = 0x00;
+- kcs_pkt->data_out_len = 5;
+- } else {
+- kcs_pkt->data_out[2] =
+- IPMI_CC_INVALID; /* Invalid or not supported. */
++ /* Boundary check */
++ if ((kcs_pkt->data_in_idx - 2) > sizeof(ipmi_data.req_data)) {
++ kcs_pkt->data_out[0] =
++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun);
++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */
++ kcs_pkt->data_out[2] = IPMI_CC_OUT_OF_SPACE; /* CC code */
+ kcs_pkt->data_out_len = 3;
++ goto done;
+ }
+- /* END: TODO */
++ /* Fill in IPMI request data */
++ ipmi_data.req_len = kcs_pkt->data_in_idx - 2;
++ for (i = 0; i < kcs_pkt->data_in_idx - 2; i++)
++ ipmi_data.req_data[i] = kcs_pkt->data_in[i + 2];
++
++ /* Call IPMI command handler */
++ ipmi_cmd_handler(&ipmi_data);
++
++ /* Get IPMI response and fill KCS out data */
++ /* First 2 bytes in KCS response are netFn, Cmd */
++ kcs_pkt->data_out[0] = GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun);
++ kcs_pkt->data_out[1] = ipmi_data.cmd;
++ if ((ipmi_data.res_len + 2) > sizeof(kcs_pkt->data_out)) {
++ kcs_pkt->data_out[2] = IPMI_CC_UNSPECIFIED; /* CC code */
++ kcs_pkt->data_out_len = 3;
++ goto done;
++ }
++ for (i = 0; i < ipmi_data.res_len; i++)
++ kcs_pkt->data_out[i + 2] = ipmi_data.res_data[i];
++
++ kcs_pkt->data_out_len = ipmi_data.res_len + 2;
+
+ #ifdef DEBUG_KCS_ENABLED
+ DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len);
+@@ -156,6 +164,7 @@ static void process_kcs_request(u16 channel_num)
+ DBG_KCS("\n");
+ #endif
+
++done:
+ kcs_pkt->phase = KCS_PHASE_READ;
+ write_data(channel_num, kcs_pkt->data_out[kcs_pkt->data_out_idx++]);
+ kcs_pkt->read_req_done = false;
+diff --git a/board/aspeed/ast-g5/ipmi-handler.c b/board/aspeed/ast-g5/ipmi-handler.c
+new file mode 100644
+index 0000000000..9cccee9f2f
+--- /dev/null
++++ b/board/aspeed/ast-g5/ipmi-handler.c
+@@ -0,0 +1,118 @@
++
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018-2019 Intel Corporation
++
++#include "ipmi-handler.h"
++
++/* IPMI network function codes */
++#define NETFN_APP 0x06
++
++/* IPMI command codes */
++#define CMD_GET_DEV_ID 0x01
++#define CMD_GET_SELF_TEST_RESULTS 0x04
++
++typedef u16 (*fun_handler)(u8 *req, u16 req_len, u8 *res);
++
++struct get_dev_id {
++ u8 completion_code;
++ u8 dev_id;
++ u8 dev_rev;
++ u8 fw_rev1;
++ u8 fw_rev2;
++ u8 ipmi_ver;
++ u8 dev_support;
++ u8 mfg_id[3];
++ u8 product_id[2];
++ u8 aux_fw_rev[4];
++};
++struct self_test_res {
++ u8 completion_code;
++ u8 res_byte[2];
++};
++
++struct ipmi_cmd_table {
++ u8 net_fun;
++ u8 cmd;
++ fun_handler process_cmd;
++};
++
++static u16 get_device_id(u8 *req, u16 req_len, u8 *res)
++{
++ /* Get Device ID */
++ bool operation = 1; /* Firmware operation */
++ u8 intel_mfg_id[3] = { 0x57, 0x01, 0x00 };
++ u8 platform_id[2] = { 0x7B, 0x00 };
++ u8 aux_fw_rev[4] = { 0x00, 0x00, 0x00, 0x00 };
++ struct get_dev_id *result = (struct get_dev_id *)res;
++
++ if (req_len != 0) {
++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH;
++ return sizeof(result->completion_code);
++ }
++
++ result->completion_code = IPMI_CC_OK;
++ result->dev_id = 0x23;
++ result->dev_rev = 0x00; /* Not provides dev SDR */
++
++ result->ipmi_ver = 0x02; /* IPMI 2.0 */
++ result->dev_support = 0x00; /* No dev support in this mode */
++ memcpy(result->mfg_id, intel_mfg_id, sizeof(result->mfg_id));
++ memcpy(result->aux_fw_rev, aux_fw_rev, sizeof(result->aux_fw_rev));
++
++ /* TODO: Get Firmware version from flash(PFM Header) */
++ result->fw_rev1 = ((operation << 7) | (0x02 & 0x7F));
++ result->fw_rev2 = 0x03;
++ /* TODO: Read Platform ID from GPIO */
++ memcpy(result->product_id, platform_id, sizeof(result->product_id));
++
++ return sizeof(struct get_dev_id);
++}
++
++static u16 get_self_test_result(u8 *req, u16 req_len, u8 *res)
++{
++ /* Get Self Test Results */
++ struct self_test_res *result = (struct self_test_res *)res;
++
++ if (req_len != 0) {
++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH;
++ return sizeof(result->completion_code);
++ }
++
++ result->completion_code = IPMI_CC_OK;
++ result->res_byte[0] = 0x56; /* Self test function not implemented. */
++ result->res_byte[1] = 0x00;
++
++ return sizeof(struct self_test_res);
++}
++
++const struct ipmi_cmd_table cmd_info[] = {
++ { NETFN_APP, CMD_GET_DEV_ID, get_device_id },
++ { NETFN_APP, CMD_GET_SELF_TEST_RESULTS, get_self_test_result }
++};
++
++#define CMD_TABLE_SIZE ARRAY_SIZE(cmd_info)
++
++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data)
++{
++ int i = 0;
++ for (i = 0; i < CMD_TABLE_SIZE; i++) {
++ if ((cmd_info[i].net_fun == ipmi_data->net_fun) &&
++ (cmd_info[i].cmd == ipmi_data->cmd)) {
++ break;
++ }
++ }
++
++ if (i == CMD_TABLE_SIZE) {
++ /* Invalid or not supported. */
++ ipmi_data->res_data[0] = IPMI_CC_INVALID_CMD;
++ ipmi_data->res_len = 1;
++ return;
++ }
++
++ /* Call the appropriate function handler */
++ ipmi_data->res_len =
++ cmd_info[i].process_cmd(ipmi_data->req_data, ipmi_data->req_len,
++ &ipmi_data->res_data[0]);
++
++ return;
++}
+diff --git a/board/aspeed/ast-g5/ipmi-handler.h b/board/aspeed/ast-g5/ipmi-handler.h
+new file mode 100644
+index 0000000000..9d46d9bd9a
+--- /dev/null
++++ b/board/aspeed/ast-g5/ipmi-handler.h
+@@ -0,0 +1,40 @@
++
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright (c) 2018-2019 Intel Corporation */
++
++#include "ast-g5-kcs.h"
++
++/* IPMI completion codes */
++#define IPMI_CC_OK 0x00
++#define IPMI_CC_NODE_BUSY 0xC0
++#define IPMI_CC_INVALID_CMD 0xC1
++#define IPMI_CC_INVALID_CMD_LUN 0xC2
++#define IPMI_CC_OUT_OF_SPACE 0xC4
++#define IPMI_CC_INVALID_DATA_LENGTH 0xC7
++#define IPMI_CC_INVALID_DATA_FIELD 0xCC
++#define IPMI_CC_UNSPECIFIED 0xFF
++
++/* BMC IPMB LUNs */
++#define LUN_BMC 0x00
++#define LUN_OEM1 0x01
++#define LUN_SMS 0x02
++#define LUN_OEM2 0x01
++
++
++#define MAX_IPMI_REQ_DATA_SIZE MAX_KCS_PKT_SIZE
++#define MAX_IPMI_RES_DATA_SIZE 64
++
++/* Response netFn[7:2], Lun[1:0] */
++#define GET_RESP_NETFN_LUN(lun, netfn) \
++ ((lun & 0x03) | (((netfn + 1) << 2) & 0xFD))
++
++struct ipmi_cmd_data {
++ u8 net_fun;
++ u8 cmd;
++ u16 req_len;
++ u16 res_len;
++ u8 req_data[MAX_IPMI_REQ_DATA_SIZE];
++ u8 res_data[MAX_IPMI_RES_DATA_SIZE];
++};
++
++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data);