GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / net / wireless / mediatek / mt76 / usb_mcu.c
1 /*
2  * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/firmware.h>
18
19 #include "mt76.h"
20 #include "dma.h"
21
22 #define MT_CMD_HDR_LEN                  4
23
24 #define MT_FCE_DMA_ADDR                 0x0230
25 #define MT_FCE_DMA_LEN                  0x0234
26
27 #define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
28
29 struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len)
30 {
31         struct sk_buff *skb;
32
33         skb = alloc_skb(MT_CMD_HDR_LEN + len + 8, GFP_KERNEL);
34         if (!skb)
35                 return NULL;
36
37         skb_reserve(skb, MT_CMD_HDR_LEN);
38         skb_put_data(skb, data, len);
39
40         return skb;
41 }
42 EXPORT_SYMBOL_GPL(mt76u_mcu_msg_alloc);
43
44 void mt76u_mcu_complete_urb(struct urb *urb)
45 {
46         struct completion *cmpl = urb->context;
47
48         complete(cmpl);
49 }
50 EXPORT_SYMBOL_GPL(mt76u_mcu_complete_urb);
51
52 static int mt76u_mcu_wait_resp(struct mt76_dev *dev, u8 seq)
53 {
54         struct mt76_usb *usb = &dev->usb;
55         struct mt76u_buf *buf = &usb->mcu.res;
56         int i, ret;
57         u32 rxfce;
58
59         for (i = 0; i < 5; i++) {
60                 if (!wait_for_completion_timeout(&usb->mcu.cmpl,
61                                                  msecs_to_jiffies(300)))
62                         continue;
63
64                 if (buf->urb->status)
65                         return -EIO;
66
67                 rxfce = get_unaligned_le32(sg_virt(&buf->urb->sg[0]));
68                 ret = mt76u_submit_buf(dev, USB_DIR_IN,
69                                        MT_EP_IN_CMD_RESP,
70                                        buf, GFP_KERNEL,
71                                        mt76u_mcu_complete_urb,
72                                        &usb->mcu.cmpl);
73                 if (ret)
74                         return ret;
75
76                 if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce))
77                         return 0;
78
79                 dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n",
80                         FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce),
81                         seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce));
82         }
83
84         dev_err(dev->dev, "error: %s timed out\n", __func__);
85         return -ETIMEDOUT;
86 }
87
88 int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
89                        int cmd, bool wait_resp)
90 {
91         struct usb_interface *intf = to_usb_interface(dev->dev);
92         struct usb_device *udev = interface_to_usbdev(intf);
93         struct mt76_usb *usb = &dev->usb;
94         unsigned int pipe;
95         int ret, sent;
96         u8 seq = 0;
97         u32 info;
98
99         if (test_bit(MT76_REMOVED, &dev->state))
100                 return 0;
101
102         mutex_lock(&usb->mcu.mutex);
103
104         pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]);
105         if (wait_resp) {
106                 seq = ++usb->mcu.msg_seq & 0xf;
107                 if (!seq)
108                         seq = ++usb->mcu.msg_seq & 0xf;
109         }
110
111         info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
112                FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
113                MT_MCU_MSG_TYPE_CMD;
114         ret = mt76u_skb_dma_info(skb, CPU_TX_PORT, info);
115         if (ret)
116                 goto out;
117
118         ret = usb_bulk_msg(udev, pipe, skb->data, skb->len, &sent, 500);
119         if (ret)
120                 goto out;
121
122         if (wait_resp)
123                 ret = mt76u_mcu_wait_resp(dev, seq);
124
125 out:
126         mutex_unlock(&usb->mcu.mutex);
127
128         consume_skb(skb);
129
130         return ret;
131 }
132 EXPORT_SYMBOL_GPL(mt76u_mcu_send_msg);
133
134 void mt76u_mcu_fw_reset(struct mt76_dev *dev)
135 {
136         mt76u_vendor_request(dev, MT_VEND_DEV_MODE,
137                              USB_DIR_OUT | USB_TYPE_VENDOR,
138                              0x1, 0, NULL, 0);
139 }
140 EXPORT_SYMBOL_GPL(mt76u_mcu_fw_reset);
141
142 static int
143 __mt76u_mcu_fw_send_data(struct mt76_dev *dev, struct mt76u_buf *buf,
144                          const void *fw_data, int len, u32 dst_addr)
145 {
146         u8 *data = sg_virt(&buf->urb->sg[0]);
147         DECLARE_COMPLETION_ONSTACK(cmpl);
148         __le32 info;
149         u32 val;
150         int err;
151
152         info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
153                            FIELD_PREP(MT_MCU_MSG_LEN, len) |
154                            MT_MCU_MSG_TYPE_CMD);
155
156         memcpy(data, &info, sizeof(info));
157         memcpy(data + sizeof(info), fw_data, len);
158         memset(data + sizeof(info) + len, 0, 4);
159
160         mt76u_single_wr(dev, MT_VEND_WRITE_FCE,
161                         MT_FCE_DMA_ADDR, dst_addr);
162         len = roundup(len, 4);
163         mt76u_single_wr(dev, MT_VEND_WRITE_FCE,
164                         MT_FCE_DMA_LEN, len << 16);
165
166         buf->len = MT_CMD_HDR_LEN + len + sizeof(info);
167         err = mt76u_submit_buf(dev, USB_DIR_OUT,
168                                MT_EP_OUT_INBAND_CMD,
169                                buf, GFP_KERNEL,
170                                mt76u_mcu_complete_urb, &cmpl);
171         if (err < 0)
172                 return err;
173
174         if (!wait_for_completion_timeout(&cmpl,
175                                          msecs_to_jiffies(1000))) {
176                 dev_err(dev->dev, "firmware upload timed out\n");
177                 usb_kill_urb(buf->urb);
178                 return -ETIMEDOUT;
179         }
180
181         if (mt76u_urb_error(buf->urb)) {
182                 dev_err(dev->dev, "firmware upload failed: %d\n",
183                         buf->urb->status);
184                 return buf->urb->status;
185         }
186
187         val = mt76u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX);
188         val++;
189         mt76u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val);
190
191         return 0;
192 }
193
194 int mt76u_mcu_fw_send_data(struct mt76_dev *dev, const void *data,
195                            int data_len, u32 max_payload, u32 offset)
196 {
197         int err, len, pos = 0, max_len = max_payload - 8;
198         struct mt76u_buf buf;
199
200         err = mt76u_buf_alloc(dev, &buf, 1, max_payload, max_payload,
201                               GFP_KERNEL);
202         if (err < 0)
203                 return err;
204
205         while (data_len > 0) {
206                 len = min_t(int, data_len, max_len);
207                 err = __mt76u_mcu_fw_send_data(dev, &buf, data + pos,
208                                                len, offset + pos);
209                 if (err < 0)
210                         break;
211
212                 data_len -= len;
213                 pos += len;
214                 usleep_range(5000, 10000);
215         }
216         mt76u_buf_free(&buf);
217
218         return err;
219 }
220 EXPORT_SYMBOL_GPL(mt76u_mcu_fw_send_data);
221
222 int mt76u_mcu_init_rx(struct mt76_dev *dev)
223 {
224         struct mt76_usb *usb = &dev->usb;
225         int err;
226
227         err = mt76u_buf_alloc(dev, &usb->mcu.res, 1,
228                               MCU_RESP_URB_SIZE, MCU_RESP_URB_SIZE,
229                               GFP_KERNEL);
230         if (err < 0)
231                 return err;
232
233         err = mt76u_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP,
234                                &usb->mcu.res, GFP_KERNEL,
235                                mt76u_mcu_complete_urb,
236                                &usb->mcu.cmpl);
237         if (err < 0)
238                 mt76u_buf_free(&usb->mcu.res);
239
240         return err;
241 }
242 EXPORT_SYMBOL_GPL(mt76u_mcu_init_rx);