From 90e0b5f18569bdd03c5ddd1d8c99946f42af77b8 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 8 Jan 2013 23:07:14 +0200 Subject: mei: fix client functions names Use common prefix for function names: mei_cl_ - for host clients mei_me_ - for me clients mei_io_ - for io callback functions Because mei_cl holds mei_device back pointer we can also drop the dev argument from the client functions add client.h header to export the clients API Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.h | 97 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 drivers/misc/mei/client.h (limited to 'drivers/misc/mei/client.h') diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h new file mode 100644 index 000000000000..8dfd052dd0e6 --- /dev/null +++ b/drivers/misc/mei/client.h @@ -0,0 +1,97 @@ +/* + * + * Intel Management Engine Interface (Intel MEI) Linux driver + * Copyright (c) 2003-2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef _MEI_CLIENT_H_ +#define _MEI_CLIENT_H_ + +#include +#include +#include +#include + +#include "mei_dev.h" + +int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid); +int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); + +/* + * MEI IO Functions + */ +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp); +void mei_io_cb_free(struct mei_cl_cb *priv_cb); +int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length); +int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length); + + +/** + * mei_io_list_init - Sets up a queue list. + * + * @list: An instance cl callback structure + */ +static inline void mei_io_list_init(struct mei_cl_cb *list) +{ + INIT_LIST_HEAD(&list->list); +} +void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl); + +/* + * MEI Host 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_link_me(struct mei_cl *cl, const uuid_le *uuid, u8 host_cl_id); +int mei_cl_unlink(struct mei_cl *cl); + +int mei_cl_flush_queues(struct mei_cl *cl); +struct mei_cl_cb *mei_cl_find_read_cb(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); +} + + +int mei_cl_flow_ctrl_creds(struct mei_cl *cl); + +int mei_cl_flow_ctrl_reduce(struct mei_cl *cl); +/* + * MEI input output function prototype + */ +bool mei_cl_is_other_connecting(struct mei_cl *cl); +int mei_cl_disconnect(struct mei_cl *cl); + +int mei_cl_read_start(struct mei_cl *cl); + +int mei_cl_connect(struct mei_cl *cl, struct file *file); + +void mei_host_client_init(struct work_struct *work); + + +#endif /* _MEI_CLIENT_H_ */ -- cgit v1.2.3 From 781d0d89224bbbc438c2c0360cfd4822bb35d280 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 8 Jan 2013 23:07:22 +0200 Subject: mei: normalize me host client linking routines In order we can use the same code pattern for in-kernel and user space host clients we replace mei_cl_link_to_me with mei_cl_link function. We then have to keep me client lookupout of the new link function. The unlinking cannot be yet symetric due to amthif connection handling Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 42 ++++++++++++++++++++++-------------- drivers/misc/mei/client.c | 53 ++++++++++++++++++++++++++-------------------- drivers/misc/mei/client.h | 2 +- drivers/misc/mei/init.c | 4 ++++ drivers/misc/mei/main.c | 27 ++++++++--------------- drivers/misc/mei/mei_dev.h | 10 ++++----- drivers/misc/mei/wd.c | 35 +++++++++++++++++++----------- 7 files changed, 98 insertions(+), 75 deletions(-) (limited to 'drivers/misc/mei/client.h') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 64a9bfa5ad20..88e6aa0f6b4e 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -65,22 +65,22 @@ void mei_amthif_reset_params(struct mei_device *dev) * @dev: the device structure * */ -void mei_amthif_host_init(struct mei_device *dev) +int mei_amthif_host_init(struct mei_device *dev) { - int i; + struct mei_cl *cl = &dev->iamthif_cl; unsigned char *msg_buf; + int ret, i; - mei_cl_init(&dev->iamthif_cl, dev); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; + mei_cl_init(cl, dev); - /* find ME amthif client */ - i = mei_cl_link_me(&dev->iamthif_cl, - &mei_amthif_guid, MEI_IAMTHIF_HOST_CLIENT_ID); + i = mei_me_cl_by_uuid(dev, &mei_amthif_guid); if (i < 0) { - dev_info(&dev->pdev->dev, "failed to find iamthif client.\n"); - return; + dev_info(&dev->pdev->dev, "amthif: failed to find the client\n"); + return -ENOENT; } + cl->me_client_id = dev->me_clients[i].client_id; + /* Assign iamthif_mtu to the value received from ME */ dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; @@ -94,19 +94,29 @@ void mei_amthif_host_init(struct mei_device *dev) msg_buf = kcalloc(dev->iamthif_mtu, sizeof(unsigned char), GFP_KERNEL); if (!msg_buf) { - dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); - return; + dev_err(&dev->pdev->dev, "amthif: memory allocation for ME message buffer failed.\n"); + return -ENOMEM; } dev->iamthif_msg_buf = msg_buf; - if (mei_hbm_cl_connect_req(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - dev->iamthif_cl.host_client_id = 0; + ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID); + + if (ret < 0) { + dev_err(&dev->pdev->dev, "amthif: failed link client\n"); + return -ENOENT; + } + + cl->state = MEI_FILE_CONNECTING; + + if (mei_hbm_cl_connect_req(dev, cl)) { + dev_dbg(&dev->pdev->dev, "amthif: Failed to connect to ME client\n"); + cl->state = MEI_FILE_DISCONNECTED; + cl->host_client_id = 0; } else { - dev->iamthif_cl.timer_count = MEI_CONNECT_TIMEOUT; + cl->timer_count = MEI_CONNECT_TIMEOUT; } + return 0; } /** diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 8103d94facb8..d566dd880eb0 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -258,54 +258,61 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) return NULL; } - -/** - * mei_me_cl_link - create link between host and me clinet and add - * me_cl to the list - * - * @cl: link between me and host client assocated with opened file descriptor - * @uuid: uuid of ME client - * @client_id: id of the host client +/** mei_cl_link: allocte host id in the host map * - * returns ME client index if ME client + * @cl - host client + * @id - fixed host id or -1 for genereting one + * returns 0 on success * -EINVAL on incorrect values * -ENONET if client not found */ -int mei_cl_link_me(struct mei_cl *cl, const uuid_le *uuid, u8 host_cl_id) +int mei_cl_link(struct mei_cl *cl, int id) { struct mei_device *dev; - int i; - if (WARN_ON(!cl || !cl->dev || !uuid)) + if (WARN_ON(!cl || !cl->dev)) return -EINVAL; dev = cl->dev; - /* check for valid client id */ - i = mei_me_cl_by_uuid(dev, uuid); - if (i >= 0) { - cl->me_client_id = dev->me_clients[i].client_id; - cl->state = MEI_FILE_CONNECTING; - cl->host_client_id = host_cl_id; + /* If Id is not asigned get one*/ + if (id == MEI_HOST_CLIENT_ID_ANY) + id = find_first_zero_bit(dev->host_clients_map, + MEI_CLIENTS_MAX); - list_add_tail(&cl->link, &dev->file_list); - return (u8)i; + if (id >= MEI_CLIENTS_MAX) { + dev_err(&dev->pdev->dev, "id exceded %d", MEI_CLIENTS_MAX) ; + return -ENOENT; } - return -ENOENT; + dev->open_handle_count++; + + cl->host_client_id = id; + list_add_tail(&cl->link, &dev->file_list); + + set_bit(id, dev->host_clients_map); + + cl->state = MEI_FILE_INITIALIZING; + + dev_dbg(&dev->pdev->dev, "link cl host id = %d\n", cl->host_client_id); + return 0; } + /** * mei_cl_unlink - remove me_cl from the list * * @dev: the device structure - * @host_client_id: host client id to be removed */ int mei_cl_unlink(struct mei_cl *cl) { struct mei_device *dev; struct mei_cl *pos, *next; - if (WARN_ON(!cl || !cl->dev)) + /* don't shout on error exit path */ + if (!cl) + return 0; + + if (WARN_ON(!cl->dev)) return -EINVAL; dev = cl->dev; diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 8dfd052dd0e6..240a1f321342 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -55,7 +55,7 @@ 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_link_me(struct mei_cl *cl, const uuid_le *uuid, u8 host_cl_id); +int mei_cl_link(struct mei_cl *cl, int id); int mei_cl_unlink(struct mei_cl *cl); int mei_cl_flush_queues(struct mei_cl *cl); diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 636639fbfc0a..9e4011ef8508 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -242,7 +242,11 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) /* remove entry if already in list */ dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); mei_cl_unlink(&dev->wd_cl); + if (dev->open_handle_count > 0) + dev->open_handle_count--; mei_cl_unlink(&dev->iamthif_cl); + if (dev->open_handle_count > 0) + dev->open_handle_count--; mei_amthif_reset_params(dev); memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index d5d1a5957d5f..ec5fd7a0e289 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -103,7 +103,6 @@ static int mei_open(struct inode *inode, struct file *file) { struct mei_cl *cl; struct mei_device *dev; - unsigned long cl_id; int err; err = -ENODEV; @@ -133,24 +132,9 @@ static int mei_open(struct inode *inode, struct file *file) goto out_unlock; } - cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX); - if (cl_id >= MEI_CLIENTS_MAX) { - dev_err(&dev->pdev->dev, "client_id exceded %d", - MEI_CLIENTS_MAX) ; + err = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY); + if (err) goto out_unlock; - } - - cl->host_client_id = cl_id; - - dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id); - - dev->open_handle_count++; - - list_add_tail(&cl->link, &dev->file_list); - - set_bit(cl->host_client_id, dev->host_clients_map); - cl->state = MEI_FILE_INITIALIZING; - cl->sm_state = 0; file->private_data = cl; mutex_unlock(&dev->device_lock); @@ -209,6 +193,7 @@ static int mei_release(struct inode *inode, struct file *file) } mei_cl_unlink(cl); + /* free read cb */ cb = NULL; if (cl->read_cb) { @@ -991,7 +976,13 @@ static void mei_remove(struct pci_dev *pdev) /* remove entry if already in list */ dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); + + if (dev->open_handle_count > 0) + dev->open_handle_count--; mei_cl_unlink(&dev->wd_cl); + + if (dev->open_handle_count > 0) + dev->open_handle_count--; mei_cl_unlink(&dev->iamthif_cl); dev->iamthif_current_cb = NULL; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 285e8e01d429..dcd7a44a806e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -67,16 +67,16 @@ extern const u8 mei_wd_state_independence_msg[3][4]; * Number of File descriptors/handles * that can be opened to the driver. * - * Limit to 253: 256 Total Clients + * Limit to 255: 256 Total Clients * minus internal client for MEI Bus Messags - * minus internal client for AMTHI - * minus internal client for Watchdog */ -#define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 3) +#define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1) /* * Internal Clients Number */ +#define MEI_HOST_CLIENT_ID_ANY (-1) +#define MEI_HBM_HOST_CLIENT_ID 0 /* not used, just for documentation */ #define MEI_WD_HOST_CLIENT_ID 1 #define MEI_IAMTHIF_HOST_CLIENT_ID 2 @@ -339,7 +339,7 @@ void mei_timer(struct work_struct *work); */ void mei_amthif_reset_params(struct mei_device *dev); -void mei_amthif_host_init(struct mei_device *dev); +int mei_amthif_host_init(struct mei_device *dev); int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index bfcbcc8c028b..77b3820380b0 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -64,30 +64,41 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout) */ int mei_wd_host_init(struct mei_device *dev) { - int id; - mei_cl_init(&dev->wd_cl, dev); + struct mei_cl *cl = &dev->wd_cl; + int i; + int ret; + + mei_cl_init(cl, dev); - /* look for WD client and connect to it */ - dev->wd_cl.state = MEI_FILE_DISCONNECTED; dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT; dev->wd_state = MEI_WD_IDLE; - /* Connect WD ME client to the host client */ - id = mei_cl_link_me(&dev->wd_cl, - &mei_wd_guid, MEI_WD_HOST_CLIENT_ID); - if (id < 0) { + /* check for valid client id */ + i = mei_me_cl_by_uuid(dev, &mei_wd_guid); + if (i < 0) { dev_info(&dev->pdev->dev, "wd: failed to find the client\n"); return -ENOENT; } - if (mei_hbm_cl_connect_req(dev, &dev->wd_cl)) { + cl->me_client_id = dev->me_clients[i].client_id; + + ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID); + + if (ret < 0) { + dev_info(&dev->pdev->dev, "wd: failed link client\n"); + return -ENOENT; + } + + cl->state = MEI_FILE_CONNECTING; + + if (mei_hbm_cl_connect_req(dev, cl)) { dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n"); - dev->wd_cl.state = MEI_FILE_DISCONNECTED; - dev->wd_cl.host_client_id = 0; + cl->state = MEI_FILE_DISCONNECTED; + cl->host_client_id = 0; return -EIO; } - dev->wd_cl.timer_count = MEI_CONNECT_TIMEOUT; + cl->timer_count = MEI_CONNECT_TIMEOUT; return 0; } -- cgit v1.2.3 From 074b4c01abb68c6767612a01f41e9b4ed93d5fb8 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 6 Feb 2013 14:06:44 +0200 Subject: mei: move clients cleanup code from init.c to client.c during reset we clean up client data structures we move that code into wrappers in client and call the wrappers Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/mei/client.h | 5 +++++ drivers/misc/mei/init.c | 28 ++++++-------------------- 3 files changed, 62 insertions(+), 22 deletions(-) (limited to 'drivers/misc/mei/client.h') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index e46663ee76de..1569afe935de 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -676,3 +676,54 @@ err: return rets; } +/** + * mei_cl_all_disconnect - disconnect forcefully all connected clients + * + * @dev - mei device + */ + +void mei_cl_all_disconnect(struct mei_device *dev) +{ + struct mei_cl *cl, *next; + + list_for_each_entry_safe(cl, next, &dev->file_list, link) { + cl->state = MEI_FILE_DISCONNECTED; + cl->mei_flow_ctrl_creds = 0; + cl->read_cb = NULL; + cl->timer_count = 0; + } +} + + +/** + * mei_cl_all_read_wakeup - wake up all readings so they can be interrupted + * + * @dev - mei device + */ +void mei_cl_all_read_wakeup(struct mei_device *dev) +{ + struct mei_cl *cl, *next; + list_for_each_entry_safe(cl, next, &dev->file_list, link) { + if (waitqueue_active(&cl->rx_wait)) { + dev_dbg(&dev->pdev->dev, "Waking up client!\n"); + wake_up_interruptible(&cl->rx_wait); + } + } +} + +/** + * mei_cl_all_write_clear - clear all pending writes + + * @dev - mei device + */ +void mei_cl_all_write_clear(struct mei_device *dev) +{ + struct mei_cl_cb *cb, *next; + + list_for_each_entry_safe(cb, next, &dev->write_list.list, list) { + list_del(&cb->list); + mei_io_cb_free(cb); + } +} + + diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 240a1f321342..214b2397ec3e 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -94,4 +94,9 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file); void mei_host_client_init(struct work_struct *work); +void mei_cl_all_disconnect(struct mei_device *dev); +void mei_cl_all_read_wakeup(struct mei_device *dev); +void mei_cl_all_write_clear(struct mei_device *dev); + + #endif /* _MEI_CLIENT_H_ */ diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 51a005e80952..6ec530168afb 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -135,10 +135,6 @@ err: */ void mei_reset(struct mei_device *dev, int interrupts_enabled) { - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; bool unexpected; if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) @@ -157,13 +153,8 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) dev->dev_state != MEI_DEV_POWER_DOWN) dev->dev_state = MEI_DEV_RESETING; - list_for_each_entry_safe(cl_pos, - cl_next, &dev->file_list, link) { - cl_pos->state = MEI_FILE_DISCONNECTED; - cl_pos->mei_flow_ctrl_creds = 0; - cl_pos->read_cb = NULL; - cl_pos->timer_count = 0; - } + mei_cl_all_disconnect(dev); + /* remove entry if already in list */ dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); mei_cl_unlink(&dev->wd_cl); @@ -185,18 +176,11 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", mei_dev_state_str(dev->dev_state)); - /* Wake up all readings so they can be interrupted */ - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (waitqueue_active(&cl_pos->rx_wait)) { - dev_dbg(&dev->pdev->dev, "Waking up client!\n"); - wake_up_interruptible(&cl_pos->rx_wait); - } - } + /* wake up all readings so they can be interrupted */ + mei_cl_all_read_wakeup(dev); + /* remove all waiting requests */ - list_for_each_entry_safe(cb_pos, cb_next, &dev->write_list.list, list) { - list_del(&cb_pos->list); - mei_io_cb_free(cb_pos); - } + mei_cl_all_write_clear(dev); } -- cgit v1.2.3