cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rtl8712_cmd.c (12278B)


      1// SPDX-License-Identifier: GPL-2.0
      2/******************************************************************************
      3 * rtl8712_cmd.c
      4 *
      5 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
      6 * Linux device driver for RTL8192SU
      7 *
      8 * Modifications for inclusion into the Linux staging tree are
      9 * Copyright(c) 2010 Larry Finger. All rights reserved.
     10 *
     11 * Contact information:
     12 * WLAN FAE <wlanfae@realtek.com>.
     13 * Larry Finger <Larry.Finger@lwfinger.net>
     14 *
     15 ******************************************************************************/
     16
     17#define _RTL8712_CMD_C_
     18
     19#include <linux/compiler.h>
     20#include <linux/kernel.h>
     21#include <linux/errno.h>
     22#include <linux/slab.h>
     23#include <linux/sched/signal.h>
     24#include <linux/module.h>
     25#include <linux/kref.h>
     26#include <linux/netdevice.h>
     27#include <linux/skbuff.h>
     28#include <linux/usb.h>
     29#include <linux/usb/ch9.h>
     30#include <linux/circ_buf.h>
     31#include <linux/uaccess.h>
     32#include <asm/byteorder.h>
     33#include <linux/atomic.h>
     34#include <linux/semaphore.h>
     35#include <linux/rtnetlink.h>
     36
     37#include "osdep_service.h"
     38#include "drv_types.h"
     39#include "recv_osdep.h"
     40#include "mlme_osdep.h"
     41#include "rtl871x_ioctl_set.h"
     42
     43static void check_hw_pbc(struct _adapter *padapter)
     44{
     45	u8	tmp1byte;
     46
     47	r8712_write8(padapter, MAC_PINMUX_CTRL, (GPIOMUX_EN | GPIOSEL_GPIO));
     48	tmp1byte = r8712_read8(padapter, GPIO_IO_SEL);
     49	tmp1byte &= ~(HAL_8192S_HW_GPIO_WPS_BIT);
     50	r8712_write8(padapter, GPIO_IO_SEL, tmp1byte);
     51	tmp1byte = r8712_read8(padapter, GPIO_CTRL);
     52	if (tmp1byte == 0xff)
     53		return;
     54	if (tmp1byte & HAL_8192S_HW_GPIO_WPS_BIT) {
     55		/* Here we only set bPbcPressed to true
     56		 * After trigger PBC, the variable will be set to false
     57		 */
     58		netdev_dbg(padapter->pnetdev, "CheckPbcGPIO - PBC is pressed !!!!\n");
     59		/* 0 is the default value and it means the application monitors
     60		 * the HW PBC doesn't provide its pid to driver.
     61		 */
     62		if (padapter->pid == 0)
     63			return;
     64		kill_pid(find_vpid(padapter->pid), SIGUSR1, 1);
     65	}
     66}
     67
     68/* query rx phy status from fw.
     69 * Adhoc mode: beacon.
     70 * Infrastructure mode: beacon , data.
     71 */
     72static void query_fw_rx_phy_status(struct _adapter *padapter)
     73{
     74	u32 val32 = 0;
     75	int pollingcnts = 50;
     76
     77	if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
     78		r8712_write32(padapter, IOCMD_CTRL_REG, 0xf4000001);
     79		msleep(100);
     80		/* Wait FW complete IO Cmd */
     81		while ((r8712_read32(padapter, IOCMD_CTRL_REG)) &&
     82		       (pollingcnts > 0)) {
     83			pollingcnts--;
     84			msleep(20);
     85		}
     86		if (pollingcnts != 0)
     87			val32 = r8712_read32(padapter, IOCMD_DATA_REG);
     88		else /* time out */
     89			val32 = 0;
     90		val32 >>= 4;
     91		padapter->recvpriv.fw_rssi =
     92			 (u8)r8712_signal_scale_mapping(val32);
     93	}
     94}
     95
     96/* check mlme, hw, phy, or dynamic algorithm status. */
     97static void StatusWatchdogCallback(struct _adapter *padapter)
     98{
     99	check_hw_pbc(padapter);
    100	query_fw_rx_phy_status(padapter);
    101}
    102
    103static void r871x_internal_cmd_hdl(struct _adapter *padapter, u8 *pbuf)
    104{
    105	struct drvint_cmd_parm *pdrvcmd;
    106
    107	if (!pbuf)
    108		return;
    109	pdrvcmd = (struct drvint_cmd_parm *)pbuf;
    110	switch (pdrvcmd->i_cid) {
    111	case WDG_WK_CID:
    112		StatusWatchdogCallback(padapter);
    113		break;
    114	default:
    115		break;
    116	}
    117	kfree(pdrvcmd->pbuf);
    118}
    119
    120static u8 read_macreg_hdl(struct _adapter *padapter, u8 *pbuf)
    121{
    122	void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj	*pcmd);
    123	struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
    124
    125	/*  invoke cmd->callback function */
    126	pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
    127	if (!pcmd_callback)
    128		r8712_free_cmd_obj(pcmd);
    129	else
    130		pcmd_callback(padapter, pcmd);
    131	return H2C_SUCCESS;
    132}
    133
    134static u8 write_macreg_hdl(struct _adapter *padapter, u8 *pbuf)
    135{
    136	void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj	*pcmd);
    137	struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
    138
    139	/*  invoke cmd->callback function */
    140	pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
    141	if (!pcmd_callback)
    142		r8712_free_cmd_obj(pcmd);
    143	else
    144		pcmd_callback(padapter, pcmd);
    145	return H2C_SUCCESS;
    146}
    147
    148static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf)
    149{
    150	struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
    151
    152	r8712_free_cmd_obj(pcmd);
    153	return H2C_SUCCESS;
    154}
    155
    156static u8 write_bbreg_hdl(struct _adapter *padapter, u8 *pbuf)
    157{
    158	void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd);
    159	struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
    160
    161	pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
    162	if (!pcmd_callback)
    163		r8712_free_cmd_obj(pcmd);
    164	else
    165		pcmd_callback(padapter, pcmd);
    166	return H2C_SUCCESS;
    167}
    168
    169static u8 read_rfreg_hdl(struct _adapter *padapter, u8 *pbuf)
    170{
    171	u32 val;
    172	void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd);
    173	struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
    174
    175	if (pcmd->rsp && pcmd->rspsz > 0)
    176		memcpy(pcmd->rsp, (u8 *)&val, pcmd->rspsz);
    177	pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
    178	if (!pcmd_callback)
    179		r8712_free_cmd_obj(pcmd);
    180	else
    181		pcmd_callback(padapter, pcmd);
    182	return H2C_SUCCESS;
    183}
    184
    185static u8 write_rfreg_hdl(struct _adapter *padapter, u8 *pbuf)
    186{
    187	void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd);
    188	struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
    189
    190	pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
    191	if (!pcmd_callback)
    192		r8712_free_cmd_obj(pcmd);
    193	else
    194		pcmd_callback(padapter, pcmd);
    195	return H2C_SUCCESS;
    196}
    197
    198static u8 sys_suspend_hdl(struct _adapter *padapter, u8 *pbuf)
    199{
    200	struct cmd_obj *pcmd  = (struct cmd_obj *)pbuf;
    201
    202	r8712_free_cmd_obj(pcmd);
    203	return H2C_SUCCESS;
    204}
    205
    206static struct cmd_obj *cmd_hdl_filter(struct _adapter *padapter,
    207				      struct cmd_obj *pcmd)
    208{
    209	struct cmd_obj *pcmd_r;
    210
    211	if (!pcmd)
    212		return pcmd;
    213	pcmd_r = NULL;
    214
    215	switch (pcmd->cmdcode) {
    216	case GEN_CMD_CODE(_Read_MACREG):
    217		read_macreg_hdl(padapter, (u8 *)pcmd);
    218		pcmd_r = pcmd;
    219		break;
    220	case GEN_CMD_CODE(_Write_MACREG):
    221		write_macreg_hdl(padapter, (u8 *)pcmd);
    222		pcmd_r = pcmd;
    223		break;
    224	case GEN_CMD_CODE(_Read_BBREG):
    225		read_bbreg_hdl(padapter, (u8 *)pcmd);
    226		break;
    227	case GEN_CMD_CODE(_Write_BBREG):
    228		write_bbreg_hdl(padapter, (u8 *)pcmd);
    229		break;
    230	case GEN_CMD_CODE(_Read_RFREG):
    231		read_rfreg_hdl(padapter, (u8 *)pcmd);
    232		break;
    233	case GEN_CMD_CODE(_Write_RFREG):
    234		write_rfreg_hdl(padapter, (u8 *)pcmd);
    235		break;
    236	case GEN_CMD_CODE(_SetUsbSuspend):
    237		sys_suspend_hdl(padapter, (u8 *)pcmd);
    238		break;
    239	case GEN_CMD_CODE(_JoinBss):
    240		r8712_joinbss_reset(padapter);
    241		/* Before set JoinBss_CMD to FW, driver must ensure FW is in
    242		 * PS_MODE_ACTIVE. Directly write rpwm to radio on and assign
    243		 * new pwr_mode to Driver, instead of use workitem to change
    244		 * state.
    245		 */
    246		if (padapter->pwrctrlpriv.pwr_mode > PS_MODE_ACTIVE) {
    247			padapter->pwrctrlpriv.pwr_mode = PS_MODE_ACTIVE;
    248			mutex_lock(&padapter->pwrctrlpriv.mutex_lock);
    249			r8712_set_rpwm(padapter, PS_STATE_S4);
    250			mutex_unlock(&padapter->pwrctrlpriv.mutex_lock);
    251		}
    252		pcmd_r = pcmd;
    253		break;
    254	case _DRV_INT_CMD_:
    255		r871x_internal_cmd_hdl(padapter, pcmd->parmbuf);
    256		r8712_free_cmd_obj(pcmd);
    257		pcmd_r = NULL;
    258		break;
    259	default:
    260		pcmd_r = pcmd;
    261		break;
    262	}
    263	return pcmd_r; /* if returning pcmd_r == NULL, pcmd must be free. */
    264}
    265
    266u8 r8712_fw_cmd(struct _adapter *pAdapter, u32 cmd)
    267{
    268	int pollingcnts = 50;
    269
    270	r8712_write32(pAdapter, IOCMD_CTRL_REG, cmd);
    271	msleep(100);
    272	while ((r8712_read32(pAdapter, IOCMD_CTRL_REG != 0)) &&
    273	       (pollingcnts > 0)) {
    274		pollingcnts--;
    275		msleep(20);
    276	}
    277	if (pollingcnts == 0)
    278		return false;
    279	return true;
    280}
    281
    282void r8712_fw_cmd_data(struct _adapter *pAdapter, u32 *value, u8 flag)
    283{
    284	if (flag == 0)	/* set */
    285		r8712_write32(pAdapter, IOCMD_DATA_REG, *value);
    286	else		/* query */
    287		*value = r8712_read32(pAdapter, IOCMD_DATA_REG);
    288}
    289
    290int r8712_cmd_thread(void *context)
    291{
    292	struct cmd_obj *pcmd;
    293	unsigned int cmdsz, wr_sz;
    294	__le32 *pcmdbuf;
    295	struct tx_desc *pdesc;
    296	void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd);
    297	struct _adapter *padapter = context;
    298	struct	cmd_priv *pcmdpriv = &padapter->cmdpriv;
    299	struct completion *cmd_queue_comp =
    300		&pcmdpriv->cmd_queue_comp;
    301	struct mutex *pwctrl_lock = &padapter->pwrctrlpriv.mutex_lock;
    302
    303	allow_signal(SIGTERM);
    304	while (1) {
    305		if (wait_for_completion_interruptible(cmd_queue_comp))
    306			break;
    307		if (padapter->driver_stopped || padapter->surprise_removed)
    308			break;
    309		if (r8712_register_cmd_alive(padapter))
    310			continue;
    311_next:
    312		pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue);
    313		if (!(pcmd)) {
    314			r8712_unregister_cmd_alive(padapter);
    315			continue;
    316		}
    317		pcmdbuf = (__le32 *)pcmdpriv->cmd_buf;
    318		pdesc = (struct tx_desc *)pcmdbuf;
    319		memset(pdesc, 0, TXDESC_SIZE);
    320		pcmd = cmd_hdl_filter(padapter, pcmd);
    321		if (pcmd) { /* if pcmd != NULL, cmd will be handled by f/w */
    322			struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
    323			u8 blnPending = 0;
    324			u16 cmdcode = pcmd->cmdcode;
    325
    326			pcmdpriv->cmd_issued_cnt++;
    327			cmdsz = round_up(pcmd->cmdsz, 8);
    328			wr_sz = TXDESC_SIZE + 8 + cmdsz;
    329			pdesc->txdw0 |= cpu_to_le32((wr_sz - TXDESC_SIZE) &
    330						     0x0000ffff);
    331			if (pdvobj->ishighspeed) {
    332				if ((wr_sz % 512) == 0)
    333					blnPending = 1;
    334			} else {
    335				if ((wr_sz % 64) == 0)
    336					blnPending = 1;
    337			}
    338			if (blnPending) { /* 32 bytes for TX Desc - 8 offset */
    339				pdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE +
    340						OFFSET_SZ + 8) << OFFSET_SHT) &
    341						0x00ff0000);
    342			} else {
    343				pdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE +
    344							      OFFSET_SZ) <<
    345							      OFFSET_SHT) &
    346							      0x00ff0000);
    347			}
    348			pdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
    349			pdesc->txdw1 |= cpu_to_le32((0x13 << QSEL_SHT) &
    350						    0x00001f00);
    351			pcmdbuf += (TXDESC_SIZE >> 2);
    352			*pcmdbuf = cpu_to_le32((cmdsz & 0x0000ffff) |
    353					       (pcmd->cmdcode << 16) |
    354					       (pcmdpriv->cmd_seq << 24));
    355			pcmdbuf += 2; /* 8 bytes alignment */
    356			memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
    357			if (blnPending)
    358				wr_sz += 8;   /* Append 8 bytes */
    359			r8712_write_mem(padapter, RTL8712_DMA_H2CCMD, wr_sz,
    360					(u8 *)pdesc);
    361			pcmdpriv->cmd_seq++;
    362			if (cmdcode == GEN_CMD_CODE(_CreateBss)) {
    363				pcmd->res = H2C_SUCCESS;
    364				pcmd_callback = cmd_callback[cmdcode].callback;
    365				if (pcmd_callback)
    366					pcmd_callback(padapter, pcmd);
    367				continue;
    368			}
    369			if (cmdcode == GEN_CMD_CODE(_SetPwrMode)) {
    370				if (padapter->pwrctrlpriv.bSleep) {
    371					mutex_lock(pwctrl_lock);
    372					r8712_set_rpwm(padapter, PS_STATE_S2);
    373					mutex_unlock(pwctrl_lock);
    374				}
    375			}
    376			r8712_free_cmd_obj(pcmd);
    377			if (list_empty(&pcmdpriv->cmd_queue.queue)) {
    378				r8712_unregister_cmd_alive(padapter);
    379				continue;
    380			} else {
    381				goto _next;
    382			}
    383		} else {
    384			goto _next;
    385		}
    386		flush_signals_thread();
    387	}
    388	/* free all cmd_obj resources */
    389	do {
    390		pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue);
    391		if (!pcmd)
    392			break;
    393		r8712_free_cmd_obj(pcmd);
    394	} while (1);
    395	complete(&pcmdpriv->terminate_cmdthread_comp);
    396	return 0;
    397}
    398
    399void r8712_event_handle(struct _adapter *padapter, __le32 *peventbuf)
    400{
    401	u8 evt_code, evt_seq;
    402	u16 evt_sz;
    403	void (*event_callback)(struct _adapter *dev, u8 *pbuf);
    404	struct	evt_priv *pevt_priv = &padapter->evtpriv;
    405
    406	if (!peventbuf)
    407		goto _abort_event_;
    408	evt_sz = (u16)(le32_to_cpu(*peventbuf) & 0xffff);
    409	evt_seq = (u8)((le32_to_cpu(*peventbuf) >> 24) & 0x7f);
    410	evt_code = (u8)((le32_to_cpu(*peventbuf) >> 16) & 0xff);
    411	/* checking event sequence... */
    412	if ((evt_seq & 0x7f) != pevt_priv->event_seq) {
    413		pevt_priv->event_seq = ((evt_seq + 1) & 0x7f);
    414		goto _abort_event_;
    415	}
    416	/* checking if event code is valid */
    417	if (evt_code >= MAX_C2HEVT) {
    418		pevt_priv->event_seq = ((evt_seq + 1) & 0x7f);
    419		goto _abort_event_;
    420	} else if ((evt_code == GEN_EVT_CODE(_Survey)) &&
    421		   (evt_sz > sizeof(struct wlan_bssid_ex))) {
    422		pevt_priv->event_seq = ((evt_seq + 1) & 0x7f);
    423		goto _abort_event_;
    424	}
    425	/* checking if event size match the event parm size */
    426	if ((wlanevents[evt_code].parmsize) &&
    427	    (wlanevents[evt_code].parmsize != evt_sz)) {
    428		pevt_priv->event_seq = ((evt_seq + 1) & 0x7f);
    429		goto _abort_event_;
    430	} else if ((evt_sz == 0) && (evt_code != GEN_EVT_CODE(_WPS_PBC))) {
    431		pevt_priv->event_seq = ((evt_seq + 1) & 0x7f);
    432		goto _abort_event_;
    433	}
    434	pevt_priv->event_seq++;	/* update evt_seq */
    435	if (pevt_priv->event_seq > 127)
    436		pevt_priv->event_seq = 0;
    437	/* move to event content, 8 bytes alignment */
    438	peventbuf = peventbuf + 2;
    439	event_callback = wlanevents[evt_code].event_callback;
    440	if (event_callback)
    441		event_callback(padapter, (u8 *)peventbuf);
    442	pevt_priv->evt_done_cnt++;
    443_abort_event_:
    444	return;
    445}