aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/mei
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/mei')
-rw-r--r--drivers/staging/mei/Kconfig2
-rw-r--r--drivers/staging/mei/TODO10
-rw-r--r--drivers/staging/mei/init.c181
-rw-r--r--drivers/staging/mei/interface.c13
-rw-r--r--drivers/staging/mei/interface.h8
-rw-r--r--drivers/staging/mei/interrupt.c128
-rw-r--r--drivers/staging/mei/iorw.c32
-rw-r--r--drivers/staging/mei/main.c117
-rw-r--r--drivers/staging/mei/mei_dev.h155
-rw-r--r--drivers/staging/mei/wd.c254
10 files changed, 573 insertions, 327 deletions
diff --git a/drivers/staging/mei/Kconfig b/drivers/staging/mei/Kconfig
index 3f3f170..47d78a7 100644
--- a/drivers/staging/mei/Kconfig
+++ b/drivers/staging/mei/Kconfig
@@ -1,6 +1,6 @@
config INTEL_MEI
tristate "Intel Management Engine Interface (Intel MEI)"
- depends on X86 && PCI && EXPERIMENTAL
+ depends on X86 && PCI && EXPERIMENTAL && WATCHDOG_CORE
help
The Intel Management Engine (Intel ME) provides Manageability,
Security and Media services for system containing Intel chipsets.
diff --git a/drivers/staging/mei/TODO b/drivers/staging/mei/TODO
index 3b6a667..7d9a13b 100644
--- a/drivers/staging/mei/TODO
+++ b/drivers/staging/mei/TODO
@@ -1,14 +1,4 @@
TODO:
- - Create in-kernel Client API. Examples of in-kernel clients are watchdog and AMTHI.
- - ME Watchdog Driver to expose standard Linux watchdog interface
- - Rewrite AMTHI to use in-kernel client interface
- - Cleanup init and probe functions
- - Review BUG/BUG_ON usage
- - Cleanup and reorganize header files
- - Rewrite client data structure
- - Make state machine more readable
- - Add mei.txt with driver explanation and it's driver
- - Fix Kconfig
- Cleanup and split the timer function
Upon Unstaging:
- move mei.h to include/linux/mei.h
diff --git a/drivers/staging/mei/init.c b/drivers/staging/mei/init.c
index 685fcf6..a78e63b 100644
--- a/drivers/staging/mei/init.c
+++ b/drivers/staging/mei/init.c
@@ -29,54 +29,29 @@ const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
0x81, 0x4c);
/**
- * mei_initialize_list - Sets up a queue list.
+ * mei_io_list_init - Sets up a queue list.
*
- * @list: An instance of our list structure
+ * @list: An instance io list structure
* @dev: the device structure
*/
-void mei_initialize_list(struct mei_io_list *list, struct mei_device *dev)
+void mei_io_list_init(struct mei_io_list *list)
{
/* initialize our queue list */
INIT_LIST_HEAD(&list->mei_cb.cb_list);
list->status = 0;
- list->device_extension = dev;
}
/**
- * mei_flush_queues - flushes queue lists belonging to cl.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- */
-void mei_flush_queues(struct mei_device *dev, struct mei_cl *cl)
-{
- int i;
-
- if (!dev || !cl)
- return;
-
- for (i = 0; i < MEI_IO_LISTS_NUMBER; i++) {
- dev_dbg(&dev->pdev->dev, "remove list entry belonging to cl\n");
- mei_flush_list(dev->io_list_array[i], cl);
- }
-}
-
-
-/**
- * mei_flush_list - removes list entry belonging to cl.
+ * mei_io_list_flush - removes list entry belonging to cl.
*
* @list: An instance of our list structure
* @cl: private data of the file object
*/
-void mei_flush_list(struct mei_io_list *list, struct mei_cl *cl)
+void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl)
{
- struct mei_cl *cl_tmp;
struct mei_cl_cb *cb_pos = NULL;
struct mei_cl_cb *cb_next = NULL;
- if (!list || !cl)
- return;
-
if (list->status != 0)
return;
@@ -86,14 +61,36 @@ void mei_flush_list(struct mei_io_list *list, struct mei_cl *cl)
list_for_each_entry_safe(cb_pos, cb_next,
&list->mei_cb.cb_list, cb_list) {
if (cb_pos) {
- cl_tmp = (struct mei_cl *)
- cb_pos->file_private;
- if (cl_tmp &&
- mei_fe_same_id(cl, cl_tmp))
+ struct mei_cl *cl_tmp;
+ cl_tmp = (struct mei_cl *)cb_pos->file_private;
+ if (mei_cl_cmp_id(cl, cl_tmp))
list_del(&cb_pos->cb_list);
}
}
}
+/**
+ * mei_cl_flush_queues - flushes queue lists belonging to cl.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ */
+int mei_cl_flush_queues(struct mei_cl *cl)
+{
+ if (!cl || !cl->dev)
+ return -EINVAL;
+
+ dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
+ mei_io_list_flush(&cl->dev->read_list, cl);
+ mei_io_list_flush(&cl->dev->write_list, cl);
+ mei_io_list_flush(&cl->dev->write_waiting_list, cl);
+ mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
+ mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
+ mei_io_list_flush(&cl->dev->amthi_cmd_list, cl);
+ mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl);
+ return 0;
+}
+
+
/**
* mei_reset_iamthif_params - initializes mei device iamthif
@@ -106,8 +103,8 @@ static void mei_reset_iamthif_params(struct mei_device *dev)
dev->iamthif_current_cb = NULL;
dev->iamthif_msg_buf_size = 0;
dev->iamthif_msg_buf_index = 0;
- dev->iamthif_canceled = 0;
- dev->iamthif_ioctl = 0;
+ dev->iamthif_canceled = false;
+ dev->iamthif_ioctl = false;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
dev->iamthif_timer = 0;
}
@@ -119,9 +116,8 @@ static void mei_reset_iamthif_params(struct mei_device *dev)
*
* returns The mei_device_device pointer on success, NULL on failure.
*/
-struct mei_device *init_mei_device(struct pci_dev *pdev)
+struct mei_device *mei_device_init(struct pci_dev *pdev)
{
- int i;
struct mei_device *dev;
dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL);
@@ -129,13 +125,6 @@ struct mei_device *init_mei_device(struct pci_dev *pdev)
return NULL;
/* setup our list array */
- dev->io_list_array[0] = &dev->read_list;
- dev->io_list_array[1] = &dev->write_list;
- dev->io_list_array[2] = &dev->write_waiting_list;
- dev->io_list_array[3] = &dev->ctrl_wr_list;
- dev->io_list_array[4] = &dev->ctrl_rd_list;
- dev->io_list_array[5] = &dev->amthi_cmd_list;
- dev->io_list_array[6] = &dev->amthi_read_complete_list;
INIT_LIST_HEAD(&dev->file_list);
INIT_LIST_HEAD(&dev->wd_cl.link);
INIT_LIST_HEAD(&dev->iamthif_cl.link);
@@ -143,9 +132,18 @@ struct mei_device *init_mei_device(struct pci_dev *pdev)
init_waitqueue_head(&dev->wait_recvd_msg);
init_waitqueue_head(&dev->wait_stop_wd);
dev->mei_state = MEI_INITIALIZING;
+ dev->reset_count = 0;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
- for (i = 0; i < MEI_IO_LISTS_NUMBER; i++)
- mei_initialize_list(dev->io_list_array[i], dev);
+ dev->wd_interface_reg = false;
+
+
+ mei_io_list_init(&dev->read_list);
+ mei_io_list_init(&dev->write_list);
+ mei_io_list_init(&dev->write_waiting_list);
+ mei_io_list_init(&dev->ctrl_wr_list);
+ mei_io_list_init(&dev->ctrl_rd_list);
+ mei_io_list_init(&dev->amthi_cmd_list);
+ mei_io_list_init(&dev->amthi_read_complete_list);
dev->pdev = pdev;
return dev;
}
@@ -173,7 +171,7 @@ int mei_hw_init(struct mei_device *dev)
if ((dev->host_hw_state & H_IS) == H_IS)
mei_reg_write(dev, H_CSR, dev->host_hw_state);
- dev->recvd_msg = 0;
+ dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
mei_reset(dev, 1);
@@ -223,7 +221,7 @@ int mei_hw_init(struct mei_device *dev)
goto out;
}
- dev->recvd_msg = 0;
+ dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
dev->host_hw_state, dev->me_hw_state);
dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n");
@@ -267,7 +265,7 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
bool unexpected;
if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
- dev->need_reset = 1;
+ dev->need_reset = true;
return;
}
@@ -291,7 +289,15 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n",
dev->host_hw_state);
- dev->need_reset = 0;
+ dev->need_reset = false;
+
+ dev->reset_count++;
+ if (dev->reset_count > MEI_MAX_CONSEC_RESET) {
+ dev_err(&dev->pdev->dev, "reset: reached maximal consecutive resets: disabling the device\n");
+ dev->mei_state = MEI_DISABLED;
+ return;
+ }
+
if (dev->mei_state != MEI_INITIALIZING) {
if (dev->mei_state != MEI_DISABLED &&
@@ -318,10 +324,10 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev->extra_write_index = 0;
}
- dev->num_mei_me_clients = 0;
+ dev->me_clients_num = 0;
dev->rd_msg_hdr = 0;
- dev->stop = 0;
- dev->wd_pending = 0;
+ dev->stop = false;
+ dev->wd_pending = false;
/* update the state of the registers after reset */
dev->host_hw_state = mei_hcsr_read(dev);
@@ -363,7 +369,7 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
*
* returns none.
*/
-void host_start_message(struct mei_device *dev)
+void mei_host_start_message(struct mei_device *dev)
{
struct mei_msg_hdr *mei_hdr;
struct hbm_host_version_request *host_start_req;
@@ -382,7 +388,7 @@ void host_start_message(struct mei_device *dev)
host_start_req->cmd.cmd = HOST_START_REQ_CMD;
host_start_req->host_version.major_version = HBM_MAJOR_VERSION;
host_start_req->host_version.minor_version = HBM_MINOR_VERSION;
- dev->recvd_msg = 0;
+ dev->recvd_msg = false;
if (!mei_write_message(dev, mei_hdr,
(unsigned char *) (host_start_req),
mei_hdr->length)) {
@@ -402,7 +408,7 @@ void host_start_message(struct mei_device *dev)
*
* returns none.
*/
-void host_enum_clients_message(struct mei_device *dev)
+void mei_host_enum_clients_message(struct mei_device *dev)
{
struct mei_msg_hdr *mei_hdr;
struct hbm_host_enum_request *host_enum_req;
@@ -437,16 +443,16 @@ void host_enum_clients_message(struct mei_device *dev)
*
* returns none.
*/
-void allocate_me_clients_storage(struct mei_device *dev)
+void mei_allocate_me_clients_storage(struct mei_device *dev)
{
struct mei_me_client *clients;
int b;
/* count how many ME clients we have */
for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
- dev->num_mei_me_clients++;
+ dev->me_clients_num++;
- if (dev->num_mei_me_clients <= 0)
+ if (dev->me_clients_num <= 0)
return ;
@@ -455,9 +461,9 @@ void allocate_me_clients_storage(struct mei_device *dev)
dev->me_clients = NULL;
}
dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
- dev->num_mei_me_clients * sizeof(struct mei_me_client));
+ dev->me_clients_num * sizeof(struct mei_me_client));
/* allocate storage for ME clients representation */
- clients = kcalloc(dev->num_mei_me_clients,
+ clients = kcalloc(dev->me_clients_num,
sizeof(struct mei_me_client), GFP_KERNEL);
if (!clients) {
dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
@@ -473,9 +479,12 @@ void allocate_me_clients_storage(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns none.
+ * returns:
+ * < 0 - Error.
+ * = 0 - no more clients.
+ * = 1 - still have clients to send properties request.
*/
-void host_client_properties(struct mei_device *dev)
+int mei_host_client_properties(struct mei_device *dev)
{
struct mei_msg_hdr *mei_header;
struct hbm_props_request *host_cli_req;
@@ -507,27 +516,15 @@ void host_client_properties(struct mei_device *dev)
dev->mei_state = MEI_RESETING;
dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
mei_reset(dev, 1);
- return;
+ return -EIO;
}
dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
dev->me_client_index = b;
- return;
+ return 1;
}
-
- /*
- * Clear Map for indicating now ME clients
- * with associated host client
- */
- bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
- dev->write_hang = -1;
- dev->open_handle_count = 0;
- bitmap_set(dev->host_clients_map, 0, 3);
- dev->mei_state = MEI_ENABLED;
-
- mei_wd_host_init(dev);
- return;
+ return 0;
}
/**
@@ -536,7 +533,7 @@ void host_client_properties(struct mei_device *dev)
* @priv: private file structure to be initialized
* @file: the file structure
*/
-void mei_init_file_private(struct mei_cl *priv, struct mei_device *dev)
+void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
{
memset(priv, 0, sizeof(struct mei_cl));
init_waitqueue_head(&priv->wait);
@@ -552,7 +549,7 @@ int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
{
int i, res = -1;
- for (i = 0; i < dev->num_mei_me_clients; ++i)
+ for (i = 0; i < dev->me_clients_num; ++i)
if (uuid_le_cmp(cuuid,
dev->me_clients[i].props.protocol_name) == 0) {
res = i;
@@ -601,12 +598,12 @@ u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
* @dev: the device structure
*
*/
-void host_init_iamthif(struct mei_device *dev)
+void mei_host_init_iamthif(struct mei_device *dev)
{
u8 i;
unsigned char *msg_buf;
- mei_init_file_private(&dev->iamthif_cl, dev);
+ mei_cl_init(&dev->iamthif_cl, dev);
dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
/* find ME amthi client */
@@ -656,17 +653,17 @@ void host_init_iamthif(struct mei_device *dev)
*
* returns The allocated file or NULL on failure
*/
-struct mei_cl *mei_alloc_file_private(struct mei_device *dev)
+struct mei_cl *mei_cl_allocate(struct mei_device *dev)
{
- struct mei_cl *priv;
+ struct mei_cl *cl;
- priv = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
- if (!priv)
+ cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
+ if (!cl)
return NULL;
- mei_init_file_private(priv, dev);
+ mei_cl_init(cl, dev);
- return priv;
+ return cl;
}
@@ -701,7 +698,7 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
cb->file_private = cl;
cb->major_file_operations = MEI_CLOSE;
if (dev->mei_host_buffer_is_empty) {
- dev->mei_host_buffer_is_empty = 0;
+ dev->mei_host_buffer_is_empty = false;
if (mei_disconnect(dev, cl)) {
mdelay(10); /* Wait for hardware disconnection ready */
list_add_tail(&cb->cb_list,
@@ -739,8 +736,8 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
}
- mei_flush_list(&dev->ctrl_rd_list, cl);
- mei_flush_list(&dev->ctrl_wr_list, cl);
+ mei_io_list_flush(&dev->ctrl_rd_list, cl);
+ mei_io_list_flush(&dev->ctrl_wr_list, cl);
free:
mei_free_cb_private(cb);
return rets;
diff --git a/drivers/staging/mei/interface.c b/drivers/staging/mei/interface.c
index 4959aae..a65dacf 100644
--- a/drivers/staging/mei/interface.c
+++ b/drivers/staging/mei/interface.c
@@ -179,7 +179,6 @@ int mei_write_message(struct mei_device *dev,
if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
return 0;
- dev->write_hang = 0;
return 1;
}
@@ -256,13 +255,13 @@ int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
{
int i;
- if (!dev->num_mei_me_clients)
+ if (!dev->me_clients_num)
return 0;
if (cl->mei_flow_ctrl_creds > 0)
return 1;
- for (i = 0; i < dev->num_mei_me_clients; i++) {
+ for (i = 0; i < dev->me_clients_num; i++) {
struct mei_me_client *me_cl = &dev->me_clients[i];
if (me_cl->client_id == cl->me_client_id) {
if (me_cl->mei_flow_ctrl_creds) {
@@ -291,10 +290,10 @@ int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
{
int i;
- if (!dev->num_mei_me_clients)
+ if (!dev->me_clients_num)
return -ENOENT;
- for (i = 0; i < dev->num_mei_me_clients; i++) {
+ for (i = 0; i < dev->me_clients_num; i++) {
struct mei_me_client *me_cl = &dev->me_clients[i];
if (me_cl->client_id == cl->me_client_id) {
if (me_cl->props.single_recv_buf != 0) {
@@ -333,7 +332,7 @@ int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
mei_hdr->reserved = 0;
mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
- memset(mei_flow_control, 0, sizeof(mei_flow_control));
+ memset(mei_flow_control, 0, sizeof(*mei_flow_control));
mei_flow_control->host_addr = cl->host_client_id;
mei_flow_control->me_addr = cl->me_client_id;
mei_flow_control->cmd.cmd = MEI_FLOW_CONTROL_CMD;
@@ -397,7 +396,7 @@ int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
mei_cli_disconnect =
(struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1];
- memset(mei_cli_disconnect, 0, sizeof(mei_cli_disconnect));
+ memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect));
mei_cli_disconnect->host_addr = cl->host_client_id;
mei_cli_disconnect->me_addr = cl->me_client_id;
mei_cli_disconnect->cmd.cmd = CLIENT_DISCONNECT_REQ_CMD;
diff --git a/drivers/staging/mei/interface.h b/drivers/staging/mei/interface.h
index d0bf5cf..7bd38ae 100644
--- a/drivers/staging/mei/interface.h
+++ b/drivers/staging/mei/interface.h
@@ -23,7 +23,9 @@
#include "mei_dev.h"
-#define AMT_WD_VALUE 120 /* seconds */
+#define AMT_WD_DEFAULT_TIMEOUT 120 /* seconds */
+#define AMT_WD_MIN_TIMEOUT 120 /* seconds */
+#define AMT_WD_MAX_TIMEOUT 65535 /* seconds */
#define MEI_WATCHDOG_DATA_SIZE 16
#define MEI_START_WD_DATA_SIZE 20
@@ -48,8 +50,8 @@ int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
int mei_wd_send(struct mei_device *dev);
int mei_wd_stop(struct mei_device *dev, bool preserve);
-void mei_wd_host_init(struct mei_device *dev);
-void mei_wd_start_setup(struct mei_device *dev);
+bool mei_wd_host_init(struct mei_device *dev);
+void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout);
int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl);
diff --git a/drivers/staging/mei/interrupt.c b/drivers/staging/mei/interrupt.c
index d1b9214..42b7c9a 100644
--- a/drivers/staging/mei/interrupt.c
+++ b/drivers/staging/mei/interrupt.c
@@ -94,7 +94,7 @@ static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos)
dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
dev->iamthif_timer);
} else {
- run_next_iamthif_cmd(dev);
+ mei_run_next_iamthif_cmd(dev);
}
dev_dbg(&dev->pdev->dev, "completing amthi call back.\n");
@@ -195,7 +195,7 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
{
struct mei_cl *cl;
struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
- unsigned char *buffer;
+ unsigned char *buffer = NULL;
dev_dbg(&dev->pdev->dev, "start client msg\n");
if (!(dev->read_list.status == 0 &&
@@ -280,7 +280,7 @@ static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots)
} else {
dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
dev->iamthif_state = MEI_IAMTHIF_READING;
- dev->iamthif_flow_control_pending = 0;
+ dev->iamthif_flow_control_pending = false;
dev->iamthif_msg_buf_index = 0;
dev->iamthif_msg_buf_size = 0;
dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
@@ -396,7 +396,19 @@ static void mei_client_connect_response(struct mei_device *dev,
dev->wd_due_counter = (dev->wd_timeout) ? 1 : 0;
dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
- host_init_iamthif(dev);
+
+ /* Registering watchdog interface device once we got connection
+ to the WD Client
+ */
+ if (watchdog_register_device(&amt_wd_dev)) {
+ printk(KERN_ERR "mei: unable to register watchdog device.\n");
+ dev->wd_interface_reg = false;
+ } else {
+ dev_dbg(&dev->pdev->dev, "successfully register watchdog interface.\n");
+ dev->wd_interface_reg = true;
+ }
+
+ mei_host_init_iamthif(dev);
return;
}
@@ -499,7 +511,7 @@ static void add_single_flow_creds(struct mei_device *dev,
struct mei_me_client *client;
int i;
- for (i = 0; i < dev->num_mei_me_clients; i++) {
+ for (i = 0; i < dev->me_clients_num; i++) {
client = &dev->me_clients[i];
if (client && flow->me_addr == client->client_id) {
if (client->props.single_recv_buf) {
@@ -593,7 +605,7 @@ static void mei_client_disconnect_request(struct mei_device *dev,
cl_pos->timer_count = 0;
if (cl_pos == &dev->wd_cl) {
dev->wd_due_counter = 0;
- dev->wd_pending = 0;
+ dev->wd_pending = false;
} else if (cl_pos == &dev->iamthif_cl)
dev->iamthif_timer = 0;
@@ -641,6 +653,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
struct hbm_host_enum_response *enum_res;
struct hbm_client_disconnect_request *disconnect_req;
struct hbm_host_stop_request *host_stop_req;
+ int res;
unsigned char *buffer;
@@ -659,9 +672,9 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
if (dev->mei_state == MEI_INIT_CLIENTS &&
dev->init_clients_state == MEI_START_MESSAGE) {
dev->init_clients_timer = 0;
- host_enum_clients_message(dev);
+ mei_host_enum_clients_message(dev);
} else {
- dev->recvd_msg = 0;
+ dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
mei_reset(dev, 1);
return;
@@ -690,7 +703,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
return;
}
- dev->recvd_msg = 1;
+ dev->recvd_msg = true;
dev_dbg(&dev->pdev->dev, "host start response message received.\n");
break;
@@ -734,7 +747,39 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
MEI_CLIENT_PROPERTIES_MESSAGE) {
dev->me_client_index++;
dev->me_client_presentation_num++;
- host_client_properties(dev);
+
+ /** Send Client Propeties request **/
+ res = mei_host_client_properties(dev);
+ if (res < 0) {
+ dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed");
+ return;
+ } else if (!res) {
+ /*
+ * No more clients to send to.
+ * Clear Map for indicating now ME clients
+ * with associated host client
+ */
+ bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
+ dev->open_handle_count = 0;
+
+ /*
+ * Reserving the first three client IDs
+ * Client Id 0 - Reserved for MEI Bus Message communications
+ * Client Id 1 - Reserved for Watchdog
+ * Client ID 2 - Reserved for AMTHI
+ */
+ bitmap_set(dev->host_clients_map, 0, 3);
+ dev->mei_state = MEI_ENABLED;
+ dev->reset_count = 0;
+
+ /* if wd initialization fails, initialization the AMTHI client,
+ * otherwise the AMTHI client will be initialized after the WD client connect response
+ * will be received
+ */
+ if (mei_wd_host_init(dev))
+ mei_host_init_iamthif(dev);
+ }
+
} else {
dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message");
mei_reset(dev, 1);
@@ -755,10 +800,10 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
dev->init_clients_timer = 0;
dev->me_client_presentation_num = 0;
dev->me_client_index = 0;
- allocate_me_clients_storage(dev);
+ mei_allocate_me_clients_storage(dev);
dev->init_clients_state =
MEI_CLIENT_PROPERTIES_MESSAGE;
- host_client_properties(dev);
+ mei_host_client_properties(dev);
} else {
dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
mei_reset(dev, 1);
@@ -1028,7 +1073,7 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots,
cb_pos->information = dev->iamthif_msg_buf_index;
cl->status = 0;
dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
- dev->iamthif_flow_control_pending = 1;
+ dev->iamthif_flow_control_pending = true;
/* save iamthif cb sent to amthi client */
dev->iamthif_current_cb = cb_pos;
list_move_tail(&cb_pos->cb_list,
@@ -1192,7 +1237,6 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
return 0;
}
- dev->write_hang = -1;
*slots = mei_count_empty_write_slots(dev);
/* complete all waiting for write CB */
dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
@@ -1232,7 +1276,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
}
if (dev->stop && !dev->wd_pending) {
- dev->wd_stopped = 1;
+ dev->wd_stopped = true;
wake_up_interruptible(&dev->wait_stop_wd);
return 0;
}
@@ -1256,7 +1300,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
return -ENODEV;
- dev->wd_pending = 0;
+ dev->wd_pending = false;
if (dev->wd_timeout) {
*slots -= (sizeof(struct mei_msg_hdr) +
@@ -1382,7 +1426,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
*
* NOTE: This function is called by timer interrupt work
*/
-void mei_wd_timer(struct work_struct *work)
+void mei_timer(struct work_struct *work)
{
unsigned long timeout;
struct mei_cl *cl_pos = NULL;
@@ -1392,7 +1436,7 @@ void mei_wd_timer(struct work_struct *work)
struct mei_cl_cb *cb_next = NULL;
struct mei_device *dev = container_of(work,
- struct mei_device, wd_work.work);
+ struct mei_device, timer_work.work);
mutex_lock(&dev->device_lock);
@@ -1419,41 +1463,14 @@ void mei_wd_timer(struct work_struct *work)
}
}
- if (dev->wd_cl.state != MEI_FILE_CONNECTED)
- goto out;
-
- /* Watchdog */
- if (dev->wd_due_counter && !dev->wd_bypass) {
- if (--dev->wd_due_counter == 0) {
- if (dev->mei_host_buffer_is_empty &&
- mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
- dev->mei_host_buffer_is_empty = 0;
- dev_dbg(&dev->pdev->dev, "send watchdog.\n");
-
- if (mei_wd_send(dev))
- dev_dbg(&dev->pdev->dev, "wd send failed.\n");
- else
- if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
- goto out;
-
- if (dev->wd_timeout)
- dev->wd_due_counter = 2;
- else
- dev->wd_due_counter = 0;
-
- } else
- dev->wd_pending = 1;
-
- }
- }
if (dev->iamthif_stall_timer) {
if (--dev->iamthif_stall_timer == 0) {
dev_dbg(&dev->pdev->dev, "reseting because of hang to amthi.\n");
mei_reset(dev, 1);
dev->iamthif_msg_buf_size = 0;
dev->iamthif_msg_buf_index = 0;
- dev->iamthif_canceled = 0;
- dev->iamthif_ioctl = 1;
+ dev->iamthif_canceled = false;
+ dev->iamthif_ioctl = true;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
dev->iamthif_timer = 0;
@@ -1462,7 +1479,7 @@ void mei_wd_timer(struct work_struct *work)
dev->iamthif_file_object = NULL;
dev->iamthif_current_cb = NULL;
- run_next_iamthif_cmd(dev);
+ mei_run_next_iamthif_cmd(dev);
}
}
@@ -1506,12 +1523,13 @@ void mei_wd_timer(struct work_struct *work)
dev->iamthif_file_object = NULL;
dev->iamthif_current_cb = NULL;
dev->iamthif_timer = 0;
- run_next_iamthif_cmd(dev);
+ mei_run_next_iamthif_cmd(dev);
}
}
out:
- schedule_delayed_work(&dev->wd_work, 2 * HZ);
+ if (dev->mei_state != MEI_DISABLED)
+ schedule_delayed_work(&dev->timer_work, 2 * HZ);
mutex_unlock(&dev->device_lock);
}
@@ -1539,8 +1557,14 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
/* initialize our complete list */
mutex_lock(&dev->device_lock);
- mei_initialize_list(&complete_list, dev);
+ mei_io_list_init(&complete_list);
dev->host_hw_state = mei_hcsr_read(dev);
+
+ /* Ack the interrupt here
+ * In case of MSI we don't go throuhg the quick handler */
+ if (pci_dev_msi_enabled(dev->pdev))
+ mei_reg_write(dev, H_CSR, dev->host_hw_state);
+
dev->me_hw_state = mei_mecsr_read(dev);
/* check if ME wants a reset */
@@ -1564,7 +1588,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
/* link is established
* start sending messages.
*/
- host_start_message(dev);
+ mei_host_start_message(dev);
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
} else {
diff --git a/drivers/staging/mei/iorw.c b/drivers/staging/mei/iorw.c
index 697a277..8a61d12 100644
--- a/drivers/staging/mei/iorw.c
+++ b/drivers/staging/mei/iorw.c
@@ -121,7 +121,7 @@ int mei_ioctl_connect_client(struct file *file,
clear_bit(cl->host_client_id, dev->host_clients_map);
list_for_each_entry_safe(cl_pos, cl_next,
&dev->file_list, link) {
- if (mei_fe_same_id(cl, cl_pos)) {
+ if (mei_cl_cmp_id(cl, cl_pos)) {
dev_dbg(&dev->pdev->dev,
"remove file private data node host"
" client = %d, ME client = %d.\n",
@@ -161,7 +161,7 @@ int mei_ioctl_connect_client(struct file *file,
if (dev->mei_host_buffer_is_empty
&& !mei_other_client_is_connecting(dev, cl)) {
dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
- dev->mei_host_buffer_is_empty = 0;
+ dev->mei_host_buffer_is_empty = false;
if (!mei_connect(dev, cl)) {
dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
rets = -ENODEV;
@@ -204,8 +204,8 @@ int mei_ioctl_connect_client(struct file *file,
}
rets = -EFAULT;
- mei_flush_list(&dev->ctrl_rd_list, cl);
- mei_flush_list(&dev->ctrl_wr_list, cl);
+ mei_io_list_flush(&dev->ctrl_rd_list, cl);
+ mei_io_list_flush(&dev->ctrl_wr_list, cl);
goto end;
}
rets = 0;
@@ -277,13 +277,13 @@ int amthi_read(struct mei_device *dev, struct file *file,
return -ETIMEDOUT;
}
- for (i = 0; i < dev->num_mei_me_clients; i++) {
+ for (i = 0; i < dev->me_clients_num; i++) {
if (dev->me_clients[i].client_id ==
dev->iamthif_cl.me_client_id)
break;
}
- if (i == dev->num_mei_me_clients) {
+ if (i == dev->me_clients_num) {
dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
return -ENODEV;
}
@@ -409,7 +409,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
cl->host_client_id, cl->me_client_id);
- for (i = 0; i < dev->num_mei_me_clients; i++) {
+ for (i = 0; i < dev->me_clients_num; i++) {
if (dev->me_clients[i].client_id == cl->me_client_id)
break;
@@ -420,7 +420,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
goto unlock;
}
- if (i == dev->num_mei_me_clients) {
+ if (i == dev->me_clients_num) {
rets = -ENODEV;
goto unlock;
}
@@ -439,7 +439,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
cb->file_private = (void *) cl;
cl->read_cb = cb;
if (dev->mei_host_buffer_is_empty) {
- dev->mei_host_buffer_is_empty = 0;
+ dev->mei_host_buffer_is_empty = false;
if (!mei_send_flow_control(dev, cl)) {
rets = -ENODEV;
goto unlock;
@@ -478,8 +478,8 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
dev->iamthif_state = MEI_IAMTHIF_WRITING;
dev->iamthif_current_cb = cb;
dev->iamthif_file_object = cb->file_object;
- dev->iamthif_canceled = 0;
- dev->iamthif_ioctl = 1;
+ dev->iamthif_canceled = false;
+ dev->iamthif_ioctl = true;
dev->iamthif_msg_buf_size = cb->request_buffer.size;
memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
cb->request_buffer.size);
@@ -490,7 +490,7 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
if (ret && dev->mei_host_buffer_is_empty) {
ret = 0;
- dev->mei_host_buffer_is_empty = 0;
+ dev->mei_host_buffer_is_empty = false;
if (cb->request_buffer.size >
(((dev->host_hw_state & H_CBD) >> 24) * sizeof(u32))
-sizeof(struct mei_msg_hdr)) {
@@ -515,7 +515,7 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
if (mei_hdr.msg_complete) {
if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl))
return -ENODEV;
- dev->iamthif_flow_control_pending = 1;
+ dev->iamthif_flow_control_pending = true;
dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n");
dev->iamthif_current_cb = cb;
@@ -547,7 +547,7 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
*
* returns 0 on success, <0 on failure.
*/
-void run_next_iamthif_cmd(struct mei_device *dev)
+void mei_run_next_iamthif_cmd(struct mei_device *dev)
{
struct mei_cl *cl_tmp;
struct mei_cl_cb *cb_pos = NULL;
@@ -559,8 +559,8 @@ void run_next_iamthif_cmd(struct mei_device *dev)
dev->iamthif_msg_buf_size = 0;
dev->iamthif_msg_buf_index = 0;
- dev->iamthif_canceled = 0;
- dev->iamthif_ioctl = 1;
+ dev->iamthif_canceled = false;
+ dev->iamthif_ioctl = true;
dev->iamthif_state = MEI_IAMTHIF_IDLE;
dev->iamthif_timer = 0;
dev->iamthif_file_object = NULL;
diff --git a/drivers/staging/mei/main.c b/drivers/staging/mei/main.c
index bfd1b46..44ed7a8 100644
--- a/drivers/staging/mei/main.c
+++ b/drivers/staging/mei/main.c
@@ -14,8 +14,6 @@
*
*/
-
-
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -30,7 +28,6 @@
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
-#include <linux/version.h>
#include <linux/sched.h>
#include <linux/uuid.h>
#include <linux/compat.h>
@@ -61,7 +58,7 @@ static struct cdev mei_cdev;
static int mei_major;
/* The device pointer */
/* Currently this driver works as long as there is only a single AMT device. */
-static struct pci_dev *mei_device;
+struct pci_dev *mei_device;
static struct class *mei_class;
@@ -109,6 +106,27 @@ MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
static DEFINE_MUTEX(mei_mutex);
/**
+ * mei_quirk_probe - probe for devices that doesn't valid ME interface
+ * @pdev: PCI device structure
+ * @ent: entry into pci_device_table
+ *
+ * returns true if ME Interface is valid, false otherwise
+ */
+static bool __devinit mei_quirk_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ u32 reg;
+ if (ent->device == MEI_DEV_ID_PBG_1) {
+ pci_read_config_dword(pdev, 0x48, &reg);
+ /* make sure that bit 9 is up and bit 10 is down */
+ if ((reg & 0x600) == 0x200) {
+ dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
+ return false;
+ }
+ }
+ return true;
+}
+/**
* mei_probe - Device Initialization Routine
*
* @pdev: PCI device structure
@@ -123,6 +141,12 @@ static int __devinit mei_probe(struct pci_dev *pdev,
int err;
mutex_lock(&mei_mutex);
+
+ if (!mei_quirk_probe(pdev, ent)) {
+ err = -ENODEV;
+ goto end;
+ }
+
if (mei_device) {
err = -EEXIST;
goto end;
@@ -142,7 +166,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
goto disable_device;
}
/* allocates and initializes the mei dev structure */
- dev = init_mei_device(pdev);
+ dev = mei_device_init(pdev);
if (!dev) {
err = -ENOMEM;
goto release_regions;
@@ -154,17 +178,26 @@ static int __devinit mei_probe(struct pci_dev *pdev,
err = -ENOMEM;
goto free_device;
}
- /* request and enable interrupt */
- err = request_threaded_irq(pdev->irq,
+ pci_enable_msi(pdev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_interrupt_thread_handler,
+ 0, mei_driver_name, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
mei_interrupt_quick_handler,
mei_interrupt_thread_handler,
IRQF_SHARED, mei_driver_name, dev);
+
if (err) {
printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n",
pdev->irq);
goto unmap_memory;
}
- INIT_DELAYED_WORK(&dev->wd_work, mei_wd_timer);
+ INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
if (mei_hw_init(dev)) {
printk(KERN_ERR "mei: Init hw failure.\n");
err = -ENODEV;
@@ -172,7 +205,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
}
mei_device = pdev;
pci_set_drvdata(pdev, dev);
- schedule_delayed_work(&dev->wd_work, HZ);
+ schedule_delayed_work(&dev->timer_work, HZ);
mutex_unlock(&mei_mutex);
@@ -186,6 +219,7 @@ release_irq:
mei_disable_interrupts(dev);
flush_scheduled_work();
free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
unmap_memory:
pci_iounmap(pdev, dev->mem_addr);
free_device:
@@ -234,13 +268,17 @@ static void __devexit mei_remove(struct pci_dev *pdev)
mei_disconnect_host_client(dev, &dev->wd_cl);
}
+ /* Unregistering watchdog device */
+ if (dev->wd_interface_reg)
+ watchdog_unregister_device(&amt_wd_dev);
+
/* remove entry if already in list */
dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id);
mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id);
dev->iamthif_current_cb = NULL;
- dev->num_mei_me_clients = 0;
+ dev->me_clients_num = 0;
mutex_unlock(&dev->device_lock);
@@ -250,6 +288,7 @@ static void __devexit mei_remove(struct pci_dev *pdev)
mei_disable_interrupts(dev);
free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
pci_set_drvdata(pdev, NULL);
if (dev->mem_addr)
@@ -362,7 +401,6 @@ static struct mei_cl_cb *find_read_list_entry(
{
struct mei_cl_cb *cb_pos = NULL;
struct mei_cl_cb *cb_next = NULL;
- struct mei_cl *cl_list_temp;
if (!dev->read_list.status &&
!list_empty(&dev->read_list.mei_cb.cb_list)) {
@@ -370,14 +408,11 @@ static struct mei_cl_cb *find_read_list_entry(
dev_dbg(&dev->pdev->dev, "remove read_list CB\n");
list_for_each_entry_safe(cb_pos, cb_next,
&dev->read_list.mei_cb.cb_list, cb_list) {
+ struct mei_cl *cl_temp;
+ cl_temp = (struct mei_cl *)cb_pos->file_private;
- cl_list_temp = (struct mei_cl *)
- cb_pos->file_private;
-
- if (cl_list_temp &&
- mei_fe_same_id(cl, cl_list_temp))
+ if (mei_cl_cmp_id(cl, cl_temp))
return cb_pos;
-
}
}
return NULL;
@@ -407,9 +442,9 @@ static int mei_open(struct inode *inode, struct file *file)
mutex_lock(&dev->device_lock);
err = -ENOMEM;
- cl = mei_alloc_file_private(dev);
+ cl = mei_cl_allocate(dev);
if (!cl)
- goto out;
+ goto out_unlock;
err = -ENODEV;
if (dev->mei_state != MEI_ENABLED) {
@@ -478,7 +513,7 @@ static int mei_release(struct inode *inode, struct file *file)
cl->me_client_id);
rets = mei_disconnect_host_client(dev, cl);
}
- mei_flush_queues(dev, cl);
+ mei_cl_flush_queues(cl);
dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
cl->host_client_id,
cl->me_client_id);
@@ -519,10 +554,10 @@ static int mei_release(struct inode *inode, struct file *file)
dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n",
dev->iamthif_state);
- dev->iamthif_canceled = 1;
+ dev->iamthif_canceled = true;
if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n");
- run_next_iamthif_cmd(dev);
+ mei_run_next_iamthif_cmd(dev);
}
}
@@ -800,7 +835,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = -ENODEV;
goto unlock_dev;
}
- for (i = 0; i < dev->num_mei_me_clients; i++) {
+ for (i = 0; i < dev->me_clients_num; i++) {
if (dev->me_clients[i].client_id ==
dev->iamthif_cl.me_client_id)
break;
@@ -810,7 +845,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = -ENODEV;
goto unlock_dev;
}
- if (i == dev->num_mei_me_clients ||
+ if (i == dev->me_clients_num ||
(dev->me_clients[i].client_id !=
dev->iamthif_cl.me_client_id)) {
rets = -ENODEV;
@@ -868,7 +903,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
cl->me_client_id);
goto unlock_dev;
}
- for (i = 0; i < dev->num_mei_me_clients; i++) {
+ for (i = 0; i < dev->me_clients_num; i++) {
if (dev->me_clients[i].client_id ==
cl->me_client_id)
break;
@@ -877,7 +912,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = -ENODEV;
goto unlock_dev;
}
- if (i == dev->num_mei_me_clients) {
+ if (i == dev->me_clients_num) {
rets = -ENODEV;
goto unlock_dev;
}
@@ -893,7 +928,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
if (rets && dev->mei_host_buffer_is_empty) {
rets = 0;
- dev->mei_host_buffer_is_empty = 0;
+ dev->mei_host_buffer_is_empty = false;
if (length > ((((dev->host_hw_state & H_CBD) >> 24) *
sizeof(u32)) - sizeof(struct mei_msg_hdr))) {
@@ -1066,7 +1101,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
dev->iamthif_file_object == file) {
mask |= (POLLIN | POLLRDNORM);
dev_dbg(&dev->pdev->dev, "run next amthi cb\n");
- run_next_iamthif_cmd(dev);
+ mei_run_next_iamthif_cmd(dev);
}
goto out;
}
@@ -1103,7 +1138,7 @@ static int mei_pci_suspend(struct device *device)
mutex_unlock(&dev->device_lock);
free_irq(pdev->irq, dev);
-
+ pci_disable_msi(pdev);
return err;
}
@@ -1118,11 +1153,20 @@ static int mei_pci_resume(struct device *device)
if (!dev)
return -ENODEV;
- /* request and enable interrupt */
- err = request_threaded_irq(pdev->irq,
+ pci_enable_msi(pdev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_interrupt_thread_handler,
+ 0, mei_driver_name, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
mei_interrupt_quick_handler,
mei_interrupt_thread_handler,
IRQF_SHARED, mei_driver_name, dev);
+
if (err) {
printk(KERN_ERR "mei: Request_irq failure. irq = %d\n",
pdev->irq);
@@ -1134,12 +1178,9 @@ static int mei_pci_resume(struct device *device)
mei_reset(dev, 1);
mutex_unlock(&dev->device_lock);
- /* Start watchdog if stopped in suspend */
- if (dev->wd_timeout) {
- mei_wd_start_setup(dev);
- dev->wd_due_counter = 1;
- schedule_delayed_work(&dev->wd_work, HZ);
- }
+ /* Start timer if stopped in suspend */
+ schedule_delayed_work(&dev->timer_work, HZ);
+
return err;
}
static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
@@ -1333,9 +1374,9 @@ module_init(mei_init_module);
*/
static void __exit mei_exit_module(void)
{
- pci_unregister_driver(&mei_driver);
mei_sysfs_device_remove();
mei_unregister_cdev();
+ pci_unregister_driver(&mei_driver);
pr_debug("mei: Driver unloaded successfully.\n");
}
diff --git a/drivers/staging/mei/mei_dev.h b/drivers/staging/mei/mei_dev.h
index 6f3ec06..264bf23 100644
--- a/drivers/staging/mei/mei_dev.h
+++ b/drivers/staging/mei/mei_dev.h
@@ -18,6 +18,7 @@
#define _MEI_DEV_H_
#include <linux/types.h>
+#include <linux/watchdog.h>
#include "mei.h"
#include "hw.h"
@@ -37,6 +38,17 @@
#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
/*
+ * MEI PCI Device object
+ */
+extern struct pci_dev *mei_device;
+
+/*
+ * AMT Watchdog Device
+ */
+#define INTEL_AMT_WATCHDOG_ID "INTCAMT"
+extern struct watchdog_device amt_wd_dev;
+
+/*
* AMTHI Client UUID
*/
extern const uuid_le mei_amthi_guid;
@@ -52,6 +64,11 @@ extern const uuid_le mei_wd_guid;
extern const u8 mei_wd_state_independence_msg[3][4];
/*
+ * maximum number of consecutive resets
+ */
+#define MEI_MAX_CONSEC_RESET 3
+
+/*
* Number of File descriptors/handles
* that can be opened to the driver.
*
@@ -62,11 +79,6 @@ extern const u8 mei_wd_state_independence_msg[3][4];
#define MEI_MAX_OPEN_HANDLE_COUNT 253
/*
- * Number of queue lists used by this driver
- */
-#define MEI_IO_LISTS_NUMBER 7
-
-/*
* Number of Maximum MEI Clients
*/
#define MEI_CLIENTS_MAX 255
@@ -169,17 +181,19 @@ struct mei_cl {
struct mei_io_list {
struct mei_cl_cb mei_cb;
int status;
- struct mei_device *device_extension;
};
-/* MEI private device struct */
+/**
+ * mei_device - MEI private device struct
+ *
+ * @reset_count - limits the number of consecutive resets
+ */
struct mei_device {
struct pci_dev *pdev; /* pointer to pci device struct */
/*
* lists of queues
*/
/* array of pointers to aio lists */
- struct mei_io_list *io_list_array[MEI_IO_LISTS_NUMBER];
struct mei_io_list read_list; /* driver read queue */
struct mei_io_list write_list; /* driver write queue */
struct mei_io_list write_waiting_list; /* write waiting queue */
@@ -193,6 +207,7 @@ struct mei_device {
* list of files
*/
struct list_head file_list;
+ long open_handle_count;
/*
* memory of device
*/
@@ -203,8 +218,8 @@ struct mei_device {
* lock for the device
*/
struct mutex device_lock; /* device lock */
- int recvd_msg;
- struct delayed_work wd_work; /* watch dog deleye work */
+ struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
+ bool recvd_msg;
/*
* hw states of host and fw(ME)
*/
@@ -219,10 +234,12 @@ struct mei_device {
/*
* mei device states
*/
+ unsigned long reset_count;
enum mei_states mei_state;
enum mei_init_clients_states init_clients_state;
u16 init_clients_timer;
- int stop;
+ bool stop;
+ bool need_reset;
u32 extra_write_index;
u32 rd_msg_buf[128]; /* used for control messages */
@@ -232,81 +249,107 @@ struct mei_device {
struct hbm_version version;
- int mei_host_buffer_is_empty;
- struct mei_cl wd_cl;
struct mei_me_client *me_clients; /* Note: memory has to be allocated */
DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
- u8 num_mei_me_clients;
+ u8 me_clients_num;
u8 me_client_presentation_num;
u8 me_client_index;
+ bool mei_host_buffer_is_empty;
- int wd_pending;
- int wd_stopped;
+ struct mei_cl wd_cl;
+ bool wd_pending;
+ bool wd_stopped;
+ bool wd_bypass; /* if false, don't refresh watchdog ME client */
u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */
+ u16 wd_due_counter;
unsigned char wd_data[MEI_START_WD_DATA_SIZE];
- u16 wd_due_counter;
- bool wd_bypass; /* if false, don't refresh watchdog ME client */
struct file *iamthif_file_object;
struct mei_cl iamthif_cl;
- int iamthif_ioctl;
- int iamthif_canceled;
+ struct mei_cl_cb *iamthif_current_cb;
int iamthif_mtu;
unsigned long iamthif_timer;
u32 iamthif_stall_timer;
unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */
u32 iamthif_msg_buf_size;
u32 iamthif_msg_buf_index;
- int iamthif_flow_control_pending;
enum iamthif_states iamthif_state;
- struct mei_cl_cb *iamthif_current_cb;
- u8 write_hang;
- int need_reset;
- long open_handle_count;
+ bool iamthif_flow_control_pending;
+ bool iamthif_ioctl;
+ bool iamthif_canceled;
+ bool wd_interface_reg;
};
/*
* mei init function prototypes
*/
-struct mei_device *init_mei_device(struct pci_dev *pdev);
+struct mei_device *mei_device_init(struct pci_dev *pdev);
void mei_reset(struct mei_device *dev, int interrupts);
int mei_hw_init(struct mei_device *dev);
int mei_task_initialize_clients(void *data);
int mei_initialize_clients(struct mei_device *dev);
-struct mei_cl *mei_alloc_file_private(struct mei_device *dev);
int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl);
-void mei_initialize_list(struct mei_io_list *list,
- struct mei_device *dev);
-void mei_flush_list(struct mei_io_list *list, struct mei_cl *cl);
-void mei_flush_queues(struct mei_device *dev, struct mei_cl *cl);
-void mei_remove_client_from_file_list(struct mei_device *dev,
- u8 host_client_id);
-void host_init_iamthif(struct mei_device *dev);
-void mei_init_file_private(struct mei_cl *priv, struct mei_device *dev);
-void allocate_me_clients_storage(struct mei_device *dev);
-
-void host_start_message(struct mei_device *dev);
-void host_enum_clients_message(struct mei_device *dev);
-void host_client_properties(struct mei_device *dev);
+void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id);
+void mei_host_init_iamthif(struct mei_device *dev);
+void mei_allocate_me_clients_storage(struct mei_device *dev);
+
u8 mei_find_me_client_update_filext(struct mei_device *dev,
struct mei_cl *priv,
const uuid_le *cguid, u8 client_id);
/*
- * interrupt functions prototype
+ * MEI IO List Functions
+ */
+void mei_io_list_init(struct mei_io_list *list);
+void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl);
+
+/*
+ * MEI ME Client Functions
+ */
+
+struct mei_cl *mei_cl_allocate(struct mei_device *dev);
+void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
+int mei_cl_flush_queues(struct mei_cl *cl);
+/**
+ * mei_cl_cmp_id - tells if file private data have same id
+ *
+ * @fe1: private data of 1. file object
+ * @fe2: private data of 2. file object
+ *
+ * returns true - if ids are the same and not NULL
+ */
+static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
+ const struct mei_cl *cl2)
+{
+ return cl1 && cl2 &&
+ (cl1->host_client_id == cl2->host_client_id) &&
+ (cl1->me_client_id == cl2->me_client_id);
+}
+
+
+
+/*
+ * MEI Host Client Functions
+ */
+void mei_host_start_message(struct mei_device *dev);
+void mei_host_enum_clients_message(struct mei_device *dev);
+int mei_host_client_properties(struct mei_device *dev);
+
+/*
+ * MEI interrupt functions prototype
*/
irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id);
-irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id);
-void mei_wd_timer(struct work_struct *work);
+irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id);
+void mei_timer(struct work_struct *work);
/*
- * input output function prototype
+ * MEI input output function prototype
*/
int mei_ioctl_connect_client(struct file *file,
struct mei_connect_client_data *data);
@@ -321,7 +364,7 @@ int amthi_read(struct mei_device *dev, struct file *file,
struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev,
struct file *file);
-void run_next_iamthif_cmd(struct mei_device *dev);
+void mei_run_next_iamthif_cmd(struct mei_device *dev);
void mei_free_cb_private(struct mei_cl_cb *priv_cb);
@@ -337,10 +380,9 @@ int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
* @dev: the device structure
* @offset: offset from which to read the data
*
- * returns the byte read.
+ * returns register value (u32)
*/
-static inline u32 mei_reg_read(struct mei_device *dev,
- unsigned long offset)
+static inline u32 mei_reg_read(struct mei_device *dev, unsigned long offset)
{
return ioread32(dev->mem_addr + offset);
}
@@ -350,7 +392,7 @@ static inline u32 mei_reg_read(struct mei_device *dev,
*
* @dev: the device structure
* @offset: offset from which to write the data
- * @value: the byte to write
+ * @value: register value to write (u32)
*/
static inline void mei_reg_write(struct mei_device *dev,
unsigned long offset, u32 value)
@@ -404,19 +446,4 @@ void mei_csr_clear_his(struct mei_device *dev);
void mei_enable_interrupts(struct mei_device *dev);
void mei_disable_interrupts(struct mei_device *dev);
-/**
- * mei_fe_same_id - tells if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns !=0 - if ids are the same, 0 - if differ.
- */
-static inline int mei_fe_same_id(const struct mei_cl *fe1,
- const struct mei_cl *fe2)
-{
- return ((fe1->host_client_id == fe2->host_client_id) &&
- (fe1->me_client_id == fe2->me_client_id));
-}
-
#endif
diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c
index fff53d0..ffca7ca 100644
--- a/drivers/staging/mei/wd.c
+++ b/drivers/staging/mei/wd.c
@@ -19,22 +19,13 @@
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/sched.h>
+#include <linux/watchdog.h>
#include "mei_dev.h"
#include "hw.h"
#include "interface.h"
#include "mei.h"
-/*
- * MEI Watchdog Module Parameters
- */
-static u16 watchdog_timeout = AMT_WD_VALUE;
-module_param(watchdog_timeout, ushort, 0);
-MODULE_PARM_DESC(watchdog_timeout,
- "Intel(R) AMT Watchdog timeout value in seconds. (default="
- __MODULE_STRING(AMT_WD_VALUE)
- ", disable=0)");
-
static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
@@ -50,12 +41,12 @@ const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
0x32, 0xAB);
-void mei_wd_start_setup(struct mei_device *dev)
+void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
{
- dev_dbg(&dev->pdev->dev, "dev->wd_timeout=%d.\n", dev->wd_timeout);
+ dev_dbg(&dev->pdev->dev, "timeout=%d.\n", timeout);
memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE,
- &dev->wd_timeout, sizeof(u16));
+ &timeout, sizeof(u16));
}
/**
@@ -63,39 +54,39 @@ void mei_wd_start_setup(struct mei_device *dev)
*
* @dev: the device structure
*/
-void mei_wd_host_init(struct mei_device *dev)
+bool mei_wd_host_init(struct mei_device *dev)
{
- mei_init_file_private(&dev->wd_cl, dev);
+ bool ret = false;
+
+ mei_cl_init(&dev->wd_cl, dev);
/* look for WD client and connect to it */
dev->wd_cl.state = MEI_FILE_DISCONNECTED;
- dev->wd_timeout = watchdog_timeout;
-
- if (dev->wd_timeout > 0) {
- mei_wd_start_setup(dev);
- /* find ME WD client */
- mei_find_me_client_update_filext(dev, &dev->wd_cl,
- &mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
-
- dev_dbg(&dev->pdev->dev, "check wd_cl\n");
- if (MEI_FILE_CONNECTING == dev->wd_cl.state) {
- if (!mei_connect(dev, &dev->wd_cl)) {
- dev_dbg(&dev->pdev->dev, "Failed to connect to WD client\n");
- dev->wd_cl.state = MEI_FILE_DISCONNECTED;
- dev->wd_cl.host_client_id = 0;
- host_init_iamthif(dev) ;
- } else {
- dev->wd_cl.timer_count = CONNECT_TIMEOUT;
- }
+ dev->wd_timeout = AMT_WD_DEFAULT_TIMEOUT;
+
+ /* find ME WD client */
+ mei_find_me_client_update_filext(dev, &dev->wd_cl,
+ &mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
+
+ dev_dbg(&dev->pdev->dev, "check wd_cl\n");
+ if (MEI_FILE_CONNECTING == dev->wd_cl.state) {
+ if (!mei_connect(dev, &dev->wd_cl)) {
+ dev_dbg(&dev->pdev->dev, "Failed to connect to WD client\n");
+ dev->wd_cl.state = MEI_FILE_DISCONNECTED;
+ dev->wd_cl.host_client_id = 0;
+ ret = false;
+ goto end;
} else {
- dev_dbg(&dev->pdev->dev, "Failed to find WD client\n");
- host_init_iamthif(dev) ;
+ dev->wd_cl.timer_count = CONNECT_TIMEOUT;
}
} else {
- dev->wd_bypass = true;
- dev_dbg(&dev->pdev->dev, "WD requested to be disabled\n");
- host_init_iamthif(dev) ;
+ dev_dbg(&dev->pdev->dev, "Failed to find WD client\n");
+ ret = false;
+ goto end;
}
+
+end:
+ return ret;
}
/**
@@ -129,19 +120,29 @@ int mei_wd_send(struct mei_device *dev)
return -EIO;
}
+/**
+ * mei_wd_stop - sends watchdog stop message to fw.
+ *
+ * @dev: the device structure
+ * @preserve: indicate if to keep the timeout value
+ *
+ * returns 0 if success,
+ * -EIO when message send fails
+ * -EINVAL when invalid message is to be sent
+ */
int mei_wd_stop(struct mei_device *dev, bool preserve)
{
int ret;
u16 wd_timeout = dev->wd_timeout;
- cancel_delayed_work(&dev->wd_work);
+ cancel_delayed_work(&dev->timer_work);
if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
return 0;
dev->wd_timeout = 0;
dev->wd_due_counter = 0;
memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
- dev->stop = 1;
+ dev->stop = true;
ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
if (ret < 0)
@@ -149,7 +150,7 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
if (ret && dev->mei_host_buffer_is_empty) {
ret = 0;
- dev->mei_host_buffer_is_empty = 0;
+ dev->mei_host_buffer_is_empty = false;
if (!mei_wd_send(dev)) {
ret = mei_flow_ctrl_reduce(dev, &dev->wd_cl);
@@ -159,11 +160,11 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
dev_dbg(&dev->pdev->dev, "send stop WD failed\n");
}
- dev->wd_pending = 0;
+ dev->wd_pending = false;
} else {
- dev->wd_pending = 1;
+ dev->wd_pending = true;
}
- dev->wd_stopped = 0;
+ dev->wd_stopped = false;
mutex_unlock(&dev->device_lock);
ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
@@ -186,3 +187,168 @@ out:
return ret;
}
+/*
+ * mei_wd_ops_start - wd start command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_start(struct watchdog_device *wd_dev)
+{
+ int err = -ENODEV;
+ struct mei_device *dev;
+
+ dev = pci_get_drvdata(mei_device);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->device_lock);
+
+ if (dev->mei_state != MEI_ENABLED) {
+ dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED mei_state= %d\n",
+ dev->mei_state);
+ goto end_unlock;
+ }
+
+ if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
+ dev_dbg(&dev->pdev->dev, "MEI Driver is not connected to Watchdog Client\n");
+ goto end_unlock;
+ }
+
+ mei_wd_set_start_timeout(dev, dev->wd_timeout);
+
+ err = 0;
+end_unlock:
+ mutex_unlock(&dev->device_lock);
+ return err;
+}
+
+/*
+ * mei_wd_ops_stop - wd stop command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
+{
+ struct mei_device *dev;
+ dev = pci_get_drvdata(mei_device);
+
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->device_lock);
+ mei_wd_stop(dev, false);
+ mutex_unlock(&dev->device_lock);
+
+ return 0;
+}
+
+/*
+ * mei_wd_ops_ping - wd ping command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
+{
+ int ret = 0;
+ struct mei_device *dev;
+ dev = pci_get_drvdata(mei_device);
+
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->device_lock);
+
+ if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
+ dev_dbg(&dev->pdev->dev, "wd is not connected.\n");
+ ret = -ENODEV;
+ goto end;
+ }
+
+ /* Check if we can send the ping to HW*/
+ if (dev->mei_host_buffer_is_empty &&
+ mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
+
+ dev->mei_host_buffer_is_empty = false;
+ dev_dbg(&dev->pdev->dev, "sending watchdog ping\n");
+
+ if (mei_wd_send(dev)) {
+ dev_dbg(&dev->pdev->dev, "wd send failed.\n");
+ ret = -EIO;
+ goto end;
+ }
+
+ if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) {
+ dev_dbg(&dev->pdev->dev, "mei_flow_ctrl_reduce() failed.\n");
+ ret = -EIO;
+ goto end;
+ }
+
+ } else {
+ dev->wd_pending = true;
+ }
+
+end:
+ mutex_unlock(&dev->device_lock);
+ return ret;
+}
+
+/*
+ * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core.
+ *
+ * @wd_dev - watchdog device struct
+ * @timeout - timeout value to set
+ *
+ * returns 0 if success, negative errno code for failure
+ */
+static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
+{
+ struct mei_device *dev;
+ dev = pci_get_drvdata(mei_device);
+
+ if (!dev)
+ return -ENODEV;
+
+ /* Check Timeout value */
+ if (timeout < AMT_WD_MIN_TIMEOUT || timeout > AMT_WD_MAX_TIMEOUT)
+ return -EINVAL;
+
+ mutex_lock(&dev->device_lock);
+
+ dev->wd_timeout = timeout;
+ mei_wd_set_start_timeout(dev, dev->wd_timeout);
+
+ mutex_unlock(&dev->device_lock);
+
+ return 0;
+}
+
+/*
+ * Watchdog Device structs
+ */
+const struct watchdog_ops wd_ops = {
+ .owner = THIS_MODULE,
+ .start = mei_wd_ops_start,
+ .stop = mei_wd_ops_stop,
+ .ping = mei_wd_ops_ping,
+ .set_timeout = mei_wd_ops_set_timeout,
+};
+const struct watchdog_info wd_info = {
+ .identity = INTEL_AMT_WATCHDOG_ID,
+ .options = WDIOF_KEEPALIVEPING,
+};
+
+struct watchdog_device amt_wd_dev = {
+ .info = &wd_info,
+ .ops = &wd_ops,
+ .timeout = AMT_WD_DEFAULT_TIMEOUT,
+ .min_timeout = AMT_WD_MIN_TIMEOUT,
+ .max_timeout = AMT_WD_MAX_TIMEOUT,
+};
+
+