mei: add common prefix to hbm function
[linux-2.6/btrfs-unstable.git] / drivers / misc / mei / hbm.c
blob3c9914038490f97cd47d7785b6493cab5d58f74c
1 /*
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2012, Intel Corporation.
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.
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.
17 #include <linux/pci.h>
18 #include <linux/sched.h>
19 #include <linux/wait.h>
20 #include <linux/mei.h>
22 #include "mei_dev.h"
23 #include "interface.h"
25 /**
26 * mei_hbm_cl_hdr - construct client hbm header
27 * @cl: - client
28 * @hbm_cmd: host bus message command
29 * @buf: buffer for cl header
30 * @len: buffer length
32 static inline
33 void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
35 struct mei_hbm_cl_cmd *cmd = buf;
37 memset(cmd, 0, len);
39 cmd->hbm_cmd = hbm_cmd;
40 cmd->host_addr = cl->host_client_id;
41 cmd->me_addr = cl->me_client_id;
44 /**
45 * same_disconn_addr - tells if they have the same address
47 * @file: private data of the file object.
48 * @disconn: disconnection request.
50 * returns true if addres are same
52 static inline
53 bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
55 struct mei_hbm_cl_cmd *cmd = buf;
56 return cl->host_client_id == cmd->host_addr &&
57 cl->me_client_id == cmd->me_addr;
61 /**
62 * mei_hbm_start_req - sends start request message.
64 * @dev: the device structure
66 void mei_hbm_start_req(struct mei_device *dev)
68 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
69 struct hbm_host_version_request *start_req;
70 const size_t len = sizeof(struct hbm_host_version_request);
72 mei_hbm_hdr(mei_hdr, len);
74 /* host start message */
75 start_req = (struct hbm_host_version_request *)dev->wr_msg.data;
76 memset(start_req, 0, len);
77 start_req->hbm_cmd = HOST_START_REQ_CMD;
78 start_req->host_version.major_version = HBM_MAJOR_VERSION;
79 start_req->host_version.minor_version = HBM_MINOR_VERSION;
81 dev->recvd_msg = false;
82 if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
83 dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
84 dev->dev_state = MEI_DEV_RESETING;
85 mei_reset(dev, 1);
87 dev->init_clients_state = MEI_START_MESSAGE;
88 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
89 return ;
92 /**
93 * mei_hbm_enum_clients_req - sends enumeration client request message.
95 * @dev: the device structure
97 * returns none.
99 static void mei_hbm_enum_clients_req(struct mei_device *dev)
101 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
102 struct hbm_host_enum_request *enum_req;
103 const size_t len = sizeof(struct hbm_host_enum_request);
104 /* enumerate clients */
105 mei_hbm_hdr(mei_hdr, len);
107 enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
108 memset(enum_req, 0, len);
109 enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
111 if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
112 dev->dev_state = MEI_DEV_RESETING;
113 dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
114 mei_reset(dev, 1);
116 dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
117 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
118 return;
122 * mei_hbm_prop_requsest - request property for a single client
124 * @dev: the device structure
126 * returns none.
129 static int mei_hbm_prop_req(struct mei_device *dev)
132 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
133 struct hbm_props_request *prop_req;
134 const size_t len = sizeof(struct hbm_props_request);
135 unsigned long next_client_index;
136 u8 client_num;
139 client_num = dev->me_client_presentation_num;
141 next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
142 dev->me_client_index);
144 /* We got all client properties */
145 if (next_client_index == MEI_CLIENTS_MAX) {
146 schedule_work(&dev->init_work);
148 return 0;
151 dev->me_clients[client_num].client_id = next_client_index;
152 dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
154 mei_hbm_hdr(mei_hdr, len);
155 prop_req = (struct hbm_props_request *)dev->wr_msg.data;
157 memset(prop_req, 0, sizeof(struct hbm_props_request));
160 prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
161 prop_req->address = next_client_index;
163 if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
164 dev->dev_state = MEI_DEV_RESETING;
165 dev_err(&dev->pdev->dev, "Properties request command failed\n");
166 mei_reset(dev, 1);
168 return -EIO;
171 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
172 dev->me_client_index = next_client_index;
174 return 0;
178 * mei_hbm_stop_req_prepare - perpare stop request message
180 * @dev - mei device
181 * @mei_hdr - mei message header
182 * @data - hbm message body buffer
184 static void mei_hbm_stop_req_prepare(struct mei_device *dev,
185 struct mei_msg_hdr *mei_hdr, unsigned char *data)
187 struct hbm_host_stop_request *req =
188 (struct hbm_host_stop_request *)data;
189 const size_t len = sizeof(struct hbm_host_stop_request);
191 mei_hbm_hdr(mei_hdr, len);
193 memset(req, 0, len);
194 req->hbm_cmd = HOST_STOP_REQ_CMD;
195 req->reason = DRIVER_STOP_REQUEST;
199 * mei_hbm_cl_flow_control_req - sends flow control requst.
201 * @dev: the device structure
202 * @cl: client info
204 * This function returns -EIO on write failure
206 int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
208 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
209 const size_t len = sizeof(struct hbm_flow_control);
211 mei_hbm_hdr(mei_hdr, len);
212 mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len);
214 dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
215 cl->host_client_id, cl->me_client_id);
217 return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
221 * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
223 * @dev: the device structure
224 * @cl: a client to disconnect from
226 * This function returns -EIO on write failure
228 int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
230 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
231 const size_t len = sizeof(struct hbm_client_connect_request);
233 mei_hbm_hdr(mei_hdr, len);
234 mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, dev->wr_msg.data, len);
236 return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
240 * mei_hbm_cl_connect_req - send connection request to specific me client
242 * @dev: the device structure
243 * @cl: a client to connect to
245 * returns -EIO on write failure
247 int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
249 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
250 const size_t len = sizeof(struct hbm_client_connect_request);
252 mei_hbm_hdr(mei_hdr, len);
253 mei_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, dev->wr_msg.data, len);
255 return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
259 * mei_client_disconnect_request - disconnect request initiated by me
260 * host sends disoconnect response
262 * @dev: the device structure.
263 * @disconnect_req: disconnect request bus message from the me
265 static void mei_hbm_fw_disconnect_req(struct mei_device *dev,
266 struct hbm_client_connect_request *disconnect_req)
268 struct mei_cl *cl, *next;
269 const size_t len = sizeof(struct hbm_client_connect_response);
271 list_for_each_entry_safe(cl, next, &dev->file_list, link) {
272 if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
273 dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
274 disconnect_req->host_addr,
275 disconnect_req->me_addr);
276 cl->state = MEI_FILE_DISCONNECTED;
277 cl->timer_count = 0;
278 if (cl == &dev->wd_cl)
279 dev->wd_pending = false;
280 else if (cl == &dev->iamthif_cl)
281 dev->iamthif_timer = 0;
283 /* prepare disconnect response */
284 mei_hbm_hdr(&dev->wr_ext_msg.hdr, len);
285 mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD,
286 dev->wr_ext_msg.data, len);
287 break;
294 * mei_hbm_dispatch - bottom half read routine after ISR to
295 * handle the read bus message cmd processing.
297 * @dev: the device structure
298 * @mei_hdr: header of bus message
300 void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
302 struct mei_bus_message *mei_msg;
303 struct mei_me_client *me_client;
304 struct hbm_host_version_response *version_res;
305 struct hbm_client_connect_response *connect_res;
306 struct hbm_client_connect_response *disconnect_res;
307 struct hbm_client_connect_request *disconnect_req;
308 struct hbm_flow_control *flow_control;
309 struct hbm_props_response *props_res;
310 struct hbm_host_enum_response *enum_res;
312 /* read the message to our buffer */
313 BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
314 mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
315 mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
317 switch (mei_msg->hbm_cmd) {
318 case HOST_START_RES_CMD:
319 version_res = (struct hbm_host_version_response *)mei_msg;
320 if (!version_res->host_version_supported) {
321 dev->version = version_res->me_max_version;
322 dev_dbg(&dev->pdev->dev, "version mismatch.\n");
324 mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
325 dev->wr_msg.data);
326 mei_write_message(dev, &dev->wr_msg.hdr,
327 dev->wr_msg.data);
328 return;
331 dev->version.major_version = HBM_MAJOR_VERSION;
332 dev->version.minor_version = HBM_MINOR_VERSION;
333 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
334 dev->init_clients_state == MEI_START_MESSAGE) {
335 dev->init_clients_timer = 0;
336 mei_hbm_enum_clients_req(dev);
337 } else {
338 dev->recvd_msg = false;
339 dev_dbg(&dev->pdev->dev, "reset due to received hbm: host start\n");
340 mei_reset(dev, 1);
341 return;
344 dev->recvd_msg = true;
345 dev_dbg(&dev->pdev->dev, "host start response message received.\n");
346 break;
348 case CLIENT_CONNECT_RES_CMD:
349 connect_res = (struct hbm_client_connect_response *) mei_msg;
350 mei_client_connect_response(dev, connect_res);
351 dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
352 wake_up(&dev->wait_recvd_msg);
353 break;
355 case CLIENT_DISCONNECT_RES_CMD:
356 disconnect_res = (struct hbm_client_connect_response *) mei_msg;
357 mei_client_disconnect_response(dev, disconnect_res);
358 dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
359 wake_up(&dev->wait_recvd_msg);
360 break;
362 case MEI_FLOW_CONTROL_CMD:
363 flow_control = (struct hbm_flow_control *) mei_msg;
364 mei_client_flow_control_response(dev, flow_control);
365 dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
366 break;
368 case HOST_CLIENT_PROPERTIES_RES_CMD:
369 props_res = (struct hbm_props_response *)mei_msg;
370 me_client = &dev->me_clients[dev->me_client_presentation_num];
372 if (props_res->status || !dev->me_clients) {
373 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
374 mei_reset(dev, 1);
375 return;
378 if (me_client->client_id != props_res->address) {
379 dev_err(&dev->pdev->dev,
380 "Host client properties reply mismatch\n");
381 mei_reset(dev, 1);
383 return;
386 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
387 dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
388 dev_err(&dev->pdev->dev,
389 "Unexpected client properties reply\n");
390 mei_reset(dev, 1);
392 return;
395 me_client->props = props_res->client_properties;
396 dev->me_client_index++;
397 dev->me_client_presentation_num++;
399 /* request property for the next client */
400 mei_hbm_prop_req(dev);
402 break;
404 case HOST_ENUM_RES_CMD:
405 enum_res = (struct hbm_host_enum_response *) mei_msg;
406 memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
407 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
408 dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
409 dev->init_clients_timer = 0;
410 dev->me_client_presentation_num = 0;
411 dev->me_client_index = 0;
412 mei_allocate_me_clients_storage(dev);
413 dev->init_clients_state =
414 MEI_CLIENT_PROPERTIES_MESSAGE;
416 /* first property reqeust */
417 mei_hbm_prop_req(dev);
418 } else {
419 dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
420 mei_reset(dev, 1);
421 return;
423 break;
425 case HOST_STOP_RES_CMD:
426 dev->dev_state = MEI_DEV_DISABLED;
427 dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
428 mei_reset(dev, 1);
429 break;
431 case CLIENT_DISCONNECT_REQ_CMD:
432 /* search for client */
433 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
434 mei_hbm_fw_disconnect_req(dev, disconnect_req);
435 break;
437 case ME_STOP_REQ_CMD:
439 mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
440 dev->wr_ext_msg.data);
441 break;
442 default:
443 BUG();
444 break;