root/drivers/staging/rtl8712/rtl8712_cmd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_hw_pbc
  2. query_fw_rx_phy_status
  3. StatusWatchdogCallback
  4. r871x_internal_cmd_hdl
  5. read_macreg_hdl
  6. write_macreg_hdl
  7. read_bbreg_hdl
  8. write_bbreg_hdl
  9. read_rfreg_hdl
  10. write_rfreg_hdl
  11. sys_suspend_hdl
  12. cmd_hdl_filter
  13. r8712_fw_cmd
  14. r8712_fw_cmd_data
  15. r8712_cmd_thread
  16. r8712_event_handle

   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 
  43 static 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                 DBG_8712("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  */
  72 static 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. */
  97 static void StatusWatchdogCallback(struct _adapter *padapter)
  98 {
  99         check_hw_pbc(padapter);
 100         query_fw_rx_phy_status(padapter);
 101 }
 102 
 103 static 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 
 120 static 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 
 134 static 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 
 148 static 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 
 156 static 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 
 169 static 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 
 185 static 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 
 198 static 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 
 206 static 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 
 266 u8 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 
 282 void 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 
 290 int 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         thread_exit();
 397 }
 398 
 399 void 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 }

/* [<][>][^][v][top][bottom][index][help] */