|
@@ -1,7 +1,7 @@
|
|
|
/*
|
|
|
*
|
|
|
* Intel Management Engine Interface (Intel MEI) Linux driver
|
|
|
- * Copyright (c) 2003-2013, Intel Corporation.
|
|
|
+ * Copyright (c) 2003-2018, Intel Corporation.
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
* under the terms and conditions of the GNU General Public License,
|
|
@@ -96,8 +96,22 @@ struct mkhi_fwcaps {
|
|
|
u8 data[0];
|
|
|
} __packed;
|
|
|
|
|
|
+struct mkhi_fw_ver_block {
|
|
|
+ u16 minor;
|
|
|
+ u8 major;
|
|
|
+ u8 platform;
|
|
|
+ u16 buildno;
|
|
|
+ u16 hotfix;
|
|
|
+} __packed;
|
|
|
+
|
|
|
+struct mkhi_fw_ver {
|
|
|
+ struct mkhi_fw_ver_block ver[MEI_MAX_FW_VER_BLOCKS];
|
|
|
+} __packed;
|
|
|
+
|
|
|
#define MKHI_FWCAPS_GROUP_ID 0x3
|
|
|
#define MKHI_FWCAPS_SET_OS_VER_APP_RULE_CMD 6
|
|
|
+#define MKHI_GEN_GROUP_ID 0xFF
|
|
|
+#define MKHI_GEN_GET_FW_VERSION_CMD 0x2
|
|
|
struct mkhi_msg_hdr {
|
|
|
u8 group_id;
|
|
|
u8 command;
|
|
@@ -139,21 +153,81 @@ static int mei_osver(struct mei_cl_device *cldev)
|
|
|
return __mei_cl_send(cldev->cl, buf, size, mode);
|
|
|
}
|
|
|
|
|
|
+#define MKHI_FWVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \
|
|
|
+ sizeof(struct mkhi_fw_ver))
|
|
|
+#define MKHI_FWVER_LEN(__num) (sizeof(struct mkhi_msg_hdr) + \
|
|
|
+ sizeof(struct mkhi_fw_ver_block) * (__num))
|
|
|
+#define MKHI_RCV_TIMEOUT 500 /* receive timeout in msec */
|
|
|
+static int mei_fwver(struct mei_cl_device *cldev)
|
|
|
+{
|
|
|
+ char buf[MKHI_FWVER_BUF_LEN];
|
|
|
+ struct mkhi_msg *req;
|
|
|
+ struct mkhi_fw_ver *fwver;
|
|
|
+ int bytes_recv, ret, i;
|
|
|
+
|
|
|
+ memset(buf, 0, sizeof(buf));
|
|
|
+
|
|
|
+ req = (struct mkhi_msg *)buf;
|
|
|
+ req->hdr.group_id = MKHI_GEN_GROUP_ID;
|
|
|
+ req->hdr.command = MKHI_GEN_GET_FW_VERSION_CMD;
|
|
|
+
|
|
|
+ ret = __mei_cl_send(cldev->cl, buf, sizeof(struct mkhi_msg_hdr),
|
|
|
+ MEI_CL_IO_TX_BLOCKING);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&cldev->dev, "Could not send ReqFWVersion cmd\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = 0;
|
|
|
+ bytes_recv = __mei_cl_recv(cldev->cl, buf, sizeof(buf), 0,
|
|
|
+ MKHI_RCV_TIMEOUT);
|
|
|
+ if (bytes_recv < MKHI_FWVER_LEN(1)) {
|
|
|
+ /*
|
|
|
+ * Should be at least one version block,
|
|
|
+ * error out if nothing found
|
|
|
+ */
|
|
|
+ dev_err(&cldev->dev, "Could not read FW version\n");
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ fwver = (struct mkhi_fw_ver *)req->data;
|
|
|
+ memset(cldev->bus->fw_ver, 0, sizeof(cldev->bus->fw_ver));
|
|
|
+ for (i = 0; i < MEI_MAX_FW_VER_BLOCKS; i++) {
|
|
|
+ if (bytes_recv < MKHI_FWVER_LEN(i + 1))
|
|
|
+ break;
|
|
|
+ dev_dbg(&cldev->dev, "FW version%d %d:%d.%d.%d.%d\n",
|
|
|
+ i, fwver->ver[i].platform,
|
|
|
+ fwver->ver[i].major, fwver->ver[i].minor,
|
|
|
+ fwver->ver[i].hotfix, fwver->ver[i].buildno);
|
|
|
+
|
|
|
+ cldev->bus->fw_ver[i].platform = fwver->ver[i].platform;
|
|
|
+ cldev->bus->fw_ver[i].major = fwver->ver[i].major;
|
|
|
+ cldev->bus->fw_ver[i].minor = fwver->ver[i].minor;
|
|
|
+ cldev->bus->fw_ver[i].hotfix = fwver->ver[i].hotfix;
|
|
|
+ cldev->bus->fw_ver[i].buildno = fwver->ver[i].buildno;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static void mei_mkhi_fix(struct mei_cl_device *cldev)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
- if (!cldev->bus->hbm_f_os_supported)
|
|
|
- return;
|
|
|
-
|
|
|
ret = mei_cldev_enable(cldev);
|
|
|
if (ret)
|
|
|
return;
|
|
|
|
|
|
- ret = mei_osver(cldev);
|
|
|
+ ret = mei_fwver(cldev);
|
|
|
if (ret < 0)
|
|
|
- dev_err(&cldev->dev, "OS version command failed %d\n", ret);
|
|
|
+ dev_err(&cldev->dev, "FW version command failed %d\n", ret);
|
|
|
|
|
|
+ if (cldev->bus->hbm_f_os_supported) {
|
|
|
+ ret = mei_osver(cldev);
|
|
|
+ if (ret < 0)
|
|
|
+ dev_err(&cldev->dev, "OS version command failed %d\n",
|
|
|
+ ret);
|
|
|
+ }
|
|
|
mei_cldev_disable(cldev);
|
|
|
}
|
|
|
|