shm_ipc.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */
  3. #include <linux/types.h>
  4. #include <linux/io.h>
  5. #include "shm_ipc.h"
  6. #undef pr_fmt
  7. #define pr_fmt(fmt) "qtnfmac shm_ipc: %s: " fmt, __func__
  8. static bool qtnf_shm_ipc_has_new_data(struct qtnf_shm_ipc *ipc)
  9. {
  10. const u32 flags = readl(&ipc->shm_region->headroom.hdr.flags);
  11. return (flags & QTNF_SHM_IPC_NEW_DATA);
  12. }
  13. static void qtnf_shm_handle_new_data(struct qtnf_shm_ipc *ipc)
  14. {
  15. size_t size;
  16. bool rx_buff_ok = true;
  17. struct qtnf_shm_ipc_region_header __iomem *shm_reg_hdr;
  18. shm_reg_hdr = &ipc->shm_region->headroom.hdr;
  19. size = readw(&shm_reg_hdr->data_len);
  20. if (unlikely(size == 0 || size > QTN_IPC_MAX_DATA_SZ)) {
  21. pr_err("wrong rx packet size: %zu\n", size);
  22. rx_buff_ok = false;
  23. }
  24. if (likely(rx_buff_ok)) {
  25. ipc->rx_packet_count++;
  26. ipc->rx_callback.fn(ipc->rx_callback.arg,
  27. ipc->shm_region->data, size);
  28. }
  29. writel(QTNF_SHM_IPC_ACK, &shm_reg_hdr->flags);
  30. readl(&shm_reg_hdr->flags); /* flush PCIe write */
  31. ipc->interrupt.fn(ipc->interrupt.arg);
  32. }
  33. static void qtnf_shm_ipc_irq_work(struct work_struct *work)
  34. {
  35. struct qtnf_shm_ipc *ipc = container_of(work, struct qtnf_shm_ipc,
  36. irq_work);
  37. while (qtnf_shm_ipc_has_new_data(ipc))
  38. qtnf_shm_handle_new_data(ipc);
  39. }
  40. static void qtnf_shm_ipc_irq_inbound_handler(struct qtnf_shm_ipc *ipc)
  41. {
  42. u32 flags;
  43. flags = readl(&ipc->shm_region->headroom.hdr.flags);
  44. if (flags & QTNF_SHM_IPC_NEW_DATA)
  45. queue_work(ipc->workqueue, &ipc->irq_work);
  46. }
  47. static void qtnf_shm_ipc_irq_outbound_handler(struct qtnf_shm_ipc *ipc)
  48. {
  49. u32 flags;
  50. if (!READ_ONCE(ipc->waiting_for_ack))
  51. return;
  52. flags = readl(&ipc->shm_region->headroom.hdr.flags);
  53. if (flags & QTNF_SHM_IPC_ACK) {
  54. WRITE_ONCE(ipc->waiting_for_ack, 0);
  55. complete(&ipc->tx_completion);
  56. }
  57. }
  58. int qtnf_shm_ipc_init(struct qtnf_shm_ipc *ipc,
  59. enum qtnf_shm_ipc_direction direction,
  60. struct qtnf_shm_ipc_region __iomem *shm_region,
  61. struct workqueue_struct *workqueue,
  62. const struct qtnf_shm_ipc_int *interrupt,
  63. const struct qtnf_shm_ipc_rx_callback *rx_callback)
  64. {
  65. BUILD_BUG_ON(offsetof(struct qtnf_shm_ipc_region, data) !=
  66. QTN_IPC_REG_HDR_SZ);
  67. BUILD_BUG_ON(sizeof(struct qtnf_shm_ipc_region) > QTN_IPC_REG_SZ);
  68. ipc->shm_region = shm_region;
  69. ipc->direction = direction;
  70. ipc->interrupt = *interrupt;
  71. ipc->rx_callback = *rx_callback;
  72. ipc->tx_packet_count = 0;
  73. ipc->rx_packet_count = 0;
  74. ipc->workqueue = workqueue;
  75. ipc->waiting_for_ack = 0;
  76. ipc->tx_timeout_count = 0;
  77. switch (direction) {
  78. case QTNF_SHM_IPC_OUTBOUND:
  79. ipc->irq_handler = qtnf_shm_ipc_irq_outbound_handler;
  80. break;
  81. case QTNF_SHM_IPC_INBOUND:
  82. ipc->irq_handler = qtnf_shm_ipc_irq_inbound_handler;
  83. break;
  84. default:
  85. return -EINVAL;
  86. }
  87. INIT_WORK(&ipc->irq_work, qtnf_shm_ipc_irq_work);
  88. init_completion(&ipc->tx_completion);
  89. return 0;
  90. }
  91. void qtnf_shm_ipc_free(struct qtnf_shm_ipc *ipc)
  92. {
  93. complete_all(&ipc->tx_completion);
  94. }
  95. int qtnf_shm_ipc_send(struct qtnf_shm_ipc *ipc, const u8 *buf, size_t size)
  96. {
  97. int ret = 0;
  98. struct qtnf_shm_ipc_region_header __iomem *shm_reg_hdr;
  99. shm_reg_hdr = &ipc->shm_region->headroom.hdr;
  100. if (unlikely(size > QTN_IPC_MAX_DATA_SZ))
  101. return -E2BIG;
  102. ipc->tx_packet_count++;
  103. writew(size, &shm_reg_hdr->data_len);
  104. memcpy_toio(ipc->shm_region->data, buf, size);
  105. /* sync previous writes before proceeding */
  106. dma_wmb();
  107. WRITE_ONCE(ipc->waiting_for_ack, 1);
  108. /* sync previous memory write before announcing new data ready */
  109. wmb();
  110. writel(QTNF_SHM_IPC_NEW_DATA, &shm_reg_hdr->flags);
  111. readl(&shm_reg_hdr->flags); /* flush PCIe write */
  112. ipc->interrupt.fn(ipc->interrupt.arg);
  113. if (!wait_for_completion_timeout(&ipc->tx_completion,
  114. QTN_SHM_IPC_ACK_TIMEOUT)) {
  115. ret = -ETIMEDOUT;
  116. ipc->tx_timeout_count++;
  117. pr_err("TX ACK timeout\n");
  118. }
  119. /* now we're not waiting for ACK even in case of timeout */
  120. WRITE_ONCE(ipc->waiting_for_ack, 0);
  121. return ret;
  122. }