mcu.c (2912B)
1// SPDX-License-Identifier: ISC 2/* 3 * Copyright (C) 2019 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 4 */ 5 6#include "mt76.h" 7 8struct sk_buff * 9__mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, 10 int data_len, gfp_t gfp) 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); 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} 28EXPORT_SYMBOL_GPL(__mt76_mcu_msg_alloc); 29 30struct 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} 45EXPORT_SYMBOL_GPL(mt76_mcu_get_response); 46 47void 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} 52EXPORT_SYMBOL_GPL(mt76_mcu_rx_event); 53 54int 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} 68EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg); 69 70int 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 102out: 103 mutex_unlock(&dev->mcu.mutex); 104 105 return ret; 106} 107EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg); 108 109int __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 114 while (len > 0) { 115 cur_len = min_t(int, max_len, 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} 132EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware);