brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · 3353012 Raw
158 lines · c
1// SPDX-License-Identifier: ISC2/*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 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}30EXPORT_SYMBOL_GPL(__mt76_mcu_msg_alloc);31 32struct 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}47EXPORT_SYMBOL_GPL(mt76_mcu_get_response);48 49void 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}54EXPORT_SYMBOL_GPL(mt76_mcu_rx_event);55 56int 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}70EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg);71 72int 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 int retry = 0;77	struct sk_buff *orig_skb = NULL;78	unsigned long expires;79	int ret, seq;80 81	if (ret_skb)82		*ret_skb = NULL;83 84	mutex_lock(&dev->mcu.mutex);85 86	if (dev->mcu_ops->mcu_skb_prepare_msg) {87		orig_skb = skb;88		ret = dev->mcu_ops->mcu_skb_prepare_msg(dev, skb, cmd, &seq);89		if (ret < 0)90			goto out;91	}92 93retry:94	/* orig skb might be needed for retry, mcu_skb_send_msg consumes it */95	if (orig_skb)96		skb_get(orig_skb);97	ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);98	if (ret < 0)99		goto out;100 101	if (!wait_resp) {102		ret = 0;103		goto out;104	}105 106	expires = jiffies + dev->mcu.timeout;107 108	do {109		skb = mt76_mcu_get_response(dev, expires);110		if (!skb && !test_bit(MT76_MCU_RESET, &dev->phy.state) &&111		    orig_skb && retry++ < dev->mcu_ops->max_retry) {112			dev_err(dev->dev, "Retry message %08x (seq %d)\n",113				cmd, seq);114			skb = orig_skb;115			goto retry;116		}117 118		ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq);119		if (!ret && ret_skb)120			*ret_skb = skb;121		else122			dev_kfree_skb(skb);123	} while (ret == -EAGAIN);124 125 126out:127	dev_kfree_skb(orig_skb);128	mutex_unlock(&dev->mcu.mutex);129 130	return ret;131}132EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);133 134int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,135			     int len, int max_len)136{137	int err, cur_len;138 139	while (len > 0) {140		cur_len = min_t(int, max_len, len);141 142		err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);143		if (err)144			return err;145 146		data += cur_len;147		len -= cur_len;148 149		if (dev->queue_ops->tx_cleanup)150			dev->queue_ops->tx_cleanup(dev,151						   dev->q_mcu[MT_MCUQ_FWDL],152						   false);153	}154 155	return 0;156}157EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware);158