iorw.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  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/kernel.h>
  17. #include <linux/fs.h>
  18. #include <linux/errno.h>
  19. #include <linux/types.h>
  20. #include <linux/fcntl.h>
  21. #include <linux/aio.h>
  22. #include <linux/pci.h>
  23. #include <linux/init.h>
  24. #include <linux/ioctl.h>
  25. #include <linux/cdev.h>
  26. #include <linux/list.h>
  27. #include <linux/delay.h>
  28. #include <linux/sched.h>
  29. #include <linux/uuid.h>
  30. #include <linux/jiffies.h>
  31. #include <linux/uaccess.h>
  32. #include "mei_dev.h"
  33. #include "hw.h"
  34. #include <linux/mei.h>
  35. #include "interface.h"
  36. /**
  37. * mei_io_cb_free - free mei_cb_private related memory
  38. *
  39. * @cb: mei callback struct
  40. */
  41. void mei_io_cb_free(struct mei_cl_cb *cb)
  42. {
  43. if (cb == NULL)
  44. return;
  45. kfree(cb->request_buffer.data);
  46. kfree(cb->response_buffer.data);
  47. kfree(cb);
  48. }
  49. /**
  50. * mei_io_cb_init - allocate and initialize io callback
  51. *
  52. * @cl - mei client
  53. * @file: pointer to file structure
  54. *
  55. * returns mei_cl_cb pointer or NULL;
  56. */
  57. struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
  58. {
  59. struct mei_cl_cb *cb;
  60. cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
  61. if (!cb)
  62. return NULL;
  63. mei_io_list_init(cb);
  64. cb->file_object = fp;
  65. cb->cl = cl;
  66. cb->buf_idx = 0;
  67. return cb;
  68. }
  69. /**
  70. * mei_io_cb_alloc_req_buf - allocate request buffer
  71. *
  72. * @cb - io callback structure
  73. * @size: size of the buffer
  74. *
  75. * returns 0 on success
  76. * -EINVAL if cb is NULL
  77. * -ENOMEM if allocation failed
  78. */
  79. int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
  80. {
  81. if (!cb)
  82. return -EINVAL;
  83. if (length == 0)
  84. return 0;
  85. cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
  86. if (!cb->request_buffer.data)
  87. return -ENOMEM;
  88. cb->request_buffer.size = length;
  89. return 0;
  90. }
  91. /**
  92. * mei_io_cb_alloc_req_buf - allocate respose buffer
  93. *
  94. * @cb - io callback structure
  95. * @size: size of the buffer
  96. *
  97. * returns 0 on success
  98. * -EINVAL if cb is NULL
  99. * -ENOMEM if allocation failed
  100. */
  101. int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
  102. {
  103. if (!cb)
  104. return -EINVAL;
  105. if (length == 0)
  106. return 0;
  107. cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
  108. if (!cb->response_buffer.data)
  109. return -ENOMEM;
  110. cb->response_buffer.size = length;
  111. return 0;
  112. }
  113. /**
  114. * mei_me_cl_by_id return index to me_clients for client_id
  115. *
  116. * @dev: the device structure
  117. * @client_id: me client id
  118. *
  119. * Locking: called under "dev->device_lock" lock
  120. *
  121. * returns index on success, -ENOENT on failure.
  122. */
  123. int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
  124. {
  125. int i;
  126. for (i = 0; i < dev->me_clients_num; i++)
  127. if (dev->me_clients[i].client_id == client_id)
  128. break;
  129. if (WARN_ON(dev->me_clients[i].client_id != client_id))
  130. return -ENOENT;
  131. if (i == dev->me_clients_num)
  132. return -ENOENT;
  133. return i;
  134. }
  135. /**
  136. * mei_ioctl_connect_client - the connect to fw client IOCTL function
  137. *
  138. * @dev: the device structure
  139. * @data: IOCTL connect data, input and output parameters
  140. * @file: private data of the file object
  141. *
  142. * Locking: called under "dev->device_lock" lock
  143. *
  144. * returns 0 on success, <0 on failure.
  145. */
  146. int mei_ioctl_connect_client(struct file *file,
  147. struct mei_connect_client_data *data)
  148. {
  149. struct mei_device *dev;
  150. struct mei_cl_cb *cb;
  151. struct mei_client *client;
  152. struct mei_cl *cl;
  153. long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT);
  154. int i;
  155. int err;
  156. int rets;
  157. cl = file->private_data;
  158. if (WARN_ON(!cl || !cl->dev))
  159. return -ENODEV;
  160. dev = cl->dev;
  161. dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n");
  162. /* buffered ioctl cb */
  163. cb = mei_io_cb_init(cl, file);
  164. if (!cb) {
  165. rets = -ENOMEM;
  166. goto end;
  167. }
  168. cb->fop_type = MEI_FOP_IOCTL;
  169. if (dev->dev_state != MEI_DEV_ENABLED) {
  170. rets = -ENODEV;
  171. goto end;
  172. }
  173. if (cl->state != MEI_FILE_INITIALIZING &&
  174. cl->state != MEI_FILE_DISCONNECTED) {
  175. rets = -EBUSY;
  176. goto end;
  177. }
  178. /* find ME client we're trying to connect to */
  179. i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
  180. if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
  181. cl->me_client_id = dev->me_clients[i].client_id;
  182. cl->state = MEI_FILE_CONNECTING;
  183. }
  184. dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
  185. cl->me_client_id);
  186. dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
  187. dev->me_clients[i].props.protocol_version);
  188. dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
  189. dev->me_clients[i].props.max_msg_length);
  190. /* if we're connecting to amthi client then we will use the
  191. * existing connection
  192. */
  193. if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
  194. dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
  195. if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
  196. rets = -ENODEV;
  197. goto end;
  198. }
  199. clear_bit(cl->host_client_id, dev->host_clients_map);
  200. mei_me_cl_unlink(dev, cl);
  201. kfree(cl);
  202. cl = NULL;
  203. file->private_data = &dev->iamthif_cl;
  204. client = &data->out_client_properties;
  205. client->max_msg_length =
  206. dev->me_clients[i].props.max_msg_length;
  207. client->protocol_version =
  208. dev->me_clients[i].props.protocol_version;
  209. rets = dev->iamthif_cl.status;
  210. goto end;
  211. }
  212. if (cl->state != MEI_FILE_CONNECTING) {
  213. rets = -ENODEV;
  214. goto end;
  215. }
  216. /* prepare the output buffer */
  217. client = &data->out_client_properties;
  218. client->max_msg_length = dev->me_clients[i].props.max_msg_length;
  219. client->protocol_version = dev->me_clients[i].props.protocol_version;
  220. dev_dbg(&dev->pdev->dev, "Can connect?\n");
  221. if (dev->mei_host_buffer_is_empty
  222. && !mei_other_client_is_connecting(dev, cl)) {
  223. dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
  224. dev->mei_host_buffer_is_empty = false;
  225. if (mei_connect(dev, cl)) {
  226. dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
  227. rets = -ENODEV;
  228. goto end;
  229. } else {
  230. dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n");
  231. cl->timer_count = MEI_CONNECT_TIMEOUT;
  232. list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
  233. }
  234. } else {
  235. dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n");
  236. dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n");
  237. list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
  238. }
  239. mutex_unlock(&dev->device_lock);
  240. err = wait_event_timeout(dev->wait_recvd_msg,
  241. (MEI_FILE_CONNECTED == cl->state ||
  242. MEI_FILE_DISCONNECTED == cl->state), timeout);
  243. mutex_lock(&dev->device_lock);
  244. if (MEI_FILE_CONNECTED == cl->state) {
  245. dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n");
  246. rets = cl->status;
  247. goto end;
  248. } else {
  249. dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n",
  250. cl->state);
  251. if (!err) {
  252. dev_dbg(&dev->pdev->dev,
  253. "wait_event_interruptible_timeout failed on client"
  254. " connect message fw response message.\n");
  255. }
  256. rets = -EFAULT;
  257. mei_io_list_flush(&dev->ctrl_rd_list, cl);
  258. mei_io_list_flush(&dev->ctrl_wr_list, cl);
  259. goto end;
  260. }
  261. rets = 0;
  262. end:
  263. dev_dbg(&dev->pdev->dev, "free connect cb memory.");
  264. mei_io_cb_free(cb);
  265. return rets;
  266. }
  267. /**
  268. * mei_start_read - the start read client message function.
  269. *
  270. * @dev: the device structure
  271. * @if_num: minor number
  272. * @cl: private data of the file object
  273. *
  274. * returns 0 on success, <0 on failure.
  275. */
  276. int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
  277. {
  278. struct mei_cl_cb *cb;
  279. int rets;
  280. int i;
  281. if (cl->state != MEI_FILE_CONNECTED)
  282. return -ENODEV;
  283. if (dev->dev_state != MEI_DEV_ENABLED)
  284. return -ENODEV;
  285. if (cl->read_pending || cl->read_cb) {
  286. dev_dbg(&dev->pdev->dev, "read is pending.\n");
  287. return -EBUSY;
  288. }
  289. i = mei_me_cl_by_id(dev, cl->me_client_id);
  290. if (i < 0) {
  291. dev_err(&dev->pdev->dev, "no such me client %d\n",
  292. cl->me_client_id);
  293. return -ENODEV;
  294. }
  295. cb = mei_io_cb_init(cl, NULL);
  296. if (!cb)
  297. return -ENOMEM;
  298. rets = mei_io_cb_alloc_resp_buf(cb,
  299. dev->me_clients[i].props.max_msg_length);
  300. if (rets)
  301. goto err;
  302. cb->fop_type = MEI_FOP_READ;
  303. cl->read_cb = cb;
  304. if (dev->mei_host_buffer_is_empty) {
  305. dev->mei_host_buffer_is_empty = false;
  306. if (mei_send_flow_control(dev, cl)) {
  307. rets = -ENODEV;
  308. goto err;
  309. }
  310. list_add_tail(&cb->list, &dev->read_list.list);
  311. } else {
  312. list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
  313. }
  314. return rets;
  315. err:
  316. mei_io_cb_free(cb);
  317. return rets;
  318. }