diff options
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r-- | drivers/misc/mei/amthif.c | 34 | ||||
-rw-r--r-- | drivers/misc/mei/bus.c | 4 | ||||
-rw-r--r-- | drivers/misc/mei/client.c | 2 | ||||
-rw-r--r-- | drivers/misc/mei/debugfs.c | 8 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.c | 23 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.h | 4 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me-regs.h | 12 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.c | 49 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.h | 10 | ||||
-rw-r--r-- | drivers/misc/mei/hw-txe.c | 7 | ||||
-rw-r--r-- | drivers/misc/mei/init.c | 38 | ||||
-rw-r--r-- | drivers/misc/mei/interrupt.c | 12 | ||||
-rw-r--r-- | drivers/misc/mei/main.c | 43 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 39 | ||||
-rw-r--r-- | drivers/misc/mei/nfc.c | 52 | ||||
-rw-r--r-- | drivers/misc/mei/pci-me.c | 12 | ||||
-rw-r--r-- | drivers/misc/mei/pci-txe.c | 1 | ||||
-rw-r--r-- | drivers/misc/mei/wd.c | 9 |
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); |