hbm.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  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/export.h>
  17. #include <linux/sched.h>
  18. #include <linux/wait.h>
  19. #include <linux/pm_runtime.h>
  20. #include <linux/slab.h>
  21. #include <linux/mei.h>
  22. #include "mei_dev.h"
  23. #include "hbm.h"
  24. #include "client.h"
  25. static const char *mei_hbm_status_str(enum mei_hbm_status status)
  26. {
  27. #define MEI_HBM_STATUS(status) case MEI_HBMS_##status: return #status
  28. switch (status) {
  29. MEI_HBM_STATUS(SUCCESS);
  30. MEI_HBM_STATUS(CLIENT_NOT_FOUND);
  31. MEI_HBM_STATUS(ALREADY_EXISTS);
  32. MEI_HBM_STATUS(REJECTED);
  33. MEI_HBM_STATUS(INVALID_PARAMETER);
  34. MEI_HBM_STATUS(NOT_ALLOWED);
  35. MEI_HBM_STATUS(ALREADY_STARTED);
  36. MEI_HBM_STATUS(NOT_STARTED);
  37. default: return "unknown";
  38. }
  39. #undef MEI_HBM_STATUS
  40. };
  41. static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
  42. {
  43. #define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
  44. switch (status) {
  45. MEI_CL_CS(SUCCESS);
  46. MEI_CL_CS(NOT_FOUND);
  47. MEI_CL_CS(ALREADY_STARTED);
  48. MEI_CL_CS(OUT_OF_RESOURCES);
  49. MEI_CL_CS(MESSAGE_SMALL);
  50. default: return "unknown";
  51. }
  52. #undef MEI_CL_CCS
  53. }
  54. const char *mei_hbm_state_str(enum mei_hbm_state state)
  55. {
  56. #define MEI_HBM_STATE(state) case MEI_HBM_##state: return #state
  57. switch (state) {
  58. MEI_HBM_STATE(IDLE);
  59. MEI_HBM_STATE(STARTING);
  60. MEI_HBM_STATE(STARTED);
  61. MEI_HBM_STATE(ENUM_CLIENTS);
  62. MEI_HBM_STATE(CLIENT_PROPERTIES);
  63. MEI_HBM_STATE(STOPPED);
  64. default:
  65. return "unknown";
  66. }
  67. #undef MEI_HBM_STATE
  68. }
  69. /**
  70. * mei_cl_conn_status_to_errno - convert client connect response
  71. * status to error code
  72. *
  73. * @status: client connect response status
  74. *
  75. * Return: corresponding error code
  76. */
  77. static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
  78. {
  79. switch (status) {
  80. case MEI_CL_CONN_SUCCESS: return 0;
  81. case MEI_CL_CONN_NOT_FOUND: return -ENOTTY;
  82. case MEI_CL_CONN_ALREADY_STARTED: return -EBUSY;
  83. case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
  84. case MEI_CL_CONN_MESSAGE_SMALL: return -EINVAL;
  85. default: return -EINVAL;
  86. }
  87. }
  88. /**
  89. * mei_hbm_idle - set hbm to idle state
  90. *
  91. * @dev: the device structure
  92. */
  93. void mei_hbm_idle(struct mei_device *dev)
  94. {
  95. dev->init_clients_timer = 0;
  96. dev->hbm_state = MEI_HBM_IDLE;
  97. }
  98. /**
  99. * mei_hbm_reset - reset hbm counters and book keeping data structurs
  100. *
  101. * @dev: the device structure
  102. */
  103. void mei_hbm_reset(struct mei_device *dev)
  104. {
  105. dev->me_client_index = 0;
  106. mei_me_cl_rm_all(dev);
  107. mei_hbm_idle(dev);
  108. }
  109. /**
  110. * mei_hbm_hdr - construct hbm header
  111. *
  112. * @hdr: hbm header
  113. * @length: payload length
  114. */
  115. static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
  116. {
  117. hdr->host_addr = 0;
  118. hdr->me_addr = 0;
  119. hdr->length = length;
  120. hdr->msg_complete = 1;
  121. hdr->reserved = 0;
  122. }
  123. /**
  124. * mei_hbm_cl_hdr - construct client hbm header
  125. *
  126. * @cl: client
  127. * @hbm_cmd: host bus message command
  128. * @buf: buffer for cl header
  129. * @len: buffer length
  130. */
  131. static inline
  132. void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
  133. {
  134. struct mei_hbm_cl_cmd *cmd = buf;
  135. memset(cmd, 0, len);
  136. cmd->hbm_cmd = hbm_cmd;
  137. cmd->host_addr = cl->host_client_id;
  138. cmd->me_addr = cl->me_client_id;
  139. }
  140. /**
  141. * mei_hbm_cl_write - write simple hbm client message
  142. *
  143. * @dev: the device structure
  144. * @cl: client
  145. * @hbm_cmd: host bus message command
  146. * @len: buffer length
  147. *
  148. * Return: 0 on success, <0 on failure.
  149. */
  150. static inline
  151. int mei_hbm_cl_write(struct mei_device *dev,
  152. struct mei_cl *cl, u8 hbm_cmd, size_t len)
  153. {
  154. struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
  155. mei_hbm_hdr(mei_hdr, len);
  156. mei_hbm_cl_hdr(cl, hbm_cmd, dev->wr_msg.data, len);
  157. return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
  158. }
  159. /**
  160. * mei_hbm_cl_addr_equal - check if the client's and
  161. * the message address match
  162. *
  163. * @cl: client
  164. * @cmd: hbm client message
  165. *
  166. * Return: true if addresses are the same
  167. */
  168. static inline
  169. bool mei_hbm_cl_addr_equal(struct mei_cl *cl, struct mei_hbm_cl_cmd *cmd)
  170. {
  171. return cl->host_client_id == cmd->host_addr &&
  172. cl->me_client_id == cmd->me_addr;
  173. }
  174. /**
  175. * mei_hbm_cl_find_by_cmd - find recipient client
  176. *
  177. * @dev: the device structure
  178. * @buf: a buffer with hbm cl command
  179. *
  180. * Return: the recipient client or NULL if not found
  181. */
  182. static inline
  183. struct mei_cl *mei_hbm_cl_find_by_cmd(struct mei_device *dev, void *buf)
  184. {
  185. struct mei_hbm_cl_cmd *cmd = (struct mei_hbm_cl_cmd *)buf;
  186. struct mei_cl *cl;
  187. list_for_each_entry(cl, &dev->file_list, link)
  188. if (mei_hbm_cl_addr_equal(cl, cmd))
  189. return cl;
  190. return NULL;
  191. }
  192. /**
  193. * mei_hbm_start_wait - wait for start response message.
  194. *
  195. * @dev: the device structure
  196. *
  197. * Return: 0 on success and < 0 on failure
  198. */
  199. int mei_hbm_start_wait(struct mei_device *dev)
  200. {
  201. int ret;
  202. if (dev->hbm_state > MEI_HBM_STARTING)
  203. return 0;
  204. mutex_unlock(&dev->device_lock);
  205. ret = wait_event_timeout(dev->wait_hbm_start,
  206. dev->hbm_state != MEI_HBM_STARTING,
  207. mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
  208. mutex_lock(&dev->device_lock);
  209. if (ret == 0 && (dev->hbm_state <= MEI_HBM_STARTING)) {
  210. dev->hbm_state = MEI_HBM_IDLE;
  211. dev_err(dev->dev, "waiting for mei start failed\n");
  212. return -ETIME;
  213. }
  214. return 0;
  215. }
  216. /**
  217. * mei_hbm_start_req - sends start request message.
  218. *
  219. * @dev: the device structure
  220. *
  221. * Return: 0 on success and < 0 on failure
  222. */
  223. int mei_hbm_start_req(struct mei_device *dev)
  224. {
  225. struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
  226. struct hbm_host_version_request *start_req;
  227. const size_t len = sizeof(struct hbm_host_version_request);
  228. int ret;
  229. mei_hbm_reset(dev);
  230. mei_hbm_hdr(mei_hdr, len);
  231. /* host start message */
  232. start_req = (struct hbm_host_version_request *)dev->wr_msg.data;
  233. memset(start_req, 0, len);
  234. start_req->hbm_cmd = HOST_START_REQ_CMD;
  235. start_req->host_version.major_version = HBM_MAJOR_VERSION;
  236. start_req->host_version.minor_version = HBM_MINOR_VERSION;
  237. dev->hbm_state = MEI_HBM_IDLE;
  238. ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
  239. if (ret) {
  240. dev_err(dev->dev, "version message write failed: ret = %d\n",
  241. ret);
  242. return ret;
  243. }
  244. dev->hbm_state = MEI_HBM_STARTING;
  245. dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
  246. return 0;
  247. }
  248. /*
  249. * mei_hbm_enum_clients_req - sends enumeration client request message.
  250. *
  251. * @dev: the device structure
  252. *
  253. * Return: 0 on success and < 0 on failure
  254. */
  255. static int mei_hbm_enum_clients_req(struct mei_device *dev)
  256. {
  257. struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
  258. struct hbm_host_enum_request *enum_req;
  259. const size_t len = sizeof(struct hbm_host_enum_request);
  260. int ret;
  261. /* enumerate clients */
  262. mei_hbm_hdr(mei_hdr, len);
  263. enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
  264. memset(enum_req, 0, len);
  265. enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
  266. ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
  267. if (ret) {
  268. dev_err(dev->dev, "enumeration request write failed: ret = %d.\n",
  269. ret);
  270. return ret;
  271. }
  272. dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
  273. dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
  274. return 0;
  275. }
  276. /*
  277. * mei_hbm_me_cl_add - add new me client to the list
  278. *
  279. * @dev: the device structure
  280. * @res: hbm property response
  281. *
  282. * Return: 0 on success and -ENOMEM on allocation failure
  283. */
  284. static int mei_hbm_me_cl_add(struct mei_device *dev,
  285. struct hbm_props_response *res)
  286. {
  287. struct mei_me_client *me_cl;
  288. const uuid_le *uuid = &res->client_properties.protocol_name;
  289. mei_me_cl_rm_by_uuid(dev, uuid);
  290. me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL);
  291. if (!me_cl)
  292. return -ENOMEM;
  293. mei_me_cl_init(me_cl);
  294. me_cl->props = res->client_properties;
  295. me_cl->client_id = res->me_addr;
  296. me_cl->mei_flow_ctrl_creds = 0;
  297. mei_me_cl_add(dev, me_cl);
  298. return 0;
  299. }
  300. /**
  301. * mei_hbm_prop_req - request property for a single client
  302. *
  303. * @dev: the device structure
  304. *
  305. * Return: 0 on success and < 0 on failure
  306. */
  307. static int mei_hbm_prop_req(struct mei_device *dev)
  308. {
  309. struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
  310. struct hbm_props_request *prop_req;
  311. const size_t len = sizeof(struct hbm_props_request);
  312. unsigned long next_client_index;
  313. int ret;
  314. next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
  315. dev->me_client_index);
  316. /* We got all client properties */
  317. if (next_client_index == MEI_CLIENTS_MAX) {
  318. dev->hbm_state = MEI_HBM_STARTED;
  319. schedule_work(&dev->init_work);
  320. return 0;
  321. }
  322. mei_hbm_hdr(mei_hdr, len);
  323. prop_req = (struct hbm_props_request *)dev->wr_msg.data;
  324. memset(prop_req, 0, sizeof(struct hbm_props_request));
  325. prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
  326. prop_req->me_addr = next_client_index;
  327. ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
  328. if (ret) {
  329. dev_err(dev->dev, "properties request write failed: ret = %d\n",
  330. ret);
  331. return ret;
  332. }
  333. dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
  334. dev->me_client_index = next_client_index;
  335. return 0;
  336. }
  337. /*
  338. * mei_hbm_pg - sends pg command
  339. *
  340. * @dev: the device structure
  341. * @pg_cmd: the pg command code
  342. *
  343. * Return: -EIO on write failure
  344. * -EOPNOTSUPP if the operation is not supported by the protocol
  345. */
  346. int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
  347. {
  348. struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
  349. struct hbm_power_gate *req;
  350. const size_t len = sizeof(struct hbm_power_gate);
  351. int ret;
  352. if (!dev->hbm_f_pg_supported)
  353. return -EOPNOTSUPP;
  354. mei_hbm_hdr(mei_hdr, len);
  355. req = (struct hbm_power_gate *)dev->wr_msg.data;
  356. memset(req, 0, len);
  357. req->hbm_cmd = pg_cmd;
  358. ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
  359. if (ret)
  360. dev_err(dev->dev, "power gate command write failed.\n");
  361. return ret;
  362. }
  363. EXPORT_SYMBOL_GPL(mei_hbm_pg);
  364. /**
  365. * mei_hbm_stop_req - send stop request message
  366. *
  367. * @dev: mei device
  368. *
  369. * Return: -EIO on write failure
  370. */
  371. static int mei_hbm_stop_req(struct mei_device *dev)
  372. {
  373. struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
  374. struct hbm_host_stop_request *req =
  375. (struct hbm_host_stop_request *)dev->wr_msg.data;
  376. const size_t len = sizeof(struct hbm_host_stop_request);
  377. mei_hbm_hdr(mei_hdr, len);
  378. memset(req, 0, len);
  379. req->hbm_cmd = HOST_STOP_REQ_CMD;
  380. req->reason = DRIVER_STOP_REQUEST;
  381. return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
  382. }
  383. /**
  384. * mei_hbm_cl_flow_control_req - sends flow control request.
  385. *
  386. * @dev: the device structure
  387. * @cl: client info
  388. *
  389. * Return: -EIO on write failure
  390. */
  391. int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
  392. {
  393. const size_t len = sizeof(struct hbm_flow_control);
  394. cl_dbg(dev, cl, "sending flow control\n");
  395. return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, len);
  396. }
  397. /**
  398. * mei_hbm_add_single_flow_creds - adds single buffer credentials.
  399. *
  400. * @dev: the device structure
  401. * @flow: flow control.
  402. *
  403. * Return: 0 on success, < 0 otherwise
  404. */
  405. static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
  406. struct hbm_flow_control *flow)
  407. {
  408. struct mei_me_client *me_cl;
  409. int rets;
  410. me_cl = mei_me_cl_by_id(dev, flow->me_addr);
  411. if (!me_cl) {
  412. dev_err(dev->dev, "no such me client %d\n",
  413. flow->me_addr);
  414. return -ENOENT;
  415. }
  416. if (WARN_ON(me_cl->props.single_recv_buf == 0)) {
  417. rets = -EINVAL;
  418. goto out;
  419. }
  420. me_cl->mei_flow_ctrl_creds++;
  421. dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
  422. flow->me_addr, me_cl->mei_flow_ctrl_creds);
  423. rets = 0;
  424. out:
  425. mei_me_cl_put(me_cl);
  426. return rets;
  427. }
  428. /**
  429. * mei_hbm_cl_flow_control_res - flow control response from me
  430. *
  431. * @dev: the device structure
  432. * @flow_control: flow control response bus message
  433. */
  434. static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
  435. struct hbm_flow_control *flow_control)
  436. {
  437. struct mei_cl *cl;
  438. if (!flow_control->host_addr) {
  439. /* single receive buffer */
  440. mei_hbm_add_single_flow_creds(dev, flow_control);
  441. return;
  442. }
  443. cl = mei_hbm_cl_find_by_cmd(dev, flow_control);
  444. if (cl) {
  445. cl->mei_flow_ctrl_creds++;
  446. cl_dbg(dev, cl, "flow control creds = %d.\n",
  447. cl->mei_flow_ctrl_creds);
  448. }
  449. }
  450. /**
  451. * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
  452. *
  453. * @dev: the device structure
  454. * @cl: a client to disconnect from
  455. *
  456. * Return: -EIO on write failure
  457. */
  458. int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
  459. {
  460. const size_t len = sizeof(struct hbm_client_connect_request);
  461. return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, len);
  462. }
  463. /**
  464. * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW
  465. *
  466. * @dev: the device structure
  467. * @cl: a client to disconnect from
  468. *
  469. * Return: -EIO on write failure
  470. */
  471. int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
  472. {
  473. const size_t len = sizeof(struct hbm_client_connect_response);
  474. return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, len);
  475. }
  476. /**
  477. * mei_hbm_cl_disconnect_res - update the client state according
  478. * disconnect response
  479. *
  480. * @dev: the device structure
  481. * @cl: mei host client
  482. * @cmd: disconnect client response host bus message
  483. */
  484. static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl,
  485. struct mei_hbm_cl_cmd *cmd)
  486. {
  487. struct hbm_client_connect_response *rs =
  488. (struct hbm_client_connect_response *)cmd;
  489. cl_dbg(dev, cl, "hbm: disconnect response status=%d\n", rs->status);
  490. if (rs->status == MEI_CL_DISCONN_SUCCESS)
  491. cl->state = MEI_FILE_DISCONNECTED;
  492. cl->status = 0;
  493. }
  494. /**
  495. * mei_hbm_cl_connect_req - send connection request to specific me client
  496. *
  497. * @dev: the device structure
  498. * @cl: a client to connect to
  499. *
  500. * Return: -EIO on write failure
  501. */
  502. int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
  503. {
  504. const size_t len = sizeof(struct hbm_client_connect_request);
  505. return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, len);
  506. }
  507. /**
  508. * mei_hbm_cl_connect_res - update the client state according
  509. * connection response
  510. *
  511. * @dev: the device structure
  512. * @cl: mei host client
  513. * @cmd: connect client response host bus message
  514. */
  515. static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl,
  516. struct mei_hbm_cl_cmd *cmd)
  517. {
  518. struct hbm_client_connect_response *rs =
  519. (struct hbm_client_connect_response *)cmd;
  520. cl_dbg(dev, cl, "hbm: connect response status=%s\n",
  521. mei_cl_conn_status_str(rs->status));
  522. if (rs->status == MEI_CL_CONN_SUCCESS)
  523. cl->state = MEI_FILE_CONNECTED;
  524. else
  525. cl->state = MEI_FILE_DISCONNECTED;
  526. cl->status = mei_cl_conn_status_to_errno(rs->status);
  527. }
  528. /**
  529. * mei_hbm_cl_res - process hbm response received on behalf
  530. * an client
  531. *
  532. * @dev: the device structure
  533. * @rs: hbm client message
  534. * @fop_type: file operation type
  535. */
  536. static void mei_hbm_cl_res(struct mei_device *dev,
  537. struct mei_hbm_cl_cmd *rs,
  538. enum mei_cb_file_ops fop_type)
  539. {
  540. struct mei_cl *cl;
  541. struct mei_cl_cb *cb, *next;
  542. cl = NULL;
  543. list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
  544. cl = cb->cl;
  545. if (cb->fop_type != fop_type)
  546. continue;
  547. if (mei_hbm_cl_addr_equal(cl, rs)) {
  548. list_del_init(&cb->list);
  549. break;
  550. }
  551. }
  552. if (!cl)
  553. return;
  554. switch (fop_type) {
  555. case MEI_FOP_CONNECT:
  556. mei_hbm_cl_connect_res(dev, cl, rs);
  557. break;
  558. case MEI_FOP_DISCONNECT:
  559. mei_hbm_cl_disconnect_res(dev, cl, rs);
  560. break;
  561. default:
  562. return;
  563. }
  564. cl->timer_count = 0;
  565. wake_up(&cl->wait);
  566. }
  567. /**
  568. * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware
  569. * host sends disconnect response
  570. *
  571. * @dev: the device structure.
  572. * @disconnect_req: disconnect request bus message from the me
  573. *
  574. * Return: -ENOMEM on allocation failure
  575. */
  576. static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
  577. struct hbm_client_connect_request *disconnect_req)
  578. {
  579. struct mei_cl *cl;
  580. struct mei_cl_cb *cb;
  581. cl = mei_hbm_cl_find_by_cmd(dev, disconnect_req);
  582. if (cl) {
  583. cl_dbg(dev, cl, "disconnect request received\n");
  584. cl->state = MEI_FILE_DISCONNECTED;
  585. cl->timer_count = 0;
  586. cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT_RSP, NULL);
  587. if (!cb)
  588. return -ENOMEM;
  589. cl_dbg(dev, cl, "add disconnect response as first\n");
  590. list_add(&cb->list, &dev->ctrl_wr_list.list);
  591. }
  592. return 0;
  593. }
  594. /**
  595. * mei_hbm_config_features - check what hbm features and commands
  596. * are supported by the fw
  597. *
  598. * @dev: the device structure
  599. */
  600. static void mei_hbm_config_features(struct mei_device *dev)
  601. {
  602. /* Power Gating Isolation Support */
  603. dev->hbm_f_pg_supported = 0;
  604. if (dev->version.major_version > HBM_MAJOR_VERSION_PGI)
  605. dev->hbm_f_pg_supported = 1;
  606. if (dev->version.major_version == HBM_MAJOR_VERSION_PGI &&
  607. dev->version.minor_version >= HBM_MINOR_VERSION_PGI)
  608. dev->hbm_f_pg_supported = 1;
  609. }
  610. /**
  611. * mei_hbm_version_is_supported - checks whether the driver can
  612. * support the hbm version of the device
  613. *
  614. * @dev: the device structure
  615. * Return: true if driver can support hbm version of the device
  616. */
  617. bool mei_hbm_version_is_supported(struct mei_device *dev)
  618. {
  619. return (dev->version.major_version < HBM_MAJOR_VERSION) ||
  620. (dev->version.major_version == HBM_MAJOR_VERSION &&
  621. dev->version.minor_version <= HBM_MINOR_VERSION);
  622. }
  623. /**
  624. * mei_hbm_dispatch - bottom half read routine after ISR to
  625. * handle the read bus message cmd processing.
  626. *
  627. * @dev: the device structure
  628. * @hdr: header of bus message
  629. *
  630. * Return: 0 on success and < 0 on failure
  631. */
  632. int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
  633. {
  634. struct mei_bus_message *mei_msg;
  635. struct hbm_host_version_response *version_res;
  636. struct hbm_props_response *props_res;
  637. struct hbm_host_enum_response *enum_res;
  638. struct mei_hbm_cl_cmd *cl_cmd;
  639. struct hbm_client_connect_request *disconnect_req;
  640. struct hbm_flow_control *flow_control;
  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. cl_cmd = (struct mei_hbm_cl_cmd *)mei_msg;
  646. /* 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->dev, "hbm: state is idle ignore spurious messages\n");
  651. return 0;
  652. }
  653. switch (mei_msg->hbm_cmd) {
  654. case HOST_START_RES_CMD:
  655. dev_dbg(dev->dev, "hbm: start: response message received.\n");
  656. dev->init_clients_timer = 0;
  657. version_res = (struct hbm_host_version_response *)mei_msg;
  658. dev_dbg(dev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
  659. HBM_MAJOR_VERSION, HBM_MINOR_VERSION,
  660. version_res->me_max_version.major_version,
  661. version_res->me_max_version.minor_version);
  662. if (version_res->host_version_supported) {
  663. dev->version.major_version = HBM_MAJOR_VERSION;
  664. dev->version.minor_version = HBM_MINOR_VERSION;
  665. } else {
  666. dev->version.major_version =
  667. version_res->me_max_version.major_version;
  668. dev->version.minor_version =
  669. version_res->me_max_version.minor_version;
  670. }
  671. if (!mei_hbm_version_is_supported(dev)) {
  672. dev_warn(dev->dev, "hbm: start: version mismatch - stopping the driver.\n");
  673. dev->hbm_state = MEI_HBM_STOPPED;
  674. if (mei_hbm_stop_req(dev)) {
  675. dev_err(dev->dev, "hbm: start: failed to send stop request\n");
  676. return -EIO;
  677. }
  678. break;
  679. }
  680. mei_hbm_config_features(dev);
  681. if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
  682. dev->hbm_state != MEI_HBM_STARTING) {
  683. dev_err(dev->dev, "hbm: start: state mismatch, [%d, %d]\n",
  684. dev->dev_state, dev->hbm_state);
  685. return -EPROTO;
  686. }
  687. if (mei_hbm_enum_clients_req(dev)) {
  688. dev_err(dev->dev, "hbm: start: failed to send enumeration request\n");
  689. return -EIO;
  690. }
  691. wake_up(&dev->wait_hbm_start);
  692. break;
  693. case CLIENT_CONNECT_RES_CMD:
  694. dev_dbg(dev->dev, "hbm: client connect response: message received.\n");
  695. mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_CONNECT);
  696. break;
  697. case CLIENT_DISCONNECT_RES_CMD:
  698. dev_dbg(dev->dev, "hbm: client disconnect response: message received.\n");
  699. mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_DISCONNECT);
  700. break;
  701. case MEI_FLOW_CONTROL_CMD:
  702. dev_dbg(dev->dev, "hbm: client flow control response: message received.\n");
  703. flow_control = (struct hbm_flow_control *) mei_msg;
  704. mei_hbm_cl_flow_control_res(dev, flow_control);
  705. break;
  706. case MEI_PG_ISOLATION_ENTRY_RES_CMD:
  707. dev_dbg(dev->dev, "power gate isolation entry response received\n");
  708. dev->pg_event = MEI_PG_EVENT_RECEIVED;
  709. if (waitqueue_active(&dev->wait_pg))
  710. wake_up(&dev->wait_pg);
  711. break;
  712. case MEI_PG_ISOLATION_EXIT_REQ_CMD:
  713. dev_dbg(dev->dev, "power gate isolation exit request received\n");
  714. dev->pg_event = MEI_PG_EVENT_RECEIVED;
  715. if (waitqueue_active(&dev->wait_pg))
  716. wake_up(&dev->wait_pg);
  717. else
  718. /*
  719. * If the driver is not waiting on this then
  720. * this is HW initiated exit from PG.
  721. * Start runtime pm resume sequence to exit from PG.
  722. */
  723. pm_request_resume(dev->dev);
  724. break;
  725. case HOST_CLIENT_PROPERTIES_RES_CMD:
  726. dev_dbg(dev->dev, "hbm: properties response: message received.\n");
  727. dev->init_clients_timer = 0;
  728. if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
  729. dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
  730. dev_err(dev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
  731. dev->dev_state, dev->hbm_state);
  732. return -EPROTO;
  733. }
  734. props_res = (struct hbm_props_response *)mei_msg;
  735. if (props_res->status) {
  736. dev_err(dev->dev, "hbm: properties response: wrong status = %d %s\n",
  737. props_res->status,
  738. mei_hbm_status_str(props_res->status));
  739. return -EPROTO;
  740. }
  741. mei_hbm_me_cl_add(dev, props_res);
  742. dev->me_client_index++;
  743. /* request property for the next client */
  744. if (mei_hbm_prop_req(dev))
  745. return -EIO;
  746. break;
  747. case HOST_ENUM_RES_CMD:
  748. dev_dbg(dev->dev, "hbm: enumeration response: message received\n");
  749. dev->init_clients_timer = 0;
  750. enum_res = (struct hbm_host_enum_response *) mei_msg;
  751. BUILD_BUG_ON(sizeof(dev->me_clients_map)
  752. < sizeof(enum_res->valid_addresses));
  753. memcpy(dev->me_clients_map, enum_res->valid_addresses,
  754. sizeof(enum_res->valid_addresses));
  755. if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
  756. dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {
  757. dev_err(dev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
  758. dev->dev_state, dev->hbm_state);
  759. return -EPROTO;
  760. }
  761. dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
  762. /* first property request */
  763. if (mei_hbm_prop_req(dev))
  764. return -EIO;
  765. break;
  766. case HOST_STOP_RES_CMD:
  767. dev_dbg(dev->dev, "hbm: stop response: message received\n");
  768. dev->init_clients_timer = 0;
  769. if (dev->hbm_state != MEI_HBM_STOPPED) {
  770. dev_err(dev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
  771. dev->dev_state, dev->hbm_state);
  772. return -EPROTO;
  773. }
  774. dev->dev_state = MEI_DEV_POWER_DOWN;
  775. dev_info(dev->dev, "hbm: stop response: resetting.\n");
  776. /* force the reset */
  777. return -EPROTO;
  778. break;
  779. case CLIENT_DISCONNECT_REQ_CMD:
  780. dev_dbg(dev->dev, "hbm: disconnect request: message received\n");
  781. disconnect_req = (struct hbm_client_connect_request *)mei_msg;
  782. mei_hbm_fw_disconnect_req(dev, disconnect_req);
  783. break;
  784. case ME_STOP_REQ_CMD:
  785. dev_dbg(dev->dev, "hbm: stop request: message received\n");
  786. dev->hbm_state = MEI_HBM_STOPPED;
  787. if (mei_hbm_stop_req(dev)) {
  788. dev_err(dev->dev, "hbm: stop request: failed to send stop request\n");
  789. return -EIO;
  790. }
  791. break;
  792. default:
  793. BUG();
  794. break;
  795. }
  796. return 0;
  797. }