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