aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2012-12-25 12:06:07 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-07 13:31:29 -0500
commitbb1b0133b3780987c2c74f267e294d016f9fa04c (patch)
treea13c23f34c8d2bb65b79d48cbfb7b4a404e3e85b /drivers/misc
parent3a65dd4ea32c3e3a3befec58ad20d1c96580834e (diff)
mei: move host bus message handling to hbm.c
for sake of more layered design we move host bus message handling to the new hbm.c file Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/mei/Makefile1
-rw-r--r--drivers/misc/mei/hbm.c440
-rw-r--r--drivers/misc/mei/init.c111
-rw-r--r--drivers/misc/mei/interface.c78
-rw-r--r--drivers/misc/mei/interrupt.c235
-rw-r--r--drivers/misc/mei/mei_dev.h10
6 files changed, 456 insertions, 419 deletions
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 0017842e166c..1f382a5ca3a6 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -4,6 +4,7 @@
4# 4#
5obj-$(CONFIG_INTEL_MEI) += mei.o 5obj-$(CONFIG_INTEL_MEI) += mei.o
6mei-objs := init.o 6mei-objs := init.o
7mei-objs += hbm.o
7mei-objs += interrupt.o 8mei-objs += interrupt.o
8mei-objs += interface.o 9mei-objs += interface.o
9mei-objs += iorw.o 10mei-objs += iorw.o
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
new file mode 100644
index 000000000000..2c4c1bb6d36a
--- /dev/null
+++ b/drivers/misc/mei/hbm.c
@@ -0,0 +1,440 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2012, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17#include <linux/pci.h>
18#include <linux/sched.h>
19#include <linux/wait.h>
20#include <linux/mei.h>
21
22#include "mei_dev.h"
23#include "interface.h"
24
25/**
26 * host_start_message - mei host sends start message.
27 *
28 * @dev: the device structure
29 *
30 * returns none.
31 */
32void mei_host_start_message(struct mei_device *dev)
33{
34 struct mei_msg_hdr *mei_hdr;
35 struct hbm_host_version_request *start_req;
36 const size_t len = sizeof(struct hbm_host_version_request);
37
38 mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
39
40 /* host start message */
41 start_req = (struct hbm_host_version_request *)&dev->wr_msg_buf[1];
42 memset(start_req, 0, len);
43 start_req->hbm_cmd = HOST_START_REQ_CMD;
44 start_req->host_version.major_version = HBM_MAJOR_VERSION;
45 start_req->host_version.minor_version = HBM_MINOR_VERSION;
46
47 dev->recvd_msg = false;
48 if (mei_write_message(dev, mei_hdr, (unsigned char *)start_req)) {
49 dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
50 dev->dev_state = MEI_DEV_RESETING;
51 mei_reset(dev, 1);
52 }
53 dev->init_clients_state = MEI_START_MESSAGE;
54 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
55 return ;
56}
57
58/**
59 * host_enum_clients_message - host sends enumeration client request message.
60 *
61 * @dev: the device structure
62 *
63 * returns none.
64 */
65void mei_host_enum_clients_message(struct mei_device *dev)
66{
67 struct mei_msg_hdr *mei_hdr;
68 struct hbm_host_enum_request *enum_req;
69 const size_t len = sizeof(struct hbm_host_enum_request);
70 /* enumerate clients */
71 mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
72
73 enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
74 memset(enum_req, 0, sizeof(struct hbm_host_enum_request));
75 enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
76
77 if (mei_write_message(dev, mei_hdr, (unsigned char *)enum_req)) {
78 dev->dev_state = MEI_DEV_RESETING;
79 dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
80 mei_reset(dev, 1);
81 }
82 dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
83 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
84 return;
85}
86
87
88int mei_host_client_enumerate(struct mei_device *dev)
89{
90
91 struct mei_msg_hdr *mei_hdr;
92 struct hbm_props_request *prop_req;
93 const size_t len = sizeof(struct hbm_props_request);
94 unsigned long next_client_index;
95 u8 client_num;
96
97
98 client_num = dev->me_client_presentation_num;
99
100 next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
101 dev->me_client_index);
102
103 /* We got all client properties */
104 if (next_client_index == MEI_CLIENTS_MAX) {
105 schedule_work(&dev->init_work);
106
107 return 0;
108 }
109
110 dev->me_clients[client_num].client_id = next_client_index;
111 dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
112
113 mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
114 prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1];
115
116 memset(prop_req, 0, sizeof(struct hbm_props_request));
117
118
119 prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
120 prop_req->address = next_client_index;
121
122 if (mei_write_message(dev, mei_hdr, (unsigned char *) prop_req)) {
123 dev->dev_state = MEI_DEV_RESETING;
124 dev_err(&dev->pdev->dev, "Properties request command failed\n");
125 mei_reset(dev, 1);
126
127 return -EIO;
128 }
129
130 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
131 dev->me_client_index = next_client_index;
132
133 return 0;
134}
135
136/**
137 * mei_send_flow_control - sends flow control to fw.
138 *
139 * @dev: the device structure
140 * @cl: private data of the file object
141 *
142 * This function returns -EIO on write failure
143 */
144int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
145{
146 struct mei_msg_hdr *mei_hdr;
147 struct hbm_flow_control *flow_ctrl;
148 const size_t len = sizeof(struct hbm_flow_control);
149
150 mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
151
152 flow_ctrl = (struct hbm_flow_control *)&dev->wr_msg_buf[1];
153 memset(flow_ctrl, 0, len);
154 flow_ctrl->hbm_cmd = MEI_FLOW_CONTROL_CMD;
155 flow_ctrl->host_addr = cl->host_client_id;
156 flow_ctrl->me_addr = cl->me_client_id;
157 /* FIXME: reserved !? */
158 memset(flow_ctrl->reserved, 0, sizeof(flow_ctrl->reserved));
159 dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
160 cl->host_client_id, cl->me_client_id);
161
162 return mei_write_message(dev, mei_hdr, (unsigned char *) flow_ctrl);
163}
164
165/**
166 * mei_disconnect - sends disconnect message to fw.
167 *
168 * @dev: the device structure
169 * @cl: private data of the file object
170 *
171 * This function returns -EIO on write failure
172 */
173int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
174{
175 struct mei_msg_hdr *hdr;
176 struct hbm_client_connect_request *req;
177 const size_t len = sizeof(struct hbm_client_connect_request);
178
179 hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
180
181 req = (struct hbm_client_connect_request *)&dev->wr_msg_buf[1];
182 memset(req, 0, len);
183 req->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD;
184 req->host_addr = cl->host_client_id;
185 req->me_addr = cl->me_client_id;
186 req->reserved = 0;
187
188 return mei_write_message(dev, hdr, (unsigned char *)req);
189}
190
191/**
192 * mei_connect - sends connect message to fw.
193 *
194 * @dev: the device structure
195 * @cl: private data of the file object
196 *
197 * This function returns -EIO on write failure
198 */
199int mei_connect(struct mei_device *dev, struct mei_cl *cl)
200{
201 struct mei_msg_hdr *hdr;
202 struct hbm_client_connect_request *req;
203 const size_t len = sizeof(struct hbm_client_connect_request);
204
205 hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
206
207 req = (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
208 req->hbm_cmd = CLIENT_CONNECT_REQ_CMD;
209 req->host_addr = cl->host_client_id;
210 req->me_addr = cl->me_client_id;
211 req->reserved = 0;
212
213 return mei_write_message(dev, hdr, (unsigned char *) req);
214}
215
216/**
217 * same_disconn_addr - tells if they have the same address
218 *
219 * @file: private data of the file object.
220 * @disconn: disconnection request.
221 *
222 * returns !=0, same; 0,not.
223 */
224static int same_disconn_addr(struct mei_cl *cl,
225 struct hbm_client_connect_request *req)
226{
227 return (cl->host_client_id == req->host_addr &&
228 cl->me_client_id == req->me_addr);
229}
230
231/**
232 * mei_client_disconnect_request - disconnects from request irq routine
233 *
234 * @dev: the device structure.
235 * @disconnect_req: disconnect request bus message.
236 */
237static void mei_client_disconnect_request(struct mei_device *dev,
238 struct hbm_client_connect_request *disconnect_req)
239{
240 struct hbm_client_connect_response *disconnect_res;
241 struct mei_cl *pos, *next;
242 const size_t len = sizeof(struct hbm_client_connect_response);
243
244 list_for_each_entry_safe(pos, next, &dev->file_list, link) {
245 if (same_disconn_addr(pos, disconnect_req)) {
246 dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
247 disconnect_req->host_addr,
248 disconnect_req->me_addr);
249 pos->state = MEI_FILE_DISCONNECTED;
250 pos->timer_count = 0;
251 if (pos == &dev->wd_cl)
252 dev->wd_pending = false;
253 else if (pos == &dev->iamthif_cl)
254 dev->iamthif_timer = 0;
255
256 /* prepare disconnect response */
257 (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
258 disconnect_res =
259 (struct hbm_client_connect_response *)
260 &dev->wr_ext_msg.data;
261 disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
262 disconnect_res->host_addr = pos->host_client_id;
263 disconnect_res->me_addr = pos->me_client_id;
264 disconnect_res->status = 0;
265 break;
266 }
267 }
268}
269
270
271/**
272 * mei_hbm_dispatch - bottom half read routine after ISR to
273 * handle the read bus message cmd processing.
274 *
275 * @dev: the device structure
276 * @mei_hdr: header of bus message
277 */
278void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
279{
280 struct mei_bus_message *mei_msg;
281 struct mei_me_client *me_client;
282 struct hbm_host_version_response *version_res;
283 struct hbm_client_connect_response *connect_res;
284 struct hbm_client_connect_response *disconnect_res;
285 struct hbm_client_connect_request *disconnect_req;
286 struct hbm_flow_control *flow_control;
287 struct hbm_props_response *props_res;
288 struct hbm_host_enum_response *enum_res;
289 struct hbm_host_stop_request *stop_req;
290
291 /* read the message to our buffer */
292 BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
293 mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
294 mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
295
296 switch (mei_msg->hbm_cmd) {
297 case HOST_START_RES_CMD:
298 version_res = (struct hbm_host_version_response *)mei_msg;
299 if (version_res->host_version_supported) {
300 dev->version.major_version = HBM_MAJOR_VERSION;
301 dev->version.minor_version = HBM_MINOR_VERSION;
302 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
303 dev->init_clients_state == MEI_START_MESSAGE) {
304 dev->init_clients_timer = 0;
305 mei_host_enum_clients_message(dev);
306 } else {
307 dev->recvd_msg = false;
308 dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
309 mei_reset(dev, 1);
310 return;
311 }
312 } else {
313 u32 *buf = dev->wr_msg_buf;
314 const size_t len = sizeof(struct hbm_host_stop_request);
315
316 dev->version = version_res->me_max_version;
317
318 /* send stop message */
319 hdr = mei_hbm_hdr(&buf[0], len);
320 stop_req = (struct hbm_host_stop_request *)&buf[1];
321 memset(stop_req, 0, len);
322 stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
323 stop_req->reason = DRIVER_STOP_REQUEST;
324
325 mei_write_message(dev, hdr, (unsigned char *)stop_req);
326 dev_dbg(&dev->pdev->dev, "version mismatch.\n");
327 return;
328 }
329
330 dev->recvd_msg = true;
331 dev_dbg(&dev->pdev->dev, "host start response message received.\n");
332 break;
333
334 case CLIENT_CONNECT_RES_CMD:
335 connect_res = (struct hbm_client_connect_response *) mei_msg;
336 mei_client_connect_response(dev, connect_res);
337 dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
338 wake_up(&dev->wait_recvd_msg);
339 break;
340
341 case CLIENT_DISCONNECT_RES_CMD:
342 disconnect_res = (struct hbm_client_connect_response *) mei_msg;
343 mei_client_disconnect_response(dev, disconnect_res);
344 dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
345 wake_up(&dev->wait_recvd_msg);
346 break;
347
348 case MEI_FLOW_CONTROL_CMD:
349 flow_control = (struct hbm_flow_control *) mei_msg;
350 mei_client_flow_control_response(dev, flow_control);
351 dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
352 break;
353
354 case HOST_CLIENT_PROPERTIES_RES_CMD:
355 props_res = (struct hbm_props_response *)mei_msg;
356 me_client = &dev->me_clients[dev->me_client_presentation_num];
357
358 if (props_res->status || !dev->me_clients) {
359 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
360 mei_reset(dev, 1);
361 return;
362 }
363
364 if (me_client->client_id != props_res->address) {
365 dev_err(&dev->pdev->dev,
366 "Host client properties reply mismatch\n");
367 mei_reset(dev, 1);
368
369 return;
370 }
371
372 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
373 dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
374 dev_err(&dev->pdev->dev,
375 "Unexpected client properties reply\n");
376 mei_reset(dev, 1);
377
378 return;
379 }
380
381 me_client->props = props_res->client_properties;
382 dev->me_client_index++;
383 dev->me_client_presentation_num++;
384
385 mei_host_client_enumerate(dev);
386
387 break;
388
389 case HOST_ENUM_RES_CMD:
390 enum_res = (struct hbm_host_enum_response *) mei_msg;
391 memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
392 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
393 dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
394 dev->init_clients_timer = 0;
395 dev->me_client_presentation_num = 0;
396 dev->me_client_index = 0;
397 mei_allocate_me_clients_storage(dev);
398 dev->init_clients_state =
399 MEI_CLIENT_PROPERTIES_MESSAGE;
400
401 mei_host_client_enumerate(dev);
402 } else {
403 dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
404 mei_reset(dev, 1);
405 return;
406 }
407 break;
408
409 case HOST_STOP_RES_CMD:
410 dev->dev_state = MEI_DEV_DISABLED;
411 dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
412 mei_reset(dev, 1);
413 break;
414
415 case CLIENT_DISCONNECT_REQ_CMD:
416 /* search for client */
417 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
418 mei_client_disconnect_request(dev, disconnect_req);
419 break;
420
421 case ME_STOP_REQ_CMD:
422 {
423 /* prepare stop request: sent in next interrupt event */
424
425 const size_t len = sizeof(struct hbm_host_stop_request);
426
427 hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
428 stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data;
429 memset(stop_req, 0, len);
430 stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
431 stop_req->reason = DRIVER_STOP_REQUEST;
432 break;
433 }
434 default:
435 BUG();
436 break;
437
438 }
439}
440
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index eb180555d282..0536170ff856 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -320,70 +320,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
320} 320}
321 321
322 322
323
324/**
325 * host_start_message - mei host sends start message.
326 *
327 * @dev: the device structure
328 *
329 * returns none.
330 */
331void mei_host_start_message(struct mei_device *dev)
332{
333 struct mei_msg_hdr *mei_hdr;
334 struct hbm_host_version_request *start_req;
335 const size_t len = sizeof(struct hbm_host_version_request);
336
337 mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
338
339 /* host start message */
340 start_req = (struct hbm_host_version_request *)&dev->wr_msg_buf[1];
341 memset(start_req, 0, len);
342 start_req->hbm_cmd = HOST_START_REQ_CMD;
343 start_req->host_version.major_version = HBM_MAJOR_VERSION;
344 start_req->host_version.minor_version = HBM_MINOR_VERSION;
345
346 dev->recvd_msg = false;
347 if (mei_write_message(dev, mei_hdr, (unsigned char *)start_req)) {
348 dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
349 dev->dev_state = MEI_DEV_RESETING;
350 mei_reset(dev, 1);
351 }
352 dev->init_clients_state = MEI_START_MESSAGE;
353 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
354 return ;
355}
356
357/**
358 * host_enum_clients_message - host sends enumeration client request message.
359 *
360 * @dev: the device structure
361 *
362 * returns none.
363 */
364void mei_host_enum_clients_message(struct mei_device *dev)
365{
366 struct mei_msg_hdr *mei_hdr;
367 struct hbm_host_enum_request *enum_req;
368 const size_t len = sizeof(struct hbm_host_enum_request);
369 /* enumerate clients */
370 mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
371
372 enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
373 memset(enum_req, 0, sizeof(struct hbm_host_enum_request));
374 enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
375
376 if (mei_write_message(dev, mei_hdr, (unsigned char *)enum_req)) {
377 dev->dev_state = MEI_DEV_RESETING;
378 dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
379 mei_reset(dev, 1);
380 }
381 dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
382 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
383 return;
384}
385
386
387/** 323/**
388 * allocate_me_clients_storage - allocates storage for me clients 324 * allocate_me_clients_storage - allocates storage for me clients
389 * 325 *
@@ -457,53 +393,6 @@ void mei_host_client_init(struct work_struct *work)
457 mutex_unlock(&dev->device_lock); 393 mutex_unlock(&dev->device_lock);
458} 394}
459 395
460int mei_host_client_enumerate(struct mei_device *dev)
461{
462
463 struct mei_msg_hdr *mei_hdr;
464 struct hbm_props_request *prop_req;
465 const size_t len = sizeof(struct hbm_props_request);
466 unsigned long next_client_index;
467 u8 client_num;
468
469
470 client_num = dev->me_client_presentation_num;
471
472 next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
473 dev->me_client_index);
474
475 /* We got all client properties */
476 if (next_client_index == MEI_CLIENTS_MAX) {
477 schedule_work(&dev->init_work);
478
479 return 0;
480 }
481
482 dev->me_clients[client_num].client_id = next_client_index;
483 dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
484
485 mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
486 prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1];
487
488 memset(prop_req, 0, sizeof(struct hbm_props_request));
489
490
491 prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
492 prop_req->address = next_client_index;
493
494 if (mei_write_message(dev, mei_hdr, (unsigned char *) prop_req)) {
495 dev->dev_state = MEI_DEV_RESETING;
496 dev_err(&dev->pdev->dev, "Properties request command failed\n");
497 mei_reset(dev, 1);
498
499 return -EIO;
500 }
501
502 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
503 dev->me_client_index = next_client_index;
504
505 return 0;
506}
507 396
508/** 397/**
509 * mei_init_file_private - initializes private file structure. 398 * mei_init_file_private - initializes private file structure.
diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c
index 939d85b40738..155bd7efe4e5 100644
--- a/drivers/misc/mei/interface.c
+++ b/drivers/misc/mei/interface.c
@@ -367,34 +367,6 @@ int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
367 return -ENOENT; 367 return -ENOENT;
368} 368}
369 369
370/**
371 * mei_send_flow_control - sends flow control to fw.
372 *
373 * @dev: the device structure
374 * @cl: private data of the file object
375 *
376 * This function returns -EIO on write failure
377 */
378int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
379{
380 struct mei_msg_hdr *mei_hdr;
381 struct hbm_flow_control *flow_ctrl;
382 const size_t len = sizeof(struct hbm_flow_control);
383
384 mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
385
386 flow_ctrl = (struct hbm_flow_control *)&dev->wr_msg_buf[1];
387 memset(flow_ctrl, 0, len);
388 flow_ctrl->hbm_cmd = MEI_FLOW_CONTROL_CMD;
389 flow_ctrl->host_addr = cl->host_client_id;
390 flow_ctrl->me_addr = cl->me_client_id;
391 /* FIXME: reserved !? */
392 memset(flow_ctrl->reserved, 0, sizeof(flow_ctrl->reserved));
393 dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
394 cl->host_client_id, cl->me_client_id);
395
396 return mei_write_message(dev, mei_hdr, (unsigned char *) flow_ctrl);
397}
398 370
399/** 371/**
400 * mei_other_client_is_connecting - checks if other 372 * mei_other_client_is_connecting - checks if other
@@ -421,53 +393,3 @@ int mei_other_client_is_connecting(struct mei_device *dev,
421 return 0; 393 return 0;
422} 394}
423 395
424/**
425 * mei_disconnect - sends disconnect message to fw.
426 *
427 * @dev: the device structure
428 * @cl: private data of the file object
429 *
430 * This function returns -EIO on write failure
431 */
432int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
433{
434 struct mei_msg_hdr *hdr;
435 struct hbm_client_connect_request *req;
436 const size_t len = sizeof(struct hbm_client_connect_request);
437
438 hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
439
440 req = (struct hbm_client_connect_request *)&dev->wr_msg_buf[1];
441 memset(req, 0, len);
442 req->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD;
443 req->host_addr = cl->host_client_id;
444 req->me_addr = cl->me_client_id;
445 req->reserved = 0;
446
447 return mei_write_message(dev, hdr, (unsigned char *)req);
448}
449
450/**
451 * mei_connect - sends connect message to fw.
452 *
453 * @dev: the device structure
454 * @cl: private data of the file object
455 *
456 * This function returns -EIO on write failure
457 */
458int mei_connect(struct mei_device *dev, struct mei_cl *cl)
459{
460 struct mei_msg_hdr *hdr;
461 struct hbm_client_connect_request *req;
462 const size_t len = sizeof(struct hbm_client_connect_request);
463
464 hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
465
466 req = (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
467 req->hbm_cmd = CLIENT_CONNECT_REQ_CMD;
468 req->host_addr = cl->host_client_id;
469 req->me_addr = cl->me_client_id;
470 req->reserved = 0;
471
472 return mei_write_message(dev, hdr, (unsigned char *) req);
473}
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index cd89b68fcf43..d4312a8e139a 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -208,7 +208,7 @@ static bool is_treat_specially_client(struct mei_cl *cl,
208 * @dev: the device structure 208 * @dev: the device structure
209 * @rs: connect response bus message 209 * @rs: connect response bus message
210 */ 210 */
211static void mei_client_connect_response(struct mei_device *dev, 211void mei_client_connect_response(struct mei_device *dev,
212 struct hbm_client_connect_response *rs) 212 struct hbm_client_connect_response *rs)
213{ 213{
214 214
@@ -261,8 +261,8 @@ static void mei_client_connect_response(struct mei_device *dev,
261 * @dev: the device structure 261 * @dev: the device structure
262 * @rs: disconnect response bus message 262 * @rs: disconnect response bus message
263 */ 263 */
264static void mei_client_disconnect_response(struct mei_device *dev, 264void mei_client_disconnect_response(struct mei_device *dev,
265 struct hbm_client_connect_response *rs) 265 struct hbm_client_connect_response *rs)
266{ 266{
267 struct mei_cl *cl; 267 struct mei_cl *cl;
268 struct mei_cl_cb *pos = NULL, *next = NULL; 268 struct mei_cl_cb *pos = NULL, *next = NULL;
@@ -347,7 +347,7 @@ static void add_single_flow_creds(struct mei_device *dev,
347 * @dev: the device structure 347 * @dev: the device structure
348 * @flow_control: flow control response bus message 348 * @flow_control: flow control response bus message
349 */ 349 */
350static void mei_client_flow_control_response(struct mei_device *dev, 350void mei_client_flow_control_response(struct mei_device *dev,
351 struct hbm_flow_control *flow_control) 351 struct hbm_flow_control *flow_control)
352{ 352{
353 struct mei_cl *cl_pos = NULL; 353 struct mei_cl *cl_pos = NULL;
@@ -381,231 +381,6 @@ static void mei_client_flow_control_response(struct mei_device *dev,
381 } 381 }
382} 382}
383 383
384/**
385 * same_disconn_addr - tells if they have the same address
386 *
387 * @file: private data of the file object.
388 * @disconn: disconnection request.
389 *
390 * returns !=0, same; 0,not.
391 */
392static int same_disconn_addr(struct mei_cl *cl,
393 struct hbm_client_connect_request *req)
394{
395 return (cl->host_client_id == req->host_addr &&
396 cl->me_client_id == req->me_addr);
397}
398
399/**
400 * mei_client_disconnect_request - disconnects from request irq routine
401 *
402 * @dev: the device structure.
403 * @disconnect_req: disconnect request bus message.
404 */
405static void mei_client_disconnect_request(struct mei_device *dev,
406 struct hbm_client_connect_request *disconnect_req)
407{
408 struct hbm_client_connect_response *disconnect_res;
409 struct mei_cl *pos, *next;
410 const size_t len = sizeof(struct hbm_client_connect_response);
411
412 list_for_each_entry_safe(pos, next, &dev->file_list, link) {
413 if (same_disconn_addr(pos, disconnect_req)) {
414 dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
415 disconnect_req->host_addr,
416 disconnect_req->me_addr);
417 pos->state = MEI_FILE_DISCONNECTED;
418 pos->timer_count = 0;
419 if (pos == &dev->wd_cl)
420 dev->wd_pending = false;
421 else if (pos == &dev->iamthif_cl)
422 dev->iamthif_timer = 0;
423
424 /* prepare disconnect response */
425 (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
426 disconnect_res =
427 (struct hbm_client_connect_response *)
428 &dev->wr_ext_msg.data;
429 disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
430 disconnect_res->host_addr = pos->host_client_id;
431 disconnect_res->me_addr = pos->me_client_id;
432 disconnect_res->status = 0;
433 break;
434 }
435 }
436}
437
438/**
439 * mei_irq_thread_read_bus_message - bottom half read routine after ISR to
440 * handle the read bus message cmd processing.
441 *
442 * @dev: the device structure
443 * @mei_hdr: header of bus message
444 */
445static void mei_irq_thread_read_bus_message(struct mei_device *dev,
446 struct mei_msg_hdr *hdr)
447{
448 struct mei_bus_message *mei_msg;
449 struct mei_me_client *me_client;
450 struct hbm_host_version_response *version_res;
451 struct hbm_client_connect_response *connect_res;
452 struct hbm_client_connect_response *disconnect_res;
453 struct hbm_client_connect_request *disconnect_req;
454 struct hbm_flow_control *flow_control;
455 struct hbm_props_response *props_res;
456 struct hbm_host_enum_response *enum_res;
457 struct hbm_host_stop_request *stop_req;
458
459 /* read the message to our buffer */
460 BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
461 mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
462 mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
463
464 switch (mei_msg->hbm_cmd) {
465 case HOST_START_RES_CMD:
466 version_res = (struct hbm_host_version_response *) mei_msg;
467 if (version_res->host_version_supported) {
468 dev->version.major_version = HBM_MAJOR_VERSION;
469 dev->version.minor_version = HBM_MINOR_VERSION;
470 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
471 dev->init_clients_state == MEI_START_MESSAGE) {
472 dev->init_clients_timer = 0;
473 mei_host_enum_clients_message(dev);
474 } else {
475 dev->recvd_msg = false;
476 dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
477 mei_reset(dev, 1);
478 return;
479 }
480 } else {
481 u32 *buf = dev->wr_msg_buf;
482 const size_t len = sizeof(struct hbm_host_stop_request);
483
484 dev->version = version_res->me_max_version;
485
486 /* send stop message */
487 hdr = mei_hbm_hdr(&buf[0], len);
488 stop_req = (struct hbm_host_stop_request *)&buf[1];
489 memset(stop_req, 0, len);
490 stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
491 stop_req->reason = DRIVER_STOP_REQUEST;
492
493 mei_write_message(dev, hdr, (unsigned char *)stop_req);
494 dev_dbg(&dev->pdev->dev, "version mismatch.\n");
495 return;
496 }
497
498 dev->recvd_msg = true;
499 dev_dbg(&dev->pdev->dev, "host start response message received.\n");
500 break;
501
502 case CLIENT_CONNECT_RES_CMD:
503 connect_res = (struct hbm_client_connect_response *) mei_msg;
504 mei_client_connect_response(dev, connect_res);
505 dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
506 wake_up(&dev->wait_recvd_msg);
507 break;
508
509 case CLIENT_DISCONNECT_RES_CMD:
510 disconnect_res = (struct hbm_client_connect_response *) mei_msg;
511 mei_client_disconnect_response(dev, disconnect_res);
512 dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
513 wake_up(&dev->wait_recvd_msg);
514 break;
515
516 case MEI_FLOW_CONTROL_CMD:
517 flow_control = (struct hbm_flow_control *) mei_msg;
518 mei_client_flow_control_response(dev, flow_control);
519 dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
520 break;
521
522 case HOST_CLIENT_PROPERTIES_RES_CMD:
523 props_res = (struct hbm_props_response *)mei_msg;
524 me_client = &dev->me_clients[dev->me_client_presentation_num];
525
526 if (props_res->status || !dev->me_clients) {
527 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
528 mei_reset(dev, 1);
529 return;
530 }
531
532 if (me_client->client_id != props_res->address) {
533 dev_err(&dev->pdev->dev,
534 "Host client properties reply mismatch\n");
535 mei_reset(dev, 1);
536
537 return;
538 }
539
540 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
541 dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
542 dev_err(&dev->pdev->dev,
543 "Unexpected client properties reply\n");
544 mei_reset(dev, 1);
545
546 return;
547 }
548
549 me_client->props = props_res->client_properties;
550 dev->me_client_index++;
551 dev->me_client_presentation_num++;
552
553 mei_host_client_enumerate(dev);
554
555 break;
556
557 case HOST_ENUM_RES_CMD:
558 enum_res = (struct hbm_host_enum_response *) mei_msg;
559 memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
560 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
561 dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
562 dev->init_clients_timer = 0;
563 dev->me_client_presentation_num = 0;
564 dev->me_client_index = 0;
565 mei_allocate_me_clients_storage(dev);
566 dev->init_clients_state =
567 MEI_CLIENT_PROPERTIES_MESSAGE;
568
569 mei_host_client_enumerate(dev);
570 } else {
571 dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
572 mei_reset(dev, 1);
573 return;
574 }
575 break;
576
577 case HOST_STOP_RES_CMD:
578 dev->dev_state = MEI_DEV_DISABLED;
579 dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
580 mei_reset(dev, 1);
581 break;
582
583 case CLIENT_DISCONNECT_REQ_CMD:
584 /* search for client */
585 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
586 mei_client_disconnect_request(dev, disconnect_req);
587 break;
588
589 case ME_STOP_REQ_CMD:
590 {
591 /* prepare stop request: sent in next interrupt event */
592
593 const size_t len = sizeof(struct hbm_host_stop_request);
594
595 hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
596 stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data;
597 memset(stop_req, 0, len);
598 stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
599 stop_req->reason = DRIVER_STOP_REQUEST;
600 break;
601 }
602 default:
603 BUG();
604 break;
605
606 }
607}
608
609 384
610/** 385/**
611 * _mei_hb_read - processes read related operation. 386 * _mei_hb_read - processes read related operation.
@@ -806,7 +581,7 @@ static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list,
806 /* decide where to read the message too */ 581 /* decide where to read the message too */
807 if (!mei_hdr->host_addr) { 582 if (!mei_hdr->host_addr) {
808 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n"); 583 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
809 mei_irq_thread_read_bus_message(dev, mei_hdr); 584 mei_hbm_dispatch(dev, mei_hdr);
810 dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n"); 585 dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
811 } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && 586 } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
812 (MEI_FILE_CONNECTED == dev->iamthif_cl.state) && 587 (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 472c9cacc543..b437f8b15406 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -402,6 +402,14 @@ int mei_ioctl_connect_client(struct file *file,
402int mei_start_read(struct mei_device *dev, struct mei_cl *cl); 402int mei_start_read(struct mei_device *dev, struct mei_cl *cl);
403 403
404 404
405void mei_client_disconnect_response(struct mei_device *dev,
406 struct hbm_client_connect_response *rs);
407
408void mei_client_connect_response(struct mei_device *dev,
409 struct hbm_client_connect_response *rs);
410
411void mei_client_flow_control_response(struct mei_device *dev,
412 struct hbm_flow_control *flow_control);
405/* 413/*
406 * AMTHIF - AMT Host Interface Functions 414 * AMTHIF - AMT Host Interface Functions
407 */ 415 */
@@ -452,6 +460,8 @@ void mei_enable_interrupts(struct mei_device *dev);
452void mei_disable_interrupts(struct mei_device *dev); 460void mei_disable_interrupts(struct mei_device *dev);
453 461
454 462
463void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
464
455static inline struct mei_msg_hdr *mei_hbm_hdr(u32 *buf, size_t length) 465static inline struct mei_msg_hdr *mei_hbm_hdr(u32 *buf, size_t length)
456{ 466{
457 struct mei_msg_hdr *hdr = (struct mei_msg_hdr *)buf; 467 struct mei_msg_hdr *hdr = (struct mei_msg_hdr *)buf;