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 */ 521