hbm.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. /*
  2. * ISHTP bus layer messages handling
  3. *
  4. * Copyright (c) 2003-2016, 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/slab.h>
  18. #include <linux/sched.h>
  19. #include <linux/wait.h>
  20. #include <linux/spinlock.h>
  21. #include "ishtp-dev.h"
  22. #include "hbm.h"
  23. #include "client.h"
  24. /**
  25. * ishtp_hbm_fw_cl_allocate() - Allocate FW clients
  26. * @dev: ISHTP device instance
  27. *
  28. * Allocates storage for fw clients
  29. */
  30. static void ishtp_hbm_fw_cl_allocate(struct ishtp_device *dev)
  31. {
  32. struct ishtp_fw_client *clients;
  33. int b;
  34. /* count how many ISH clients we have */
  35. for_each_set_bit(b, dev->fw_clients_map, ISHTP_CLIENTS_MAX)
  36. dev->fw_clients_num++;
  37. if (dev->fw_clients_num <= 0)
  38. return;
  39. /* allocate storage for fw clients representation */
  40. clients = kcalloc(dev->fw_clients_num, sizeof(struct ishtp_fw_client),
  41. GFP_KERNEL);
  42. if (!clients) {
  43. dev->dev_state = ISHTP_DEV_RESETTING;
  44. ish_hw_reset(dev);
  45. return;
  46. }
  47. dev->fw_clients = clients;
  48. }
  49. /**
  50. * ishtp_hbm_cl_hdr() - construct client hbm header
  51. * @cl: client
  52. * @hbm_cmd: host bus message command
  53. * @buf: buffer for cl header
  54. * @len: buffer length
  55. *
  56. * Initialize HBM buffer
  57. */
  58. static inline void ishtp_hbm_cl_hdr(struct ishtp_cl *cl, uint8_t hbm_cmd,
  59. void *buf, size_t len)
  60. {
  61. struct ishtp_hbm_cl_cmd *cmd = buf;
  62. memset(cmd, 0, len);
  63. cmd->hbm_cmd = hbm_cmd;
  64. cmd->host_addr = cl->host_client_id;
  65. cmd->fw_addr = cl->fw_client_id;
  66. }
  67. /**
  68. * ishtp_hbm_cl_addr_equal() - Compare client address
  69. * @cl: client
  70. * @buf: Client command buffer
  71. *
  72. * Compare client address with the address in command buffer
  73. *
  74. * Return: True if they have the same address
  75. */
  76. static inline bool ishtp_hbm_cl_addr_equal(struct ishtp_cl *cl, void *buf)
  77. {
  78. struct ishtp_hbm_cl_cmd *cmd = buf;
  79. return cl->host_client_id == cmd->host_addr &&
  80. cl->fw_client_id == cmd->fw_addr;
  81. }
  82. /**
  83. * ishtp_hbm_start_wait() - Wait for HBM start message
  84. * @dev: ISHTP device instance
  85. *
  86. * Wait for HBM start message from firmware
  87. *
  88. * Return: 0 if HBM start is/was received else timeout error
  89. */
  90. int ishtp_hbm_start_wait(struct ishtp_device *dev)
  91. {
  92. int ret;
  93. if (dev->hbm_state > ISHTP_HBM_START)
  94. return 0;
  95. dev_dbg(dev->devc, "Going to wait for ishtp start. hbm_state=%08X\n",
  96. dev->hbm_state);
  97. ret = wait_event_interruptible_timeout(dev->wait_hbm_recvd_msg,
  98. dev->hbm_state >= ISHTP_HBM_STARTED,
  99. (ISHTP_INTEROP_TIMEOUT * HZ));
  100. dev_dbg(dev->devc,
  101. "Woke up from waiting for ishtp start. hbm_state=%08X\n",
  102. dev->hbm_state);
  103. if (ret <= 0 && (dev->hbm_state <= ISHTP_HBM_START)) {
  104. dev->hbm_state = ISHTP_HBM_IDLE;
  105. dev_err(dev->devc,
  106. "waiting for ishtp start failed. ret=%d hbm_state=%08X\n",
  107. ret, dev->hbm_state);
  108. return -ETIMEDOUT;
  109. }
  110. return 0;
  111. }
  112. /**
  113. * ishtp_hbm_start_req() - Send HBM start message
  114. * @dev: ISHTP device instance
  115. *
  116. * Send HBM start message to firmware
  117. *
  118. * Return: 0 if success else error code
  119. */
  120. int ishtp_hbm_start_req(struct ishtp_device *dev)
  121. {
  122. struct ishtp_msg_hdr hdr;
  123. unsigned char data[128];
  124. struct ishtp_msg_hdr *ishtp_hdr = &hdr;
  125. struct hbm_host_version_request *start_req;
  126. const size_t len = sizeof(struct hbm_host_version_request);
  127. ishtp_hbm_hdr(ishtp_hdr, len);
  128. /* host start message */
  129. start_req = (struct hbm_host_version_request *)data;
  130. memset(start_req, 0, len);
  131. start_req->hbm_cmd = HOST_START_REQ_CMD;
  132. start_req->host_version.major_version = HBM_MAJOR_VERSION;
  133. start_req->host_version.minor_version = HBM_MINOR_VERSION;
  134. /*
  135. * (!) Response to HBM start may be so quick that this thread would get
  136. * preempted BEFORE managing to set hbm_state = ISHTP_HBM_START.
  137. * So set it at first, change back to ISHTP_HBM_IDLE upon failure
  138. */
  139. dev->hbm_state = ISHTP_HBM_START;
  140. if (ishtp_write_message(dev, ishtp_hdr, data)) {
  141. dev_err(dev->devc, "version message send failed\n");
  142. dev->dev_state = ISHTP_DEV_RESETTING;
  143. dev->hbm_state = ISHTP_HBM_IDLE;
  144. ish_hw_reset(dev);
  145. return -ENODEV;
  146. }
  147. return 0;
  148. }
  149. /**
  150. * ishtp_hbm_enum_clients_req() - Send client enum req
  151. * @dev: ISHTP device instance
  152. *
  153. * Send enumeration client request message
  154. *
  155. * Return: 0 if success else error code
  156. */
  157. void ishtp_hbm_enum_clients_req(struct ishtp_device *dev)
  158. {
  159. struct ishtp_msg_hdr hdr;
  160. unsigned char data[128];
  161. struct ishtp_msg_hdr *ishtp_hdr = &hdr;
  162. struct hbm_host_enum_request *enum_req;
  163. const size_t len = sizeof(struct hbm_host_enum_request);
  164. /* enumerate clients */
  165. ishtp_hbm_hdr(ishtp_hdr, len);
  166. enum_req = (struct hbm_host_enum_request *)data;
  167. memset(enum_req, 0, len);
  168. enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
  169. if (ishtp_write_message(dev, ishtp_hdr, data)) {
  170. dev->dev_state = ISHTP_DEV_RESETTING;
  171. dev_err(dev->devc, "enumeration request send failed\n");
  172. ish_hw_reset(dev);
  173. }
  174. dev->hbm_state = ISHTP_HBM_ENUM_CLIENTS;
  175. }
  176. /**
  177. * ishtp_hbm_prop_req() - Request property
  178. * @dev: ISHTP device instance
  179. *
  180. * Request property for a single client
  181. *
  182. * Return: 0 if success else error code
  183. */
  184. static int ishtp_hbm_prop_req(struct ishtp_device *dev)
  185. {
  186. struct ishtp_msg_hdr hdr;
  187. unsigned char data[128];
  188. struct ishtp_msg_hdr *ishtp_hdr = &hdr;
  189. struct hbm_props_request *prop_req;
  190. const size_t len = sizeof(struct hbm_props_request);
  191. unsigned long next_client_index;
  192. uint8_t client_num;
  193. client_num = dev->fw_client_presentation_num;
  194. next_client_index = find_next_bit(dev->fw_clients_map,
  195. ISHTP_CLIENTS_MAX, dev->fw_client_index);
  196. /* We got all client properties */
  197. if (next_client_index == ISHTP_CLIENTS_MAX) {
  198. dev->hbm_state = ISHTP_HBM_WORKING;
  199. dev->dev_state = ISHTP_DEV_ENABLED;
  200. for (dev->fw_client_presentation_num = 1;
  201. dev->fw_client_presentation_num < client_num + 1;
  202. ++dev->fw_client_presentation_num)
  203. /* Add new client device */
  204. ishtp_bus_new_client(dev);
  205. return 0;
  206. }
  207. dev->fw_clients[client_num].client_id = next_client_index;
  208. ishtp_hbm_hdr(ishtp_hdr, len);
  209. prop_req = (struct hbm_props_request *)data;
  210. memset(prop_req, 0, sizeof(struct hbm_props_request));
  211. prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
  212. prop_req->address = next_client_index;
  213. if (ishtp_write_message(dev, ishtp_hdr, data)) {
  214. dev->dev_state = ISHTP_DEV_RESETTING;
  215. dev_err(dev->devc, "properties request send failed\n");
  216. ish_hw_reset(dev);
  217. return -EIO;
  218. }
  219. dev->fw_client_index = next_client_index;
  220. return 0;
  221. }
  222. /**
  223. * ishtp_hbm_stop_req() - Send HBM stop
  224. * @dev: ISHTP device instance
  225. *
  226. * Send stop request message
  227. */
  228. static void ishtp_hbm_stop_req(struct ishtp_device *dev)
  229. {
  230. struct ishtp_msg_hdr hdr;
  231. unsigned char data[128];
  232. struct ishtp_msg_hdr *ishtp_hdr = &hdr;
  233. struct hbm_host_stop_request *req;
  234. const size_t len = sizeof(struct hbm_host_stop_request);
  235. ishtp_hbm_hdr(ishtp_hdr, len);
  236. req = (struct hbm_host_stop_request *)data;
  237. memset(req, 0, sizeof(struct hbm_host_stop_request));
  238. req->hbm_cmd = HOST_STOP_REQ_CMD;
  239. req->reason = DRIVER_STOP_REQUEST;
  240. ishtp_write_message(dev, ishtp_hdr, data);
  241. }
  242. /**
  243. * ishtp_hbm_cl_flow_control_req() - Send flow control request
  244. * @dev: ISHTP device instance
  245. * @cl: ISHTP client instance
  246. *
  247. * Send flow control request
  248. *
  249. * Return: 0 if success else error code
  250. */
  251. int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
  252. struct ishtp_cl *cl)
  253. {
  254. struct ishtp_msg_hdr hdr;
  255. unsigned char data[128];
  256. struct ishtp_msg_hdr *ishtp_hdr = &hdr;
  257. const size_t len = sizeof(struct hbm_flow_control);
  258. int rv;
  259. unsigned long flags;
  260. spin_lock_irqsave(&cl->fc_spinlock, flags);
  261. ishtp_hbm_hdr(ishtp_hdr, len);
  262. ishtp_hbm_cl_hdr(cl, ISHTP_FLOW_CONTROL_CMD, data, len);
  263. /*
  264. * Sync possible race when RB recycle and packet receive paths
  265. * both try to send an out FC
  266. */
  267. if (cl->out_flow_ctrl_creds) {
  268. spin_unlock_irqrestore(&cl->fc_spinlock, flags);
  269. return 0;
  270. }
  271. cl->recv_msg_num_frags = 0;
  272. rv = ishtp_write_message(dev, ishtp_hdr, data);
  273. if (!rv) {
  274. ++cl->out_flow_ctrl_creds;
  275. ++cl->out_flow_ctrl_cnt;
  276. cl->ts_out_fc = ktime_get();
  277. if (cl->ts_rx) {
  278. ktime_t ts_diff = ktime_sub(cl->ts_out_fc, cl->ts_rx);
  279. if (ktime_after(ts_diff, cl->ts_max_fc_delay))
  280. cl->ts_max_fc_delay = ts_diff;
  281. }
  282. } else {
  283. ++cl->err_send_fc;
  284. }
  285. spin_unlock_irqrestore(&cl->fc_spinlock, flags);
  286. return rv;
  287. }
  288. /**
  289. * ishtp_hbm_cl_disconnect_req() - Send disconnect request
  290. * @dev: ISHTP device instance
  291. * @cl: ISHTP client instance
  292. *
  293. * Send disconnect message to fw
  294. *
  295. * Return: 0 if success else error code
  296. */
  297. int ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
  298. {
  299. struct ishtp_msg_hdr hdr;
  300. unsigned char data[128];
  301. struct ishtp_msg_hdr *ishtp_hdr = &hdr;
  302. const size_t len = sizeof(struct hbm_client_connect_request);
  303. ishtp_hbm_hdr(ishtp_hdr, len);
  304. ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, data, len);
  305. return ishtp_write_message(dev, ishtp_hdr, data);
  306. }
  307. /**
  308. * ishtp_hbm_cl_disconnect_res() - Get disconnect response
  309. * @dev: ISHTP device instance
  310. * @rs: Response message
  311. *
  312. * Received disconnect response from fw
  313. */
  314. static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev,
  315. struct hbm_client_connect_response *rs)
  316. {
  317. struct ishtp_cl *cl = NULL;
  318. unsigned long flags;
  319. spin_lock_irqsave(&dev->cl_list_lock, flags);
  320. list_for_each_entry(cl, &dev->cl_list, link) {
  321. if (!rs->status && ishtp_hbm_cl_addr_equal(cl, rs)) {
  322. cl->state = ISHTP_CL_DISCONNECTED;
  323. wake_up_interruptible(&cl->wait_ctrl_res);
  324. break;
  325. }
  326. }
  327. spin_unlock_irqrestore(&dev->cl_list_lock, flags);
  328. }
  329. /**
  330. * ishtp_hbm_cl_connect_req() - Send connect request
  331. * @dev: ISHTP device instance
  332. * @cl: client device instance
  333. *
  334. * Send connection request to specific fw client
  335. *
  336. * Return: 0 if success else error code
  337. */
  338. int ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
  339. {
  340. struct ishtp_msg_hdr hdr;
  341. unsigned char data[128];
  342. struct ishtp_msg_hdr *ishtp_hdr = &hdr;
  343. const size_t len = sizeof(struct hbm_client_connect_request);
  344. ishtp_hbm_hdr(ishtp_hdr, len);
  345. ishtp_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, data, len);
  346. return ishtp_write_message(dev, ishtp_hdr, data);
  347. }
  348. /**
  349. * ishtp_hbm_cl_connect_res() - Get connect response
  350. * @dev: ISHTP device instance
  351. * @rs: Response message
  352. *
  353. * Received connect response from fw
  354. */
  355. static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
  356. struct hbm_client_connect_response *rs)
  357. {
  358. struct ishtp_cl *cl = NULL;
  359. unsigned long flags;
  360. spin_lock_irqsave(&dev->cl_list_lock, flags);
  361. list_for_each_entry(cl, &dev->cl_list, link) {
  362. if (ishtp_hbm_cl_addr_equal(cl, rs)) {
  363. if (!rs->status) {
  364. cl->state = ISHTP_CL_CONNECTED;
  365. cl->status = 0;
  366. } else {
  367. cl->state = ISHTP_CL_DISCONNECTED;
  368. cl->status = -ENODEV;
  369. }
  370. wake_up_interruptible(&cl->wait_ctrl_res);
  371. break;
  372. }
  373. }
  374. spin_unlock_irqrestore(&dev->cl_list_lock, flags);
  375. }
  376. /**
  377. * ishtp_client_disconnect_request() - Receive disconnect request
  378. * @dev: ISHTP device instance
  379. * @disconnect_req: disconnect request structure
  380. *
  381. * Disconnect request bus message from the fw. Send diconnect response.
  382. */
  383. static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev,
  384. struct hbm_client_connect_request *disconnect_req)
  385. {
  386. struct ishtp_cl *cl;
  387. const size_t len = sizeof(struct hbm_client_connect_response);
  388. unsigned long flags;
  389. struct ishtp_msg_hdr hdr;
  390. unsigned char data[4]; /* All HBM messages are 4 bytes */
  391. spin_lock_irqsave(&dev->cl_list_lock, flags);
  392. list_for_each_entry(cl, &dev->cl_list, link) {
  393. if (ishtp_hbm_cl_addr_equal(cl, disconnect_req)) {
  394. cl->state = ISHTP_CL_DISCONNECTED;
  395. /* send disconnect response */
  396. ishtp_hbm_hdr(&hdr, len);
  397. ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, data,
  398. len);
  399. ishtp_write_message(dev, &hdr, data);
  400. break;
  401. }
  402. }
  403. spin_unlock_irqrestore(&dev->cl_list_lock, flags);
  404. }
  405. /**
  406. * ishtp_hbm_dma_xfer_ack(() - Receive transfer ACK
  407. * @dev: ISHTP device instance
  408. * @dma_xfer: HBM transfer message
  409. *
  410. * Receive ack for ISHTP-over-DMA client message
  411. */
  412. static void ishtp_hbm_dma_xfer_ack(struct ishtp_device *dev,
  413. struct dma_xfer_hbm *dma_xfer)
  414. {
  415. void *msg;
  416. uint64_t offs;
  417. struct ishtp_msg_hdr *ishtp_hdr =
  418. (struct ishtp_msg_hdr *)&dev->ishtp_msg_hdr;
  419. unsigned int msg_offs;
  420. struct ishtp_cl *cl;
  421. for (msg_offs = 0; msg_offs < ishtp_hdr->length;
  422. msg_offs += sizeof(struct dma_xfer_hbm)) {
  423. offs = dma_xfer->msg_addr - dev->ishtp_host_dma_tx_buf_phys;
  424. if (offs > dev->ishtp_host_dma_tx_buf_size) {
  425. dev_err(dev->devc, "Bad DMA Tx ack message address\n");
  426. return;
  427. }
  428. if (dma_xfer->msg_length >
  429. dev->ishtp_host_dma_tx_buf_size - offs) {
  430. dev_err(dev->devc, "Bad DMA Tx ack message size\n");
  431. return;
  432. }
  433. /* logical address of the acked mem */
  434. msg = (unsigned char *)dev->ishtp_host_dma_tx_buf + offs;
  435. ishtp_cl_release_dma_acked_mem(dev, msg, dma_xfer->msg_length);
  436. list_for_each_entry(cl, &dev->cl_list, link) {
  437. if (cl->fw_client_id == dma_xfer->fw_client_id &&
  438. cl->host_client_id == dma_xfer->host_client_id)
  439. /*
  440. * in case that a single ack may be sent
  441. * over several dma transfers, and the last msg
  442. * addr was inside the acked memory, but not in
  443. * its start
  444. */
  445. if (cl->last_dma_addr >=
  446. (unsigned char *)msg &&
  447. cl->last_dma_addr <
  448. (unsigned char *)msg +
  449. dma_xfer->msg_length) {
  450. cl->last_dma_acked = 1;
  451. if (!list_empty(&cl->tx_list.list) &&
  452. cl->ishtp_flow_ctrl_creds) {
  453. /*
  454. * start sending the first msg
  455. */
  456. ishtp_cl_send_msg(dev, cl);
  457. }
  458. }
  459. }
  460. ++dma_xfer;
  461. }
  462. }
  463. /**
  464. * ishtp_hbm_dma_xfer() - Receive DMA transfer message
  465. * @dev: ISHTP device instance
  466. * @dma_xfer: HBM transfer message
  467. *
  468. * Receive ISHTP-over-DMA client message
  469. */
  470. static void ishtp_hbm_dma_xfer(struct ishtp_device *dev,
  471. struct dma_xfer_hbm *dma_xfer)
  472. {
  473. void *msg;
  474. uint64_t offs;
  475. struct ishtp_msg_hdr hdr;
  476. struct ishtp_msg_hdr *ishtp_hdr =
  477. (struct ishtp_msg_hdr *) &dev->ishtp_msg_hdr;
  478. struct dma_xfer_hbm *prm = dma_xfer;
  479. unsigned int msg_offs;
  480. for (msg_offs = 0; msg_offs < ishtp_hdr->length;
  481. msg_offs += sizeof(struct dma_xfer_hbm)) {
  482. offs = dma_xfer->msg_addr - dev->ishtp_host_dma_rx_buf_phys;
  483. if (offs > dev->ishtp_host_dma_rx_buf_size) {
  484. dev_err(dev->devc, "Bad DMA Rx message address\n");
  485. return;
  486. }
  487. if (dma_xfer->msg_length >
  488. dev->ishtp_host_dma_rx_buf_size - offs) {
  489. dev_err(dev->devc, "Bad DMA Rx message size\n");
  490. return;
  491. }
  492. msg = dev->ishtp_host_dma_rx_buf + offs;
  493. recv_ishtp_cl_msg_dma(dev, msg, dma_xfer);
  494. dma_xfer->hbm = DMA_XFER_ACK; /* Prepare for response */
  495. ++dma_xfer;
  496. }
  497. /* Send DMA_XFER_ACK [...] */
  498. ishtp_hbm_hdr(&hdr, ishtp_hdr->length);
  499. ishtp_write_message(dev, &hdr, (unsigned char *)prm);
  500. }
  501. /**
  502. * ishtp_hbm_dispatch() - HBM dispatch function
  503. * @dev: ISHTP device instance
  504. * @hdr: bus message
  505. *
  506. * Bottom half read routine after ISR to handle the read bus message cmd
  507. * processing
  508. */
  509. void ishtp_hbm_dispatch(struct ishtp_device *dev,
  510. struct ishtp_bus_message *hdr)
  511. {
  512. struct ishtp_bus_message *ishtp_msg;
  513. struct ishtp_fw_client *fw_client;
  514. struct hbm_host_version_response *version_res;
  515. struct hbm_client_connect_response *connect_res;
  516. struct hbm_client_connect_response *disconnect_res;
  517. struct hbm_client_connect_request *disconnect_req;
  518. struct hbm_props_response *props_res;
  519. struct hbm_host_enum_response *enum_res;
  520. struct ishtp_msg_hdr ishtp_hdr;
  521. struct dma_alloc_notify dma_alloc_notify;
  522. struct dma_xfer_hbm *dma_xfer;
  523. ishtp_msg = hdr;
  524. switch (ishtp_msg->hbm_cmd) {
  525. case HOST_START_RES_CMD:
  526. version_res = (struct hbm_host_version_response *)ishtp_msg;
  527. if (!version_res->host_version_supported) {
  528. dev->version = version_res->fw_max_version;
  529. dev->hbm_state = ISHTP_HBM_STOPPED;
  530. ishtp_hbm_stop_req(dev);
  531. return;
  532. }
  533. dev->version.major_version = HBM_MAJOR_VERSION;
  534. dev->version.minor_version = HBM_MINOR_VERSION;
  535. if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
  536. dev->hbm_state == ISHTP_HBM_START) {
  537. dev->hbm_state = ISHTP_HBM_STARTED;
  538. ishtp_hbm_enum_clients_req(dev);
  539. } else {
  540. dev_err(dev->devc,
  541. "reset: wrong host start response\n");
  542. /* BUG: why do we arrive here? */
  543. ish_hw_reset(dev);
  544. return;
  545. }
  546. wake_up_interruptible(&dev->wait_hbm_recvd_msg);
  547. break;
  548. case CLIENT_CONNECT_RES_CMD:
  549. connect_res = (struct hbm_client_connect_response *)ishtp_msg;
  550. ishtp_hbm_cl_connect_res(dev, connect_res);
  551. break;
  552. case CLIENT_DISCONNECT_RES_CMD:
  553. disconnect_res =
  554. (struct hbm_client_connect_response *)ishtp_msg;
  555. ishtp_hbm_cl_disconnect_res(dev, disconnect_res);
  556. break;
  557. case HOST_CLIENT_PROPERTIES_RES_CMD:
  558. props_res = (struct hbm_props_response *)ishtp_msg;
  559. fw_client = &dev->fw_clients[dev->fw_client_presentation_num];
  560. if (props_res->status || !dev->fw_clients) {
  561. dev_err(dev->devc,
  562. "reset: properties response hbm wrong status\n");
  563. ish_hw_reset(dev);
  564. return;
  565. }
  566. if (fw_client->client_id != props_res->address) {
  567. dev_err(dev->devc,
  568. "reset: host properties response address mismatch [%02X %02X]\n",
  569. fw_client->client_id, props_res->address);
  570. ish_hw_reset(dev);
  571. return;
  572. }
  573. if (dev->dev_state != ISHTP_DEV_INIT_CLIENTS ||
  574. dev->hbm_state != ISHTP_HBM_CLIENT_PROPERTIES) {
  575. dev_err(dev->devc,
  576. "reset: unexpected properties response\n");
  577. ish_hw_reset(dev);
  578. return;
  579. }
  580. fw_client->props = props_res->client_properties;
  581. dev->fw_client_index++;
  582. dev->fw_client_presentation_num++;
  583. /* request property for the next client */
  584. ishtp_hbm_prop_req(dev);
  585. if (dev->dev_state != ISHTP_DEV_ENABLED)
  586. break;
  587. if (!ishtp_use_dma_transfer())
  588. break;
  589. dev_dbg(dev->devc, "Requesting to use DMA\n");
  590. ishtp_cl_alloc_dma_buf(dev);
  591. if (dev->ishtp_host_dma_rx_buf) {
  592. const size_t len = sizeof(dma_alloc_notify);
  593. memset(&dma_alloc_notify, 0, sizeof(dma_alloc_notify));
  594. dma_alloc_notify.hbm = DMA_BUFFER_ALLOC_NOTIFY;
  595. dma_alloc_notify.buf_size =
  596. dev->ishtp_host_dma_rx_buf_size;
  597. dma_alloc_notify.buf_address =
  598. dev->ishtp_host_dma_rx_buf_phys;
  599. ishtp_hbm_hdr(&ishtp_hdr, len);
  600. ishtp_write_message(dev, &ishtp_hdr,
  601. (unsigned char *)&dma_alloc_notify);
  602. }
  603. break;
  604. case HOST_ENUM_RES_CMD:
  605. enum_res = (struct hbm_host_enum_response *) ishtp_msg;
  606. memcpy(dev->fw_clients_map, enum_res->valid_addresses, 32);
  607. if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS &&
  608. dev->hbm_state == ISHTP_HBM_ENUM_CLIENTS) {
  609. dev->fw_client_presentation_num = 0;
  610. dev->fw_client_index = 0;
  611. ishtp_hbm_fw_cl_allocate(dev);
  612. dev->hbm_state = ISHTP_HBM_CLIENT_PROPERTIES;
  613. /* first property request */
  614. ishtp_hbm_prop_req(dev);
  615. } else {
  616. dev_err(dev->devc,
  617. "reset: unexpected enumeration response hbm\n");
  618. ish_hw_reset(dev);
  619. return;
  620. }
  621. break;
  622. case HOST_STOP_RES_CMD:
  623. if (dev->hbm_state != ISHTP_HBM_STOPPED)
  624. dev_err(dev->devc, "unexpected stop response\n");
  625. dev->dev_state = ISHTP_DEV_DISABLED;
  626. dev_info(dev->devc, "reset: FW stop response\n");
  627. ish_hw_reset(dev);
  628. break;
  629. case CLIENT_DISCONNECT_REQ_CMD:
  630. /* search for client */
  631. disconnect_req =
  632. (struct hbm_client_connect_request *)ishtp_msg;
  633. ishtp_hbm_fw_disconnect_req(dev, disconnect_req);
  634. break;
  635. case FW_STOP_REQ_CMD:
  636. dev->hbm_state = ISHTP_HBM_STOPPED;
  637. break;
  638. case DMA_BUFFER_ALLOC_RESPONSE:
  639. dev->ishtp_host_dma_enabled = 1;
  640. break;
  641. case DMA_XFER:
  642. dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
  643. if (!dev->ishtp_host_dma_enabled) {
  644. dev_err(dev->devc,
  645. "DMA XFER requested but DMA is not enabled\n");
  646. break;
  647. }
  648. ishtp_hbm_dma_xfer(dev, dma_xfer);
  649. break;
  650. case DMA_XFER_ACK:
  651. dma_xfer = (struct dma_xfer_hbm *)ishtp_msg;
  652. if (!dev->ishtp_host_dma_enabled ||
  653. !dev->ishtp_host_dma_tx_buf) {
  654. dev_err(dev->devc,
  655. "DMA XFER acked but DMA Tx is not enabled\n");
  656. break;
  657. }
  658. ishtp_hbm_dma_xfer_ack(dev, dma_xfer);
  659. break;
  660. default:
  661. dev_err(dev->devc, "unknown HBM: %u\n",
  662. (unsigned int)ishtp_msg->hbm_cmd);
  663. break;
  664. }
  665. }
  666. /**
  667. * bh_hbm_work_fn() - HBM work function
  668. * @work: work struct
  669. *
  670. * Bottom half processing work function (instead of thread handler)
  671. * for processing hbm messages
  672. */
  673. void bh_hbm_work_fn(struct work_struct *work)
  674. {
  675. unsigned long flags;
  676. struct ishtp_device *dev;
  677. unsigned char hbm[IPC_PAYLOAD_SIZE];
  678. dev = container_of(work, struct ishtp_device, bh_hbm_work);
  679. spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
  680. if (dev->rd_msg_fifo_head != dev->rd_msg_fifo_tail) {
  681. memcpy(hbm, dev->rd_msg_fifo + dev->rd_msg_fifo_head,
  682. IPC_PAYLOAD_SIZE);
  683. dev->rd_msg_fifo_head =
  684. (dev->rd_msg_fifo_head + IPC_PAYLOAD_SIZE) %
  685. (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
  686. spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
  687. ishtp_hbm_dispatch(dev, (struct ishtp_bus_message *)hbm);
  688. } else {
  689. spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
  690. }
  691. }
  692. /**
  693. * recv_hbm() - Receive HBM message
  694. * @dev: ISHTP device instance
  695. * @ishtp_hdr: received bus message
  696. *
  697. * Receive and process ISHTP bus messages in ISR context. This will schedule
  698. * work function to process message
  699. */
  700. void recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr)
  701. {
  702. uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
  703. struct ishtp_bus_message *ishtp_msg =
  704. (struct ishtp_bus_message *)rd_msg_buf;
  705. unsigned long flags;
  706. dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
  707. /* Flow control - handle in place */
  708. if (ishtp_msg->hbm_cmd == ISHTP_FLOW_CONTROL_CMD) {
  709. struct hbm_flow_control *flow_control =
  710. (struct hbm_flow_control *)ishtp_msg;
  711. struct ishtp_cl *cl = NULL;
  712. unsigned long flags, tx_flags;
  713. spin_lock_irqsave(&dev->cl_list_lock, flags);
  714. list_for_each_entry(cl, &dev->cl_list, link) {
  715. if (cl->host_client_id == flow_control->host_addr &&
  716. cl->fw_client_id ==
  717. flow_control->fw_addr) {
  718. /*
  719. * NOTE: It's valid only for counting
  720. * flow-control implementation to receive a
  721. * FC in the middle of sending. Meanwhile not
  722. * supported
  723. */
  724. if (cl->ishtp_flow_ctrl_creds)
  725. dev_err(dev->devc,
  726. "recv extra FC from FW client %u (host client %u) (FC count was %d)\n",
  727. (unsigned int)cl->fw_client_id,
  728. (unsigned int)cl->host_client_id,
  729. cl->ishtp_flow_ctrl_creds);
  730. else {
  731. ++cl->ishtp_flow_ctrl_creds;
  732. ++cl->ishtp_flow_ctrl_cnt;
  733. cl->last_ipc_acked = 1;
  734. spin_lock_irqsave(
  735. &cl->tx_list_spinlock,
  736. tx_flags);
  737. if (!list_empty(&cl->tx_list.list)) {
  738. /*
  739. * start sending the first msg
  740. * = the callback function
  741. */
  742. spin_unlock_irqrestore(
  743. &cl->tx_list_spinlock,
  744. tx_flags);
  745. ishtp_cl_send_msg(dev, cl);
  746. } else {
  747. spin_unlock_irqrestore(
  748. &cl->tx_list_spinlock,
  749. tx_flags);
  750. }
  751. }
  752. break;
  753. }
  754. }
  755. spin_unlock_irqrestore(&dev->cl_list_lock, flags);
  756. goto eoi;
  757. }
  758. /*
  759. * Some messages that are safe for ISR processing and important
  760. * to be done "quickly" and in-order, go here
  761. */
  762. if (ishtp_msg->hbm_cmd == CLIENT_CONNECT_RES_CMD ||
  763. ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_RES_CMD ||
  764. ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_REQ_CMD ||
  765. ishtp_msg->hbm_cmd == DMA_XFER) {
  766. ishtp_hbm_dispatch(dev, ishtp_msg);
  767. goto eoi;
  768. }
  769. /*
  770. * All other HBMs go here.
  771. * We schedule HBMs for processing serially by using system wq,
  772. * possibly there will be multiple HBMs scheduled at the same time.
  773. */
  774. spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
  775. if ((dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
  776. (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE) ==
  777. dev->rd_msg_fifo_head) {
  778. spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
  779. dev_err(dev->devc, "BH buffer overflow, dropping HBM %u\n",
  780. (unsigned int)ishtp_msg->hbm_cmd);
  781. goto eoi;
  782. }
  783. memcpy(dev->rd_msg_fifo + dev->rd_msg_fifo_tail, ishtp_msg,
  784. ishtp_hdr->length);
  785. dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
  786. (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
  787. spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
  788. schedule_work(&dev->bh_hbm_work);
  789. eoi:
  790. return;
  791. }
  792. /**
  793. * recv_fixed_cl_msg() - Receive fixed client message
  794. * @dev: ISHTP device instance
  795. * @ishtp_hdr: received bus message
  796. *
  797. * Receive and process ISHTP fixed client messages (address == 0)
  798. * in ISR context
  799. */
  800. void recv_fixed_cl_msg(struct ishtp_device *dev,
  801. struct ishtp_msg_hdr *ishtp_hdr)
  802. {
  803. uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE];
  804. dev->print_log(dev,
  805. "%s() got fixed client msg from client #%d\n",
  806. __func__, ishtp_hdr->fw_addr);
  807. dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length);
  808. if (ishtp_hdr->fw_addr == ISHTP_SYSTEM_STATE_CLIENT_ADDR) {
  809. struct ish_system_states_header *msg_hdr =
  810. (struct ish_system_states_header *)rd_msg_buf;
  811. if (msg_hdr->cmd == SYSTEM_STATE_SUBSCRIBE)
  812. ishtp_send_resume(dev);
  813. /* if FW request arrived here, the system is not suspended */
  814. else
  815. dev_err(dev->devc, "unknown fixed client msg [%02X]\n",
  816. msg_hdr->cmd);
  817. }
  818. }
  819. /**
  820. * fix_cl_hdr() - Initialize fixed client header
  821. * @hdr: message header
  822. * @length: length of message
  823. * @cl_addr: Client address
  824. *
  825. * Initialize message header for fixed client
  826. */
  827. static inline void fix_cl_hdr(struct ishtp_msg_hdr *hdr, size_t length,
  828. uint8_t cl_addr)
  829. {
  830. hdr->host_addr = 0;
  831. hdr->fw_addr = cl_addr;
  832. hdr->length = length;
  833. hdr->msg_complete = 1;
  834. hdr->reserved = 0;
  835. }
  836. /*** Suspend and resume notification ***/
  837. static uint32_t current_state;
  838. static uint32_t supported_states = 0 | SUSPEND_STATE_BIT;
  839. /**
  840. * ishtp_send_suspend() - Send suspend message to FW
  841. * @dev: ISHTP device instance
  842. *
  843. * Send suspend message to FW. This is useful for system freeze (non S3) case
  844. */
  845. void ishtp_send_suspend(struct ishtp_device *dev)
  846. {
  847. struct ishtp_msg_hdr ishtp_hdr;
  848. struct ish_system_states_status state_status_msg;
  849. const size_t len = sizeof(struct ish_system_states_status);
  850. fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
  851. memset(&state_status_msg, 0, len);
  852. state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
  853. state_status_msg.supported_states = supported_states;
  854. current_state |= SUSPEND_STATE_BIT;
  855. dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__);
  856. state_status_msg.states_status = current_state;
  857. ishtp_write_message(dev, &ishtp_hdr,
  858. (unsigned char *)&state_status_msg);
  859. }
  860. EXPORT_SYMBOL(ishtp_send_suspend);
  861. /**
  862. * ishtp_send_resume() - Send resume message to FW
  863. * @dev: ISHTP device instance
  864. *
  865. * Send resume message to FW. This is useful for system freeze (non S3) case
  866. */
  867. void ishtp_send_resume(struct ishtp_device *dev)
  868. {
  869. struct ishtp_msg_hdr ishtp_hdr;
  870. struct ish_system_states_status state_status_msg;
  871. const size_t len = sizeof(struct ish_system_states_status);
  872. fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
  873. memset(&state_status_msg, 0, len);
  874. state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
  875. state_status_msg.supported_states = supported_states;
  876. current_state &= ~SUSPEND_STATE_BIT;
  877. dev->print_log(dev, "%s() sends RESUME notification\n", __func__);
  878. state_status_msg.states_status = current_state;
  879. ishtp_write_message(dev, &ishtp_hdr,
  880. (unsigned char *)&state_status_msg);
  881. }
  882. EXPORT_SYMBOL(ishtp_send_resume);
  883. /**
  884. * ishtp_query_subscribers() - Send query subscribers message
  885. * @dev: ISHTP device instance
  886. *
  887. * Send message to query subscribers
  888. */
  889. void ishtp_query_subscribers(struct ishtp_device *dev)
  890. {
  891. struct ishtp_msg_hdr ishtp_hdr;
  892. struct ish_system_states_query_subscribers query_subscribers_msg;
  893. const size_t len = sizeof(struct ish_system_states_query_subscribers);
  894. fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR);
  895. memset(&query_subscribers_msg, 0, len);
  896. query_subscribers_msg.hdr.cmd = SYSTEM_STATE_QUERY_SUBSCRIBERS;
  897. ishtp_write_message(dev, &ishtp_hdr,
  898. (unsigned char *)&query_subscribers_msg);
  899. }