From 47a73801f498883ea3acccb8f6ff1b5c7a3553de Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 25 Dec 2012 19:06:03 +0200 Subject: mei: include local headers after the system ones first include linux/mei.h then only local headers to avoid possible false dependencies Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/iorw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc/mei/iorw.c') diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index eb93a1b53b9b..7ccc3d8a079e 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -33,9 +33,9 @@ #include -#include "mei_dev.h" -#include "hw.h" #include + +#include "mei_dev.h" #include "interface.h" /** -- cgit v1.2.3 From 8120e7201cf9795bc98ffb2e3064b657c0f34c05 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 25 Dec 2012 19:06:11 +0200 Subject: mei: add common prefix to hbm function 1. use mei_hbm_ for basic host bus message function 2. use mei_hbm_cl prefix for host bus messages that operation on behalf of a client Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 7 +++--- drivers/misc/mei/hbm.c | 56 +++++++++++++++++++++++++------------------- drivers/misc/mei/init.c | 4 ++-- drivers/misc/mei/interface.h | 11 +++++---- drivers/misc/mei/interrupt.c | 10 ++++---- drivers/misc/mei/iorw.c | 4 ++-- drivers/misc/mei/mei_dev.h | 9 ------- drivers/misc/mei/wd.c | 2 +- 8 files changed, 53 insertions(+), 50 deletions(-) (limited to 'drivers/misc/mei/iorw.c') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index f9d458cced21..6e3cd31eae3b 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -98,7 +98,7 @@ void mei_amthif_host_init(struct mei_device *dev) dev->iamthif_msg_buf = msg_buf; - if (mei_connect(dev, &dev->iamthif_cl)) { + 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; @@ -558,7 +558,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots) return -EMSGSIZE; } *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); - if (mei_send_flow_control(dev, &dev->iamthif_cl)) { + if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) { dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); return -EIO; } @@ -630,7 +630,8 @@ static bool mei_clear_list(struct mei_device *dev, if (dev->iamthif_current_cb == cb_pos) { dev->iamthif_current_cb = NULL; /* send flow control to iamthif client */ - mei_send_flow_control(dev, &dev->iamthif_cl); + mei_hbm_cl_flow_control_req(dev, + &dev->iamthif_cl); } /* free all allocated buffers */ mei_io_cb_free(cb_pos); diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index e9ba51d5a46c..3c9914038490 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -59,13 +59,11 @@ bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf) /** - * host_start_message - mei host sends start message. + * mei_hbm_start_req - sends start request message. * * @dev: the device structure - * - * returns none. */ -void mei_host_start_message(struct mei_device *dev) +void mei_hbm_start_req(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; struct hbm_host_version_request *start_req; @@ -92,13 +90,13 @@ void mei_host_start_message(struct mei_device *dev) } /** - * host_enum_clients_message - host sends enumeration client request message. + * mei_hbm_enum_clients_req - sends enumeration client request message. * * @dev: the device structure * * returns none. */ -void mei_host_enum_clients_message(struct mei_device *dev) +static void mei_hbm_enum_clients_req(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; struct hbm_host_enum_request *enum_req; @@ -120,8 +118,15 @@ void mei_host_enum_clients_message(struct mei_device *dev) return; } +/** + * mei_hbm_prop_requsest - request property for a single client + * + * @dev: the device structure + * + * returns none. + */ -int mei_host_client_enumerate(struct mei_device *dev) +static int mei_hbm_prop_req(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; @@ -191,14 +196,14 @@ static void mei_hbm_stop_req_prepare(struct mei_device *dev, } /** - * mei_send_flow_control - sends flow control to fw. + * mei_hbm_cl_flow_control_req - sends flow control requst. * * @dev: the device structure - * @cl: private data of the file object + * @cl: client info * * This function returns -EIO on write failure */ -int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl) +int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; const size_t len = sizeof(struct hbm_flow_control); @@ -213,14 +218,14 @@ int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl) } /** - * mei_disconnect - sends disconnect message to fw. + * mei_hbm_cl_disconnect_req - sends disconnect message to fw. * * @dev: the device structure - * @cl: private data of the file object + * @cl: a client to disconnect from * * This function returns -EIO on write failure */ -int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) +int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; const size_t len = sizeof(struct hbm_client_connect_request); @@ -232,14 +237,14 @@ int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) } /** - * mei_connect - sends connect message to fw. + * mei_hbm_cl_connect_req - send connection request to specific me client * * @dev: the device structure - * @cl: private data of the file object + * @cl: a client to connect to * - * This function returns -EIO on write failure + * returns -EIO on write failure */ -int mei_connect(struct mei_device *dev, struct mei_cl *cl) +int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; const size_t len = sizeof(struct hbm_client_connect_request); @@ -251,12 +256,13 @@ int mei_connect(struct mei_device *dev, struct mei_cl *cl) } /** - * mei_client_disconnect_request - disconnects from request irq routine + * mei_client_disconnect_request - disconnect request initiated by me + * host sends disoconnect response * * @dev: the device structure. - * @disconnect_req: disconnect request bus message. + * @disconnect_req: disconnect request bus message from the me */ -static void mei_client_disconnect_request(struct mei_device *dev, +static void mei_hbm_fw_disconnect_req(struct mei_device *dev, struct hbm_client_connect_request *disconnect_req) { struct mei_cl *cl, *next; @@ -327,7 +333,7 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) if (dev->dev_state == MEI_DEV_INIT_CLIENTS && dev->init_clients_state == MEI_START_MESSAGE) { dev->init_clients_timer = 0; - mei_host_enum_clients_message(dev); + mei_hbm_enum_clients_req(dev); } else { dev->recvd_msg = false; dev_dbg(&dev->pdev->dev, "reset due to received hbm: host start\n"); @@ -390,7 +396,8 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) dev->me_client_index++; dev->me_client_presentation_num++; - mei_host_client_enumerate(dev); + /* request property for the next client */ + mei_hbm_prop_req(dev); break; @@ -406,7 +413,8 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) dev->init_clients_state = MEI_CLIENT_PROPERTIES_MESSAGE; - mei_host_client_enumerate(dev); + /* first property reqeust */ + mei_hbm_prop_req(dev); } else { dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n"); mei_reset(dev, 1); @@ -423,7 +431,7 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) case CLIENT_DISCONNECT_REQ_CMD: /* search for client */ disconnect_req = (struct hbm_client_connect_request *)mei_msg; - mei_client_disconnect_request(dev, disconnect_req); + mei_hbm_fw_disconnect_req(dev, disconnect_req); break; case ME_STOP_REQ_CMD: diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 0536170ff856..418a85f315f1 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -529,9 +529,9 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) cb->fop_type = MEI_FOP_CLOSE; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; - if (mei_disconnect(dev, cl)) { + if (mei_hbm_cl_disconnect_req(dev, cl)) { rets = -ENODEV; - dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n"); + dev_err(&dev->pdev->dev, "failed to disconnect.\n"); goto free; } mdelay(10); /* Wait for hardware disconnection ready */ diff --git a/drivers/misc/mei/interface.h b/drivers/misc/mei/interface.h index ca732990a7eb..90a3dfda9db5 100644 --- a/drivers/misc/mei/interface.h +++ b/drivers/misc/mei/interface.h @@ -69,12 +69,15 @@ void mei_watchdog_register(struct mei_device *dev); */ void mei_watchdog_unregister(struct mei_device *dev); +int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl); int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl); -int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl); +void mei_hbm_start_req(struct mei_device *dev); -int mei_disconnect(struct mei_device *dev, struct mei_cl *cl); -int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl); -int mei_connect(struct mei_device *dev, struct mei_cl *cl); +int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); +int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl); +int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl); + +void mei_host_client_init(struct work_struct *work); #endif /* _MEI_INTERFACE_H_ */ diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 9cbf148e02e0..eb744cc4f72a 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -157,7 +157,7 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); - if (mei_disconnect(dev, cl)) { + if (mei_hbm_cl_disconnect_req(dev, cl)) { cl->status = 0; cb_pos->buf_idx = 0; list_move_tail(&cb_pos->list, &cmpl_list->list); @@ -407,7 +407,7 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); - if (mei_send_flow_control(dev, cl)) { + if (mei_hbm_cl_flow_control_req(dev, cl)) { cl->status = -ENODEV; cb_pos->buf_idx = 0; list_move_tail(&cb_pos->list, &cmpl_list->list); @@ -443,8 +443,8 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, } cl->state = MEI_FILE_CONNECTING; - *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); - if (mei_connect(dev, cl)) { + *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); + if (mei_hbm_cl_connect_req(dev, cl)) { cl->status = -ENODEV; cb_pos->buf_idx = 0; list_del(&cb_pos->list); @@ -927,7 +927,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) /* link is established * start sending messages. */ - mei_host_start_message(dev); + mei_hbm_start_req(dev); mutex_unlock(&dev->device_lock); return IRQ_HANDLED; } else { diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index 7ccc3d8a079e..d8e08bcf3263 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -258,7 +258,7 @@ int mei_ioctl_connect_client(struct file *file, && !mei_other_client_is_connecting(dev, cl)) { dev_dbg(&dev->pdev->dev, "Sending Connect Message\n"); dev->mei_host_buffer_is_empty = false; - if (mei_connect(dev, cl)) { + if (mei_hbm_cl_connect_req(dev, cl)) { dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n"); rets = -ENODEV; goto end; @@ -350,7 +350,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) cl->read_cb = cb; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; - if (mei_send_flow_control(dev, cl)) { + if (mei_hbm_cl_flow_control_req(dev, cl)) { rets = -ENODEV; goto err; } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 1ea331ac2463..0ad32cc49c06 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -383,15 +383,6 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1, } - -/* - * 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_enumerate(struct mei_device *dev); -void mei_host_client_init(struct work_struct *work); - /* * MEI interrupt functions prototype */ diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index 3997a630847f..4f2e9db86478 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -79,7 +79,7 @@ int mei_wd_host_init(struct mei_device *dev) return -ENOENT; } - if (mei_connect(dev, &dev->wd_cl)) { + if (mei_hbm_cl_connect_req(dev, &dev->wd_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; -- cgit v1.2.3 From 0edb23fc3451c84350edcc999c023d225a49530d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 8 Jan 2013 23:07:12 +0200 Subject: mei: add new hbm.h header to export hbm protocol hbm.h provides access host bus messaging functionality for other MEI layers Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 1 + drivers/misc/mei/hbm.c | 1 + drivers/misc/mei/hbm.h | 39 +++++++++++++++++++++++++++++++++++++++ drivers/misc/mei/init.c | 1 + drivers/misc/mei/interface.h | 7 ++----- drivers/misc/mei/interrupt.c | 1 + drivers/misc/mei/iorw.c | 1 + drivers/misc/mei/mei_dev.h | 10 ---------- drivers/misc/mei/wd.c | 1 + 9 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 drivers/misc/mei/hbm.h (limited to 'drivers/misc/mei/iorw.c') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 6e3cd31eae3b..add4254eb850 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -34,6 +34,7 @@ #include #include "mei_dev.h" +#include "hbm.h" #include "interface.h" const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 6b58b0a10378..9956aaf58aa4 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -20,6 +20,7 @@ #include #include "mei_dev.h" +#include "hbm.h" #include "interface.h" /** diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h new file mode 100644 index 000000000000..b552afbaf85c --- /dev/null +++ b/drivers/misc/mei/hbm.h @@ -0,0 +1,39 @@ +/* + * + * 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_HBM_H_ +#define _MEI_HBM_H_ + +void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr); + +static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) +{ + hdr->host_addr = 0; + hdr->me_addr = 0; + hdr->length = length; + hdr->msg_complete = 1; + hdr->reserved = 0; +} + +void mei_hbm_start_req(struct mei_device *dev); + +int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); +int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl); +int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl); + + +#endif /* _MEI_HBM_H_ */ + diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 418a85f315f1..55895fc21ff1 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -22,6 +22,7 @@ #include #include "mei_dev.h" +#include "hbm.h" #include "interface.h" const char *mei_dev_state_str(int state) diff --git a/drivers/misc/mei/interface.h b/drivers/misc/mei/interface.h index 90a3dfda9db5..3d06c087ddd2 100644 --- a/drivers/misc/mei/interface.h +++ b/drivers/misc/mei/interface.h @@ -72,12 +72,9 @@ void mei_watchdog_unregister(struct mei_device *dev); int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl); int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl); -void mei_hbm_start_req(struct mei_device *dev); +void mei_host_client_init(struct work_struct *work); + -int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); -int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl); -int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl); -void mei_host_client_init(struct work_struct *work); #endif /* _MEI_INTERFACE_H_ */ diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index a735c8b7ca82..2495e35ccb27 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -24,6 +24,7 @@ #include #include "mei_dev.h" +#include "hbm.h" #include "interface.h" diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index d8e08bcf3263..4328c2d2ca54 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -36,6 +36,7 @@ #include #include "mei_dev.h" +#include "hbm.h" #include "interface.h" /** diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 54ddac324578..1b54e675d3f1 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -445,16 +445,6 @@ void mei_enable_interrupts(struct mei_device *dev); void mei_disable_interrupts(struct mei_device *dev); -void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr); - -static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) -{ - hdr->host_addr = 0; - hdr->me_addr = 0; - hdr->length = length; - hdr->msg_complete = 1; - hdr->reserved = 0; -} #define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d comp=%1d" #define MEI_HDR_PRM(hdr) \ diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index 4f2e9db86478..9814bc1dba01 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -24,6 +24,7 @@ #include #include "mei_dev.h" +#include "hbm.h" #include "interface.h" static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 }; -- cgit v1.2.3 From 9ca9050b3df690d9d44e39424ab2a531120af936 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 8 Jan 2013 23:07:13 +0200 Subject: mei: move client functions to client.c This file now contains me and host client functions and also io callback helpers We also kill iorw.c which is no longer needed Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/Makefile | 2 +- drivers/misc/mei/client.c | 710 +++++++++++++++++++++++++++++++++++++++++++ drivers/misc/mei/init.c | 252 --------------- drivers/misc/mei/interface.c | 96 ------ drivers/misc/mei/iorw.c | 367 ---------------------- 5 files changed, 711 insertions(+), 716 deletions(-) create mode 100644 drivers/misc/mei/client.c delete mode 100644 drivers/misc/mei/iorw.c (limited to 'drivers/misc/mei/iorw.c') diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index 1f382a5ca3a6..67f543ab234f 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile @@ -7,7 +7,7 @@ mei-objs := init.o mei-objs += hbm.o mei-objs += interrupt.o mei-objs += interface.o -mei-objs += iorw.o mei-objs += main.o mei-objs += amthif.o mei-objs += wd.o +mei-objs += client.o diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c new file mode 100644 index 000000000000..19f62073fa67 --- /dev/null +++ b/drivers/misc/mei/client.c @@ -0,0 +1,710 @@ +/* + * + * 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. + * + */ + +#include +#include +#include +#include + +#include + +#include "mei_dev.h" +#include "hbm.h" +#include "interface.h" + + +/** + * mei_io_list_flush - removes list entry belonging to cl. + * + * @list: An instance of our list structure + * @cl: host client + */ +void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) +{ + struct mei_cl_cb *cb; + struct mei_cl_cb *next; + + list_for_each_entry_safe(cb, next, &list->list, list) { + if (cb->cl && mei_cl_cmp_id(cl, cb->cl)) + list_del(&cb->list); + } +} + +/** + * mei_io_cb_free - free mei_cb_private related memory + * + * @cb: mei callback struct + */ +void mei_io_cb_free(struct mei_cl_cb *cb) +{ + if (cb == NULL) + return; + + kfree(cb->request_buffer.data); + kfree(cb->response_buffer.data); + kfree(cb); +} + +/** + * mei_io_cb_init - allocate and initialize io callback + * + * @cl - mei client + * @file: pointer to file structure + * + * returns mei_cl_cb pointer or NULL; + */ +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) +{ + struct mei_cl_cb *cb; + + cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + if (!cb) + return NULL; + + mei_io_list_init(cb); + + cb->file_object = fp; + cb->cl = cl; + cb->buf_idx = 0; + return cb; +} + +/** + * mei_io_cb_alloc_req_buf - allocate request buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->request_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->request_buffer.data) + return -ENOMEM; + cb->request_buffer.size = length; + return 0; +} +/** + * mei_io_cb_alloc_req_buf - allocate respose buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->response_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->response_buffer.data) + return -ENOMEM; + cb->response_buffer.size = length; + return 0; +} + + + +/** + * mei_cl_flush_queues - flushes queue lists belonging to cl. + * + * @dev: the device structure + * @cl: host client + */ +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->amthif_cmd_list, cl); + mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); + return 0; +} + +/** + * mei_me_cl_by_uuid - locate index of me client + * + * @dev: mei device + * returns me client index or -ENOENT if not found + */ +int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid) +{ + int i, res = -ENOENT; + + for (i = 0; i < dev->me_clients_num; ++i) + if (uuid_le_cmp(*uuid, + dev->me_clients[i].props.protocol_name) == 0) { + res = i; + break; + } + + return res; +} + + +/** + * mei_me_cl_by_id return index to me_clients for client_id + * + * @dev: the device structure + * @client_id: me client id + * + * Locking: called under "dev->device_lock" lock + * + * returns index on success, -ENOENT on failure. + */ + +int mei_me_cl_by_id(struct mei_device *dev, u8 client_id) +{ + int i; + for (i = 0; i < dev->me_clients_num; i++) + if (dev->me_clients[i].client_id == client_id) + break; + if (WARN_ON(dev->me_clients[i].client_id != client_id)) + return -ENOENT; + + if (i == dev->me_clients_num) + return -ENOENT; + + return i; +} + +/** + * mei_cl_init - initializes intialize cl. + * + * @cl: host client to be initialized + * @dev: mei device + */ +void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) +{ + memset(cl, 0, sizeof(struct mei_cl)); + init_waitqueue_head(&cl->wait); + init_waitqueue_head(&cl->rx_wait); + init_waitqueue_head(&cl->tx_wait); + INIT_LIST_HEAD(&cl->link); + cl->reading_state = MEI_IDLE; + cl->writing_state = MEI_IDLE; + cl->dev = dev; +} + +/** + * mei_cl_allocate - allocates cl structure and sets it up. + * + * @dev: mei device + * returns The allocated file or NULL on failure + */ +struct mei_cl *mei_cl_allocate(struct mei_device *dev) +{ + struct mei_cl *cl; + + cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); + if (!cl) + return NULL; + + mei_cl_init(cl, dev); + + return cl; +} + + +/** + * mei_me_cl_link - create link between host and me clinet and add + * me_cl to the list + * + * @dev: the device structure + * @cl: link between me and host client assocated with opened file descriptor + * @uuid: uuid of ME client + * @client_id: id of the host client + * + * returns ME client index if ME client + * -EINVAL on incorrect values + * -ENONET if client not found + */ +int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, + const uuid_le *uuid, u8 host_cl_id) +{ + int i; + + if (!dev || !cl || !uuid) + return -EINVAL; + + /* 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; + + list_add_tail(&cl->link, &dev->file_list); + return (u8)i; + } + + return -ENOENT; +} +/** + * mei_me_cl_unlink - remove me_cl from the list + * + * @dev: the device structure + * @host_client_id: host client id to be removed + */ +void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl) +{ + struct mei_cl *pos, *next; + list_for_each_entry_safe(pos, next, &dev->file_list, link) { + if (cl->host_client_id == pos->host_client_id) { + dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", + pos->host_client_id, pos->me_client_id); + list_del_init(&pos->link); + break; + } + } +} + + +void mei_host_client_init(struct work_struct *work) +{ + struct mei_device *dev = container_of(work, + struct mei_device, init_work); + struct mei_client_properties *client_props; + int i; + + mutex_lock(&dev->device_lock); + + bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); + dev->open_handle_count = 0; + + /* + * Reserving the first three client IDs + * 0: Reserved for MEI Bus Message communications + * 1: Reserved for Watchdog + * 2: Reserved for AMTHI + */ + bitmap_set(dev->host_clients_map, 0, 3); + + for (i = 0; i < dev->me_clients_num; i++) { + client_props = &dev->me_clients[i].props; + + if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) + mei_amthif_host_init(dev); + else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) + mei_wd_host_init(dev); + } + + dev->dev_state = MEI_DEV_ENABLED; + + mutex_unlock(&dev->device_lock); +} + + +/** + * mei_disconnect_host_client - sends disconnect message to fw from host client. + * + * @dev: the device structure + * @cl: private data of the file object + * + * Locking: called under "dev->device_lock" lock + * + * returns 0 on success, <0 on failure. + */ +int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) +{ + struct mei_cl_cb *cb; + int rets, err; + + if (!dev || !cl) + return -ENODEV; + + if (cl->state != MEI_FILE_DISCONNECTING) + return 0; + + cb = mei_io_cb_init(cl, NULL); + if (!cb) + return -ENOMEM; + + cb->fop_type = MEI_FOP_CLOSE; + if (dev->mei_host_buffer_is_empty) { + dev->mei_host_buffer_is_empty = false; + if (mei_hbm_cl_disconnect_req(dev, cl)) { + rets = -ENODEV; + dev_err(&dev->pdev->dev, "failed to disconnect.\n"); + goto free; + } + mdelay(10); /* Wait for hardware disconnection ready */ + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); + } else { + dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + + } + mutex_unlock(&dev->device_lock); + + err = wait_event_timeout(dev->wait_recvd_msg, + MEI_FILE_DISCONNECTED == cl->state, + mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); + + mutex_lock(&dev->device_lock); + if (MEI_FILE_DISCONNECTED == cl->state) { + rets = 0; + dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); + } else { + rets = -ENODEV; + if (MEI_FILE_DISCONNECTED != cl->state) + dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); + + if (err) + dev_dbg(&dev->pdev->dev, + "wait failed disconnect err=%08x\n", + err); + + dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); + } + + mei_io_list_flush(&dev->ctrl_rd_list, cl); + mei_io_list_flush(&dev->ctrl_wr_list, cl); +free: + mei_io_cb_free(cb); + return rets; +} + + +/** + * mei_other_client_is_connecting - checks if other + * client with the same client id is connected. + * + * @dev: the device structure + * @cl: private data of the file object + * + * returns 1 if other client is connected, 0 - otherwise. + */ +int mei_other_client_is_connecting(struct mei_device *dev, + struct mei_cl *cl) +{ + struct mei_cl *cl_pos = NULL; + struct mei_cl *cl_next = NULL; + + list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { + if ((cl_pos->state == MEI_FILE_CONNECTING) && + (cl_pos != cl) && + cl->me_client_id == cl_pos->me_client_id) + return 1; + + } + return 0; +} + +/** + * mei_flow_ctrl_creds - checks flow_control credentials. + * + * @dev: the device structure + * @cl: private data of the file object + * + * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise. + * -ENOENT if mei_cl is not present + * -EINVAL if single_recv_buf == 0 + */ +int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl) +{ + int i; + + if (!dev->me_clients_num) + return 0; + + if (cl->mei_flow_ctrl_creds > 0) + return 1; + + 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) { + if (WARN_ON(me_cl->props.single_recv_buf == 0)) + return -EINVAL; + return 1; + } else { + return 0; + } + } + } + return -ENOENT; +} + +/** + * mei_flow_ctrl_reduce - reduces flow_control. + * + * @dev: the device structure + * @cl: private data of the file object + * @returns + * 0 on success + * -ENOENT when me client is not found + * -EINVAL when ctrl credits are <= 0 + */ +int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl) +{ + int i; + + if (!dev->me_clients_num) + return -ENOENT; + + 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) { + if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) + return -EINVAL; + dev->me_clients[i].mei_flow_ctrl_creds--; + } else { + if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) + return -EINVAL; + cl->mei_flow_ctrl_creds--; + } + return 0; + } + } + return -ENOENT; +} + + + +/** + * mei_ioctl_connect_client - the connect to fw client IOCTL function + * + * @dev: the device structure + * @data: IOCTL connect data, input and output parameters + * @file: private data of the file object + * + * Locking: called under "dev->device_lock" lock + * + * returns 0 on success, <0 on failure. + */ +int mei_ioctl_connect_client(struct file *file, + struct mei_connect_client_data *data) +{ + struct mei_device *dev; + struct mei_cl_cb *cb; + struct mei_client *client; + struct mei_cl *cl; + long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); + int i; + int err; + int rets; + + cl = file->private_data; + if (WARN_ON(!cl || !cl->dev)) + return -ENODEV; + + dev = cl->dev; + + dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); + + /* buffered ioctl cb */ + cb = mei_io_cb_init(cl, file); + if (!cb) { + rets = -ENOMEM; + goto end; + } + + cb->fop_type = MEI_FOP_IOCTL; + + if (dev->dev_state != MEI_DEV_ENABLED) { + rets = -ENODEV; + goto end; + } + if (cl->state != MEI_FILE_INITIALIZING && + cl->state != MEI_FILE_DISCONNECTED) { + rets = -EBUSY; + goto end; + } + + /* find ME client we're trying to connect to */ + i = mei_me_cl_by_uuid(dev, &data->in_client_uuid); + if (i >= 0 && !dev->me_clients[i].props.fixed_address) { + cl->me_client_id = dev->me_clients[i].client_id; + cl->state = MEI_FILE_CONNECTING; + } + + dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", + cl->me_client_id); + dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n", + dev->me_clients[i].props.protocol_version); + dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n", + dev->me_clients[i].props.max_msg_length); + + /* if we're connecting to amthi client then we will use the + * existing connection + */ + if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) { + dev_dbg(&dev->pdev->dev, "FW Client is amthi\n"); + if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { + rets = -ENODEV; + goto end; + } + clear_bit(cl->host_client_id, dev->host_clients_map); + mei_me_cl_unlink(dev, cl); + + kfree(cl); + cl = NULL; + file->private_data = &dev->iamthif_cl; + + client = &data->out_client_properties; + client->max_msg_length = + dev->me_clients[i].props.max_msg_length; + client->protocol_version = + dev->me_clients[i].props.protocol_version; + rets = dev->iamthif_cl.status; + + goto end; + } + + if (cl->state != MEI_FILE_CONNECTING) { + rets = -ENODEV; + goto end; + } + + + /* prepare the output buffer */ + client = &data->out_client_properties; + client->max_msg_length = dev->me_clients[i].props.max_msg_length; + client->protocol_version = dev->me_clients[i].props.protocol_version; + dev_dbg(&dev->pdev->dev, "Can connect?\n"); + 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 = false; + if (mei_hbm_cl_connect_req(dev, cl)) { + dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n"); + rets = -ENODEV; + goto end; + } else { + dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); + cl->timer_count = MEI_CONNECT_TIMEOUT; + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); + } + + + } else { + dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); + dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + } + mutex_unlock(&dev->device_lock); + err = wait_event_timeout(dev->wait_recvd_msg, + (MEI_FILE_CONNECTED == cl->state || + MEI_FILE_DISCONNECTED == cl->state), timeout); + + mutex_lock(&dev->device_lock); + if (MEI_FILE_CONNECTED == cl->state) { + dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n"); + rets = cl->status; + goto end; + } else { + dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n", + cl->state); + if (!err) { + dev_dbg(&dev->pdev->dev, + "wait_event_interruptible_timeout failed on client" + " connect message fw response message.\n"); + } + rets = -EFAULT; + + mei_io_list_flush(&dev->ctrl_rd_list, cl); + mei_io_list_flush(&dev->ctrl_wr_list, cl); + goto end; + } + rets = 0; +end: + dev_dbg(&dev->pdev->dev, "free connect cb memory."); + mei_io_cb_free(cb); + return rets; +} + +/** + * mei_start_read - the start read client message function. + * + * @dev: the device structure + * @if_num: minor number + * @cl: private data of the file object + * + * returns 0 on success, <0 on failure. + */ +int mei_start_read(struct mei_device *dev, struct mei_cl *cl) +{ + struct mei_cl_cb *cb; + int rets; + int i; + + if (cl->state != MEI_FILE_CONNECTED) + return -ENODEV; + + if (dev->dev_state != MEI_DEV_ENABLED) + return -ENODEV; + + if (cl->read_pending || cl->read_cb) { + dev_dbg(&dev->pdev->dev, "read is pending.\n"); + return -EBUSY; + } + i = mei_me_cl_by_id(dev, cl->me_client_id); + if (i < 0) { + dev_err(&dev->pdev->dev, "no such me client %d\n", + cl->me_client_id); + return -ENODEV; + } + + cb = mei_io_cb_init(cl, NULL); + if (!cb) + return -ENOMEM; + + rets = mei_io_cb_alloc_resp_buf(cb, + dev->me_clients[i].props.max_msg_length); + if (rets) + goto err; + + cb->fop_type = MEI_FOP_READ; + cl->read_cb = cb; + if (dev->mei_host_buffer_is_empty) { + dev->mei_host_buffer_is_empty = false; + if (mei_hbm_cl_flow_control_req(dev, cl)) { + rets = -ENODEV; + goto err; + } + list_add_tail(&cb->list, &dev->read_list.list); + } else { + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + } + return rets; +err: + mei_io_cb_free(cb); + return rets; +} + diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 55895fc21ff1..6c1f1f838d2b 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -22,7 +22,6 @@ #include #include "mei_dev.h" -#include "hbm.h" #include "interface.h" const char *mei_dev_state_str(int state) @@ -45,47 +44,6 @@ const char *mei_dev_state_str(int state) -/** - * 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_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) -{ - struct mei_cl_cb *pos; - struct mei_cl_cb *next; - - list_for_each_entry_safe(pos, next, &list->list, list) { - if (pos->cl) { - if (mei_cl_cmp_id(cl, pos->cl)) - list_del(&pos->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->amthif_cmd_list, cl); - mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); - return 0; -} - - /** * init_mei_device - allocates and initializes the mei device structure @@ -360,215 +318,5 @@ void mei_allocate_me_clients_storage(struct mei_device *dev) return ; } -void mei_host_client_init(struct work_struct *work) -{ - struct mei_device *dev = container_of(work, - struct mei_device, init_work); - struct mei_client_properties *client_props; - int i; - - mutex_lock(&dev->device_lock); - - bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); - dev->open_handle_count = 0; - - /* - * Reserving the first three client IDs - * 0: Reserved for MEI Bus Message communications - * 1: Reserved for Watchdog - * 2: Reserved for AMTHI - */ - bitmap_set(dev->host_clients_map, 0, 3); - - for (i = 0; i < dev->me_clients_num; i++) { - client_props = &dev->me_clients[i].props; - - if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) - mei_amthif_host_init(dev); - else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) - mei_wd_host_init(dev); - } - dev->dev_state = MEI_DEV_ENABLED; - - mutex_unlock(&dev->device_lock); -} - - -/** - * mei_init_file_private - initializes private file structure. - * - * @priv: private file structure to be initialized - * @file: the file structure - */ -void mei_cl_init(struct mei_cl *priv, struct mei_device *dev) -{ - memset(priv, 0, sizeof(struct mei_cl)); - init_waitqueue_head(&priv->wait); - init_waitqueue_head(&priv->rx_wait); - init_waitqueue_head(&priv->tx_wait); - INIT_LIST_HEAD(&priv->link); - priv->reading_state = MEI_IDLE; - priv->writing_state = MEI_IDLE; - priv->dev = dev; -} - -int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid) -{ - int i, res = -ENOENT; - - for (i = 0; i < dev->me_clients_num; ++i) - if (uuid_le_cmp(*cuuid, - dev->me_clients[i].props.protocol_name) == 0) { - res = i; - break; - } - - return res; -} - - -/** - * mei_me_cl_link - create link between host and me clinet and add - * me_cl to the list - * - * @dev: the device structure - * @cl: link between me and host client assocated with opened file descriptor - * @cuuid: uuid of ME client - * @client_id: id of the host client - * - * returns ME client index if ME client - * -EINVAL on incorrect values - * -ENONET if client not found - */ -int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, - const uuid_le *cuuid, u8 host_cl_id) -{ - int i; - - if (!dev || !cl || !cuuid) - return -EINVAL; - - /* check for valid client id */ - i = mei_me_cl_by_uuid(dev, cuuid); - 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; - - list_add_tail(&cl->link, &dev->file_list); - return (u8)i; - } - - return -ENOENT; -} -/** - * mei_me_cl_unlink - remove me_cl from the list - * - * @dev: the device structure - * @host_client_id: host client id to be removed - */ -void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl) -{ - struct mei_cl *pos, *next; - list_for_each_entry_safe(pos, next, &dev->file_list, link) { - if (cl->host_client_id == pos->host_client_id) { - dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", - pos->host_client_id, pos->me_client_id); - list_del_init(&pos->link); - break; - } - } -} - -/** - * mei_alloc_file_private - allocates a private file structure and sets it up. - * @file: the file structure - * - * returns The allocated file or NULL on failure - */ -struct mei_cl *mei_cl_allocate(struct mei_device *dev) -{ - struct mei_cl *cl; - - cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); - if (!cl) - return NULL; - - mei_cl_init(cl, dev); - - return cl; -} - - - -/** - * mei_disconnect_host_client - sends disconnect message to fw from host client. - * - * @dev: the device structure - * @cl: private data of the file object - * - * Locking: called under "dev->device_lock" lock - * - * returns 0 on success, <0 on failure. - */ -int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) -{ - struct mei_cl_cb *cb; - int rets, err; - - if (!dev || !cl) - return -ENODEV; - - if (cl->state != MEI_FILE_DISCONNECTING) - return 0; - - cb = mei_io_cb_init(cl, NULL); - if (!cb) - return -ENOMEM; - - cb->fop_type = MEI_FOP_CLOSE; - if (dev->mei_host_buffer_is_empty) { - dev->mei_host_buffer_is_empty = false; - if (mei_hbm_cl_disconnect_req(dev, cl)) { - rets = -ENODEV; - dev_err(&dev->pdev->dev, "failed to disconnect.\n"); - goto free; - } - mdelay(10); /* Wait for hardware disconnection ready */ - list_add_tail(&cb->list, &dev->ctrl_rd_list.list); - } else { - dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); - list_add_tail(&cb->list, &dev->ctrl_wr_list.list); - - } - mutex_unlock(&dev->device_lock); - - err = wait_event_timeout(dev->wait_recvd_msg, - MEI_FILE_DISCONNECTED == cl->state, - mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); - - mutex_lock(&dev->device_lock); - if (MEI_FILE_DISCONNECTED == cl->state) { - rets = 0; - dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); - } else { - rets = -ENODEV; - if (MEI_FILE_DISCONNECTED != cl->state) - dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); - - if (err) - dev_dbg(&dev->pdev->dev, - "wait failed disconnect err=%08x\n", - err); - - dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); - } - - mei_io_list_flush(&dev->ctrl_rd_list, cl); - mei_io_list_flush(&dev->ctrl_wr_list, cl); -free: - mei_io_cb_free(cb); - return rets; -} diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c index 155bd7efe4e5..3cb0cff01285 100644 --- a/drivers/misc/mei/interface.c +++ b/drivers/misc/mei/interface.c @@ -297,99 +297,3 @@ void mei_read_slots(struct mei_device *dev, unsigned char *buffer, mei_hcsr_set(dev); } -/** - * mei_flow_ctrl_creds - checks flow_control credentials. - * - * @dev: the device structure - * @cl: private data of the file object - * - * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise. - * -ENOENT if mei_cl is not present - * -EINVAL if single_recv_buf == 0 - */ -int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl) -{ - int i; - - if (!dev->me_clients_num) - return 0; - - if (cl->mei_flow_ctrl_creds > 0) - return 1; - - 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) { - if (WARN_ON(me_cl->props.single_recv_buf == 0)) - return -EINVAL; - return 1; - } else { - return 0; - } - } - } - return -ENOENT; -} - -/** - * mei_flow_ctrl_reduce - reduces flow_control. - * - * @dev: the device structure - * @cl: private data of the file object - * @returns - * 0 on success - * -ENOENT when me client is not found - * -EINVAL when ctrl credits are <= 0 - */ -int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl) -{ - int i; - - if (!dev->me_clients_num) - return -ENOENT; - - 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) { - if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) - return -EINVAL; - dev->me_clients[i].mei_flow_ctrl_creds--; - } else { - if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) - return -EINVAL; - cl->mei_flow_ctrl_creds--; - } - return 0; - } - } - return -ENOENT; -} - - -/** - * mei_other_client_is_connecting - checks if other - * client with the same client id is connected. - * - * @dev: the device structure - * @cl: private data of the file object - * - * returns 1 if other client is connected, 0 - otherwise. - */ -int mei_other_client_is_connecting(struct mei_device *dev, - struct mei_cl *cl) -{ - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if ((cl_pos->state == MEI_FILE_CONNECTING) && - (cl_pos != cl) && - cl->me_client_id == cl_pos->me_client_id) - return 1; - - } - return 0; -} - diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c deleted file mode 100644 index 4328c2d2ca54..000000000000 --- a/drivers/misc/mei/iorw.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * - * 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. - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include - -#include "mei_dev.h" -#include "hbm.h" -#include "interface.h" - -/** - * mei_io_cb_free - free mei_cb_private related memory - * - * @cb: mei callback struct - */ -void mei_io_cb_free(struct mei_cl_cb *cb) -{ - if (cb == NULL) - return; - - kfree(cb->request_buffer.data); - kfree(cb->response_buffer.data); - kfree(cb); -} -/** - * mei_io_cb_init - allocate and initialize io callback - * - * @cl - mei client - * @file: pointer to file structure - * - * returns mei_cl_cb pointer or NULL; - */ -struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) -{ - struct mei_cl_cb *cb; - - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); - if (!cb) - return NULL; - - mei_io_list_init(cb); - - cb->file_object = fp; - cb->cl = cl; - cb->buf_idx = 0; - return cb; -} - - -/** - * mei_io_cb_alloc_req_buf - allocate request buffer - * - * @cb - io callback structure - * @size: size of the buffer - * - * returns 0 on success - * -EINVAL if cb is NULL - * -ENOMEM if allocation failed - */ -int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) -{ - if (!cb) - return -EINVAL; - - if (length == 0) - return 0; - - cb->request_buffer.data = kmalloc(length, GFP_KERNEL); - if (!cb->request_buffer.data) - return -ENOMEM; - cb->request_buffer.size = length; - return 0; -} -/** - * mei_io_cb_alloc_req_buf - allocate respose buffer - * - * @cb - io callback structure - * @size: size of the buffer - * - * returns 0 on success - * -EINVAL if cb is NULL - * -ENOMEM if allocation failed - */ -int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) -{ - if (!cb) - return -EINVAL; - - if (length == 0) - return 0; - - cb->response_buffer.data = kmalloc(length, GFP_KERNEL); - if (!cb->response_buffer.data) - return -ENOMEM; - cb->response_buffer.size = length; - return 0; -} - - -/** - * mei_me_cl_by_id return index to me_clients for client_id - * - * @dev: the device structure - * @client_id: me client id - * - * Locking: called under "dev->device_lock" lock - * - * returns index on success, -ENOENT on failure. - */ - -int mei_me_cl_by_id(struct mei_device *dev, u8 client_id) -{ - int i; - for (i = 0; i < dev->me_clients_num; i++) - if (dev->me_clients[i].client_id == client_id) - break; - if (WARN_ON(dev->me_clients[i].client_id != client_id)) - return -ENOENT; - - if (i == dev->me_clients_num) - return -ENOENT; - - return i; -} - -/** - * mei_ioctl_connect_client - the connect to fw client IOCTL function - * - * @dev: the device structure - * @data: IOCTL connect data, input and output parameters - * @file: private data of the file object - * - * Locking: called under "dev->device_lock" lock - * - * returns 0 on success, <0 on failure. - */ -int mei_ioctl_connect_client(struct file *file, - struct mei_connect_client_data *data) -{ - struct mei_device *dev; - struct mei_cl_cb *cb; - struct mei_client *client; - struct mei_cl *cl; - long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); - int i; - int err; - int rets; - - cl = file->private_data; - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); - - /* buffered ioctl cb */ - cb = mei_io_cb_init(cl, file); - if (!cb) { - rets = -ENOMEM; - goto end; - } - - cb->fop_type = MEI_FOP_IOCTL; - - if (dev->dev_state != MEI_DEV_ENABLED) { - rets = -ENODEV; - goto end; - } - if (cl->state != MEI_FILE_INITIALIZING && - cl->state != MEI_FILE_DISCONNECTED) { - rets = -EBUSY; - goto end; - } - - /* find ME client we're trying to connect to */ - i = mei_me_cl_by_uuid(dev, &data->in_client_uuid); - if (i >= 0 && !dev->me_clients[i].props.fixed_address) { - cl->me_client_id = dev->me_clients[i].client_id; - cl->state = MEI_FILE_CONNECTING; - } - - dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", - cl->me_client_id); - dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n", - dev->me_clients[i].props.protocol_version); - dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n", - dev->me_clients[i].props.max_msg_length); - - /* if we're connecting to amthi client then we will use the - * existing connection - */ - if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) { - dev_dbg(&dev->pdev->dev, "FW Client is amthi\n"); - if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - goto end; - } - clear_bit(cl->host_client_id, dev->host_clients_map); - mei_me_cl_unlink(dev, cl); - - kfree(cl); - cl = NULL; - file->private_data = &dev->iamthif_cl; - - client = &data->out_client_properties; - client->max_msg_length = - dev->me_clients[i].props.max_msg_length; - client->protocol_version = - dev->me_clients[i].props.protocol_version; - rets = dev->iamthif_cl.status; - - goto end; - } - - if (cl->state != MEI_FILE_CONNECTING) { - rets = -ENODEV; - goto end; - } - - - /* prepare the output buffer */ - client = &data->out_client_properties; - client->max_msg_length = dev->me_clients[i].props.max_msg_length; - client->protocol_version = dev->me_clients[i].props.protocol_version; - dev_dbg(&dev->pdev->dev, "Can connect?\n"); - 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 = false; - if (mei_hbm_cl_connect_req(dev, cl)) { - dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n"); - rets = -ENODEV; - goto end; - } else { - dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); - cl->timer_count = MEI_CONNECT_TIMEOUT; - list_add_tail(&cb->list, &dev->ctrl_rd_list.list); - } - - - } else { - dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); - dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); - list_add_tail(&cb->list, &dev->ctrl_wr_list.list); - } - mutex_unlock(&dev->device_lock); - err = wait_event_timeout(dev->wait_recvd_msg, - (MEI_FILE_CONNECTED == cl->state || - MEI_FILE_DISCONNECTED == cl->state), timeout); - - mutex_lock(&dev->device_lock); - if (MEI_FILE_CONNECTED == cl->state) { - dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n"); - rets = cl->status; - goto end; - } else { - dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n", - cl->state); - if (!err) { - dev_dbg(&dev->pdev->dev, - "wait_event_interruptible_timeout failed on client" - " connect message fw response message.\n"); - } - rets = -EFAULT; - - mei_io_list_flush(&dev->ctrl_rd_list, cl); - mei_io_list_flush(&dev->ctrl_wr_list, cl); - goto end; - } - rets = 0; -end: - dev_dbg(&dev->pdev->dev, "free connect cb memory."); - mei_io_cb_free(cb); - return rets; -} - -/** - * mei_start_read - the start read client message function. - * - * @dev: the device structure - * @if_num: minor number - * @cl: private data of the file object - * - * returns 0 on success, <0 on failure. - */ -int mei_start_read(struct mei_device *dev, struct mei_cl *cl) -{ - struct mei_cl_cb *cb; - int rets; - int i; - - if (cl->state != MEI_FILE_CONNECTED) - return -ENODEV; - - if (dev->dev_state != MEI_DEV_ENABLED) - return -ENODEV; - - if (cl->read_pending || cl->read_cb) { - dev_dbg(&dev->pdev->dev, "read is pending.\n"); - return -EBUSY; - } - i = mei_me_cl_by_id(dev, cl->me_client_id); - if (i < 0) { - dev_err(&dev->pdev->dev, "no such me client %d\n", - cl->me_client_id); - return -ENODEV; - } - - cb = mei_io_cb_init(cl, NULL); - if (!cb) - return -ENOMEM; - - rets = mei_io_cb_alloc_resp_buf(cb, - dev->me_clients[i].props.max_msg_length); - if (rets) - goto err; - - cb->fop_type = MEI_FOP_READ; - cl->read_cb = cb; - if (dev->mei_host_buffer_is_empty) { - dev->mei_host_buffer_is_empty = false; - if (mei_hbm_cl_flow_control_req(dev, cl)) { - rets = -ENODEV; - goto err; - } - list_add_tail(&cb->list, &dev->read_list.list); - } else { - list_add_tail(&cb->list, &dev->ctrl_wr_list.list); - } - return rets; -err: - mei_io_cb_free(cb); - return rets; -} - -- cgit v1.2.3