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