Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (C) 2019 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
0004  */
0005 
0006 #include "mt76.h"
0007 
0008 struct sk_buff *
0009 __mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
0010              int len, int data_len, gfp_t gfp)
0011 {
0012     const struct mt76_mcu_ops *ops = dev->mcu_ops;
0013     struct sk_buff *skb;
0014 
0015     len = max_t(int, len, data_len);
0016     len = ops->headroom + len + ops->tailroom;
0017 
0018     skb = alloc_skb(len, gfp);
0019     if (!skb)
0020         return NULL;
0021 
0022     memset(skb->head, 0, len);
0023     skb_reserve(skb, ops->headroom);
0024 
0025     if (data && data_len)
0026         skb_put_data(skb, data, data_len);
0027 
0028     return skb;
0029 }
0030 EXPORT_SYMBOL_GPL(__mt76_mcu_msg_alloc);
0031 
0032 struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev,
0033                       unsigned long expires)
0034 {
0035     unsigned long timeout;
0036 
0037     if (!time_is_after_jiffies(expires))
0038         return NULL;
0039 
0040     timeout = expires - jiffies;
0041     wait_event_timeout(dev->mcu.wait,
0042                (!skb_queue_empty(&dev->mcu.res_q) ||
0043                 test_bit(MT76_MCU_RESET, &dev->phy.state)),
0044                timeout);
0045     return skb_dequeue(&dev->mcu.res_q);
0046 }
0047 EXPORT_SYMBOL_GPL(mt76_mcu_get_response);
0048 
0049 void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb)
0050 {
0051     skb_queue_tail(&dev->mcu.res_q, skb);
0052     wake_up(&dev->mcu.wait);
0053 }
0054 EXPORT_SYMBOL_GPL(mt76_mcu_rx_event);
0055 
0056 int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data,
0057                   int len, bool wait_resp, struct sk_buff **ret_skb)
0058 {
0059     struct sk_buff *skb;
0060 
0061     if (dev->mcu_ops->mcu_send_msg)
0062         return dev->mcu_ops->mcu_send_msg(dev, cmd, data, len, wait_resp);
0063 
0064     skb = mt76_mcu_msg_alloc(dev, data, len);
0065     if (!skb)
0066         return -ENOMEM;
0067 
0068     return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, ret_skb);
0069 }
0070 EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg);
0071 
0072 int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
0073                   int cmd, bool wait_resp,
0074                   struct sk_buff **ret_skb)
0075 {
0076     unsigned long expires;
0077     int ret, seq;
0078 
0079     if (ret_skb)
0080         *ret_skb = NULL;
0081 
0082     mutex_lock(&dev->mcu.mutex);
0083 
0084     ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);
0085     if (ret < 0)
0086         goto out;
0087 
0088     if (!wait_resp) {
0089         ret = 0;
0090         goto out;
0091     }
0092 
0093     expires = jiffies + dev->mcu.timeout;
0094 
0095     do {
0096         skb = mt76_mcu_get_response(dev, expires);
0097         ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq);
0098         if (!ret && ret_skb)
0099             *ret_skb = skb;
0100         else
0101             dev_kfree_skb(skb);
0102     } while (ret == -EAGAIN);
0103 
0104 out:
0105     mutex_unlock(&dev->mcu.mutex);
0106 
0107     return ret;
0108 }
0109 EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);
0110 
0111 int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
0112                  int len, int max_len)
0113 {
0114     int err, cur_len;
0115 
0116     while (len > 0) {
0117         cur_len = min_t(int, max_len, len);
0118 
0119         err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);
0120         if (err)
0121             return err;
0122 
0123         data += cur_len;
0124         len -= cur_len;
0125 
0126         if (dev->queue_ops->tx_cleanup)
0127             dev->queue_ops->tx_cleanup(dev,
0128                            dev->q_mcu[MT_MCUQ_FWDL],
0129                            false);
0130     }
0131 
0132     return 0;
0133 }
0134 EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware);