Commit 3cfaeb33 authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman

mei: expose fw version to sysfs

The ME FW version is constantly used by detection and update tools.
To improve the reliability and simplify these tools provide
a sysfs interface to access version of the platform ME firmware
in the following format:
<platform>:<major>.<minor>.<milestone>.<build>.
There can be up to three such blocks for different FW components.
Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9a7c0b69
...@@ -54,3 +54,14 @@ Description: Configure tx queue limit ...@@ -54,3 +54,14 @@ Description: Configure tx queue limit
Set maximal number of pending writes Set maximal number of pending writes
per opened session. per opened session.
What: /sys/class/mei/meiN/fw_ver
Date: May 2018
KernelVersion: 4.18
Contact: Tomas Winkler <tomas.winkler@intel.com>
Description: Display the ME firmware version.
The version of the platform ME firmware is in format:
<platform>:<major>.<minor>.<milestone>.<build_no>.
There can be up to three such blocks for different
FW components.
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -96,8 +96,22 @@ struct mkhi_fwcaps { ...@@ -96,8 +96,22 @@ struct mkhi_fwcaps {
u8 data[0]; u8 data[0];
} __packed; } __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_GROUP_ID 0x3
#define MKHI_FWCAPS_SET_OS_VER_APP_RULE_CMD 6 #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 { struct mkhi_msg_hdr {
u8 group_id; u8 group_id;
u8 command; u8 command;
...@@ -139,21 +153,81 @@ static int mei_osver(struct mei_cl_device *cldev) ...@@ -139,21 +153,81 @@ static int mei_osver(struct mei_cl_device *cldev)
return __mei_cl_send(cldev->cl, buf, size, mode); 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) static void mei_mkhi_fix(struct mei_cl_device *cldev)
{ {
int ret; int ret;
if (!cldev->bus->hbm_f_os_supported)
return;
ret = mei_cldev_enable(cldev); ret = mei_cldev_enable(cldev);
if (ret) if (ret)
return; return;
ret = mei_osver(cldev); ret = mei_fwver(cldev);
if (ret < 0) 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); mei_cldev_disable(cldev);
} }
......
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * Intel Management Engine Interface (Intel MEI) Linux driver
* Copyright (c) 2003-2012, Intel Corporation. * Copyright (c) 2003-2018, Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -812,11 +812,39 @@ static ssize_t tx_queue_limit_store(struct device *device, ...@@ -812,11 +812,39 @@ static ssize_t tx_queue_limit_store(struct device *device,
} }
static DEVICE_ATTR_RW(tx_queue_limit); static DEVICE_ATTR_RW(tx_queue_limit);
/**
* fw_ver_show - display ME FW version
*
* @device: device pointer
* @attr: attribute pointer
* @buf: char out buffer
*
* Return: number of the bytes printed into buf or error
*/
static ssize_t fw_ver_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct mei_device *dev = dev_get_drvdata(device);
struct mei_fw_version *ver;
ssize_t cnt = 0;
int i;
ver = dev->fw_ver;
for (i = 0; i < MEI_MAX_FW_VER_BLOCKS; i++)
cnt += scnprintf(buf + cnt, PAGE_SIZE - cnt, "%u:%u.%u.%u.%u\n",
ver[i].platform, ver[i].major, ver[i].minor,
ver[i].hotfix, ver[i].buildno);
return cnt;
}
static DEVICE_ATTR_RO(fw_ver);
static struct attribute *mei_attrs[] = { static struct attribute *mei_attrs[] = {
&dev_attr_fw_status.attr, &dev_attr_fw_status.attr,
&dev_attr_hbm_ver.attr, &dev_attr_hbm_ver.attr,
&dev_attr_hbm_ver_drv.attr, &dev_attr_hbm_ver_drv.attr,
&dev_attr_tx_queue_limit.attr, &dev_attr_tx_queue_limit.attr,
&dev_attr_fw_ver.attr,
NULL NULL
}; };
ATTRIBUTE_GROUPS(mei); ATTRIBUTE_GROUPS(mei);
......
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * Intel Management Engine Interface (Intel MEI) Linux driver
* Copyright (c) 2003-2012, Intel Corporation. * Copyright (c) 2003-2018, Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -354,6 +354,25 @@ enum mei_pg_state { ...@@ -354,6 +354,25 @@ enum mei_pg_state {
const char *mei_pg_state_str(enum mei_pg_state state); const char *mei_pg_state_str(enum mei_pg_state state);
/**
* struct mei_fw_version - MEI FW version struct
*
* @platform: platform identifier
* @major: major version field
* @minor: minor version field
* @buildno: build number version field
* @hotfix: hotfix number version field
*/
struct mei_fw_version {
u8 platform;
u8 major;
u16 minor;
u16 buildno;
u16 hotfix;
};
#define MEI_MAX_FW_VER_BLOCKS 3
/** /**
* struct mei_device - MEI private device struct * struct mei_device - MEI private device struct
* *
...@@ -402,6 +421,8 @@ const char *mei_pg_state_str(enum mei_pg_state state); ...@@ -402,6 +421,8 @@ const char *mei_pg_state_str(enum mei_pg_state state);
* @hbm_f_ie_supported : hbm feature immediate reply to enum request * @hbm_f_ie_supported : hbm feature immediate reply to enum request
* @hbm_f_os_supported : hbm feature support OS ver message * @hbm_f_os_supported : hbm feature support OS ver message
* *
* @fw_ver : FW versions
*
* @me_clients_rwsem: rw lock over me_clients list * @me_clients_rwsem: rw lock over me_clients list
* @me_clients : list of FW clients * @me_clients : list of FW clients
* @me_clients_map : FW clients bit map * @me_clients_map : FW clients bit map
...@@ -478,6 +499,8 @@ struct mei_device { ...@@ -478,6 +499,8 @@ struct mei_device {
unsigned int hbm_f_ie_supported:1; unsigned int hbm_f_ie_supported:1;
unsigned int hbm_f_os_supported:1; unsigned int hbm_f_os_supported:1;
struct mei_fw_version fw_ver[MEI_MAX_FW_VER_BLOCKS];
struct rw_semaphore me_clients_rwsem; struct rw_semaphore me_clients_rwsem;
struct list_head me_clients; struct list_head me_clients;
DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX); DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment