mcu.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // SPDX-License-Identifier: BSD-3-Clause-Clear
  2. /*
  3. * Copyright (C) 2019 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
  4. */
  5. #include "mt76.h"
  6. struct sk_buff *
  7. __mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
  8. int len, int data_len, gfp_t gfp)
  9. {
  10. const struct mt76_mcu_ops *ops = dev->mcu_ops;
  11. struct sk_buff *skb;
  12. len = max_t(int, len, data_len);
  13. len = ops->headroom + len + ops->tailroom;
  14. skb = alloc_skb(len, gfp);
  15. if (!skb)
  16. return NULL;
  17. memset(skb->head, 0, len);
  18. skb_reserve(skb, ops->headroom);
  19. if (data && data_len)
  20. skb_put_data(skb, data, data_len);
  21. return skb;
  22. }
  23. EXPORT_SYMBOL_GPL(__mt76_mcu_msg_alloc);
  24. struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev,
  25. unsigned long expires)
  26. {
  27. unsigned long timeout;
  28. if (!time_is_after_jiffies(expires))
  29. return NULL;
  30. timeout = expires - jiffies;
  31. wait_event_timeout(dev->mcu.wait,
  32. (!skb_queue_empty(&dev->mcu.res_q) ||
  33. test_bit(MT76_MCU_RESET, &dev->phy.state)),
  34. timeout);
  35. return skb_dequeue(&dev->mcu.res_q);
  36. }
  37. EXPORT_SYMBOL_GPL(mt76_mcu_get_response);
  38. void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb)
  39. {
  40. skb_queue_tail(&dev->mcu.res_q, skb);
  41. wake_up(&dev->mcu.wait);
  42. }
  43. EXPORT_SYMBOL_GPL(mt76_mcu_rx_event);
  44. int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data,
  45. int len, bool wait_resp, struct sk_buff **ret_skb)
  46. {
  47. struct sk_buff *skb;
  48. if (dev->mcu_ops->mcu_send_msg)
  49. return dev->mcu_ops->mcu_send_msg(dev, cmd, data, len, wait_resp);
  50. skb = mt76_mcu_msg_alloc(dev, data, len);
  51. if (!skb)
  52. return -ENOMEM;
  53. return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, ret_skb);
  54. }
  55. EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg);
  56. int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
  57. int cmd, bool wait_resp,
  58. struct sk_buff **ret_skb)
  59. {
  60. unsigned int retry = 0;
  61. struct sk_buff *orig_skb = NULL;
  62. unsigned long expires;
  63. int ret, seq;
  64. if (mt76_is_sdio(dev))
  65. if (test_bit(MT76_RESET, &dev->phy.state) && atomic_read(&dev->bus_hung))
  66. return -EIO;
  67. if (ret_skb)
  68. *ret_skb = NULL;
  69. mutex_lock(&dev->mcu.mutex);
  70. if (dev->mcu_ops->mcu_skb_prepare_msg) {
  71. orig_skb = skb;
  72. ret = dev->mcu_ops->mcu_skb_prepare_msg(dev, skb, cmd, &seq);
  73. if (ret < 0)
  74. goto out;
  75. }
  76. retry:
  77. /* orig skb might be needed for retry, mcu_skb_send_msg consumes it */
  78. if (orig_skb)
  79. skb_get(orig_skb);
  80. ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);
  81. if (ret < 0)
  82. goto out;
  83. if (!wait_resp) {
  84. ret = 0;
  85. goto out;
  86. }
  87. expires = jiffies + dev->mcu.timeout;
  88. do {
  89. skb = mt76_mcu_get_response(dev, expires);
  90. if (!skb && !test_bit(MT76_MCU_RESET, &dev->phy.state) &&
  91. orig_skb && retry++ < dev->mcu_ops->max_retry) {
  92. dev_err(dev->dev, "Retry message %08x (seq %d)\n",
  93. cmd, seq);
  94. skb = orig_skb;
  95. goto retry;
  96. }
  97. ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq);
  98. if (!ret && ret_skb)
  99. *ret_skb = skb;
  100. else
  101. dev_kfree_skb(skb);
  102. } while (ret == -EAGAIN);
  103. out:
  104. dev_kfree_skb(orig_skb);
  105. mutex_unlock(&dev->mcu.mutex);
  106. return ret;
  107. }
  108. EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);
  109. int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
  110. int len, int max_len)
  111. {
  112. int err, cur_len;
  113. while (len > 0) {
  114. cur_len = min_t(int, max_len, len);
  115. err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);
  116. if (err)
  117. return err;
  118. data += cur_len;
  119. len -= cur_len;
  120. if (dev->queue_ops->tx_cleanup)
  121. dev->queue_ops->tx_cleanup(dev,
  122. dev->q_mcu[MT_MCUQ_FWDL],
  123. false);
  124. }
  125. return 0;
  126. }
  127. EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware);