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