mcu.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // SPDX-License-Identifier: ISC
  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 data_len)
  9. {
  10. const struct mt76_mcu_ops *ops = dev->mcu_ops;
  11. int length = ops->headroom + data_len + ops->tailroom;
  12. struct sk_buff *skb;
  13. skb = alloc_skb(length, GFP_KERNEL);
  14. if (!skb)
  15. return NULL;
  16. memset(skb->head, 0, length);
  17. skb_reserve(skb, ops->headroom);
  18. if (data && data_len)
  19. skb_put_data(skb, data, data_len);
  20. return skb;
  21. }
  22. EXPORT_SYMBOL_GPL(mt76_mcu_msg_alloc);
  23. struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev,
  24. unsigned long expires)
  25. {
  26. unsigned long timeout;
  27. if (!time_is_after_jiffies(expires))
  28. return NULL;
  29. timeout = expires - jiffies;
  30. wait_event_timeout(dev->mcu.wait,
  31. (!skb_queue_empty(&dev->mcu.res_q) ||
  32. test_bit(MT76_MCU_RESET, &dev->phy.state)),
  33. timeout);
  34. return skb_dequeue(&dev->mcu.res_q);
  35. }
  36. EXPORT_SYMBOL_GPL(mt76_mcu_get_response);
  37. void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb)
  38. {
  39. skb_queue_tail(&dev->mcu.res_q, skb);
  40. wake_up(&dev->mcu.wait);
  41. }
  42. EXPORT_SYMBOL_GPL(mt76_mcu_rx_event);
  43. int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data,
  44. int len, bool wait_resp, struct sk_buff **ret_skb)
  45. {
  46. struct sk_buff *skb;
  47. if (dev->mcu_ops->mcu_send_msg)
  48. return dev->mcu_ops->mcu_send_msg(dev, cmd, data, len, wait_resp);
  49. skb = mt76_mcu_msg_alloc(dev, data, len);
  50. if (!skb)
  51. return -ENOMEM;
  52. return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, ret_skb);
  53. }
  54. EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg);
  55. int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
  56. int cmd, bool wait_resp,
  57. struct sk_buff **ret_skb)
  58. {
  59. unsigned long expires;
  60. int ret, seq;
  61. if (ret_skb)
  62. *ret_skb = NULL;
  63. mutex_lock(&dev->mcu.mutex);
  64. ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);
  65. if (ret < 0)
  66. goto out;
  67. if (!wait_resp) {
  68. ret = 0;
  69. goto out;
  70. }
  71. expires = jiffies + dev->mcu.timeout;
  72. do {
  73. skb = mt76_mcu_get_response(dev, expires);
  74. ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq);
  75. if (!ret && ret_skb)
  76. *ret_skb = skb;
  77. else
  78. dev_kfree_skb(skb);
  79. } while (ret == -EAGAIN);
  80. out:
  81. mutex_unlock(&dev->mcu.mutex);
  82. return ret;
  83. }
  84. EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);
  85. int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
  86. int len)
  87. {
  88. int err, cur_len;
  89. while (len > 0) {
  90. cur_len = min_t(int, 4096 - dev->mcu_ops->headroom, len);
  91. err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);
  92. if (err)
  93. return err;
  94. data += cur_len;
  95. len -= cur_len;
  96. if (dev->queue_ops->tx_cleanup)
  97. dev->queue_ops->tx_cleanup(dev,
  98. dev->q_mcu[MT_MCUQ_FWDL],
  99. false);
  100. }
  101. return 0;
  102. }
  103. EXPORT_SYMBOL_GPL(mt76_mcu_send_firmware);