blob: 45659de141869a8787c06c54390a60726c36385c [file] [log] [blame]
Tomas Winklerbb1b0132012-12-25 19:06:07 +02001/*
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
Tomas Winkler4fcbc992014-03-18 22:51:55 +020017#include <linux/export.h>
Tomas Winklerbb1b0132012-12-25 19:06:07 +020018#include <linux/pci.h>
19#include <linux/sched.h>
20#include <linux/wait.h>
21#include <linux/mei.h>
Tomas Winkler180ea052014-03-18 22:52:02 +020022#include <linux/pm_runtime.h>
Tomas Winklerbb1b0132012-12-25 19:06:07 +020023
24#include "mei_dev.h"
Tomas Winkler0edb23f2013-01-08 23:07:12 +020025#include "hbm.h"
Alexander Usyskin12d00662014-02-17 15:13:23 +020026#include "client.h"
Tomas Winklerbb1b0132012-12-25 19:06:07 +020027
Alexander Usyskin285e2992014-02-17 15:13:20 +020028static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
29{
30#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
31 switch (status) {
32 MEI_CL_CS(SUCCESS);
33 MEI_CL_CS(NOT_FOUND);
34 MEI_CL_CS(ALREADY_STARTED);
35 MEI_CL_CS(OUT_OF_RESOURCES);
36 MEI_CL_CS(MESSAGE_SMALL);
37 default: return "unknown";
38 }
39#undef MEI_CL_CCS
40}
41
42/**
43 * mei_cl_conn_status_to_errno - convert client connect response
44 * status to error code
45 *
46 * @status: client connect response status
47 *
48 * returns corresponding error code
49 */
50static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
51{
52 switch (status) {
53 case MEI_CL_CONN_SUCCESS: return 0;
54 case MEI_CL_CONN_NOT_FOUND: return -ENOTTY;
55 case MEI_CL_CONN_ALREADY_STARTED: return -EBUSY;
56 case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
57 case MEI_CL_CONN_MESSAGE_SMALL: return -EINVAL;
58 default: return -EINVAL;
59 }
60}
61
Tomas Winklerbb1b0132012-12-25 19:06:07 +020062/**
Tomas Winkler84b32942014-05-07 16:51:28 +030063 * mei_hbm_idle - set hbm to idle state
64 *
65 * @dev: the device structure
66 */
67void mei_hbm_idle(struct mei_device *dev)
68{
69 dev->init_clients_timer = 0;
70 dev->hbm_state = MEI_HBM_IDLE;
71}
72
73/**
74 * mei_hbm_reset - reset hbm counters and book keeping data structurs
75 *
76 * @dev: the device structure
77 */
78void mei_hbm_reset(struct mei_device *dev)
79{
Tomas Winkler5ca2d382014-08-21 14:29:13 +030080 struct mei_me_client *me_cl, *next;
81
Tomas Winkler84b32942014-05-07 16:51:28 +030082 dev->me_client_presentation_num = 0;
83 dev->me_client_index = 0;
84
Tomas Winkler5ca2d382014-08-21 14:29:13 +030085 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
86 list_del(&me_cl->list);
87 kfree(me_cl);
88 }
Tomas Winkler84b32942014-05-07 16:51:28 +030089
90 mei_hbm_idle(dev);
91}
92
93/**
Tomas Winklercd51ed62012-12-25 19:06:09 +020094 * mei_hbm_cl_hdr - construct client hbm header
Masanari Iida393b1482013-04-05 01:05:05 +090095 *
Tomas Winkler68d1aa62014-08-21 14:29:11 +030096 * @cl: client
Tomas Winklercd51ed62012-12-25 19:06:09 +020097 * @hbm_cmd: host bus message command
98 * @buf: buffer for cl header
99 * @len: buffer length
100 */
101static inline
102void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
103{
104 struct mei_hbm_cl_cmd *cmd = buf;
105
106 memset(cmd, 0, len);
107
108 cmd->hbm_cmd = hbm_cmd;
109 cmd->host_addr = cl->host_client_id;
110 cmd->me_addr = cl->me_client_id;
111}
112
113/**
Tomas Winkler68d1aa62014-08-21 14:29:11 +0300114 * mei_hbm_cl_write - write simple hbm client message
115 *
116 * @dev: the device structure
117 * @cl: client
118 * @hbm_cmd: host bus message command
119 * @len: buffer length
120 */
121static inline
122int mei_hbm_cl_write(struct mei_device *dev,
123 struct mei_cl *cl, u8 hbm_cmd, size_t len)
124{
125 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
126
127 mei_hbm_hdr(mei_hdr, len);
128 mei_hbm_cl_hdr(cl, hbm_cmd, dev->wr_msg.data, len);
129
130 return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
131}
132
133/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200134 * mei_hbm_cl_addr_equal - tells if they have the same address
Tomas Winklercd51ed62012-12-25 19:06:09 +0200135 *
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200136 * @cl: - client
137 * @buf: buffer with cl header
Tomas Winklercd51ed62012-12-25 19:06:09 +0200138 *
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200139 * returns true if addresses are the same
Tomas Winklercd51ed62012-12-25 19:06:09 +0200140 */
141static inline
142bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
143{
144 struct mei_hbm_cl_cmd *cmd = buf;
145 return cl->host_client_id == cmd->host_addr &&
146 cl->me_client_id == cmd->me_addr;
147}
148
149
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300150int mei_hbm_start_wait(struct mei_device *dev)
151{
152 int ret;
153 if (dev->hbm_state > MEI_HBM_START)
154 return 0;
155
156 mutex_unlock(&dev->device_lock);
157 ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
158 dev->hbm_state == MEI_HBM_IDLE ||
Tomas Winkler544f9462014-01-08 20:19:21 +0200159 dev->hbm_state >= MEI_HBM_STARTED,
Tomas Winkler7d93e582014-01-14 23:10:10 +0200160 mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300161 mutex_lock(&dev->device_lock);
162
163 if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
164 dev->hbm_state = MEI_HBM_IDLE;
Masanari Iida8b513d02013-05-21 23:13:12 +0900165 dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +0200166 return -ETIME;
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300167 }
168 return 0;
169}
170
Tomas Winkler6bbda152012-12-25 19:06:12 +0200171/**
Tomas Winkler8120e722012-12-25 19:06:11 +0200172 * mei_hbm_start_req - sends start request message.
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200173 *
174 * @dev: the device structure
Tomas Winkler544f9462014-01-08 20:19:21 +0200175 *
176 * returns 0 on success and < 0 on failure
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200177 */
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300178int mei_hbm_start_req(struct mei_device *dev)
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200179{
Tomas Winklere46f1872012-12-25 19:06:10 +0200180 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200181 struct hbm_host_version_request *start_req;
182 const size_t len = sizeof(struct hbm_host_version_request);
Tomas Winkler544f9462014-01-08 20:19:21 +0200183 int ret;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200184
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300185 mei_hbm_reset(dev);
186
Tomas Winklere46f1872012-12-25 19:06:10 +0200187 mei_hbm_hdr(mei_hdr, len);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200188
189 /* host start message */
Tomas Winklere46f1872012-12-25 19:06:10 +0200190 start_req = (struct hbm_host_version_request *)dev->wr_msg.data;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200191 memset(start_req, 0, len);
192 start_req->hbm_cmd = HOST_START_REQ_CMD;
193 start_req->host_version.major_version = HBM_MAJOR_VERSION;
194 start_req->host_version.minor_version = HBM_MINOR_VERSION;
195
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300196 dev->hbm_state = MEI_HBM_IDLE;
Tomas Winkler544f9462014-01-08 20:19:21 +0200197 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
198 if (ret) {
199 dev_err(&dev->pdev->dev, "version message write failed: ret = %d\n",
200 ret);
201 return ret;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200202 }
Tomas Winkler544f9462014-01-08 20:19:21 +0200203
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300204 dev->hbm_state = MEI_HBM_START;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200205 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300206 return 0;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200207}
208
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300209/*
Tomas Winkler8120e722012-12-25 19:06:11 +0200210 * mei_hbm_enum_clients_req - sends enumeration client request message.
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200211 *
212 * @dev: the device structure
213 *
Tomas Winkler544f9462014-01-08 20:19:21 +0200214 * returns 0 on success and < 0 on failure
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200215 */
Tomas Winkler544f9462014-01-08 20:19:21 +0200216static int mei_hbm_enum_clients_req(struct mei_device *dev)
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200217{
Tomas Winklere46f1872012-12-25 19:06:10 +0200218 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200219 struct hbm_host_enum_request *enum_req;
220 const size_t len = sizeof(struct hbm_host_enum_request);
Tomas Winkler544f9462014-01-08 20:19:21 +0200221 int ret;
222
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200223 /* enumerate clients */
Tomas Winklere46f1872012-12-25 19:06:10 +0200224 mei_hbm_hdr(mei_hdr, len);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200225
Tomas Winklere46f1872012-12-25 19:06:10 +0200226 enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
227 memset(enum_req, 0, len);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200228 enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
229
Tomas Winkler544f9462014-01-08 20:19:21 +0200230 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
231 if (ret) {
232 dev_err(&dev->pdev->dev, "enumeration request write failed: ret = %d.\n",
233 ret);
234 return ret;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200235 }
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300236 dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200237 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
Tomas Winkler544f9462014-01-08 20:19:21 +0200238 return 0;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200239}
240
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300241/*
242 * mei_hbm_me_cl_add - add new me client to the list
243 *
244 * @dev: the device structure
245 * @res: hbm property response
246 *
247 * returns 0 on success and -ENOMEM on allocation failure
248 */
249
250static int mei_hbm_me_cl_add(struct mei_device *dev,
251 struct hbm_props_response *res)
252{
253 struct mei_me_client *me_cl;
254
255 me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL);
256 if (!me_cl)
257 return -ENOMEM;
258
259 me_cl->props = res->client_properties;
260 me_cl->client_id = res->me_addr;
261 me_cl->mei_flow_ctrl_creds = 0;
262
263 list_add(&me_cl->list, &dev->me_clients);
264 return 0;
265}
266
Tomas Winkler8120e722012-12-25 19:06:11 +0200267/**
Masanari Iida393b1482013-04-05 01:05:05 +0900268 * mei_hbm_prop_req - request property for a single client
Tomas Winkler8120e722012-12-25 19:06:11 +0200269 *
270 * @dev: the device structure
271 *
Tomas Winkler544f9462014-01-08 20:19:21 +0200272 * returns 0 on success and < 0 on failure
Tomas Winkler8120e722012-12-25 19:06:11 +0200273 */
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200274
Tomas Winkler8120e722012-12-25 19:06:11 +0200275static int mei_hbm_prop_req(struct mei_device *dev)
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200276{
277
Tomas Winklere46f1872012-12-25 19:06:10 +0200278 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200279 struct hbm_props_request *prop_req;
280 const size_t len = sizeof(struct hbm_props_request);
281 unsigned long next_client_index;
Tomas Winkler544f9462014-01-08 20:19:21 +0200282 int ret;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200283
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200284 next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
285 dev->me_client_index);
286
287 /* We got all client properties */
288 if (next_client_index == MEI_CLIENTS_MAX) {
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300289 dev->hbm_state = MEI_HBM_STARTED;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200290 schedule_work(&dev->init_work);
291
292 return 0;
293 }
294
Tomas Winklere46f1872012-12-25 19:06:10 +0200295 mei_hbm_hdr(mei_hdr, len);
296 prop_req = (struct hbm_props_request *)dev->wr_msg.data;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200297
298 memset(prop_req, 0, sizeof(struct hbm_props_request));
299
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200300 prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
Tomas Winkler3438c1f2014-08-21 14:29:10 +0300301 prop_req->me_addr = next_client_index;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200302
Tomas Winkler544f9462014-01-08 20:19:21 +0200303 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
304 if (ret) {
305 dev_err(&dev->pdev->dev, "properties request write failed: ret = %d\n",
306 ret);
307 return ret;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200308 }
309
310 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
311 dev->me_client_index = next_client_index;
312
313 return 0;
314}
315
Tomas Winkler4fcbc992014-03-18 22:51:55 +0200316/*
317 * mei_hbm_pg - sends pg command
318 *
319 * @dev: the device structure
320 * @pg_cmd: the pg command code
321 *
322 * This function returns -EIO on write failure
323 */
324int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
325{
326 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
327 struct hbm_power_gate *req;
328 const size_t len = sizeof(struct hbm_power_gate);
329 int ret;
330
331 mei_hbm_hdr(mei_hdr, len);
332
333 req = (struct hbm_power_gate *)dev->wr_msg.data;
334 memset(req, 0, len);
335 req->hbm_cmd = pg_cmd;
336
337 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
338 if (ret)
339 dev_err(&dev->pdev->dev, "power gate command write failed.\n");
340 return ret;
341}
342EXPORT_SYMBOL_GPL(mei_hbm_pg);
343
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200344/**
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200345 * mei_hbm_stop_req - send stop request message
Tomas Winklere46f1872012-12-25 19:06:10 +0200346 *
347 * @dev - mei device
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200348 * @cl: client info
349 *
350 * This function returns -EIO on write failure
Tomas Winklere46f1872012-12-25 19:06:10 +0200351 */
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200352static int mei_hbm_stop_req(struct mei_device *dev)
Tomas Winklere46f1872012-12-25 19:06:10 +0200353{
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200354 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
Tomas Winklere46f1872012-12-25 19:06:10 +0200355 struct hbm_host_stop_request *req =
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200356 (struct hbm_host_stop_request *)dev->wr_msg.data;
Tomas Winklere46f1872012-12-25 19:06:10 +0200357 const size_t len = sizeof(struct hbm_host_stop_request);
358
359 mei_hbm_hdr(mei_hdr, len);
360
361 memset(req, 0, len);
362 req->hbm_cmd = HOST_STOP_REQ_CMD;
363 req->reason = DRIVER_STOP_REQUEST;
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200364
365 return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
Tomas Winklere46f1872012-12-25 19:06:10 +0200366}
367
368/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200369 * mei_hbm_cl_flow_control_req - sends flow control request.
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200370 *
371 * @dev: the device structure
Tomas Winkler8120e722012-12-25 19:06:11 +0200372 * @cl: client info
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200373 *
374 * This function returns -EIO on write failure
375 */
Tomas Winkler8120e722012-12-25 19:06:11 +0200376int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200377{
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200378 const size_t len = sizeof(struct hbm_flow_control);
Tomas Winkler46922182014-03-16 14:35:55 +0200379 cl_dbg(dev, cl, "sending flow control\n");
Tomas Winkler68d1aa62014-08-21 14:29:11 +0300380 return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, len);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200381}
382
383/**
Masanari Iida393b1482013-04-05 01:05:05 +0900384 * mei_hbm_add_single_flow_creds - adds single buffer credentials.
Tomas Winkler6bbda152012-12-25 19:06:12 +0200385 *
Masanari Iida393b1482013-04-05 01:05:05 +0900386 * @dev: the device structure
Tomas Winkler6bbda152012-12-25 19:06:12 +0200387 * @flow: flow control.
Alexander Usyskin12d00662014-02-17 15:13:23 +0200388 *
389 * return 0 on success, < 0 otherwise
Tomas Winkler6bbda152012-12-25 19:06:12 +0200390 */
Alexander Usyskin12d00662014-02-17 15:13:23 +0200391static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
Tomas Winkler6bbda152012-12-25 19:06:12 +0200392 struct hbm_flow_control *flow)
393{
Alexander Usyskin12d00662014-02-17 15:13:23 +0200394 struct mei_me_client *me_cl;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200395
Tomas Winklerd3208322014-08-24 12:08:55 +0300396 me_cl = mei_me_cl_by_id(dev, flow->me_addr);
397 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200398 dev_err(&dev->pdev->dev, "no such me client %d\n",
399 flow->me_addr);
Tomas Winklerd3208322014-08-24 12:08:55 +0300400 return -ENOENT;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200401 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200402
Tomas Winklerd3208322014-08-24 12:08:55 +0300403 if (WARN_ON(me_cl->props.single_recv_buf == 0))
404 return -EINVAL;
405
406 me_cl->mei_flow_ctrl_creds++;
407 dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
408 flow->me_addr, me_cl->mei_flow_ctrl_creds);
Alexander Usyskin12d00662014-02-17 15:13:23 +0200409
410 return 0;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200411}
412
413/**
414 * mei_hbm_cl_flow_control_res - flow control response from me
415 *
416 * @dev: the device structure
417 * @flow_control: flow control response bus message
418 */
419static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
420 struct hbm_flow_control *flow_control)
421{
Tomas Winkler31f88f52014-02-17 15:13:25 +0200422 struct mei_cl *cl;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200423
424 if (!flow_control->host_addr) {
425 /* single receive buffer */
426 mei_hbm_add_single_flow_creds(dev, flow_control);
427 return;
428 }
429
430 /* normal connection */
Tomas Winkler31f88f52014-02-17 15:13:25 +0200431 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler6bbda152012-12-25 19:06:12 +0200432 if (mei_hbm_cl_addr_equal(cl, flow_control)) {
433 cl->mei_flow_ctrl_creds++;
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300434 dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d creds %d.\n",
435 flow_control->host_addr, flow_control->me_addr,
436 cl->mei_flow_ctrl_creds);
437 break;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200438 }
439 }
440}
441
442
443/**
Tomas Winkler8120e722012-12-25 19:06:11 +0200444 * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200445 *
446 * @dev: the device structure
Tomas Winkler8120e722012-12-25 19:06:11 +0200447 * @cl: a client to disconnect from
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200448 *
449 * This function returns -EIO on write failure
450 */
Tomas Winkler8120e722012-12-25 19:06:11 +0200451int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200452{
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200453 const size_t len = sizeof(struct hbm_client_connect_request);
Tomas Winkler68d1aa62014-08-21 14:29:11 +0300454 return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, len);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200455}
456
457/**
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200458 * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW
459 *
460 * @dev: the device structure
461 * @cl: a client to disconnect from
462 *
463 * This function returns -EIO on write failure
464 */
465int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
466{
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200467 const size_t len = sizeof(struct hbm_client_connect_response);
Tomas Winkler68d1aa62014-08-21 14:29:11 +0300468 return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, len);
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200469}
470
471/**
Tomas Winkler6bbda152012-12-25 19:06:12 +0200472 * mei_hbm_cl_disconnect_res - disconnect response from ME
473 *
474 * @dev: the device structure
475 * @rs: disconnect response bus message
476 */
477static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
478 struct hbm_client_connect_response *rs)
479{
480 struct mei_cl *cl;
Tomas Winkler64092852014-02-17 15:13:21 +0200481 struct mei_cl_cb *cb, *next;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200482
Alexander Usyskin285e2992014-02-17 15:13:20 +0200483 dev_dbg(&dev->pdev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
484 rs->me_addr, rs->host_addr, rs->status);
Tomas Winkler6bbda152012-12-25 19:06:12 +0200485
Tomas Winkler64092852014-02-17 15:13:21 +0200486 list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
487 cl = cb->cl;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200488
Tomas Winkler64092852014-02-17 15:13:21 +0200489 /* this should not happen */
490 if (WARN_ON(!cl)) {
491 list_del(&cb->list);
Tomas Winkler6bbda152012-12-25 19:06:12 +0200492 return;
493 }
494
Tomas Winkler6bbda152012-12-25 19:06:12 +0200495 if (mei_hbm_cl_addr_equal(cl, rs)) {
Tomas Winkler64092852014-02-17 15:13:21 +0200496 list_del(&cb->list);
Alexander Usyskin285e2992014-02-17 15:13:20 +0200497 if (rs->status == MEI_CL_DISCONN_SUCCESS)
Tomas Winkler6bbda152012-12-25 19:06:12 +0200498 cl->state = MEI_FILE_DISCONNECTED;
499
500 cl->status = 0;
501 cl->timer_count = 0;
502 break;
503 }
504 }
505}
506
507/**
Tomas Winkler8120e722012-12-25 19:06:11 +0200508 * mei_hbm_cl_connect_req - send connection request to specific me client
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200509 *
510 * @dev: the device structure
Tomas Winkler8120e722012-12-25 19:06:11 +0200511 * @cl: a client to connect to
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200512 *
Tomas Winkler8120e722012-12-25 19:06:11 +0200513 * returns -EIO on write failure
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200514 */
Tomas Winkler8120e722012-12-25 19:06:11 +0200515int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200516{
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200517 const size_t len = sizeof(struct hbm_client_connect_request);
Tomas Winkler68d1aa62014-08-21 14:29:11 +0300518 return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, len);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200519}
520
521/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200522 * mei_hbm_cl_connect_res - connect response from the ME
Tomas Winkler6bbda152012-12-25 19:06:12 +0200523 *
524 * @dev: the device structure
525 * @rs: connect response bus message
526 */
527static void mei_hbm_cl_connect_res(struct mei_device *dev,
528 struct hbm_client_connect_response *rs)
529{
530
531 struct mei_cl *cl;
Tomas Winkler64092852014-02-17 15:13:21 +0200532 struct mei_cl_cb *cb, *next;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200533
Alexander Usyskin285e2992014-02-17 15:13:20 +0200534 dev_dbg(&dev->pdev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
535 rs->me_addr, rs->host_addr,
536 mei_cl_conn_status_str(rs->status));
Tomas Winkler6bbda152012-12-25 19:06:12 +0200537
Tomas Winkler64092852014-02-17 15:13:21 +0200538 cl = NULL;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200539
Tomas Winkler64092852014-02-17 15:13:21 +0200540 list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
Tomas Winkler6bbda152012-12-25 19:06:12 +0200541
Tomas Winkler64092852014-02-17 15:13:21 +0200542 cl = cb->cl;
543 /* this should not happen */
544 if (WARN_ON(!cl)) {
545 list_del_init(&cb->list);
546 continue;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200547 }
Tomas Winkler64092852014-02-17 15:13:21 +0200548
549 if (cb->fop_type != MEI_FOP_CONNECT)
550 continue;
551
552 if (mei_hbm_cl_addr_equal(cl, rs)) {
553 list_del(&cb->list);
554 break;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200555 }
556 }
Tomas Winkler64092852014-02-17 15:13:21 +0200557
558 if (!cl)
559 return;
560
561 cl->timer_count = 0;
562 if (rs->status == MEI_CL_CONN_SUCCESS)
563 cl->state = MEI_FILE_CONNECTED;
564 else
565 cl->state = MEI_FILE_DISCONNECTED;
566 cl->status = mei_cl_conn_status_to_errno(rs->status);
Tomas Winkler6bbda152012-12-25 19:06:12 +0200567}
568
569
570/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200571 * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware
572 * host sends disconnect response
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200573 *
574 * @dev: the device structure.
Tomas Winkler8120e722012-12-25 19:06:11 +0200575 * @disconnect_req: disconnect request bus message from the me
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200576 *
577 * returns -ENOMEM on allocation failure
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200578 */
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200579static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200580 struct hbm_client_connect_request *disconnect_req)
581{
Tomas Winkler31f88f52014-02-17 15:13:25 +0200582 struct mei_cl *cl;
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200583 struct mei_cl_cb *cb;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200584
Tomas Winkler31f88f52014-02-17 15:13:25 +0200585 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winklercd51ed62012-12-25 19:06:09 +0200586 if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200587 dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
588 disconnect_req->host_addr,
589 disconnect_req->me_addr);
Tomas Winklercd51ed62012-12-25 19:06:09 +0200590 cl->state = MEI_FILE_DISCONNECTED;
591 cl->timer_count = 0;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200592
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200593 cb = mei_io_cb_init(cl, NULL);
594 if (!cb)
595 return -ENOMEM;
596 cb->fop_type = MEI_FOP_DISCONNECT_RSP;
597 cl_dbg(dev, cl, "add disconnect response as first\n");
598 list_add(&cb->list, &dev->ctrl_wr_list.list);
599
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200600 break;
601 }
602 }
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200603 return 0;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200604}
605
606
607/**
Tomas Winkler2c9b48a2013-06-16 09:16:31 +0300608 * mei_hbm_version_is_supported - checks whether the driver can
609 * support the hbm version of the device
610 *
611 * @dev: the device structure
612 * returns true if driver can support hbm version of the device
613 */
614bool mei_hbm_version_is_supported(struct mei_device *dev)
615{
616 return (dev->version.major_version < HBM_MAJOR_VERSION) ||
617 (dev->version.major_version == HBM_MAJOR_VERSION &&
618 dev->version.minor_version <= HBM_MINOR_VERSION);
619}
620
621/**
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200622 * mei_hbm_dispatch - bottom half read routine after ISR to
623 * handle the read bus message cmd processing.
624 *
625 * @dev: the device structure
626 * @mei_hdr: header of bus message
Tomas Winkler544f9462014-01-08 20:19:21 +0200627 *
628 * returns 0 on success and < 0 on failure
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200629 */
Tomas Winkler544f9462014-01-08 20:19:21 +0200630int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200631{
632 struct mei_bus_message *mei_msg;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200633 struct hbm_host_version_response *version_res;
634 struct hbm_client_connect_response *connect_res;
635 struct hbm_client_connect_response *disconnect_res;
636 struct hbm_client_connect_request *disconnect_req;
637 struct hbm_flow_control *flow_control;
638 struct hbm_props_response *props_res;
639 struct hbm_host_enum_response *enum_res;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200640
641 /* read the message to our buffer */
642 BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
643 mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
644 mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
645
Tomas Winkler66ae4602014-01-08 20:19:22 +0200646 /* ignore spurious message and prevent reset nesting
647 * hbm is put to idle during system reset
648 */
649 if (dev->hbm_state == MEI_HBM_IDLE) {
650 dev_dbg(&dev->pdev->dev, "hbm: state is idle ignore spurious messages\n");
651 return 0;
652 }
653
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200654 switch (mei_msg->hbm_cmd) {
655 case HOST_START_RES_CMD:
Tomas Winkler544f9462014-01-08 20:19:21 +0200656 dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n");
657
658 dev->init_clients_timer = 0;
659
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200660 version_res = (struct hbm_host_version_response *)mei_msg;
Tomas Winkler2c9b48a2013-06-16 09:16:31 +0300661
662 dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
663 HBM_MAJOR_VERSION, HBM_MINOR_VERSION,
664 version_res->me_max_version.major_version,
665 version_res->me_max_version.minor_version);
666
667 if (version_res->host_version_supported) {
668 dev->version.major_version = HBM_MAJOR_VERSION;
669 dev->version.minor_version = HBM_MINOR_VERSION;
670 } else {
671 dev->version.major_version =
672 version_res->me_max_version.major_version;
673 dev->version.minor_version =
674 version_res->me_max_version.minor_version;
675 }
676
677 if (!mei_hbm_version_is_supported(dev)) {
Tomas Winkler544f9462014-01-08 20:19:21 +0200678 dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n");
Tomas Winklere46f1872012-12-25 19:06:10 +0200679
Tomas Winkler544f9462014-01-08 20:19:21 +0200680 dev->hbm_state = MEI_HBM_STOPPED;
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200681 if (mei_hbm_stop_req(dev)) {
Tomas Winkler544f9462014-01-08 20:19:21 +0200682 dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
683 return -EIO;
684 }
685 break;
Tomas Winklere46f1872012-12-25 19:06:10 +0200686 }
687
Tomas Winkler544f9462014-01-08 20:19:21 +0200688 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
689 dev->hbm_state != MEI_HBM_START) {
690 dev_err(&dev->pdev->dev, "hbm: start: state mismatch, [%d, %d]\n",
691 dev->dev_state, dev->hbm_state);
692 return -EPROTO;
693 }
694
695 dev->hbm_state = MEI_HBM_STARTED;
696
697 if (mei_hbm_enum_clients_req(dev)) {
698 dev_err(&dev->pdev->dev, "hbm: start: failed to send enumeration request\n");
699 return -EIO;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200700 }
701
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300702 wake_up_interruptible(&dev->wait_recvd_msg);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200703 break;
704
705 case CLIENT_CONNECT_RES_CMD:
Tomas Winkler544f9462014-01-08 20:19:21 +0200706 dev_dbg(&dev->pdev->dev, "hbm: client connect response: message received.\n");
707
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200708 connect_res = (struct hbm_client_connect_response *) mei_msg;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200709 mei_hbm_cl_connect_res(dev, connect_res);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200710 wake_up(&dev->wait_recvd_msg);
711 break;
712
713 case CLIENT_DISCONNECT_RES_CMD:
Tomas Winkler544f9462014-01-08 20:19:21 +0200714 dev_dbg(&dev->pdev->dev, "hbm: client disconnect response: message received.\n");
715
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200716 disconnect_res = (struct hbm_client_connect_response *) mei_msg;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200717 mei_hbm_cl_disconnect_res(dev, disconnect_res);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200718 wake_up(&dev->wait_recvd_msg);
719 break;
720
721 case MEI_FLOW_CONTROL_CMD:
Tomas Winkler544f9462014-01-08 20:19:21 +0200722 dev_dbg(&dev->pdev->dev, "hbm: client flow control response: message received.\n");
723
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200724 flow_control = (struct hbm_flow_control *) mei_msg;
Tomas Winkler6bbda152012-12-25 19:06:12 +0200725 mei_hbm_cl_flow_control_res(dev, flow_control);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200726 break;
727
Tomas Winkler4fcbc992014-03-18 22:51:55 +0200728 case MEI_PG_ISOLATION_ENTRY_RES_CMD:
729 dev_dbg(&dev->pdev->dev, "power gate isolation entry response received\n");
Tomas Winklerba9cdd02014-03-18 22:52:00 +0200730 dev->pg_event = MEI_PG_EVENT_RECEIVED;
Tomas Winkler4fcbc992014-03-18 22:51:55 +0200731 if (waitqueue_active(&dev->wait_pg))
732 wake_up(&dev->wait_pg);
733 break;
734
735 case MEI_PG_ISOLATION_EXIT_REQ_CMD:
736 dev_dbg(&dev->pdev->dev, "power gate isolation exit request received\n");
Tomas Winklerba9cdd02014-03-18 22:52:00 +0200737 dev->pg_event = MEI_PG_EVENT_RECEIVED;
Tomas Winkler4fcbc992014-03-18 22:51:55 +0200738 if (waitqueue_active(&dev->wait_pg))
739 wake_up(&dev->wait_pg);
Tomas Winkler180ea052014-03-18 22:52:02 +0200740 else
741 /*
742 * If the driver is not waiting on this then
743 * this is HW initiated exit from PG.
744 * Start runtime pm resume sequence to exit from PG.
745 */
746 pm_request_resume(&dev->pdev->dev);
Tomas Winkler4fcbc992014-03-18 22:51:55 +0200747 break;
748
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200749 case HOST_CLIENT_PROPERTIES_RES_CMD:
Tomas Winkler544f9462014-01-08 20:19:21 +0200750 dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n");
751
752 dev->init_clients_timer = 0;
753
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200754 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300755 dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
Tomas Winkler544f9462014-01-08 20:19:21 +0200756 dev_err(&dev->pdev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
757 dev->dev_state, dev->hbm_state);
758 return -EPROTO;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200759 }
760
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300761 props_res = (struct hbm_props_response *)mei_msg;
762
763 if (props_res->status) {
764 dev_err(&dev->pdev->dev, "hbm: properties response: wrong status = %d\n",
765 props_res->status);
766 return -EPROTO;
767 }
768
769 mei_hbm_me_cl_add(dev, props_res);
770
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200771 dev->me_client_index++;
772 dev->me_client_presentation_num++;
773
Tomas Winkler8120e722012-12-25 19:06:11 +0200774 /* request property for the next client */
Tomas Winkler544f9462014-01-08 20:19:21 +0200775 if (mei_hbm_prop_req(dev))
776 return -EIO;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200777
778 break;
779
780 case HOST_ENUM_RES_CMD:
Tomas Winkler544f9462014-01-08 20:19:21 +0200781 dev_dbg(&dev->pdev->dev, "hbm: enumeration response: message received\n");
782
783 dev->init_clients_timer = 0;
784
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200785 enum_res = (struct hbm_host_enum_response *) mei_msg;
Tomas Winkler23f5a322013-09-02 03:11:01 +0300786 BUILD_BUG_ON(sizeof(dev->me_clients_map)
787 < sizeof(enum_res->valid_addresses));
788 memcpy(dev->me_clients_map, enum_res->valid_addresses,
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300789 sizeof(enum_res->valid_addresses));
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200790
Tomas Winkler544f9462014-01-08 20:19:21 +0200791 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
792 dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {
793 dev_err(&dev->pdev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
794 dev->dev_state, dev->hbm_state);
795 return -EPROTO;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200796 }
Tomas Winkler544f9462014-01-08 20:19:21 +0200797
Tomas Winkler544f9462014-01-08 20:19:21 +0200798 dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
799
800 /* first property request */
801 if (mei_hbm_prop_req(dev))
802 return -EIO;
803
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200804 break;
805
806 case HOST_STOP_RES_CMD:
Tomas Winkler544f9462014-01-08 20:19:21 +0200807 dev_dbg(&dev->pdev->dev, "hbm: stop response: message received\n");
Tomas Winkler9b0d5ef2013-04-18 23:03:48 +0300808
Tomas Winkler544f9462014-01-08 20:19:21 +0200809 dev->init_clients_timer = 0;
810
811 if (dev->hbm_state != MEI_HBM_STOPPED) {
812 dev_err(&dev->pdev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
813 dev->dev_state, dev->hbm_state);
814 return -EPROTO;
815 }
816
Tomas Winkler33ec0822014-01-12 00:36:09 +0200817 dev->dev_state = MEI_DEV_POWER_DOWN;
Tomas Winkler544f9462014-01-08 20:19:21 +0200818 dev_info(&dev->pdev->dev, "hbm: stop response: resetting.\n");
819 /* force the reset */
820 return -EPROTO;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200821 break;
822
823 case CLIENT_DISCONNECT_REQ_CMD:
Tomas Winkler544f9462014-01-08 20:19:21 +0200824 dev_dbg(&dev->pdev->dev, "hbm: disconnect request: message received\n");
825
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200826 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
Tomas Winkler8120e722012-12-25 19:06:11 +0200827 mei_hbm_fw_disconnect_req(dev, disconnect_req);
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200828 break;
829
830 case ME_STOP_REQ_CMD:
Tomas Winkler544f9462014-01-08 20:19:21 +0200831 dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n");
Tomas Winkler544f9462014-01-08 20:19:21 +0200832 dev->hbm_state = MEI_HBM_STOPPED;
Tomas Winkler6bb948c2014-02-12 21:41:52 +0200833 if (mei_hbm_stop_req(dev)) {
834 dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
835 return -EIO;
836 }
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200837 break;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200838 default:
839 BUG();
840 break;
841
842 }
Tomas Winkler544f9462014-01-08 20:19:21 +0200843 return 0;
Tomas Winklerbb1b0132012-12-25 19:06:07 +0200844}
845