1 // SPDX-License-Identifier: GPL-2.0 2 /****************************************************************************** 3 * 4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. 5 * 6 ******************************************************************************/ 7 #include <drv_types.h> 8 #include <hal_btcoex.h> 9 #include <linux/jiffies.h> 10 11 static struct _cmd_callback rtw_cmd_callback[] = { 12 {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ 13 {GEN_CMD_CODE(_Write_MACREG), NULL}, 14 {GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback}, 15 {GEN_CMD_CODE(_Write_BBREG), NULL}, 16 {GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback}, 17 {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/ 18 {GEN_CMD_CODE(_Read_EEPROM), NULL}, 19 {GEN_CMD_CODE(_Write_EEPROM), NULL}, 20 {GEN_CMD_CODE(_Read_EFUSE), NULL}, 21 {GEN_CMD_CODE(_Write_EFUSE), NULL}, 22 23 {GEN_CMD_CODE(_Read_CAM), NULL}, /*10*/ 24 {GEN_CMD_CODE(_Write_CAM), NULL}, 25 {GEN_CMD_CODE(_setBCNITV), NULL}, 26 {GEN_CMD_CODE(_setMBIDCFG), NULL}, 27 {GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd_callback}, /*14*/ 28 {GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd_callback}, /*15*/ 29 {GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd_callback}, 30 {GEN_CMD_CODE(_SetOpMode), NULL}, 31 {GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback}, /*18*/ 32 {GEN_CMD_CODE(_SetAuth), NULL}, 33 34 {GEN_CMD_CODE(_SetKey), NULL}, /*20*/ 35 {GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback}, 36 {GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback}, 37 {GEN_CMD_CODE(_DelAssocSta), NULL}, 38 {GEN_CMD_CODE(_SetStaPwrState), NULL}, 39 {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/ 40 {GEN_CMD_CODE(_GetBasicRate), NULL}, 41 {GEN_CMD_CODE(_SetDataRate), NULL}, 42 {GEN_CMD_CODE(_GetDataRate), NULL}, 43 {GEN_CMD_CODE(_SetPhyInfo), NULL}, 44 45 {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/ 46 {GEN_CMD_CODE(_SetPhy), NULL}, 47 {GEN_CMD_CODE(_GetPhy), NULL}, 48 {GEN_CMD_CODE(_readRssi), NULL}, 49 {GEN_CMD_CODE(_readGain), NULL}, 50 {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/ 51 {GEN_CMD_CODE(_SetPwrMode), NULL}, 52 {GEN_CMD_CODE(_JoinbssRpt), NULL}, 53 {GEN_CMD_CODE(_SetRaTable), NULL}, 54 {GEN_CMD_CODE(_GetRaTable), NULL}, 55 56 {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/ 57 {GEN_CMD_CODE(_GetDTMReport), NULL}, 58 {GEN_CMD_CODE(_GetTXRateStatistics), NULL}, 59 {GEN_CMD_CODE(_SetUsbSuspend), NULL}, 60 {GEN_CMD_CODE(_SetH2cLbk), NULL}, 61 {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/ 62 {GEN_CMD_CODE(_SetChannel), NULL}, /*46*/ 63 {GEN_CMD_CODE(_SetTxPower), NULL}, 64 {GEN_CMD_CODE(_SwitchAntenna), NULL}, 65 {GEN_CMD_CODE(_SetCrystalCap), NULL}, 66 {GEN_CMD_CODE(_SetSingleCarrierTx), NULL}, /*50*/ 67 68 {GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/ 69 {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL}, 70 {GEN_CMD_CODE(_SetContinuousTx), NULL}, 71 {GEN_CMD_CODE(_SwitchBandwidth), NULL}, /*54*/ 72 {GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/ 73 74 {GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/ 75 {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/ 76 {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/ 77 {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/ 78 79 {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*60*/ 80 {GEN_CMD_CODE(_TDLS), NULL},/*61*/ 81 {GEN_CMD_CODE(_ChkBMCSleepq), NULL}, /*62*/ 82 83 {GEN_CMD_CODE(_RunInThreadCMD), NULL},/*63*/ 84 }; 85 86 static struct cmd_hdl wlancmds[] = { 87 GEN_DRV_CMD_HANDLER(0, NULL) /*0*/ 88 GEN_DRV_CMD_HANDLER(0, NULL) 89 GEN_DRV_CMD_HANDLER(0, NULL) 90 GEN_DRV_CMD_HANDLER(0, NULL) 91 GEN_DRV_CMD_HANDLER(0, NULL) 92 GEN_DRV_CMD_HANDLER(0, NULL) 93 GEN_MLME_EXT_HANDLER(0, NULL) 94 GEN_MLME_EXT_HANDLER(0, NULL) 95 GEN_MLME_EXT_HANDLER(0, NULL) 96 GEN_MLME_EXT_HANDLER(0, NULL) 97 GEN_MLME_EXT_HANDLER(0, NULL) /*10*/ 98 GEN_MLME_EXT_HANDLER(0, NULL) 99 GEN_MLME_EXT_HANDLER(0, NULL) 100 GEN_MLME_EXT_HANDLER(0, NULL) 101 GEN_MLME_EXT_HANDLER(sizeof(struct joinbss_parm), join_cmd_hdl) /*14*/ 102 GEN_MLME_EXT_HANDLER(sizeof(struct disconnect_parm), disconnect_hdl) 103 GEN_MLME_EXT_HANDLER(sizeof(struct createbss_parm), createbss_hdl) 104 GEN_MLME_EXT_HANDLER(sizeof(struct setopmode_parm), setopmode_hdl) 105 GEN_MLME_EXT_HANDLER(sizeof(struct sitesurvey_parm), sitesurvey_cmd_hdl) /*18*/ 106 GEN_MLME_EXT_HANDLER(sizeof(struct setauth_parm), setauth_hdl) 107 GEN_MLME_EXT_HANDLER(sizeof(struct setkey_parm), setkey_hdl) /*20*/ 108 GEN_MLME_EXT_HANDLER(sizeof(struct set_stakey_parm), set_stakey_hdl) 109 GEN_MLME_EXT_HANDLER(sizeof(struct set_assocsta_parm), NULL) 110 GEN_MLME_EXT_HANDLER(sizeof(struct del_assocsta_parm), NULL) 111 GEN_MLME_EXT_HANDLER(sizeof(struct setstapwrstate_parm), NULL) 112 GEN_MLME_EXT_HANDLER(sizeof(struct setbasicrate_parm), NULL) 113 GEN_MLME_EXT_HANDLER(sizeof(struct getbasicrate_parm), NULL) 114 GEN_MLME_EXT_HANDLER(sizeof(struct setdatarate_parm), NULL) 115 GEN_MLME_EXT_HANDLER(sizeof(struct getdatarate_parm), NULL) 116 GEN_MLME_EXT_HANDLER(sizeof(struct setphyinfo_parm), NULL) 117 GEN_MLME_EXT_HANDLER(sizeof(struct getphyinfo_parm), NULL) /*30*/ 118 GEN_MLME_EXT_HANDLER(sizeof(struct setphy_parm), NULL) 119 GEN_MLME_EXT_HANDLER(sizeof(struct getphy_parm), NULL) 120 GEN_MLME_EXT_HANDLER(0, NULL) 121 GEN_MLME_EXT_HANDLER(0, NULL) 122 GEN_MLME_EXT_HANDLER(0, NULL) 123 GEN_MLME_EXT_HANDLER(0, NULL) 124 GEN_MLME_EXT_HANDLER(0, NULL) 125 GEN_MLME_EXT_HANDLER(0, NULL) 126 GEN_MLME_EXT_HANDLER(0, NULL) 127 GEN_MLME_EXT_HANDLER(0, NULL) /*40*/ 128 GEN_MLME_EXT_HANDLER(0, NULL) 129 GEN_MLME_EXT_HANDLER(0, NULL) 130 GEN_MLME_EXT_HANDLER(0, NULL) 131 GEN_MLME_EXT_HANDLER(0, NULL) 132 GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl) 133 GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), set_ch_hdl) /* 46 */ 134 GEN_MLME_EXT_HANDLER(0, NULL) 135 GEN_MLME_EXT_HANDLER(0, NULL) 136 GEN_MLME_EXT_HANDLER(0, NULL) 137 GEN_MLME_EXT_HANDLER(0, NULL) /*50*/ 138 GEN_MLME_EXT_HANDLER(0, NULL) 139 GEN_MLME_EXT_HANDLER(0, NULL) 140 GEN_MLME_EXT_HANDLER(0, NULL) 141 GEN_MLME_EXT_HANDLER(0, NULL) 142 GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param), tx_beacon_hdl) /*55*/ 143 144 GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl) /*56*/ 145 GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl) /*57*/ 146 147 GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/ 148 GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl) /*59*/ 149 150 GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param), set_csa_hdl) /*60*/ 151 GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl) /*61*/ 152 GEN_MLME_EXT_HANDLER(0, chk_bmc_sleepq_hdl) /*62*/ 153 GEN_MLME_EXT_HANDLER(sizeof(struct RunInThread_param), run_in_thread_hdl) /*63*/ 154 }; 155 156 /* 157 * Caller and the rtw_cmd_thread can protect cmd_q by spin_lock. 158 * No irqsave is necessary. 159 */ 160 rtw_init_cmd_priv(struct cmd_priv * pcmdpriv)161 int rtw_init_cmd_priv(struct cmd_priv *pcmdpriv) 162 { 163 init_completion(&pcmdpriv->cmd_queue_comp); 164 init_completion(&pcmdpriv->terminate_cmdthread_comp); 165 166 INIT_LIST_HEAD(&pcmdpriv->cmd_queue.queue); 167 spin_lock_init(&pcmdpriv->cmd_queue.lock); 168 169 /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ 170 171 pcmdpriv->cmd_seq = 1; 172 173 pcmdpriv->cmd_allocated_buf = rtw_zmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ); 174 175 if (!pcmdpriv->cmd_allocated_buf) 176 return -ENOMEM; 177 178 pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - ((SIZE_PTR)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ-1)); 179 180 pcmdpriv->rsp_allocated_buf = rtw_zmalloc(MAX_RSPSZ + 4); 181 182 if (!pcmdpriv->rsp_allocated_buf) { 183 kfree(pcmdpriv->cmd_allocated_buf); 184 return -ENOMEM; 185 } 186 187 pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - ((SIZE_PTR)(pcmdpriv->rsp_allocated_buf) & 3); 188 189 pcmdpriv->cmd_issued_cnt = 0; 190 pcmdpriv->cmd_done_cnt = 0; 191 pcmdpriv->rsp_cnt = 0; 192 193 mutex_init(&pcmdpriv->sctx_mutex); 194 195 return 0; 196 } 197 198 static void c2h_wk_callback(struct work_struct *work); rtw_init_evt_priv(struct evt_priv * pevtpriv)199 int rtw_init_evt_priv(struct evt_priv *pevtpriv) 200 { 201 /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ 202 atomic_set(&pevtpriv->event_seq, 0); 203 pevtpriv->evt_done_cnt = 0; 204 205 _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL); 206 pevtpriv->c2h_wk_alive = false; 207 pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1); 208 if (!pevtpriv->c2h_queue) 209 return -ENOMEM; 210 211 return 0; 212 } 213 _rtw_free_evt_priv(struct evt_priv * pevtpriv)214 void _rtw_free_evt_priv(struct evt_priv *pevtpriv) 215 { 216 _cancel_workitem_sync(&pevtpriv->c2h_wk); 217 while (pevtpriv->c2h_wk_alive) 218 msleep(10); 219 220 while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) { 221 void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue); 222 223 if (c2h && c2h != (void *)pevtpriv) 224 kfree(c2h); 225 } 226 kfree(pevtpriv->c2h_queue); 227 } 228 _rtw_free_cmd_priv(struct cmd_priv * pcmdpriv)229 void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) 230 { 231 if (pcmdpriv) { 232 kfree(pcmdpriv->cmd_allocated_buf); 233 234 kfree(pcmdpriv->rsp_allocated_buf); 235 236 mutex_destroy(&pcmdpriv->sctx_mutex); 237 } 238 } 239 240 /* 241 * Calling Context: 242 * 243 * rtw_enqueue_cmd can only be called between kernel thread, 244 * since only spin_lock is used. 245 * 246 * ISR/Call-Back functions can't call this sub-function. 247 * 248 */ 249 _rtw_enqueue_cmd(struct __queue * queue,struct cmd_obj * obj)250 int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj) 251 { 252 unsigned long irqL; 253 254 if (!obj) 255 goto exit; 256 257 /* spin_lock_bh(&queue->lock); */ 258 spin_lock_irqsave(&queue->lock, irqL); 259 260 list_add_tail(&obj->list, &queue->queue); 261 262 /* spin_unlock_bh(&queue->lock); */ 263 spin_unlock_irqrestore(&queue->lock, irqL); 264 265 exit: 266 return _SUCCESS; 267 } 268 _rtw_dequeue_cmd(struct __queue * queue)269 struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue) 270 { 271 unsigned long irqL; 272 struct cmd_obj *obj; 273 274 /* spin_lock_bh(&(queue->lock)); */ 275 spin_lock_irqsave(&queue->lock, irqL); 276 if (list_empty(&queue->queue)) 277 obj = NULL; 278 else { 279 obj = container_of(get_next(&queue->queue), struct cmd_obj, list); 280 list_del_init(&obj->list); 281 } 282 283 /* spin_unlock_bh(&(queue->lock)); */ 284 spin_unlock_irqrestore(&queue->lock, irqL); 285 286 return obj; 287 } 288 rtw_free_evt_priv(struct evt_priv * pevtpriv)289 void rtw_free_evt_priv(struct evt_priv *pevtpriv) 290 { 291 _rtw_free_evt_priv(pevtpriv); 292 } 293 rtw_free_cmd_priv(struct cmd_priv * pcmdpriv)294 void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) 295 { 296 _rtw_free_cmd_priv(pcmdpriv); 297 } 298 299 int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj); rtw_cmd_filter(struct cmd_priv * pcmdpriv,struct cmd_obj * cmd_obj)300 int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) 301 { 302 u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */ 303 304 if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan)) 305 bAllow = true; 306 307 if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) || 308 !atomic_read(&pcmdpriv->cmdthd_running)) /* com_thread not running */ 309 return _FAIL; 310 311 return _SUCCESS; 312 } 313 rtw_enqueue_cmd(struct cmd_priv * pcmdpriv,struct cmd_obj * cmd_obj)314 int rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) 315 { 316 int res = _FAIL; 317 struct adapter *padapter = pcmdpriv->padapter; 318 319 if (!cmd_obj) 320 goto exit; 321 322 cmd_obj->padapter = padapter; 323 324 res = rtw_cmd_filter(pcmdpriv, cmd_obj); 325 if (res == _FAIL) { 326 rtw_free_cmd_obj(cmd_obj); 327 goto exit; 328 } 329 330 res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj); 331 332 if (res == _SUCCESS) 333 complete(&pcmdpriv->cmd_queue_comp); 334 335 exit: 336 return res; 337 } 338 rtw_dequeue_cmd(struct cmd_priv * pcmdpriv)339 struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv) 340 { 341 return _rtw_dequeue_cmd(&pcmdpriv->cmd_queue); 342 } 343 rtw_free_cmd_obj(struct cmd_obj * pcmd)344 void rtw_free_cmd_obj(struct cmd_obj *pcmd) 345 { 346 if ((pcmd->cmdcode != _JoinBss_CMD_) && 347 (pcmd->cmdcode != _CreateBss_CMD_)) { 348 /* free parmbuf in cmd_obj */ 349 kfree(pcmd->parmbuf); 350 } 351 352 if (pcmd->rsp) { 353 if (pcmd->rspsz != 0) { 354 /* free rsp in cmd_obj */ 355 kfree(pcmd->rsp); 356 } 357 } 358 359 /* free cmd_obj */ 360 kfree(pcmd); 361 } 362 rtw_stop_cmd_thread(struct adapter * adapter)363 void rtw_stop_cmd_thread(struct adapter *adapter) 364 { 365 if (adapter->cmdThread && 366 atomic_read(&adapter->cmdpriv.cmdthd_running) && 367 adapter->cmdpriv.stop_req == 0) { 368 adapter->cmdpriv.stop_req = 1; 369 complete(&adapter->cmdpriv.cmd_queue_comp); 370 wait_for_completion(&adapter->cmdpriv.terminate_cmdthread_comp); 371 } 372 } 373 rtw_cmd_thread(void * context)374 int rtw_cmd_thread(void *context) 375 { 376 u8 ret; 377 struct cmd_obj *pcmd; 378 u8 *pcmdbuf; 379 u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf); 380 void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd); 381 struct adapter *padapter = context; 382 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 383 struct drvextra_cmd_parm *extra_parm = NULL; 384 385 thread_enter("RTW_CMD_THREAD"); 386 387 pcmdbuf = pcmdpriv->cmd_buf; 388 389 pcmdpriv->stop_req = 0; 390 atomic_set(&pcmdpriv->cmdthd_running, true); 391 complete(&pcmdpriv->terminate_cmdthread_comp); 392 393 while (1) { 394 if (wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp)) { 395 netdev_dbg(padapter->pnetdev, 396 FUNC_ADPT_FMT " wait_for_completion_interruptible(&pcmdpriv->cmd_queue_comp) return != 0, break\n", 397 FUNC_ADPT_ARG(padapter)); 398 break; 399 } 400 401 if (padapter->bDriverStopped || padapter->bSurpriseRemoved) { 402 netdev_dbg(padapter->pnetdev, 403 "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", 404 __func__, padapter->bDriverStopped, 405 padapter->bSurpriseRemoved, __LINE__); 406 break; 407 } 408 409 if (pcmdpriv->stop_req) { 410 netdev_dbg(padapter->pnetdev, 411 FUNC_ADPT_FMT " stop_req:%u, break\n", 412 FUNC_ADPT_ARG(padapter), 413 pcmdpriv->stop_req); 414 break; 415 } 416 417 if (list_empty(&pcmdpriv->cmd_queue.queue)) 418 continue; 419 420 if (rtw_register_cmd_alive(padapter) != _SUCCESS) 421 continue; 422 423 _next: 424 if (padapter->bDriverStopped || padapter->bSurpriseRemoved) { 425 netdev_dbg(padapter->pnetdev, 426 "%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", 427 __func__, padapter->bDriverStopped, 428 padapter->bSurpriseRemoved, __LINE__); 429 break; 430 } 431 432 pcmd = rtw_dequeue_cmd(pcmdpriv); 433 if (!pcmd) { 434 rtw_unregister_cmd_alive(padapter); 435 continue; 436 } 437 438 if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) { 439 pcmd->res = H2C_DROPPED; 440 goto post_process; 441 } 442 443 pcmdpriv->cmd_issued_cnt++; 444 445 pcmd->cmdsz = round_up((pcmd->cmdsz), 4); 446 447 memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); 448 449 if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) { 450 cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; 451 452 if (cmd_hdl) { 453 ret = cmd_hdl(pcmd->padapter, pcmdbuf); 454 pcmd->res = ret; 455 } 456 457 pcmdpriv->cmd_seq++; 458 } else { 459 pcmd->res = H2C_PARAMETERS_ERROR; 460 } 461 462 cmd_hdl = NULL; 463 464 post_process: 465 466 if (mutex_lock_interruptible(&pcmd->padapter->cmdpriv.sctx_mutex) == 0) { 467 if (pcmd->sctx) { 468 netdev_dbg(padapter->pnetdev, 469 FUNC_ADPT_FMT " pcmd->sctx\n", 470 FUNC_ADPT_ARG(pcmd->padapter)); 471 472 if (pcmd->res == H2C_SUCCESS) 473 rtw_sctx_done(&pcmd->sctx); 474 else 475 rtw_sctx_done_err(&pcmd->sctx, RTW_SCTX_DONE_CMD_ERROR); 476 } 477 mutex_unlock(&pcmd->padapter->cmdpriv.sctx_mutex); 478 } 479 480 /* call callback function for post-processed */ 481 if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) { 482 pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback; 483 if (!pcmd_callback) { 484 rtw_free_cmd_obj(pcmd); 485 } else { 486 /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */ 487 pcmd_callback(pcmd->padapter, pcmd);/* need consider that free cmd_obj in rtw_cmd_callback */ 488 } 489 } else { 490 rtw_free_cmd_obj(pcmd); 491 } 492 flush_signals_thread(); 493 goto _next; 494 } 495 496 /* free all cmd_obj resources */ 497 do { 498 pcmd = rtw_dequeue_cmd(pcmdpriv); 499 if (!pcmd) { 500 rtw_unregister_cmd_alive(padapter); 501 break; 502 } 503 504 if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { 505 extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf; 506 if (extra_parm->pbuf && extra_parm->size > 0) 507 kfree(extra_parm->pbuf); 508 } 509 510 rtw_free_cmd_obj(pcmd); 511 } while (1); 512 513 complete(&pcmdpriv->terminate_cmdthread_comp); 514 atomic_set(&pcmdpriv->cmdthd_running, false); 515 516 return 0; 517 } 518 519 /* 520 * rtw_sitesurvey_cmd(~) 521 * ### NOTE:#### (!!!!) 522 * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock 523 */ 524 rtw_sitesurvey_cmd(struct adapter * padapter,struct ndis_802_11_ssid * ssid,int ssid_num,struct rtw_ieee80211_channel * ch,int ch_num)525 u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int ssid_num, 526 struct rtw_ieee80211_channel *ch, int ch_num) 527 { 528 u8 res = _FAIL; 529 struct cmd_obj *ph2c; 530 struct sitesurvey_parm *psurveyPara; 531 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 532 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 533 534 if (check_fwstate(pmlmepriv, _FW_LINKED)) 535 rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1); 536 537 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 538 if (!ph2c) 539 return _FAIL; 540 541 psurveyPara = rtw_zmalloc(sizeof(struct sitesurvey_parm)); 542 if (!psurveyPara) { 543 kfree(ph2c); 544 return _FAIL; 545 } 546 547 rtw_free_network_queue(padapter, false); 548 549 init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); 550 551 /* psurveyPara->bsslimit = 48; */ 552 psurveyPara->scan_mode = pmlmepriv->scan_mode; 553 554 /* prepare ssid list */ 555 if (ssid) { 556 int i; 557 558 for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) { 559 if (ssid[i].ssid_length) { 560 memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid)); 561 psurveyPara->ssid_num++; 562 } 563 } 564 } 565 566 /* prepare channel list */ 567 if (ch) { 568 int i; 569 570 for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) { 571 if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) { 572 memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel)); 573 psurveyPara->ch_num++; 574 } 575 } 576 } 577 578 set_fwstate(pmlmepriv, _FW_UNDER_SURVEY); 579 580 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 581 582 if (res == _SUCCESS) { 583 pmlmepriv->scan_start_time = jiffies; 584 _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT); 585 } else { 586 _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); 587 } 588 return res; 589 } 590 rtw_getbbrfreg_cmdrsp_callback(struct adapter * padapter,struct cmd_obj * pcmd)591 void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) 592 { 593 /* rtw_free_cmd_obj(pcmd); */ 594 kfree(pcmd->parmbuf); 595 kfree(pcmd); 596 } 597 rtw_createbss_cmd(struct adapter * padapter)598 u8 rtw_createbss_cmd(struct adapter *padapter) 599 { 600 struct cmd_obj *pcmd; 601 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 602 struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network; 603 u8 res = _SUCCESS; 604 605 pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); 606 if (!pcmd) { 607 res = _FAIL; 608 goto exit; 609 } 610 611 INIT_LIST_HEAD(&pcmd->list); 612 pcmd->cmdcode = _CreateBss_CMD_; 613 pcmd->parmbuf = (unsigned char *)pdev_network; 614 pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network); 615 pcmd->rsp = NULL; 616 pcmd->rspsz = 0; 617 618 pdev_network->length = pcmd->cmdsz; 619 620 res = rtw_enqueue_cmd(pcmdpriv, pcmd); 621 622 exit: 623 return res; 624 } 625 rtw_startbss_cmd(struct adapter * padapter,int flags)626 int rtw_startbss_cmd(struct adapter *padapter, int flags) 627 { 628 struct cmd_obj *pcmd; 629 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 630 struct submit_ctx sctx; 631 int res = _SUCCESS; 632 633 if (flags & RTW_CMDF_DIRECTLY) { 634 /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ 635 start_bss_network(padapter); 636 } else { 637 /* need enqueue, prepare cmd_obj and enqueue */ 638 pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); 639 if (!pcmd) { 640 res = _FAIL; 641 goto exit; 642 } 643 644 INIT_LIST_HEAD(&pcmd->list); 645 pcmd->cmdcode = GEN_CMD_CODE(_CreateBss); 646 pcmd->parmbuf = NULL; 647 pcmd->cmdsz = 0; 648 pcmd->rsp = NULL; 649 pcmd->rspsz = 0; 650 651 if (flags & RTW_CMDF_WAIT_ACK) { 652 pcmd->sctx = &sctx; 653 rtw_sctx_init(&sctx, 2000); 654 } 655 656 res = rtw_enqueue_cmd(pcmdpriv, pcmd); 657 658 if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) { 659 rtw_sctx_wait(&sctx); 660 if (mutex_lock_interruptible(&pcmdpriv->sctx_mutex) == 0) { 661 if (sctx.status == RTW_SCTX_SUBMITTED) 662 pcmd->sctx = NULL; 663 mutex_unlock(&pcmdpriv->sctx_mutex); 664 } 665 } 666 } 667 668 exit: 669 return res; 670 } 671 rtw_joinbss_cmd(struct adapter * padapter,struct wlan_network * pnetwork)672 u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork) 673 { 674 u8 res = _SUCCESS; 675 uint t_len = 0; 676 struct wlan_bssid_ex *psecnetwork; 677 struct cmd_obj *pcmd; 678 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 679 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 680 struct qos_priv *pqospriv = &pmlmepriv->qospriv; 681 struct security_priv *psecuritypriv = &padapter->securitypriv; 682 struct registry_priv *pregistrypriv = &padapter->registrypriv; 683 struct ht_priv *phtpriv = &pmlmepriv->htpriv; 684 enum ndis_802_11_network_infrastructure ndis_network_mode = pnetwork->network.infrastructure_mode; 685 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; 686 struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; 687 u32 tmp_len; 688 u8 *ptmp = NULL; 689 690 pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); 691 if (!pcmd) { 692 res = _FAIL; 693 goto exit; 694 } 695 /* for ies is fix buf size */ 696 t_len = sizeof(struct wlan_bssid_ex); 697 698 699 /* for hidden ap to set fw_state here */ 700 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != true) { 701 switch (ndis_network_mode) { 702 case Ndis802_11IBSS: 703 set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); 704 break; 705 706 case Ndis802_11Infrastructure: 707 set_fwstate(pmlmepriv, WIFI_STATION_STATE); 708 break; 709 710 case Ndis802_11APMode: 711 case Ndis802_11AutoUnknown: 712 case Ndis802_11InfrastructureMax: 713 break; 714 } 715 } 716 717 psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss; 718 719 memset(psecnetwork, 0, t_len); 720 721 memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network)); 722 723 psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->ie_length; 724 725 if ((psecnetwork->ie_length-12) < (256-1)) 726 memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->ies[12], psecnetwork->ie_length-12); 727 else 728 memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->ies[12], (256-1)); 729 730 psecnetwork->ie_length = 0; 731 /* Added by Albert 2009/02/18 */ 732 /* If the driver wants to use the bssid to create the connection. */ 733 /* If not, we have to copy the connecting AP's MAC address to it so that */ 734 /* the driver just has the bssid information for PMKIDList searching. */ 735 736 if (!pmlmepriv->assoc_by_bssid) 737 memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.mac_address[0], ETH_ALEN); 738 739 psecnetwork->ie_length = rtw_restruct_sec_ie(padapter, &pnetwork->network.ies[0], &psecnetwork->ies[0], pnetwork->network.ie_length); 740 741 742 pqospriv->qos_option = 0; 743 744 if (pregistrypriv->wmm_enable) { 745 tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.ies[0], &psecnetwork->ies[0], pnetwork->network.ie_length, psecnetwork->ie_length); 746 747 if (psecnetwork->ie_length != tmp_len) { 748 psecnetwork->ie_length = tmp_len; 749 pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */ 750 } else { 751 pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */ 752 } 753 } 754 755 phtpriv->ht_option = false; 756 ptmp = rtw_get_ie(&pnetwork->network.ies[12], WLAN_EID_HT_CAPABILITY, &tmp_len, pnetwork->network.ie_length-12); 757 if (pregistrypriv->ht_enable && ptmp && tmp_len > 0) { 758 /* Added by Albert 2010/06/23 */ 759 /* For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */ 760 /* Especially for Realtek 8192u SoftAP. */ 761 if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) && 762 (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) && 763 (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) { 764 rtw_ht_use_default_setting(padapter); 765 766 rtw_build_wmm_ie_ht(padapter, &psecnetwork->ies[12], &psecnetwork->ie_length); 767 768 /* rtw_restructure_ht_ie */ 769 rtw_restructure_ht_ie(padapter, &pnetwork->network.ies[12], &psecnetwork->ies[0], 770 pnetwork->network.ie_length-12, &psecnetwork->ie_length, 771 pnetwork->network.configuration.ds_config); 772 } 773 } 774 775 rtw_append_exented_cap(padapter, &psecnetwork->ies[0], &psecnetwork->ie_length); 776 777 pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.ies, pnetwork->network.ie_length); 778 779 pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */ 780 781 INIT_LIST_HEAD(&pcmd->list); 782 pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */ 783 pcmd->parmbuf = (unsigned char *)psecnetwork; 784 pcmd->rsp = NULL; 785 pcmd->rspsz = 0; 786 787 res = rtw_enqueue_cmd(pcmdpriv, pcmd); 788 789 exit: 790 return res; 791 } 792 rtw_disassoc_cmd(struct adapter * padapter,u32 deauth_timeout_ms,bool enqueue)793 u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */ 794 { 795 struct cmd_obj *cmdobj = NULL; 796 struct disconnect_parm *param = NULL; 797 struct cmd_priv *cmdpriv = &padapter->cmdpriv; 798 u8 res = _SUCCESS; 799 800 /* prepare cmd parameter */ 801 param = rtw_zmalloc(sizeof(*param)); 802 if (!param) { 803 res = _FAIL; 804 goto exit; 805 } 806 param->deauth_timeout_ms = deauth_timeout_ms; 807 808 if (enqueue) { 809 /* need enqueue, prepare cmd_obj and enqueue */ 810 cmdobj = rtw_zmalloc(sizeof(*cmdobj)); 811 if (!cmdobj) { 812 res = _FAIL; 813 kfree(param); 814 goto exit; 815 } 816 init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_); 817 res = rtw_enqueue_cmd(cmdpriv, cmdobj); 818 } else { 819 /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ 820 if (disconnect_hdl(padapter, (u8 *)param) != H2C_SUCCESS) 821 res = _FAIL; 822 kfree(param); 823 } 824 825 exit: 826 return res; 827 } 828 rtw_setopmode_cmd(struct adapter * padapter,enum ndis_802_11_network_infrastructure networktype,bool enqueue)829 u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infrastructure networktype, bool enqueue) 830 { 831 struct cmd_obj *ph2c; 832 struct setopmode_parm *psetop; 833 834 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 835 u8 res = _SUCCESS; 836 837 psetop = rtw_zmalloc(sizeof(struct setopmode_parm)); 838 839 if (!psetop) { 840 res = _FAIL; 841 goto exit; 842 } 843 psetop->mode = (u8)networktype; 844 845 if (enqueue) { 846 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 847 if (!ph2c) { 848 kfree(psetop); 849 res = _FAIL; 850 goto exit; 851 } 852 853 init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); 854 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 855 } else { 856 setopmode_hdl(padapter, (u8 *)psetop); 857 kfree(psetop); 858 } 859 exit: 860 return res; 861 } 862 rtw_setstakey_cmd(struct adapter * padapter,struct sta_info * sta,u8 unicast_key,bool enqueue)863 u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_key, bool enqueue) 864 { 865 struct cmd_obj *ph2c; 866 struct set_stakey_parm *psetstakey_para; 867 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 868 struct set_stakey_rsp *psetstakey_rsp = NULL; 869 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 870 struct security_priv *psecuritypriv = &padapter->securitypriv; 871 u8 res = _SUCCESS; 872 873 psetstakey_para = rtw_zmalloc(sizeof(struct set_stakey_parm)); 874 if (!psetstakey_para) { 875 res = _FAIL; 876 goto exit; 877 } 878 879 memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); 880 881 if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) 882 psetstakey_para->algorithm = (unsigned char)psecuritypriv->dot11PrivacyAlgrthm; 883 else 884 GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false); 885 886 if (unicast_key) 887 memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16); 888 else 889 memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16); 890 891 /* jeff: set this because at least sw key is ready */ 892 padapter->securitypriv.busetkipkey = true; 893 894 if (enqueue) { 895 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 896 if (!ph2c) { 897 kfree(psetstakey_para); 898 res = _FAIL; 899 goto exit; 900 } 901 902 psetstakey_rsp = rtw_zmalloc(sizeof(struct set_stakey_rsp)); 903 if (!psetstakey_rsp) { 904 kfree(ph2c); 905 kfree(psetstakey_para); 906 res = _FAIL; 907 goto exit; 908 } 909 910 init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); 911 ph2c->rsp = (u8 *)psetstakey_rsp; 912 ph2c->rspsz = sizeof(struct set_stakey_rsp); 913 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 914 } else { 915 set_stakey_hdl(padapter, (u8 *)psetstakey_para); 916 kfree(psetstakey_para); 917 } 918 exit: 919 return res; 920 } 921 rtw_clearstakey_cmd(struct adapter * padapter,struct sta_info * sta,u8 enqueue)922 u8 rtw_clearstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 enqueue) 923 { 924 struct cmd_obj *ph2c; 925 struct set_stakey_parm *psetstakey_para; 926 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 927 struct set_stakey_rsp *psetstakey_rsp = NULL; 928 s16 cam_id = 0; 929 u8 res = _SUCCESS; 930 931 if (!enqueue) { 932 while ((cam_id = rtw_camid_search(padapter, sta->hwaddr, -1)) >= 0) { 933 netdev_dbg(padapter->pnetdev, 934 "clear key for addr:%pM, camid:%d\n", 935 MAC_ARG(sta->hwaddr), cam_id); 936 clear_cam_entry(padapter, cam_id); 937 rtw_camid_free(padapter, cam_id); 938 } 939 } else { 940 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 941 if (!ph2c) { 942 res = _FAIL; 943 goto exit; 944 } 945 946 psetstakey_para = rtw_zmalloc(sizeof(struct set_stakey_parm)); 947 if (!psetstakey_para) { 948 kfree(ph2c); 949 res = _FAIL; 950 goto exit; 951 } 952 953 psetstakey_rsp = rtw_zmalloc(sizeof(struct set_stakey_rsp)); 954 if (!psetstakey_rsp) { 955 kfree(ph2c); 956 kfree(psetstakey_para); 957 res = _FAIL; 958 goto exit; 959 } 960 961 init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); 962 ph2c->rsp = (u8 *)psetstakey_rsp; 963 ph2c->rspsz = sizeof(struct set_stakey_rsp); 964 965 memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); 966 967 psetstakey_para->algorithm = _NO_PRIVACY_; 968 969 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 970 } 971 exit: 972 return res; 973 } 974 rtw_addbareq_cmd(struct adapter * padapter,u8 tid,u8 * addr)975 u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr) 976 { 977 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 978 struct cmd_obj *ph2c; 979 struct addBaReq_parm *paddbareq_parm; 980 981 u8 res = _SUCCESS; 982 983 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 984 if (!ph2c) { 985 res = _FAIL; 986 goto exit; 987 } 988 989 paddbareq_parm = rtw_zmalloc(sizeof(struct addBaReq_parm)); 990 if (!paddbareq_parm) { 991 kfree(ph2c); 992 res = _FAIL; 993 goto exit; 994 } 995 996 paddbareq_parm->tid = tid; 997 memcpy(paddbareq_parm->addr, addr, ETH_ALEN); 998 999 init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq)); 1000 1001 /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ 1002 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1003 1004 exit: 1005 return res; 1006 } 1007 /* add for CONFIG_IEEE80211W, none 11w can use it */ rtw_reset_securitypriv_cmd(struct adapter * padapter)1008 u8 rtw_reset_securitypriv_cmd(struct adapter *padapter) 1009 { 1010 struct cmd_obj *ph2c; 1011 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1012 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1013 u8 res = _SUCCESS; 1014 1015 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 1016 if (!ph2c) { 1017 res = _FAIL; 1018 goto exit; 1019 } 1020 1021 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1022 if (!pdrvextra_cmd_parm) { 1023 kfree(ph2c); 1024 res = _FAIL; 1025 goto exit; 1026 } 1027 1028 pdrvextra_cmd_parm->ec_id = RESET_SECURITYPRIV; 1029 pdrvextra_cmd_parm->type = 0; 1030 pdrvextra_cmd_parm->size = 0; 1031 pdrvextra_cmd_parm->pbuf = NULL; 1032 1033 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1034 1035 1036 /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ 1037 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1038 exit: 1039 return res; 1040 } 1041 rtw_free_assoc_resources_cmd(struct adapter * padapter)1042 u8 rtw_free_assoc_resources_cmd(struct adapter *padapter) 1043 { 1044 struct cmd_obj *ph2c; 1045 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1046 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1047 u8 res = _SUCCESS; 1048 1049 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 1050 if (!ph2c) { 1051 res = _FAIL; 1052 goto exit; 1053 } 1054 1055 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1056 if (!pdrvextra_cmd_parm) { 1057 kfree(ph2c); 1058 res = _FAIL; 1059 goto exit; 1060 } 1061 1062 pdrvextra_cmd_parm->ec_id = FREE_ASSOC_RESOURCES; 1063 pdrvextra_cmd_parm->type = 0; 1064 pdrvextra_cmd_parm->size = 0; 1065 pdrvextra_cmd_parm->pbuf = NULL; 1066 1067 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1068 1069 /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ 1070 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1071 exit: 1072 return res; 1073 } 1074 rtw_dynamic_chk_wk_cmd(struct adapter * padapter)1075 u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter) 1076 { 1077 struct cmd_obj *ph2c; 1078 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1079 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1080 u8 res = _SUCCESS; 1081 1082 /* only primary padapter does this cmd */ 1083 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 1084 if (!ph2c) { 1085 res = _FAIL; 1086 goto exit; 1087 } 1088 1089 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1090 if (!pdrvextra_cmd_parm) { 1091 kfree(ph2c); 1092 res = _FAIL; 1093 goto exit; 1094 } 1095 1096 pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID; 1097 pdrvextra_cmd_parm->type = 0; 1098 pdrvextra_cmd_parm->size = 0; 1099 pdrvextra_cmd_parm->pbuf = NULL; 1100 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1101 1102 1103 /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ 1104 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1105 exit: 1106 return res; 1107 } 1108 collect_traffic_statistics(struct adapter * padapter)1109 static void collect_traffic_statistics(struct adapter *padapter) 1110 { 1111 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); 1112 1113 /* Tx */ 1114 pdvobjpriv->traffic_stat.tx_bytes = padapter->xmitpriv.tx_bytes; 1115 pdvobjpriv->traffic_stat.tx_pkts = padapter->xmitpriv.tx_pkts; 1116 pdvobjpriv->traffic_stat.tx_drop = padapter->xmitpriv.tx_drop; 1117 1118 /* Rx */ 1119 pdvobjpriv->traffic_stat.rx_bytes = padapter->recvpriv.rx_bytes; 1120 pdvobjpriv->traffic_stat.rx_pkts = padapter->recvpriv.rx_pkts; 1121 pdvobjpriv->traffic_stat.rx_drop = padapter->recvpriv.rx_drop; 1122 1123 /* Calculate throughput in last interval */ 1124 pdvobjpriv->traffic_stat.cur_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes - pdvobjpriv->traffic_stat.last_tx_bytes; 1125 pdvobjpriv->traffic_stat.cur_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes - pdvobjpriv->traffic_stat.last_rx_bytes; 1126 pdvobjpriv->traffic_stat.last_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes; 1127 pdvobjpriv->traffic_stat.last_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes; 1128 1129 pdvobjpriv->traffic_stat.cur_tx_tp = (u32)(pdvobjpriv->traffic_stat.cur_tx_bytes * 8/2/1024/1024); 1130 pdvobjpriv->traffic_stat.cur_rx_tp = (u32)(pdvobjpriv->traffic_stat.cur_rx_bytes * 8/2/1024/1024); 1131 } 1132 traffic_status_watchdog(struct adapter * padapter,u8 from_timer)1133 u8 traffic_status_watchdog(struct adapter *padapter, u8 from_timer) 1134 { 1135 u8 bEnterPS = false; 1136 u16 BusyThresholdHigh = 25; 1137 u16 BusyThresholdLow = 10; 1138 u16 BusyThreshold = BusyThresholdHigh; 1139 u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false; 1140 u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false; 1141 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 1142 1143 collect_traffic_statistics(padapter); 1144 1145 /* */ 1146 /* Determine if our traffic is busy now */ 1147 /* */ 1148 if ((check_fwstate(pmlmepriv, _FW_LINKED)) 1149 /*&& !MgntInitAdapterInProgress(pMgntInfo)*/) { 1150 /* if we raise bBusyTraffic in last watchdog, using lower threshold. */ 1151 if (pmlmepriv->LinkDetectInfo.bBusyTraffic) 1152 BusyThreshold = BusyThresholdLow; 1153 1154 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > BusyThreshold || 1155 pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > BusyThreshold) { 1156 bBusyTraffic = true; 1157 1158 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) 1159 bRxBusyTraffic = true; 1160 else 1161 bTxBusyTraffic = true; 1162 } 1163 1164 /* Higher Tx/Rx data. */ 1165 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 || 1166 pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) { 1167 bHigherBusyTraffic = true; 1168 1169 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) 1170 bHigherBusyRxTraffic = true; 1171 else 1172 bHigherBusyTxTraffic = true; 1173 } 1174 1175 /* check traffic for powersaving. */ 1176 if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) || 1177 (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2)) { 1178 bEnterPS = false; 1179 1180 if (bBusyTraffic) { 1181 if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount <= 4) 1182 pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 4; 1183 1184 pmlmepriv->LinkDetectInfo.TrafficTransitionCount++; 1185 1186 if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount > 30/*TrafficTransitionLevel*/) 1187 pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 30; 1188 } 1189 } else { 1190 if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount >= 2) 1191 pmlmepriv->LinkDetectInfo.TrafficTransitionCount -= 2; 1192 else 1193 pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; 1194 1195 if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount == 0) 1196 bEnterPS = true; 1197 } 1198 1199 /* LeisurePS only work in infra mode. */ 1200 if (bEnterPS) { 1201 if (!from_timer) 1202 LPS_Enter(padapter, "TRAFFIC_IDLE"); 1203 } else { 1204 if (!from_timer) 1205 LPS_Leave(padapter, "TRAFFIC_BUSY"); 1206 else 1207 rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_TRAFFIC_BUSY, 1); 1208 } 1209 } else { 1210 struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); 1211 int n_assoc_iface = 0; 1212 1213 if (check_fwstate(&dvobj->padapters->mlmepriv, WIFI_ASOC_STATE)) 1214 n_assoc_iface++; 1215 1216 if (!from_timer && n_assoc_iface == 0) 1217 LPS_Leave(padapter, "NON_LINKED"); 1218 } 1219 1220 pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0; 1221 pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0; 1222 pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0; 1223 pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic; 1224 pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic; 1225 pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic; 1226 pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic; 1227 pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic; 1228 pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic; 1229 1230 return bEnterPS; 1231 1232 } 1233 dynamic_chk_wk_hdl(struct adapter * padapter)1234 static void dynamic_chk_wk_hdl(struct adapter *padapter) 1235 { 1236 struct mlme_priv *pmlmepriv; 1237 1238 pmlmepriv = &padapter->mlmepriv; 1239 1240 if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) 1241 expire_timeout_chk(padapter); 1242 1243 /* for debug purpose */ 1244 _linked_info_dump(padapter); 1245 /* if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING|_FW_UNDER_SURVEY) ==false) */ 1246 { 1247 linked_status_chk(padapter); 1248 traffic_status_watchdog(padapter, 0); 1249 } 1250 rtw_hal_dm_watchdog(padapter); 1251 1252 /* check_hw_pbc(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type); */ 1253 1254 /* */ 1255 /* BT-Coexist */ 1256 /* */ 1257 hal_btcoex_Handler(padapter); 1258 1259 1260 /* always call rtw_ps_processor() at last one. */ 1261 if (is_primary_adapter(padapter)) 1262 rtw_ps_processor(padapter); 1263 } 1264 1265 void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type); lps_ctrl_wk_hdl(struct adapter * padapter,u8 lps_ctrl_type)1266 void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type) 1267 { 1268 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); 1269 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 1270 u8 mstatus; 1271 1272 if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || 1273 check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { 1274 return; 1275 } 1276 1277 switch (lps_ctrl_type) { 1278 case LPS_CTRL_SCAN: 1279 hal_btcoex_ScanNotify(padapter, true); 1280 1281 if (check_fwstate(pmlmepriv, _FW_LINKED)) { 1282 /* connect */ 1283 LPS_Leave(padapter, "LPS_CTRL_SCAN"); 1284 } 1285 break; 1286 case LPS_CTRL_JOINBSS: 1287 LPS_Leave(padapter, "LPS_CTRL_JOINBSS"); 1288 break; 1289 case LPS_CTRL_CONNECT: 1290 mstatus = 1;/* connect */ 1291 /* Reset LPS Setting */ 1292 pwrpriv->LpsIdleCount = 0; 1293 rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); 1294 rtw_btcoex_MediaStatusNotify(padapter, mstatus); 1295 break; 1296 case LPS_CTRL_DISCONNECT: 1297 mstatus = 0;/* disconnect */ 1298 rtw_btcoex_MediaStatusNotify(padapter, mstatus); 1299 LPS_Leave(padapter, "LPS_CTRL_DISCONNECT"); 1300 rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); 1301 break; 1302 case LPS_CTRL_SPECIAL_PACKET: 1303 pwrpriv->DelayLPSLastTimeStamp = jiffies; 1304 hal_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP); 1305 LPS_Leave(padapter, "LPS_CTRL_SPECIAL_PACKET"); 1306 break; 1307 case LPS_CTRL_LEAVE: 1308 LPS_Leave(padapter, "LPS_CTRL_LEAVE"); 1309 break; 1310 case LPS_CTRL_TRAFFIC_BUSY: 1311 LPS_Leave(padapter, "LPS_CTRL_TRAFFIC_BUSY"); 1312 break; 1313 default: 1314 break; 1315 } 1316 } 1317 rtw_lps_ctrl_wk_cmd(struct adapter * padapter,u8 lps_ctrl_type,u8 enqueue)1318 u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue) 1319 { 1320 struct cmd_obj *ph2c; 1321 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1322 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1323 /* struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); */ 1324 u8 res = _SUCCESS; 1325 1326 /* if (!pwrctrlpriv->bLeisurePs) */ 1327 /* return res; */ 1328 1329 if (enqueue) { 1330 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 1331 if (!ph2c) { 1332 res = _FAIL; 1333 goto exit; 1334 } 1335 1336 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1337 if (!pdrvextra_cmd_parm) { 1338 kfree(ph2c); 1339 res = _FAIL; 1340 goto exit; 1341 } 1342 1343 pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID; 1344 pdrvextra_cmd_parm->type = lps_ctrl_type; 1345 pdrvextra_cmd_parm->size = 0; 1346 pdrvextra_cmd_parm->pbuf = NULL; 1347 1348 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1349 1350 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1351 } else { 1352 lps_ctrl_wk_hdl(padapter, lps_ctrl_type); 1353 } 1354 1355 exit: 1356 return res; 1357 } 1358 rtw_dm_in_lps_hdl(struct adapter * padapter)1359 static void rtw_dm_in_lps_hdl(struct adapter *padapter) 1360 { 1361 rtw_hal_set_hwreg(padapter, HW_VAR_DM_IN_LPS, NULL); 1362 } 1363 rtw_dm_in_lps_wk_cmd(struct adapter * padapter)1364 u8 rtw_dm_in_lps_wk_cmd(struct adapter *padapter) 1365 { 1366 struct cmd_obj *ph2c; 1367 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1368 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1369 u8 res = _SUCCESS; 1370 1371 1372 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 1373 if (!ph2c) { 1374 res = _FAIL; 1375 goto exit; 1376 } 1377 1378 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1379 if (!pdrvextra_cmd_parm) { 1380 kfree(ph2c); 1381 res = _FAIL; 1382 goto exit; 1383 } 1384 1385 pdrvextra_cmd_parm->ec_id = DM_IN_LPS_WK_CID; 1386 pdrvextra_cmd_parm->type = 0; 1387 pdrvextra_cmd_parm->size = 0; 1388 pdrvextra_cmd_parm->pbuf = NULL; 1389 1390 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1391 1392 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1393 1394 exit: 1395 return res; 1396 } 1397 rtw_lps_change_dtim_hdl(struct adapter * padapter,u8 dtim)1398 static void rtw_lps_change_dtim_hdl(struct adapter *padapter, u8 dtim) 1399 { 1400 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); 1401 1402 if (dtim <= 0 || dtim > 16) 1403 return; 1404 1405 if (hal_btcoex_IsBtControlLps(padapter)) 1406 return; 1407 1408 mutex_lock(&pwrpriv->lock); 1409 1410 pwrpriv->dtim = dtim; 1411 1412 if (pwrpriv->fw_current_in_ps_mode && (pwrpriv->pwr_mode > PS_MODE_ACTIVE)) { 1413 u8 ps_mode = pwrpriv->pwr_mode; 1414 1415 rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); 1416 } 1417 1418 mutex_unlock(&pwrpriv->lock); 1419 } 1420 rtw_dm_ra_mask_hdl(struct adapter * padapter,struct sta_info * psta)1421 static void rtw_dm_ra_mask_hdl(struct adapter *padapter, struct sta_info *psta) 1422 { 1423 if (psta) 1424 set_sta_rate(padapter, psta); 1425 } 1426 rtw_dm_ra_mask_wk_cmd(struct adapter * padapter,u8 * psta)1427 u8 rtw_dm_ra_mask_wk_cmd(struct adapter *padapter, u8 *psta) 1428 { 1429 struct cmd_obj *ph2c; 1430 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1431 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1432 u8 res = _SUCCESS; 1433 1434 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 1435 if (!ph2c) { 1436 res = _FAIL; 1437 goto exit; 1438 } 1439 1440 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1441 if (!pdrvextra_cmd_parm) { 1442 kfree(ph2c); 1443 res = _FAIL; 1444 goto exit; 1445 } 1446 1447 pdrvextra_cmd_parm->ec_id = DM_RA_MSK_WK_CID; 1448 pdrvextra_cmd_parm->type = 0; 1449 pdrvextra_cmd_parm->size = 0; 1450 pdrvextra_cmd_parm->pbuf = psta; 1451 1452 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1453 1454 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1455 1456 exit: 1457 1458 return res; 1459 1460 } 1461 rtw_ps_cmd(struct adapter * padapter)1462 u8 rtw_ps_cmd(struct adapter *padapter) 1463 { 1464 struct cmd_obj *ppscmd; 1465 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1466 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1467 u8 res = _SUCCESS; 1468 ppscmd = rtw_zmalloc(sizeof(struct cmd_obj)); 1469 if (!ppscmd) { 1470 res = _FAIL; 1471 goto exit; 1472 } 1473 1474 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1475 if (!pdrvextra_cmd_parm) { 1476 kfree(ppscmd); 1477 res = _FAIL; 1478 goto exit; 1479 } 1480 1481 pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID; 1482 pdrvextra_cmd_parm->type = 0; 1483 pdrvextra_cmd_parm->size = 0; 1484 pdrvextra_cmd_parm->pbuf = NULL; 1485 init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1486 1487 res = rtw_enqueue_cmd(pcmdpriv, ppscmd); 1488 1489 exit: 1490 return res; 1491 } 1492 1493 u32 g_wait_hiq_empty; 1494 rtw_chk_hi_queue_hdl(struct adapter * padapter)1495 static void rtw_chk_hi_queue_hdl(struct adapter *padapter) 1496 { 1497 struct sta_info *psta_bmc; 1498 struct sta_priv *pstapriv = &padapter->stapriv; 1499 unsigned long start = jiffies; 1500 u8 empty = false; 1501 1502 psta_bmc = rtw_get_bcmc_stainfo(padapter); 1503 if (!psta_bmc) 1504 return; 1505 1506 rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty); 1507 1508 while (!empty && jiffies_to_msecs(jiffies - start) < g_wait_hiq_empty) { 1509 msleep(100); 1510 rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty); 1511 } 1512 1513 if (psta_bmc->sleepq_len == 0) { 1514 if (empty == _SUCCESS) { 1515 bool update_tim = false; 1516 1517 if (pstapriv->tim_bitmap & BIT(0)) 1518 update_tim = true; 1519 1520 pstapriv->tim_bitmap &= ~BIT(0); 1521 pstapriv->sta_dz_bitmap &= ~BIT(0); 1522 1523 if (update_tim) 1524 update_beacon(padapter, WLAN_EID_TIM, NULL, true); 1525 } else {/* re check again */ 1526 rtw_chk_hi_queue_cmd(padapter); 1527 } 1528 1529 } 1530 1531 } 1532 rtw_chk_hi_queue_cmd(struct adapter * padapter)1533 u8 rtw_chk_hi_queue_cmd(struct adapter *padapter) 1534 { 1535 struct cmd_obj *ph2c; 1536 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1537 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1538 u8 res = _SUCCESS; 1539 1540 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 1541 if (!ph2c) { 1542 res = _FAIL; 1543 goto exit; 1544 } 1545 1546 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1547 if (!pdrvextra_cmd_parm) { 1548 kfree(ph2c); 1549 res = _FAIL; 1550 goto exit; 1551 } 1552 1553 pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID; 1554 pdrvextra_cmd_parm->type = 0; 1555 pdrvextra_cmd_parm->size = 0; 1556 pdrvextra_cmd_parm->pbuf = NULL; 1557 1558 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1559 1560 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1561 1562 exit: 1563 return res; 1564 } 1565 1566 struct btinfo { 1567 u8 cid; 1568 u8 len; 1569 1570 u8 bConnection:1; 1571 u8 bSCOeSCO:1; 1572 u8 bInQPage:1; 1573 u8 bACLBusy:1; 1574 u8 bSCOBusy:1; 1575 u8 bHID:1; 1576 u8 bA2DP:1; 1577 u8 bFTP:1; 1578 1579 u8 retry_cnt:4; 1580 u8 rsvd_34:1; 1581 u8 rsvd_35:1; 1582 u8 rsvd_36:1; 1583 u8 rsvd_37:1; 1584 1585 u8 rssi; 1586 1587 u8 rsvd_50:1; 1588 u8 rsvd_51:1; 1589 u8 rsvd_52:1; 1590 u8 rsvd_53:1; 1591 u8 rsvd_54:1; 1592 u8 rsvd_55:1; 1593 u8 eSCO_SCO:1; 1594 u8 Master_Slave:1; 1595 1596 u8 rsvd_6; 1597 u8 rsvd_7; 1598 }; 1599 rtw_btinfo_hdl(struct adapter * adapter,u8 * buf,u16 buf_len)1600 static void rtw_btinfo_hdl(struct adapter *adapter, u8 *buf, u16 buf_len) 1601 { 1602 #define BTINFO_WIFI_FETCH 0x23 1603 #define BTINFO_BT_AUTO_RPT 0x27 1604 struct btinfo *info = (struct btinfo *)buf; 1605 u8 cmd_idx; 1606 u8 len; 1607 1608 cmd_idx = info->cid; 1609 1610 if (info->len > buf_len-2) { 1611 rtw_warn_on(1); 1612 len = buf_len-2; 1613 } else { 1614 len = info->len; 1615 } 1616 1617 /* transform BT-FW btinfo to WiFI-FW C2H format and notify */ 1618 if (cmd_idx == BTINFO_WIFI_FETCH) 1619 buf[1] = 0; 1620 else if (cmd_idx == BTINFO_BT_AUTO_RPT) 1621 buf[1] = 2; 1622 hal_btcoex_BtInfoNotify(adapter, len+1, &buf[1]); 1623 } 1624 rtw_c2h_packet_wk_cmd(struct adapter * padapter,u8 * pbuf,u16 length)1625 u8 rtw_c2h_packet_wk_cmd(struct adapter *padapter, u8 *pbuf, u16 length) 1626 { 1627 struct cmd_obj *ph2c; 1628 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1629 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1630 u8 res = _SUCCESS; 1631 1632 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 1633 if (!ph2c) { 1634 res = _FAIL; 1635 goto exit; 1636 } 1637 1638 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1639 if (!pdrvextra_cmd_parm) { 1640 kfree(ph2c); 1641 res = _FAIL; 1642 goto exit; 1643 } 1644 1645 pdrvextra_cmd_parm->ec_id = C2H_WK_CID; 1646 pdrvextra_cmd_parm->type = 0; 1647 pdrvextra_cmd_parm->size = length; 1648 pdrvextra_cmd_parm->pbuf = pbuf; 1649 1650 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1651 1652 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1653 1654 exit: 1655 return res; 1656 } 1657 1658 /* dont call R/W in this function, beucase SDIO interrupt have claim host */ 1659 /* or deadlock will happen and cause special-systemserver-died in android */ rtw_c2h_wk_cmd(struct adapter * padapter,u8 * c2h_evt)1660 u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt) 1661 { 1662 struct cmd_obj *ph2c; 1663 struct drvextra_cmd_parm *pdrvextra_cmd_parm; 1664 struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 1665 u8 res = _SUCCESS; 1666 1667 ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); 1668 if (!ph2c) { 1669 res = _FAIL; 1670 goto exit; 1671 } 1672 1673 pdrvextra_cmd_parm = rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 1674 if (!pdrvextra_cmd_parm) { 1675 kfree(ph2c); 1676 res = _FAIL; 1677 goto exit; 1678 } 1679 1680 pdrvextra_cmd_parm->ec_id = C2H_WK_CID; 1681 pdrvextra_cmd_parm->type = 0; 1682 pdrvextra_cmd_parm->size = c2h_evt?16:0; 1683 pdrvextra_cmd_parm->pbuf = c2h_evt; 1684 1685 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); 1686 1687 res = rtw_enqueue_cmd(pcmdpriv, ph2c); 1688 1689 exit: 1690 1691 return res; 1692 } 1693 c2h_wk_callback(struct work_struct * work)1694 static void c2h_wk_callback(struct work_struct *work) 1695 { 1696 struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk); 1697 struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv); 1698 u8 *c2h_evt; 1699 c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter); 1700 1701 evtpriv->c2h_wk_alive = true; 1702 1703 while (!rtw_cbuf_empty(evtpriv->c2h_queue)) { 1704 c2h_evt = (u8 *)rtw_cbuf_pop(evtpriv->c2h_queue); 1705 if (c2h_evt) { 1706 /* This C2H event is read, clear it */ 1707 c2h_evt_clear(adapter); 1708 } else { 1709 c2h_evt = rtw_malloc(16); 1710 if (c2h_evt) { 1711 /* This C2H event is not read, read & clear now */ 1712 if (c2h_evt_read_88xx(adapter, c2h_evt) != _SUCCESS) { 1713 kfree(c2h_evt); 1714 continue; 1715 } 1716 } 1717 } 1718 1719 /* Special pointer to trigger c2h_evt_clear only */ 1720 if ((void *)c2h_evt == (void *)evtpriv) 1721 continue; 1722 1723 if (!rtw_hal_c2h_valid(adapter, c2h_evt)) { 1724 kfree(c2h_evt); 1725 continue; 1726 } 1727 1728 if (ccx_id_filter(c2h_evt)) { 1729 /* Handle CCX report here */ 1730 rtw_hal_c2h_handler(adapter, c2h_evt); 1731 kfree(c2h_evt); 1732 } else { 1733 /* Enqueue into cmd_thread for others */ 1734 rtw_c2h_wk_cmd(adapter, c2h_evt); 1735 } 1736 } 1737 1738 evtpriv->c2h_wk_alive = false; 1739 } 1740 rtw_drvextra_cmd_hdl(struct adapter * padapter,unsigned char * pbuf)1741 u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf) 1742 { 1743 struct drvextra_cmd_parm *pdrvextra_cmd; 1744 1745 if (!pbuf) 1746 return H2C_PARAMETERS_ERROR; 1747 1748 pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf; 1749 1750 switch (pdrvextra_cmd->ec_id) { 1751 case DYNAMIC_CHK_WK_CID:/* only primary padapter go to this cmd, but execute dynamic_chk_wk_hdl() for two interfaces */ 1752 dynamic_chk_wk_hdl(padapter); 1753 break; 1754 case POWER_SAVING_CTRL_WK_CID: 1755 rtw_ps_processor(padapter); 1756 break; 1757 case LPS_CTRL_WK_CID: 1758 lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type); 1759 break; 1760 case DM_IN_LPS_WK_CID: 1761 rtw_dm_in_lps_hdl(padapter); 1762 break; 1763 case LPS_CHANGE_DTIM_CID: 1764 rtw_lps_change_dtim_hdl(padapter, (u8)pdrvextra_cmd->type); 1765 break; 1766 case CHECK_HIQ_WK_CID: 1767 rtw_chk_hi_queue_hdl(padapter); 1768 break; 1769 /* add for CONFIG_IEEE80211W, none 11w can use it */ 1770 case RESET_SECURITYPRIV: 1771 rtw_reset_securitypriv(padapter); 1772 break; 1773 case FREE_ASSOC_RESOURCES: 1774 rtw_free_assoc_resources(padapter, 1); 1775 break; 1776 case C2H_WK_CID: 1777 rtw_hal_set_hwreg_with_buf(padapter, HW_VAR_C2H_HANDLE, pdrvextra_cmd->pbuf, pdrvextra_cmd->size); 1778 break; 1779 case DM_RA_MSK_WK_CID: 1780 rtw_dm_ra_mask_hdl(padapter, (struct sta_info *)pdrvextra_cmd->pbuf); 1781 break; 1782 case BTINFO_WK_CID: 1783 rtw_btinfo_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->size); 1784 break; 1785 default: 1786 break; 1787 } 1788 1789 if (pdrvextra_cmd->pbuf && pdrvextra_cmd->size > 0) 1790 kfree(pdrvextra_cmd->pbuf); 1791 1792 return H2C_SUCCESS; 1793 } 1794 rtw_survey_cmd_callback(struct adapter * padapter,struct cmd_obj * pcmd)1795 void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) 1796 { 1797 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 1798 1799 if (pcmd->res != H2C_SUCCESS) { 1800 /* TODO: cancel timer and do timeout handler directly... */ 1801 _set_timer(&pmlmepriv->scan_to_timer, 1); 1802 } 1803 1804 /* free cmd */ 1805 rtw_free_cmd_obj(pcmd); 1806 } 1807 rtw_disassoc_cmd_callback(struct adapter * padapter,struct cmd_obj * pcmd)1808 void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) 1809 { 1810 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 1811 1812 if (pcmd->res != H2C_SUCCESS) { 1813 spin_lock_bh(&pmlmepriv->lock); 1814 set_fwstate(pmlmepriv, _FW_LINKED); 1815 spin_unlock_bh(&pmlmepriv->lock); 1816 1817 return; 1818 } 1819 /* free cmd */ 1820 rtw_free_cmd_obj(pcmd); 1821 } 1822 rtw_joinbss_cmd_callback(struct adapter * padapter,struct cmd_obj * pcmd)1823 void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) 1824 { 1825 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 1826 1827 if (pcmd->res != H2C_SUCCESS) { 1828 /* TODO: cancel timer and do timeout handler directly... */ 1829 _set_timer(&pmlmepriv->assoc_timer, 1); 1830 } 1831 1832 rtw_free_cmd_obj(pcmd); 1833 } 1834 rtw_createbss_cmd_callback(struct adapter * padapter,struct cmd_obj * pcmd)1835 void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) 1836 { 1837 struct sta_info *psta = NULL; 1838 struct wlan_network *pwlan = NULL; 1839 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 1840 struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf; 1841 struct wlan_network *tgt_network = &pmlmepriv->cur_network; 1842 1843 if (!pcmd->parmbuf) 1844 goto exit; 1845 1846 if (pcmd->res != H2C_SUCCESS) 1847 _set_timer(&pmlmepriv->assoc_timer, 1); 1848 1849 del_timer_sync(&pmlmepriv->assoc_timer); 1850 1851 spin_lock_bh(&pmlmepriv->lock); 1852 1853 1854 if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { 1855 psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->mac_address); 1856 if (!psta) { 1857 psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->mac_address); 1858 if (!psta) 1859 goto createbss_cmd_fail; 1860 } 1861 1862 rtw_indicate_connect(padapter); 1863 } else { 1864 pwlan = rtw_alloc_network(pmlmepriv); 1865 spin_lock_bh(&pmlmepriv->scanned_queue.lock); 1866 if (!pwlan) { 1867 pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue); 1868 if (!pwlan) { 1869 spin_unlock_bh(&pmlmepriv->scanned_queue.lock); 1870 goto createbss_cmd_fail; 1871 } 1872 pwlan->last_scanned = jiffies; 1873 } else { 1874 list_add_tail(&pwlan->list, &pmlmepriv->scanned_queue.queue); 1875 } 1876 1877 pnetwork->length = get_wlan_bssid_ex_sz(pnetwork); 1878 memcpy(&pwlan->network, pnetwork, pnetwork->length); 1879 /* pwlan->fixed = true; */ 1880 1881 /* list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); */ 1882 1883 /* copy pdev_network information to pmlmepriv->cur_network */ 1884 memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork))); 1885 1886 _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); 1887 1888 spin_unlock_bh(&pmlmepriv->scanned_queue.lock); 1889 /* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */ 1890 1891 } 1892 1893 createbss_cmd_fail: 1894 1895 spin_unlock_bh(&pmlmepriv->lock); 1896 exit: 1897 rtw_free_cmd_obj(pcmd); 1898 } 1899 rtw_setstaKey_cmdrsp_callback(struct adapter * padapter,struct cmd_obj * pcmd)1900 void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) 1901 { 1902 struct sta_priv *pstapriv = &padapter->stapriv; 1903 struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp); 1904 struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr); 1905 1906 if (!psta) 1907 goto exit; 1908 1909 exit: 1910 rtw_free_cmd_obj(pcmd); 1911 } 1912 rtw_setassocsta_cmdrsp_callback(struct adapter * padapter,struct cmd_obj * pcmd)1913 void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) 1914 { 1915 struct sta_priv *pstapriv = &padapter->stapriv; 1916 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 1917 struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf); 1918 struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp); 1919 struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr); 1920 1921 if (!psta) 1922 goto exit; 1923 1924 psta->aid = passocsta_rsp->cam_id; 1925 psta->mac_id = passocsta_rsp->cam_id; 1926 1927 spin_lock_bh(&pmlmepriv->lock); 1928 1929 if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) 1930 _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); 1931 1932 set_fwstate(pmlmepriv, _FW_LINKED); 1933 spin_unlock_bh(&pmlmepriv->lock); 1934 1935 exit: 1936 rtw_free_cmd_obj(pcmd); 1937 } 1938