mcdi.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Management-Controller-to-Driver Interface
  4. *
  5. * Copyright 2008-2013 Solarflare Communications Inc.
  6. * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
  7. */
  8. #include <linux/delay.h>
  9. #include <linux/slab.h>
  10. #include <linux/io.h>
  11. #include <linux/spinlock.h>
  12. #include <linux/netdevice.h>
  13. #include <linux/etherdevice.h>
  14. #include <linux/ethtool.h>
  15. #include <linux/if_vlan.h>
  16. #include <linux/timer.h>
  17. #include <linux/list.h>
  18. #include <linux/pci.h>
  19. #include <linux/device.h>
  20. #include <linux/rwsem.h>
  21. #include <linux/vmalloc.h>
  22. #include <net/netevent.h>
  23. #include <linux/log2.h>
  24. #include <linux/net_tstamp.h>
  25. #include <linux/wait.h>
  26. #include "bitfield.h"
  27. #include "mcdi.h"
  28. static void cdx_mcdi_cancel_cmd(struct cdx_mcdi *cdx, struct cdx_mcdi_cmd *cmd);
  29. static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi *cdx);
  30. static int cdx_mcdi_rpc_async_internal(struct cdx_mcdi *cdx,
  31. struct cdx_mcdi_cmd *cmd,
  32. unsigned int *handle);
  33. static void cdx_mcdi_start_or_queue(struct cdx_mcdi_iface *mcdi,
  34. bool allow_retry);
  35. static void cdx_mcdi_cmd_start_or_queue(struct cdx_mcdi_iface *mcdi,
  36. struct cdx_mcdi_cmd *cmd);
  37. static bool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface *mcdi,
  38. struct cdx_mcdi_cmd *cmd,
  39. struct cdx_dword *outbuf,
  40. int len,
  41. struct list_head *cleanup_list);
  42. static void cdx_mcdi_timeout_cmd(struct cdx_mcdi_iface *mcdi,
  43. struct cdx_mcdi_cmd *cmd,
  44. struct list_head *cleanup_list);
  45. static void cdx_mcdi_cmd_work(struct work_struct *context);
  46. static void cdx_mcdi_mode_fail(struct cdx_mcdi *cdx, struct list_head *cleanup_list);
  47. static void _cdx_mcdi_display_error(struct cdx_mcdi *cdx, unsigned int cmd,
  48. size_t inlen, int raw, int arg, int err_no);
  49. static bool cdx_cmd_cancelled(struct cdx_mcdi_cmd *cmd)
  50. {
  51. return cmd->state == MCDI_STATE_RUNNING_CANCELLED;
  52. }
  53. static void cdx_mcdi_cmd_release(struct kref *ref)
  54. {
  55. kfree(container_of(ref, struct cdx_mcdi_cmd, ref));
  56. }
  57. static unsigned int cdx_mcdi_cmd_handle(struct cdx_mcdi_cmd *cmd)
  58. {
  59. return cmd->handle;
  60. }
  61. static void _cdx_mcdi_remove_cmd(struct cdx_mcdi_iface *mcdi,
  62. struct cdx_mcdi_cmd *cmd,
  63. struct list_head *cleanup_list)
  64. {
  65. /* if cancelled, the completers have already been called */
  66. if (cdx_cmd_cancelled(cmd))
  67. return;
  68. if (cmd->completer) {
  69. list_add_tail(&cmd->cleanup_list, cleanup_list);
  70. ++mcdi->outstanding_cleanups;
  71. kref_get(&cmd->ref);
  72. }
  73. }
  74. static void cdx_mcdi_remove_cmd(struct cdx_mcdi_iface *mcdi,
  75. struct cdx_mcdi_cmd *cmd,
  76. struct list_head *cleanup_list)
  77. {
  78. list_del(&cmd->list);
  79. _cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list);
  80. cmd->state = MCDI_STATE_FINISHED;
  81. kref_put(&cmd->ref, cdx_mcdi_cmd_release);
  82. if (list_empty(&mcdi->cmd_list))
  83. wake_up(&mcdi->cmd_complete_wq);
  84. }
  85. static unsigned long cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd)
  86. {
  87. if (!cdx->mcdi_ops->mcdi_rpc_timeout)
  88. return MCDI_RPC_TIMEOUT;
  89. else
  90. return cdx->mcdi_ops->mcdi_rpc_timeout(cdx, cmd);
  91. }
  92. int cdx_mcdi_init(struct cdx_mcdi *cdx)
  93. {
  94. struct cdx_mcdi_iface *mcdi;
  95. int rc = -ENOMEM;
  96. cdx->mcdi = kzalloc(sizeof(*cdx->mcdi), GFP_KERNEL);
  97. if (!cdx->mcdi)
  98. goto fail;
  99. mcdi = cdx_mcdi_if(cdx);
  100. mcdi->cdx = cdx;
  101. mcdi->workqueue = alloc_ordered_workqueue("mcdi_wq", 0);
  102. if (!mcdi->workqueue)
  103. goto fail2;
  104. mutex_init(&mcdi->iface_lock);
  105. mcdi->mode = MCDI_MODE_EVENTS;
  106. INIT_LIST_HEAD(&mcdi->cmd_list);
  107. init_waitqueue_head(&mcdi->cmd_complete_wq);
  108. mcdi->new_epoch = true;
  109. return 0;
  110. fail2:
  111. kfree(cdx->mcdi);
  112. cdx->mcdi = NULL;
  113. fail:
  114. return rc;
  115. }
  116. void cdx_mcdi_finish(struct cdx_mcdi *cdx)
  117. {
  118. struct cdx_mcdi_iface *mcdi;
  119. mcdi = cdx_mcdi_if(cdx);
  120. if (!mcdi)
  121. return;
  122. cdx_mcdi_wait_for_cleanup(cdx);
  123. destroy_workqueue(mcdi->workqueue);
  124. kfree(cdx->mcdi);
  125. cdx->mcdi = NULL;
  126. }
  127. static bool cdx_mcdi_flushed(struct cdx_mcdi_iface *mcdi, bool ignore_cleanups)
  128. {
  129. bool flushed;
  130. mutex_lock(&mcdi->iface_lock);
  131. flushed = list_empty(&mcdi->cmd_list) &&
  132. (ignore_cleanups || !mcdi->outstanding_cleanups);
  133. mutex_unlock(&mcdi->iface_lock);
  134. return flushed;
  135. }
  136. /* Wait for outstanding MCDI commands to complete. */
  137. static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi *cdx)
  138. {
  139. struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx);
  140. if (!mcdi)
  141. return;
  142. wait_event(mcdi->cmd_complete_wq,
  143. cdx_mcdi_flushed(mcdi, false));
  144. }
  145. int cdx_mcdi_wait_for_quiescence(struct cdx_mcdi *cdx,
  146. unsigned int timeout_jiffies)
  147. {
  148. struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx);
  149. DEFINE_WAIT_FUNC(wait, woken_wake_function);
  150. int rc = 0;
  151. if (!mcdi)
  152. return -EINVAL;
  153. flush_workqueue(mcdi->workqueue);
  154. add_wait_queue(&mcdi->cmd_complete_wq, &wait);
  155. while (!cdx_mcdi_flushed(mcdi, true)) {
  156. rc = wait_woken(&wait, TASK_IDLE, timeout_jiffies);
  157. if (rc)
  158. continue;
  159. break;
  160. }
  161. remove_wait_queue(&mcdi->cmd_complete_wq, &wait);
  162. if (rc > 0)
  163. rc = 0;
  164. else if (rc == 0)
  165. rc = -ETIMEDOUT;
  166. return rc;
  167. }
  168. static u8 cdx_mcdi_payload_csum(const struct cdx_dword *hdr, size_t hdr_len,
  169. const struct cdx_dword *sdu, size_t sdu_len)
  170. {
  171. u8 *p = (u8 *)hdr;
  172. u8 csum = 0;
  173. int i;
  174. for (i = 0; i < hdr_len; i++)
  175. csum += p[i];
  176. p = (u8 *)sdu;
  177. for (i = 0; i < sdu_len; i++)
  178. csum += p[i];
  179. return ~csum & 0xff;
  180. }
  181. static void cdx_mcdi_send_request(struct cdx_mcdi *cdx,
  182. struct cdx_mcdi_cmd *cmd)
  183. {
  184. struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx);
  185. const struct cdx_dword *inbuf = cmd->inbuf;
  186. size_t inlen = cmd->inlen;
  187. struct cdx_dword hdr[2];
  188. size_t hdr_len;
  189. bool not_epoch;
  190. u32 xflags;
  191. if (!mcdi)
  192. return;
  193. mcdi->prev_seq = cmd->seq;
  194. mcdi->seq_held_by[cmd->seq] = cmd;
  195. mcdi->db_held_by = cmd;
  196. cmd->started = jiffies;
  197. not_epoch = !mcdi->new_epoch;
  198. xflags = 0;
  199. /* MCDI v2 */
  200. WARN_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V2);
  201. CDX_POPULATE_DWORD_7(hdr[0],
  202. MCDI_HEADER_RESPONSE, 0,
  203. MCDI_HEADER_RESYNC, 1,
  204. MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
  205. MCDI_HEADER_DATALEN, 0,
  206. MCDI_HEADER_SEQ, cmd->seq,
  207. MCDI_HEADER_XFLAGS, xflags,
  208. MCDI_HEADER_NOT_EPOCH, not_epoch);
  209. CDX_POPULATE_DWORD_3(hdr[1],
  210. MC_CMD_V2_EXTN_IN_EXTENDED_CMD, cmd->cmd,
  211. MC_CMD_V2_EXTN_IN_ACTUAL_LEN, inlen,
  212. MC_CMD_V2_EXTN_IN_MESSAGE_TYPE,
  213. MC_CMD_V2_EXTN_IN_MCDI_MESSAGE_TYPE_PLATFORM);
  214. hdr_len = 8;
  215. hdr[0].cdx_u32 |= (__force __le32)(cdx_mcdi_payload_csum(hdr, hdr_len, inbuf, inlen) <<
  216. MCDI_HEADER_XFLAGS_LBN);
  217. print_hex_dump_debug("MCDI REQ HEADER: ", DUMP_PREFIX_NONE, 32, 4, hdr, hdr_len, false);
  218. print_hex_dump_debug("MCDI REQ PAYLOAD: ", DUMP_PREFIX_NONE, 32, 4, inbuf, inlen, false);
  219. cdx->mcdi_ops->mcdi_request(cdx, hdr, hdr_len, inbuf, inlen);
  220. mcdi->new_epoch = false;
  221. }
  222. static int cdx_mcdi_errno(struct cdx_mcdi *cdx, unsigned int mcdi_err)
  223. {
  224. switch (mcdi_err) {
  225. case 0:
  226. case MC_CMD_ERR_QUEUE_FULL:
  227. return mcdi_err;
  228. case MC_CMD_ERR_EPERM:
  229. return -EPERM;
  230. case MC_CMD_ERR_ENOENT:
  231. return -ENOENT;
  232. case MC_CMD_ERR_EINTR:
  233. return -EINTR;
  234. case MC_CMD_ERR_EAGAIN:
  235. return -EAGAIN;
  236. case MC_CMD_ERR_EACCES:
  237. return -EACCES;
  238. case MC_CMD_ERR_EBUSY:
  239. return -EBUSY;
  240. case MC_CMD_ERR_EINVAL:
  241. return -EINVAL;
  242. case MC_CMD_ERR_ERANGE:
  243. return -ERANGE;
  244. case MC_CMD_ERR_EDEADLK:
  245. return -EDEADLK;
  246. case MC_CMD_ERR_ENOSYS:
  247. return -EOPNOTSUPP;
  248. case MC_CMD_ERR_ETIME:
  249. return -ETIME;
  250. case MC_CMD_ERR_EALREADY:
  251. return -EALREADY;
  252. case MC_CMD_ERR_ENOSPC:
  253. return -ENOSPC;
  254. case MC_CMD_ERR_ENOMEM:
  255. return -ENOMEM;
  256. case MC_CMD_ERR_ENOTSUP:
  257. return -EOPNOTSUPP;
  258. case MC_CMD_ERR_ALLOC_FAIL:
  259. return -ENOBUFS;
  260. case MC_CMD_ERR_MAC_EXIST:
  261. return -EADDRINUSE;
  262. case MC_CMD_ERR_NO_EVB_PORT:
  263. return -EAGAIN;
  264. default:
  265. return -EPROTO;
  266. }
  267. }
  268. static void cdx_mcdi_process_cleanup_list(struct cdx_mcdi *cdx,
  269. struct list_head *cleanup_list)
  270. {
  271. struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx);
  272. unsigned int cleanups = 0;
  273. if (!mcdi)
  274. return;
  275. while (!list_empty(cleanup_list)) {
  276. struct cdx_mcdi_cmd *cmd =
  277. list_first_entry(cleanup_list,
  278. struct cdx_mcdi_cmd, cleanup_list);
  279. cmd->completer(cdx, cmd->cookie, cmd->rc,
  280. cmd->outbuf, cmd->outlen);
  281. list_del(&cmd->cleanup_list);
  282. kref_put(&cmd->ref, cdx_mcdi_cmd_release);
  283. ++cleanups;
  284. }
  285. if (cleanups) {
  286. bool all_done;
  287. mutex_lock(&mcdi->iface_lock);
  288. CDX_WARN_ON_PARANOID(cleanups > mcdi->outstanding_cleanups);
  289. all_done = (mcdi->outstanding_cleanups -= cleanups) == 0;
  290. mutex_unlock(&mcdi->iface_lock);
  291. if (all_done)
  292. wake_up(&mcdi->cmd_complete_wq);
  293. }
  294. }
  295. static void _cdx_mcdi_cancel_cmd(struct cdx_mcdi_iface *mcdi,
  296. unsigned int handle,
  297. struct list_head *cleanup_list)
  298. {
  299. struct cdx_mcdi_cmd *cmd;
  300. list_for_each_entry(cmd, &mcdi->cmd_list, list)
  301. if (cdx_mcdi_cmd_handle(cmd) == handle) {
  302. switch (cmd->state) {
  303. case MCDI_STATE_QUEUED:
  304. case MCDI_STATE_RETRY:
  305. pr_debug("command %#x inlen %zu cancelled in queue\n",
  306. cmd->cmd, cmd->inlen);
  307. /* if not yet running, properly cancel it */
  308. cmd->rc = -EPIPE;
  309. cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list);
  310. break;
  311. case MCDI_STATE_RUNNING:
  312. case MCDI_STATE_RUNNING_CANCELLED:
  313. case MCDI_STATE_FINISHED:
  314. default:
  315. /* invalid state? */
  316. WARN_ON(1);
  317. }
  318. break;
  319. }
  320. }
  321. static void cdx_mcdi_cancel_cmd(struct cdx_mcdi *cdx, struct cdx_mcdi_cmd *cmd)
  322. {
  323. struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx);
  324. LIST_HEAD(cleanup_list);
  325. if (!mcdi)
  326. return;
  327. mutex_lock(&mcdi->iface_lock);
  328. cdx_mcdi_timeout_cmd(mcdi, cmd, &cleanup_list);
  329. mutex_unlock(&mcdi->iface_lock);
  330. cdx_mcdi_process_cleanup_list(cdx, &cleanup_list);
  331. }
  332. struct cdx_mcdi_blocking_data {
  333. struct kref ref;
  334. bool done;
  335. wait_queue_head_t wq;
  336. int rc;
  337. struct cdx_dword *outbuf;
  338. size_t outlen;
  339. size_t outlen_actual;
  340. };
  341. static void cdx_mcdi_blocking_data_release(struct kref *ref)
  342. {
  343. kfree(container_of(ref, struct cdx_mcdi_blocking_data, ref));
  344. }
  345. static void cdx_mcdi_rpc_completer(struct cdx_mcdi *cdx, unsigned long cookie,
  346. int rc, struct cdx_dword *outbuf,
  347. size_t outlen_actual)
  348. {
  349. struct cdx_mcdi_blocking_data *wait_data =
  350. (struct cdx_mcdi_blocking_data *)cookie;
  351. wait_data->rc = rc;
  352. memcpy(wait_data->outbuf, outbuf,
  353. min(outlen_actual, wait_data->outlen));
  354. wait_data->outlen_actual = outlen_actual;
  355. /* memory barrier */
  356. smp_wmb();
  357. wait_data->done = true;
  358. wake_up(&wait_data->wq);
  359. kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release);
  360. }
  361. static int cdx_mcdi_rpc_sync(struct cdx_mcdi *cdx, unsigned int cmd,
  362. const struct cdx_dword *inbuf, size_t inlen,
  363. struct cdx_dword *outbuf, size_t outlen,
  364. size_t *outlen_actual, bool quiet)
  365. {
  366. struct cdx_mcdi_blocking_data *wait_data;
  367. struct cdx_mcdi_cmd *cmd_item;
  368. unsigned int handle;
  369. int rc;
  370. if (outlen_actual)
  371. *outlen_actual = 0;
  372. wait_data = kmalloc(sizeof(*wait_data), GFP_KERNEL);
  373. if (!wait_data)
  374. return -ENOMEM;
  375. cmd_item = kmalloc(sizeof(*cmd_item), GFP_KERNEL);
  376. if (!cmd_item) {
  377. kfree(wait_data);
  378. return -ENOMEM;
  379. }
  380. kref_init(&wait_data->ref);
  381. wait_data->done = false;
  382. init_waitqueue_head(&wait_data->wq);
  383. wait_data->outbuf = outbuf;
  384. wait_data->outlen = outlen;
  385. kref_init(&cmd_item->ref);
  386. cmd_item->quiet = quiet;
  387. cmd_item->cookie = (unsigned long)wait_data;
  388. cmd_item->completer = &cdx_mcdi_rpc_completer;
  389. cmd_item->cmd = cmd;
  390. cmd_item->inlen = inlen;
  391. cmd_item->inbuf = inbuf;
  392. /* Claim an extra reference for the completer to put. */
  393. kref_get(&wait_data->ref);
  394. rc = cdx_mcdi_rpc_async_internal(cdx, cmd_item, &handle);
  395. if (rc) {
  396. kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release);
  397. goto out;
  398. }
  399. if (!wait_event_timeout(wait_data->wq, wait_data->done,
  400. cdx_mcdi_rpc_timeout(cdx, cmd)) &&
  401. !wait_data->done) {
  402. pr_err("MC command 0x%x inlen %zu timed out (sync)\n",
  403. cmd, inlen);
  404. cdx_mcdi_cancel_cmd(cdx, cmd_item);
  405. wait_data->rc = -ETIMEDOUT;
  406. wait_data->outlen_actual = 0;
  407. }
  408. if (outlen_actual)
  409. *outlen_actual = wait_data->outlen_actual;
  410. rc = wait_data->rc;
  411. out:
  412. kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release);
  413. return rc;
  414. }
  415. static bool cdx_mcdi_get_seq(struct cdx_mcdi_iface *mcdi, unsigned char *seq)
  416. {
  417. *seq = mcdi->prev_seq;
  418. do {
  419. *seq = (*seq + 1) % ARRAY_SIZE(mcdi->seq_held_by);
  420. } while (mcdi->seq_held_by[*seq] && *seq != mcdi->prev_seq);
  421. return !mcdi->seq_held_by[*seq];
  422. }
  423. static int cdx_mcdi_rpc_async_internal(struct cdx_mcdi *cdx,
  424. struct cdx_mcdi_cmd *cmd,
  425. unsigned int *handle)
  426. {
  427. struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx);
  428. LIST_HEAD(cleanup_list);
  429. if (!mcdi) {
  430. kref_put(&cmd->ref, cdx_mcdi_cmd_release);
  431. return -ENETDOWN;
  432. }
  433. if (mcdi->mode == MCDI_MODE_FAIL) {
  434. kref_put(&cmd->ref, cdx_mcdi_cmd_release);
  435. return -ENETDOWN;
  436. }
  437. cmd->mcdi = mcdi;
  438. INIT_WORK(&cmd->work, cdx_mcdi_cmd_work);
  439. INIT_LIST_HEAD(&cmd->list);
  440. INIT_LIST_HEAD(&cmd->cleanup_list);
  441. cmd->rc = 0;
  442. cmd->outbuf = NULL;
  443. cmd->outlen = 0;
  444. queue_work(mcdi->workqueue, &cmd->work);
  445. return 0;
  446. }
  447. static void cdx_mcdi_cmd_start_or_queue(struct cdx_mcdi_iface *mcdi,
  448. struct cdx_mcdi_cmd *cmd)
  449. {
  450. struct cdx_mcdi *cdx = mcdi->cdx;
  451. u8 seq;
  452. if (!mcdi->db_held_by &&
  453. cdx_mcdi_get_seq(mcdi, &seq)) {
  454. cmd->seq = seq;
  455. cmd->reboot_seen = false;
  456. cdx_mcdi_send_request(cdx, cmd);
  457. cmd->state = MCDI_STATE_RUNNING;
  458. } else {
  459. cmd->state = MCDI_STATE_QUEUED;
  460. }
  461. }
  462. /* try to advance other commands */
  463. static void cdx_mcdi_start_or_queue(struct cdx_mcdi_iface *mcdi,
  464. bool allow_retry)
  465. {
  466. struct cdx_mcdi_cmd *cmd, *tmp;
  467. list_for_each_entry_safe(cmd, tmp, &mcdi->cmd_list, list)
  468. if (cmd->state == MCDI_STATE_QUEUED ||
  469. (cmd->state == MCDI_STATE_RETRY && allow_retry))
  470. cdx_mcdi_cmd_start_or_queue(mcdi, cmd);
  471. }
  472. void cdx_mcdi_process_cmd(struct cdx_mcdi *cdx, struct cdx_dword *outbuf, int len)
  473. {
  474. struct cdx_mcdi_iface *mcdi;
  475. struct cdx_mcdi_cmd *cmd;
  476. LIST_HEAD(cleanup_list);
  477. unsigned int respseq;
  478. if (!len || !outbuf) {
  479. pr_err("Got empty MC response\n");
  480. return;
  481. }
  482. mcdi = cdx_mcdi_if(cdx);
  483. if (!mcdi)
  484. return;
  485. respseq = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_SEQ);
  486. mutex_lock(&mcdi->iface_lock);
  487. cmd = mcdi->seq_held_by[respseq];
  488. if (cmd) {
  489. if (cmd->state == MCDI_STATE_FINISHED) {
  490. mutex_unlock(&mcdi->iface_lock);
  491. kref_put(&cmd->ref, cdx_mcdi_cmd_release);
  492. return;
  493. }
  494. cdx_mcdi_complete_cmd(mcdi, cmd, outbuf, len, &cleanup_list);
  495. } else {
  496. pr_err("MC response unexpected for seq : %0X\n", respseq);
  497. }
  498. mutex_unlock(&mcdi->iface_lock);
  499. cdx_mcdi_process_cleanup_list(mcdi->cdx, &cleanup_list);
  500. }
  501. static void cdx_mcdi_cmd_work(struct work_struct *context)
  502. {
  503. struct cdx_mcdi_cmd *cmd =
  504. container_of(context, struct cdx_mcdi_cmd, work);
  505. struct cdx_mcdi_iface *mcdi = cmd->mcdi;
  506. mutex_lock(&mcdi->iface_lock);
  507. cmd->handle = mcdi->prev_handle++;
  508. list_add_tail(&cmd->list, &mcdi->cmd_list);
  509. cdx_mcdi_cmd_start_or_queue(mcdi, cmd);
  510. mutex_unlock(&mcdi->iface_lock);
  511. }
  512. /*
  513. * Returns true if the MCDI module is finished with the command.
  514. * (examples of false would be if the command was proxied, or it was
  515. * rejected by the MC due to lack of resources and requeued).
  516. */
  517. static bool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface *mcdi,
  518. struct cdx_mcdi_cmd *cmd,
  519. struct cdx_dword *outbuf,
  520. int len,
  521. struct list_head *cleanup_list)
  522. {
  523. size_t resp_hdr_len, resp_data_len;
  524. struct cdx_mcdi *cdx = mcdi->cdx;
  525. unsigned int respcmd, error;
  526. bool completed = false;
  527. int rc;
  528. /* ensure the command can't go away before this function returns */
  529. kref_get(&cmd->ref);
  530. respcmd = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_CODE);
  531. error = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_ERROR);
  532. if (respcmd != MC_CMD_V2_EXTN) {
  533. resp_hdr_len = 4;
  534. resp_data_len = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_DATALEN);
  535. } else {
  536. resp_data_len = 0;
  537. resp_hdr_len = 8;
  538. if (len >= 8)
  539. resp_data_len =
  540. CDX_DWORD_FIELD(outbuf[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
  541. }
  542. if ((resp_hdr_len + resp_data_len) > len) {
  543. pr_warn("Incomplete MCDI response received %d. Expected %zu\n",
  544. len, (resp_hdr_len + resp_data_len));
  545. resp_data_len = 0;
  546. }
  547. print_hex_dump_debug("MCDI RESP HEADER: ", DUMP_PREFIX_NONE, 32, 4,
  548. outbuf, resp_hdr_len, false);
  549. print_hex_dump_debug("MCDI RESP PAYLOAD: ", DUMP_PREFIX_NONE, 32, 4,
  550. outbuf + (resp_hdr_len / 4), resp_data_len, false);
  551. if (error && resp_data_len == 0) {
  552. /* MC rebooted during command */
  553. rc = -EIO;
  554. } else {
  555. if (WARN_ON_ONCE(error && resp_data_len < 4))
  556. resp_data_len = 4;
  557. if (error) {
  558. rc = CDX_DWORD_FIELD(outbuf[resp_hdr_len / 4], CDX_DWORD);
  559. if (!cmd->quiet) {
  560. int err_arg = 0;
  561. if (resp_data_len >= MC_CMD_ERR_ARG_OFST + 4) {
  562. int offset = (resp_hdr_len + MC_CMD_ERR_ARG_OFST) / 4;
  563. err_arg = CDX_DWORD_VAL(outbuf[offset]);
  564. }
  565. _cdx_mcdi_display_error(cdx, cmd->cmd,
  566. cmd->inlen, rc, err_arg,
  567. cdx_mcdi_errno(cdx, rc));
  568. }
  569. rc = cdx_mcdi_errno(cdx, rc);
  570. } else {
  571. rc = 0;
  572. }
  573. }
  574. /* free doorbell */
  575. if (mcdi->db_held_by == cmd)
  576. mcdi->db_held_by = NULL;
  577. if (cdx_cmd_cancelled(cmd)) {
  578. list_del(&cmd->list);
  579. kref_put(&cmd->ref, cdx_mcdi_cmd_release);
  580. completed = true;
  581. } else if (rc == MC_CMD_ERR_QUEUE_FULL) {
  582. cmd->state = MCDI_STATE_RETRY;
  583. } else {
  584. cmd->rc = rc;
  585. cmd->outbuf = outbuf + DIV_ROUND_UP(resp_hdr_len, 4);
  586. cmd->outlen = resp_data_len;
  587. cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list);
  588. completed = true;
  589. }
  590. /* free sequence number and buffer */
  591. mcdi->seq_held_by[cmd->seq] = NULL;
  592. cdx_mcdi_start_or_queue(mcdi, rc != MC_CMD_ERR_QUEUE_FULL);
  593. /* wake up anyone waiting for flush */
  594. wake_up(&mcdi->cmd_complete_wq);
  595. kref_put(&cmd->ref, cdx_mcdi_cmd_release);
  596. return completed;
  597. }
  598. static void cdx_mcdi_timeout_cmd(struct cdx_mcdi_iface *mcdi,
  599. struct cdx_mcdi_cmd *cmd,
  600. struct list_head *cleanup_list)
  601. {
  602. struct cdx_mcdi *cdx = mcdi->cdx;
  603. pr_err("MC command 0x%x inlen %zu state %d timed out after %u ms\n",
  604. cmd->cmd, cmd->inlen, cmd->state,
  605. jiffies_to_msecs(jiffies - cmd->started));
  606. cmd->rc = -ETIMEDOUT;
  607. cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list);
  608. cdx_mcdi_mode_fail(cdx, cleanup_list);
  609. }
  610. /**
  611. * cdx_mcdi_rpc - Issue an MCDI command and wait for completion
  612. * @cdx: NIC through which to issue the command
  613. * @cmd: Command type number
  614. * @inbuf: Command parameters
  615. * @inlen: Length of command parameters, in bytes. Must be a multiple
  616. * of 4 and no greater than %MCDI_CTL_SDU_LEN_MAX_V1.
  617. * @outbuf: Response buffer. May be %NULL if @outlen is 0.
  618. * @outlen: Length of response buffer, in bytes. If the actual
  619. * response is longer than @outlen & ~3, it will be truncated
  620. * to that length.
  621. * @outlen_actual: Pointer through which to return the actual response
  622. * length. May be %NULL if this is not needed.
  623. *
  624. * This function may sleep and therefore must be called in process
  625. * context.
  626. *
  627. * Return: A negative error code, or zero if successful. The error
  628. * code may come from the MCDI response or may indicate a failure
  629. * to communicate with the MC. In the former case, the response
  630. * will still be copied to @outbuf and *@outlen_actual will be
  631. * set accordingly. In the latter case, *@outlen_actual will be
  632. * set to zero.
  633. */
  634. int cdx_mcdi_rpc(struct cdx_mcdi *cdx, unsigned int cmd,
  635. const struct cdx_dword *inbuf, size_t inlen,
  636. struct cdx_dword *outbuf, size_t outlen,
  637. size_t *outlen_actual)
  638. {
  639. return cdx_mcdi_rpc_sync(cdx, cmd, inbuf, inlen, outbuf, outlen,
  640. outlen_actual, false);
  641. }
  642. /**
  643. * cdx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously
  644. * @cdx: NIC through which to issue the command
  645. * @cmd: Command type number
  646. * @inbuf: Command parameters
  647. * @inlen: Length of command parameters, in bytes
  648. * @complete: Function to be called on completion or cancellation.
  649. * @cookie: Arbitrary value to be passed to @complete.
  650. *
  651. * This function does not sleep and therefore may be called in atomic
  652. * context. It will fail if event queues are disabled or if MCDI
  653. * event completions have been disabled due to an error.
  654. *
  655. * If it succeeds, the @complete function will be called exactly once
  656. * in process context, when one of the following occurs:
  657. * (a) the completion event is received (in process context)
  658. * (b) event queues are disabled (in the process that disables them)
  659. */
  660. int
  661. cdx_mcdi_rpc_async(struct cdx_mcdi *cdx, unsigned int cmd,
  662. const struct cdx_dword *inbuf, size_t inlen,
  663. cdx_mcdi_async_completer *complete, unsigned long cookie)
  664. {
  665. struct cdx_mcdi_cmd *cmd_item =
  666. kmalloc(sizeof(struct cdx_mcdi_cmd) + inlen, GFP_ATOMIC);
  667. if (!cmd_item)
  668. return -ENOMEM;
  669. kref_init(&cmd_item->ref);
  670. cmd_item->quiet = true;
  671. cmd_item->cookie = cookie;
  672. cmd_item->completer = complete;
  673. cmd_item->cmd = cmd;
  674. cmd_item->inlen = inlen;
  675. /* inbuf is probably not valid after return, so take a copy */
  676. cmd_item->inbuf = (struct cdx_dword *)(cmd_item + 1);
  677. memcpy(cmd_item + 1, inbuf, inlen);
  678. return cdx_mcdi_rpc_async_internal(cdx, cmd_item, NULL);
  679. }
  680. static void _cdx_mcdi_display_error(struct cdx_mcdi *cdx, unsigned int cmd,
  681. size_t inlen, int raw, int arg, int err_no)
  682. {
  683. pr_err("MC command 0x%x inlen %d failed err_no=%d (raw=%d) arg=%d\n",
  684. cmd, (int)inlen, err_no, raw, arg);
  685. }
  686. /*
  687. * Set MCDI mode to fail to prevent any new commands, then cancel any
  688. * outstanding commands.
  689. * Caller must hold the mcdi iface_lock.
  690. */
  691. static void cdx_mcdi_mode_fail(struct cdx_mcdi *cdx, struct list_head *cleanup_list)
  692. {
  693. struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx);
  694. if (!mcdi)
  695. return;
  696. mcdi->mode = MCDI_MODE_FAIL;
  697. while (!list_empty(&mcdi->cmd_list)) {
  698. struct cdx_mcdi_cmd *cmd;
  699. cmd = list_first_entry(&mcdi->cmd_list, struct cdx_mcdi_cmd,
  700. list);
  701. _cdx_mcdi_cancel_cmd(mcdi, cdx_mcdi_cmd_handle(cmd), cleanup_list);
  702. }
  703. }