Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/mediatek/mt76/mcu.c
48378 views
1
// SPDX-License-Identifier: ISC
2
/*
3
* Copyright (C) 2019 Lorenzo Bianconi <[email protected]>
4
*/
5
6
#include "mt76.h"
7
8
struct 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
}
30
EXPORT_SYMBOL_GPL(__mt76_mcu_msg_alloc);
31
32
struct 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
}
47
EXPORT_SYMBOL_GPL(mt76_mcu_get_response);
48
49
void 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
}
54
EXPORT_SYMBOL_GPL(mt76_mcu_rx_event);
55
56
int 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
}
70
EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg);
71
72
int 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 (mt76_is_sdio(dev))
82
if (test_bit(MT76_RESET, &dev->phy.state) && atomic_read(&dev->bus_hung))
83
return -EIO;
84
85
if (ret_skb)
86
*ret_skb = NULL;
87
88
mutex_lock(&dev->mcu.mutex);
89
90
if (dev->mcu_ops->mcu_skb_prepare_msg) {
91
orig_skb = skb;
92
ret = dev->mcu_ops->mcu_skb_prepare_msg(dev, skb, cmd, &seq);
93
if (ret < 0)
94
goto out;
95
}
96
97
retry:
98
/* orig skb might be needed for retry, mcu_skb_send_msg consumes it */
99
if (orig_skb)
100
skb_get(orig_skb);
101
ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);
102
if (ret < 0)
103
goto out;
104
105
if (!wait_resp) {
106
ret = 0;
107
goto out;
108
}
109
110
expires = jiffies + dev->mcu.timeout;
111
112
do {
113
skb = mt76_mcu_get_response(dev, expires);
114
if (!skb && !test_bit(MT76_MCU_RESET, &dev->phy.state) &&
115
orig_skb && retry++ < dev->mcu_ops->max_retry) {
116
dev_err(dev->dev, "Retry message %08x (seq %d)\n",
117
cmd, seq);
118
skb = orig_skb;
119
goto retry;
120
}
121
122
ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq);
123
if (!ret && ret_skb)
124
*ret_skb = skb;
125
else
126
dev_kfree_skb(skb);
127
} while (ret == -EAGAIN);
128
129
130
out:
131
dev_kfree_skb(orig_skb);
132
mutex_unlock(&dev->mcu.mutex);
133
134
return ret;
135
}
136
EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);
137
138
#if defined(__linux__)
139
int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
140
#elif defined(__FreeBSD__)
141
int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const u8 *data,
142
#endif
143
int len, int max_len)
144
{
145
int err, cur_len;
146
147
while (len > 0) {
148
cur_len = min_t(int, max_len, len);
149
150
err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);
151
if (err)
152
return err;
153
154
data += cur_len;
155
len -= cur_len;
156
157
if (dev->queue_ops->tx_cleanup)
158
dev->queue_ops->tx_cleanup(dev,
159
dev->q_mcu[MT_MCUQ_FWDL],
160
false);
161
}
162
163
return 0;
164
}
165
EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware);
166
167