hbm.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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. #include <linux/pci.h>
  17. #include <linux/sched.h>
  18. #include <linux/wait.h>
  19. #include <linux/mei.h>
  20. #include "mei_dev.h"
  21. #include "interface.h"
  22. /**
  23. * mei_hbm_cl_hdr - construct client hbm header
  24. * @cl: - client
  25. * @hbm_cmd: host bus message command
  26. * @buf: buffer for cl header
  27. * @len: buffer length
  28. */
  29. static inline
  30. void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
  31. {
  32. struct mei_hbm_cl_cmd *cmd = buf;
  33. memset(cmd, 0, len);
  34. cmd->hbm_cmd = hbm_cmd;
  35. cmd->host_addr = cl->host_client_id;
  36. cmd->me_addr = cl->me_client_id;
  37. }
  38. /**
  39. * same_disconn_addr - tells if they have the same address
  40. *
  41. * @file: private data of the file object.
  42. * @disconn: disconnection request.
  43. *
  44. * returns true if addres are same
  45. */
  46. static inline
  47. bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
  48. {
  49. struct mei_hbm_cl_cmd *cmd = buf;
  50. return cl->host_client_id == cmd->host_addr &&
  51. cl->me_client_id == cmd->me_addr;
  52. }
  53. /**
  54. * host_start_message - mei host sends start message.
  55. *
  56. * @dev: the device structure
  57. *
  58. * returns none.
  59. */
  60. void mei_host_start_message(struct mei_device *dev)
  61. {
  62. struct mei_msg_hdr *mei_hdr;
  63. struct hbm_host_version_request *start_req;
  64. const size_t len = sizeof(struct hbm_host_version_request);
  65. mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
  66. /* host start message */
  67. start_req = (struct hbm_host_version_request *)&dev->wr_msg_buf[1];
  68. memset(start_req, 0, len);
  69. start_req->hbm_cmd = HOST_START_REQ_CMD;
  70. start_req->host_version.major_version = HBM_MAJOR_VERSION;
  71. start_req->host_version.minor_version = HBM_MINOR_VERSION;
  72. dev->recvd_msg = false;
  73. if (mei_write_message(dev, mei_hdr, (unsigned char *)start_req)) {
  74. dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
  75. dev->dev_state = MEI_DEV_RESETING;
  76. mei_reset(dev, 1);
  77. }
  78. dev->init_clients_state = MEI_START_MESSAGE;
  79. dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
  80. return ;
  81. }
  82. /**
  83. * host_enum_clients_message - host sends enumeration client request message.
  84. *
  85. * @dev: the device structure
  86. *
  87. * returns none.
  88. */
  89. void mei_host_enum_clients_message(struct mei_device *dev)
  90. {
  91. struct mei_msg_hdr *mei_hdr;
  92. struct hbm_host_enum_request *enum_req;
  93. const size_t len = sizeof(struct hbm_host_enum_request);
  94. /* enumerate clients */
  95. mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
  96. enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
  97. memset(enum_req, 0, sizeof(struct hbm_host_enum_request));
  98. enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
  99. if (mei_write_message(dev, mei_hdr, (unsigned char *)enum_req)) {
  100. dev->dev_state = MEI_DEV_RESETING;
  101. dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
  102. mei_reset(dev, 1);
  103. }
  104. dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
  105. dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
  106. return;
  107. }
  108. int mei_host_client_enumerate(struct mei_device *dev)
  109. {
  110. struct mei_msg_hdr *mei_hdr;
  111. struct hbm_props_request *prop_req;
  112. const size_t len = sizeof(struct hbm_props_request);
  113. unsigned long next_client_index;
  114. u8 client_num;
  115. client_num = dev->me_client_presentation_num;
  116. next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
  117. dev->me_client_index);
  118. /* We got all client properties */
  119. if (next_client_index == MEI_CLIENTS_MAX) {
  120. schedule_work(&dev->init_work);
  121. return 0;
  122. }
  123. dev->me_clients[client_num].client_id = next_client_index;
  124. dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
  125. mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
  126. prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1];
  127. memset(prop_req, 0, sizeof(struct hbm_props_request));
  128. prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
  129. prop_req->address = next_client_index;
  130. if (mei_write_message(dev, mei_hdr, (unsigned char *) prop_req)) {
  131. dev->dev_state = MEI_DEV_RESETING;
  132. dev_err(&dev->pdev->dev, "Properties request command failed\n");
  133. mei_reset(dev, 1);
  134. return -EIO;
  135. }
  136. dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
  137. dev->me_client_index = next_client_index;
  138. return 0;
  139. }
  140. /**
  141. * mei_send_flow_control - sends flow control to fw.
  142. *
  143. * @dev: the device structure
  144. * @cl: private data of the file object
  145. *
  146. * This function returns -EIO on write failure
  147. */
  148. int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
  149. {
  150. struct mei_msg_hdr *mei_hdr;
  151. unsigned char *buf = (unsigned char *)&dev->wr_msg_buf[1];
  152. const size_t len = sizeof(struct hbm_flow_control);
  153. mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
  154. mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, buf, len);
  155. dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
  156. cl->host_client_id, cl->me_client_id);
  157. return mei_write_message(dev, mei_hdr, buf);
  158. }
  159. /**
  160. * mei_disconnect - sends disconnect message to fw.
  161. *
  162. * @dev: the device structure
  163. * @cl: private data of the file object
  164. *
  165. * This function returns -EIO on write failure
  166. */
  167. int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
  168. {
  169. struct mei_msg_hdr *hdr;
  170. unsigned char *buf = (unsigned char *)&dev->wr_msg_buf[1];
  171. const size_t len = sizeof(struct hbm_client_connect_request);
  172. hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
  173. mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, buf, len);
  174. return mei_write_message(dev, hdr, buf);
  175. }
  176. /**
  177. * mei_connect - sends connect message to fw.
  178. *
  179. * @dev: the device structure
  180. * @cl: private data of the file object
  181. *
  182. * This function returns -EIO on write failure
  183. */
  184. int mei_connect(struct mei_device *dev, struct mei_cl *cl)
  185. {
  186. struct mei_msg_hdr *hdr;
  187. unsigned char *buf = (unsigned char *)&dev->wr_msg_buf[1];
  188. const size_t len = sizeof(struct hbm_client_connect_request);
  189. hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
  190. mei_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, buf, len);
  191. return mei_write_message(dev, hdr, buf);
  192. }
  193. /**
  194. * mei_client_disconnect_request - disconnects from request irq routine
  195. *
  196. * @dev: the device structure.
  197. * @disconnect_req: disconnect request bus message.
  198. */
  199. static void mei_client_disconnect_request(struct mei_device *dev,
  200. struct hbm_client_connect_request *disconnect_req)
  201. {
  202. struct mei_cl *cl, *next;
  203. const size_t len = sizeof(struct hbm_client_connect_response);
  204. list_for_each_entry_safe(cl, next, &dev->file_list, link) {
  205. if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
  206. dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
  207. disconnect_req->host_addr,
  208. disconnect_req->me_addr);
  209. cl->state = MEI_FILE_DISCONNECTED;
  210. cl->timer_count = 0;
  211. if (cl == &dev->wd_cl)
  212. dev->wd_pending = false;
  213. else if (cl == &dev->iamthif_cl)
  214. dev->iamthif_timer = 0;
  215. /* prepare disconnect response */
  216. (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
  217. mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD,
  218. &dev->wr_ext_msg.data, len);
  219. break;
  220. }
  221. }
  222. }
  223. /**
  224. * mei_hbm_dispatch - bottom half read routine after ISR to
  225. * handle the read bus message cmd processing.
  226. *
  227. * @dev: the device structure
  228. * @mei_hdr: header of bus message
  229. */
  230. void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
  231. {
  232. struct mei_bus_message *mei_msg;
  233. struct mei_me_client *me_client;
  234. struct hbm_host_version_response *version_res;
  235. struct hbm_client_connect_response *connect_res;
  236. struct hbm_client_connect_response *disconnect_res;
  237. struct hbm_client_connect_request *disconnect_req;
  238. struct hbm_flow_control *flow_control;
  239. struct hbm_props_response *props_res;
  240. struct hbm_host_enum_response *enum_res;
  241. struct hbm_host_stop_request *stop_req;
  242. /* read the message to our buffer */
  243. BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
  244. mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
  245. mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
  246. switch (mei_msg->hbm_cmd) {
  247. case HOST_START_RES_CMD:
  248. version_res = (struct hbm_host_version_response *)mei_msg;
  249. if (version_res->host_version_supported) {
  250. dev->version.major_version = HBM_MAJOR_VERSION;
  251. dev->version.minor_version = HBM_MINOR_VERSION;
  252. if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
  253. dev->init_clients_state == MEI_START_MESSAGE) {
  254. dev->init_clients_timer = 0;
  255. mei_host_enum_clients_message(dev);
  256. } else {
  257. dev->recvd_msg = false;
  258. dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
  259. mei_reset(dev, 1);
  260. return;
  261. }
  262. } else {
  263. u32 *buf = dev->wr_msg_buf;
  264. const size_t len = sizeof(struct hbm_host_stop_request);
  265. dev->version = version_res->me_max_version;
  266. /* send stop message */
  267. hdr = mei_hbm_hdr(&buf[0], len);
  268. stop_req = (struct hbm_host_stop_request *)&buf[1];
  269. memset(stop_req, 0, len);
  270. stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
  271. stop_req->reason = DRIVER_STOP_REQUEST;
  272. mei_write_message(dev, hdr, (unsigned char *)stop_req);
  273. dev_dbg(&dev->pdev->dev, "version mismatch.\n");
  274. return;
  275. }
  276. dev->recvd_msg = true;
  277. dev_dbg(&dev->pdev->dev, "host start response message received.\n");
  278. break;
  279. case CLIENT_CONNECT_RES_CMD:
  280. connect_res = (struct hbm_client_connect_response *) mei_msg;
  281. mei_client_connect_response(dev, connect_res);
  282. dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
  283. wake_up(&dev->wait_recvd_msg);
  284. break;
  285. case CLIENT_DISCONNECT_RES_CMD:
  286. disconnect_res = (struct hbm_client_connect_response *) mei_msg;
  287. mei_client_disconnect_response(dev, disconnect_res);
  288. dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
  289. wake_up(&dev->wait_recvd_msg);
  290. break;
  291. case MEI_FLOW_CONTROL_CMD:
  292. flow_control = (struct hbm_flow_control *) mei_msg;
  293. mei_client_flow_control_response(dev, flow_control);
  294. dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
  295. break;
  296. case HOST_CLIENT_PROPERTIES_RES_CMD:
  297. props_res = (struct hbm_props_response *)mei_msg;
  298. me_client = &dev->me_clients[dev->me_client_presentation_num];
  299. if (props_res->status || !dev->me_clients) {
  300. dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
  301. mei_reset(dev, 1);
  302. return;
  303. }
  304. if (me_client->client_id != props_res->address) {
  305. dev_err(&dev->pdev->dev,
  306. "Host client properties reply mismatch\n");
  307. mei_reset(dev, 1);
  308. return;
  309. }
  310. if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
  311. dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
  312. dev_err(&dev->pdev->dev,
  313. "Unexpected client properties reply\n");
  314. mei_reset(dev, 1);
  315. return;
  316. }
  317. me_client->props = props_res->client_properties;
  318. dev->me_client_index++;
  319. dev->me_client_presentation_num++;
  320. mei_host_client_enumerate(dev);
  321. break;
  322. case HOST_ENUM_RES_CMD:
  323. enum_res = (struct hbm_host_enum_response *) mei_msg;
  324. memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
  325. if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
  326. dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
  327. dev->init_clients_timer = 0;
  328. dev->me_client_presentation_num = 0;
  329. dev->me_client_index = 0;
  330. mei_allocate_me_clients_storage(dev);
  331. dev->init_clients_state =
  332. MEI_CLIENT_PROPERTIES_MESSAGE;
  333. mei_host_client_enumerate(dev);
  334. } else {
  335. dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
  336. mei_reset(dev, 1);
  337. return;
  338. }
  339. break;
  340. case HOST_STOP_RES_CMD:
  341. dev->dev_state = MEI_DEV_DISABLED;
  342. dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
  343. mei_reset(dev, 1);
  344. break;
  345. case CLIENT_DISCONNECT_REQ_CMD:
  346. /* search for client */
  347. disconnect_req = (struct hbm_client_connect_request *)mei_msg;
  348. mei_client_disconnect_request(dev, disconnect_req);
  349. break;
  350. case ME_STOP_REQ_CMD:
  351. {
  352. /* prepare stop request: sent in next interrupt event */
  353. const size_t len = sizeof(struct hbm_host_stop_request);
  354. hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
  355. stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data;
  356. memset(stop_req, 0, len);
  357. stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
  358. stop_req->reason = DRIVER_STOP_REQUEST;
  359. break;
  360. }
  361. default:
  362. BUG();
  363. break;
  364. }
  365. }