aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/mei
diff options
context:
space:
mode:
authorLinus Torvalds2014-12-14 16:43:47 -0800
committerLinus Torvalds2014-12-14 16:43:47 -0800
commit6ae840e7cc4be0be3aa40d9f67c35c75cfc67d83 (patch)
tree9c83c87a8670ef678d95f8d6f76a07f24a09a49f /drivers/misc/mei
parente6b5be2be4e30037eb551e0ed09dd97bd00d85d3 (diff)
parent91905b6f4afe51e23a3f58df93e4cdc5e49cf40c (diff)
Merge tag 'char-misc-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH: "Here's the big char/misc driver update for 3.19-rc1 Lots of little things all over the place in different drivers, and a new subsystem, "coresight" has been added. Full details are in the shortlog" * tag 'char-misc-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (73 commits) parport: parport_pc, do not remove parent devices early spmi: Remove shutdown/suspend/resume kernel-doc carma-fpga-program: drop videobuf dependency carma-fpga: drop videobuf dependency carma-fpga-program.c: fix compile errors i8k: Fix temperature bug handling in i8k_get_temp() cxl: Name interrupts in /proc/interrupt CXL: Return error to PSL if IRQ demultiplexing fails & print clearer warning coresight-replicator: remove .owner field for driver coresight: fixed comments in coresight.h coresight: fix typo in comment in coresight-priv.h coresight: bindings for coresight drivers coresight: Adding ABI documentation w1: support auto-load of w1_bq27000 module. w1: avoid potential u16 overflow cn: verify msg->len before making callback mei: export fw status registers through sysfs mei: read and print all six FW status registers mei: txe: add cherrytrail device id mei: kill cached host and me csr values ...
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r--drivers/misc/mei/amthif.c34
-rw-r--r--drivers/misc/mei/bus.c4
-rw-r--r--drivers/misc/mei/client.c2
-rw-r--r--drivers/misc/mei/debugfs.c8
-rw-r--r--drivers/misc/mei/hbm.c23
-rw-r--r--drivers/misc/mei/hbm.h4
-rw-r--r--drivers/misc/mei/hw-me-regs.h12
-rw-r--r--drivers/misc/mei/hw-me.c49
-rw-r--r--drivers/misc/mei/hw-me.h10
-rw-r--r--drivers/misc/mei/hw-txe.c7
-rw-r--r--drivers/misc/mei/init.c38
-rw-r--r--drivers/misc/mei/interrupt.c12
-rw-r--r--drivers/misc/mei/main.c43
-rw-r--r--drivers/misc/mei/mei_dev.h39
-rw-r--r--drivers/misc/mei/nfc.c52
-rw-r--r--drivers/misc/mei/pci-me.c12
-rw-r--r--drivers/misc/mei/pci-txe.c1
-rw-r--r--drivers/misc/mei/wd.c9
18 files changed, 239 insertions, 120 deletions
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 6cdce8477f57..79f53941779d 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -262,6 +262,7 @@ out:
static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
{
struct mei_msg_hdr mei_hdr;
+ struct mei_cl *cl;
int ret;
if (!dev || !cb)
@@ -277,8 +278,9 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
dev->iamthif_msg_buf_size = cb->request_buffer.size;
memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
cb->request_buffer.size);
+ cl = &dev->iamthif_cl;
- ret = mei_cl_flow_ctrl_creds(&dev->iamthif_cl);
+ ret = mei_cl_flow_ctrl_creds(cl);
if (ret < 0)
return ret;
@@ -292,8 +294,8 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
mei_hdr.msg_complete = 1;
}
- mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
- mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
+ mei_hdr.host_addr = cl->host_client_id;
+ mei_hdr.me_addr = cl->me_client_id;
mei_hdr.reserved = 0;
mei_hdr.internal = 0;
dev->iamthif_msg_buf_index += mei_hdr.length;
@@ -302,7 +304,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
return ret;
if (mei_hdr.msg_complete) {
- if (mei_cl_flow_ctrl_reduce(&dev->iamthif_cl))
+ if (mei_cl_flow_ctrl_reduce(cl))
return -EIO;
dev->iamthif_flow_control_pending = true;
dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
@@ -360,8 +362,7 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
void mei_amthif_run_next_cmd(struct mei_device *dev)
{
struct mei_cl_cb *cb;
- struct mei_cl_cb *next;
- int status;
+ int ret;
if (!dev)
return;
@@ -376,16 +377,14 @@ void mei_amthif_run_next_cmd(struct mei_device *dev)
dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
- list_for_each_entry_safe(cb, next, &dev->amthif_cmd_list.list, list) {
- list_del(&cb->list);
- if (!cb->cl)
- continue;
- status = mei_amthif_send_cmd(dev, cb);
- if (status)
- dev_warn(dev->dev, "amthif write failed status = %d\n",
- status);
- break;
- }
+ cb = list_first_entry_or_null(&dev->amthif_cmd_list.list,
+ typeof(*cb), list);
+ if (!cb)
+ return;
+ list_del(&cb->list);
+ ret = mei_amthif_send_cmd(dev, cb);
+ if (ret)
+ dev_warn(dev->dev, "amthif write failed status = %d\n", ret);
}
@@ -536,9 +535,6 @@ int mei_amthif_irq_read_msg(struct mei_device *dev,
cb = dev->iamthif_current_cb;
dev->iamthif_current_cb = NULL;
- if (!cb->cl)
- return -ENODEV;
-
dev->iamthif_stall_timer = 0;
cb->buf_idx = dev->iamthif_msg_buf_index;
cb->read_time = jiffies;
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 4d20d60ca38d..b3a72bca5242 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -140,7 +140,7 @@ static struct device_type mei_cl_device_type = {
.release = mei_cl_dev_release,
};
-static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
+struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *dev,
uuid_le uuid)
{
struct mei_cl *cl;
@@ -160,7 +160,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
struct mei_cl *cl;
int status;
- cl = mei_bus_find_mei_cl_by_uuid(dev, uuid);
+ cl = mei_cl_bus_find_cl_by_uuid(dev, uuid);
if (cl == NULL)
return NULL;
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index bc9ba5359bc6..1382d551d7ed 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -146,7 +146,7 @@ static void __mei_io_list_flush(struct mei_cl_cb *list,
/* enable removing everything if no cl is specified */
list_for_each_entry_safe(cb, next, &list->list, list) {
- if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
+ if (!cl || mei_cl_cmp_id(cl, cb->cl)) {
list_del(&cb->list);
if (free)
mei_io_cb_free(cb);
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index ce1566715f80..b60b4263cf0f 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -34,7 +34,7 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
int pos = 0;
int ret;
-#define HDR " |id|addr| UUID |con|msg len|sb|\n"
+#define HDR " |id|fix| UUID |con|msg len|sb|\n"
mutex_lock(&dev->device_lock);
@@ -56,12 +56,8 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
list_for_each_entry(me_cl, &dev->me_clients, list) {
- /* skip me clients that cannot be connected */
- if (me_cl->props.max_number_of_connections == 0)
- continue;
-
pos += scnprintf(buf + pos, bufsz - pos,
- "%2d|%2d|%4d|%pUl|%3d|%7d|%2d|\n",
+ "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|\n",
i++, me_cl->client_id,
me_cl->props.fixed_address,
&me_cl->props.protocol_name,
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 49a2653d91a5..239d7f5d6a92 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -562,17 +562,17 @@ int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
* mei_hbm_cl_disconnect_res - update the client state according
* disconnect response
*
+ * @dev: the device structure
* @cl: mei host client
* @cmd: disconnect client response host bus message
*/
-static void mei_hbm_cl_disconnect_res(struct mei_cl *cl,
+static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl,
struct mei_hbm_cl_cmd *cmd)
{
struct hbm_client_connect_response *rs =
(struct hbm_client_connect_response *)cmd;
- dev_dbg(cl->dev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
- rs->me_addr, rs->host_addr, rs->status);
+ cl_dbg(dev, cl, "hbm: disconnect response status=%d\n", rs->status);
if (rs->status == MEI_CL_DISCONN_SUCCESS)
cl->state = MEI_FILE_DISCONNECTED;
@@ -598,17 +598,17 @@ int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
* mei_hbm_cl_connect_res - update the client state according
* connection response
*
+ * @dev: the device structure
* @cl: mei host client
* @cmd: connect client response host bus message
*/
-static void mei_hbm_cl_connect_res(struct mei_cl *cl,
+static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl,
struct mei_hbm_cl_cmd *cmd)
{
struct hbm_client_connect_response *rs =
(struct hbm_client_connect_response *)cmd;
- dev_dbg(cl->dev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
- rs->me_addr, rs->host_addr,
+ cl_dbg(dev, cl, "hbm: connect response status=%s\n",
mei_cl_conn_status_str(rs->status));
if (rs->status == MEI_CL_CONN_SUCCESS)
@@ -637,11 +637,6 @@ static void mei_hbm_cl_res(struct mei_device *dev,
list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
cl = cb->cl;
- /* this should not happen */
- if (WARN_ON(!cl)) {
- list_del_init(&cb->list);
- continue;
- }
if (cb->fop_type != fop_type)
continue;
@@ -657,10 +652,10 @@ static void mei_hbm_cl_res(struct mei_device *dev,
switch (fop_type) {
case MEI_FOP_CONNECT:
- mei_hbm_cl_connect_res(cl, rs);
+ mei_hbm_cl_connect_res(dev, cl, rs);
break;
case MEI_FOP_DISCONNECT:
- mei_hbm_cl_disconnect_res(cl, rs);
+ mei_hbm_cl_disconnect_res(dev, cl, rs);
break;
default:
return;
@@ -811,8 +806,6 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
return -EPROTO;
}
- dev->hbm_state = MEI_HBM_STARTED;
-
if (mei_hbm_enum_clients_req(dev)) {
dev_err(dev->dev, "hbm: start: failed to send enumeration request\n");
return -EIO;
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h
index b7cd3d857fd5..2544db7d1649 100644
--- a/drivers/misc/mei/hbm.h
+++ b/drivers/misc/mei/hbm.h
@@ -26,17 +26,17 @@ struct mei_cl;
*
* @MEI_HBM_IDLE : protocol not started
* @MEI_HBM_STARTING : start request message was sent
- * @MEI_HBM_STARTED : start reply message was received
* @MEI_HBM_ENUM_CLIENTS : enumeration request was sent
* @MEI_HBM_CLIENT_PROPERTIES : acquiring clients properties
+ * @MEI_HBM_STARTED : enumeration was completed
* @MEI_HBM_STOPPED : stopping exchange
*/
enum mei_hbm_state {
MEI_HBM_IDLE = 0,
MEI_HBM_STARTING,
- MEI_HBM_STARTED,
MEI_HBM_ENUM_CLIENTS,
MEI_HBM_CLIENT_PROPERTIES,
+ MEI_HBM_STARTED,
MEI_HBM_STOPPED,
};
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
index c5feafdd58a8..9eb7ed70ace2 100644
--- a/drivers/misc/mei/hw-me-regs.h
+++ b/drivers/misc/mei/hw-me-regs.h
@@ -117,14 +117,18 @@
#define MEI_DEV_ID_WPT_LP 0x9CBA /* Wildcat Point LP */
#define MEI_DEV_ID_WPT_LP_2 0x9CBB /* Wildcat Point LP 2 */
-/* Host Firmware Status Registers in PCI Config Space */
-#define PCI_CFG_HFS_1 0x40
-#define PCI_CFG_HFS_2 0x48
-
/*
* MEI HW Section
*/
+/* Host Firmware Status Registers in PCI Config Space */
+#define PCI_CFG_HFS_1 0x40
+#define PCI_CFG_HFS_2 0x48
+#define PCI_CFG_HFS_3 0x60
+#define PCI_CFG_HFS_4 0x64
+#define PCI_CFG_HFS_5 0x68
+#define PCI_CFG_HFS_6 0x6C
+
/* MEI registers */
/* H_CB_WW - Host Circular Buffer (CB) Write Window register */
#define H_CB_WW 0
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 4f2fd6fc1e23..ff2755062b44 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -270,10 +270,10 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
static void mei_me_host_set_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
- hw->host_hw_state = mei_hcsr_read(hw);
- hw->host_hw_state |= H_IE | H_IG | H_RDY;
- mei_hcsr_set(hw, hw->host_hw_state);
+ hcsr |= H_IE | H_IG | H_RDY;
+ mei_hcsr_set(hw, hcsr);
}
/**
@@ -285,9 +285,9 @@ static void mei_me_host_set_ready(struct mei_device *dev)
static bool mei_me_host_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
- hw->host_hw_state = mei_hcsr_read(hw);
- return (hw->host_hw_state & H_RDY) == H_RDY;
+ return (hcsr & H_RDY) == H_RDY;
}
/**
@@ -299,9 +299,9 @@ static bool mei_me_host_is_ready(struct mei_device *dev)
static bool mei_me_hw_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+ u32 mecsr = mei_me_mecsr_read(hw);
- hw->me_hw_state = mei_me_mecsr_read(hw);
- return (hw->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
+ return (mecsr & ME_RDY_HRA) == ME_RDY_HRA;
}
/**
@@ -356,12 +356,13 @@ static int mei_me_hw_start(struct mei_device *dev)
static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr;
char read_ptr, write_ptr;
- hw->host_hw_state = mei_hcsr_read(hw);
+ hcsr = mei_hcsr_read(hw);
- read_ptr = (char) ((hw->host_hw_state & H_CBRP) >> 8);
- write_ptr = (char) ((hw->host_hw_state & H_CBWP) >> 16);
+ read_ptr = (char) ((hcsr & H_CBRP) >> 8);
+ write_ptr = (char) ((hcsr & H_CBWP) >> 16);
return (unsigned char) (write_ptr - read_ptr);
}
@@ -474,13 +475,14 @@ static int mei_me_write_message(struct mei_device *dev,
static int mei_me_count_full_read_slots(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+ u32 me_csr;
char read_ptr, write_ptr;
unsigned char buffer_depth, filled_slots;
- hw->me_hw_state = mei_me_mecsr_read(hw);
- buffer_depth = (unsigned char)((hw->me_hw_state & ME_CBD_HRA) >> 24);
- read_ptr = (char) ((hw->me_hw_state & ME_CBRP_HRA) >> 8);
- write_ptr = (char) ((hw->me_hw_state & ME_CBWP_HRA) >> 16);
+ me_csr = mei_me_mecsr_read(hw);
+ buffer_depth = (unsigned char)((me_csr & ME_CBD_HRA) >> 24);
+ read_ptr = (char) ((me_csr & ME_CBRP_HRA) >> 8);
+ write_ptr = (char) ((me_csr & ME_CBWP_HRA) >> 16);
filled_slots = (unsigned char) (write_ptr - read_ptr);
/* check for overflow */
@@ -833,6 +835,14 @@ static bool mei_me_fw_type_sps(struct pci_dev *pdev)
.fw_status.status[0] = PCI_CFG_HFS_1, \
.fw_status.status[1] = PCI_CFG_HFS_2
+#define MEI_CFG_PCH8_HFS \
+ .fw_status.count = 6, \
+ .fw_status.status[0] = PCI_CFG_HFS_1, \
+ .fw_status.status[1] = PCI_CFG_HFS_2, \
+ .fw_status.status[2] = PCI_CFG_HFS_3, \
+ .fw_status.status[3] = PCI_CFG_HFS_4, \
+ .fw_status.status[4] = PCI_CFG_HFS_5, \
+ .fw_status.status[5] = PCI_CFG_HFS_6
/* ICH Legacy devices */
const struct mei_cfg mei_me_legacy_cfg = {
@@ -856,9 +866,14 @@ const struct mei_cfg mei_me_pch_cpt_pbg_cfg = {
MEI_CFG_FW_NM,
};
-/* PCH Lynx Point with quirk for SPS Firmware exclusion */
-const struct mei_cfg mei_me_lpt_cfg = {
- MEI_CFG_PCH_HFS,
+/* PCH8 Lynx Point and newer devices */
+const struct mei_cfg mei_me_pch8_cfg = {
+ MEI_CFG_PCH8_HFS,
+};
+
+/* PCH8 Lynx Point with quirk for SPS Firmware exclusion */
+const struct mei_cfg mei_me_pch8_sps_cfg = {
+ MEI_CFG_PCH8_HFS,
MEI_CFG_FW_SPS,
};
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index e6a59a62573a..d6567af44377 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -51,18 +51,11 @@ struct mei_cfg {
*
* @cfg: per device generation config and ops
* @mem_addr: io memory address
- * @host_hw_state: cached host state
- * @me_hw_state: cached me (fw) state
* @pg_state: power gating state
*/
struct mei_me_hw {
const struct mei_cfg *cfg;
void __iomem *mem_addr;
- /*
- * hw states of host and fw(ME)
- */
- u32 host_hw_state;
- u32 me_hw_state;
enum mei_pg_state pg_state;
};
@@ -72,7 +65,8 @@ extern const struct mei_cfg mei_me_legacy_cfg;
extern const struct mei_cfg mei_me_ich_cfg;
extern const struct mei_cfg mei_me_pch_cfg;
extern const struct mei_cfg mei_me_pch_cpt_pbg_cfg;
-extern const struct mei_cfg mei_me_lpt_cfg;
+extern const struct mei_cfg mei_me_pch8_cfg;
+extern const struct mei_cfg mei_me_pch8_sps_cfg;
struct mei_device *mei_me_dev_init(struct pci_dev *pdev,
const struct mei_cfg *cfg);
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
index c5e1902e493f..618ea721aca8 100644
--- a/drivers/misc/mei/hw-txe.c
+++ b/drivers/misc/mei/hw-txe.c
@@ -700,11 +700,10 @@ static int mei_txe_write(struct mei_device *dev,
mei_txe_input_ready_interrupt_enable(dev);
if (!mei_txe_is_input_ready(dev)) {
- struct mei_fw_status fw_status;
+ char fw_sts_str[MEI_FW_STATUS_STR_SZ];
- mei_fw_status(dev, &fw_status);
- dev_err(dev->dev, "Input is not ready " FW_STS_FMT "\n",
- FW_STS_PRM(fw_status));
+ mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ);
+ dev_err(dev->dev, "Input is not ready %s\n", fw_sts_str);
return -EAGAIN;
}
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 7901d076c127..9306219d5675 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -54,6 +54,35 @@ const char *mei_pg_state_str(enum mei_pg_state state)
#undef MEI_PG_STATE
}
+/**
+ * mei_fw_status2str - convert fw status registers to printable string
+ *
+ * @fw_status: firmware status
+ * @buf: string buffer at minimal size MEI_FW_STATUS_STR_SZ
+ * @len: buffer len must be >= MEI_FW_STATUS_STR_SZ
+ *
+ * Return: number of bytes written or -EINVAL if buffer is to small
+ */
+ssize_t mei_fw_status2str(struct mei_fw_status *fw_status,
+ char *buf, size_t len)
+{
+ ssize_t cnt = 0;
+ int i;
+
+ buf[0] = '\0';
+
+ if (len < MEI_FW_STATUS_STR_SZ)
+ return -EINVAL;
+
+ for (i = 0; i < fw_status->count; i++)
+ cnt += scnprintf(buf + cnt, len - cnt, "%08X ",
+ fw_status->status[i]);
+
+ /* drop last space */
+ buf[cnt] = '\0';
+ return cnt;
+}
+EXPORT_SYMBOL_GPL(mei_fw_status2str);
/**
* mei_cancel_work - Cancel mei background jobs
@@ -86,12 +115,11 @@ int mei_reset(struct mei_device *dev)
state != MEI_DEV_DISABLED &&
state != MEI_DEV_POWER_DOWN &&
state != MEI_DEV_POWER_UP) {
- struct mei_fw_status fw_status;
+ char fw_sts_str[MEI_FW_STATUS_STR_SZ];
- mei_fw_status(dev, &fw_status);
- dev_warn(dev->dev,
- "unexpected reset: dev_state = %s " FW_STS_FMT "\n",
- mei_dev_state_str(state), FW_STS_PRM(fw_status));
+ mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ);
+ dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n",
+ mei_dev_state_str(state), fw_sts_str);
}
/* we're already in reset, cancel the init timer
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 20c6c511f438..711cddfa9c99 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -44,8 +44,6 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
list_for_each_entry_safe(cb, next, &compl_list->list, list) {
cl = cb->cl;
list_del(&cb->list);
- if (!cl)
- continue;
dev_dbg(dev->dev, "completing call back.\n");
if (cl == &dev->iamthif_cl)
@@ -105,7 +103,7 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
list_for_each_entry_safe(cb, next, &dev->read_list.list, list) {
cl = cb->cl;
- if (!cl || !mei_cl_is_reading(cl, mei_hdr))
+ if (!mei_cl_is_reading(cl, mei_hdr))
continue;
cl->reading_state = MEI_READING;
@@ -449,8 +447,6 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
list = &dev->write_waiting_list;
list_for_each_entry_safe(cb, next, &list->list, list) {
cl = cb->cl;
- if (cl == NULL)
- continue;
cl->status = 0;
list_del(&cb->list);
@@ -489,10 +485,6 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
dev_dbg(dev->dev, "complete control write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list.list, list) {
cl = cb->cl;
- if (!cl) {
- list_del(&cb->list);
- return -ENODEV;
- }
switch (cb->fop_type) {
case MEI_FOP_DISCONNECT:
/* send disconnect message */
@@ -530,8 +522,6 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
dev_dbg(dev->dev, "complete write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->write_list.list, list) {
cl = cb->cl;
- if (cl == NULL)
- continue;
if (cl == &dev->iamthif_cl)
ret = mei_amthif_irq_write(cl, cb, cmpl_list);
else
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index beedc91f03a6..ae56ba6ca0e3 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -631,6 +631,44 @@ out:
return mask;
}
+/**
+ * fw_status_show - mei device attribute show method
+ *
+ * @device: device pointer
+ * @attr: attribute pointer
+ * @buf: char out buffer
+ *
+ * Return: number of the bytes printed into buf or error
+ */
+static ssize_t fw_status_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct mei_device *dev = dev_get_drvdata(device);
+ struct mei_fw_status fw_status;
+ int err, i;
+ ssize_t cnt = 0;
+
+ mutex_lock(&dev->device_lock);
+ err = mei_fw_status(dev, &fw_status);
+ mutex_unlock(&dev->device_lock);
+ if (err) {
+ dev_err(device, "read fw_status error = %d\n", err);
+ return err;
+ }
+
+ for (i = 0; i < fw_status.count; i++)
+ cnt += scnprintf(buf + cnt, PAGE_SIZE - cnt, "%08X\n",
+ fw_status.status[i]);
+ return cnt;
+}
+static DEVICE_ATTR_RO(fw_status);
+
+static struct attribute *mei_attrs[] = {
+ &dev_attr_fw_status.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(mei);
+
/*
* file operations structure will be used for mei char device.
*/
@@ -710,8 +748,9 @@ int mei_register(struct mei_device *dev, struct device *parent)
goto err_dev_add;
}
- clsdev = device_create(mei_class, parent, devno,
- NULL, "mei%d", dev->minor);
+ clsdev = device_create_with_groups(mei_class, parent, devno,
+ dev, mei_groups,
+ "mei%d", dev->minor);
if (IS_ERR(clsdev)) {
dev_err(parent, "unable to create device %d:%d\n",
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 61b04d7646f1..3dad74a8d496 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -152,7 +152,10 @@ struct mei_msg_data {
};
/* Maximum number of processed FW status registers */
-#define MEI_FW_STATUS_MAX 2
+#define MEI_FW_STATUS_MAX 6
+/* Minimal buffer for FW status string (8 bytes in dw + space or '\0') */
+#define MEI_FW_STATUS_STR_SZ (MEI_FW_STATUS_MAX * (8 + 1))
+
/*
* struct mei_fw_status - storage of FW status data
@@ -349,6 +352,7 @@ void mei_cl_bus_rx_event(struct mei_cl *cl);
void mei_cl_bus_remove_devices(struct mei_device *dev);
int mei_cl_bus_init(void);
void mei_cl_bus_exit(void);
+struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *dev, uuid_le uuid);
/**
@@ -804,11 +808,6 @@ static inline int mei_fw_status(struct mei_device *dev,
return dev->ops->fw_status(dev, fw_status);
}
-#define FW_STS_FMT "%08X %08X"
-#define FW_STS_PRM(fw_status) \
- (fw_status).count > 0 ? (fw_status).status[0] : 0xDEADBEEF, \
- (fw_status).count > 1 ? (fw_status).status[1] : 0xDEADBEEF
-
bool mei_hbuf_acquire(struct mei_device *dev);
bool mei_write_is_idle(struct mei_device *dev);
@@ -832,4 +831,32 @@ void mei_deregister(struct mei_device *dev);
(hdr)->host_addr, (hdr)->me_addr, \
(hdr)->length, (hdr)->internal, (hdr)->msg_complete
+ssize_t mei_fw_status2str(struct mei_fw_status *fw_sts, char *buf, size_t len);
+/**
+ * mei_fw_status_str - fetch and convert fw status registers to printable string
+ *
+ * @dev: the device structure
+ * @buf: string buffer at minimal size MEI_FW_STATUS_STR_SZ
+ * @len: buffer len must be >= MEI_FW_STATUS_STR_SZ
+ *
+ * Return: number of bytes written or < 0 on failure
+ */
+static inline ssize_t mei_fw_status_str(struct mei_device *dev,
+ char *buf, size_t len)
+{
+ struct mei_fw_status fw_status;
+ int ret;
+
+ buf[0] = '\0';
+
+ ret = mei_fw_status(dev, &fw_status);
+ if (ret)
+ return ret;
+
+ ret = mei_fw_status2str(&fw_status, buf, MEI_FW_STATUS_STR_SZ);
+
+ return ret;
+}
+
+
#endif
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 622654323177..60ca9240368e 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -117,8 +117,6 @@ struct mei_nfc_dev {
u16 recv_req_id;
};
-static struct mei_nfc_dev nfc_dev;
-
/* UUIDs for NFC F/W clients */
const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50,
0x94, 0xd4, 0x50, 0x26,
@@ -138,6 +136,9 @@ static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d,
static void mei_nfc_free(struct mei_nfc_dev *ndev)
{
+ if (!ndev)
+ return;
+
if (ndev->cl) {
list_del(&ndev->cl->device_link);
mei_cl_unlink(ndev->cl);
@@ -150,7 +151,7 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev)
kfree(ndev->cl_info);
}
- memset(ndev, 0, sizeof(struct mei_nfc_dev));
+ kfree(ndev);
}
static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
@@ -319,9 +320,10 @@ err:
static int mei_nfc_enable(struct mei_cl_device *cldev)
{
struct mei_device *dev;
- struct mei_nfc_dev *ndev = &nfc_dev;
+ struct mei_nfc_dev *ndev;
int ret;
+ ndev = (struct mei_nfc_dev *)cldev->priv_data;
dev = ndev->cl->dev;
ret = mei_nfc_connect(ndev);
@@ -479,15 +481,25 @@ err:
int mei_nfc_host_init(struct mei_device *dev)
{
- struct mei_nfc_dev *ndev = &nfc_dev;
+ struct mei_nfc_dev *ndev;
struct mei_cl *cl_info, *cl = NULL;
struct mei_me_client *me_cl;
int ret;
- /* already initialized */
- if (ndev->cl_info)
+
+ /* in case of internal reset bail out
+ * as the device is already setup
+ */
+ cl = mei_cl_bus_find_cl_by_uuid(dev, mei_nfc_guid);
+ if (cl)
return 0;
+ ndev = kzalloc(sizeof(struct mei_nfc_dev), GFP_KERNEL);
+ if (!ndev) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
ndev->cl_info = mei_cl_allocate(dev);
ndev->cl = mei_cl_allocate(dev);
@@ -550,9 +562,31 @@ err:
void mei_nfc_host_exit(struct mei_device *dev)
{
- struct mei_nfc_dev *ndev = &nfc_dev;
+ struct mei_nfc_dev *ndev;
+ struct mei_cl *cl;
+ struct mei_cl_device *cldev;
+
+ cl = mei_cl_bus_find_cl_by_uuid(dev, mei_nfc_guid);
+ if (!cl)
+ return;
+
+ cldev = cl->device;
+ if (!cldev)
+ return;
- cancel_work_sync(&ndev->init_work);
+ ndev = (struct mei_nfc_dev *)cldev->priv_data;
+ if (ndev)
+ cancel_work_sync(&ndev->init_work);
+
+ cldev->priv_data = NULL;
+
+ mutex_lock(&dev->device_lock);
+ /* Need to remove the device here
+ * since mei_nfc_free will unlink the clients
+ */
+ mei_cl_remove_device(cldev);
+ mei_nfc_free(ndev);
+ mutex_unlock(&dev->device_lock);
}
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index cf20d397068a..bd3039ab8f98 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -76,12 +76,12 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
{MEI_PCI_DEVICE(MEI_DEV_ID_PPT_1, mei_me_pch_cfg)},
{MEI_PCI_DEVICE(MEI_DEV_ID_PPT_2, mei_me_pch_cfg)},
{MEI_PCI_DEVICE(MEI_DEV_ID_PPT_3, mei_me_pch_cfg)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_H, mei_me_lpt_cfg)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_W, mei_me_lpt_cfg)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_LP, mei_me_pch_cfg)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_HR, mei_me_lpt_cfg)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP, mei_me_pch_cfg)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP_2, mei_me_pch_cfg)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_H, mei_me_pch8_sps_cfg)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_W, mei_me_pch8_sps_cfg)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_LP, mei_me_pch8_cfg)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_HR, mei_me_pch8_sps_cfg)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP, mei_me_pch8_cfg)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP_2, mei_me_pch8_cfg)},
/* required last entry */
{0, }
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index 1f572deacf54..c86e2ddbe30a 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -37,6 +37,7 @@
static const struct pci_device_id mei_txe_pci_tbl[] = {
{PCI_VDEVICE(INTEL, 0x0F18)}, /* Baytrail */
+ {PCI_VDEVICE(INTEL, 0x2298)}, /* Cherrytrail */
{0, }
};
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index b836dfffceb5..b1d892cea94d 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -270,15 +270,18 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
{
struct mei_device *dev;
+ struct mei_cl *cl;
int ret;
dev = watchdog_get_drvdata(wd_dev);
if (!dev)
return -ENODEV;
+ cl = &dev->wd_cl;
+
mutex_lock(&dev->device_lock);
- if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
+ if (cl->state != MEI_FILE_CONNECTED) {
dev_err(dev->dev, "wd: not connected.\n");
ret = -ENODEV;
goto end;
@@ -286,12 +289,12 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
dev->wd_state = MEI_WD_RUNNING;
- ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
+ ret = mei_cl_flow_ctrl_creds(cl);
if (ret < 0)
goto end;
+
/* Check if we can send the ping to HW*/
if (ret && mei_hbuf_acquire(dev)) {
-
dev_dbg(dev->dev, "wd: sending ping\n");
ret = mei_wd_send(dev);