summaryrefslogtreecommitdiff
path: root/drivers/misc/mei/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mei/init.c')
-rw-r--r--drivers/misc/mei/init.c100
1 files changed, 65 insertions, 35 deletions
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 5c8cb679b997..b789c4d9c709 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2012-2019, Intel Corporation. All rights reserved.
+ * Copyright (c) 2012-2022, Intel Corporation. All rights reserved.
* Intel Management Engine Interface (Intel MEI) Linux driver
*/
@@ -24,6 +24,7 @@ const char *mei_dev_state_str(int state)
MEI_DEV_STATE(ENABLED);
MEI_DEV_STATE(RESETTING);
MEI_DEV_STATE(DISABLED);
+ MEI_DEV_STATE(POWERING_DOWN);
MEI_DEV_STATE(POWER_DOWN);
MEI_DEV_STATE(POWER_UP);
default:
@@ -108,8 +109,13 @@ int mei_reset(struct mei_device *dev)
char fw_sts_str[MEI_FW_STATUS_STR_SZ];
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);
+ if (kind_is_gsc(dev) || kind_is_gscfi(dev)) {
+ dev_dbg(&dev->dev, "unexpected reset: dev_state = %s fw status = %s\n",
+ mei_dev_state_str(state), fw_sts_str);
+ } else {
+ dev_warn(&dev->dev, "unexpected reset: dev_state = %s fw status = %s\n",
+ mei_dev_state_str(state), fw_sts_str);
+ }
}
mei_clear_interrupts(dev);
@@ -127,7 +133,7 @@ int mei_reset(struct mei_device *dev)
dev->reset_count++;
if (dev->reset_count > MEI_MAX_CONSEC_RESET) {
- dev_err(dev->dev, "reset: reached maximal consecutive resets: disabling the device\n");
+ dev_err(&dev->dev, "reset: reached maximal consecutive resets: disabling the device\n");
mei_set_devstate(dev, MEI_DEV_DISABLED);
return -ENODEV;
}
@@ -141,31 +147,42 @@ int mei_reset(struct mei_device *dev)
mei_hbm_reset(dev);
+ /* clean stale FW version */
+ dev->fw_ver_received = 0;
+
memset(dev->rd_msg_hdr, 0, sizeof(dev->rd_msg_hdr));
if (ret) {
- dev_err(dev->dev, "hw_reset failed ret = %d\n", ret);
+ dev_err(&dev->dev, "hw_reset failed ret = %d\n", ret);
return ret;
}
if (state == MEI_DEV_POWER_DOWN) {
- dev_dbg(dev->dev, "powering down: end of reset\n");
+ dev_dbg(&dev->dev, "powering down: end of reset\n");
mei_set_devstate(dev, MEI_DEV_DISABLED);
return 0;
}
ret = mei_hw_start(dev);
if (ret) {
- dev_err(dev->dev, "hw_start failed ret = %d\n", ret);
+ char fw_sts_str[MEI_FW_STATUS_STR_SZ];
+
+ mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ);
+ dev_err(&dev->dev, "hw_start failed ret = %d fw status = %s\n", ret, fw_sts_str);
return ret;
}
- dev_dbg(dev->dev, "link is established start sending messages.\n");
+ if (dev->dev_state != MEI_DEV_RESETTING) {
+ dev_dbg(&dev->dev, "wrong state = %d on link start\n", dev->dev_state);
+ return 0;
+ }
+
+ dev_dbg(&dev->dev, "link is established start sending messages.\n");
mei_set_devstate(dev, MEI_DEV_INIT_CLIENTS);
ret = mei_hbm_start_req(dev);
if (ret) {
- dev_err(dev->dev, "hbm_start failed ret = %d\n", ret);
+ dev_err(&dev->dev, "hbm_start failed ret = %d\n", ret);
mei_set_devstate(dev, MEI_DEV_RESETTING);
return ret;
}
@@ -194,7 +211,7 @@ int mei_start(struct mei_device *dev)
if (ret)
goto err;
- dev_dbg(dev->dev, "reset in start the mei device.\n");
+ dev_dbg(&dev->dev, "reset in start the mei device.\n");
dev->reset_count = 0;
do {
@@ -202,37 +219,27 @@ int mei_start(struct mei_device *dev)
ret = mei_reset(dev);
if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
- dev_err(dev->dev, "reset failed ret = %d", ret);
+ dev_err(&dev->dev, "reset failed ret = %d", ret);
goto err;
}
} while (ret);
if (mei_hbm_start_wait(dev)) {
- dev_err(dev->dev, "HBM haven't started");
- goto err;
- }
-
- if (!mei_host_is_ready(dev)) {
- dev_err(dev->dev, "host is not ready.\n");
- goto err;
- }
-
- if (!mei_hw_is_ready(dev)) {
- dev_err(dev->dev, "ME is not ready.\n");
+ dev_err(&dev->dev, "HBM haven't started");
goto err;
}
if (!mei_hbm_version_is_supported(dev)) {
- dev_dbg(dev->dev, "MEI start failed.\n");
+ dev_dbg(&dev->dev, "MEI start failed.\n");
goto err;
}
- dev_dbg(dev->dev, "link layer has been established.\n");
+ dev_dbg(&dev->dev, "link layer has been established.\n");
mutex_unlock(&dev->device_lock);
return 0;
err:
- dev_err(dev->dev, "link layer initialization failed.\n");
+ dev_err(&dev->dev, "link layer initialization failed.\n");
mei_set_devstate(dev, MEI_DEV_DISABLED);
mutex_unlock(&dev->device_lock);
return -ENODEV;
@@ -260,7 +267,7 @@ int mei_restart(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
if (err == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
- dev_err(dev->dev, "device disabled = %d\n", err);
+ dev_err(&dev->dev, "device disabled = %d\n", err);
return -ENODEV;
}
@@ -289,7 +296,7 @@ static void mei_reset_work(struct work_struct *work)
mutex_unlock(&dev->device_lock);
if (dev->dev_state == MEI_DEV_DISABLED) {
- dev_err(dev->dev, "device disabled = %d\n", ret);
+ dev_err(&dev->dev, "device disabled = %d\n", ret);
return;
}
@@ -300,7 +307,7 @@ static void mei_reset_work(struct work_struct *work)
void mei_stop(struct mei_device *dev)
{
- dev_dbg(dev->dev, "stopping the device.\n");
+ dev_dbg(&dev->dev, "stopping the device.\n");
mutex_lock(&dev->device_lock);
mei_set_devstate(dev, MEI_DEV_POWERING_DOWN);
@@ -314,6 +321,8 @@ void mei_stop(struct mei_device *dev)
mei_clear_interrupts(dev);
mei_synchronize_irq(dev);
+ /* to catch HW-initiated reset */
+ mei_cancel_work(dev);
mutex_lock(&dev->device_lock);
@@ -339,7 +348,7 @@ bool mei_write_is_idle(struct mei_device *dev)
list_empty(&dev->write_list) &&
list_empty(&dev->write_waiting_list));
- dev_dbg(dev->dev, "write pg: is idle[%d] state=%s ctrl=%01d write=%01d wwait=%01d\n",
+ dev_dbg(&dev->dev, "write pg: is idle[%d] state=%s ctrl=%01d write=%01d wwait=%01d\n",
idle,
mei_dev_state_str(dev->dev_state),
list_empty(&dev->ctrl_wr_list),
@@ -351,14 +360,16 @@ bool mei_write_is_idle(struct mei_device *dev)
EXPORT_SYMBOL_GPL(mei_write_is_idle);
/**
- * mei_device_init -- initialize mei_device structure
+ * mei_device_init - initialize mei_device structure
*
* @dev: the mei device
- * @device: the device structure
+ * @parent: the parent device
+ * @slow_fw: configure longer timeouts as FW is slow
* @hw_ops: hw operations
*/
void mei_device_init(struct mei_device *dev,
- struct device *device,
+ struct device *parent,
+ bool slow_fw,
const struct mei_hw_ops *hw_ops)
{
/* setup our list array */
@@ -371,7 +382,8 @@ void mei_device_init(struct mei_device *dev,
init_waitqueue_head(&dev->wait_hw_ready);
init_waitqueue_head(&dev->wait_pg);
init_waitqueue_head(&dev->wait_hbm_start);
- dev->dev_state = MEI_DEV_INITIALIZING;
+ dev->dev_state = MEI_DEV_UNINITIALIZED;
+ init_waitqueue_head(&dev->wait_dev_state);
dev->reset_count = 0;
INIT_LIST_HEAD(&dev->write_list);
@@ -387,6 +399,9 @@ void mei_device_init(struct mei_device *dev,
bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
dev->open_handle_count = 0;
+ dev->pxp_mode = MEI_DEV_PXP_DEFAULT;
+ dev->gsc_reset_to_pxp = MEI_DEV_RESET_TO_PXP_DEFAULT;
+
/*
* Reserving the first client ID
* 0: Reserved for MEI Bus Message communications
@@ -395,7 +410,22 @@ void mei_device_init(struct mei_device *dev,
dev->pg_event = MEI_PG_EVENT_IDLE;
dev->ops = hw_ops;
- dev->dev = device;
+ dev->parent = parent;
+
+ dev->timeouts.hw_ready = mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT);
+ dev->timeouts.connect = MEI_CONNECT_TIMEOUT;
+ dev->timeouts.client_init = MEI_CLIENTS_INIT_TIMEOUT;
+ dev->timeouts.pgi = mei_secs_to_jiffies(MEI_PGI_TIMEOUT);
+ dev->timeouts.d0i3 = mei_secs_to_jiffies(MEI_D0I3_TIMEOUT);
+ if (slow_fw) {
+ dev->timeouts.cl_connect = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT_SLOW);
+ dev->timeouts.hbm = mei_secs_to_jiffies(MEI_HBM_TIMEOUT_SLOW);
+ dev->timeouts.mkhi_recv = msecs_to_jiffies(MKHI_RCV_TIMEOUT_SLOW);
+ } else {
+ dev->timeouts.cl_connect = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT);
+ dev->timeouts.hbm = mei_secs_to_jiffies(MEI_HBM_TIMEOUT);
+ dev->timeouts.mkhi_recv = msecs_to_jiffies(MKHI_RCV_TIMEOUT);
+ }
+ dev->timeouts.link_reset_wait = msecs_to_jiffies(MEI_LINK_RESET_WAIT_TIMEOUT_MSEC);
}
EXPORT_SYMBOL_GPL(mei_device_init);
-