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