1e24c1f86SMichael Straube // SPDX-License-Identifier: GPL-2.0 22865d42cSLarry Finger /****************************************************************************** 32865d42cSLarry Finger * rtl8712_cmd.c 42865d42cSLarry Finger * 52865d42cSLarry Finger * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 62865d42cSLarry Finger * Linux device driver for RTL8192SU 72865d42cSLarry Finger * 82865d42cSLarry Finger * Modifications for inclusion into the Linux staging tree are 92865d42cSLarry Finger * Copyright(c) 2010 Larry Finger. All rights reserved. 102865d42cSLarry Finger * 112865d42cSLarry Finger * Contact information: 122865d42cSLarry Finger * WLAN FAE <wlanfae@realtek.com>. 132865d42cSLarry Finger * Larry Finger <Larry.Finger@lwfinger.net> 142865d42cSLarry Finger * 152865d42cSLarry Finger ******************************************************************************/ 162865d42cSLarry Finger 172865d42cSLarry Finger #define _RTL8712_CMD_C_ 182865d42cSLarry Finger 19359140aaSAli Bahar #include <linux/compiler.h> 20359140aaSAli Bahar #include <linux/kernel.h> 21359140aaSAli Bahar #include <linux/errno.h> 22359140aaSAli Bahar #include <linux/slab.h> 233f07c014SIngo Molnar #include <linux/sched/signal.h> 24359140aaSAli Bahar #include <linux/module.h> 25359140aaSAli Bahar #include <linux/kref.h> 26359140aaSAli Bahar #include <linux/netdevice.h> 27359140aaSAli Bahar #include <linux/skbuff.h> 28359140aaSAli Bahar #include <linux/usb.h> 29359140aaSAli Bahar #include <linux/usb/ch9.h> 30359140aaSAli Bahar #include <linux/circ_buf.h> 31359140aaSAli Bahar #include <linux/uaccess.h> 32359140aaSAli Bahar #include <asm/byteorder.h> 33359140aaSAli Bahar #include <linux/atomic.h> 34359140aaSAli Bahar #include <linux/semaphore.h> 35359140aaSAli Bahar #include <linux/rtnetlink.h> 36359140aaSAli Bahar 372865d42cSLarry Finger #include "osdep_service.h" 382865d42cSLarry Finger #include "drv_types.h" 392865d42cSLarry Finger #include "recv_osdep.h" 402865d42cSLarry Finger #include "mlme_osdep.h" 412865d42cSLarry Finger #include "rtl871x_ioctl_set.h" 422865d42cSLarry Finger 432865d42cSLarry Finger static void check_hw_pbc(struct _adapter *padapter) 442865d42cSLarry Finger { 452865d42cSLarry Finger u8 tmp1byte; 462865d42cSLarry Finger 472865d42cSLarry Finger r8712_write8(padapter, MAC_PINMUX_CTRL, (GPIOMUX_EN | GPIOSEL_GPIO)); 482865d42cSLarry Finger tmp1byte = r8712_read8(padapter, GPIO_IO_SEL); 492865d42cSLarry Finger tmp1byte &= ~(HAL_8192S_HW_GPIO_WPS_BIT); 502865d42cSLarry Finger r8712_write8(padapter, GPIO_IO_SEL, tmp1byte); 512865d42cSLarry Finger tmp1byte = r8712_read8(padapter, GPIO_CTRL); 522865d42cSLarry Finger if (tmp1byte == 0xff) 532865d42cSLarry Finger return; 542865d42cSLarry Finger if (tmp1byte & HAL_8192S_HW_GPIO_WPS_BIT) { 552865d42cSLarry Finger /* Here we only set bPbcPressed to true 56ed9c838aSPunit Vara * After trigger PBC, the variable will be set to false 57ed9c838aSPunit Vara */ 582865d42cSLarry Finger DBG_8712("CheckPbcGPIO - PBC is pressed !!!!\n"); 592865d42cSLarry Finger /* 0 is the default value and it means the application monitors 60ed9c838aSPunit Vara * the HW PBC doesn't provide its pid to driver. 61ed9c838aSPunit Vara */ 622865d42cSLarry Finger if (padapter->pid == 0) 632865d42cSLarry Finger return; 642865d42cSLarry Finger kill_pid(find_vpid(padapter->pid), SIGUSR1, 1); 652865d42cSLarry Finger } 662865d42cSLarry Finger } 672865d42cSLarry Finger 682865d42cSLarry Finger /* query rx phy status from fw. 692865d42cSLarry Finger * Adhoc mode: beacon. 70ed9c838aSPunit Vara * Infrastructure mode: beacon , data. 71ed9c838aSPunit Vara */ 722865d42cSLarry Finger static void query_fw_rx_phy_status(struct _adapter *padapter) 732865d42cSLarry Finger { 742865d42cSLarry Finger u32 val32 = 0; 752865d42cSLarry Finger int pollingcnts = 50; 762865d42cSLarry Finger 771ca96884SLuis de Bethencourt if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { 782865d42cSLarry Finger r8712_write32(padapter, IOCMD_CTRL_REG, 0xf4000001); 792865d42cSLarry Finger msleep(100); 802865d42cSLarry Finger /* Wait FW complete IO Cmd */ 812865d42cSLarry Finger while ((r8712_read32(padapter, IOCMD_CTRL_REG)) && 822865d42cSLarry Finger (pollingcnts > 0)) { 832865d42cSLarry Finger pollingcnts--; 842865d42cSLarry Finger msleep(20); 852865d42cSLarry Finger } 862865d42cSLarry Finger if (pollingcnts != 0) 872865d42cSLarry Finger val32 = r8712_read32(padapter, IOCMD_DATA_REG); 882865d42cSLarry Finger else /* time out */ 892865d42cSLarry Finger val32 = 0; 90ae52e527SAya Mahfouz val32 >>= 4; 912865d42cSLarry Finger padapter->recvpriv.fw_rssi = 922865d42cSLarry Finger (u8)r8712_signal_scale_mapping(val32); 932865d42cSLarry Finger } 942865d42cSLarry Finger } 952865d42cSLarry Finger 962865d42cSLarry Finger /* check mlme, hw, phy, or dynamic algorithm status. */ 972865d42cSLarry Finger static void StatusWatchdogCallback(struct _adapter *padapter) 982865d42cSLarry Finger { 992865d42cSLarry Finger check_hw_pbc(padapter); 1002865d42cSLarry Finger query_fw_rx_phy_status(padapter); 1012865d42cSLarry Finger } 1022865d42cSLarry Finger 1032865d42cSLarry Finger static void r871x_internal_cmd_hdl(struct _adapter *padapter, u8 *pbuf) 1042865d42cSLarry Finger { 1052865d42cSLarry Finger struct drvint_cmd_parm *pdrvcmd; 1062865d42cSLarry Finger 1072865d42cSLarry Finger if (!pbuf) 1082865d42cSLarry Finger return; 1092865d42cSLarry Finger pdrvcmd = (struct drvint_cmd_parm *)pbuf; 1102865d42cSLarry Finger switch (pdrvcmd->i_cid) { 1112865d42cSLarry Finger case WDG_WK_CID: 1122865d42cSLarry Finger StatusWatchdogCallback(padapter); 1132865d42cSLarry Finger break; 1142865d42cSLarry Finger default: 1152865d42cSLarry Finger break; 1162865d42cSLarry Finger } 1172865d42cSLarry Finger kfree(pdrvcmd->pbuf); 1182865d42cSLarry Finger } 1192865d42cSLarry Finger 1202865d42cSLarry Finger static u8 read_macreg_hdl(struct _adapter *padapter, u8 *pbuf) 1212865d42cSLarry Finger { 1222865d42cSLarry Finger void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); 1232865d42cSLarry Finger struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; 1242865d42cSLarry Finger 1252865d42cSLarry Finger /* invoke cmd->callback function */ 1262865d42cSLarry Finger pcmd_callback = cmd_callback[pcmd->cmdcode].callback; 1277fcf92c0SJuliana Rodrigues if (!pcmd_callback) 1282865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 1292865d42cSLarry Finger else 1302865d42cSLarry Finger pcmd_callback(padapter, pcmd); 1312865d42cSLarry Finger return H2C_SUCCESS; 1322865d42cSLarry Finger } 1332865d42cSLarry Finger 1342865d42cSLarry Finger static u8 write_macreg_hdl(struct _adapter *padapter, u8 *pbuf) 1352865d42cSLarry Finger { 1362865d42cSLarry Finger void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); 1372865d42cSLarry Finger struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; 1382865d42cSLarry Finger 1392865d42cSLarry Finger /* invoke cmd->callback function */ 1402865d42cSLarry Finger pcmd_callback = cmd_callback[pcmd->cmdcode].callback; 1417fcf92c0SJuliana Rodrigues if (!pcmd_callback) 1422865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 1432865d42cSLarry Finger else 1442865d42cSLarry Finger pcmd_callback(padapter, pcmd); 1452865d42cSLarry Finger return H2C_SUCCESS; 1462865d42cSLarry Finger } 1472865d42cSLarry Finger 1482865d42cSLarry Finger static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf) 1492865d42cSLarry Finger { 1502865d42cSLarry Finger u32 val; 1512865d42cSLarry Finger void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); 1522865d42cSLarry Finger struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; 1532865d42cSLarry Finger 1542865d42cSLarry Finger if (pcmd->rsp && pcmd->rspsz > 0) 1552865d42cSLarry Finger memcpy(pcmd->rsp, (u8 *)&val, pcmd->rspsz); 1562865d42cSLarry Finger pcmd_callback = cmd_callback[pcmd->cmdcode].callback; 1577fcf92c0SJuliana Rodrigues if (!pcmd_callback) 1582865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 1592865d42cSLarry Finger else 1602865d42cSLarry Finger pcmd_callback(padapter, pcmd); 1612865d42cSLarry Finger return H2C_SUCCESS; 1622865d42cSLarry Finger } 1632865d42cSLarry Finger 1642865d42cSLarry Finger static u8 write_bbreg_hdl(struct _adapter *padapter, u8 *pbuf) 1652865d42cSLarry Finger { 1662865d42cSLarry Finger void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); 1672865d42cSLarry Finger struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; 1682865d42cSLarry Finger 1692865d42cSLarry Finger pcmd_callback = cmd_callback[pcmd->cmdcode].callback; 1707fcf92c0SJuliana Rodrigues if (!pcmd_callback) 1712865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 1722865d42cSLarry Finger else 1732865d42cSLarry Finger pcmd_callback(padapter, pcmd); 1742865d42cSLarry Finger return H2C_SUCCESS; 1752865d42cSLarry Finger } 1762865d42cSLarry Finger 1772865d42cSLarry Finger static u8 read_rfreg_hdl(struct _adapter *padapter, u8 *pbuf) 1782865d42cSLarry Finger { 1792865d42cSLarry Finger u32 val; 1802865d42cSLarry Finger void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); 1812865d42cSLarry Finger struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; 1822865d42cSLarry Finger 1832865d42cSLarry Finger if (pcmd->rsp && pcmd->rspsz > 0) 1842865d42cSLarry Finger memcpy(pcmd->rsp, (u8 *)&val, pcmd->rspsz); 1852865d42cSLarry Finger pcmd_callback = cmd_callback[pcmd->cmdcode].callback; 1867fcf92c0SJuliana Rodrigues if (!pcmd_callback) 1872865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 1882865d42cSLarry Finger else 1892865d42cSLarry Finger pcmd_callback(padapter, pcmd); 1902865d42cSLarry Finger return H2C_SUCCESS; 1912865d42cSLarry Finger } 1922865d42cSLarry Finger 1932865d42cSLarry Finger static u8 write_rfreg_hdl(struct _adapter *padapter, u8 *pbuf) 1942865d42cSLarry Finger { 1952865d42cSLarry Finger void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); 1962865d42cSLarry Finger struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; 1972865d42cSLarry Finger 1982865d42cSLarry Finger pcmd_callback = cmd_callback[pcmd->cmdcode].callback; 1997fcf92c0SJuliana Rodrigues if (!pcmd_callback) 2002865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 2012865d42cSLarry Finger else 2022865d42cSLarry Finger pcmd_callback(padapter, pcmd); 2032865d42cSLarry Finger return H2C_SUCCESS; 2042865d42cSLarry Finger } 2052865d42cSLarry Finger 2062865d42cSLarry Finger static u8 sys_suspend_hdl(struct _adapter *padapter, u8 *pbuf) 2072865d42cSLarry Finger { 2082865d42cSLarry Finger struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; 2092865d42cSLarry Finger 2102865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 2112865d42cSLarry Finger return H2C_SUCCESS; 2122865d42cSLarry Finger } 2132865d42cSLarry Finger 2142865d42cSLarry Finger static struct cmd_obj *cmd_hdl_filter(struct _adapter *padapter, 2152865d42cSLarry Finger struct cmd_obj *pcmd) 2162865d42cSLarry Finger { 2172865d42cSLarry Finger struct cmd_obj *pcmd_r; 2182865d42cSLarry Finger 2197fcf92c0SJuliana Rodrigues if (!pcmd) 2202865d42cSLarry Finger return pcmd; 2212865d42cSLarry Finger pcmd_r = NULL; 2222865d42cSLarry Finger 2232865d42cSLarry Finger switch (pcmd->cmdcode) { 2242865d42cSLarry Finger case GEN_CMD_CODE(_Read_MACREG): 2252865d42cSLarry Finger read_macreg_hdl(padapter, (u8 *)pcmd); 2262865d42cSLarry Finger pcmd_r = pcmd; 2272865d42cSLarry Finger break; 2282865d42cSLarry Finger case GEN_CMD_CODE(_Write_MACREG): 2292865d42cSLarry Finger write_macreg_hdl(padapter, (u8 *)pcmd); 2302865d42cSLarry Finger pcmd_r = pcmd; 2312865d42cSLarry Finger break; 2322865d42cSLarry Finger case GEN_CMD_CODE(_Read_BBREG): 2332865d42cSLarry Finger read_bbreg_hdl(padapter, (u8 *)pcmd); 2342865d42cSLarry Finger break; 2352865d42cSLarry Finger case GEN_CMD_CODE(_Write_BBREG): 2362865d42cSLarry Finger write_bbreg_hdl(padapter, (u8 *)pcmd); 2372865d42cSLarry Finger break; 2382865d42cSLarry Finger case GEN_CMD_CODE(_Read_RFREG): 2392865d42cSLarry Finger read_rfreg_hdl(padapter, (u8 *)pcmd); 2402865d42cSLarry Finger break; 2412865d42cSLarry Finger case GEN_CMD_CODE(_Write_RFREG): 2422865d42cSLarry Finger write_rfreg_hdl(padapter, (u8 *)pcmd); 2432865d42cSLarry Finger break; 2442865d42cSLarry Finger case GEN_CMD_CODE(_SetUsbSuspend): 2452865d42cSLarry Finger sys_suspend_hdl(padapter, (u8 *)pcmd); 2462865d42cSLarry Finger break; 2472865d42cSLarry Finger case GEN_CMD_CODE(_JoinBss): 2482865d42cSLarry Finger r8712_joinbss_reset(padapter); 2492865d42cSLarry Finger /* Before set JoinBss_CMD to FW, driver must ensure FW is in 2502865d42cSLarry Finger * PS_MODE_ACTIVE. Directly write rpwm to radio on and assign 2512865d42cSLarry Finger * new pwr_mode to Driver, instead of use workitem to change 252ed9c838aSPunit Vara * state. 253ed9c838aSPunit Vara */ 2542865d42cSLarry Finger if (padapter->pwrctrlpriv.pwr_mode > PS_MODE_ACTIVE) { 2552865d42cSLarry Finger padapter->pwrctrlpriv.pwr_mode = PS_MODE_ACTIVE; 2565c2ba8b8SBinoy Jayan mutex_lock(&padapter->pwrctrlpriv.mutex_lock); 2572865d42cSLarry Finger r8712_set_rpwm(padapter, PS_STATE_S4); 2585c2ba8b8SBinoy Jayan mutex_unlock(&padapter->pwrctrlpriv.mutex_lock); 2592865d42cSLarry Finger } 2602865d42cSLarry Finger pcmd_r = pcmd; 2612865d42cSLarry Finger break; 2622865d42cSLarry Finger case _DRV_INT_CMD_: 2632865d42cSLarry Finger r871x_internal_cmd_hdl(padapter, pcmd->parmbuf); 2642865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 2652865d42cSLarry Finger pcmd_r = NULL; 2662865d42cSLarry Finger break; 2672865d42cSLarry Finger default: 2682865d42cSLarry Finger pcmd_r = pcmd; 2692865d42cSLarry Finger break; 2702865d42cSLarry Finger } 2712865d42cSLarry Finger return pcmd_r; /* if returning pcmd_r == NULL, pcmd must be free. */ 2722865d42cSLarry Finger } 2732865d42cSLarry Finger 2742865d42cSLarry Finger static u8 check_cmd_fifo(struct _adapter *padapter, uint sz) 2752865d42cSLarry Finger { 2768ffca9eaSPeter Senna Tschudin return _SUCCESS; 2772865d42cSLarry Finger } 2782865d42cSLarry Finger 2792865d42cSLarry Finger u8 r8712_fw_cmd(struct _adapter *pAdapter, u32 cmd) 2802865d42cSLarry Finger { 2812865d42cSLarry Finger int pollingcnts = 50; 2822865d42cSLarry Finger 2832865d42cSLarry Finger r8712_write32(pAdapter, IOCMD_CTRL_REG, cmd); 2842865d42cSLarry Finger msleep(100); 28597e2ba90SRakhi Sharma while ((r8712_read32(pAdapter, IOCMD_CTRL_REG != 0)) && 2862865d42cSLarry Finger (pollingcnts > 0)) { 2872865d42cSLarry Finger pollingcnts--; 2882865d42cSLarry Finger msleep(20); 2892865d42cSLarry Finger } 2902865d42cSLarry Finger if (pollingcnts == 0) 2912865d42cSLarry Finger return false; 2922865d42cSLarry Finger return true; 2932865d42cSLarry Finger } 2942865d42cSLarry Finger 2952865d42cSLarry Finger void r8712_fw_cmd_data(struct _adapter *pAdapter, u32 *value, u8 flag) 2962865d42cSLarry Finger { 2972865d42cSLarry Finger if (flag == 0) /* set */ 2982865d42cSLarry Finger r8712_write32(pAdapter, IOCMD_DATA_REG, *value); 2992865d42cSLarry Finger else /* query */ 3002865d42cSLarry Finger *value = r8712_read32(pAdapter, IOCMD_DATA_REG); 3012865d42cSLarry Finger } 3022865d42cSLarry Finger 3032865d42cSLarry Finger int r8712_cmd_thread(void *context) 3042865d42cSLarry Finger { 3052865d42cSLarry Finger struct cmd_obj *pcmd; 306e8cd841bSJannik Becher unsigned int cmdsz, wr_sz; 307e8cd841bSJannik Becher __le32 *pcmdbuf; 3082865d42cSLarry Finger struct tx_desc *pdesc; 3092865d42cSLarry Finger void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); 31056238e45SBhaktipriya Shridhar struct _adapter *padapter = context; 311500320b7SArushi Singhal struct cmd_priv *pcmdpriv = &padapter->cmdpriv; 3123be4fdf6SMartin Homuth struct completion *cmd_queue_comp = 3133be4fdf6SMartin Homuth &pcmdpriv->cmd_queue_comp; 3143be4fdf6SMartin Homuth struct mutex *pwctrl_lock = &padapter->pwrctrlpriv.mutex_lock; 3152865d42cSLarry Finger 316fee51243SJames A Shackleford allow_signal(SIGTERM); 3172865d42cSLarry Finger while (1) { 3183be4fdf6SMartin Homuth if (wait_for_completion_interruptible(cmd_queue_comp)) 3192865d42cSLarry Finger break; 3200ec6fc6fSHimadri Pandya if (padapter->driver_stopped || padapter->bSurpriseRemoved) 3212865d42cSLarry Finger break; 3222865d42cSLarry Finger if (r8712_register_cmd_alive(padapter) != _SUCCESS) 3232865d42cSLarry Finger continue; 3242865d42cSLarry Finger _next: 325500320b7SArushi Singhal pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue); 3262865d42cSLarry Finger if (!(pcmd)) { 3272865d42cSLarry Finger r8712_unregister_cmd_alive(padapter); 3282865d42cSLarry Finger continue; 3292865d42cSLarry Finger } 330e8cd841bSJannik Becher pcmdbuf = (__le32 *)pcmdpriv->cmd_buf; 3312865d42cSLarry Finger pdesc = (struct tx_desc *)pcmdbuf; 3322865d42cSLarry Finger memset(pdesc, 0, TXDESC_SIZE); 3332865d42cSLarry Finger pcmd = cmd_hdl_filter(padapter, pcmd); 3342865d42cSLarry Finger if (pcmd) { /* if pcmd != NULL, cmd will be handled by f/w */ 335adc08cc4SShivani Bhardwaj struct dvobj_priv *pdvobj = &padapter->dvobjpriv; 3362865d42cSLarry Finger u8 blnPending = 0; 3373be4fdf6SMartin Homuth u16 cmdcode = pcmd->cmdcode; 33802a29d2dSTapasweni Pathak 3392865d42cSLarry Finger pcmdpriv->cmd_issued_cnt++; 340d913e54eSJames A Shackleford cmdsz = round_up(pcmd->cmdsz, 8); 3412865d42cSLarry Finger wr_sz = TXDESC_SIZE + 8 + cmdsz; 3422865d42cSLarry Finger pdesc->txdw0 |= cpu_to_le32((wr_sz - TXDESC_SIZE) & 3432865d42cSLarry Finger 0x0000ffff); 3442865d42cSLarry Finger if (pdvobj->ishighspeed) { 3452865d42cSLarry Finger if ((wr_sz % 512) == 0) 3462865d42cSLarry Finger blnPending = 1; 3472865d42cSLarry Finger } else { 3482865d42cSLarry Finger if ((wr_sz % 64) == 0) 3492865d42cSLarry Finger blnPending = 1; 3502865d42cSLarry Finger } 351a7e58591SLiam Ryan if (blnPending) { /* 32 bytes for TX Desc - 8 offset */ 3522865d42cSLarry Finger pdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + 3532865d42cSLarry Finger OFFSET_SZ + 8) << OFFSET_SHT) & 3542865d42cSLarry Finger 0x00ff0000); 355a7e58591SLiam Ryan } else { 3562865d42cSLarry Finger pdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + 3572865d42cSLarry Finger OFFSET_SZ) << 3582865d42cSLarry Finger OFFSET_SHT) & 3592865d42cSLarry Finger 0x00ff0000); 3602865d42cSLarry Finger } 3612865d42cSLarry Finger pdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); 3622865d42cSLarry Finger pdesc->txdw1 |= cpu_to_le32((0x13 << QSEL_SHT) & 3632865d42cSLarry Finger 0x00001f00); 3642865d42cSLarry Finger pcmdbuf += (TXDESC_SIZE >> 2); 3652865d42cSLarry Finger *pcmdbuf = cpu_to_le32((cmdsz & 0x0000ffff) | 3662865d42cSLarry Finger (pcmd->cmdcode << 16) | 3672865d42cSLarry Finger (pcmdpriv->cmd_seq << 24)); 368be10ac2bSJustin P. Mattock pcmdbuf += 2; /* 8 bytes alignment */ 3692865d42cSLarry Finger memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); 3702865d42cSLarry Finger while (check_cmd_fifo(padapter, wr_sz) == _FAIL) { 3710ec6fc6fSHimadri Pandya if (padapter->driver_stopped || 3721ca96884SLuis de Bethencourt padapter->bSurpriseRemoved) 3732865d42cSLarry Finger break; 3742865d42cSLarry Finger msleep(100); 3752865d42cSLarry Finger continue; 3762865d42cSLarry Finger } 3772865d42cSLarry Finger if (blnPending) 3782865d42cSLarry Finger wr_sz += 8; /* Append 8 bytes */ 3792865d42cSLarry Finger r8712_write_mem(padapter, RTL8712_DMA_H2CCMD, wr_sz, 3802865d42cSLarry Finger (u8 *)pdesc); 3812865d42cSLarry Finger pcmdpriv->cmd_seq++; 3823be4fdf6SMartin Homuth if (cmdcode == GEN_CMD_CODE(_CreateBss)) { 3832865d42cSLarry Finger pcmd->res = H2C_SUCCESS; 3843be4fdf6SMartin Homuth pcmd_callback = cmd_callback[cmdcode].callback; 3852865d42cSLarry Finger if (pcmd_callback) 3862865d42cSLarry Finger pcmd_callback(padapter, pcmd); 3872865d42cSLarry Finger continue; 3882865d42cSLarry Finger } 3893be4fdf6SMartin Homuth if (cmdcode == GEN_CMD_CODE(_SetPwrMode)) { 3902865d42cSLarry Finger if (padapter->pwrctrlpriv.bSleep) { 3913be4fdf6SMartin Homuth mutex_lock(pwctrl_lock); 3922865d42cSLarry Finger r8712_set_rpwm(padapter, PS_STATE_S2); 3933be4fdf6SMartin Homuth mutex_unlock(pwctrl_lock); 3942865d42cSLarry Finger } 3952865d42cSLarry Finger } 3962865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 397df353f61SJames A Shackleford if (list_empty(&pcmdpriv->cmd_queue.queue)) { 3982865d42cSLarry Finger r8712_unregister_cmd_alive(padapter); 3992865d42cSLarry Finger continue; 400168a2c10SLuis de Bethencourt } else { 4012865d42cSLarry Finger goto _next; 402168a2c10SLuis de Bethencourt } 403168a2c10SLuis de Bethencourt } else { 4042865d42cSLarry Finger goto _next; 405168a2c10SLuis de Bethencourt } 4062865d42cSLarry Finger flush_signals_thread(); 4072865d42cSLarry Finger } 4082865d42cSLarry Finger /* free all cmd_obj resources */ 4092865d42cSLarry Finger do { 410500320b7SArushi Singhal pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue); 4117fcf92c0SJuliana Rodrigues if (!pcmd) 4122865d42cSLarry Finger break; 4132865d42cSLarry Finger r8712_free_cmd_obj(pcmd); 4142865d42cSLarry Finger } while (1); 415204a8ac1SBinoy Jayan complete(&pcmdpriv->terminate_cmdthread_comp); 4162865d42cSLarry Finger thread_exit(); 4172865d42cSLarry Finger } 4182865d42cSLarry Finger 419bcb91a5cSJannik Becher void r8712_event_handle(struct _adapter *padapter, __le32 *peventbuf) 4202865d42cSLarry Finger { 4212865d42cSLarry Finger u8 evt_code, evt_seq; 4222865d42cSLarry Finger u16 evt_sz; 4232865d42cSLarry Finger void (*event_callback)(struct _adapter *dev, u8 *pbuf); 424500320b7SArushi Singhal struct evt_priv *pevt_priv = &padapter->evtpriv; 4252865d42cSLarry Finger 4267fcf92c0SJuliana Rodrigues if (!peventbuf) 4272865d42cSLarry Finger goto _abort_event_; 4282865d42cSLarry Finger evt_sz = (u16)(le32_to_cpu(*peventbuf) & 0xffff); 4292865d42cSLarry Finger evt_seq = (u8)((le32_to_cpu(*peventbuf) >> 24) & 0x7f); 4302865d42cSLarry Finger evt_code = (u8)((le32_to_cpu(*peventbuf) >> 16) & 0xff); 4312865d42cSLarry Finger /* checking event sequence... */ 4322865d42cSLarry Finger if ((evt_seq & 0x7f) != pevt_priv->event_seq) { 4332865d42cSLarry Finger pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); 4342865d42cSLarry Finger goto _abort_event_; 4352865d42cSLarry Finger } 4362865d42cSLarry Finger /* checking if event code is valid */ 4372865d42cSLarry Finger if (evt_code >= MAX_C2HEVT) { 4382865d42cSLarry Finger pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); 4392865d42cSLarry Finger goto _abort_event_; 4402865d42cSLarry Finger } else if ((evt_code == GEN_EVT_CODE(_Survey)) && 4412865d42cSLarry Finger (evt_sz > sizeof(struct wlan_bssid_ex))) { 4422865d42cSLarry Finger pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); 4432865d42cSLarry Finger goto _abort_event_; 4442865d42cSLarry Finger } 4452865d42cSLarry Finger /* checking if event size match the event parm size */ 4462865d42cSLarry Finger if ((wlanevents[evt_code].parmsize) && 4472865d42cSLarry Finger (wlanevents[evt_code].parmsize != evt_sz)) { 4482865d42cSLarry Finger pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); 4492865d42cSLarry Finger goto _abort_event_; 4502865d42cSLarry Finger } else if ((evt_sz == 0) && (evt_code != GEN_EVT_CODE(_WPS_PBC))) { 4512865d42cSLarry Finger pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); 4522865d42cSLarry Finger goto _abort_event_; 4532865d42cSLarry Finger } 4542865d42cSLarry Finger pevt_priv->event_seq++; /* update evt_seq */ 4552865d42cSLarry Finger if (pevt_priv->event_seq > 127) 4562865d42cSLarry Finger pevt_priv->event_seq = 0; 45757b6686eSTapasweni Pathak /* move to event content, 8 bytes alignment */ 45857b6686eSTapasweni Pathak peventbuf = peventbuf + 2; 4592865d42cSLarry Finger event_callback = wlanevents[evt_code].event_callback; 4602865d42cSLarry Finger if (event_callback) 4612865d42cSLarry Finger event_callback(padapter, (u8 *)peventbuf); 4622865d42cSLarry Finger pevt_priv->evt_done_cnt++; 4632865d42cSLarry Finger _abort_event_: 4642865d42cSLarry Finger return; 4652865d42cSLarry Finger } 466