]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/rtwn/rtl8192c/r92c_fw.c
Merge ^/vendor/lldb/dist up to its last change, and resolve conflicts.
[FreeBSD/FreeBSD.git] / sys / dev / rtwn / rtl8192c / r92c_fw.c
1 /*      $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $   */
2
3 /*-
4  * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5  * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6  * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
23
24 #include "opt_wlan.h"
25
26 #include <sys/param.h>
27 #include <sys/lock.h>
28 #include <sys/mutex.h>
29 #include <sys/mbuf.h>
30 #include <sys/kernel.h>
31 #include <sys/socket.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/queue.h>
35 #include <sys/taskqueue.h>
36 #include <sys/bus.h>
37 #include <sys/endian.h>
38 #include <sys/linker.h>
39
40 #include <net/if.h>
41 #include <net/ethernet.h>
42 #include <net/if_media.h>
43
44 #include <net80211/ieee80211_var.h>
45 #include <net80211/ieee80211_radiotap.h>
46 #include <net80211/ieee80211_ratectl.h>
47
48 #include <dev/rtwn/if_rtwnreg.h>
49 #include <dev/rtwn/if_rtwnvar.h>
50
51 #include <dev/rtwn/if_rtwn_debug.h>
52 #include <dev/rtwn/if_rtwn_ridx.h>
53 #include <dev/rtwn/if_rtwn_rx.h>
54 #include <dev/rtwn/if_rtwn_task.h>
55 #include <dev/rtwn/if_rtwn_tx.h>
56
57 #include <dev/rtwn/rtl8192c/r92c.h>
58 #include <dev/rtwn/rtl8192c/r92c_reg.h>
59 #include <dev/rtwn/rtl8192c/r92c_var.h>
60 #include <dev/rtwn/rtl8192c/r92c_fw_cmd.h>
61 #include <dev/rtwn/rtl8192c/r92c_tx_desc.h>
62
63
64 #ifndef RTWN_WITHOUT_UCODE
65 static int
66 r92c_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len)
67 {
68         struct r92c_fw_cmd cmd;
69         int ntries, error;
70
71         KASSERT(len <= sizeof(cmd.msg),
72             ("%s: firmware command too long (%d > %zu)\n",
73             __func__, len, sizeof(cmd.msg)));
74
75         if (!(sc->sc_flags & RTWN_FW_LOADED)) {
76                 RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware "
77                     "was not loaded; command (id %u) will be discarded\n",
78                     __func__, id);
79                 return (0);
80         }
81
82         /* Wait for current FW box to be empty. */
83         for (ntries = 0; ntries < 100; ntries++) {
84                 if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
85                         break;
86                 rtwn_delay(sc, 2000);
87         }
88         if (ntries == 100) {
89                 device_printf(sc->sc_dev,
90                     "could not send firmware command\n");
91                 return (ETIMEDOUT);
92         }
93         memset(&cmd, 0, sizeof(cmd));
94         cmd.id = id;
95         if (len > 3) {
96                 /* Ext command: [id : byte2 : byte3 : byte4 : byte0 : byte1] */
97                 cmd.id |= R92C_CMD_FLAG_EXT;
98                 memcpy(cmd.msg, (const uint8_t *)buf + 2, len - 2);
99                 memcpy(cmd.msg + 3, buf, 2);
100         } else
101                 memcpy(cmd.msg, buf, len);
102
103         /* Write the first word last since that will trigger the FW. */
104         if (len > 3) {
105                 error = rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur),
106                     *(uint16_t *)((uint8_t *)&cmd + 4));
107                 if (error != 0)
108                         return (error);
109         }
110         error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur),
111             *(uint32_t *)&cmd);
112         if (error != 0)
113                 return (error);
114
115         sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
116
117         return (0);
118 }
119
120 void
121 r92c_fw_reset(struct rtwn_softc *sc, int reason)
122 {
123         int ntries;
124
125         if (reason == RTWN_FW_RESET_CHECKSUM)
126                 return;
127
128         /* Tell 8051 to reset itself. */
129         rtwn_write_1(sc, R92C_HMETFR + 3, 0x20);
130
131         /* Wait until 8051 resets by itself. */
132         for (ntries = 0; ntries < 100; ntries++) {
133                 if ((rtwn_read_2(sc, R92C_SYS_FUNC_EN) &
134                     R92C_SYS_FUNC_EN_CPUEN) == 0)
135                         return;
136                 rtwn_delay(sc, 50);
137         }
138         /* Force 8051 reset. */
139         rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
140             R92C_SYS_FUNC_EN_CPUEN, 0, 1);
141 }
142
143 void
144 r92c_fw_download_enable(struct rtwn_softc *sc, int enable)
145 {
146         if (enable) {
147                 /* 8051 enable. */
148                 rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, 0,
149                     R92C_SYS_FUNC_EN_CPUEN, 1);
150                 /* MCU firmware download enable. */
151                 rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN);
152                 /* 8051 reset. */
153                 rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN,
154                     0, 2);
155         } else {
156                 /* MCU download disable. */
157                 rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0);
158                 /* Reserved for f/w extension. */
159                 rtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
160         }
161 }
162 #endif
163
164 /*
165  * Initialize firmware rate adaptation.
166  */
167 #ifndef RTWN_WITHOUT_UCODE
168 static int
169 r92c_send_ra_cmd(struct rtwn_softc *sc, int macid, uint32_t rates,
170     int maxrate)
171 {
172         struct r92c_fw_cmd_macid_cfg cmd;
173         uint8_t mode;
174         int error = 0;
175
176         /* XXX should be called directly from iv_newstate() for MACID_BC */
177         /* XXX joinbss, not send_ra_cmd() */
178 #ifdef RTWN_TODO
179         /* NB: group addressed frames are done at 11bg rates for now */
180         if (ic->ic_curmode == IEEE80211_MODE_11B)
181                 mode = R92C_RAID_11B;
182         else
183                 mode = R92C_RAID_11BG;
184         /* XXX misleading 'mode' value here for unicast frames */
185         RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
186             "%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__,
187             mode, rates, basicrates);
188
189         /* Set rates mask for group addressed frames. */
190         cmd.macid = RTWN_MACID_BC | R92C_CMD_MACID_VALID;
191         cmd.mask = htole32(mode << 28 | basicrates);
192         error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
193         if (error != 0) {
194                 device_printf(sc->sc_dev,
195                     "could not set RA mask for broadcast station\n");
196                 return (error);
197         }
198 #endif
199
200         /* Set rates mask for unicast frames. */
201         if (maxrate >= RTWN_RIDX_HT_MCS(0))
202                 mode = R92C_RAID_11GN;
203         else if (maxrate >= RTWN_RIDX_OFDM6)
204                 mode = R92C_RAID_11BG;
205         else
206                 mode = R92C_RAID_11B;
207         cmd.macid = macid | R92C_CMD_MACID_VALID;
208         cmd.mask = htole32(mode << 28 | rates);
209         error = r92c_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
210         if (error != 0) {
211                 device_printf(sc->sc_dev,
212                     "%s: could not set RA mask for %d station\n",
213                     __func__, macid);
214                 return (error);
215         }
216
217         return (0);
218 }
219 #endif
220
221 static void
222 r92c_init_ra(struct rtwn_softc *sc, int macid)
223 {
224         struct ieee80211_htrateset *rs_ht;
225         struct ieee80211_node *ni;
226         uint32_t rates;
227         int maxrate;
228
229         RTWN_NT_LOCK(sc);
230         if (sc->node_list[macid] == NULL) {
231                 RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: macid %d, ni is NULL\n",
232                     __func__, macid);
233                 RTWN_NT_UNLOCK(sc);
234                 return;
235         }
236
237         ni = ieee80211_ref_node(sc->node_list[macid]);
238         if (ni->ni_flags & IEEE80211_NODE_HT)
239                 rs_ht = &ni->ni_htrates;
240         else
241                 rs_ht = NULL;
242         /* XXX MACID_BC */
243         rtwn_get_rates(sc, &ni->ni_rates, rs_ht, &rates, &maxrate, 0);
244         RTWN_NT_UNLOCK(sc);
245
246 #ifndef RTWN_WITHOUT_UCODE
247         if (sc->sc_ratectl == RTWN_RATECTL_FW) {
248                 r92c_send_ra_cmd(sc, macid, rates, maxrate);
249         }
250 #endif
251
252         rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(macid), maxrate);
253
254         ieee80211_free_node(ni);
255 }
256
257 void
258 r92c_joinbss_rpt(struct rtwn_softc *sc, int macid)
259 {
260 #ifndef RTWN_WITHOUT_UCODE
261         struct r92c_softc *rs = sc->sc_priv;
262         struct ieee80211vap *vap;
263         struct r92c_fw_cmd_joinbss_rpt cmd;
264
265         if (sc->vaps[0] == NULL)        /* XXX fix */
266                 goto end;
267
268         vap = &sc->vaps[0]->vap;
269         if ((vap->iv_state == IEEE80211_S_RUN) ^
270             !(rs->rs_flags & R92C_FLAG_ASSOCIATED))
271                 goto end;
272
273         if (rs->rs_flags & R92C_FLAG_ASSOCIATED) {
274                 cmd.mstatus = R92C_MSTATUS_DISASSOC;
275                 rs->rs_flags &= ~R92C_FLAG_ASSOCIATED;
276         } else {
277                 cmd.mstatus = R92C_MSTATUS_ASSOC;
278                 rs->rs_flags |= R92C_FLAG_ASSOCIATED;
279         }
280
281         if (r92c_fw_cmd(sc, R92C_CMD_JOINBSS_RPT, &cmd, sizeof(cmd)) != 0) {
282                 device_printf(sc->sc_dev, "%s: cannot change media status!\n",
283                     __func__);
284         }
285
286 end:
287 #endif
288
289         /* TODO: init rates for RTWN_MACID_BC. */
290         if (macid & RTWN_MACID_VALID)
291                 r92c_init_ra(sc, macid & ~RTWN_MACID_VALID);
292 }
293
294 #ifndef RTWN_WITHOUT_UCODE
295 int
296 r92c_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null,
297     int qos_null)
298 {
299         struct r92c_fw_cmd_rsvdpage rsvd;
300
301         rsvd.probe_resp = probe_resp;
302         rsvd.ps_poll = 0;
303         rsvd.null_data = null;
304
305         return (r92c_fw_cmd(sc, R92C_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd)));
306 }
307
308 int
309 r92c_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap,
310     int off)
311 {
312         struct r92c_fw_cmd_pwrmode mode;
313         int error;
314
315         /* XXX dm_RF_saving */
316
317         if (off && vap->iv_state == IEEE80211_S_RUN &&
318             (vap->iv_flags & IEEE80211_F_PMGTON))
319                 mode.mode = R92C_PWRMODE_MIN;
320         else
321                 mode.mode = R92C_PWRMODE_CAM;
322         mode.smart_ps = R92C_PWRMODE_SMARTPS_NULLDATA;
323         mode.bcn_pass = 1;      /* XXX */
324         error = r92c_fw_cmd(sc, R92C_CMD_SET_PWRMODE, &mode, sizeof(mode));
325         if (error != 0) {
326                 device_printf(sc->sc_dev,
327                     "%s: CMD_SET_PWRMODE was not sent, error %d\n",
328                     __func__, error);
329         }
330
331         return (error);
332 }
333
334 void
335 r92c_set_rssi(struct rtwn_softc *sc)
336 {
337         struct ieee80211_node *ni;
338         struct rtwn_node *rn;
339         struct r92c_fw_cmd_rssi cmd;
340         int i;
341
342         cmd.reserved = 0;
343
344         RTWN_NT_LOCK(sc);
345         for (i = 0; i < sc->macid_limit; i++) {
346                 /* XXX optimize? */
347                 ni = sc->node_list[i];
348                 if (ni == NULL)
349                         continue;
350
351                 rn = RTWN_NODE(ni);
352                 cmd.macid = i;
353                 cmd.pwdb = rn->avg_pwdb;
354                 RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI,
355                     "%s: sending RSSI command (macid %d, rssi %d)\n",
356                     __func__, i, rn->avg_pwdb);
357
358                 RTWN_NT_UNLOCK(sc);
359                 r92c_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd));
360                 RTWN_NT_LOCK(sc);
361         }
362         RTWN_NT_UNLOCK(sc);
363 }
364
365 static void
366 r92c_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
367 {
368 #if __FreeBSD_version >= 1200012
369         struct ieee80211_ratectl_tx_status txs;
370 #endif
371         struct r92c_c2h_tx_rpt *rpt;
372         struct ieee80211_node *ni;
373         uint8_t macid;
374         int ntries;
375
376         if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
377                 /* shouldn't happen */
378                 device_printf(sc->sc_dev, "%s called while ratectl = %d!\n",
379                     __func__, sc->sc_ratectl);
380                 return;
381         }
382
383         rpt = (struct r92c_c2h_tx_rpt *)buf;
384         if (len != sizeof(*rpt)) {
385                 device_printf(sc->sc_dev,
386                     "%s: wrong report size (%d, must be %zu)\n",
387                     __func__, len, sizeof(*rpt));
388                 return;
389         }
390
391         RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
392             "%s: ccx report dump: 0: %02X, 1: %02X, queue time: "
393             "low %02X, high %02X, 4: %02X, 5: %02X, 6: %02X, 7: %02X\n",
394             __func__, rpt->rptb0, rpt->rptb1, rpt->queue_time_low,
395             rpt->queue_time_high, rpt->rptb4, rpt->rptb5, rpt->rptb6,
396             rpt->rptb7);
397
398         macid = MS(rpt->rptb5, R92C_RPTB5_MACID);
399         if (macid > sc->macid_limit) {
400                 device_printf(sc->sc_dev,
401                     "macid %u is too big; increase MACID_MAX limit\n",
402                     macid);
403                 return;
404         }
405
406         ntries = MS(rpt->rptb0, R92C_RPTB0_RETRY_CNT);
407
408         RTWN_NT_LOCK(sc);
409         ni = sc->node_list[macid];
410         if (ni != NULL) {
411                 RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
412                     "%s sent (%d retries)\n", __func__, macid,
413                     (rpt->rptb7 & R92C_RPTB7_PKT_OK) ? "" : " not",
414                     ntries);
415
416 #if __FreeBSD_version >= 1200012
417                 txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY;
418                 txs.long_retries = ntries;
419                 if (rpt->rptb7 & R92C_RPTB7_PKT_OK)
420                         txs.status = IEEE80211_RATECTL_TX_SUCCESS;
421                 else if (rpt->rptb6 & R92C_RPTB6_RETRY_OVER)
422                         txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; /* XXX */
423                 else if (rpt->rptb6 & R92C_RPTB6_LIFE_EXPIRE)
424                         txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
425                 else
426                         txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
427                 ieee80211_ratectl_tx_complete(ni, &txs);
428 #else
429                 struct ieee80211vap *vap = ni->ni_vap;
430                 if (rpt->rptb7 & R92C_RPTB7_PKT_OK) {
431                         ieee80211_ratectl_tx_complete(vap, ni,
432                             IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL);
433                 } else {
434                         ieee80211_ratectl_tx_complete(vap, ni,
435                             IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL);
436                 }
437 #endif
438         } else {
439                 RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n",
440                     __func__, macid);
441         }
442         RTWN_NT_UNLOCK(sc);
443
444 #ifdef IEEE80211_SUPPORT_SUPERG
445         if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1)
446                 rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
447 #endif
448 }
449
450 static void
451 r92c_handle_c2h_task(struct rtwn_softc *sc, union sec_param *data)
452 {
453         const uint16_t off = R92C_C2H_EVT_MSG + sizeof(struct r92c_c2h_evt);
454         struct r92c_softc *rs = sc->sc_priv;
455         uint16_t buf[R92C_C2H_MSG_MAX_LEN / 2 + 1];
456         uint8_t id, len, status;
457         int i;
458
459         /* Do not reschedule the task if device is not running. */
460         if (!(sc->sc_flags & RTWN_RUNNING))
461                 return;
462
463         /* Read current status. */
464         status = rtwn_read_1(sc, R92C_C2H_EVT_CLEAR);
465         if (status == R92C_C2H_EVT_HOST_CLOSE)
466                 goto end;       /* nothing to do */
467         else if (status == R92C_C2H_EVT_FW_CLOSE) {
468                 len = rtwn_read_1(sc, R92C_C2H_EVT_MSG);
469                 id = MS(len, R92C_C2H_EVTB0_ID);
470                 len = MS(len, R92C_C2H_EVTB0_LEN);
471
472                 memset(buf, 0, sizeof(buf));
473                 /* Try to optimize event reads. */
474                 for (i = 0; i < len; i += 2)
475                         buf[i / 2] = rtwn_read_2(sc, off + i);
476                 KASSERT(i < sizeof(buf), ("%s: buffer overrun (%d >= %zu)!",
477                     __func__, i, sizeof(buf)));
478
479                 switch (id) {
480                 case R92C_C2H_EVT_TX_REPORT:
481                         r92c_ratectl_tx_complete(sc, (uint8_t *)buf, len);
482                         break;
483                 default:
484                         device_printf(sc->sc_dev,
485                             "%s: C2H report %u (len %u) was not handled\n",
486                             __func__, id, len);
487                         break;
488                 }
489         }
490
491         /* Prepare for next event. */
492         rtwn_write_1(sc, R92C_C2H_EVT_CLEAR, R92C_C2H_EVT_HOST_CLOSE);
493
494 end:
495         /* Adjust timeout for next call. */
496         if (rs->rs_c2h_pending != 0) {
497                 rs->rs_c2h_pending = 0;
498                 rs->rs_c2h_paused = 0;
499         } else
500                 rs->rs_c2h_paused++;
501
502         if (rs->rs_c2h_paused > R92C_TX_PAUSED_THRESHOLD)
503                 rs->rs_c2h_timeout = hz;
504         else
505                 rs->rs_c2h_timeout = MAX(hz / 100, 1);
506
507         /* Reschedule the task. */
508         callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout,
509             r92c_handle_c2h_report, sc);
510 }
511
512 void
513 r92c_handle_c2h_report(void *arg)
514 {
515         struct rtwn_softc *sc = arg;
516
517         rtwn_cmd_sleepable(sc, NULL, 0, r92c_handle_c2h_task);
518 }
519
520 #endif  /* RTWN_WITHOUT_UCODE */