Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/net/wireless/ralink/rt2x00/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 381 kB image not shown  

Quelle  rt2800lib.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>

Based on the original rt2800pci.c and rt2800usb.c.
  Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
  Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
  Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
  Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
  Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
  Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
  <http://rt2x00.serialmonkey.com>

 */


/*
Module: rt2800lib
Abstract: rt2800 generic device routines.
 */


#include <linux/crc-ccitt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>

#include "rt2x00.h"
#include "rt2800lib.h"
#include "rt2800.h"

static unsigned int modparam_watchdog = RT2800_WATCHDOG_DMA_BUSY;
module_param_named(watchdog, modparam_watchdog, uint, 0444);
MODULE_PARM_DESC(watchdog, "Enable watchdog to recover tx/rx hangs.\n"
   "\t\t(0=disabled, 1=hang watchdog, 2=DMA watchdog(default), 3=both)");

/*
 * Register access.
 * All access to the CSR registers will go through the methods
 * rt2800_register_read and rt2800_register_write.
 * BBP and RF register require indirect register access,
 * and use the CSR registers BBPCSR and RFCSR to achieve this.
 * These indirect registers work with busy bits,
 * and we will try maximal REGISTER_BUSY_COUNT times to access
 * the register while taking a REGISTER_BUSY_DELAY us delay
 * between each attampt. When the busy bit is still set at that time,
 * the access attempt is considered to have failed,
 * and we will print an error.
 * The _lock versions must be used if you already hold the csr_mutex
 */

#define WAIT_FOR_BBP(__dev, __reg) \
 rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg))
#define WAIT_FOR_RFCSR(__dev, __reg) \
 rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg))
#define WAIT_FOR_RFCSR_MT7620(__dev, __reg) \
 rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY_MT7620, \
       (__reg))
#define WAIT_FOR_RF(__dev, __reg) \
 rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg))
#define WAIT_FOR_MCU(__dev, __reg) \
 rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \
       H2M_MAILBOX_CSR_OWNER, (__reg))

static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev)
{
 /* check for rt2872 on SoC */
 if (!rt2x00_is_soc(rt2x00dev) ||
     !rt2x00_rt(rt2x00dev, RT2872))
  return false;

 /* we know for sure that these rf chipsets are used on rt305x boards */
 if (rt2x00_rf(rt2x00dev, RF3020) ||
     rt2x00_rf(rt2x00dev, RF3021) ||
     rt2x00_rf(rt2x00dev, RF3022))
  return true;

 rt2x00_warn(rt2x00dev, "Unknown RF chipset on rt305x\n");
 return false;
}

static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev,
        const unsigned int word, const u8 value)
{
 u32 reg;

 mutex_lock(&rt2x00dev->csr_mutex);

 /*
 * Wait until the BBP becomes available, afterwards we
 * can safely write the new data into the register.
 */

 if (WAIT_FOR_BBP(rt2x00dev, ®)) {
  reg = 0;
  rt2x00_set_field32(®, BBP_CSR_CFG_VALUE, value);
  rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word);
  rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1);
  rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0);
  rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1);

  rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
 }

 mutex_unlock(&rt2x00dev->csr_mutex);
}

static u8 rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word)
{
 u32 reg;
 u8 value;

 mutex_lock(&rt2x00dev->csr_mutex);

 /*
 * Wait until the BBP becomes available, afterwards we
 * can safely write the read request into the register.
 * After the data has been written, we wait until hardware
 * returns the correct value, if at any time the register
 * doesn't become available in time, reg will be 0xffffffff
 * which means we return 0xff to the caller.
 */

 if (WAIT_FOR_BBP(rt2x00dev, ®)) {
  reg = 0;
  rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word);
  rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1);
  rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1);
  rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1);

  rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);

  WAIT_FOR_BBP(rt2x00dev, ®);
 }

 value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE);

 mutex_unlock(&rt2x00dev->csr_mutex);

 return value;
}

static void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev,
          const unsigned int word, const u8 value)
{
 u32 reg;

 mutex_lock(&rt2x00dev->csr_mutex);

 /*
 * Wait until the RFCSR becomes available, afterwards we
 * can safely write the new data into the register.
 */

 switch (rt2x00dev->chip.rt) {
 case RT6352:
  if (WAIT_FOR_RFCSR_MT7620(rt2x00dev, ®)) {
   reg = 0;
   rt2x00_set_field32(®, RF_CSR_CFG_DATA_MT7620, value);
   rt2x00_set_field32(®, RF_CSR_CFG_REGNUM_MT7620,
        word);
   rt2x00_set_field32(®, RF_CSR_CFG_WRITE_MT7620, 1);
   rt2x00_set_field32(®, RF_CSR_CFG_BUSY_MT7620, 1);

   rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);
  }
  break;

 default:
  if (WAIT_FOR_RFCSR(rt2x00dev, ®)) {
   reg = 0;
   rt2x00_set_field32(®, RF_CSR_CFG_DATA, value);
   rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word);
   rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1);
   rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1);

   rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);
  }
  break;
 }

 mutex_unlock(&rt2x00dev->csr_mutex);
}

static void rt2800_rfcsr_write_bank(struct rt2x00_dev *rt2x00dev, const u8 bank,
        const unsigned int reg, const u8 value)
{
 rt2800_rfcsr_write(rt2x00dev, (reg | (bank << 6)), value);
}

static void rt2800_rfcsr_write_chanreg(struct rt2x00_dev *rt2x00dev,
           const unsigned int reg, const u8 value)
{
 rt2800_rfcsr_write_bank(rt2x00dev, 4, reg, value);
 rt2800_rfcsr_write_bank(rt2x00dev, 6, reg, value);
}

static void rt2800_rfcsr_write_dccal(struct rt2x00_dev *rt2x00dev,
         const unsigned int reg, const u8 value)
{
 rt2800_rfcsr_write_bank(rt2x00dev, 5, reg, value);
 rt2800_rfcsr_write_bank(rt2x00dev, 7, reg, value);
}

static void rt2800_bbp_dcoc_write(struct rt2x00_dev *rt2x00dev,
      const u8 reg, const u8 value)
{
 rt2800_bbp_write(rt2x00dev, 158, reg);
 rt2800_bbp_write(rt2x00dev, 159, value);
}

static u8 rt2800_bbp_dcoc_read(struct rt2x00_dev *rt2x00dev, const u8 reg)
{
 rt2800_bbp_write(rt2x00dev, 158, reg);
 return rt2800_bbp_read(rt2x00dev, 159);
}

static void rt2800_bbp_glrt_write(struct rt2x00_dev *rt2x00dev,
      const u8 reg, const u8 value)
{
 rt2800_bbp_write(rt2x00dev, 195, reg);
 rt2800_bbp_write(rt2x00dev, 196, value);
}

static u8 rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev,
       const unsigned int word)
{
 u32 reg;
 u8 value;

 mutex_lock(&rt2x00dev->csr_mutex);

 /*
 * Wait until the RFCSR becomes available, afterwards we
 * can safely write the read request into the register.
 * After the data has been written, we wait until hardware
 * returns the correct value, if at any time the register
 * doesn't become available in time, reg will be 0xffffffff
 * which means we return 0xff to the caller.
 */

 switch (rt2x00dev->chip.rt) {
 case RT6352:
  if (WAIT_FOR_RFCSR_MT7620(rt2x00dev, ®)) {
   reg = 0;
   rt2x00_set_field32(®, RF_CSR_CFG_REGNUM_MT7620,
        word);
   rt2x00_set_field32(®, RF_CSR_CFG_WRITE_MT7620, 0);
   rt2x00_set_field32(®, RF_CSR_CFG_BUSY_MT7620, 1);

   rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);

   WAIT_FOR_RFCSR_MT7620(rt2x00dev, ®);
  }

  value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA_MT7620);
  break;

 default:
  if (WAIT_FOR_RFCSR(rt2x00dev, ®)) {
   reg = 0;
   rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word);
   rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0);
   rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1);

   rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);

   WAIT_FOR_RFCSR(rt2x00dev, ®);
  }

  value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA);
  break;
 }

 mutex_unlock(&rt2x00dev->csr_mutex);

 return value;
}

static u8 rt2800_rfcsr_read_bank(struct rt2x00_dev *rt2x00dev, const u8 bank,
     const unsigned int reg)
{
 return rt2800_rfcsr_read(rt2x00dev, (reg | (bank << 6)));
}

static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev,
       const unsigned int word, const u32 value)
{
 u32 reg;

 mutex_lock(&rt2x00dev->csr_mutex);

 /*
 * Wait until the RF becomes available, afterwards we
 * can safely write the new data into the register.
 */

 if (WAIT_FOR_RF(rt2x00dev, ®)) {
  reg = 0;
  rt2x00_set_field32(®, RF_CSR_CFG0_REG_VALUE_BW, value);
  rt2x00_set_field32(®, RF_CSR_CFG0_STANDBYMODE, 0);
  rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0);
  rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1);

  rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg);
  rt2x00_rf_write(rt2x00dev, word, value);
 }

 mutex_unlock(&rt2x00dev->csr_mutex);
}

static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = {
 [EEPROM_CHIP_ID]  = 0x0000,
 [EEPROM_VERSION]  = 0x0001,
 [EEPROM_MAC_ADDR_0]  = 0x0002,
 [EEPROM_MAC_ADDR_1]  = 0x0003,
 [EEPROM_MAC_ADDR_2]  = 0x0004,
 [EEPROM_NIC_CONF0]  = 0x001a,
 [EEPROM_NIC_CONF1]  = 0x001b,
 [EEPROM_FREQ]   = 0x001d,
 [EEPROM_LED_AG_CONF]  = 0x001e,
 [EEPROM_LED_ACT_CONF]  = 0x001f,
 [EEPROM_LED_POLARITY]  = 0x0020,
 [EEPROM_NIC_CONF2]  = 0x0021,
 [EEPROM_LNA]   = 0x0022,
 [EEPROM_RSSI_BG]  = 0x0023,
 [EEPROM_RSSI_BG2]  = 0x0024,
 [EEPROM_TXMIXER_GAIN_BG] = 0x0024, /* overlaps with RSSI_BG2 */
 [EEPROM_RSSI_A]   = 0x0025,
 [EEPROM_RSSI_A2]  = 0x0026,
 [EEPROM_TXMIXER_GAIN_A]  = 0x0026, /* overlaps with RSSI_A2 */
 [EEPROM_EIRP_MAX_TX_POWER] = 0x0027,
 [EEPROM_TXPOWER_DELTA]  = 0x0028,
 [EEPROM_TXPOWER_BG1]  = 0x0029,
 [EEPROM_TXPOWER_BG2]  = 0x0030,
 [EEPROM_TSSI_BOUND_BG1]  = 0x0037,
 [EEPROM_TSSI_BOUND_BG2]  = 0x0038,
 [EEPROM_TSSI_BOUND_BG3]  = 0x0039,
 [EEPROM_TSSI_BOUND_BG4]  = 0x003a,
 [EEPROM_TSSI_BOUND_BG5]  = 0x003b,
 [EEPROM_TXPOWER_A1]  = 0x003c,
 [EEPROM_TXPOWER_A2]  = 0x0053,
 [EEPROM_TXPOWER_INIT]  = 0x0068,
 [EEPROM_TSSI_BOUND_A1]  = 0x006a,
 [EEPROM_TSSI_BOUND_A2]  = 0x006b,
 [EEPROM_TSSI_BOUND_A3]  = 0x006c,
 [EEPROM_TSSI_BOUND_A4]  = 0x006d,
 [EEPROM_TSSI_BOUND_A5]  = 0x006e,
 [EEPROM_TXPOWER_BYRATE]  = 0x006f,
 [EEPROM_BBP_START]  = 0x0078,
};

static const unsigned int rt2800_eeprom_map_ext[EEPROM_WORD_COUNT] = {
 [EEPROM_CHIP_ID]  = 0x0000,
 [EEPROM_VERSION]  = 0x0001,
 [EEPROM_MAC_ADDR_0]  = 0x0002,
 [EEPROM_MAC_ADDR_1]  = 0x0003,
 [EEPROM_MAC_ADDR_2]  = 0x0004,
 [EEPROM_NIC_CONF0]  = 0x001a,
 [EEPROM_NIC_CONF1]  = 0x001b,
 [EEPROM_NIC_CONF2]  = 0x001c,
 [EEPROM_EIRP_MAX_TX_POWER] = 0x0020,
 [EEPROM_FREQ]   = 0x0022,
 [EEPROM_LED_AG_CONF]  = 0x0023,
 [EEPROM_LED_ACT_CONF]  = 0x0024,
 [EEPROM_LED_POLARITY]  = 0x0025,
 [EEPROM_LNA]   = 0x0026,
 [EEPROM_EXT_LNA2]  = 0x0027,
 [EEPROM_RSSI_BG]  = 0x0028,
 [EEPROM_RSSI_BG2]  = 0x0029,
 [EEPROM_RSSI_A]   = 0x002a,
 [EEPROM_RSSI_A2]  = 0x002b,
 [EEPROM_TXPOWER_BG1]  = 0x0030,
 [EEPROM_TXPOWER_BG2]  = 0x0037,
 [EEPROM_EXT_TXPOWER_BG3] = 0x003e,
 [EEPROM_TSSI_BOUND_BG1]  = 0x0045,
 [EEPROM_TSSI_BOUND_BG2]  = 0x0046,
 [EEPROM_TSSI_BOUND_BG3]  = 0x0047,
 [EEPROM_TSSI_BOUND_BG4]  = 0x0048,
 [EEPROM_TSSI_BOUND_BG5]  = 0x0049,
 [EEPROM_TXPOWER_A1]  = 0x004b,
 [EEPROM_TXPOWER_A2]  = 0x0065,
 [EEPROM_EXT_TXPOWER_A3]  = 0x007f,
 [EEPROM_TSSI_BOUND_A1]  = 0x009a,
 [EEPROM_TSSI_BOUND_A2]  = 0x009b,
 [EEPROM_TSSI_BOUND_A3]  = 0x009c,
 [EEPROM_TSSI_BOUND_A4]  = 0x009d,
 [EEPROM_TSSI_BOUND_A5]  = 0x009e,
 [EEPROM_TXPOWER_BYRATE]  = 0x00a0,
};

static unsigned int rt2800_eeprom_word_index(struct rt2x00_dev *rt2x00dev,
          const enum rt2800_eeprom_word word)
{
 const unsigned int *map;
 unsigned int index;

 if (WARN_ONCE(word >= EEPROM_WORD_COUNT,
        "%s: invalid EEPROM word %d\n",
        wiphy_name(rt2x00dev->hw->wiphy), word))
  return 0;

 if (rt2x00_rt(rt2x00dev, RT3593) ||
     rt2x00_rt(rt2x00dev, RT3883))
  map = rt2800_eeprom_map_ext;
 else
  map = rt2800_eeprom_map;

 index = map[word];

 /* Index 0 is valid only for EEPROM_CHIP_ID.
 * Otherwise it means that the offset of the
 * given word is not initialized in the map,
 * or that the field is not usable on the
 * actual chipset.
 */

 WARN_ONCE(word != EEPROM_CHIP_ID && index == 0,
    "%s: invalid access of EEPROM word %d\n",
    wiphy_name(rt2x00dev->hw->wiphy), word);

 return index;
}

static void *rt2800_eeprom_addr(struct rt2x00_dev *rt2x00dev,
    const enum rt2800_eeprom_word word)
{
 unsigned int index;

 index = rt2800_eeprom_word_index(rt2x00dev, word);
 return rt2x00_eeprom_addr(rt2x00dev, index);
}

static u16 rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev,
         const enum rt2800_eeprom_word word)
{
 unsigned int index;

 index = rt2800_eeprom_word_index(rt2x00dev, word);
 return rt2x00_eeprom_read(rt2x00dev, index);
}

static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev,
    const enum rt2800_eeprom_word word, u16 data)
{
 unsigned int index;

 index = rt2800_eeprom_word_index(rt2x00dev, word);
 rt2x00_eeprom_write(rt2x00dev, index, data);
}

static u16 rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev,
      const enum rt2800_eeprom_word array,
      unsigned int offset)
{
 unsigned int index;

 index = rt2800_eeprom_word_index(rt2x00dev, array);
 return rt2x00_eeprom_read(rt2x00dev, index + offset);
}

static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev)
{
 u32 reg;
 int i, count;

 reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL);
 rt2x00_set_field32(®, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff);
 rt2x00_set_field32(®, FRC_WL_ANT_SET, 1);
 rt2x00_set_field32(®, WLAN_CLK_EN, 0);
 rt2x00_set_field32(®, WLAN_EN, 1);
 rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);

 udelay(REGISTER_BUSY_DELAY);

 count = 0;
 do {
  /*
 * Check PLL_LD & XTAL_RDY.
 */

  for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
   reg = rt2800_register_read(rt2x00dev, CMB_CTRL);
   if (rt2x00_get_field32(reg, PLL_LD) &&
       rt2x00_get_field32(reg, XTAL_RDY))
    break;
   udelay(REGISTER_BUSY_DELAY);
  }

  if (i >= REGISTER_BUSY_COUNT) {

   if (count >= 10)
    return -EIO;

   rt2800_register_write(rt2x00dev, 0x58, 0x018);
   udelay(REGISTER_BUSY_DELAY);
   rt2800_register_write(rt2x00dev, 0x58, 0x418);
   udelay(REGISTER_BUSY_DELAY);
   rt2800_register_write(rt2x00dev, 0x58, 0x618);
   udelay(REGISTER_BUSY_DELAY);
   count++;
  } else {
   count = 0;
  }

  reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL);
  rt2x00_set_field32(®, PCIE_APP0_CLK_REQ, 0);
  rt2x00_set_field32(®, WLAN_CLK_EN, 1);
  rt2x00_set_field32(®, WLAN_RESET, 1);
  rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
  udelay(10);
  rt2x00_set_field32(®, WLAN_RESET, 0);
  rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
  udelay(10);
  rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff);
 } while (count != 0);

 return 0;
}

void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
   const u8 command, const u8 token,
   const u8 arg0, const u8 arg1)
{
 u32 reg;

 /*
 * SOC devices don't support MCU requests.
 */

 if (rt2x00_is_soc(rt2x00dev))
  return;

 mutex_lock(&rt2x00dev->csr_mutex);

 /*
 * Wait until the MCU becomes available, afterwards we
 * can safely write the new data into the register.
 */

 if (WAIT_FOR_MCU(rt2x00dev, ®)) {
  rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1);
  rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token);
  rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0);
  rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1);
  rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg);

  reg = 0;
  rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command);
  rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg);
 }

 mutex_unlock(&rt2x00dev->csr_mutex);
}
EXPORT_SYMBOL_GPL(rt2800_mcu_request);

int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev)
{
 unsigned int i = 0;
 u32 reg;

 for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
  reg = rt2800_register_read(rt2x00dev, MAC_CSR0);
  if (reg && reg != ~0)
   return 0;
  msleep(1);
 }

 rt2x00_err(rt2x00dev, "Unstable hardware\n");
 return -EBUSY;
}
EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready);

int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
{
 unsigned int i;
 u32 reg;

 /*
 * Some devices are really slow to respond here. Wait a whole second
 * before timing out.
 */

 for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
  reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG);
  if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
      !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
   return 0;

  msleep(10);
 }

 rt2x00_err(rt2x00dev, "WPDMA TX/RX busy [0x%08x]\n", reg);
 return -EACCES;
}
EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);

void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev)
{
 u32 reg;

 reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG);
 rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
 rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
 rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
 rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
 rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
 rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
}
EXPORT_SYMBOL_GPL(rt2800_disable_wpdma);

void rt2800_get_txwi_rxwi_size(struct rt2x00_dev *rt2x00dev,
          unsigned short *txwi_size,
          unsigned short *rxwi_size)
{
 switch (rt2x00dev->chip.rt) {
 case RT3593:
 case RT3883:
  *txwi_size = TXWI_DESC_SIZE_4WORDS;
  *rxwi_size = RXWI_DESC_SIZE_5WORDS;
  break;

 case RT5592:
 case RT6352:
  *txwi_size = TXWI_DESC_SIZE_5WORDS;
  *rxwi_size = RXWI_DESC_SIZE_6WORDS;
  break;

 default:
  *txwi_size = TXWI_DESC_SIZE_4WORDS;
  *rxwi_size = RXWI_DESC_SIZE_4WORDS;
  break;
 }
}
EXPORT_SYMBOL_GPL(rt2800_get_txwi_rxwi_size);

static bool rt2800_check_firmware_crc(const u8 *data, const size_t len)
{
 u16 fw_crc;
 u16 crc;

 /*
 * The last 2 bytes in the firmware array are the crc checksum itself,
 * this means that we should never pass those 2 bytes to the crc
 * algorithm.
 */

 fw_crc = (data[len - 2] << 8 | data[len - 1]);

 /*
 * Use the crc ccitt algorithm.
 * This will return the same value as the legacy driver which
 * used bit ordering reversion on both the firmware bytes
 * before input input as well as on the final output.
 * Obviously using crc ccitt directly is much more efficient.
 */

 crc = crc_ccitt(~0, data, len - 2);

 /*
 * There is a small difference between the crc-itu-t + bitrev and
 * the crc-ccitt crc calculation. In the latter method the 2 bytes
 * will be swapped, use swab16 to convert the crc to the correct
 * value.
 */

 crc = swab16(crc);

 return fw_crc == crc;
}

int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
     const u8 *data, const size_t len)
{
 size_t offset = 0;
 size_t fw_len;
 bool multiple;

 /*
 * PCI(e) & SOC devices require firmware with a length
 * of 8kb. USB devices require firmware files with a length
 * of 4kb. Certain USB chipsets however require different firmware,
 * which Ralink only provides attached to the original firmware
 * file. Thus for USB devices, firmware files have a length
 * which is a multiple of 4kb. The firmware for rt3290 chip also
 * have a length which is a multiple of 4kb.
 */

 if (rt2x00_is_usb(rt2x00dev) || rt2x00_rt(rt2x00dev, RT3290))
  fw_len = 4096;
 else
  fw_len = 8192;

 multiple = true;
 /*
 * Validate the firmware length
 */

 if (len != fw_len && (!multiple || (len % fw_len) != 0))
  return FW_BAD_LENGTH;

 /*
 * Check if the chipset requires one of the upper parts
 * of the firmware.
 */

 if (rt2x00_is_usb(rt2x00dev) &&
     !rt2x00_rt(rt2x00dev, RT2860) &&
     !rt2x00_rt(rt2x00dev, RT2872) &&
     !rt2x00_rt(rt2x00dev, RT3070) &&
     ((len / fw_len) == 1))
  return FW_BAD_VERSION;

 /*
 * 8kb firmware files must be checked as if it were
 * 2 separate firmware files.
 */

 while (offset < len) {
  if (!rt2800_check_firmware_crc(data + offset, fw_len))
   return FW_BAD_CRC;

  offset += fw_len;
 }

 return FW_OK;
}
EXPORT_SYMBOL_GPL(rt2800_check_firmware);

int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
    const u8 *data, const size_t len)
{
 unsigned int i;
 u32 reg;
 int retval;

 if (rt2x00_rt(rt2x00dev, RT3290)) {
  retval = rt2800_enable_wlan_rt3290(rt2x00dev);
  if (retval)
   return -EBUSY;
 }

 /*
 * If driver doesn't wake up firmware here,
 * rt2800_load_firmware will hang forever when interface is up again.
 */

 rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);

 /*
 * Wait for stable hardware.
 */

 if (rt2800_wait_csr_ready(rt2x00dev))
  return -EBUSY;

 if (rt2x00_is_pci(rt2x00dev)) {
  if (rt2x00_rt(rt2x00dev, RT3290) ||
      rt2x00_rt(rt2x00dev, RT3572) ||
      rt2x00_rt(rt2x00dev, RT5390) ||
      rt2x00_rt(rt2x00dev, RT5392)) {
   reg = rt2800_register_read(rt2x00dev, AUX_CTRL);
   rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1);
   rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1);
   rt2800_register_write(rt2x00dev, AUX_CTRL, reg);
  }
  rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
 }

 rt2800_disable_wpdma(rt2x00dev);

 /*
 * Write firmware to the device.
 */

 rt2800_drv_write_firmware(rt2x00dev, data, len);

 /*
 * Wait for device to stabilize.
 */

 for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
  reg = rt2800_register_read(rt2x00dev, PBF_SYS_CTRL);
  if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
   break;
  msleep(1);
 }

 if (i == REGISTER_BUSY_COUNT) {
  rt2x00_err(rt2x00dev, "PBF system register not ready\n");
  return -EBUSY;
 }

 /*
 * Disable DMA, will be reenabled later when enabling
 * the radio.
 */

 rt2800_disable_wpdma(rt2x00dev);

 /*
 * Initialize firmware.
 */

 rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
 rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
 if (rt2x00_is_usb(rt2x00dev)) {
  rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
  rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
 }
 msleep(1);

 return 0;
}
EXPORT_SYMBOL_GPL(rt2800_load_firmware);

void rt2800_write_tx_data(struct queue_entry *entry,
     struct txentry_desc *txdesc)
{
 __le32 *txwi = rt2800_drv_get_txwi(entry);
 u32 word;
 int i;

 /*
 * Initialize TX Info descriptor
 */

 word = rt2x00_desc_read(txwi, 0);
 rt2x00_set_field32(&word, TXWI_W0_FRAG,
      test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
 rt2x00_set_field32(&word, TXWI_W0_MIMO_PS,
      test_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags));
 rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
 rt2x00_set_field32(&word, TXWI_W0_TS,
      test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
 rt2x00_set_field32(&word, TXWI_W0_AMPDU,
      test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
 rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY,
      txdesc->u.ht.mpdu_density);
 rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->u.ht.txop);
 rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->u.ht.mcs);
 rt2x00_set_field32(&word, TXWI_W0_BW,
      test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
 rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
      test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
 rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->u.ht.stbc);
 rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
 rt2x00_desc_write(txwi, 0, word);

 word = rt2x00_desc_read(txwi, 1);
 rt2x00_set_field32(&word, TXWI_W1_ACK,
      test_bit(ENTRY_TXD_ACK, &txdesc->flags));
 rt2x00_set_field32(&word, TXWI_W1_NSEQ,
      test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
 rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->u.ht.ba_size);
 rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
      test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
      txdesc->key_idx : txdesc->u.ht.wcid);
 rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
      txdesc->length);
 rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid);
 rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1);
 rt2x00_desc_write(txwi, 1, word);

 /*
 * Always write 0 to IV/EIV fields (word 2 and 3), hardware will insert
 * the IV from the IVEIV register when TXD_W3_WIV is set to 0.
 * When TXD_W3_WIV is set to 1 it will use the IV data
 * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
 * crypto entry in the registers should be used to encrypt the frame.
 *
 * Nulify all remaining words as well, we don't know how to program them.
 */

 for (i = 2; i < entry->queue->winfo_size / sizeof(__le32); i++)
  _rt2x00_desc_write(txwi, i, 0);
}
EXPORT_SYMBOL_GPL(rt2800_write_tx_data);

static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2)
{
 s8 rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);
 s8 rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1);
 s8 rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2);
 s8 base_val = rt2x00_rt(rt2x00dev, RT6352) ? -2 : -12;
 u16 eeprom;
 u8 offset0;
 u8 offset1;
 u8 offset2;

 if (rt2x00dev->curr_band == NL80211_BAND_2GHZ) {
  eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG);
  offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
  offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
  eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2);
  offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2);
 } else {
  eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A);
  offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0);
  offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1);
  eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2);
  offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2);
 }

 /*
 * Convert the value from the descriptor into the RSSI value
 * If the value in the descriptor is 0, it is considered invalid
 * and the default (extremely low) rssi value is assumed
 */

 rssi0 = (rssi0) ? (base_val - offset0 - rt2x00dev->lna_gain - rssi0) : -128;
 rssi1 = (rssi1) ? (base_val - offset1 - rt2x00dev->lna_gain - rssi1) : -128;
 rssi2 = (rssi2) ? (base_val - offset2 - rt2x00dev->lna_gain - rssi2) : -128;

 /*
 * mac80211 only accepts a single RSSI value. Calculating the
 * average doesn't deliver a fair answer either since -60:-60 would
 * be considered equally good as -50:-70 while the second is the one
 * which gives less energy...
 */

 rssi0 = max(rssi0, rssi1);
 return (int)max(rssi0, rssi2);
}

void rt2800_process_rxwi(struct queue_entry *entry,
    struct rxdone_entry_desc *rxdesc)
{
 __le32 *rxwi = (__le32 *) entry->skb->data;
 u32 word;

 word = rt2x00_desc_read(rxwi, 0);

 rxdesc->cipher = rt2x00_get_field32(word, RXWI_W0_UDF);
 rxdesc->size = rt2x00_get_field32(word, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);

 word = rt2x00_desc_read(rxwi, 1);

 if (rt2x00_get_field32(word, RXWI_W1_SHORT_GI))
  rxdesc->enc_flags |= RX_ENC_FLAG_SHORT_GI;

 if (rt2x00_get_field32(word, RXWI_W1_BW))
  rxdesc->bw = RATE_INFO_BW_40;

 /*
 * Detect RX rate, always use MCS as signal type.
 */

 rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
 rxdesc->signal = rt2x00_get_field32(word, RXWI_W1_MCS);
 rxdesc->rate_mode = rt2x00_get_field32(word, RXWI_W1_PHYMODE);

 /*
 * Mask of 0x8 bit to remove the short preamble flag.
 */

 if (rxdesc->rate_mode == RATE_MODE_CCK)
  rxdesc->signal &= ~0x8;

 word = rt2x00_desc_read(rxwi, 2);

 /*
 * Convert descriptor AGC value to RSSI value.
 */

 rxdesc->rssi = rt2800_agc_to_rssi(entry->queue->rt2x00dev, word);
 /*
 * Remove RXWI descriptor from start of the buffer.
 */

 skb_pull(entry->skb, entry->queue->winfo_size);
}
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);

static void rt2800_rate_from_status(struct skb_frame_desc *skbdesc,
        u32 status, enum nl80211_band band)
{
 u8 flags = 0;
 u8 idx = rt2x00_get_field32(status, TX_STA_FIFO_MCS);

 switch (rt2x00_get_field32(status, TX_STA_FIFO_PHYMODE)) {
 case RATE_MODE_HT_GREENFIELD:
  flags |= IEEE80211_TX_RC_GREEN_FIELD;
  fallthrough;
 case RATE_MODE_HT_MIX:
  flags |= IEEE80211_TX_RC_MCS;
  break;
 case RATE_MODE_OFDM:
  if (band == NL80211_BAND_2GHZ)
   idx += 4;
  break;
 case RATE_MODE_CCK:
  if (idx >= 8)
   idx -= 8;
  break;
 }

 if (rt2x00_get_field32(status, TX_STA_FIFO_BW))
  flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;

 if (rt2x00_get_field32(status, TX_STA_FIFO_SGI))
  flags |= IEEE80211_TX_RC_SHORT_GI;

 skbdesc->tx_rate_idx = idx;
 skbdesc->tx_rate_flags = flags;
}

static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
{
 __le32 *txwi;
 u32 word;
 int wcid, ack, pid;
 int tx_wcid, tx_ack, tx_pid, is_agg;

 /*
 * This frames has returned with an IO error,
 * so the status report is not intended for this
 * frame.
 */

 if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
  return false;

 wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
 ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
 pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
 is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE);

 /*
 * Validate if this TX status report is intended for
 * this entry by comparing the WCID/ACK/PID fields.
 */

 txwi = rt2800_drv_get_txwi(entry);

 word = rt2x00_desc_read(txwi, 1);
 tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
 tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
 tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);

 if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
  rt2x00_dbg(entry->queue->rt2x00dev,
      "TX status report missed for queue %d entry %d\n",
      entry->queue->qid, entry->entry_idx);
  return false;
 }

 return true;
}

void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
    bool match)
{
 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
 struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 struct txdone_entry_desc txdesc;
 u32 word;
 u16 mcs, real_mcs;
 int aggr, ampdu, wcid, ack_req;

 /*
 * Obtain the status about this packet.
 */

 txdesc.flags = 0;
 word = rt2x00_desc_read(txwi, 0);

 mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
 ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU);

 real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS);
 aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE);
 wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID);
 ack_req = rt2x00_get_field32(status, TX_STA_FIFO_TX_ACK_REQUIRED);

 /*
 * If a frame was meant to be sent as a single non-aggregated MPDU
 * but ended up in an aggregate the used tx rate doesn't correlate
 * with the one specified in the TXWI as the whole aggregate is sent
 * with the same rate.
 *
 * For example: two frames are sent to rt2x00, the first one sets
 * AMPDU=1 and requests MCS7 whereas the second frame sets AMDPU=0
 * and requests MCS15. If the hw aggregates both frames into one
 * AMDPU the tx status for both frames will contain MCS7 although
 * the frame was sent successfully.
 *
 * Hence, replace the requested rate with the real tx rate to not
 * confuse the rate control algortihm by providing clearly wrong
 * data.
 *
 * FIXME: if we do not find matching entry, we tell that frame was
 * posted without any retries. We need to find a way to fix that
 * and provide retry count.
 */

 if (unlikely((aggr == 1 && ampdu == 0 && real_mcs != mcs)) || !match) {
  rt2800_rate_from_status(skbdesc, status, rt2x00dev->curr_band);
  mcs = real_mcs;
 }

 if (aggr == 1 || ampdu == 1)
  __set_bit(TXDONE_AMPDU, &txdesc.flags);

 if (!ack_req)
  __set_bit(TXDONE_NO_ACK_REQ, &txdesc.flags);

 /*
 * Ralink has a retry mechanism using a global fallback
 * table. We setup this fallback table to try the immediate
 * lower rate for all rates. In the TX_STA_FIFO, the MCS field
 * always contains the MCS used for the last transmission, be
 * it successful or not.
 */

 if (rt2x00_get_field32(status, TX_STA_FIFO_TX_SUCCESS)) {
  /*
 * Transmission succeeded. The number of retries is
 * mcs - real_mcs
 */

  __set_bit(TXDONE_SUCCESS, &txdesc.flags);
  txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
 } else {
  /*
 * Transmission failed. The number of retries is
 * always 7 in this case (for a total number of 8
 * frames sent).
 */

  __set_bit(TXDONE_FAILURE, &txdesc.flags);
  txdesc.retry = rt2x00dev->long_retry;
 }

 /*
 * the frame was retried at least once
 * -> hw used fallback rates
 */

 if (txdesc.retry)
  __set_bit(TXDONE_FALLBACK, &txdesc.flags);

 if (!match) {
  /* RCU assures non-null sta will not be freed by mac80211. */
  rcu_read_lock();
  if (likely(wcid >= WCID_START && wcid <= WCID_END))
   skbdesc->sta = drv_data->wcid_to_sta[wcid - WCID_START];
  else
   skbdesc->sta = NULL;
  rt2x00lib_txdone_nomatch(entry, &txdesc);
  rcu_read_unlock();
 } else {
  rt2x00lib_txdone(entry, &txdesc);
 }
}
EXPORT_SYMBOL_GPL(rt2800_txdone_entry);

void rt2800_txdone(struct rt2x00_dev *rt2x00dev, unsigned int quota)
{
 struct data_queue *queue;
 struct queue_entry *entry;
 u32 reg;
 u8 qid;
 bool match;

 while (quota-- > 0 && kfifo_get(&rt2x00dev->txstatus_fifo, ®)) {
  /*
 * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is
 * guaranteed to be one of the TX QIDs .
 */

  qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
  queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);

  if (unlikely(rt2x00queue_empty(queue))) {
   rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
       qid);
   break;
  }

  entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);

  if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
        !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) {
   rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n",
        entry->entry_idx, qid);
   break;
  }

  match = rt2800_txdone_entry_check(entry, reg);
  rt2800_txdone_entry(entry, reg, rt2800_drv_get_txwi(entry), match);
 }
}
EXPORT_SYMBOL_GPL(rt2800_txdone);

static inline bool rt2800_entry_txstatus_timeout(struct rt2x00_dev *rt2x00dev,
       struct queue_entry *entry)
{
 bool ret;
 unsigned long tout;

 if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
  return false;

 if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
  tout = msecs_to_jiffies(50);
 else
  tout = msecs_to_jiffies(2000);

 ret = time_after(jiffies, entry->last_action + tout);
 if (unlikely(ret))
  rt2x00_dbg(entry->queue->rt2x00dev,
      "TX status timeout for entry %d in queue %d\n",
      entry->entry_idx, entry->queue->qid);
 return ret;
}

bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
{
 struct data_queue *queue;
 struct queue_entry *entry;

 tx_queue_for_each(rt2x00dev, queue) {
  entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
  if (rt2800_entry_txstatus_timeout(rt2x00dev, entry))
   return true;
 }

 return false;
}
EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout);

/*
 * test if there is an entry in any TX queue for which DMA is done
 * but the TX status has not been returned yet
 */

bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev)
{
 struct data_queue *queue;

 tx_queue_for_each(rt2x00dev, queue) {
  if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) !=
      rt2x00queue_get_entry(queue, Q_INDEX_DONE))
   return true;
 }
 return false;
}
EXPORT_SYMBOL_GPL(rt2800_txstatus_pending);

void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
{
 struct data_queue *queue;
 struct queue_entry *entry;

 /*
 * Process any trailing TX status reports for IO failures,
 * we loop until we find the first non-IO error entry. This
 * can either be a frame which is free, is being uploaded,
 * or has completed the upload but didn't have an entry
 * in the TX_STAT_FIFO register yet.
 */

 tx_queue_for_each(rt2x00dev, queue) {
  while (!rt2x00queue_empty(queue)) {
   entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);

   if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
       !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
    break;

   if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) ||
       rt2800_entry_txstatus_timeout(rt2x00dev, entry))
    rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
   else
    break;
  }
 }
}
EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus);

static bool rt2800_check_hung(struct data_queue *queue)
{
 unsigned int cur_idx = rt2800_drv_get_dma_done(queue);

 if (queue->wd_idx != cur_idx) {
  queue->wd_idx = cur_idx;
  queue->wd_count = 0;
 } else
  queue->wd_count++;

 return queue->wd_count > 16;
}

static void rt2800_update_survey(struct rt2x00_dev *rt2x00dev)
{
 struct ieee80211_channel *chan = rt2x00dev->hw->conf.chandef.chan;
 struct rt2x00_chan_survey *chan_survey =
     &rt2x00dev->chan_survey[chan->hw_value];

 chan_survey->time_idle += rt2800_register_read(rt2x00dev, CH_IDLE_STA);
 chan_survey->time_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA);
 chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
}

static bool rt2800_watchdog_hung(struct rt2x00_dev *rt2x00dev)
{
 struct data_queue *queue;
 bool hung_tx = false;
 bool hung_rx = false;

 rt2800_update_survey(rt2x00dev);

 queue_for_each(rt2x00dev, queue) {
  switch (queue->qid) {
  case QID_AC_VO:
  case QID_AC_VI:
  case QID_AC_BE:
  case QID_AC_BK:
  case QID_MGMT:
   if (rt2x00queue_empty(queue))
    continue;
   hung_tx = hung_tx || rt2800_check_hung(queue);
   break;
  case QID_RX:
   /* For station mode we should reactive at least
 * beacons. TODO: need to find good way detect
 * RX hung for AP mode.
 */

   if (rt2x00dev->intf_sta_count == 0)
    continue;
   hung_rx = hung_rx || rt2800_check_hung(queue);
   break;
  default:
   break;
  }
 }

 if (!hung_tx && !hung_rx)
  return false;

 if (hung_tx)
  rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n");

 if (hung_rx)
  rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");

 queue_for_each(rt2x00dev, queue)
  queue->wd_count = 0;

 return true;
}

static bool rt2800_watchdog_dma_busy(struct rt2x00_dev *rt2x00dev)
{
 bool busy_rx, busy_tx;
 u32 reg_cfg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG);
 u32 reg_int = rt2800_register_read(rt2x00dev, INT_SOURCE_CSR);

 if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_RX_DMA_BUSY) &&
     rt2x00_get_field32(reg_int, INT_SOURCE_CSR_RX_COHERENT))
  rt2x00dev->rxdma_busy++;
 else
  rt2x00dev->rxdma_busy = 0;

 if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
     rt2x00_get_field32(reg_int, INT_SOURCE_CSR_TX_COHERENT))
  rt2x00dev->txdma_busy++;
 else
  rt2x00dev->txdma_busy = 0;

 busy_rx = rt2x00dev->rxdma_busy > 30;
 busy_tx = rt2x00dev->txdma_busy > 30;

 if (!busy_rx && !busy_tx)
  return false;

 if (busy_rx)
  rt2x00_warn(rt2x00dev, "Watchdog RX DMA busy detected\n");

 if (busy_tx)
  rt2x00_warn(rt2x00dev, "Watchdog TX DMA busy detected\n");

 rt2x00dev->rxdma_busy = 0;
 rt2x00dev->txdma_busy = 0;

 return true;
}

void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
{
 bool reset = false;

 if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
  return;

 if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_DMA_BUSY)
  reset = rt2800_watchdog_dma_busy(rt2x00dev);

 if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_HANG)
  reset = rt2800_watchdog_hung(rt2x00dev) || reset;

 if (reset)
  ieee80211_restart_hw(rt2x00dev->hw);
}
EXPORT_SYMBOL_GPL(rt2800_watchdog);

static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
       unsigned int index)
{
 return HW_BEACON_BASE(index);
}

static inline u8 rt2800_get_beacon_offset(struct rt2x00_dev *rt2x00dev,
       unsigned int index)
{
 return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index));
}

static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev)
{
 struct data_queue *queue = rt2x00dev->bcn;
 struct queue_entry *entry;
 int i, bcn_num = 0;
 u64 off, reg = 0;
 u32 bssid_dw1;

 /*
 * Setup offsets of all active beacons in BCN_OFFSET{0,1} registers.
 */

 for (i = 0; i < queue->limit; i++) {
  entry = &queue->entries[i];
  if (!test_bit(ENTRY_BCN_ENABLED, &entry->flags))
   continue;
  off = rt2800_get_beacon_offset(rt2x00dev, entry->entry_idx);
  reg |= off << (8 * bcn_num);
  bcn_num++;
 }

 rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg);
 rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32));

 /*
 * H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons.
 */

 bssid_dw1 = rt2800_register_read(rt2x00dev, MAC_BSSID_DW1);
 rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM,
      bcn_num > 0 ? bcn_num - 1 : 0);
 rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1);
}

void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
{
 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 unsigned int beacon_base;
 unsigned int padding_len;
 u32 orig_reg, reg;
 const int txwi_desc_size = entry->queue->winfo_size;

 /*
 * Disable beaconing while we are reloading the beacon data,
 * otherwise we might be sending out invalid data.
 */

 reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG);
 orig_reg = reg;
 rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0);
 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);

 /*
 * Add space for the TXWI in front of the skb.
 */

 memset(skb_push(entry->skb, txwi_desc_size), 0, txwi_desc_size);

 /*
 * Register descriptor details in skb frame descriptor.
 */

 skbdesc->flags |= SKBDESC_DESC_IN_SKB;
 skbdesc->desc = entry->skb->data;
 skbdesc->desc_len = txwi_desc_size;

 /*
 * Add the TXWI for the beacon to the skb.
 */

 rt2800_write_tx_data(entry, txdesc);

 /*
 * Dump beacon to userspace through debugfs.
 */

 rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry);

 /*
 * Write entire beacon with TXWI and padding to register.
 */

 padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
 if (padding_len && skb_pad(entry->skb, padding_len)) {
  rt2x00_err(rt2x00dev, "Failure padding beacon, aborting\n");
  /* skb freed by skb_pad() on failure */
  entry->skb = NULL;
  rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
  return;
 }

 beacon_base = rt2800_hw_beacon_base(rt2x00dev, entry->entry_idx);

 rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
       entry->skb->len + padding_len);
 __set_bit(ENTRY_BCN_ENABLED, &entry->flags);

 /*
 * Change global beacons settings.
 */

 rt2800_update_beacons_setup(rt2x00dev);

 /*
 * Restore beaconing state.
 */

 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);

 /*
 * Clean up beacon skb.
 */

 dev_kfree_skb_any(entry->skb);
 entry->skb = NULL;
}
EXPORT_SYMBOL_GPL(rt2800_write_beacon);

static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,
      unsigned int index)
{
 int i;
 const int txwi_desc_size = rt2x00dev->bcn->winfo_size;
 unsigned int beacon_base;

 beacon_base = rt2800_hw_beacon_base(rt2x00dev, index);

 /*
 * For the Beacon base registers we only need to clear
 * the whole TXWI which (when set to 0) will invalidate
 * the entire beacon.
 */

 for (i = 0; i < txwi_desc_size; i += sizeof(__le32))
  rt2800_register_write(rt2x00dev, beacon_base + i, 0);
}

void rt2800_clear_beacon(struct queue_entry *entry)
{
 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
 u32 orig_reg, reg;

 /*
 * Disable beaconing while we are reloading the beacon data,
 * otherwise we might be sending out invalid data.
 */

 orig_reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG);
 reg = orig_reg;
 rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0);
 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);

 /*
 * Clear beacon.
 */

 rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx);
 __clear_bit(ENTRY_BCN_ENABLED, &entry->flags);

 /*
 * Change global beacons settings.
 */

 rt2800_update_beacons_setup(rt2x00dev);
 /*
 * Restore beaconing state.
 */

 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
}
EXPORT_SYMBOL_GPL(rt2800_clear_beacon);

#ifdef CONFIG_RT2X00_LIB_DEBUGFS
const struct rt2x00debug rt2800_rt2x00debug = {
 .owner = THIS_MODULE,
 .csr = {
  .read  = rt2800_register_read,
  .write  = rt2800_register_write,
  .flags  = RT2X00DEBUGFS_OFFSET,
  .word_base = CSR_REG_BASE,
  .word_size = sizeof(u32),
  .word_count = CSR_REG_SIZE / sizeof(u32),
 },
 .eeprom = {
  /* NOTE: The local EEPROM access functions can't
 * be used here, use the generic versions instead.
 */

  .read  = rt2x00_eeprom_read,
  .write  = rt2x00_eeprom_write,
  .word_base = EEPROM_BASE,
  .word_size = sizeof(u16),
  .word_count = EEPROM_SIZE / sizeof(u16),
 },
 .bbp = {
  .read  = rt2800_bbp_read,
  .write  = rt2800_bbp_write,
  .word_base = BBP_BASE,
  .word_size = sizeof(u8),
  .word_count = BBP_SIZE / sizeof(u8),
 },
 .rf = {
  .read  = rt2x00_rf_read,
  .write  = rt2800_rf_write,
  .word_base = RF_BASE,
  .word_size = sizeof(u32),
  .word_count = RF_SIZE / sizeof(u32),
 },
 .rfcsr = {
  .read  = rt2800_rfcsr_read,
  .write  = rt2800_rfcsr_write,
  .word_base = RFCSR_BASE,
  .word_size = sizeof(u8),
  .word_count = RFCSR_SIZE / sizeof(u8),
 },
};
EXPORT_SYMBOL_GPL(rt2800_rt2x00debug);
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */

int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
 u32 reg;

 if (rt2x00_rt(rt2x00dev, RT3290)) {
  reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL);
  return rt2x00_get_field32(reg, WLAN_GPIO_IN_BIT0);
 } else {
  reg = rt2800_register_read(rt2x00dev, GPIO_CTRL);
  return rt2x00_get_field32(reg, GPIO_CTRL_VAL2);
 }
}
EXPORT_SYMBOL_GPL(rt2800_rfkill_poll);

#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2800_brightness_set(struct led_classdev *led_cdev,
      enum led_brightness brightness)
{
 struct rt2x00_led *led =
     container_of(led_cdev, struct rt2x00_led, led_dev);
 unsigned int enabled = brightness != LED_OFF;
 unsigned int bg_mode =
     (enabled && led->rt2x00dev->curr_band == NL80211_BAND_2GHZ);
 unsigned int polarity =
  rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
       EEPROM_FREQ_LED_POLARITY);
 unsigned int ledmode =
  rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
       EEPROM_FREQ_LED_MODE);
 u32 reg;

 /* Check for SoC (SOC devices don't support MCU requests) */
 if (rt2x00_is_soc(led->rt2x00dev)) {
  reg = rt2800_register_read(led->rt2x00dev, LED_CFG);

  /* Set LED Polarity */
  rt2x00_set_field32(®, LED_CFG_LED_POLAR, polarity);

  /* Set LED Mode */
  if (led->type == LED_TYPE_RADIO) {
   rt2x00_set_field32(®, LED_CFG_G_LED_MODE,
        enabled ? 3 : 0);
  } else if (led->type == LED_TYPE_ASSOC) {
   rt2x00_set_field32(®, LED_CFG_Y_LED_MODE,
        enabled ? 3 : 0);
  } else if (led->type == LED_TYPE_QUALITY) {
   rt2x00_set_field32(®, LED_CFG_R_LED_MODE,
        enabled ? 3 : 0);
  }

  rt2800_register_write(led->rt2x00dev, LED_CFG, reg);

 } else {
  if (led->type == LED_TYPE_RADIO) {
   rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
           enabled ? 0x20 : 0);
  } else if (led->type == LED_TYPE_ASSOC) {
   rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
           enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20);
  } else if (led->type == LED_TYPE_QUALITY) {
   /*
 * The brightness is divided into 6 levels (0 - 5),
 * The specs tell us the following levels:
 * 0, 1 ,3, 7, 15, 31
 * to determine the level in a simple way we can simply
 * work with bitshifting:
 * (1 << level) - 1
 */

   rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
           (1 << brightness / (LED_FULL / 6)) - 1,
           polarity);
  }
 }
}

static void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
       struct rt2x00_led *led, enum led_type type)
{
 led->rt2x00dev = rt2x00dev;
 led->type = type;
 led->led_dev.brightness_set = rt2800_brightness_set;
 led->flags = LED_INITIALIZED;
}
#endif /* CONFIG_RT2X00_LIB_LEDS */

/*
 * Configuration handlers.
 */

static void rt2800_config_wcid(struct rt2x00_dev *rt2x00dev,
          const u8 *address,
          int wcid)
{
 struct mac_wcid_entry wcid_entry;
 u32 offset;

 offset = MAC_WCID_ENTRY(wcid);

 memset(&wcid_entry, 0xff, sizeof(wcid_entry));
 if (address)
  memcpy(wcid_entry.mac, address, ETH_ALEN);

 rt2800_register_multiwrite(rt2x00dev, offset,
          &wcid_entry, sizeof(wcid_entry));
}

static void rt2800_delete_wcid_attr(struct rt2x00_dev *rt2x00dev, int wcid)
{
 u32 offset;
 offset = MAC_WCID_ATTR_ENTRY(wcid);
 rt2800_register_write(rt2x00dev, offset, 0);
}

static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev,
        int wcid, u32 bssidx)
{
 u32 offset = MAC_WCID_ATTR_ENTRY(wcid);
 u32 reg;

 /*
 * The BSS Idx numbers is split in a main value of 3 bits,
 * and a extended field for adding one additional bit to the value.
 */

 reg = rt2800_register_read(rt2x00dev, offset);
 rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7));
 rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
      (bssidx & 0x8) >> 3);
 rt2800_register_write(rt2x00dev, offset, reg);
}

static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
        struct rt2x00lib_crypto *crypto,
        struct ieee80211_key_conf *key)
{
 struct mac_iveiv_entry iveiv_entry;
 u32 offset;
 u32 reg;

 offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx);

 if (crypto->cmd == SET_KEY) {
  reg = rt2800_register_read(rt2x00dev, offset);
  rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB,
       !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
  /*
 * Both the cipher as the BSS Idx numbers are split in a main
 * value of 3 bits, and a extended field for adding one additional
 * bit to the value.
 */

  rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER,
       (crypto->cipher & 0x7));
  rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER_EXT,
       (crypto->cipher & 0x8) >> 3);
  rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
  rt2800_register_write(rt2x00dev, offset, reg);
 } else {
  /* Delete the cipher without touching the bssidx */
  reg = rt2800_register_read(rt2x00dev, offset);
  rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, 0);
  rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, 0);
  rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER_EXT, 0);
  rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0);
  rt2800_register_write(rt2x00dev, offset, reg);
 }

 if (test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags))
  return;

 offset = MAC_IVEIV_ENTRY(key->hw_key_idx);

 memset(&iveiv_entry, 0, sizeof(iveiv_entry));
 if ((crypto->cipher == CIPHER_TKIP) ||
     (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
     (crypto->cipher == CIPHER_AES))
  iveiv_entry.iv[3] |= 0x20;
 iveiv_entry.iv[3] |= key->keyidx << 6;
 rt2800_register_multiwrite(rt2x00dev, offset,
       &iveiv_entry, sizeof(iveiv_entry));
}

int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
        struct rt2x00lib_crypto *crypto,
        struct ieee80211_key_conf *key)
{
 struct hw_key_entry key_entry;
 struct rt2x00_field32 field;
 u32 offset;
 u32 reg;

 if (crypto->cmd == SET_KEY) {
  key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx;

  memcpy(key_entry.key, crypto->key,
         sizeof(key_entry.key));
  memcpy(key_entry.tx_mic, crypto->tx_mic,
         sizeof(key_entry.tx_mic));
  memcpy(key_entry.rx_mic, crypto->rx_mic,
         sizeof(key_entry.rx_mic));

  offset = SHARED_KEY_ENTRY(key->hw_key_idx);
  rt2800_register_multiwrite(rt2x00dev, offset,
           &key_entry, sizeof(key_entry));
 }

 /*
 * The cipher types are stored over multiple registers
 * starting with SHARED_KEY_MODE_BASE each word will have
 * 32 bits and contains the cipher types for 2 bssidx each.
 * Using the correct defines correctly will cause overhead,
 * so just calculate the correct offset.
 */

 field.bit_offset = 4 * (key->hw_key_idx % 8);
 field.bit_mask = 0x7 << field.bit_offset;

 offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8);

 reg = rt2800_register_read(rt2x00dev, offset);
 rt2x00_set_field32(®, field,
      (crypto->cmd == SET_KEY) * crypto->cipher);
 rt2800_register_write(rt2x00dev, offset, reg);

 /*
 * Update WCID information
 */

 rt2800_config_wcid(rt2x00dev, crypto->address, key->hw_key_idx);
 rt2800_config_wcid_attr_bssidx(rt2x00dev, key->hw_key_idx,
           crypto->bssidx);
 rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key);

 return 0;
}
EXPORT_SYMBOL_GPL(rt2800_config_shared_key);

int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
          struct rt2x00lib_crypto *crypto,
          struct ieee80211_key_conf *key)
{
 struct hw_key_entry key_entry;
 u32 offset;

 if (crypto->cmd == SET_KEY) {
  /*
 * Allow key configuration only for STAs that are
 * known by the hw.
 */

  if (crypto->wcid > WCID_END)
   return -ENOSPC;
  key->hw_key_idx = crypto->wcid;

  memcpy(key_entry.key, crypto->key,
         sizeof(key_entry.key));
  memcpy(key_entry.tx_mic, crypto->tx_mic,
         sizeof(key_entry.tx_mic));
  memcpy(key_entry.rx_mic, crypto->rx_mic,
         sizeof(key_entry.rx_mic));

  offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
  rt2800_register_multiwrite(rt2x00dev, offset,
           &key_entry, sizeof(key_entry));
 }

 /*
 * Update WCID information
 */

 rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key);

 return 0;
}
EXPORT_SYMBOL_GPL(rt2800_config_pairwise_key);

static void rt2800_set_max_psdu_len(struct rt2x00_dev *rt2x00dev)
{
 u8 i, max_psdu;
 u32 reg;
 struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;

 for (i = 0; i < 3; i++)
  if (drv_data->ampdu_factor_cnt[i] > 0)
   break;

 max_psdu = min(drv_data->max_psdu, i);

 reg = rt2800_register_read(rt2x00dev, MAX_LEN_CFG);
 rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, max_psdu);
 rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg);
}

int rt2800_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
     struct ieee80211_sta *sta)
{
 struct rt2x00_dev *rt2x00dev = hw->priv;
 struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
 struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
 int wcid;

 /*
 * Limit global maximum TX AMPDU length to smallest value of all
 * connected stations. In AP mode this can be suboptimal, but we
 * do not have a choice if some connected STA is not capable to
 * receive the same amount of data like the others.
 */

 if (sta->deflink.ht_cap.ht_supported) {
  drv_data->ampdu_factor_cnt[sta->deflink.ht_cap.ampdu_factor & 3]++;
  rt2800_set_max_psdu_len(rt2x00dev);
 }

 /*
 * Search for the first free WCID entry and return the corresponding
 * index.
 */

 wcid = find_first_zero_bit(drv_data->sta_ids, STA_IDS_SIZE) + WCID_START;

 /*
 * Store selected wcid even if it is invalid so that we can
 * later decide if the STA is uploaded into the hw.
 */

 sta_priv->wcid = wcid;

 /*
 * No space left in the device, however, we can still communicate
 * with the STA -> No error.
 */

 if (wcid > WCID_END)
  return 0;

 __set_bit(wcid - WCID_START, drv_data->sta_ids);
 drv_data->wcid_to_sta[wcid - WCID_START] = sta;

 /*
 * Clean up WCID attributes and write STA address to the device.
 */

 rt2800_delete_wcid_attr(rt2x00dev, wcid);
 rt2800_config_wcid(rt2x00dev, sta->addr, wcid);
 rt2800_config_wcid_attr_bssidx(rt2x00dev, wcid,
           rt2x00lib_get_bssidx(rt2x00dev, vif));
 return 0;
}
EXPORT_SYMBOL_GPL(rt2800_sta_add);

int rt2800_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        struct ieee80211_sta *sta)
{
 struct rt2x00_dev *rt2x00dev = hw->priv;
 struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
 struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
 int wcid = sta_priv->wcid;

 if (sta->deflink.ht_cap.ht_supported) {
  drv_data->ampdu_factor_cnt[sta->deflink.ht_cap.ampdu_factor & 3]--;
  rt2800_set_max_psdu_len(rt2x00dev);
 }

 if (wcid > WCID_END)
  return 0;
 /*
 * Remove WCID entry, no need to clean the attributes as they will
 * get renewed when the WCID is reused.
 */

 rt2800_config_wcid(rt2x00dev, NULL, wcid);
 drv_data->wcid_to_sta[wcid - WCID_START] = NULL;
 __clear_bit(wcid - WCID_START, drv_data->sta_ids);

 return 0;
}
EXPORT_SYMBOL_GPL(rt2800_sta_remove);

void rt2800_pre_reset_hw(struct rt2x00_dev *rt2x00dev)
{
 struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
 struct data_queue *queue = rt2x00dev->bcn;
 struct queue_entry *entry;
 int i, wcid;

 for (wcid = WCID_START; wcid < WCID_END; wcid++) {
  drv_data->wcid_to_sta[wcid - WCID_START] = NULL;
  __clear_bit(wcid - WCID_START, drv_data->sta_ids);
 }

 for (i = 0; i < queue->limit; i++) {
  entry = &queue->entries[i];
  clear_bit(ENTRY_BCN_ASSIGNED, &entry->flags);
 }
}
EXPORT_SYMBOL_GPL(rt2800_pre_reset_hw);

void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
     const unsigned int filter_flags)
{
 u32 reg;

 /*
 * Start configuration steps.
 * Note that the version error will always be dropped
 * and broadcast frames will always be accepted since
 * there is no filter for it at this time.
 */

 reg = rt2800_register_read(rt2x00dev, RX_FILTER_CFG);
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR,
      !(filter_flags & FIF_FCSFAIL));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR,
      !(filter_flags & FIF_PLCPFAIL));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME,
      !test_bit(CONFIG_MONITORING, &rt2x00dev->flags));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1);
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST,
      !(filter_flags & FIF_ALLMULTI));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BROADCAST, 0);
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_DUPLICATE, 1);
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END_ACK,
      !(filter_flags & FIF_CONTROL));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END,
      !(filter_flags & FIF_CONTROL));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_ACK,
      !(filter_flags & FIF_CONTROL));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CTS,
      !(filter_flags & FIF_CONTROL));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS,
      !(filter_flags & FIF_CONTROL));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL,
      !(filter_flags & FIF_PSPOLL));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 0);
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR,
      !(filter_flags & FIF_CONTROL));
 rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL,
      !(filter_flags & FIF_CONTROL));
 rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg);
}
EXPORT_SYMBOL_GPL(rt2800_config_filter);

void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
   struct rt2x00intf_conf *conf, const unsigned int flags)
{
 u32 reg;
 bool update_bssid = false;

 if (flags & CONFIG_UPDATE_TYPE) {
  /*
 * Enable synchronisation.
 */

  reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG);
  rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync);
  rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);

  if (conf->sync == TSF_SYNC_AP_NONE) {
   /*
 * Tune beacon queue transmit parameters for AP mode
 */

   reg = rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG);
   rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 0);
   rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 1);
   rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32);
   rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 0);
   rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg);
  } else {
   reg = rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG);
   rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 4);
   rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 2);
   rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32);
   rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 16);
   rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg);
  }
 }

 if (flags & CONFIG_UPDATE_MAC) {
  if (flags & CONFIG_UPDATE_TYPE &&
      conf->sync == TSF_SYNC_AP_NONE) {
   /*
 * The BSSID register has to be set to our own mac
 * address in AP mode.
 */

   memcpy(conf->bssid, conf->mac, sizeof(conf->mac));
   update_bssid = true;
  }

  if (!is_zero_ether_addr((const u8 *)conf->mac)) {
   reg = le32_to_cpu(conf->mac[1]);
   rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
   conf->mac[1] = cpu_to_le32(reg);
  }

  rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0,
           conf->mac, sizeof(conf->mac));
 }

 if ((flags & CONFIG_UPDATE_BSSID) || update_bssid) {
  if (!is_zero_ether_addr((const u8 *)conf->bssid)) {
   reg = le32_to_cpu(conf->bssid[1]);
   rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3);
   rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0);
   conf->bssid[1] = cpu_to_le32(reg);
  }

  rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
           conf->bssid, sizeof(conf->bssid));
 }
}
EXPORT_SYMBOL_GPL(rt2800_config_intf);

static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev,
        struct rt2x00lib_erp *erp)
{
 bool any_sta_nongf = !!(erp->ht_opmode &
    IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
 u8 protection = erp->ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION;
 u8 mm20_mode, mm40_mode, gf20_mode, gf40_mode;
 u16 mm20_rate, mm40_rate, gf20_rate, gf40_rate;
 u32 reg;

 /* default protection rate for HT20: OFDM 24M */
 mm20_rate = gf20_rate = 0x4004;

 /* default protection rate for HT40: duplicate OFDM 24M */
 mm40_rate = gf40_rate = 0x4084;

 switch (protection) {
 case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
  /*
 * All STAs in this BSS are HT20/40 but there might be
 * STAs not supporting greenfield mode.
 * => Disable protection for HT transmissions.
 */

  mm20_mode = mm40_mode = gf20_mode = gf40_mode = 0;

  break;
 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
  /*
 * All STAs in this BSS are HT20 or HT20/40 but there
 * might be STAs not supporting greenfield mode.
 * => Protect all HT40 transmissions.
 */

  mm20_mode = gf20_mode = 0;
  mm40_mode = gf40_mode = 1;

  break;
 case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
  /*
 * Nonmember protection:
 * According to 802.11n we _should_ protect all
 * HT transmissions (but we don't have to).
 *
 * But if cts_protection is enabled we _shall_ protect
 * all HT transmissions using a CCK rate.
 *
 * And if any station is non GF we _shall_ protect
 * GF transmissions.
 *
 * We decide to protect everything
 * -> fall through to mixed mode.
 */

 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
  /*
 * Legacy STAs are present
 * => Protect all HT transmissions.
 */

  mm20_mode = mm40_mode = gf20_mode = gf40_mode = 1;

  /*
 * If erp protection is needed we have to protect HT
 * transmissions with CCK 11M long preamble.
 */

  if (erp->cts_protection) {
   /* don't duplicate RTS/CTS in CCK mode */
   mm20_rate = mm40_rate = 0x0003;
   gf20_rate = gf40_rate = 0x0003;
  }
  break;
 }

 /* check for STAs not supporting greenfield mode */
 if (any_sta_nongf)
  gf20_mode = gf40_mode = 1;

 /* Update HT protection config */
 reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG);
 rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, mm20_rate);
 rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, mm20_mode);
 rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg);

 reg = rt2800_register_read(rt2x00dev, MM40_PROT_CFG);
 rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, mm40_rate);
 rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, mm40_mode);
 rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg);

 reg = rt2800_register_read(rt2x00dev, GF20_PROT_CFG);
 rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, gf20_rate);
 rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, gf20_mode);
 rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg);

 reg = rt2800_register_read(rt2x00dev, GF40_PROT_CFG);
 rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, gf40_rate);
 rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, gf40_mode);
 rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
}

void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp,
         u32 changed)
{
 u32 reg;

 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
  reg = rt2800_register_read(rt2x00dev, AUTO_RSP_CFG);
  rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE,
       !!erp->short_preamble);
  rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
 }

 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
  reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG);
  rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL,
       erp->cts_protection ? 2 : 0);
  rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
 }

 if (changed & BSS_CHANGED_BASIC_RATES) {
  rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE,
          0xff0 | erp->basic_rates);
  rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
 }

 if (changed & BSS_CHANGED_ERP_SLOT) {
  reg = rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG);
  rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME,
       erp->slot_time);
  rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);

  reg = rt2800_register_read(rt2x00dev, XIFS_TIME_CFG);
  rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs);
  rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
 }

 if (changed & BSS_CHANGED_BEACON_INT) {
  reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG);
  rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL,
       erp->beacon_int * 16);
  rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 }

 if (changed & BSS_CHANGED_HT)
  rt2800_config_ht_opmode(rt2x00dev, erp);
}
EXPORT_SYMBOL_GPL(rt2800_config_erp);

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=97 G=94

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.