162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> 462306a36Sopenharmony_ci <http://rt2x00.serialmonkey.com> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci Module: rt61pci 1062306a36Sopenharmony_ci Abstract: rt61pci device specific routines. 1162306a36Sopenharmony_ci Supported chipsets: RT2561, RT2561s, RT2661. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/crc-itu-t.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/etherdevice.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/pci.h> 2162306a36Sopenharmony_ci#include <linux/eeprom_93cx6.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "rt2x00.h" 2462306a36Sopenharmony_ci#include "rt2x00mmio.h" 2562306a36Sopenharmony_ci#include "rt2x00pci.h" 2662306a36Sopenharmony_ci#include "rt61pci.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * Allow hardware encryption to be disabled. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_cistatic bool modparam_nohwcrypt = false; 3262306a36Sopenharmony_cimodule_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); 3362306a36Sopenharmony_ciMODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * Register access. 3762306a36Sopenharmony_ci * BBP and RF register require indirect register access, 3862306a36Sopenharmony_ci * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this. 3962306a36Sopenharmony_ci * These indirect registers work with busy bits, 4062306a36Sopenharmony_ci * and we will try maximal REGISTER_BUSY_COUNT times to access 4162306a36Sopenharmony_ci * the register while taking a REGISTER_BUSY_DELAY us delay 4262306a36Sopenharmony_ci * between each attempt. When the busy bit is still set at that time, 4362306a36Sopenharmony_ci * the access attempt is considered to have failed, 4462306a36Sopenharmony_ci * and we will print an error. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci#define WAIT_FOR_BBP(__dev, __reg) \ 4762306a36Sopenharmony_ci rt2x00mmio_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) 4862306a36Sopenharmony_ci#define WAIT_FOR_RF(__dev, __reg) \ 4962306a36Sopenharmony_ci rt2x00mmio_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) 5062306a36Sopenharmony_ci#define WAIT_FOR_MCU(__dev, __reg) \ 5162306a36Sopenharmony_ci rt2x00mmio_regbusy_read((__dev), H2M_MAILBOX_CSR, \ 5262306a36Sopenharmony_ci H2M_MAILBOX_CSR_OWNER, (__reg)) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, 5562306a36Sopenharmony_ci const unsigned int word, const u8 value) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci u32 reg; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* 6262306a36Sopenharmony_ci * Wait until the BBP becomes available, afterwards we 6362306a36Sopenharmony_ci * can safely write the new data into the register. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci if (WAIT_FOR_BBP(rt2x00dev, ®)) { 6662306a36Sopenharmony_ci reg = 0; 6762306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_VALUE, value); 6862306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); 6962306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); 7062306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR3, reg); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic u8 rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, 7962306a36Sopenharmony_ci const unsigned int word) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci u32 reg; 8262306a36Sopenharmony_ci u8 value; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * Wait until the BBP becomes available, afterwards we 8862306a36Sopenharmony_ci * can safely write the read request into the register. 8962306a36Sopenharmony_ci * After the data has been written, we wait until hardware 9062306a36Sopenharmony_ci * returns the correct value, if at any time the register 9162306a36Sopenharmony_ci * doesn't become available in time, reg will be 0xffffffff 9262306a36Sopenharmony_ci * which means we return 0xff to the caller. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci if (WAIT_FOR_BBP(rt2x00dev, ®)) { 9562306a36Sopenharmony_ci reg = 0; 9662306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); 9762306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); 9862306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR3, reg); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci WAIT_FOR_BBP(rt2x00dev, ®); 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return value; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, 11362306a36Sopenharmony_ci const unsigned int word, const u32 value) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci u32 reg; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* 12062306a36Sopenharmony_ci * Wait until the RF becomes available, afterwards we 12162306a36Sopenharmony_ci * can safely write the new data into the register. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci if (WAIT_FOR_RF(rt2x00dev, ®)) { 12462306a36Sopenharmony_ci reg = 0; 12562306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR4_VALUE, value); 12662306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); 12762306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); 12862306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR4, reg); 13162306a36Sopenharmony_ci rt2x00_rf_write(rt2x00dev, word, value); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, 13862306a36Sopenharmony_ci const u8 command, const u8 token, 13962306a36Sopenharmony_ci const u8 arg0, const u8 arg1) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci u32 reg; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* 14662306a36Sopenharmony_ci * Wait until the MCU becomes available, afterwards we 14762306a36Sopenharmony_ci * can safely write the new data into the register. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci if (WAIT_FOR_MCU(rt2x00dev, ®)) { 15062306a36Sopenharmony_ci rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); 15162306a36Sopenharmony_ci rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); 15262306a36Sopenharmony_ci rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); 15362306a36Sopenharmony_ci rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); 15462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, HOST_CMD_CSR); 15762306a36Sopenharmony_ci rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); 15862306a36Sopenharmony_ci rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); 15962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, reg); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = eeprom->data; 16962306a36Sopenharmony_ci u32 reg; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); 17462306a36Sopenharmony_ci eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); 17562306a36Sopenharmony_ci eeprom->reg_data_clock = 17662306a36Sopenharmony_ci !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK); 17762306a36Sopenharmony_ci eeprom->reg_chip_select = 17862306a36Sopenharmony_ci !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = eeprom->data; 18462306a36Sopenharmony_ci u32 reg = 0; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci rt2x00_set_field32(®, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in); 18762306a36Sopenharmony_ci rt2x00_set_field32(®, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out); 18862306a36Sopenharmony_ci rt2x00_set_field32(®, E2PROM_CSR_DATA_CLOCK, 18962306a36Sopenharmony_ci !!eeprom->reg_data_clock); 19062306a36Sopenharmony_ci rt2x00_set_field32(®, E2PROM_CSR_CHIP_SELECT, 19162306a36Sopenharmony_ci !!eeprom->reg_chip_select); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, E2PROM_CSR, reg); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_DEBUGFS 19762306a36Sopenharmony_cistatic const struct rt2x00debug rt61pci_rt2x00debug = { 19862306a36Sopenharmony_ci .owner = THIS_MODULE, 19962306a36Sopenharmony_ci .csr = { 20062306a36Sopenharmony_ci .read = rt2x00mmio_register_read, 20162306a36Sopenharmony_ci .write = rt2x00mmio_register_write, 20262306a36Sopenharmony_ci .flags = RT2X00DEBUGFS_OFFSET, 20362306a36Sopenharmony_ci .word_base = CSR_REG_BASE, 20462306a36Sopenharmony_ci .word_size = sizeof(u32), 20562306a36Sopenharmony_ci .word_count = CSR_REG_SIZE / sizeof(u32), 20662306a36Sopenharmony_ci }, 20762306a36Sopenharmony_ci .eeprom = { 20862306a36Sopenharmony_ci .read = rt2x00_eeprom_read, 20962306a36Sopenharmony_ci .write = rt2x00_eeprom_write, 21062306a36Sopenharmony_ci .word_base = EEPROM_BASE, 21162306a36Sopenharmony_ci .word_size = sizeof(u16), 21262306a36Sopenharmony_ci .word_count = EEPROM_SIZE / sizeof(u16), 21362306a36Sopenharmony_ci }, 21462306a36Sopenharmony_ci .bbp = { 21562306a36Sopenharmony_ci .read = rt61pci_bbp_read, 21662306a36Sopenharmony_ci .write = rt61pci_bbp_write, 21762306a36Sopenharmony_ci .word_base = BBP_BASE, 21862306a36Sopenharmony_ci .word_size = sizeof(u8), 21962306a36Sopenharmony_ci .word_count = BBP_SIZE / sizeof(u8), 22062306a36Sopenharmony_ci }, 22162306a36Sopenharmony_ci .rf = { 22262306a36Sopenharmony_ci .read = rt2x00_rf_read, 22362306a36Sopenharmony_ci .write = rt61pci_rf_write, 22462306a36Sopenharmony_ci .word_base = RF_BASE, 22562306a36Sopenharmony_ci .word_size = sizeof(u32), 22662306a36Sopenharmony_ci .word_count = RF_SIZE / sizeof(u32), 22762306a36Sopenharmony_ci }, 22862306a36Sopenharmony_ci}; 22962306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci u32 reg; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); 23662306a36Sopenharmony_ci return rt2x00_get_field32(reg, MAC_CSR13_VAL5); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_LEDS 24062306a36Sopenharmony_cistatic void rt61pci_brightness_set(struct led_classdev *led_cdev, 24162306a36Sopenharmony_ci enum led_brightness brightness) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct rt2x00_led *led = 24462306a36Sopenharmony_ci container_of(led_cdev, struct rt2x00_led, led_dev); 24562306a36Sopenharmony_ci unsigned int enabled = brightness != LED_OFF; 24662306a36Sopenharmony_ci unsigned int a_mode = 24762306a36Sopenharmony_ci (enabled && led->rt2x00dev->curr_band == NL80211_BAND_5GHZ); 24862306a36Sopenharmony_ci unsigned int bg_mode = 24962306a36Sopenharmony_ci (enabled && led->rt2x00dev->curr_band == NL80211_BAND_2GHZ); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (led->type == LED_TYPE_RADIO) { 25262306a36Sopenharmony_ci rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, 25362306a36Sopenharmony_ci MCU_LEDCS_RADIO_STATUS, enabled); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, 25662306a36Sopenharmony_ci (led->rt2x00dev->led_mcu_reg & 0xff), 25762306a36Sopenharmony_ci ((led->rt2x00dev->led_mcu_reg >> 8))); 25862306a36Sopenharmony_ci } else if (led->type == LED_TYPE_ASSOC) { 25962306a36Sopenharmony_ci rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, 26062306a36Sopenharmony_ci MCU_LEDCS_LINK_BG_STATUS, bg_mode); 26162306a36Sopenharmony_ci rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg, 26262306a36Sopenharmony_ci MCU_LEDCS_LINK_A_STATUS, a_mode); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci rt61pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, 26562306a36Sopenharmony_ci (led->rt2x00dev->led_mcu_reg & 0xff), 26662306a36Sopenharmony_ci ((led->rt2x00dev->led_mcu_reg >> 8))); 26762306a36Sopenharmony_ci } else if (led->type == LED_TYPE_QUALITY) { 26862306a36Sopenharmony_ci /* 26962306a36Sopenharmony_ci * The brightness is divided into 6 levels (0 - 5), 27062306a36Sopenharmony_ci * this means we need to convert the brightness 27162306a36Sopenharmony_ci * argument into the matching level within that range. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci rt61pci_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, 27462306a36Sopenharmony_ci brightness / (LED_FULL / 6), 0); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int rt61pci_blink_set(struct led_classdev *led_cdev, 27962306a36Sopenharmony_ci unsigned long *delay_on, 28062306a36Sopenharmony_ci unsigned long *delay_off) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct rt2x00_led *led = 28362306a36Sopenharmony_ci container_of(led_cdev, struct rt2x00_led, led_dev); 28462306a36Sopenharmony_ci u32 reg; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(led->rt2x00dev, MAC_CSR14); 28762306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); 28862306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); 28962306a36Sopenharmony_ci rt2x00mmio_register_write(led->rt2x00dev, MAC_CSR14, reg); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void rt61pci_init_led(struct rt2x00_dev *rt2x00dev, 29562306a36Sopenharmony_ci struct rt2x00_led *led, 29662306a36Sopenharmony_ci enum led_type type) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci led->rt2x00dev = rt2x00dev; 29962306a36Sopenharmony_ci led->type = type; 30062306a36Sopenharmony_ci led->led_dev.brightness_set = rt61pci_brightness_set; 30162306a36Sopenharmony_ci led->led_dev.blink_set = rt61pci_blink_set; 30262306a36Sopenharmony_ci led->flags = LED_INITIALIZED; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_LEDS */ 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/* 30762306a36Sopenharmony_ci * Configuration handlers. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_cistatic int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, 31062306a36Sopenharmony_ci struct rt2x00lib_crypto *crypto, 31162306a36Sopenharmony_ci struct ieee80211_key_conf *key) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci /* 31462306a36Sopenharmony_ci * Let the software handle the shared keys, 31562306a36Sopenharmony_ci * since the hardware decryption does not work reliably, 31662306a36Sopenharmony_ci * because the firmware does not know the key's keyidx. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci return -EOPNOTSUPP; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, 32262306a36Sopenharmony_ci struct rt2x00lib_crypto *crypto, 32362306a36Sopenharmony_ci struct ieee80211_key_conf *key) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct hw_pairwise_ta_entry addr_entry; 32662306a36Sopenharmony_ci struct hw_key_entry key_entry; 32762306a36Sopenharmony_ci u32 mask; 32862306a36Sopenharmony_ci u32 reg; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (crypto->cmd == SET_KEY) { 33162306a36Sopenharmony_ci /* 33262306a36Sopenharmony_ci * rt2x00lib can't determine the correct free 33362306a36Sopenharmony_ci * key_idx for pairwise keys. We have 2 registers 33462306a36Sopenharmony_ci * with key valid bits. The goal is simple: read 33562306a36Sopenharmony_ci * the first register. If that is full, move to 33662306a36Sopenharmony_ci * the next register. 33762306a36Sopenharmony_ci * When both registers are full, we drop the key. 33862306a36Sopenharmony_ci * Otherwise, we use the first invalid entry. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2); 34162306a36Sopenharmony_ci if (reg && reg == ~0) { 34262306a36Sopenharmony_ci key->hw_key_idx = 32; 34362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3); 34462306a36Sopenharmony_ci if (reg && reg == ~0) 34562306a36Sopenharmony_ci return -ENOSPC; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci key->hw_key_idx += reg ? ffz(reg) : 0; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* 35162306a36Sopenharmony_ci * Upload key to hardware 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci memcpy(key_entry.key, crypto->key, 35462306a36Sopenharmony_ci sizeof(key_entry.key)); 35562306a36Sopenharmony_ci memcpy(key_entry.tx_mic, crypto->tx_mic, 35662306a36Sopenharmony_ci sizeof(key_entry.tx_mic)); 35762306a36Sopenharmony_ci memcpy(key_entry.rx_mic, crypto->rx_mic, 35862306a36Sopenharmony_ci sizeof(key_entry.rx_mic)); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci memset(&addr_entry, 0, sizeof(addr_entry)); 36162306a36Sopenharmony_ci memcpy(&addr_entry, crypto->address, ETH_ALEN); 36262306a36Sopenharmony_ci addr_entry.cipher = crypto->cipher; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx); 36562306a36Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, reg, 36662306a36Sopenharmony_ci &key_entry, sizeof(key_entry)); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); 36962306a36Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, reg, 37062306a36Sopenharmony_ci &addr_entry, sizeof(addr_entry)); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * Enable pairwise lookup table for given BSS idx. 37462306a36Sopenharmony_ci * Without this, received frames will not be decrypted 37562306a36Sopenharmony_ci * by the hardware. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR4); 37862306a36Sopenharmony_ci reg |= (1 << crypto->bssidx); 37962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR4, reg); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* 38262306a36Sopenharmony_ci * The driver does not support the IV/EIV generation 38362306a36Sopenharmony_ci * in hardware. However it doesn't support the IV/EIV 38462306a36Sopenharmony_ci * inside the ieee80211 frame either, but requires it 38562306a36Sopenharmony_ci * to be provided separately for the descriptor. 38662306a36Sopenharmony_ci * rt2x00lib will cut the IV/EIV data out of all frames 38762306a36Sopenharmony_ci * given to us by mac80211, but we must tell mac80211 38862306a36Sopenharmony_ci * to generate the IV/EIV data. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* 39462306a36Sopenharmony_ci * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate 39562306a36Sopenharmony_ci * a particular key is valid. Because using the FIELD32() 39662306a36Sopenharmony_ci * defines directly will cause a lot of overhead, we use 39762306a36Sopenharmony_ci * a calculation to determine the correct bit directly. 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci if (key->hw_key_idx < 32) { 40062306a36Sopenharmony_ci mask = 1 << key->hw_key_idx; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2); 40362306a36Sopenharmony_ci if (crypto->cmd == SET_KEY) 40462306a36Sopenharmony_ci reg |= mask; 40562306a36Sopenharmony_ci else if (crypto->cmd == DISABLE_KEY) 40662306a36Sopenharmony_ci reg &= ~mask; 40762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR2, reg); 40862306a36Sopenharmony_ci } else { 40962306a36Sopenharmony_ci mask = 1 << (key->hw_key_idx - 32); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3); 41262306a36Sopenharmony_ci if (crypto->cmd == SET_KEY) 41362306a36Sopenharmony_ci reg |= mask; 41462306a36Sopenharmony_ci else if (crypto->cmd == DISABLE_KEY) 41562306a36Sopenharmony_ci reg &= ~mask; 41662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR3, reg); 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, 42362306a36Sopenharmony_ci const unsigned int filter_flags) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci u32 reg; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* 42862306a36Sopenharmony_ci * Start configuration steps. 42962306a36Sopenharmony_ci * Note that the version error will always be dropped 43062306a36Sopenharmony_ci * and broadcast frames will always be accepted since 43162306a36Sopenharmony_ci * there is no filter for it at this time. 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 43462306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 43562306a36Sopenharmony_ci !(filter_flags & FIF_FCSFAIL)); 43662306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 43762306a36Sopenharmony_ci !(filter_flags & FIF_PLCPFAIL)); 43862306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 43962306a36Sopenharmony_ci !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); 44062306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 44162306a36Sopenharmony_ci !test_bit(CONFIG_MONITORING, &rt2x00dev->flags)); 44262306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 44362306a36Sopenharmony_ci !test_bit(CONFIG_MONITORING, &rt2x00dev->flags) && 44462306a36Sopenharmony_ci !rt2x00dev->intf_ap_count); 44562306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); 44662306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, 44762306a36Sopenharmony_ci !(filter_flags & FIF_ALLMULTI)); 44862306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); 44962306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 45062306a36Sopenharmony_ci !(filter_flags & FIF_CONTROL)); 45162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, 45562306a36Sopenharmony_ci struct rt2x00_intf *intf, 45662306a36Sopenharmony_ci struct rt2x00intf_conf *conf, 45762306a36Sopenharmony_ci const unsigned int flags) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci u32 reg; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (flags & CONFIG_UPDATE_TYPE) { 46262306a36Sopenharmony_ci /* 46362306a36Sopenharmony_ci * Enable synchronisation. 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 46662306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); 46762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (flags & CONFIG_UPDATE_MAC) { 47162306a36Sopenharmony_ci reg = le32_to_cpu(conf->mac[1]); 47262306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); 47362306a36Sopenharmony_ci conf->mac[1] = cpu_to_le32(reg); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, MAC_CSR2, 47662306a36Sopenharmony_ci conf->mac, sizeof(conf->mac)); 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (flags & CONFIG_UPDATE_BSSID) { 48062306a36Sopenharmony_ci reg = le32_to_cpu(conf->bssid[1]); 48162306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR5_BSS_ID_MASK, 3); 48262306a36Sopenharmony_ci conf->bssid[1] = cpu_to_le32(reg); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, MAC_CSR4, 48562306a36Sopenharmony_ci conf->bssid, 48662306a36Sopenharmony_ci sizeof(conf->bssid)); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, 49162306a36Sopenharmony_ci struct rt2x00lib_erp *erp, 49262306a36Sopenharmony_ci u32 changed) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci u32 reg; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 49762306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); 49862306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); 49962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_PREAMBLE) { 50262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4); 50362306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); 50462306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 50562306a36Sopenharmony_ci !!erp->short_preamble); 50662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR4, reg); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (changed & BSS_CHANGED_BASIC_RATES) 51062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR5, 51162306a36Sopenharmony_ci erp->basic_rates); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_INT) { 51462306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 51562306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 51662306a36Sopenharmony_ci erp->beacon_int * 16); 51762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) { 52162306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9); 52262306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); 52362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR8); 52662306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); 52762306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); 52862306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); 52962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR8, reg); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, 53462306a36Sopenharmony_ci struct antenna_setup *ant) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci u8 r3; 53762306a36Sopenharmony_ci u8 r4; 53862306a36Sopenharmony_ci u8 r77; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci r3 = rt61pci_bbp_read(rt2x00dev, 3); 54162306a36Sopenharmony_ci r4 = rt61pci_bbp_read(rt2x00dev, 4); 54262306a36Sopenharmony_ci r77 = rt61pci_bbp_read(rt2x00dev, 77); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325)); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* 54762306a36Sopenharmony_ci * Configure the RX antenna. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_ci switch (ant->rx) { 55062306a36Sopenharmony_ci case ANTENNA_HW_DIVERSITY: 55162306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); 55262306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 55362306a36Sopenharmony_ci (rt2x00dev->curr_band != NL80211_BAND_5GHZ)); 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci case ANTENNA_A: 55662306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 55762306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); 55862306a36Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) 55962306a36Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); 56062306a36Sopenharmony_ci else 56162306a36Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); 56262306a36Sopenharmony_ci break; 56362306a36Sopenharmony_ci case ANTENNA_B: 56462306a36Sopenharmony_ci default: 56562306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 56662306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); 56762306a36Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) 56862306a36Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); 56962306a36Sopenharmony_ci else 57062306a36Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); 57162306a36Sopenharmony_ci break; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 77, r77); 57562306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, r3); 57662306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 4, r4); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, 58062306a36Sopenharmony_ci struct antenna_setup *ant) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci u8 r3; 58362306a36Sopenharmony_ci u8 r4; 58462306a36Sopenharmony_ci u8 r77; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci r3 = rt61pci_bbp_read(rt2x00dev, 3); 58762306a36Sopenharmony_ci r4 = rt61pci_bbp_read(rt2x00dev, 4); 58862306a36Sopenharmony_ci r77 = rt61pci_bbp_read(rt2x00dev, 77); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); 59162306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 59262306a36Sopenharmony_ci !rt2x00_has_cap_frame_type(rt2x00dev)); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* 59562306a36Sopenharmony_ci * Configure the RX antenna. 59662306a36Sopenharmony_ci */ 59762306a36Sopenharmony_ci switch (ant->rx) { 59862306a36Sopenharmony_ci case ANTENNA_HW_DIVERSITY: 59962306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci case ANTENNA_A: 60262306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 60362306a36Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci case ANTENNA_B: 60662306a36Sopenharmony_ci default: 60762306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 60862306a36Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 77, r77); 61362306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, r3); 61462306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 4, r4); 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev, 61862306a36Sopenharmony_ci const int p1, const int p2) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci u32 reg; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_DIR4, 0); 62562306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_VAL4, p1); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_DIR3, 0); 62862306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_VAL3, !p2); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg); 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, 63462306a36Sopenharmony_ci struct antenna_setup *ant) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci u8 r3; 63762306a36Sopenharmony_ci u8 r4; 63862306a36Sopenharmony_ci u8 r77; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci r3 = rt61pci_bbp_read(rt2x00dev, 3); 64162306a36Sopenharmony_ci r4 = rt61pci_bbp_read(rt2x00dev, 4); 64262306a36Sopenharmony_ci r77 = rt61pci_bbp_read(rt2x00dev, 77); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* 64562306a36Sopenharmony_ci * Configure the RX antenna. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ci switch (ant->rx) { 64862306a36Sopenharmony_ci case ANTENNA_A: 64962306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 65062306a36Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); 65162306a36Sopenharmony_ci rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci case ANTENNA_HW_DIVERSITY: 65462306a36Sopenharmony_ci /* 65562306a36Sopenharmony_ci * FIXME: Antenna selection for the rf 2529 is very confusing 65662306a36Sopenharmony_ci * in the legacy driver. Just default to antenna B until the 65762306a36Sopenharmony_ci * legacy code can be properly translated into rt2x00 code. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_ci case ANTENNA_B: 66062306a36Sopenharmony_ci default: 66162306a36Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 66262306a36Sopenharmony_ci rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); 66362306a36Sopenharmony_ci rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 77, r77); 66862306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, r3); 66962306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 4, r4); 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistruct antenna_sel { 67362306a36Sopenharmony_ci u8 word; 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * value[0] -> non-LNA 67662306a36Sopenharmony_ci * value[1] -> LNA 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci u8 value[2]; 67962306a36Sopenharmony_ci}; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic const struct antenna_sel antenna_sel_a[] = { 68262306a36Sopenharmony_ci { 96, { 0x58, 0x78 } }, 68362306a36Sopenharmony_ci { 104, { 0x38, 0x48 } }, 68462306a36Sopenharmony_ci { 75, { 0xfe, 0x80 } }, 68562306a36Sopenharmony_ci { 86, { 0xfe, 0x80 } }, 68662306a36Sopenharmony_ci { 88, { 0xfe, 0x80 } }, 68762306a36Sopenharmony_ci { 35, { 0x60, 0x60 } }, 68862306a36Sopenharmony_ci { 97, { 0x58, 0x58 } }, 68962306a36Sopenharmony_ci { 98, { 0x58, 0x58 } }, 69062306a36Sopenharmony_ci}; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic const struct antenna_sel antenna_sel_bg[] = { 69362306a36Sopenharmony_ci { 96, { 0x48, 0x68 } }, 69462306a36Sopenharmony_ci { 104, { 0x2c, 0x3c } }, 69562306a36Sopenharmony_ci { 75, { 0xfe, 0x80 } }, 69662306a36Sopenharmony_ci { 86, { 0xfe, 0x80 } }, 69762306a36Sopenharmony_ci { 88, { 0xfe, 0x80 } }, 69862306a36Sopenharmony_ci { 35, { 0x50, 0x50 } }, 69962306a36Sopenharmony_ci { 97, { 0x48, 0x48 } }, 70062306a36Sopenharmony_ci { 98, { 0x48, 0x48 } }, 70162306a36Sopenharmony_ci}; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, 70462306a36Sopenharmony_ci struct antenna_setup *ant) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci const struct antenna_sel *sel; 70762306a36Sopenharmony_ci unsigned int lna; 70862306a36Sopenharmony_ci unsigned int i; 70962306a36Sopenharmony_ci u32 reg; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* 71262306a36Sopenharmony_ci * We should never come here because rt2x00lib is supposed 71362306a36Sopenharmony_ci * to catch this and send us the correct antenna explicitely. 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ci BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || 71662306a36Sopenharmony_ci ant->tx == ANTENNA_SW_DIVERSITY); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) { 71962306a36Sopenharmony_ci sel = antenna_sel_a; 72062306a36Sopenharmony_ci lna = rt2x00_has_cap_external_lna_a(rt2x00dev); 72162306a36Sopenharmony_ci } else { 72262306a36Sopenharmony_ci sel = antenna_sel_bg; 72362306a36Sopenharmony_ci lna = rt2x00_has_cap_external_lna_bg(rt2x00dev); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) 72762306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, PHY_CSR0); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 73262306a36Sopenharmony_ci rt2x00dev->curr_band == NL80211_BAND_2GHZ); 73362306a36Sopenharmony_ci rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 73462306a36Sopenharmony_ci rt2x00dev->curr_band == NL80211_BAND_5GHZ); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR0, reg); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) 73962306a36Sopenharmony_ci rt61pci_config_antenna_5x(rt2x00dev, ant); 74062306a36Sopenharmony_ci else if (rt2x00_rf(rt2x00dev, RF2527)) 74162306a36Sopenharmony_ci rt61pci_config_antenna_2x(rt2x00dev, ant); 74262306a36Sopenharmony_ci else if (rt2x00_rf(rt2x00dev, RF2529)) { 74362306a36Sopenharmony_ci if (rt2x00_has_cap_double_antenna(rt2x00dev)) 74462306a36Sopenharmony_ci rt61pci_config_antenna_2x(rt2x00dev, ant); 74562306a36Sopenharmony_ci else 74662306a36Sopenharmony_ci rt61pci_config_antenna_2529(rt2x00dev, ant); 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, 75162306a36Sopenharmony_ci struct rt2x00lib_conf *libconf) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci u16 eeprom; 75462306a36Sopenharmony_ci short lna_gain = 0; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (libconf->conf->chandef.chan->band == NL80211_BAND_2GHZ) { 75762306a36Sopenharmony_ci if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) 75862306a36Sopenharmony_ci lna_gain += 14; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); 76162306a36Sopenharmony_ci lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); 76262306a36Sopenharmony_ci } else { 76362306a36Sopenharmony_ci if (rt2x00_has_cap_external_lna_a(rt2x00dev)) 76462306a36Sopenharmony_ci lna_gain += 14; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); 76762306a36Sopenharmony_ci lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci rt2x00dev->lna_gain = lna_gain; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, 77462306a36Sopenharmony_ci struct rf_channel *rf, const int txpower) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci u8 r3; 77762306a36Sopenharmony_ci u8 r94; 77862306a36Sopenharmony_ci u8 smart; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); 78162306a36Sopenharmony_ci rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci r3 = rt61pci_bbp_read(rt2x00dev, 3); 78662306a36Sopenharmony_ci rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); 78762306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, r3); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci r94 = 6; 79062306a36Sopenharmony_ci if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) 79162306a36Sopenharmony_ci r94 += txpower - MAX_TXPOWER; 79262306a36Sopenharmony_ci else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) 79362306a36Sopenharmony_ci r94 += txpower; 79462306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 94, r94); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 1, rf->rf1); 79762306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 2, rf->rf2); 79862306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); 79962306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 4, rf->rf4); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci udelay(200); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 1, rf->rf1); 80462306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 2, rf->rf2); 80562306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); 80662306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 4, rf->rf4); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci udelay(200); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 1, rf->rf1); 81162306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 2, rf->rf2); 81262306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); 81362306a36Sopenharmony_ci rt61pci_rf_write(rt2x00dev, 4, rf->rf4); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci msleep(1); 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, 81962306a36Sopenharmony_ci const int txpower) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci struct rf_channel rf; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci rf.rf1 = rt2x00_rf_read(rt2x00dev, 1); 82462306a36Sopenharmony_ci rf.rf2 = rt2x00_rf_read(rt2x00dev, 2); 82562306a36Sopenharmony_ci rf.rf3 = rt2x00_rf_read(rt2x00dev, 3); 82662306a36Sopenharmony_ci rf.rf4 = rt2x00_rf_read(rt2x00dev, 4); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci rt61pci_config_channel(rt2x00dev, &rf, txpower); 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, 83262306a36Sopenharmony_ci struct rt2x00lib_conf *libconf) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci u32 reg; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4); 83762306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1); 83862306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_STEP, 0); 83962306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0); 84062306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, 84162306a36Sopenharmony_ci libconf->conf->long_frame_max_tx_count); 84262306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, 84362306a36Sopenharmony_ci libconf->conf->short_frame_max_tx_count); 84462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR4, reg); 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, 84862306a36Sopenharmony_ci struct rt2x00lib_conf *libconf) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci enum dev_state state = 85162306a36Sopenharmony_ci (libconf->conf->flags & IEEE80211_CONF_PS) ? 85262306a36Sopenharmony_ci STATE_SLEEP : STATE_AWAKE; 85362306a36Sopenharmony_ci u32 reg; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci if (state == STATE_SLEEP) { 85662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11); 85762306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, 85862306a36Sopenharmony_ci rt2x00dev->beacon_int - 10); 85962306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, 86062306a36Sopenharmony_ci libconf->conf->listen_interval - 1); 86162306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* We must first disable autowake before it can be enabled */ 86462306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 0); 86562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 1); 86862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR, 87162306a36Sopenharmony_ci 0x00000005); 87262306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, IO_CNTL_CSR, 0x0000001c); 87362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000060); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci rt61pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 0); 87662306a36Sopenharmony_ci } else { 87762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11); 87862306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, 0); 87962306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0); 88062306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 0); 88162306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 0); 88262306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR, 88562306a36Sopenharmony_ci 0x00000007); 88662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, IO_CNTL_CSR, 0x00000018); 88762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000020); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci rt61pci_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic void rt61pci_config(struct rt2x00_dev *rt2x00dev, 89462306a36Sopenharmony_ci struct rt2x00lib_conf *libconf, 89562306a36Sopenharmony_ci const unsigned int flags) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci /* Always recalculate LNA gain before changing configuration */ 89862306a36Sopenharmony_ci rt61pci_config_lna_gain(rt2x00dev, libconf); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_CHANNEL) 90162306a36Sopenharmony_ci rt61pci_config_channel(rt2x00dev, &libconf->rf, 90262306a36Sopenharmony_ci libconf->conf->power_level); 90362306a36Sopenharmony_ci if ((flags & IEEE80211_CONF_CHANGE_POWER) && 90462306a36Sopenharmony_ci !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) 90562306a36Sopenharmony_ci rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); 90662306a36Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) 90762306a36Sopenharmony_ci rt61pci_config_retry_limit(rt2x00dev, libconf); 90862306a36Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_PS) 90962306a36Sopenharmony_ci rt61pci_config_ps(rt2x00dev, libconf); 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci/* 91362306a36Sopenharmony_ci * Link tuning 91462306a36Sopenharmony_ci */ 91562306a36Sopenharmony_cistatic void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev, 91662306a36Sopenharmony_ci struct link_qual *qual) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci u32 reg; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* 92162306a36Sopenharmony_ci * Update FCS error count from register. 92262306a36Sopenharmony_ci */ 92362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0); 92462306a36Sopenharmony_ci qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* 92762306a36Sopenharmony_ci * Update False CCA count from register. 92862306a36Sopenharmony_ci */ 92962306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1); 93062306a36Sopenharmony_ci qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic inline void rt61pci_set_vgc(struct rt2x00_dev *rt2x00dev, 93462306a36Sopenharmony_ci struct link_qual *qual, u8 vgc_level) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci if (qual->vgc_level != vgc_level) { 93762306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 17, vgc_level); 93862306a36Sopenharmony_ci qual->vgc_level = vgc_level; 93962306a36Sopenharmony_ci qual->vgc_level_reg = vgc_level; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev, 94462306a36Sopenharmony_ci struct link_qual *qual) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, 0x20); 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, 95062306a36Sopenharmony_ci struct link_qual *qual, const u32 count) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci u8 up_bound; 95362306a36Sopenharmony_ci u8 low_bound; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* 95662306a36Sopenharmony_ci * Determine r17 bounds. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) { 95962306a36Sopenharmony_ci low_bound = 0x28; 96062306a36Sopenharmony_ci up_bound = 0x48; 96162306a36Sopenharmony_ci if (rt2x00_has_cap_external_lna_a(rt2x00dev)) { 96262306a36Sopenharmony_ci low_bound += 0x10; 96362306a36Sopenharmony_ci up_bound += 0x10; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci } else { 96662306a36Sopenharmony_ci low_bound = 0x20; 96762306a36Sopenharmony_ci up_bound = 0x40; 96862306a36Sopenharmony_ci if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) { 96962306a36Sopenharmony_ci low_bound += 0x10; 97062306a36Sopenharmony_ci up_bound += 0x10; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci /* 97562306a36Sopenharmony_ci * If we are not associated, we should go straight to the 97662306a36Sopenharmony_ci * dynamic CCA tuning. 97762306a36Sopenharmony_ci */ 97862306a36Sopenharmony_ci if (!rt2x00dev->intf_associated) 97962306a36Sopenharmony_ci goto dynamic_cca_tune; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* 98262306a36Sopenharmony_ci * Special big-R17 for very short distance 98362306a36Sopenharmony_ci */ 98462306a36Sopenharmony_ci if (qual->rssi >= -35) { 98562306a36Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, 0x60); 98662306a36Sopenharmony_ci return; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci /* 99062306a36Sopenharmony_ci * Special big-R17 for short distance 99162306a36Sopenharmony_ci */ 99262306a36Sopenharmony_ci if (qual->rssi >= -58) { 99362306a36Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, up_bound); 99462306a36Sopenharmony_ci return; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* 99862306a36Sopenharmony_ci * Special big-R17 for middle-short distance 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_ci if (qual->rssi >= -66) { 100162306a36Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x10); 100262306a36Sopenharmony_ci return; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* 100662306a36Sopenharmony_ci * Special mid-R17 for middle distance 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_ci if (qual->rssi >= -74) { 100962306a36Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x08); 101062306a36Sopenharmony_ci return; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* 101462306a36Sopenharmony_ci * Special case: Change up_bound based on the rssi. 101562306a36Sopenharmony_ci * Lower up_bound when rssi is weaker then -74 dBm. 101662306a36Sopenharmony_ci */ 101762306a36Sopenharmony_ci up_bound -= 2 * (-74 - qual->rssi); 101862306a36Sopenharmony_ci if (low_bound > up_bound) 101962306a36Sopenharmony_ci up_bound = low_bound; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (qual->vgc_level > up_bound) { 102262306a36Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, up_bound); 102362306a36Sopenharmony_ci return; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cidynamic_cca_tune: 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci /* 102962306a36Sopenharmony_ci * r17 does not yet exceed upper limit, continue and base 103062306a36Sopenharmony_ci * the r17 tuning on the false CCA count. 103162306a36Sopenharmony_ci */ 103262306a36Sopenharmony_ci if ((qual->false_cca > 512) && (qual->vgc_level < up_bound)) 103362306a36Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level); 103462306a36Sopenharmony_ci else if ((qual->false_cca < 100) && (qual->vgc_level > low_bound)) 103562306a36Sopenharmony_ci rt61pci_set_vgc(rt2x00dev, qual, --qual->vgc_level); 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci/* 103962306a36Sopenharmony_ci * Queue handlers. 104062306a36Sopenharmony_ci */ 104162306a36Sopenharmony_cistatic void rt61pci_start_queue(struct data_queue *queue) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; 104462306a36Sopenharmony_ci u32 reg; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci switch (queue->qid) { 104762306a36Sopenharmony_ci case QID_RX: 104862306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 104962306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); 105062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci case QID_BEACON: 105362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 105462306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); 105562306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); 105662306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); 105762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 105862306a36Sopenharmony_ci break; 105962306a36Sopenharmony_ci default: 106062306a36Sopenharmony_ci break; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic void rt61pci_kick_queue(struct data_queue *queue) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; 106762306a36Sopenharmony_ci u32 reg; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci switch (queue->qid) { 107062306a36Sopenharmony_ci case QID_AC_VO: 107162306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 107262306a36Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, 1); 107362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 107462306a36Sopenharmony_ci break; 107562306a36Sopenharmony_ci case QID_AC_VI: 107662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 107762306a36Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, 1); 107862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 107962306a36Sopenharmony_ci break; 108062306a36Sopenharmony_ci case QID_AC_BE: 108162306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 108262306a36Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, 1); 108362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci case QID_AC_BK: 108662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 108762306a36Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, 1); 108862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 108962306a36Sopenharmony_ci break; 109062306a36Sopenharmony_ci default: 109162306a36Sopenharmony_ci break; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic void rt61pci_stop_queue(struct data_queue *queue) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; 109862306a36Sopenharmony_ci u32 reg; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci switch (queue->qid) { 110162306a36Sopenharmony_ci case QID_AC_VO: 110262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 110362306a36Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, 1); 110462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 110562306a36Sopenharmony_ci break; 110662306a36Sopenharmony_ci case QID_AC_VI: 110762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 110862306a36Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, 1); 110962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 111062306a36Sopenharmony_ci break; 111162306a36Sopenharmony_ci case QID_AC_BE: 111262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 111362306a36Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1); 111462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 111562306a36Sopenharmony_ci break; 111662306a36Sopenharmony_ci case QID_AC_BK: 111762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); 111862306a36Sopenharmony_ci rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1); 111962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); 112062306a36Sopenharmony_ci break; 112162306a36Sopenharmony_ci case QID_RX: 112262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 112362306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); 112462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 112562306a36Sopenharmony_ci break; 112662306a36Sopenharmony_ci case QID_BEACON: 112762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 112862306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); 112962306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); 113062306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); 113162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci /* 113462306a36Sopenharmony_ci * Wait for possibly running tbtt tasklets. 113562306a36Sopenharmony_ci */ 113662306a36Sopenharmony_ci tasklet_kill(&rt2x00dev->tbtt_tasklet); 113762306a36Sopenharmony_ci break; 113862306a36Sopenharmony_ci default: 113962306a36Sopenharmony_ci break; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci/* 114462306a36Sopenharmony_ci * Firmware functions 114562306a36Sopenharmony_ci */ 114662306a36Sopenharmony_cistatic char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci u16 chip; 114962306a36Sopenharmony_ci char *fw_name; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci pci_read_config_word(to_pci_dev(rt2x00dev->dev), PCI_DEVICE_ID, &chip); 115262306a36Sopenharmony_ci switch (chip) { 115362306a36Sopenharmony_ci case RT2561_PCI_ID: 115462306a36Sopenharmony_ci fw_name = FIRMWARE_RT2561; 115562306a36Sopenharmony_ci break; 115662306a36Sopenharmony_ci case RT2561s_PCI_ID: 115762306a36Sopenharmony_ci fw_name = FIRMWARE_RT2561s; 115862306a36Sopenharmony_ci break; 115962306a36Sopenharmony_ci case RT2661_PCI_ID: 116062306a36Sopenharmony_ci fw_name = FIRMWARE_RT2661; 116162306a36Sopenharmony_ci break; 116262306a36Sopenharmony_ci default: 116362306a36Sopenharmony_ci fw_name = NULL; 116462306a36Sopenharmony_ci break; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci return fw_name; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic int rt61pci_check_firmware(struct rt2x00_dev *rt2x00dev, 117162306a36Sopenharmony_ci const u8 *data, const size_t len) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci u16 fw_crc; 117462306a36Sopenharmony_ci u16 crc; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci /* 117762306a36Sopenharmony_ci * Only support 8kb firmware files. 117862306a36Sopenharmony_ci */ 117962306a36Sopenharmony_ci if (len != 8192) 118062306a36Sopenharmony_ci return FW_BAD_LENGTH; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* 118362306a36Sopenharmony_ci * The last 2 bytes in the firmware array are the crc checksum itself. 118462306a36Sopenharmony_ci * This means that we should never pass those 2 bytes to the crc 118562306a36Sopenharmony_ci * algorithm. 118662306a36Sopenharmony_ci */ 118762306a36Sopenharmony_ci fw_crc = (data[len - 2] << 8 | data[len - 1]); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci /* 119062306a36Sopenharmony_ci * Use the crc itu-t algorithm. 119162306a36Sopenharmony_ci */ 119262306a36Sopenharmony_ci crc = crc_itu_t(0, data, len - 2); 119362306a36Sopenharmony_ci crc = crc_itu_t_byte(crc, 0); 119462306a36Sopenharmony_ci crc = crc_itu_t_byte(crc, 0); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci return (fw_crc == crc) ? FW_OK : FW_BAD_CRC; 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, 120062306a36Sopenharmony_ci const u8 *data, const size_t len) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci int i; 120362306a36Sopenharmony_ci u32 reg; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci /* 120662306a36Sopenharmony_ci * Wait for stable hardware. 120762306a36Sopenharmony_ci */ 120862306a36Sopenharmony_ci for (i = 0; i < 100; i++) { 120962306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0); 121062306a36Sopenharmony_ci if (reg) 121162306a36Sopenharmony_ci break; 121262306a36Sopenharmony_ci msleep(1); 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci if (!reg) { 121662306a36Sopenharmony_ci rt2x00_err(rt2x00dev, "Unstable hardware\n"); 121762306a36Sopenharmony_ci return -EBUSY; 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci /* 122162306a36Sopenharmony_ci * Prepare MCU and mailbox for firmware loading. 122262306a36Sopenharmony_ci */ 122362306a36Sopenharmony_ci reg = 0; 122462306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 1); 122562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); 122662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); 122762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); 122862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, 0); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci /* 123162306a36Sopenharmony_ci * Write firmware to device. 123262306a36Sopenharmony_ci */ 123362306a36Sopenharmony_ci reg = 0; 123462306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 1); 123562306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_SELECT_BANK, 1); 123662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, 123962306a36Sopenharmony_ci data, len); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_SELECT_BANK, 0); 124262306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 0); 124562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci for (i = 0; i < 100; i++) { 124862306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_CNTL_CSR); 124962306a36Sopenharmony_ci if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY)) 125062306a36Sopenharmony_ci break; 125162306a36Sopenharmony_ci msleep(1); 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci if (i == 100) { 125562306a36Sopenharmony_ci rt2x00_err(rt2x00dev, "MCU Control register not ready\n"); 125662306a36Sopenharmony_ci return -EBUSY; 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* 126062306a36Sopenharmony_ci * Hardware needs another millisecond before it is ready. 126162306a36Sopenharmony_ci */ 126262306a36Sopenharmony_ci msleep(1); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci /* 126562306a36Sopenharmony_ci * Reset MAC and BBP registers. 126662306a36Sopenharmony_ci */ 126762306a36Sopenharmony_ci reg = 0; 126862306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); 126962306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); 127062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 127362306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); 127462306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); 127562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 127862306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); 127962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci return 0; 128262306a36Sopenharmony_ci} 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci/* 128562306a36Sopenharmony_ci * Initialization functions. 128662306a36Sopenharmony_ci */ 128762306a36Sopenharmony_cistatic bool rt61pci_get_entry_state(struct queue_entry *entry) 128862306a36Sopenharmony_ci{ 128962306a36Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 129062306a36Sopenharmony_ci u32 word; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (entry->queue->qid == QID_RX) { 129362306a36Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); 129662306a36Sopenharmony_ci } else { 129762306a36Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || 130062306a36Sopenharmony_ci rt2x00_get_field32(word, TXD_W0_VALID)); 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cistatic void rt61pci_clear_entry(struct queue_entry *entry) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 130762306a36Sopenharmony_ci struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 130862306a36Sopenharmony_ci u32 word; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (entry->queue->qid == QID_RX) { 131162306a36Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 5); 131262306a36Sopenharmony_ci rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, 131362306a36Sopenharmony_ci skbdesc->skb_dma); 131462306a36Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 5, word); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 131762306a36Sopenharmony_ci rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); 131862306a36Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 0, word); 131962306a36Sopenharmony_ci } else { 132062306a36Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 132162306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_VALID, 0); 132262306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); 132362306a36Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 0, word); 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci} 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_cistatic int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) 132862306a36Sopenharmony_ci{ 132962306a36Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv; 133062306a36Sopenharmony_ci u32 reg; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* 133362306a36Sopenharmony_ci * Initialize registers. 133462306a36Sopenharmony_ci */ 133562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR0); 133662306a36Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR0_AC0_RING_SIZE, 133762306a36Sopenharmony_ci rt2x00dev->tx[0].limit); 133862306a36Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR0_AC1_RING_SIZE, 133962306a36Sopenharmony_ci rt2x00dev->tx[1].limit); 134062306a36Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR0_AC2_RING_SIZE, 134162306a36Sopenharmony_ci rt2x00dev->tx[2].limit); 134262306a36Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR0_AC3_RING_SIZE, 134362306a36Sopenharmony_ci rt2x00dev->tx[3].limit); 134462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR0, reg); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR1); 134762306a36Sopenharmony_ci rt2x00_set_field32(®, TX_RING_CSR1_TXD_SIZE, 134862306a36Sopenharmony_ci rt2x00dev->tx[0].desc_size / 4); 134962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR1, reg); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci entry_priv = rt2x00dev->tx[0].entries[0].priv_data; 135262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AC0_BASE_CSR); 135362306a36Sopenharmony_ci rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, 135462306a36Sopenharmony_ci entry_priv->desc_dma); 135562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AC0_BASE_CSR, reg); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci entry_priv = rt2x00dev->tx[1].entries[0].priv_data; 135862306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AC1_BASE_CSR); 135962306a36Sopenharmony_ci rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, 136062306a36Sopenharmony_ci entry_priv->desc_dma); 136162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AC1_BASE_CSR, reg); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci entry_priv = rt2x00dev->tx[2].entries[0].priv_data; 136462306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AC2_BASE_CSR); 136562306a36Sopenharmony_ci rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, 136662306a36Sopenharmony_ci entry_priv->desc_dma); 136762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AC2_BASE_CSR, reg); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci entry_priv = rt2x00dev->tx[3].entries[0].priv_data; 137062306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AC3_BASE_CSR); 137162306a36Sopenharmony_ci rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, 137262306a36Sopenharmony_ci entry_priv->desc_dma); 137362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AC3_BASE_CSR, reg); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RX_RING_CSR); 137662306a36Sopenharmony_ci rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE, rt2x00dev->rx->limit); 137762306a36Sopenharmony_ci rt2x00_set_field32(®, RX_RING_CSR_RXD_SIZE, 137862306a36Sopenharmony_ci rt2x00dev->rx->desc_size / 4); 137962306a36Sopenharmony_ci rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4); 138062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RX_RING_CSR, reg); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci entry_priv = rt2x00dev->rx->entries[0].priv_data; 138362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RX_BASE_CSR); 138462306a36Sopenharmony_ci rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, 138562306a36Sopenharmony_ci entry_priv->desc_dma); 138662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RX_BASE_CSR, reg); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TX_DMA_DST_CSR); 138962306a36Sopenharmony_ci rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC0, 2); 139062306a36Sopenharmony_ci rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC1, 2); 139162306a36Sopenharmony_ci rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC2, 2); 139262306a36Sopenharmony_ci rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC3, 2); 139362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TX_DMA_DST_CSR, reg); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, LOAD_TX_RING_CSR); 139662306a36Sopenharmony_ci rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1); 139762306a36Sopenharmony_ci rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1); 139862306a36Sopenharmony_ci rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1); 139962306a36Sopenharmony_ci rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1); 140062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR); 140362306a36Sopenharmony_ci rt2x00_set_field32(®, RX_CNTL_CSR_LOAD_RXD, 1); 140462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci return 0; 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_cistatic int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci u32 reg; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); 141462306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); 141562306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); 141662306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); 141762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR1); 142062306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ 142162306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); 142262306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ 142362306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1_VALID, 1); 142462306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */ 142562306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2_VALID, 1); 142662306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ 142762306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3_VALID, 1); 142862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR1, reg); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* 143162306a36Sopenharmony_ci * CCK TXD BBP registers 143262306a36Sopenharmony_ci */ 143362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR2); 143462306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); 143562306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); 143662306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); 143762306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1_VALID, 1); 143862306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2, 11); 143962306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2_VALID, 1); 144062306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3, 10); 144162306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3_VALID, 1); 144262306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR2, reg); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci /* 144562306a36Sopenharmony_ci * OFDM TXD BBP registers 144662306a36Sopenharmony_ci */ 144762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR3); 144862306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); 144962306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); 145062306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); 145162306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1_VALID, 1); 145262306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2, 5); 145362306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); 145462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR3, reg); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR7); 145762306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); 145862306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); 145962306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); 146062306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); 146162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR7, reg); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR8); 146462306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); 146562306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); 146662306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); 146762306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); 146862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR8, reg); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 147162306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0); 147262306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); 147362306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); 147462306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); 147562306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); 147662306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0); 147762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR6, 0x00000fff); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9); 148462306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); 148562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR10, 0x0000071c); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) 149062306a36Sopenharmony_ci return -EBUSY; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, 0x0000e000); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci /* 149562306a36Sopenharmony_ci * Invalidate all Shared Keys (SEC_CSR0), 149662306a36Sopenharmony_ci * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) 149762306a36Sopenharmony_ci */ 149862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR0, 0x00000000); 149962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR1, 0x00000000); 150062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SEC_CSR5, 0x00000000); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR1, 0x000023b0); 150362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR5, 0x060a100c); 150462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR6, 0x00080606); 150562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PHY_CSR7, 0x00000a08); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci /* 151462306a36Sopenharmony_ci * Clear all beacons 151562306a36Sopenharmony_ci * For the Beacon base registers we only need to clear 151662306a36Sopenharmony_ci * the first byte since that byte contains the VALID and OWNER 151762306a36Sopenharmony_ci * bits which (when set to 0) will invalidate the entire beacon. 151862306a36Sopenharmony_ci */ 151962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE0, 0); 152062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE1, 0); 152162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE2, 0); 152262306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE3, 0); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci /* 152562306a36Sopenharmony_ci * We must clear the error counters. 152662306a36Sopenharmony_ci * These registers are cleared on read, 152762306a36Sopenharmony_ci * so we may pass a useless variable to store the value. 152862306a36Sopenharmony_ci */ 152962306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0); 153062306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1); 153162306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR2); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci /* 153462306a36Sopenharmony_ci * Reset MAC and BBP registers. 153562306a36Sopenharmony_ci */ 153662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 153762306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); 153862306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); 153962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 154262306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); 154362306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); 154462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); 154762306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); 154862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci return 0; 155162306a36Sopenharmony_ci} 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistatic int rt61pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) 155462306a36Sopenharmony_ci{ 155562306a36Sopenharmony_ci unsigned int i; 155662306a36Sopenharmony_ci u8 value; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 155962306a36Sopenharmony_ci value = rt61pci_bbp_read(rt2x00dev, 0); 156062306a36Sopenharmony_ci if ((value != 0xff) && (value != 0x00)) 156162306a36Sopenharmony_ci return 0; 156262306a36Sopenharmony_ci udelay(REGISTER_BUSY_DELAY); 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n"); 156662306a36Sopenharmony_ci return -EACCES; 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci unsigned int i; 157262306a36Sopenharmony_ci u16 eeprom; 157362306a36Sopenharmony_ci u8 reg_id; 157462306a36Sopenharmony_ci u8 value; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (unlikely(rt61pci_wait_bbp_ready(rt2x00dev))) 157762306a36Sopenharmony_ci return -EACCES; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 3, 0x00); 158062306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 15, 0x30); 158162306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 21, 0xc8); 158262306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 22, 0x38); 158362306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 23, 0x06); 158462306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 24, 0xfe); 158562306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 25, 0x0a); 158662306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 26, 0x0d); 158762306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 34, 0x12); 158862306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 37, 0x07); 158962306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 39, 0xf8); 159062306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 41, 0x60); 159162306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 53, 0x10); 159262306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 54, 0x18); 159362306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 60, 0x10); 159462306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 61, 0x04); 159562306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 62, 0x04); 159662306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 75, 0xfe); 159762306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 86, 0xfe); 159862306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 88, 0xfe); 159962306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 90, 0x0f); 160062306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 99, 0x00); 160162306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 102, 0x16); 160262306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, 107, 0x04); 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci for (i = 0; i < EEPROM_BBP_SIZE; i++) { 160562306a36Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (eeprom != 0xffff && eeprom != 0x0000) { 160862306a36Sopenharmony_ci reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); 160962306a36Sopenharmony_ci value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); 161062306a36Sopenharmony_ci rt61pci_bbp_write(rt2x00dev, reg_id, value); 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci return 0; 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci/* 161862306a36Sopenharmony_ci * Device state switch handlers. 161962306a36Sopenharmony_ci */ 162062306a36Sopenharmony_cistatic void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, 162162306a36Sopenharmony_ci enum dev_state state) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci int mask = (state == STATE_RADIO_IRQ_OFF); 162462306a36Sopenharmony_ci u32 reg; 162562306a36Sopenharmony_ci unsigned long flags; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci /* 162862306a36Sopenharmony_ci * When interrupts are being enabled, the interrupt registers 162962306a36Sopenharmony_ci * should clear the register to assure a clean state. 163062306a36Sopenharmony_ci */ 163162306a36Sopenharmony_ci if (state == STATE_RADIO_IRQ_ON) { 163262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); 163362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR); 163662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci /* 164062306a36Sopenharmony_ci * Only toggle the interrupts bits we are going to use. 164162306a36Sopenharmony_ci * Non-checked interrupt bits are disabled by default. 164262306a36Sopenharmony_ci */ 164362306a36Sopenharmony_ci spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); 164662306a36Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, mask); 164762306a36Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, mask); 164862306a36Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_BEACON_DONE, mask); 164962306a36Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_ENABLE_MITIGATION, mask); 165062306a36Sopenharmony_ci rt2x00_set_field32(®, INT_MASK_CSR_MITIGATION_PERIOD, 0xff); 165162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); 165462306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_0, mask); 165562306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_1, mask); 165662306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_2, mask); 165762306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_3, mask); 165862306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_4, mask); 165962306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_5, mask); 166062306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_6, mask); 166162306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_7, mask); 166262306a36Sopenharmony_ci rt2x00_set_field32(®, MCU_INT_MASK_CSR_TWAKEUP, mask); 166362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (state == STATE_RADIO_IRQ_OFF) { 166862306a36Sopenharmony_ci /* 166962306a36Sopenharmony_ci * Ensure that all tasklets are finished. 167062306a36Sopenharmony_ci */ 167162306a36Sopenharmony_ci tasklet_kill(&rt2x00dev->txstatus_tasklet); 167262306a36Sopenharmony_ci tasklet_kill(&rt2x00dev->rxdone_tasklet); 167362306a36Sopenharmony_ci tasklet_kill(&rt2x00dev->autowake_tasklet); 167462306a36Sopenharmony_ci tasklet_kill(&rt2x00dev->tbtt_tasklet); 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci} 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_cistatic int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) 167962306a36Sopenharmony_ci{ 168062306a36Sopenharmony_ci u32 reg; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci /* 168362306a36Sopenharmony_ci * Initialize all registers. 168462306a36Sopenharmony_ci */ 168562306a36Sopenharmony_ci if (unlikely(rt61pci_init_queues(rt2x00dev) || 168662306a36Sopenharmony_ci rt61pci_init_registers(rt2x00dev) || 168762306a36Sopenharmony_ci rt61pci_init_bbp(rt2x00dev))) 168862306a36Sopenharmony_ci return -EIO; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci /* 169162306a36Sopenharmony_ci * Enable RX. 169262306a36Sopenharmony_ci */ 169362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR); 169462306a36Sopenharmony_ci rt2x00_set_field32(®, RX_CNTL_CSR_ENABLE_RX_DMA, 1); 169562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg); 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci return 0; 169862306a36Sopenharmony_ci} 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_cistatic void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) 170162306a36Sopenharmony_ci{ 170262306a36Sopenharmony_ci /* 170362306a36Sopenharmony_ci * Disable power 170462306a36Sopenharmony_ci */ 170562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR10, 0x00001818); 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_cistatic int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) 170962306a36Sopenharmony_ci{ 171062306a36Sopenharmony_ci u32 reg, reg2; 171162306a36Sopenharmony_ci unsigned int i; 171262306a36Sopenharmony_ci bool put_to_sleep; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci put_to_sleep = (state != STATE_AWAKE); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12); 171762306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); 171862306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); 171962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci /* 172262306a36Sopenharmony_ci * Device is not guaranteed to be in the requested state yet. 172362306a36Sopenharmony_ci * We must wait until the register indicates that the 172462306a36Sopenharmony_ci * device has entered the correct state. 172562306a36Sopenharmony_ci */ 172662306a36Sopenharmony_ci for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 172762306a36Sopenharmony_ci reg2 = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12); 172862306a36Sopenharmony_ci state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); 172962306a36Sopenharmony_ci if (state == !put_to_sleep) 173062306a36Sopenharmony_ci return 0; 173162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg); 173262306a36Sopenharmony_ci msleep(10); 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci return -EBUSY; 173662306a36Sopenharmony_ci} 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_cistatic int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, 173962306a36Sopenharmony_ci enum dev_state state) 174062306a36Sopenharmony_ci{ 174162306a36Sopenharmony_ci int retval = 0; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci switch (state) { 174462306a36Sopenharmony_ci case STATE_RADIO_ON: 174562306a36Sopenharmony_ci retval = rt61pci_enable_radio(rt2x00dev); 174662306a36Sopenharmony_ci break; 174762306a36Sopenharmony_ci case STATE_RADIO_OFF: 174862306a36Sopenharmony_ci rt61pci_disable_radio(rt2x00dev); 174962306a36Sopenharmony_ci break; 175062306a36Sopenharmony_ci case STATE_RADIO_IRQ_ON: 175162306a36Sopenharmony_ci case STATE_RADIO_IRQ_OFF: 175262306a36Sopenharmony_ci rt61pci_toggle_irq(rt2x00dev, state); 175362306a36Sopenharmony_ci break; 175462306a36Sopenharmony_ci case STATE_DEEP_SLEEP: 175562306a36Sopenharmony_ci case STATE_SLEEP: 175662306a36Sopenharmony_ci case STATE_STANDBY: 175762306a36Sopenharmony_ci case STATE_AWAKE: 175862306a36Sopenharmony_ci retval = rt61pci_set_state(rt2x00dev, state); 175962306a36Sopenharmony_ci break; 176062306a36Sopenharmony_ci default: 176162306a36Sopenharmony_ci retval = -ENOTSUPP; 176262306a36Sopenharmony_ci break; 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci if (unlikely(retval)) 176662306a36Sopenharmony_ci rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n", 176762306a36Sopenharmony_ci state, retval); 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci return retval; 177062306a36Sopenharmony_ci} 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci/* 177362306a36Sopenharmony_ci * TX descriptor initialization 177462306a36Sopenharmony_ci */ 177562306a36Sopenharmony_cistatic void rt61pci_write_tx_desc(struct queue_entry *entry, 177662306a36Sopenharmony_ci struct txentry_desc *txdesc) 177762306a36Sopenharmony_ci{ 177862306a36Sopenharmony_ci struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 177962306a36Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 178062306a36Sopenharmony_ci __le32 *txd = entry_priv->desc; 178162306a36Sopenharmony_ci u32 word; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci /* 178462306a36Sopenharmony_ci * Start writing the descriptor words. 178562306a36Sopenharmony_ci */ 178662306a36Sopenharmony_ci word = rt2x00_desc_read(txd, 1); 178762306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid); 178862306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs); 178962306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); 179062306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max); 179162306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); 179262306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 179362306a36Sopenharmony_ci test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); 179462306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); 179562306a36Sopenharmony_ci rt2x00_desc_write(txd, 1, word); 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci word = rt2x00_desc_read(txd, 2); 179862306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); 179962306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); 180062306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, 180162306a36Sopenharmony_ci txdesc->u.plcp.length_low); 180262306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, 180362306a36Sopenharmony_ci txdesc->u.plcp.length_high); 180462306a36Sopenharmony_ci rt2x00_desc_write(txd, 2, word); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { 180762306a36Sopenharmony_ci _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); 180862306a36Sopenharmony_ci _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); 180962306a36Sopenharmony_ci } 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci word = rt2x00_desc_read(txd, 5); 181262306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); 181362306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx); 181462306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W5_TX_POWER, 181562306a36Sopenharmony_ci TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power)); 181662306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); 181762306a36Sopenharmony_ci rt2x00_desc_write(txd, 5, word); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci if (entry->queue->qid != QID_BEACON) { 182062306a36Sopenharmony_ci word = rt2x00_desc_read(txd, 6); 182162306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, 182262306a36Sopenharmony_ci skbdesc->skb_dma); 182362306a36Sopenharmony_ci rt2x00_desc_write(txd, 6, word); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci word = rt2x00_desc_read(txd, 11); 182662306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, 182762306a36Sopenharmony_ci txdesc->length); 182862306a36Sopenharmony_ci rt2x00_desc_write(txd, 11, word); 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci /* 183262306a36Sopenharmony_ci * Writing TXD word 0 must the last to prevent a race condition with 183362306a36Sopenharmony_ci * the device, whereby the device may take hold of the TXD before we 183462306a36Sopenharmony_ci * finished updating it. 183562306a36Sopenharmony_ci */ 183662306a36Sopenharmony_ci word = rt2x00_desc_read(txd, 0); 183762306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); 183862306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_VALID, 1); 183962306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, 184062306a36Sopenharmony_ci test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); 184162306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_ACK, 184262306a36Sopenharmony_ci test_bit(ENTRY_TXD_ACK, &txdesc->flags)); 184362306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, 184462306a36Sopenharmony_ci test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); 184562306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_OFDM, 184662306a36Sopenharmony_ci (txdesc->rate_mode == RATE_MODE_OFDM)); 184762306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs); 184862306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, 184962306a36Sopenharmony_ci test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); 185062306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 185162306a36Sopenharmony_ci test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags)); 185262306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, 185362306a36Sopenharmony_ci test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); 185462306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); 185562306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length); 185662306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_BURST, 185762306a36Sopenharmony_ci test_bit(ENTRY_TXD_BURST, &txdesc->flags)); 185862306a36Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); 185962306a36Sopenharmony_ci rt2x00_desc_write(txd, 0, word); 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci /* 186262306a36Sopenharmony_ci * Register descriptor details in skb frame descriptor. 186362306a36Sopenharmony_ci */ 186462306a36Sopenharmony_ci skbdesc->desc = txd; 186562306a36Sopenharmony_ci skbdesc->desc_len = (entry->queue->qid == QID_BEACON) ? TXINFO_SIZE : 186662306a36Sopenharmony_ci TXD_DESC_SIZE; 186762306a36Sopenharmony_ci} 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci/* 187062306a36Sopenharmony_ci * TX data initialization 187162306a36Sopenharmony_ci */ 187262306a36Sopenharmony_cistatic void rt61pci_write_beacon(struct queue_entry *entry, 187362306a36Sopenharmony_ci struct txentry_desc *txdesc) 187462306a36Sopenharmony_ci{ 187562306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 187662306a36Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 187762306a36Sopenharmony_ci unsigned int beacon_base; 187862306a36Sopenharmony_ci unsigned int padding_len; 187962306a36Sopenharmony_ci u32 orig_reg, reg; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci /* 188262306a36Sopenharmony_ci * Disable beaconing while we are reloading the beacon data, 188362306a36Sopenharmony_ci * otherwise we might be sending out invalid data. 188462306a36Sopenharmony_ci */ 188562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 188662306a36Sopenharmony_ci orig_reg = reg; 188762306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); 188862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci /* 189162306a36Sopenharmony_ci * Write the TX descriptor for the beacon. 189262306a36Sopenharmony_ci */ 189362306a36Sopenharmony_ci rt61pci_write_tx_desc(entry, txdesc); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci /* 189662306a36Sopenharmony_ci * Dump beacon to userspace through debugfs. 189762306a36Sopenharmony_ci */ 189862306a36Sopenharmony_ci rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci /* 190162306a36Sopenharmony_ci * Write entire beacon with descriptor and padding to register. 190262306a36Sopenharmony_ci */ 190362306a36Sopenharmony_ci padding_len = roundup(entry->skb->len, 4) - entry->skb->len; 190462306a36Sopenharmony_ci if (padding_len && skb_pad(entry->skb, padding_len)) { 190562306a36Sopenharmony_ci rt2x00_err(rt2x00dev, "Failure padding beacon, aborting\n"); 190662306a36Sopenharmony_ci /* skb freed by skb_pad() on failure */ 190762306a36Sopenharmony_ci entry->skb = NULL; 190862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, orig_reg); 190962306a36Sopenharmony_ci return; 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci beacon_base = HW_BEACON_OFFSET(entry->entry_idx); 191362306a36Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, beacon_base, 191462306a36Sopenharmony_ci entry_priv->desc, TXINFO_SIZE); 191562306a36Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE, 191662306a36Sopenharmony_ci entry->skb->data, 191762306a36Sopenharmony_ci entry->skb->len + padding_len); 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci /* 192062306a36Sopenharmony_ci * Enable beaconing again. 192162306a36Sopenharmony_ci * 192262306a36Sopenharmony_ci * For Wi-Fi faily generated beacons between participating 192362306a36Sopenharmony_ci * stations. Set TBTT phase adaptive adjustment step to 8us. 192462306a36Sopenharmony_ci */ 192562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); 192862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci /* 193162306a36Sopenharmony_ci * Clean up beacon skb. 193262306a36Sopenharmony_ci */ 193362306a36Sopenharmony_ci dev_kfree_skb_any(entry->skb); 193462306a36Sopenharmony_ci entry->skb = NULL; 193562306a36Sopenharmony_ci} 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_cistatic void rt61pci_clear_beacon(struct queue_entry *entry) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 194062306a36Sopenharmony_ci u32 orig_reg, reg; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci /* 194362306a36Sopenharmony_ci * Disable beaconing while we are reloading the beacon data, 194462306a36Sopenharmony_ci * otherwise we might be sending out invalid data. 194562306a36Sopenharmony_ci */ 194662306a36Sopenharmony_ci orig_reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); 194762306a36Sopenharmony_ci reg = orig_reg; 194862306a36Sopenharmony_ci rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); 194962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci /* 195262306a36Sopenharmony_ci * Clear beacon. 195362306a36Sopenharmony_ci */ 195462306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, 195562306a36Sopenharmony_ci HW_BEACON_OFFSET(entry->entry_idx), 0); 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci /* 195862306a36Sopenharmony_ci * Restore global beaconing state. 195962306a36Sopenharmony_ci */ 196062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, orig_reg); 196162306a36Sopenharmony_ci} 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci/* 196462306a36Sopenharmony_ci * RX control handlers 196562306a36Sopenharmony_ci */ 196662306a36Sopenharmony_cistatic int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) 196762306a36Sopenharmony_ci{ 196862306a36Sopenharmony_ci u8 offset = rt2x00dev->lna_gain; 196962306a36Sopenharmony_ci u8 lna; 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); 197262306a36Sopenharmony_ci switch (lna) { 197362306a36Sopenharmony_ci case 3: 197462306a36Sopenharmony_ci offset += 90; 197562306a36Sopenharmony_ci break; 197662306a36Sopenharmony_ci case 2: 197762306a36Sopenharmony_ci offset += 74; 197862306a36Sopenharmony_ci break; 197962306a36Sopenharmony_ci case 1: 198062306a36Sopenharmony_ci offset += 64; 198162306a36Sopenharmony_ci break; 198262306a36Sopenharmony_ci default: 198362306a36Sopenharmony_ci return 0; 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) { 198762306a36Sopenharmony_ci if (lna == 3 || lna == 2) 198862306a36Sopenharmony_ci offset += 10; 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; 199262306a36Sopenharmony_ci} 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_cistatic void rt61pci_fill_rxdone(struct queue_entry *entry, 199562306a36Sopenharmony_ci struct rxdone_entry_desc *rxdesc) 199662306a36Sopenharmony_ci{ 199762306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 199862306a36Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 199962306a36Sopenharmony_ci u32 word0; 200062306a36Sopenharmony_ci u32 word1; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci word0 = rt2x00_desc_read(entry_priv->desc, 0); 200362306a36Sopenharmony_ci word1 = rt2x00_desc_read(entry_priv->desc, 1); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) 200662306a36Sopenharmony_ci rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG); 200962306a36Sopenharmony_ci rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci if (rxdesc->cipher != CIPHER_NONE) { 201262306a36Sopenharmony_ci rxdesc->iv[0] = _rt2x00_desc_read(entry_priv->desc, 2); 201362306a36Sopenharmony_ci rxdesc->iv[1] = _rt2x00_desc_read(entry_priv->desc, 3); 201462306a36Sopenharmony_ci rxdesc->dev_flags |= RXDONE_CRYPTO_IV; 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci rxdesc->icv = _rt2x00_desc_read(entry_priv->desc, 4); 201762306a36Sopenharmony_ci rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci /* 202062306a36Sopenharmony_ci * Hardware has stripped IV/EIV data from 802.11 frame during 202162306a36Sopenharmony_ci * decryption. It has provided the data separately but rt2x00lib 202262306a36Sopenharmony_ci * should decide if it should be reinserted. 202362306a36Sopenharmony_ci */ 202462306a36Sopenharmony_ci rxdesc->flags |= RX_FLAG_IV_STRIPPED; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci /* 202762306a36Sopenharmony_ci * The hardware has already checked the Michael Mic and has 202862306a36Sopenharmony_ci * stripped it from the frame. Signal this to mac80211. 202962306a36Sopenharmony_ci */ 203062306a36Sopenharmony_ci rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) 203362306a36Sopenharmony_ci rxdesc->flags |= RX_FLAG_DECRYPTED; 203462306a36Sopenharmony_ci else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) 203562306a36Sopenharmony_ci rxdesc->flags |= RX_FLAG_MMIC_ERROR; 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci /* 203962306a36Sopenharmony_ci * Obtain the status about this packet. 204062306a36Sopenharmony_ci * When frame was received with an OFDM bitrate, 204162306a36Sopenharmony_ci * the signal is the PLCP value. If it was received with 204262306a36Sopenharmony_ci * a CCK bitrate the signal is the rate in 100kbit/s. 204362306a36Sopenharmony_ci */ 204462306a36Sopenharmony_ci rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); 204562306a36Sopenharmony_ci rxdesc->rssi = rt61pci_agc_to_rssi(rt2x00dev, word1); 204662306a36Sopenharmony_ci rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci if (rt2x00_get_field32(word0, RXD_W0_OFDM)) 204962306a36Sopenharmony_ci rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; 205062306a36Sopenharmony_ci else 205162306a36Sopenharmony_ci rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; 205262306a36Sopenharmony_ci if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) 205362306a36Sopenharmony_ci rxdesc->dev_flags |= RXDONE_MY_BSS; 205462306a36Sopenharmony_ci} 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci/* 205762306a36Sopenharmony_ci * Interrupt functions. 205862306a36Sopenharmony_ci */ 205962306a36Sopenharmony_cistatic void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) 206062306a36Sopenharmony_ci{ 206162306a36Sopenharmony_ci struct data_queue *queue; 206262306a36Sopenharmony_ci struct queue_entry *entry; 206362306a36Sopenharmony_ci struct queue_entry *entry_done; 206462306a36Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv; 206562306a36Sopenharmony_ci struct txdone_entry_desc txdesc; 206662306a36Sopenharmony_ci u32 word; 206762306a36Sopenharmony_ci u32 reg; 206862306a36Sopenharmony_ci int type; 206962306a36Sopenharmony_ci int index; 207062306a36Sopenharmony_ci int i; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci /* 207362306a36Sopenharmony_ci * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO 207462306a36Sopenharmony_ci * at most X times and also stop processing once the TX_STA_FIFO_VALID 207562306a36Sopenharmony_ci * flag is not set anymore. 207662306a36Sopenharmony_ci * 207762306a36Sopenharmony_ci * The legacy drivers use X=TX_RING_SIZE but state in a comment 207862306a36Sopenharmony_ci * that the TX_STA_FIFO stack has a size of 16. We stick to our 207962306a36Sopenharmony_ci * tx ring size for now. 208062306a36Sopenharmony_ci */ 208162306a36Sopenharmony_ci for (i = 0; i < rt2x00dev->tx->limit; i++) { 208262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR4); 208362306a36Sopenharmony_ci if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) 208462306a36Sopenharmony_ci break; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci /* 208762306a36Sopenharmony_ci * Skip this entry when it contains an invalid 208862306a36Sopenharmony_ci * queue identication number. 208962306a36Sopenharmony_ci */ 209062306a36Sopenharmony_ci type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE); 209162306a36Sopenharmony_ci queue = rt2x00queue_get_tx_queue(rt2x00dev, type); 209262306a36Sopenharmony_ci if (unlikely(!queue)) 209362306a36Sopenharmony_ci continue; 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci /* 209662306a36Sopenharmony_ci * Skip this entry when it contains an invalid 209762306a36Sopenharmony_ci * index number. 209862306a36Sopenharmony_ci */ 209962306a36Sopenharmony_ci index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE); 210062306a36Sopenharmony_ci if (unlikely(index >= queue->limit)) 210162306a36Sopenharmony_ci continue; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci entry = &queue->entries[index]; 210462306a36Sopenharmony_ci entry_priv = entry->priv_data; 210562306a36Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || 210862306a36Sopenharmony_ci !rt2x00_get_field32(word, TXD_W0_VALID)) 210962306a36Sopenharmony_ci return; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); 211262306a36Sopenharmony_ci while (entry != entry_done) { 211362306a36Sopenharmony_ci /* Catch up. 211462306a36Sopenharmony_ci * Just report any entries we missed as failed. 211562306a36Sopenharmony_ci */ 211662306a36Sopenharmony_ci rt2x00_warn(rt2x00dev, "TX status report missed for entry %d\n", 211762306a36Sopenharmony_ci entry_done->entry_idx); 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci rt2x00lib_txdone_noinfo(entry_done, TXDONE_UNKNOWN); 212062306a36Sopenharmony_ci entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); 212162306a36Sopenharmony_ci } 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci /* 212462306a36Sopenharmony_ci * Obtain the status about this packet. 212562306a36Sopenharmony_ci */ 212662306a36Sopenharmony_ci txdesc.flags = 0; 212762306a36Sopenharmony_ci switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) { 212862306a36Sopenharmony_ci case 0: /* Success, maybe with retry */ 212962306a36Sopenharmony_ci __set_bit(TXDONE_SUCCESS, &txdesc.flags); 213062306a36Sopenharmony_ci break; 213162306a36Sopenharmony_ci case 6: /* Failure, excessive retries */ 213262306a36Sopenharmony_ci __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); 213362306a36Sopenharmony_ci fallthrough; /* this is a failed frame! */ 213462306a36Sopenharmony_ci default: /* Failure */ 213562306a36Sopenharmony_ci __set_bit(TXDONE_FAILURE, &txdesc.flags); 213662306a36Sopenharmony_ci } 213762306a36Sopenharmony_ci txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci /* 214062306a36Sopenharmony_ci * the frame was retried at least once 214162306a36Sopenharmony_ci * -> hw used fallback rates 214262306a36Sopenharmony_ci */ 214362306a36Sopenharmony_ci if (txdesc.retry) 214462306a36Sopenharmony_ci __set_bit(TXDONE_FALLBACK, &txdesc.flags); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci rt2x00lib_txdone(entry, &txdesc); 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci} 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_cistatic void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev) 215162306a36Sopenharmony_ci{ 215262306a36Sopenharmony_ci struct rt2x00lib_conf libconf = { .conf = &rt2x00dev->hw->conf }; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); 215562306a36Sopenharmony_ci} 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_cistatic inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, 215862306a36Sopenharmony_ci struct rt2x00_field32 irq_field) 215962306a36Sopenharmony_ci{ 216062306a36Sopenharmony_ci u32 reg; 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci /* 216362306a36Sopenharmony_ci * Enable a single interrupt. The interrupt mask register 216462306a36Sopenharmony_ci * access needs locking. 216562306a36Sopenharmony_ci */ 216662306a36Sopenharmony_ci spin_lock_irq(&rt2x00dev->irqmask_lock); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); 216962306a36Sopenharmony_ci rt2x00_set_field32(®, irq_field, 0); 217062306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci spin_unlock_irq(&rt2x00dev->irqmask_lock); 217362306a36Sopenharmony_ci} 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_cistatic void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev, 217662306a36Sopenharmony_ci struct rt2x00_field32 irq_field) 217762306a36Sopenharmony_ci{ 217862306a36Sopenharmony_ci u32 reg; 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci /* 218162306a36Sopenharmony_ci * Enable a single MCU interrupt. The interrupt mask register 218262306a36Sopenharmony_ci * access needs locking. 218362306a36Sopenharmony_ci */ 218462306a36Sopenharmony_ci spin_lock_irq(&rt2x00dev->irqmask_lock); 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); 218762306a36Sopenharmony_ci rt2x00_set_field32(®, irq_field, 0); 218862306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci spin_unlock_irq(&rt2x00dev->irqmask_lock); 219162306a36Sopenharmony_ci} 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_cistatic void rt61pci_txstatus_tasklet(struct tasklet_struct *t) 219462306a36Sopenharmony_ci{ 219562306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, 219662306a36Sopenharmony_ci txstatus_tasklet); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci rt61pci_txdone(rt2x00dev); 219962306a36Sopenharmony_ci if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 220062306a36Sopenharmony_ci rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE); 220162306a36Sopenharmony_ci} 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_cistatic void rt61pci_tbtt_tasklet(struct tasklet_struct *t) 220462306a36Sopenharmony_ci{ 220562306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, tbtt_tasklet); 220662306a36Sopenharmony_ci rt2x00lib_beacondone(rt2x00dev); 220762306a36Sopenharmony_ci if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 220862306a36Sopenharmony_ci rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE); 220962306a36Sopenharmony_ci} 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_cistatic void rt61pci_rxdone_tasklet(struct tasklet_struct *t) 221262306a36Sopenharmony_ci{ 221362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, 221462306a36Sopenharmony_ci rxdone_tasklet); 221562306a36Sopenharmony_ci if (rt2x00mmio_rxdone(rt2x00dev)) 221662306a36Sopenharmony_ci tasklet_schedule(&rt2x00dev->rxdone_tasklet); 221762306a36Sopenharmony_ci else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 221862306a36Sopenharmony_ci rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); 221962306a36Sopenharmony_ci} 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_cistatic void rt61pci_autowake_tasklet(struct tasklet_struct *t) 222262306a36Sopenharmony_ci{ 222362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, 222462306a36Sopenharmony_ci autowake_tasklet); 222562306a36Sopenharmony_ci rt61pci_wakeup(rt2x00dev); 222662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, 222762306a36Sopenharmony_ci M2H_CMD_DONE_CSR, 0xffffffff); 222862306a36Sopenharmony_ci if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 222962306a36Sopenharmony_ci rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP); 223062306a36Sopenharmony_ci} 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_cistatic irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) 223362306a36Sopenharmony_ci{ 223462306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = dev_instance; 223562306a36Sopenharmony_ci u32 reg_mcu, mask_mcu; 223662306a36Sopenharmony_ci u32 reg, mask; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci /* 223962306a36Sopenharmony_ci * Get the interrupt sources & saved to local variable. 224062306a36Sopenharmony_ci * Write register value back to clear pending interrupts. 224162306a36Sopenharmony_ci */ 224262306a36Sopenharmony_ci reg_mcu = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR); 224362306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu); 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); 224662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci if (!reg && !reg_mcu) 224962306a36Sopenharmony_ci return IRQ_NONE; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 225262306a36Sopenharmony_ci return IRQ_HANDLED; 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci /* 225562306a36Sopenharmony_ci * Schedule tasklets for interrupt handling. 225662306a36Sopenharmony_ci */ 225762306a36Sopenharmony_ci if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE)) 225862306a36Sopenharmony_ci tasklet_schedule(&rt2x00dev->rxdone_tasklet); 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE)) 226162306a36Sopenharmony_ci tasklet_schedule(&rt2x00dev->txstatus_tasklet); 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE)) 226462306a36Sopenharmony_ci tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP)) 226762306a36Sopenharmony_ci tasklet_schedule(&rt2x00dev->autowake_tasklet); 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci /* 227062306a36Sopenharmony_ci * Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits 227162306a36Sopenharmony_ci * for interrupts and interrupt masks we can just use the value of 227262306a36Sopenharmony_ci * INT_SOURCE_CSR to create the interrupt mask. 227362306a36Sopenharmony_ci */ 227462306a36Sopenharmony_ci mask = reg; 227562306a36Sopenharmony_ci mask_mcu = reg_mcu; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci /* 227862306a36Sopenharmony_ci * Disable all interrupts for which a tasklet was scheduled right now, 227962306a36Sopenharmony_ci * the tasklet will reenable the appropriate interrupts. 228062306a36Sopenharmony_ci */ 228162306a36Sopenharmony_ci spin_lock(&rt2x00dev->irqmask_lock); 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); 228462306a36Sopenharmony_ci reg |= mask; 228562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); 228862306a36Sopenharmony_ci reg |= mask_mcu; 228962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci spin_unlock(&rt2x00dev->irqmask_lock); 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci return IRQ_HANDLED; 229462306a36Sopenharmony_ci} 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci/* 229762306a36Sopenharmony_ci * Device probe functions. 229862306a36Sopenharmony_ci */ 229962306a36Sopenharmony_cistatic int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) 230062306a36Sopenharmony_ci{ 230162306a36Sopenharmony_ci struct eeprom_93cx6 eeprom; 230262306a36Sopenharmony_ci u32 reg; 230362306a36Sopenharmony_ci u16 word; 230462306a36Sopenharmony_ci u8 *mac; 230562306a36Sopenharmony_ci s8 value; 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci eeprom.data = rt2x00dev; 231062306a36Sopenharmony_ci eeprom.register_read = rt61pci_eepromregister_read; 231162306a36Sopenharmony_ci eeprom.register_write = rt61pci_eepromregister_write; 231262306a36Sopenharmony_ci eeprom.width = rt2x00_get_field32(reg, E2PROM_CSR_TYPE_93C46) ? 231362306a36Sopenharmony_ci PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; 231462306a36Sopenharmony_ci eeprom.reg_data_in = 0; 231562306a36Sopenharmony_ci eeprom.reg_data_out = 0; 231662306a36Sopenharmony_ci eeprom.reg_data_clock = 0; 231762306a36Sopenharmony_ci eeprom.reg_chip_select = 0; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, 232062306a36Sopenharmony_ci EEPROM_SIZE / sizeof(u16)); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci /* 232362306a36Sopenharmony_ci * Start validation of the data that has been read. 232462306a36Sopenharmony_ci */ 232562306a36Sopenharmony_ci mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); 232662306a36Sopenharmony_ci rt2x00lib_set_mac_address(rt2x00dev, mac); 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); 232962306a36Sopenharmony_ci if (word == 0xffff) { 233062306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); 233162306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 233262306a36Sopenharmony_ci ANTENNA_B); 233362306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 233462306a36Sopenharmony_ci ANTENNA_B); 233562306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); 233662306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); 233762306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); 233862306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5225); 233962306a36Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); 234062306a36Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); 234462306a36Sopenharmony_ci if (word == 0xffff) { 234562306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0); 234662306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0); 234762306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_RX_FIXED, 0); 234862306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_TX_FIXED, 0); 234962306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); 235062306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); 235162306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); 235262306a36Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); 235362306a36Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); 235462306a36Sopenharmony_ci } 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); 235762306a36Sopenharmony_ci if (word == 0xffff) { 235862306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_LED_LED_MODE, 235962306a36Sopenharmony_ci LED_MODE_DEFAULT); 236062306a36Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word); 236162306a36Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "Led: 0x%04x\n", word); 236262306a36Sopenharmony_ci } 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); 236562306a36Sopenharmony_ci if (word == 0xffff) { 236662306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); 236762306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); 236862306a36Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); 236962306a36Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word); 237062306a36Sopenharmony_ci } 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); 237362306a36Sopenharmony_ci if (word == 0xffff) { 237462306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); 237562306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); 237662306a36Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); 237762306a36Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); 237862306a36Sopenharmony_ci } else { 237962306a36Sopenharmony_ci value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1); 238062306a36Sopenharmony_ci if (value < -10 || value > 10) 238162306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); 238262306a36Sopenharmony_ci value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2); 238362306a36Sopenharmony_ci if (value < -10 || value > 10) 238462306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); 238562306a36Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); 238662306a36Sopenharmony_ci } 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); 238962306a36Sopenharmony_ci if (word == 0xffff) { 239062306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); 239162306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); 239262306a36Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); 239362306a36Sopenharmony_ci rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word); 239462306a36Sopenharmony_ci } else { 239562306a36Sopenharmony_ci value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); 239662306a36Sopenharmony_ci if (value < -10 || value > 10) 239762306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); 239862306a36Sopenharmony_ci value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2); 239962306a36Sopenharmony_ci if (value < -10 || value > 10) 240062306a36Sopenharmony_ci rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); 240162306a36Sopenharmony_ci rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); 240262306a36Sopenharmony_ci } 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci return 0; 240562306a36Sopenharmony_ci} 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_cistatic int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) 240862306a36Sopenharmony_ci{ 240962306a36Sopenharmony_ci u32 reg; 241062306a36Sopenharmony_ci u16 value; 241162306a36Sopenharmony_ci u16 eeprom; 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci /* 241462306a36Sopenharmony_ci * Read EEPROM word for configuration. 241562306a36Sopenharmony_ci */ 241662306a36Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci /* 241962306a36Sopenharmony_ci * Identify RF chipset. 242062306a36Sopenharmony_ci */ 242162306a36Sopenharmony_ci value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); 242262306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0); 242362306a36Sopenharmony_ci rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), 242462306a36Sopenharmony_ci value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci if (!rt2x00_rf(rt2x00dev, RF5225) && 242762306a36Sopenharmony_ci !rt2x00_rf(rt2x00dev, RF5325) && 242862306a36Sopenharmony_ci !rt2x00_rf(rt2x00dev, RF2527) && 242962306a36Sopenharmony_ci !rt2x00_rf(rt2x00dev, RF2529)) { 243062306a36Sopenharmony_ci rt2x00_err(rt2x00dev, "Invalid RF chipset detected\n"); 243162306a36Sopenharmony_ci return -ENODEV; 243262306a36Sopenharmony_ci } 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_ci /* 243562306a36Sopenharmony_ci * Determine number of antennas. 243662306a36Sopenharmony_ci */ 243762306a36Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) 243862306a36Sopenharmony_ci __set_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags); 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci /* 244162306a36Sopenharmony_ci * Identify default antenna configuration. 244262306a36Sopenharmony_ci */ 244362306a36Sopenharmony_ci rt2x00dev->default_ant.tx = 244462306a36Sopenharmony_ci rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); 244562306a36Sopenharmony_ci rt2x00dev->default_ant.rx = 244662306a36Sopenharmony_ci rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci /* 244962306a36Sopenharmony_ci * Read the Frame type. 245062306a36Sopenharmony_ci */ 245162306a36Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) 245262306a36Sopenharmony_ci __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci /* 245562306a36Sopenharmony_ci * Detect if this device has a hardware controlled radio. 245662306a36Sopenharmony_ci */ 245762306a36Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) 245862306a36Sopenharmony_ci __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci /* 246162306a36Sopenharmony_ci * Read frequency offset and RF programming sequence. 246262306a36Sopenharmony_ci */ 246362306a36Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); 246462306a36Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ)) 246562306a36Sopenharmony_ci __set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags); 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci /* 247062306a36Sopenharmony_ci * Read external LNA informations. 247162306a36Sopenharmony_ci */ 247262306a36Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) 247562306a36Sopenharmony_ci __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); 247662306a36Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) 247762306a36Sopenharmony_ci __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci /* 248062306a36Sopenharmony_ci * When working with a RF2529 chip without double antenna, 248162306a36Sopenharmony_ci * the antenna settings should be gathered from the NIC 248262306a36Sopenharmony_ci * eeprom word. 248362306a36Sopenharmony_ci */ 248462306a36Sopenharmony_ci if (rt2x00_rf(rt2x00dev, RF2529) && 248562306a36Sopenharmony_ci !rt2x00_has_cap_double_antenna(rt2x00dev)) { 248662306a36Sopenharmony_ci rt2x00dev->default_ant.rx = 248762306a36Sopenharmony_ci ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED); 248862306a36Sopenharmony_ci rt2x00dev->default_ant.tx = 248962306a36Sopenharmony_ci ANTENNA_B - rt2x00_get_field16(eeprom, EEPROM_NIC_TX_FIXED); 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) 249262306a36Sopenharmony_ci rt2x00dev->default_ant.tx = ANTENNA_SW_DIVERSITY; 249362306a36Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) 249462306a36Sopenharmony_ci rt2x00dev->default_ant.rx = ANTENNA_SW_DIVERSITY; 249562306a36Sopenharmony_ci } 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci /* 249862306a36Sopenharmony_ci * Store led settings, for correct led behaviour. 249962306a36Sopenharmony_ci * If the eeprom value is invalid, 250062306a36Sopenharmony_ci * switch to default led mode. 250162306a36Sopenharmony_ci */ 250262306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_LEDS 250362306a36Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); 250462306a36Sopenharmony_ci value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci rt61pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); 250762306a36Sopenharmony_ci rt61pci_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); 250862306a36Sopenharmony_ci if (value == LED_MODE_SIGNAL_STRENGTH) 250962306a36Sopenharmony_ci rt61pci_init_led(rt2x00dev, &rt2x00dev->led_qual, 251062306a36Sopenharmony_ci LED_TYPE_QUALITY); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_LED_MODE, value); 251362306a36Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_0, 251462306a36Sopenharmony_ci rt2x00_get_field16(eeprom, 251562306a36Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_0)); 251662306a36Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_1, 251762306a36Sopenharmony_ci rt2x00_get_field16(eeprom, 251862306a36Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_1)); 251962306a36Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_2, 252062306a36Sopenharmony_ci rt2x00_get_field16(eeprom, 252162306a36Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_2)); 252262306a36Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_3, 252362306a36Sopenharmony_ci rt2x00_get_field16(eeprom, 252462306a36Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_3)); 252562306a36Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_GPIO_4, 252662306a36Sopenharmony_ci rt2x00_get_field16(eeprom, 252762306a36Sopenharmony_ci EEPROM_LED_POLARITY_GPIO_4)); 252862306a36Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_ACT, 252962306a36Sopenharmony_ci rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT)); 253062306a36Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_BG, 253162306a36Sopenharmony_ci rt2x00_get_field16(eeprom, 253262306a36Sopenharmony_ci EEPROM_LED_POLARITY_RDY_G)); 253362306a36Sopenharmony_ci rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, 253462306a36Sopenharmony_ci rt2x00_get_field16(eeprom, 253562306a36Sopenharmony_ci EEPROM_LED_POLARITY_RDY_A)); 253662306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_LEDS */ 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci return 0; 253962306a36Sopenharmony_ci} 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci/* 254262306a36Sopenharmony_ci * RF value list for RF5225 & RF5325 254362306a36Sopenharmony_ci * Supports: 2.4 GHz & 5.2 GHz, rf_sequence disabled 254462306a36Sopenharmony_ci */ 254562306a36Sopenharmony_cistatic const struct rf_channel rf_vals_noseq[] = { 254662306a36Sopenharmony_ci { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, 254762306a36Sopenharmony_ci { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, 254862306a36Sopenharmony_ci { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, 254962306a36Sopenharmony_ci { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, 255062306a36Sopenharmony_ci { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, 255162306a36Sopenharmony_ci { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, 255262306a36Sopenharmony_ci { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, 255362306a36Sopenharmony_ci { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, 255462306a36Sopenharmony_ci { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, 255562306a36Sopenharmony_ci { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, 255662306a36Sopenharmony_ci { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, 255762306a36Sopenharmony_ci { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, 255862306a36Sopenharmony_ci { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, 255962306a36Sopenharmony_ci { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci /* 802.11 UNI / HyperLan 2 */ 256262306a36Sopenharmony_ci { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 }, 256362306a36Sopenharmony_ci { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 }, 256462306a36Sopenharmony_ci { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b }, 256562306a36Sopenharmony_ci { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 }, 256662306a36Sopenharmony_ci { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b }, 256762306a36Sopenharmony_ci { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 }, 256862306a36Sopenharmony_ci { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 }, 256962306a36Sopenharmony_ci { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b }, 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci /* 802.11 HyperLan 2 */ 257262306a36Sopenharmony_ci { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 }, 257362306a36Sopenharmony_ci { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b }, 257462306a36Sopenharmony_ci { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 }, 257562306a36Sopenharmony_ci { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b }, 257662306a36Sopenharmony_ci { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 }, 257762306a36Sopenharmony_ci { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 }, 257862306a36Sopenharmony_ci { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b }, 257962306a36Sopenharmony_ci { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 }, 258062306a36Sopenharmony_ci { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b }, 258162306a36Sopenharmony_ci { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 }, 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci /* 802.11 UNII */ 258462306a36Sopenharmony_ci { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 }, 258562306a36Sopenharmony_ci { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f }, 258662306a36Sopenharmony_ci { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 }, 258762306a36Sopenharmony_ci { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 }, 258862306a36Sopenharmony_ci { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f }, 258962306a36Sopenharmony_ci { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 }, 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci /* MMAC(Japan)J52 ch 34,38,42,46 */ 259262306a36Sopenharmony_ci { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b }, 259362306a36Sopenharmony_ci { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 }, 259462306a36Sopenharmony_ci { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b }, 259562306a36Sopenharmony_ci { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 }, 259662306a36Sopenharmony_ci}; 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci/* 259962306a36Sopenharmony_ci * RF value list for RF5225 & RF5325 260062306a36Sopenharmony_ci * Supports: 2.4 GHz & 5.2 GHz, rf_sequence enabled 260162306a36Sopenharmony_ci */ 260262306a36Sopenharmony_cistatic const struct rf_channel rf_vals_seq[] = { 260362306a36Sopenharmony_ci { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, 260462306a36Sopenharmony_ci { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, 260562306a36Sopenharmony_ci { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, 260662306a36Sopenharmony_ci { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, 260762306a36Sopenharmony_ci { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, 260862306a36Sopenharmony_ci { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, 260962306a36Sopenharmony_ci { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, 261062306a36Sopenharmony_ci { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, 261162306a36Sopenharmony_ci { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, 261262306a36Sopenharmony_ci { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, 261362306a36Sopenharmony_ci { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, 261462306a36Sopenharmony_ci { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, 261562306a36Sopenharmony_ci { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, 261662306a36Sopenharmony_ci { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci /* 802.11 UNI / HyperLan 2 */ 261962306a36Sopenharmony_ci { 36, 0x00002cd4, 0x0004481a, 0x00098455, 0x000c0a03 }, 262062306a36Sopenharmony_ci { 40, 0x00002cd0, 0x00044682, 0x00098455, 0x000c0a03 }, 262162306a36Sopenharmony_ci { 44, 0x00002cd0, 0x00044686, 0x00098455, 0x000c0a1b }, 262262306a36Sopenharmony_ci { 48, 0x00002cd0, 0x0004468e, 0x00098655, 0x000c0a0b }, 262362306a36Sopenharmony_ci { 52, 0x00002cd0, 0x00044692, 0x00098855, 0x000c0a23 }, 262462306a36Sopenharmony_ci { 56, 0x00002cd0, 0x0004469a, 0x00098c55, 0x000c0a13 }, 262562306a36Sopenharmony_ci { 60, 0x00002cd0, 0x000446a2, 0x00098e55, 0x000c0a03 }, 262662306a36Sopenharmony_ci { 64, 0x00002cd0, 0x000446a6, 0x00099255, 0x000c0a1b }, 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci /* 802.11 HyperLan 2 */ 262962306a36Sopenharmony_ci { 100, 0x00002cd4, 0x0004489a, 0x000b9855, 0x000c0a03 }, 263062306a36Sopenharmony_ci { 104, 0x00002cd4, 0x000448a2, 0x000b9855, 0x000c0a03 }, 263162306a36Sopenharmony_ci { 108, 0x00002cd4, 0x000448aa, 0x000b9855, 0x000c0a03 }, 263262306a36Sopenharmony_ci { 112, 0x00002cd4, 0x000448b2, 0x000b9a55, 0x000c0a03 }, 263362306a36Sopenharmony_ci { 116, 0x00002cd4, 0x000448ba, 0x000b9a55, 0x000c0a03 }, 263462306a36Sopenharmony_ci { 120, 0x00002cd0, 0x00044702, 0x000b9a55, 0x000c0a03 }, 263562306a36Sopenharmony_ci { 124, 0x00002cd0, 0x00044706, 0x000b9a55, 0x000c0a1b }, 263662306a36Sopenharmony_ci { 128, 0x00002cd0, 0x0004470e, 0x000b9c55, 0x000c0a0b }, 263762306a36Sopenharmony_ci { 132, 0x00002cd0, 0x00044712, 0x000b9c55, 0x000c0a23 }, 263862306a36Sopenharmony_ci { 136, 0x00002cd0, 0x0004471a, 0x000b9e55, 0x000c0a13 }, 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci /* 802.11 UNII */ 264162306a36Sopenharmony_ci { 140, 0x00002cd0, 0x00044722, 0x000b9e55, 0x000c0a03 }, 264262306a36Sopenharmony_ci { 149, 0x00002cd0, 0x0004472e, 0x000ba255, 0x000c0a1b }, 264362306a36Sopenharmony_ci { 153, 0x00002cd0, 0x00044736, 0x000ba255, 0x000c0a0b }, 264462306a36Sopenharmony_ci { 157, 0x00002cd4, 0x0004490a, 0x000ba255, 0x000c0a17 }, 264562306a36Sopenharmony_ci { 161, 0x00002cd4, 0x00044912, 0x000ba255, 0x000c0a17 }, 264662306a36Sopenharmony_ci { 165, 0x00002cd4, 0x0004491a, 0x000ba255, 0x000c0a17 }, 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci /* MMAC(Japan)J52 ch 34,38,42,46 */ 264962306a36Sopenharmony_ci { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000c0a0b }, 265062306a36Sopenharmony_ci { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000c0a13 }, 265162306a36Sopenharmony_ci { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000c0a1b }, 265262306a36Sopenharmony_ci { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 }, 265362306a36Sopenharmony_ci}; 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_cistatic int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) 265662306a36Sopenharmony_ci{ 265762306a36Sopenharmony_ci struct hw_mode_spec *spec = &rt2x00dev->spec; 265862306a36Sopenharmony_ci struct channel_info *info; 265962306a36Sopenharmony_ci u8 *tx_power; 266062306a36Sopenharmony_ci unsigned int i; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci /* 266362306a36Sopenharmony_ci * Disable powersaving as default. 266462306a36Sopenharmony_ci */ 266562306a36Sopenharmony_ci rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci /* 266862306a36Sopenharmony_ci * Initialize all hw fields. 266962306a36Sopenharmony_ci */ 267062306a36Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK); 267162306a36Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS); 267262306a36Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING); 267362306a36Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM); 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); 267662306a36Sopenharmony_ci SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, 267762306a36Sopenharmony_ci rt2x00_eeprom_addr(rt2x00dev, 267862306a36Sopenharmony_ci EEPROM_MAC_ADDR_0)); 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_ci /* 268162306a36Sopenharmony_ci * As rt61 has a global fallback table we cannot specify 268262306a36Sopenharmony_ci * more then one tx rate per frame but since the hw will 268362306a36Sopenharmony_ci * try several rates (based on the fallback table) we should 268462306a36Sopenharmony_ci * initialize max_report_rates to the maximum number of rates 268562306a36Sopenharmony_ci * we are going to try. Otherwise mac80211 will truncate our 268662306a36Sopenharmony_ci * reported tx rates and the rc algortihm will end up with 268762306a36Sopenharmony_ci * incorrect data. 268862306a36Sopenharmony_ci */ 268962306a36Sopenharmony_ci rt2x00dev->hw->max_rates = 1; 269062306a36Sopenharmony_ci rt2x00dev->hw->max_report_rates = 7; 269162306a36Sopenharmony_ci rt2x00dev->hw->max_rate_tries = 1; 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci /* 269462306a36Sopenharmony_ci * Initialize hw_mode information. 269562306a36Sopenharmony_ci */ 269662306a36Sopenharmony_ci spec->supported_bands = SUPPORT_BAND_2GHZ; 269762306a36Sopenharmony_ci spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci if (!rt2x00_has_cap_rf_sequence(rt2x00dev)) { 270062306a36Sopenharmony_ci spec->num_channels = 14; 270162306a36Sopenharmony_ci spec->channels = rf_vals_noseq; 270262306a36Sopenharmony_ci } else { 270362306a36Sopenharmony_ci spec->num_channels = 14; 270462306a36Sopenharmony_ci spec->channels = rf_vals_seq; 270562306a36Sopenharmony_ci } 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) { 270862306a36Sopenharmony_ci spec->supported_bands |= SUPPORT_BAND_5GHZ; 270962306a36Sopenharmony_ci spec->num_channels = ARRAY_SIZE(rf_vals_seq); 271062306a36Sopenharmony_ci } 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci /* 271362306a36Sopenharmony_ci * Create channel information array 271462306a36Sopenharmony_ci */ 271562306a36Sopenharmony_ci info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); 271662306a36Sopenharmony_ci if (!info) 271762306a36Sopenharmony_ci return -ENOMEM; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci spec->channels_info = info; 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); 272262306a36Sopenharmony_ci for (i = 0; i < 14; i++) { 272362306a36Sopenharmony_ci info[i].max_power = MAX_TXPOWER; 272462306a36Sopenharmony_ci info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); 272562306a36Sopenharmony_ci } 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci if (spec->num_channels > 14) { 272862306a36Sopenharmony_ci tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); 272962306a36Sopenharmony_ci for (i = 14; i < spec->num_channels; i++) { 273062306a36Sopenharmony_ci info[i].max_power = MAX_TXPOWER; 273162306a36Sopenharmony_ci info[i].default_power1 = 273262306a36Sopenharmony_ci TXPOWER_FROM_DEV(tx_power[i - 14]); 273362306a36Sopenharmony_ci } 273462306a36Sopenharmony_ci } 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci return 0; 273762306a36Sopenharmony_ci} 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_cistatic int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) 274062306a36Sopenharmony_ci{ 274162306a36Sopenharmony_ci int retval; 274262306a36Sopenharmony_ci u32 reg; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci /* 274562306a36Sopenharmony_ci * Disable power saving. 274662306a36Sopenharmony_ci */ 274762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007); 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci /* 275062306a36Sopenharmony_ci * Allocate eeprom data. 275162306a36Sopenharmony_ci */ 275262306a36Sopenharmony_ci retval = rt61pci_validate_eeprom(rt2x00dev); 275362306a36Sopenharmony_ci if (retval) 275462306a36Sopenharmony_ci return retval; 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_ci retval = rt61pci_init_eeprom(rt2x00dev); 275762306a36Sopenharmony_ci if (retval) 275862306a36Sopenharmony_ci return retval; 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci /* 276162306a36Sopenharmony_ci * Enable rfkill polling by setting GPIO direction of the 276262306a36Sopenharmony_ci * rfkill switch GPIO pin correctly. 276362306a36Sopenharmony_ci */ 276462306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); 276562306a36Sopenharmony_ci rt2x00_set_field32(®, MAC_CSR13_DIR5, 1); 276662306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg); 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci /* 276962306a36Sopenharmony_ci * Initialize hw specifications. 277062306a36Sopenharmony_ci */ 277162306a36Sopenharmony_ci retval = rt61pci_probe_hw_mode(rt2x00dev); 277262306a36Sopenharmony_ci if (retval) 277362306a36Sopenharmony_ci return retval; 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci /* 277662306a36Sopenharmony_ci * This device has multiple filters for control frames, 277762306a36Sopenharmony_ci * but has no a separate filter for PS Poll frames. 277862306a36Sopenharmony_ci */ 277962306a36Sopenharmony_ci __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci /* 278262306a36Sopenharmony_ci * This device requires firmware and DMA mapped skbs. 278362306a36Sopenharmony_ci */ 278462306a36Sopenharmony_ci __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); 278562306a36Sopenharmony_ci __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); 278662306a36Sopenharmony_ci if (!modparam_nohwcrypt) 278762306a36Sopenharmony_ci __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); 278862306a36Sopenharmony_ci __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci /* 279162306a36Sopenharmony_ci * Set the rssi offset. 279262306a36Sopenharmony_ci */ 279362306a36Sopenharmony_ci rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci return 0; 279662306a36Sopenharmony_ci} 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci/* 279962306a36Sopenharmony_ci * IEEE80211 stack callback functions. 280062306a36Sopenharmony_ci */ 280162306a36Sopenharmony_cistatic int rt61pci_conf_tx(struct ieee80211_hw *hw, 280262306a36Sopenharmony_ci struct ieee80211_vif *vif, 280362306a36Sopenharmony_ci unsigned int link_id, u16 queue_idx, 280462306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 280562306a36Sopenharmony_ci{ 280662306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 280762306a36Sopenharmony_ci struct data_queue *queue; 280862306a36Sopenharmony_ci struct rt2x00_field32 field; 280962306a36Sopenharmony_ci int retval; 281062306a36Sopenharmony_ci u32 reg; 281162306a36Sopenharmony_ci u32 offset; 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci /* 281462306a36Sopenharmony_ci * First pass the configuration through rt2x00lib, that will 281562306a36Sopenharmony_ci * update the queue settings and validate the input. After that 281662306a36Sopenharmony_ci * we are free to update the registers based on the value 281762306a36Sopenharmony_ci * in the queue parameter. 281862306a36Sopenharmony_ci */ 281962306a36Sopenharmony_ci retval = rt2x00mac_conf_tx(hw, vif, link_id, queue_idx, params); 282062306a36Sopenharmony_ci if (retval) 282162306a36Sopenharmony_ci return retval; 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_ci /* 282462306a36Sopenharmony_ci * We only need to perform additional register initialization 282562306a36Sopenharmony_ci * for WMM queues. 282662306a36Sopenharmony_ci */ 282762306a36Sopenharmony_ci if (queue_idx >= 4) 282862306a36Sopenharmony_ci return 0; 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci /* Update WMM TXOP register */ 283362306a36Sopenharmony_ci offset = AC_TXOP_CSR0 + (sizeof(u32) * (!!(queue_idx & 2))); 283462306a36Sopenharmony_ci field.bit_offset = (queue_idx & 1) * 16; 283562306a36Sopenharmony_ci field.bit_mask = 0xffff << field.bit_offset; 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, offset); 283862306a36Sopenharmony_ci rt2x00_set_field32(®, field, queue->txop); 283962306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, offset, reg); 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci /* Update WMM registers */ 284262306a36Sopenharmony_ci field.bit_offset = queue_idx * 4; 284362306a36Sopenharmony_ci field.bit_mask = 0xf << field.bit_offset; 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, AIFSN_CSR); 284662306a36Sopenharmony_ci rt2x00_set_field32(®, field, queue->aifs); 284762306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, AIFSN_CSR, reg); 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CWMIN_CSR); 285062306a36Sopenharmony_ci rt2x00_set_field32(®, field, queue->cw_min); 285162306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CWMIN_CSR, reg); 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CWMAX_CSR); 285462306a36Sopenharmony_ci rt2x00_set_field32(®, field, queue->cw_max); 285562306a36Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CWMAX_CSR, reg); 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci return 0; 285862306a36Sopenharmony_ci} 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_cistatic u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 286162306a36Sopenharmony_ci{ 286262306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 286362306a36Sopenharmony_ci u64 tsf; 286462306a36Sopenharmony_ci u32 reg; 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR13); 286762306a36Sopenharmony_ci tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; 286862306a36Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR12); 286962306a36Sopenharmony_ci tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci return tsf; 287262306a36Sopenharmony_ci} 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_cistatic const struct ieee80211_ops rt61pci_mac80211_ops = { 287562306a36Sopenharmony_ci .tx = rt2x00mac_tx, 287662306a36Sopenharmony_ci .wake_tx_queue = ieee80211_handle_wake_tx_queue, 287762306a36Sopenharmony_ci .start = rt2x00mac_start, 287862306a36Sopenharmony_ci .stop = rt2x00mac_stop, 287962306a36Sopenharmony_ci .add_interface = rt2x00mac_add_interface, 288062306a36Sopenharmony_ci .remove_interface = rt2x00mac_remove_interface, 288162306a36Sopenharmony_ci .config = rt2x00mac_config, 288262306a36Sopenharmony_ci .configure_filter = rt2x00mac_configure_filter, 288362306a36Sopenharmony_ci .set_key = rt2x00mac_set_key, 288462306a36Sopenharmony_ci .sw_scan_start = rt2x00mac_sw_scan_start, 288562306a36Sopenharmony_ci .sw_scan_complete = rt2x00mac_sw_scan_complete, 288662306a36Sopenharmony_ci .get_stats = rt2x00mac_get_stats, 288762306a36Sopenharmony_ci .bss_info_changed = rt2x00mac_bss_info_changed, 288862306a36Sopenharmony_ci .conf_tx = rt61pci_conf_tx, 288962306a36Sopenharmony_ci .get_tsf = rt61pci_get_tsf, 289062306a36Sopenharmony_ci .rfkill_poll = rt2x00mac_rfkill_poll, 289162306a36Sopenharmony_ci .flush = rt2x00mac_flush, 289262306a36Sopenharmony_ci .set_antenna = rt2x00mac_set_antenna, 289362306a36Sopenharmony_ci .get_antenna = rt2x00mac_get_antenna, 289462306a36Sopenharmony_ci .get_ringparam = rt2x00mac_get_ringparam, 289562306a36Sopenharmony_ci .tx_frames_pending = rt2x00mac_tx_frames_pending, 289662306a36Sopenharmony_ci}; 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_cistatic const struct rt2x00lib_ops rt61pci_rt2x00_ops = { 289962306a36Sopenharmony_ci .irq_handler = rt61pci_interrupt, 290062306a36Sopenharmony_ci .txstatus_tasklet = rt61pci_txstatus_tasklet, 290162306a36Sopenharmony_ci .tbtt_tasklet = rt61pci_tbtt_tasklet, 290262306a36Sopenharmony_ci .rxdone_tasklet = rt61pci_rxdone_tasklet, 290362306a36Sopenharmony_ci .autowake_tasklet = rt61pci_autowake_tasklet, 290462306a36Sopenharmony_ci .probe_hw = rt61pci_probe_hw, 290562306a36Sopenharmony_ci .get_firmware_name = rt61pci_get_firmware_name, 290662306a36Sopenharmony_ci .check_firmware = rt61pci_check_firmware, 290762306a36Sopenharmony_ci .load_firmware = rt61pci_load_firmware, 290862306a36Sopenharmony_ci .initialize = rt2x00mmio_initialize, 290962306a36Sopenharmony_ci .uninitialize = rt2x00mmio_uninitialize, 291062306a36Sopenharmony_ci .get_entry_state = rt61pci_get_entry_state, 291162306a36Sopenharmony_ci .clear_entry = rt61pci_clear_entry, 291262306a36Sopenharmony_ci .set_device_state = rt61pci_set_device_state, 291362306a36Sopenharmony_ci .rfkill_poll = rt61pci_rfkill_poll, 291462306a36Sopenharmony_ci .link_stats = rt61pci_link_stats, 291562306a36Sopenharmony_ci .reset_tuner = rt61pci_reset_tuner, 291662306a36Sopenharmony_ci .link_tuner = rt61pci_link_tuner, 291762306a36Sopenharmony_ci .start_queue = rt61pci_start_queue, 291862306a36Sopenharmony_ci .kick_queue = rt61pci_kick_queue, 291962306a36Sopenharmony_ci .stop_queue = rt61pci_stop_queue, 292062306a36Sopenharmony_ci .flush_queue = rt2x00mmio_flush_queue, 292162306a36Sopenharmony_ci .write_tx_desc = rt61pci_write_tx_desc, 292262306a36Sopenharmony_ci .write_beacon = rt61pci_write_beacon, 292362306a36Sopenharmony_ci .clear_beacon = rt61pci_clear_beacon, 292462306a36Sopenharmony_ci .fill_rxdone = rt61pci_fill_rxdone, 292562306a36Sopenharmony_ci .config_shared_key = rt61pci_config_shared_key, 292662306a36Sopenharmony_ci .config_pairwise_key = rt61pci_config_pairwise_key, 292762306a36Sopenharmony_ci .config_filter = rt61pci_config_filter, 292862306a36Sopenharmony_ci .config_intf = rt61pci_config_intf, 292962306a36Sopenharmony_ci .config_erp = rt61pci_config_erp, 293062306a36Sopenharmony_ci .config_ant = rt61pci_config_ant, 293162306a36Sopenharmony_ci .config = rt61pci_config, 293262306a36Sopenharmony_ci}; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_cistatic void rt61pci_queue_init(struct data_queue *queue) 293562306a36Sopenharmony_ci{ 293662306a36Sopenharmony_ci switch (queue->qid) { 293762306a36Sopenharmony_ci case QID_RX: 293862306a36Sopenharmony_ci queue->limit = 32; 293962306a36Sopenharmony_ci queue->data_size = DATA_FRAME_SIZE; 294062306a36Sopenharmony_ci queue->desc_size = RXD_DESC_SIZE; 294162306a36Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 294262306a36Sopenharmony_ci break; 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci case QID_AC_VO: 294562306a36Sopenharmony_ci case QID_AC_VI: 294662306a36Sopenharmony_ci case QID_AC_BE: 294762306a36Sopenharmony_ci case QID_AC_BK: 294862306a36Sopenharmony_ci queue->limit = 32; 294962306a36Sopenharmony_ci queue->data_size = DATA_FRAME_SIZE; 295062306a36Sopenharmony_ci queue->desc_size = TXD_DESC_SIZE; 295162306a36Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 295262306a36Sopenharmony_ci break; 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci case QID_BEACON: 295562306a36Sopenharmony_ci queue->limit = 4; 295662306a36Sopenharmony_ci queue->data_size = 0; /* No DMA required for beacons */ 295762306a36Sopenharmony_ci queue->desc_size = TXINFO_SIZE; 295862306a36Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 295962306a36Sopenharmony_ci break; 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_ci case QID_ATIM: 296262306a36Sopenharmony_ci default: 296362306a36Sopenharmony_ci BUG(); 296462306a36Sopenharmony_ci break; 296562306a36Sopenharmony_ci } 296662306a36Sopenharmony_ci} 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_cistatic const struct rt2x00_ops rt61pci_ops = { 296962306a36Sopenharmony_ci .name = KBUILD_MODNAME, 297062306a36Sopenharmony_ci .max_ap_intf = 4, 297162306a36Sopenharmony_ci .eeprom_size = EEPROM_SIZE, 297262306a36Sopenharmony_ci .rf_size = RF_SIZE, 297362306a36Sopenharmony_ci .tx_queues = NUM_TX_QUEUES, 297462306a36Sopenharmony_ci .queue_init = rt61pci_queue_init, 297562306a36Sopenharmony_ci .lib = &rt61pci_rt2x00_ops, 297662306a36Sopenharmony_ci .hw = &rt61pci_mac80211_ops, 297762306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_DEBUGFS 297862306a36Sopenharmony_ci .debugfs = &rt61pci_rt2x00debug, 297962306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ 298062306a36Sopenharmony_ci}; 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci/* 298362306a36Sopenharmony_ci * RT61pci module information. 298462306a36Sopenharmony_ci */ 298562306a36Sopenharmony_cistatic const struct pci_device_id rt61pci_device_table[] = { 298662306a36Sopenharmony_ci /* RT2561s */ 298762306a36Sopenharmony_ci { PCI_DEVICE(0x1814, 0x0301) }, 298862306a36Sopenharmony_ci /* RT2561 v2 */ 298962306a36Sopenharmony_ci { PCI_DEVICE(0x1814, 0x0302) }, 299062306a36Sopenharmony_ci /* RT2661 */ 299162306a36Sopenharmony_ci { PCI_DEVICE(0x1814, 0x0401) }, 299262306a36Sopenharmony_ci { 0, } 299362306a36Sopenharmony_ci}; 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ciMODULE_AUTHOR(DRV_PROJECT); 299662306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 299762306a36Sopenharmony_ciMODULE_DESCRIPTION("Ralink RT61 PCI & PCMCIA Wireless LAN driver."); 299862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rt61pci_device_table); 299962306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RT2561); 300062306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RT2561s); 300162306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_RT2661); 300262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_cistatic int rt61pci_probe(struct pci_dev *pci_dev, 300562306a36Sopenharmony_ci const struct pci_device_id *id) 300662306a36Sopenharmony_ci{ 300762306a36Sopenharmony_ci return rt2x00pci_probe(pci_dev, &rt61pci_ops); 300862306a36Sopenharmony_ci} 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_cistatic struct pci_driver rt61pci_driver = { 301162306a36Sopenharmony_ci .name = KBUILD_MODNAME, 301262306a36Sopenharmony_ci .id_table = rt61pci_device_table, 301362306a36Sopenharmony_ci .probe = rt61pci_probe, 301462306a36Sopenharmony_ci .remove = rt2x00pci_remove, 301562306a36Sopenharmony_ci .driver.pm = &rt2x00pci_pm_ops, 301662306a36Sopenharmony_ci}; 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_cimodule_pci_driver(rt61pci_driver); 3019