1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (C) 2019 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 4 */ 5 6 #include "mt76.h" 7 8 struct sk_buff * 9 __mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, 10 int len, int data_len, gfp_t gfp) 11 { 12 const struct mt76_mcu_ops *ops = dev->mcu_ops; 13 struct sk_buff *skb; 14 15 len = max_t(int, len, data_len); 16 len = ops->headroom + len + ops->tailroom; 17 18 skb = alloc_skb(len, gfp); 19 if (!skb) 20 return NULL; 21 22 memset(skb->head, 0, len); 23 skb_reserve(skb, ops->headroom); 24 25 if (data && data_len) 26 skb_put_data(skb, data, data_len); 27 28 return skb; 29 } 30 EXPORT_SYMBOL_GPL(__mt76_mcu_msg_alloc); 31 32 struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev, 33 unsigned long expires) 34 { 35 unsigned long timeout; 36 37 if (!time_is_after_jiffies(expires)) 38 return NULL; 39 40 timeout = expires - jiffies; 41 wait_event_timeout(dev->mcu.wait, 42 (!skb_queue_empty(&dev->mcu.res_q) || 43 test_bit(MT76_MCU_RESET, &dev->phy.state)), 44 timeout); 45 return skb_dequeue(&dev->mcu.res_q); 46 } 47 EXPORT_SYMBOL_GPL(mt76_mcu_get_response); 48 49 void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb) 50 { 51 skb_queue_tail(&dev->mcu.res_q, skb); 52 wake_up(&dev->mcu.wait); 53 } 54 EXPORT_SYMBOL_GPL(mt76_mcu_rx_event); 55 56 int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data, 57 int len, bool wait_resp, struct sk_buff **ret_skb) 58 { 59 struct sk_buff *skb; 60 61 if (dev->mcu_ops->mcu_send_msg) 62 return dev->mcu_ops->mcu_send_msg(dev, cmd, data, len, wait_resp); 63 64 skb = mt76_mcu_msg_alloc(dev, data, len); 65 if (!skb) 66 return -ENOMEM; 67 68 return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, ret_skb); 69 } 70 EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg); 71 72 int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb, 73 int cmd, bool wait_resp, 74 struct sk_buff **ret_skb) 75 { 76 unsigned long expires; 77 int ret, seq; 78 79 if (ret_skb) 80 *ret_skb = NULL; 81 82 mutex_lock(&dev->mcu.mutex); 83 84 ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq); 85 if (ret < 0) 86 goto out; 87 88 if (!wait_resp) { 89 ret = 0; 90 goto out; 91 } 92 93 expires = jiffies + dev->mcu.timeout; 94 95 do { 96 skb = mt76_mcu_get_response(dev, expires); 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 104 out: 105 mutex_unlock(&dev->mcu.mutex); 106 107 return ret; 108 } 109 EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg); 110 111 #if defined(__linux__) 112 int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, 113 #elif defined(__FreeBSD__) 114 int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const u8 *data, 115 #endif 116 int len, int max_len) 117 { 118 int err, cur_len; 119 120 while (len > 0) { 121 cur_len = min_t(int, max_len, len); 122 123 err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false); 124 if (err) 125 return err; 126 127 data += cur_len; 128 len -= cur_len; 129 130 if (dev->queue_ops->tx_cleanup) 131 dev->queue_ops->tx_cleanup(dev, 132 dev->q_mcu[MT_MCUQ_FWDL], 133 false); 134 } 135 136 return 0; 137 } 138 EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware); 139