18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> 48c2ecf20Sopenharmony_ci <http://rt2x00.serialmonkey.com> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci Module: rt2400pci 108c2ecf20Sopenharmony_ci Abstract: rt2400pci device specific routines. 118c2ecf20Sopenharmony_ci Supported chipsets: RT2460. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/pci.h> 198c2ecf20Sopenharmony_ci#include <linux/eeprom_93cx6.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "rt2x00.h" 238c2ecf20Sopenharmony_ci#include "rt2x00mmio.h" 248c2ecf20Sopenharmony_ci#include "rt2x00pci.h" 258c2ecf20Sopenharmony_ci#include "rt2400pci.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * Register access. 298c2ecf20Sopenharmony_ci * All access to the CSR registers will go through the methods 308c2ecf20Sopenharmony_ci * rt2x00mmio_register_read and rt2x00mmio_register_write. 318c2ecf20Sopenharmony_ci * BBP and RF register require indirect register access, 328c2ecf20Sopenharmony_ci * and use the CSR registers BBPCSR and RFCSR to achieve this. 338c2ecf20Sopenharmony_ci * These indirect registers work with busy bits, 348c2ecf20Sopenharmony_ci * and we will try maximal REGISTER_BUSY_COUNT times to access 358c2ecf20Sopenharmony_ci * the register while taking a REGISTER_BUSY_DELAY us delay 368c2ecf20Sopenharmony_ci * between each attempt. When the busy bit is still set at that time, 378c2ecf20Sopenharmony_ci * the access attempt is considered to have failed, 388c2ecf20Sopenharmony_ci * and we will print an error. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci#define WAIT_FOR_BBP(__dev, __reg) \ 418c2ecf20Sopenharmony_ci rt2x00mmio_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg)) 428c2ecf20Sopenharmony_ci#define WAIT_FOR_RF(__dev, __reg) \ 438c2ecf20Sopenharmony_ci rt2x00mmio_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg)) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, 468c2ecf20Sopenharmony_ci const unsigned int word, const u8 value) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci u32 reg; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* 538c2ecf20Sopenharmony_ci * Wait until the BBP becomes available, afterwards we 548c2ecf20Sopenharmony_ci * can safely write the new data into the register. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci if (WAIT_FOR_BBP(rt2x00dev, ®)) { 578c2ecf20Sopenharmony_ci reg = 0; 588c2ecf20Sopenharmony_ci rt2x00_set_field32(®, BBPCSR_VALUE, value); 598c2ecf20Sopenharmony_ci rt2x00_set_field32(®, BBPCSR_REGNUM, word); 608c2ecf20Sopenharmony_ci rt2x00_set_field32(®, BBPCSR_BUSY, 1); 618c2ecf20Sopenharmony_ci rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, BBPCSR, reg); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic u8 rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, 708c2ecf20Sopenharmony_ci const unsigned int word) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci u32 reg; 738c2ecf20Sopenharmony_ci u8 value; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * Wait until the BBP becomes available, afterwards we 798c2ecf20Sopenharmony_ci * can safely write the read request into the register. 808c2ecf20Sopenharmony_ci * After the data has been written, we wait until hardware 818c2ecf20Sopenharmony_ci * returns the correct value, if at any time the register 828c2ecf20Sopenharmony_ci * doesn't become available in time, reg will be 0xffffffff 838c2ecf20Sopenharmony_ci * which means we return 0xff to the caller. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci if (WAIT_FOR_BBP(rt2x00dev, ®)) { 868c2ecf20Sopenharmony_ci reg = 0; 878c2ecf20Sopenharmony_ci rt2x00_set_field32(®, BBPCSR_REGNUM, word); 888c2ecf20Sopenharmony_ci rt2x00_set_field32(®, BBPCSR_BUSY, 1); 898c2ecf20Sopenharmony_ci rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, BBPCSR, reg); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci WAIT_FOR_BBP(rt2x00dev, ®); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci value = rt2x00_get_field32(reg, BBPCSR_VALUE); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return value; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, 1048c2ecf20Sopenharmony_ci const unsigned int word, const u32 value) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci u32 reg; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci mutex_lock(&rt2x00dev->csr_mutex); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* 1118c2ecf20Sopenharmony_ci * Wait until the RF becomes available, afterwards we 1128c2ecf20Sopenharmony_ci * can safely write the new data into the register. 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci if (WAIT_FOR_RF(rt2x00dev, ®)) { 1158c2ecf20Sopenharmony_ci reg = 0; 1168c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RFCSR_VALUE, value); 1178c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); 1188c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); 1198c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RFCSR_BUSY, 1); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RFCSR, reg); 1228c2ecf20Sopenharmony_ci rt2x00_rf_write(rt2x00dev, word, value); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci mutex_unlock(&rt2x00dev->csr_mutex); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = eeprom->data; 1318c2ecf20Sopenharmony_ci u32 reg; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR21); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN); 1368c2ecf20Sopenharmony_ci eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT); 1378c2ecf20Sopenharmony_ci eeprom->reg_data_clock = 1388c2ecf20Sopenharmony_ci !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK); 1398c2ecf20Sopenharmony_ci eeprom->reg_chip_select = 1408c2ecf20Sopenharmony_ci !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = eeprom->data; 1468c2ecf20Sopenharmony_ci u32 reg = 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in); 1498c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out); 1508c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR21_EEPROM_DATA_CLOCK, 1518c2ecf20Sopenharmony_ci !!eeprom->reg_data_clock); 1528c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR21_EEPROM_CHIP_SELECT, 1538c2ecf20Sopenharmony_ci !!eeprom->reg_chip_select); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR21, reg); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_DEBUGFS 1598c2ecf20Sopenharmony_cistatic const struct rt2x00debug rt2400pci_rt2x00debug = { 1608c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1618c2ecf20Sopenharmony_ci .csr = { 1628c2ecf20Sopenharmony_ci .read = rt2x00mmio_register_read, 1638c2ecf20Sopenharmony_ci .write = rt2x00mmio_register_write, 1648c2ecf20Sopenharmony_ci .flags = RT2X00DEBUGFS_OFFSET, 1658c2ecf20Sopenharmony_ci .word_base = CSR_REG_BASE, 1668c2ecf20Sopenharmony_ci .word_size = sizeof(u32), 1678c2ecf20Sopenharmony_ci .word_count = CSR_REG_SIZE / sizeof(u32), 1688c2ecf20Sopenharmony_ci }, 1698c2ecf20Sopenharmony_ci .eeprom = { 1708c2ecf20Sopenharmony_ci .read = rt2x00_eeprom_read, 1718c2ecf20Sopenharmony_ci .write = rt2x00_eeprom_write, 1728c2ecf20Sopenharmony_ci .word_base = EEPROM_BASE, 1738c2ecf20Sopenharmony_ci .word_size = sizeof(u16), 1748c2ecf20Sopenharmony_ci .word_count = EEPROM_SIZE / sizeof(u16), 1758c2ecf20Sopenharmony_ci }, 1768c2ecf20Sopenharmony_ci .bbp = { 1778c2ecf20Sopenharmony_ci .read = rt2400pci_bbp_read, 1788c2ecf20Sopenharmony_ci .write = rt2400pci_bbp_write, 1798c2ecf20Sopenharmony_ci .word_base = BBP_BASE, 1808c2ecf20Sopenharmony_ci .word_size = sizeof(u8), 1818c2ecf20Sopenharmony_ci .word_count = BBP_SIZE / sizeof(u8), 1828c2ecf20Sopenharmony_ci }, 1838c2ecf20Sopenharmony_ci .rf = { 1848c2ecf20Sopenharmony_ci .read = rt2x00_rf_read, 1858c2ecf20Sopenharmony_ci .write = rt2400pci_rf_write, 1868c2ecf20Sopenharmony_ci .word_base = RF_BASE, 1878c2ecf20Sopenharmony_ci .word_size = sizeof(u32), 1888c2ecf20Sopenharmony_ci .word_count = RF_SIZE / sizeof(u32), 1898c2ecf20Sopenharmony_ci }, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci u32 reg; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); 1988c2ecf20Sopenharmony_ci return rt2x00_get_field32(reg, GPIOCSR_VAL0); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_LEDS 2028c2ecf20Sopenharmony_cistatic void rt2400pci_brightness_set(struct led_classdev *led_cdev, 2038c2ecf20Sopenharmony_ci enum led_brightness brightness) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct rt2x00_led *led = 2068c2ecf20Sopenharmony_ci container_of(led_cdev, struct rt2x00_led, led_dev); 2078c2ecf20Sopenharmony_ci unsigned int enabled = brightness != LED_OFF; 2088c2ecf20Sopenharmony_ci u32 reg; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) 2138c2ecf20Sopenharmony_ci rt2x00_set_field32(®, LEDCSR_LINK, enabled); 2148c2ecf20Sopenharmony_ci else if (led->type == LED_TYPE_ACTIVITY) 2158c2ecf20Sopenharmony_ci rt2x00_set_field32(®, LEDCSR_ACTIVITY, enabled); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int rt2400pci_blink_set(struct led_classdev *led_cdev, 2218c2ecf20Sopenharmony_ci unsigned long *delay_on, 2228c2ecf20Sopenharmony_ci unsigned long *delay_off) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct rt2x00_led *led = 2258c2ecf20Sopenharmony_ci container_of(led_cdev, struct rt2x00_led, led_dev); 2268c2ecf20Sopenharmony_ci u32 reg; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); 2298c2ecf20Sopenharmony_ci rt2x00_set_field32(®, LEDCSR_ON_PERIOD, *delay_on); 2308c2ecf20Sopenharmony_ci rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, *delay_off); 2318c2ecf20Sopenharmony_ci rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic void rt2400pci_init_led(struct rt2x00_dev *rt2x00dev, 2378c2ecf20Sopenharmony_ci struct rt2x00_led *led, 2388c2ecf20Sopenharmony_ci enum led_type type) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci led->rt2x00dev = rt2x00dev; 2418c2ecf20Sopenharmony_ci led->type = type; 2428c2ecf20Sopenharmony_ci led->led_dev.brightness_set = rt2400pci_brightness_set; 2438c2ecf20Sopenharmony_ci led->led_dev.blink_set = rt2400pci_blink_set; 2448c2ecf20Sopenharmony_ci led->flags = LED_INITIALIZED; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_LEDS */ 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* 2498c2ecf20Sopenharmony_ci * Configuration handlers. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_cistatic void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev, 2528c2ecf20Sopenharmony_ci const unsigned int filter_flags) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci u32 reg; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * Start configuration steps. 2588c2ecf20Sopenharmony_ci * Note that the version error will always be dropped 2598c2ecf20Sopenharmony_ci * since there is no filter for it at this time. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); 2628c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR0_DROP_CRC, 2638c2ecf20Sopenharmony_ci !(filter_flags & FIF_FCSFAIL)); 2648c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 2658c2ecf20Sopenharmony_ci !(filter_flags & FIF_PLCPFAIL)); 2668c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 2678c2ecf20Sopenharmony_ci !(filter_flags & FIF_CONTROL)); 2688c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, 2698c2ecf20Sopenharmony_ci !test_bit(CONFIG_MONITORING, &rt2x00dev->flags)); 2708c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR0_DROP_TODS, 2718c2ecf20Sopenharmony_ci !test_bit(CONFIG_MONITORING, &rt2x00dev->flags) && 2728c2ecf20Sopenharmony_ci !rt2x00dev->intf_ap_count); 2738c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); 2748c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, 2788c2ecf20Sopenharmony_ci struct rt2x00_intf *intf, 2798c2ecf20Sopenharmony_ci struct rt2x00intf_conf *conf, 2808c2ecf20Sopenharmony_ci const unsigned int flags) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci unsigned int bcn_preload; 2838c2ecf20Sopenharmony_ci u32 reg; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (flags & CONFIG_UPDATE_TYPE) { 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * Enable beacon config 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); 2908c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, BCNCSR1); 2918c2ecf20Sopenharmony_ci rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); 2928c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, BCNCSR1, reg); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* 2958c2ecf20Sopenharmony_ci * Enable synchronisation. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR14); 2988c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); 2998c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR14, reg); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (flags & CONFIG_UPDATE_MAC) 3038c2ecf20Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, CSR3, 3048c2ecf20Sopenharmony_ci conf->mac, sizeof(conf->mac)); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (flags & CONFIG_UPDATE_BSSID) 3078c2ecf20Sopenharmony_ci rt2x00mmio_register_multiwrite(rt2x00dev, CSR5, 3088c2ecf20Sopenharmony_ci conf->bssid, 3098c2ecf20Sopenharmony_ci sizeof(conf->bssid)); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, 3138c2ecf20Sopenharmony_ci struct rt2x00lib_erp *erp, 3148c2ecf20Sopenharmony_ci u32 changed) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci int preamble_mask; 3178c2ecf20Sopenharmony_ci u32 reg; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* 3208c2ecf20Sopenharmony_ci * When short preamble is enabled, we should set bit 0x08 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_ERP_PREAMBLE) { 3238c2ecf20Sopenharmony_ci preamble_mask = erp->short_preamble << 3; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR1); 3268c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x1ff); 3278c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0x13a); 3288c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); 3298c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); 3308c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR1, reg); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, ARCSR2); 3338c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); 3348c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); 3358c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR2_LENGTH, 3368c2ecf20Sopenharmony_ci GET_DURATION(ACK_SIZE, 10)); 3378c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, ARCSR2, reg); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, ARCSR3); 3408c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); 3418c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); 3428c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR2_LENGTH, 3438c2ecf20Sopenharmony_ci GET_DURATION(ACK_SIZE, 20)); 3448c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, ARCSR3, reg); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, ARCSR4); 3478c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); 3488c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); 3498c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR2_LENGTH, 3508c2ecf20Sopenharmony_ci GET_DURATION(ACK_SIZE, 55)); 3518c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, ARCSR4, reg); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, ARCSR5); 3548c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); 3558c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); 3568c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR2_LENGTH, 3578c2ecf20Sopenharmony_ci GET_DURATION(ACK_SIZE, 110)); 3588c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, ARCSR5, reg); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BASIC_RATES) 3628c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, ARCSR1, erp->basic_rates); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) { 3658c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR11); 3668c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); 3678c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR11, reg); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR18); 3708c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); 3718c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); 3728c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR18, reg); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR19); 3758c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR19_DIFS, erp->difs); 3768c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); 3778c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR19, reg); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_INT) { 3818c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR12); 3828c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, 3838c2ecf20Sopenharmony_ci erp->beacon_int * 16); 3848c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, 3858c2ecf20Sopenharmony_ci erp->beacon_int * 16); 3868c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR12, reg); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev, 3918c2ecf20Sopenharmony_ci struct antenna_setup *ant) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci u8 r1; 3948c2ecf20Sopenharmony_ci u8 r4; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* 3978c2ecf20Sopenharmony_ci * We should never come here because rt2x00lib is supposed 3988c2ecf20Sopenharmony_ci * to catch this and send us the correct antenna explicitely. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ci BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || 4018c2ecf20Sopenharmony_ci ant->tx == ANTENNA_SW_DIVERSITY); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci r4 = rt2400pci_bbp_read(rt2x00dev, 4); 4048c2ecf20Sopenharmony_ci r1 = rt2400pci_bbp_read(rt2x00dev, 1); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* 4078c2ecf20Sopenharmony_ci * Configure the TX antenna. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ci switch (ant->tx) { 4108c2ecf20Sopenharmony_ci case ANTENNA_HW_DIVERSITY: 4118c2ecf20Sopenharmony_ci rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci case ANTENNA_A: 4148c2ecf20Sopenharmony_ci rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci case ANTENNA_B: 4178c2ecf20Sopenharmony_ci default: 4188c2ecf20Sopenharmony_ci rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* 4238c2ecf20Sopenharmony_ci * Configure the RX antenna. 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci switch (ant->rx) { 4268c2ecf20Sopenharmony_ci case ANTENNA_HW_DIVERSITY: 4278c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci case ANTENNA_A: 4308c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci case ANTENNA_B: 4338c2ecf20Sopenharmony_ci default: 4348c2ecf20Sopenharmony_ci rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 4, r4); 4398c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 1, r1); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, 4438c2ecf20Sopenharmony_ci struct rf_channel *rf) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci /* 4468c2ecf20Sopenharmony_ci * Switch on tuning bits. 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_ci rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1); 4498c2ecf20Sopenharmony_ci rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); 4528c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 2, rf->rf2); 4538c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* 4568c2ecf20Sopenharmony_ci * RF2420 chipset don't need any additional actions. 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_ci if (rt2x00_rf(rt2x00dev, RF2420)) 4598c2ecf20Sopenharmony_ci return; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* 4628c2ecf20Sopenharmony_ci * For the RT2421 chipsets we need to write an invalid 4638c2ecf20Sopenharmony_ci * reference clock rate to activate auto_tune. 4648c2ecf20Sopenharmony_ci * After that we set the value back to the correct channel. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); 4678c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 2, 0x000c2a32); 4688c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci msleep(1); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); 4738c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 2, rf->rf2); 4748c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci msleep(1); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* 4798c2ecf20Sopenharmony_ci * Switch off tuning bits. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0); 4828c2ecf20Sopenharmony_ci rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); 4858c2ecf20Sopenharmony_ci rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * Clear false CRC during channel switch. 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_ci rf->rf1 = rt2x00mmio_register_read(rt2x00dev, CNT0); 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower)); 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, 4998c2ecf20Sopenharmony_ci struct rt2x00lib_conf *libconf) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci u32 reg; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR11); 5048c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR11_LONG_RETRY, 5058c2ecf20Sopenharmony_ci libconf->conf->long_frame_max_tx_count); 5068c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR11_SHORT_RETRY, 5078c2ecf20Sopenharmony_ci libconf->conf->short_frame_max_tx_count); 5088c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR11, reg); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, 5128c2ecf20Sopenharmony_ci struct rt2x00lib_conf *libconf) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci enum dev_state state = 5158c2ecf20Sopenharmony_ci (libconf->conf->flags & IEEE80211_CONF_PS) ? 5168c2ecf20Sopenharmony_ci STATE_SLEEP : STATE_AWAKE; 5178c2ecf20Sopenharmony_ci u32 reg; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (state == STATE_SLEEP) { 5208c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR20); 5218c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, 5228c2ecf20Sopenharmony_ci (rt2x00dev->beacon_int - 20) * 16); 5238c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, 5248c2ecf20Sopenharmony_ci libconf->conf->listen_interval - 1); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* We must first disable autowake before it can be enabled */ 5278c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR20_AUTOWAKE, 0); 5288c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR20, reg); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR20_AUTOWAKE, 1); 5318c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR20, reg); 5328c2ecf20Sopenharmony_ci } else { 5338c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR20); 5348c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR20_AUTOWAKE, 0); 5358c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR20, reg); 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic void rt2400pci_config(struct rt2x00_dev *rt2x00dev, 5428c2ecf20Sopenharmony_ci struct rt2x00lib_conf *libconf, 5438c2ecf20Sopenharmony_ci const unsigned int flags) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_CHANNEL) 5468c2ecf20Sopenharmony_ci rt2400pci_config_channel(rt2x00dev, &libconf->rf); 5478c2ecf20Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_POWER) 5488c2ecf20Sopenharmony_ci rt2400pci_config_txpower(rt2x00dev, 5498c2ecf20Sopenharmony_ci libconf->conf->power_level); 5508c2ecf20Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) 5518c2ecf20Sopenharmony_ci rt2400pci_config_retry_limit(rt2x00dev, libconf); 5528c2ecf20Sopenharmony_ci if (flags & IEEE80211_CONF_CHANGE_PS) 5538c2ecf20Sopenharmony_ci rt2400pci_config_ps(rt2x00dev, libconf); 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev, 5578c2ecf20Sopenharmony_ci const int cw_min, const int cw_max) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci u32 reg; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR11); 5628c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR11_CWMIN, cw_min); 5638c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR11_CWMAX, cw_max); 5648c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR11, reg); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci/* 5688c2ecf20Sopenharmony_ci * Link tuning 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_cistatic void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev, 5718c2ecf20Sopenharmony_ci struct link_qual *qual) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci u32 reg; 5748c2ecf20Sopenharmony_ci u8 bbp; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /* 5778c2ecf20Sopenharmony_ci * Update FCS error count from register. 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CNT0); 5808c2ecf20Sopenharmony_ci qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* 5838c2ecf20Sopenharmony_ci * Update False CCA count from register. 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_ci bbp = rt2400pci_bbp_read(rt2x00dev, 39); 5868c2ecf20Sopenharmony_ci qual->false_cca = bbp; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic inline void rt2400pci_set_vgc(struct rt2x00_dev *rt2x00dev, 5908c2ecf20Sopenharmony_ci struct link_qual *qual, u8 vgc_level) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci if (qual->vgc_level_reg != vgc_level) { 5938c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 13, vgc_level); 5948c2ecf20Sopenharmony_ci qual->vgc_level = vgc_level; 5958c2ecf20Sopenharmony_ci qual->vgc_level_reg = vgc_level; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev, 6008c2ecf20Sopenharmony_ci struct link_qual *qual) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci rt2400pci_set_vgc(rt2x00dev, qual, 0x08); 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev, 6068c2ecf20Sopenharmony_ci struct link_qual *qual, const u32 count) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci /* 6098c2ecf20Sopenharmony_ci * The link tuner should not run longer then 60 seconds, 6108c2ecf20Sopenharmony_ci * and should run once every 2 seconds. 6118c2ecf20Sopenharmony_ci */ 6128c2ecf20Sopenharmony_ci if (count > 60 || !(count & 1)) 6138c2ecf20Sopenharmony_ci return; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* 6168c2ecf20Sopenharmony_ci * Base r13 link tuning on the false cca count. 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ci if ((qual->false_cca > 512) && (qual->vgc_level < 0x20)) 6198c2ecf20Sopenharmony_ci rt2400pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level); 6208c2ecf20Sopenharmony_ci else if ((qual->false_cca < 100) && (qual->vgc_level > 0x08)) 6218c2ecf20Sopenharmony_ci rt2400pci_set_vgc(rt2x00dev, qual, --qual->vgc_level); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci/* 6258c2ecf20Sopenharmony_ci * Queue handlers. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_cistatic void rt2400pci_start_queue(struct data_queue *queue) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; 6308c2ecf20Sopenharmony_ci u32 reg; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci switch (queue->qid) { 6338c2ecf20Sopenharmony_ci case QID_RX: 6348c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); 6358c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 0); 6368c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci case QID_BEACON: 6398c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR14); 6408c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); 6418c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TBCN, 1); 6428c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); 6438c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR14, reg); 6448c2ecf20Sopenharmony_ci break; 6458c2ecf20Sopenharmony_ci default: 6468c2ecf20Sopenharmony_ci break; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic void rt2400pci_kick_queue(struct data_queue *queue) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; 6538c2ecf20Sopenharmony_ci u32 reg; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci switch (queue->qid) { 6568c2ecf20Sopenharmony_ci case QID_AC_VO: 6578c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); 6588c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); 6598c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case QID_AC_VI: 6628c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); 6638c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); 6648c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); 6658c2ecf20Sopenharmony_ci break; 6668c2ecf20Sopenharmony_ci case QID_ATIM: 6678c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); 6688c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); 6698c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci default: 6728c2ecf20Sopenharmony_ci break; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void rt2400pci_stop_queue(struct data_queue *queue) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; 6798c2ecf20Sopenharmony_ci u32 reg; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci switch (queue->qid) { 6828c2ecf20Sopenharmony_ci case QID_AC_VO: 6838c2ecf20Sopenharmony_ci case QID_AC_VI: 6848c2ecf20Sopenharmony_ci case QID_ATIM: 6858c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); 6868c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR0_ABORT, 1); 6878c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci case QID_RX: 6908c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); 6918c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 1); 6928c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci case QID_BEACON: 6958c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR14); 6968c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); 6978c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TBCN, 0); 6988c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); 6998c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR14, reg); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* 7028c2ecf20Sopenharmony_ci * Wait for possibly running tbtt tasklets. 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_ci tasklet_kill(&rt2x00dev->tbtt_tasklet); 7058c2ecf20Sopenharmony_ci break; 7068c2ecf20Sopenharmony_ci default: 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci/* 7128c2ecf20Sopenharmony_ci * Initialization functions. 7138c2ecf20Sopenharmony_ci */ 7148c2ecf20Sopenharmony_cistatic bool rt2400pci_get_entry_state(struct queue_entry *entry) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 7178c2ecf20Sopenharmony_ci u32 word; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (entry->queue->qid == QID_RX) { 7208c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); 7238c2ecf20Sopenharmony_ci } else { 7248c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || 7278c2ecf20Sopenharmony_ci rt2x00_get_field32(word, TXD_W0_VALID)); 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic void rt2400pci_clear_entry(struct queue_entry *entry) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 7348c2ecf20Sopenharmony_ci struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 7358c2ecf20Sopenharmony_ci u32 word; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (entry->queue->qid == QID_RX) { 7388c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 2); 7398c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); 7408c2ecf20Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 2, word); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 1); 7438c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); 7448c2ecf20Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 1, word); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 7478c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); 7488c2ecf20Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 0, word); 7498c2ecf20Sopenharmony_ci } else { 7508c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 7518c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_VALID, 0); 7528c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); 7538c2ecf20Sopenharmony_ci rt2x00_desc_write(entry_priv->desc, 0, word); 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv; 7608c2ecf20Sopenharmony_ci u32 reg; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* 7638c2ecf20Sopenharmony_ci * Initialize registers. 7648c2ecf20Sopenharmony_ci */ 7658c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR2); 7668c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size); 7678c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit); 7688c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR2_NUM_ATIM, rt2x00dev->atim->limit); 7698c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); 7708c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR2, reg); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->tx[1].entries[0].priv_data; 7738c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR3); 7748c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, 7758c2ecf20Sopenharmony_ci entry_priv->desc_dma); 7768c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR3, reg); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->tx[0].entries[0].priv_data; 7798c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR5); 7808c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, 7818c2ecf20Sopenharmony_ci entry_priv->desc_dma); 7828c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR5, reg); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->atim->entries[0].priv_data; 7858c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR4); 7868c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, 7878c2ecf20Sopenharmony_ci entry_priv->desc_dma); 7888c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR4, reg); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->bcn->entries[0].priv_data; 7918c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TXCSR6); 7928c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, 7938c2ecf20Sopenharmony_ci entry_priv->desc_dma); 7948c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TXCSR6, reg); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RXCSR1); 7978c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); 7988c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); 7998c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RXCSR1, reg); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci entry_priv = rt2x00dev->rx->entries[0].priv_data; 8028c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RXCSR2); 8038c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, 8048c2ecf20Sopenharmony_ci entry_priv->desc_dma); 8058c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RXCSR2, reg); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci return 0; 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci u32 reg; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PSCSR0, 0x00020002); 8158c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PSCSR1, 0x00000002); 8168c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PSCSR2, 0x00023f20); 8178c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PSCSR3, 0x00000002); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, TIMECSR); 8208c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); 8218c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); 8228c2ecf20Sopenharmony_ci rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); 8238c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, TIMECSR, reg); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR9); 8268c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, 8278c2ecf20Sopenharmony_ci (rt2x00dev->rx->data_size / 128)); 8288c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR9, reg); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR14); 8318c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); 8328c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); 8338c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TBCN, 0); 8348c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TCFP, 0); 8358c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TATIMW, 0); 8368c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); 8378c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_CFP_COUNT_PRELOAD, 0); 8388c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_TBCM_PRELOAD, 0); 8398c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR14, reg); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CNT3, 0x3f080000); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, ARCSR0); 8448c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA0, 133); 8458c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR0_AR_BBP_ID0, 134); 8468c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA1, 136); 8478c2ecf20Sopenharmony_ci rt2x00_set_field32(®, ARCSR0_AR_BBP_ID1, 135); 8488c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, ARCSR0, reg); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RXCSR3); 8518c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR3_BBP_ID0, 3); /* Tx power.*/ 8528c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR3_BBP_ID0_VALID, 1); 8538c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR3_BBP_ID1, 32); /* Signal */ 8548c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR3_BBP_ID1_VALID, 1); 8558c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR3_BBP_ID2, 36); /* Rssi */ 8568c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RXCSR3_BBP_ID2_VALID, 1); 8578c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RXCSR3, reg); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) 8628c2ecf20Sopenharmony_ci return -EBUSY; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MACCSR0, 0x00217223); 8658c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MACCSR1, 0x00235518); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, MACCSR2); 8688c2ecf20Sopenharmony_ci rt2x00_set_field32(®, MACCSR2_DELAY, 64); 8698c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, MACCSR2, reg); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, RALINKCSR); 8728c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA0, 17); 8738c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID0, 154); 8748c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA1, 0); 8758c2ecf20Sopenharmony_ci rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID1, 154); 8768c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, RALINKCSR, reg); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR1); 8798c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR1_SOFT_RESET, 1); 8808c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR1_BBP_RESET, 0); 8818c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR1_HOST_READY, 0); 8828c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR1, reg); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR1); 8858c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR1_SOFT_RESET, 0); 8868c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR1_HOST_READY, 1); 8878c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR1, reg); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* 8908c2ecf20Sopenharmony_ci * We must clear the FCS and FIFO error count. 8918c2ecf20Sopenharmony_ci * These registers are cleared on read, 8928c2ecf20Sopenharmony_ci * so we may pass a useless variable to store the value. 8938c2ecf20Sopenharmony_ci */ 8948c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CNT0); 8958c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CNT4); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci return 0; 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic int rt2400pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci unsigned int i; 9038c2ecf20Sopenharmony_ci u8 value; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 9068c2ecf20Sopenharmony_ci value = rt2400pci_bbp_read(rt2x00dev, 0); 9078c2ecf20Sopenharmony_ci if ((value != 0xff) && (value != 0x00)) 9088c2ecf20Sopenharmony_ci return 0; 9098c2ecf20Sopenharmony_ci udelay(REGISTER_BUSY_DELAY); 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n"); 9138c2ecf20Sopenharmony_ci return -EACCES; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci unsigned int i; 9198c2ecf20Sopenharmony_ci u16 eeprom; 9208c2ecf20Sopenharmony_ci u8 reg_id; 9218c2ecf20Sopenharmony_ci u8 value; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (unlikely(rt2400pci_wait_bbp_ready(rt2x00dev))) 9248c2ecf20Sopenharmony_ci return -EACCES; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 1, 0x00); 9278c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 3, 0x27); 9288c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 4, 0x08); 9298c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 10, 0x0f); 9308c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 15, 0x72); 9318c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 16, 0x74); 9328c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 17, 0x20); 9338c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 18, 0x72); 9348c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 19, 0x0b); 9358c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 20, 0x00); 9368c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 28, 0x11); 9378c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 29, 0x04); 9388c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 30, 0x21); 9398c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, 31, 0x00); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci for (i = 0; i < EEPROM_BBP_SIZE; i++) { 9428c2ecf20Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (eeprom != 0xffff && eeprom != 0x0000) { 9458c2ecf20Sopenharmony_ci reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); 9468c2ecf20Sopenharmony_ci value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); 9478c2ecf20Sopenharmony_ci rt2400pci_bbp_write(rt2x00dev, reg_id, value); 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci return 0; 9528c2ecf20Sopenharmony_ci} 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci/* 9558c2ecf20Sopenharmony_ci * Device state switch handlers. 9568c2ecf20Sopenharmony_ci */ 9578c2ecf20Sopenharmony_cistatic void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, 9588c2ecf20Sopenharmony_ci enum dev_state state) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci int mask = (state == STATE_RADIO_IRQ_OFF); 9618c2ecf20Sopenharmony_ci u32 reg; 9628c2ecf20Sopenharmony_ci unsigned long flags; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* 9658c2ecf20Sopenharmony_ci * When interrupts are being enabled, the interrupt registers 9668c2ecf20Sopenharmony_ci * should clear the register to assure a clean state. 9678c2ecf20Sopenharmony_ci */ 9688c2ecf20Sopenharmony_ci if (state == STATE_RADIO_IRQ_ON) { 9698c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR7); 9708c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR7, reg); 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci /* 9748c2ecf20Sopenharmony_ci * Only toggle the interrupts bits we are going to use. 9758c2ecf20Sopenharmony_ci * Non-checked interrupt bits are disabled by default. 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_ci spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR8); 9808c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); 9818c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); 9828c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, mask); 9838c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); 9848c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR8_RXDONE, mask); 9858c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR8, reg); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (state == STATE_RADIO_IRQ_OFF) { 9908c2ecf20Sopenharmony_ci /* 9918c2ecf20Sopenharmony_ci * Ensure that all tasklets are finished before 9928c2ecf20Sopenharmony_ci * disabling the interrupts. 9938c2ecf20Sopenharmony_ci */ 9948c2ecf20Sopenharmony_ci tasklet_kill(&rt2x00dev->txstatus_tasklet); 9958c2ecf20Sopenharmony_ci tasklet_kill(&rt2x00dev->rxdone_tasklet); 9968c2ecf20Sopenharmony_ci tasklet_kill(&rt2x00dev->tbtt_tasklet); 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cistatic int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci /* 10038c2ecf20Sopenharmony_ci * Initialize all registers. 10048c2ecf20Sopenharmony_ci */ 10058c2ecf20Sopenharmony_ci if (unlikely(rt2400pci_init_queues(rt2x00dev) || 10068c2ecf20Sopenharmony_ci rt2400pci_init_registers(rt2x00dev) || 10078c2ecf20Sopenharmony_ci rt2400pci_init_bbp(rt2x00dev))) 10088c2ecf20Sopenharmony_ci return -EIO; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci /* 10168c2ecf20Sopenharmony_ci * Disable power 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PWRCSR0, 0); 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, 10228c2ecf20Sopenharmony_ci enum dev_state state) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci u32 reg, reg2; 10258c2ecf20Sopenharmony_ci unsigned int i; 10268c2ecf20Sopenharmony_ci char put_to_sleep; 10278c2ecf20Sopenharmony_ci char bbp_state; 10288c2ecf20Sopenharmony_ci char rf_state; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci put_to_sleep = (state != STATE_AWAKE); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); 10338c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); 10348c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, state); 10358c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, state); 10368c2ecf20Sopenharmony_ci rt2x00_set_field32(®, PWRCSR1_PUT_TO_SLEEP, put_to_sleep); 10378c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PWRCSR1, reg); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci /* 10408c2ecf20Sopenharmony_ci * Device is not guaranteed to be in the requested state yet. 10418c2ecf20Sopenharmony_ci * We must wait until the register indicates that the 10428c2ecf20Sopenharmony_ci * device has entered the correct state. 10438c2ecf20Sopenharmony_ci */ 10448c2ecf20Sopenharmony_ci for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 10458c2ecf20Sopenharmony_ci reg2 = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); 10468c2ecf20Sopenharmony_ci bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); 10478c2ecf20Sopenharmony_ci rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); 10488c2ecf20Sopenharmony_ci if (bbp_state == state && rf_state == state) 10498c2ecf20Sopenharmony_ci return 0; 10508c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, PWRCSR1, reg); 10518c2ecf20Sopenharmony_ci msleep(10); 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return -EBUSY; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, 10588c2ecf20Sopenharmony_ci enum dev_state state) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci int retval = 0; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci switch (state) { 10638c2ecf20Sopenharmony_ci case STATE_RADIO_ON: 10648c2ecf20Sopenharmony_ci retval = rt2400pci_enable_radio(rt2x00dev); 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci case STATE_RADIO_OFF: 10678c2ecf20Sopenharmony_ci rt2400pci_disable_radio(rt2x00dev); 10688c2ecf20Sopenharmony_ci break; 10698c2ecf20Sopenharmony_ci case STATE_RADIO_IRQ_ON: 10708c2ecf20Sopenharmony_ci case STATE_RADIO_IRQ_OFF: 10718c2ecf20Sopenharmony_ci rt2400pci_toggle_irq(rt2x00dev, state); 10728c2ecf20Sopenharmony_ci break; 10738c2ecf20Sopenharmony_ci case STATE_DEEP_SLEEP: 10748c2ecf20Sopenharmony_ci case STATE_SLEEP: 10758c2ecf20Sopenharmony_ci case STATE_STANDBY: 10768c2ecf20Sopenharmony_ci case STATE_AWAKE: 10778c2ecf20Sopenharmony_ci retval = rt2400pci_set_state(rt2x00dev, state); 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci default: 10808c2ecf20Sopenharmony_ci retval = -ENOTSUPP; 10818c2ecf20Sopenharmony_ci break; 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (unlikely(retval)) 10858c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n", 10868c2ecf20Sopenharmony_ci state, retval); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci return retval; 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci/* 10928c2ecf20Sopenharmony_ci * TX descriptor initialization 10938c2ecf20Sopenharmony_ci */ 10948c2ecf20Sopenharmony_cistatic void rt2400pci_write_tx_desc(struct queue_entry *entry, 10958c2ecf20Sopenharmony_ci struct txentry_desc *txdesc) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 10988c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 10998c2ecf20Sopenharmony_ci __le32 *txd = entry_priv->desc; 11008c2ecf20Sopenharmony_ci u32 word; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* 11038c2ecf20Sopenharmony_ci * Start writing the descriptor words. 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 1); 11068c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); 11078c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 1, word); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 2); 11108c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, txdesc->length); 11118c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, txdesc->length); 11128c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 2, word); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 3); 11158c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->u.plcp.signal); 11168c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5); 11178c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1); 11188c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->u.plcp.service); 11198c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_REGNUM, 6); 11208c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1); 11218c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 3, word); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 4); 11248c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, 11258c2ecf20Sopenharmony_ci txdesc->u.plcp.length_low); 11268c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8); 11278c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_BUSY, 1); 11288c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, 11298c2ecf20Sopenharmony_ci txdesc->u.plcp.length_high); 11308c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_REGNUM, 7); 11318c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1); 11328c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 4, word); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* 11358c2ecf20Sopenharmony_ci * Writing TXD word 0 must the last to prevent a race condition with 11368c2ecf20Sopenharmony_ci * the device, whereby the device may take hold of the TXD before we 11378c2ecf20Sopenharmony_ci * finished updating it. 11388c2ecf20Sopenharmony_ci */ 11398c2ecf20Sopenharmony_ci word = rt2x00_desc_read(txd, 0); 11408c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); 11418c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_VALID, 1); 11428c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, 11438c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); 11448c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_ACK, 11458c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_ACK, &txdesc->flags)); 11468c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, 11478c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); 11488c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_RTS, 11498c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); 11508c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs); 11518c2ecf20Sopenharmony_ci rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, 11528c2ecf20Sopenharmony_ci test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); 11538c2ecf20Sopenharmony_ci rt2x00_desc_write(txd, 0, word); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* 11568c2ecf20Sopenharmony_ci * Register descriptor details in skb frame descriptor. 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_ci skbdesc->desc = txd; 11598c2ecf20Sopenharmony_ci skbdesc->desc_len = TXD_DESC_SIZE; 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci/* 11638c2ecf20Sopenharmony_ci * TX data initialization 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_cistatic void rt2400pci_write_beacon(struct queue_entry *entry, 11668c2ecf20Sopenharmony_ci struct txentry_desc *txdesc) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 11698c2ecf20Sopenharmony_ci u32 reg; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci /* 11728c2ecf20Sopenharmony_ci * Disable beaconing while we are reloading the beacon data, 11738c2ecf20Sopenharmony_ci * otherwise we might be sending out invalid data. 11748c2ecf20Sopenharmony_ci */ 11758c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR14); 11768c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); 11778c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR14, reg); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (rt2x00queue_map_txskb(entry)) { 11808c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "Fail to map beacon, aborting\n"); 11818c2ecf20Sopenharmony_ci goto out; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci /* 11848c2ecf20Sopenharmony_ci * Enable beaconing again. 11858c2ecf20Sopenharmony_ci */ 11868c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); 11878c2ecf20Sopenharmony_ci /* 11888c2ecf20Sopenharmony_ci * Write the TX descriptor for the beacon. 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_ci rt2400pci_write_tx_desc(entry, txdesc); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci /* 11938c2ecf20Sopenharmony_ci * Dump beacon to userspace through debugfs. 11948c2ecf20Sopenharmony_ci */ 11958c2ecf20Sopenharmony_ci rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry); 11968c2ecf20Sopenharmony_ciout: 11978c2ecf20Sopenharmony_ci /* 11988c2ecf20Sopenharmony_ci * Enable beaconing again. 11998c2ecf20Sopenharmony_ci */ 12008c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); 12018c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR14, reg); 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci/* 12058c2ecf20Sopenharmony_ci * RX control handlers 12068c2ecf20Sopenharmony_ci */ 12078c2ecf20Sopenharmony_cistatic void rt2400pci_fill_rxdone(struct queue_entry *entry, 12088c2ecf20Sopenharmony_ci struct rxdone_entry_desc *rxdesc) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 12118c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv = entry->priv_data; 12128c2ecf20Sopenharmony_ci u32 word0; 12138c2ecf20Sopenharmony_ci u32 word2; 12148c2ecf20Sopenharmony_ci u32 word3; 12158c2ecf20Sopenharmony_ci u32 word4; 12168c2ecf20Sopenharmony_ci u64 tsf; 12178c2ecf20Sopenharmony_ci u32 rx_low; 12188c2ecf20Sopenharmony_ci u32 rx_high; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci word0 = rt2x00_desc_read(entry_priv->desc, 0); 12218c2ecf20Sopenharmony_ci word2 = rt2x00_desc_read(entry_priv->desc, 2); 12228c2ecf20Sopenharmony_ci word3 = rt2x00_desc_read(entry_priv->desc, 3); 12238c2ecf20Sopenharmony_ci word4 = rt2x00_desc_read(entry_priv->desc, 4); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) 12268c2ecf20Sopenharmony_ci rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; 12278c2ecf20Sopenharmony_ci if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) 12288c2ecf20Sopenharmony_ci rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* 12318c2ecf20Sopenharmony_ci * We only get the lower 32bits from the timestamp, 12328c2ecf20Sopenharmony_ci * to get the full 64bits we must complement it with 12338c2ecf20Sopenharmony_ci * the timestamp from get_tsf(). 12348c2ecf20Sopenharmony_ci * Note that when a wraparound of the lower 32bits 12358c2ecf20Sopenharmony_ci * has occurred between the frame arrival and the get_tsf() 12368c2ecf20Sopenharmony_ci * call, we must decrease the higher 32bits with 1 to get 12378c2ecf20Sopenharmony_ci * to correct value. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_ci tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw, NULL); 12408c2ecf20Sopenharmony_ci rx_low = rt2x00_get_field32(word4, RXD_W4_RX_END_TIME); 12418c2ecf20Sopenharmony_ci rx_high = upper_32_bits(tsf); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if ((u32)tsf <= rx_low) 12448c2ecf20Sopenharmony_ci rx_high--; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci /* 12478c2ecf20Sopenharmony_ci * Obtain the status about this packet. 12488c2ecf20Sopenharmony_ci * The signal is the PLCP value, and needs to be stripped 12498c2ecf20Sopenharmony_ci * of the preamble bit (0x08). 12508c2ecf20Sopenharmony_ci */ 12518c2ecf20Sopenharmony_ci rxdesc->timestamp = ((u64)rx_high << 32) | rx_low; 12528c2ecf20Sopenharmony_ci rxdesc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL) & ~0x08; 12538c2ecf20Sopenharmony_ci rxdesc->rssi = rt2x00_get_field32(word3, RXD_W3_RSSI) - 12548c2ecf20Sopenharmony_ci entry->queue->rt2x00dev->rssi_offset; 12558c2ecf20Sopenharmony_ci rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; 12588c2ecf20Sopenharmony_ci if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) 12598c2ecf20Sopenharmony_ci rxdesc->dev_flags |= RXDONE_MY_BSS; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci/* 12638c2ecf20Sopenharmony_ci * Interrupt functions. 12648c2ecf20Sopenharmony_ci */ 12658c2ecf20Sopenharmony_cistatic void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, 12668c2ecf20Sopenharmony_ci const enum data_queue_qid queue_idx) 12678c2ecf20Sopenharmony_ci{ 12688c2ecf20Sopenharmony_ci struct data_queue *queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); 12698c2ecf20Sopenharmony_ci struct queue_entry_priv_mmio *entry_priv; 12708c2ecf20Sopenharmony_ci struct queue_entry *entry; 12718c2ecf20Sopenharmony_ci struct txdone_entry_desc txdesc; 12728c2ecf20Sopenharmony_ci u32 word; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci while (!rt2x00queue_empty(queue)) { 12758c2ecf20Sopenharmony_ci entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); 12768c2ecf20Sopenharmony_ci entry_priv = entry->priv_data; 12778c2ecf20Sopenharmony_ci word = rt2x00_desc_read(entry_priv->desc, 0); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || 12808c2ecf20Sopenharmony_ci !rt2x00_get_field32(word, TXD_W0_VALID)) 12818c2ecf20Sopenharmony_ci break; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* 12848c2ecf20Sopenharmony_ci * Obtain the status about this packet. 12858c2ecf20Sopenharmony_ci */ 12868c2ecf20Sopenharmony_ci txdesc.flags = 0; 12878c2ecf20Sopenharmony_ci switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { 12888c2ecf20Sopenharmony_ci case 0: /* Success */ 12898c2ecf20Sopenharmony_ci case 1: /* Success with retry */ 12908c2ecf20Sopenharmony_ci __set_bit(TXDONE_SUCCESS, &txdesc.flags); 12918c2ecf20Sopenharmony_ci break; 12928c2ecf20Sopenharmony_ci case 2: /* Failure, excessive retries */ 12938c2ecf20Sopenharmony_ci __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); 12948c2ecf20Sopenharmony_ci fallthrough; /* this is a failed frame! */ 12958c2ecf20Sopenharmony_ci default: /* Failure */ 12968c2ecf20Sopenharmony_ci __set_bit(TXDONE_FAILURE, &txdesc.flags); 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci rt2x00lib_txdone(entry, &txdesc); 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic inline void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, 13058c2ecf20Sopenharmony_ci struct rt2x00_field32 irq_field) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci u32 reg; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci /* 13108c2ecf20Sopenharmony_ci * Enable a single interrupt. The interrupt mask register 13118c2ecf20Sopenharmony_ci * access needs locking. 13128c2ecf20Sopenharmony_ci */ 13138c2ecf20Sopenharmony_ci spin_lock_irq(&rt2x00dev->irqmask_lock); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR8); 13168c2ecf20Sopenharmony_ci rt2x00_set_field32(®, irq_field, 0); 13178c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR8, reg); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci spin_unlock_irq(&rt2x00dev->irqmask_lock); 13208c2ecf20Sopenharmony_ci} 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_cistatic void rt2400pci_txstatus_tasklet(struct tasklet_struct *t) 13238c2ecf20Sopenharmony_ci{ 13248c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, 13258c2ecf20Sopenharmony_ci txstatus_tasklet); 13268c2ecf20Sopenharmony_ci u32 reg; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci /* 13298c2ecf20Sopenharmony_ci * Handle all tx queues. 13308c2ecf20Sopenharmony_ci */ 13318c2ecf20Sopenharmony_ci rt2400pci_txdone(rt2x00dev, QID_ATIM); 13328c2ecf20Sopenharmony_ci rt2400pci_txdone(rt2x00dev, QID_AC_VO); 13338c2ecf20Sopenharmony_ci rt2400pci_txdone(rt2x00dev, QID_AC_VI); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* 13368c2ecf20Sopenharmony_ci * Enable all TXDONE interrupts again. 13378c2ecf20Sopenharmony_ci */ 13388c2ecf20Sopenharmony_ci if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { 13398c2ecf20Sopenharmony_ci spin_lock_irq(&rt2x00dev->irqmask_lock); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR8); 13428c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); 13438c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); 13448c2ecf20Sopenharmony_ci rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); 13458c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR8, reg); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci spin_unlock_irq(&rt2x00dev->irqmask_lock); 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic void rt2400pci_tbtt_tasklet(struct tasklet_struct *t) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, tbtt_tasklet); 13548c2ecf20Sopenharmony_ci rt2x00lib_beacondone(rt2x00dev); 13558c2ecf20Sopenharmony_ci if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 13568c2ecf20Sopenharmony_ci rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_cistatic void rt2400pci_rxdone_tasklet(struct tasklet_struct *t) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, 13628c2ecf20Sopenharmony_ci rxdone_tasklet); 13638c2ecf20Sopenharmony_ci if (rt2x00mmio_rxdone(rt2x00dev)) 13648c2ecf20Sopenharmony_ci tasklet_schedule(&rt2x00dev->rxdone_tasklet); 13658c2ecf20Sopenharmony_ci else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 13668c2ecf20Sopenharmony_ci rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = dev_instance; 13728c2ecf20Sopenharmony_ci u32 reg, mask; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* 13758c2ecf20Sopenharmony_ci * Get the interrupt sources & saved to local variable. 13768c2ecf20Sopenharmony_ci * Write register value back to clear pending interrupts. 13778c2ecf20Sopenharmony_ci */ 13788c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR7); 13798c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR7, reg); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (!reg) 13828c2ecf20Sopenharmony_ci return IRQ_NONE; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 13858c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci mask = reg; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* 13908c2ecf20Sopenharmony_ci * Schedule tasklets for interrupt handling. 13918c2ecf20Sopenharmony_ci */ 13928c2ecf20Sopenharmony_ci if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) 13938c2ecf20Sopenharmony_ci tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci if (rt2x00_get_field32(reg, CSR7_RXDONE)) 13968c2ecf20Sopenharmony_ci tasklet_schedule(&rt2x00dev->rxdone_tasklet); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING) || 13998c2ecf20Sopenharmony_ci rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING) || 14008c2ecf20Sopenharmony_ci rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) { 14018c2ecf20Sopenharmony_ci tasklet_schedule(&rt2x00dev->txstatus_tasklet); 14028c2ecf20Sopenharmony_ci /* 14038c2ecf20Sopenharmony_ci * Mask out all txdone interrupts. 14048c2ecf20Sopenharmony_ci */ 14058c2ecf20Sopenharmony_ci rt2x00_set_field32(&mask, CSR8_TXDONE_TXRING, 1); 14068c2ecf20Sopenharmony_ci rt2x00_set_field32(&mask, CSR8_TXDONE_ATIMRING, 1); 14078c2ecf20Sopenharmony_ci rt2x00_set_field32(&mask, CSR8_TXDONE_PRIORING, 1); 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci /* 14118c2ecf20Sopenharmony_ci * Disable all interrupts for which a tasklet was scheduled right now, 14128c2ecf20Sopenharmony_ci * the tasklet will reenable the appropriate interrupts. 14138c2ecf20Sopenharmony_ci */ 14148c2ecf20Sopenharmony_ci spin_lock(&rt2x00dev->irqmask_lock); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR8); 14178c2ecf20Sopenharmony_ci reg |= mask; 14188c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, CSR8, reg); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci spin_unlock(&rt2x00dev->irqmask_lock); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci return IRQ_HANDLED; 14258c2ecf20Sopenharmony_ci} 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci/* 14288c2ecf20Sopenharmony_ci * Device probe functions. 14298c2ecf20Sopenharmony_ci */ 14308c2ecf20Sopenharmony_cistatic int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci struct eeprom_93cx6 eeprom; 14338c2ecf20Sopenharmony_ci u32 reg; 14348c2ecf20Sopenharmony_ci u16 word; 14358c2ecf20Sopenharmony_ci u8 *mac; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR21); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci eeprom.data = rt2x00dev; 14408c2ecf20Sopenharmony_ci eeprom.register_read = rt2400pci_eepromregister_read; 14418c2ecf20Sopenharmony_ci eeprom.register_write = rt2400pci_eepromregister_write; 14428c2ecf20Sopenharmony_ci eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ? 14438c2ecf20Sopenharmony_ci PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; 14448c2ecf20Sopenharmony_ci eeprom.reg_data_in = 0; 14458c2ecf20Sopenharmony_ci eeprom.reg_data_out = 0; 14468c2ecf20Sopenharmony_ci eeprom.reg_data_clock = 0; 14478c2ecf20Sopenharmony_ci eeprom.reg_chip_select = 0; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, 14508c2ecf20Sopenharmony_ci EEPROM_SIZE / sizeof(u16)); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci /* 14538c2ecf20Sopenharmony_ci * Start validation of the data that has been read. 14548c2ecf20Sopenharmony_ci */ 14558c2ecf20Sopenharmony_ci mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); 14568c2ecf20Sopenharmony_ci rt2x00lib_set_mac_address(rt2x00dev, mac); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); 14598c2ecf20Sopenharmony_ci if (word == 0xffff) { 14608c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "Invalid EEPROM data detected\n"); 14618c2ecf20Sopenharmony_ci return -EINVAL; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci return 0; 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci u32 reg; 14708c2ecf20Sopenharmony_ci u16 value; 14718c2ecf20Sopenharmony_ci u16 eeprom; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci /* 14748c2ecf20Sopenharmony_ci * Read EEPROM word for configuration. 14758c2ecf20Sopenharmony_ci */ 14768c2ecf20Sopenharmony_ci eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* 14798c2ecf20Sopenharmony_ci * Identify RF chipset. 14808c2ecf20Sopenharmony_ci */ 14818c2ecf20Sopenharmony_ci value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); 14828c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR0); 14838c2ecf20Sopenharmony_ci rt2x00_set_chip(rt2x00dev, RT2460, value, 14848c2ecf20Sopenharmony_ci rt2x00_get_field32(reg, CSR0_REVISION)); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) { 14878c2ecf20Sopenharmony_ci rt2x00_err(rt2x00dev, "Invalid RF chipset detected\n"); 14888c2ecf20Sopenharmony_ci return -ENODEV; 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci /* 14928c2ecf20Sopenharmony_ci * Identify default antenna configuration. 14938c2ecf20Sopenharmony_ci */ 14948c2ecf20Sopenharmony_ci rt2x00dev->default_ant.tx = 14958c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); 14968c2ecf20Sopenharmony_ci rt2x00dev->default_ant.rx = 14978c2ecf20Sopenharmony_ci rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* 15008c2ecf20Sopenharmony_ci * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead. 15018c2ecf20Sopenharmony_ci * I am not 100% sure about this, but the legacy drivers do not 15028c2ecf20Sopenharmony_ci * indicate antenna swapping in software is required when 15038c2ecf20Sopenharmony_ci * diversity is enabled. 15048c2ecf20Sopenharmony_ci */ 15058c2ecf20Sopenharmony_ci if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) 15068c2ecf20Sopenharmony_ci rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; 15078c2ecf20Sopenharmony_ci if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) 15088c2ecf20Sopenharmony_ci rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci /* 15118c2ecf20Sopenharmony_ci * Store led mode, for correct led behaviour. 15128c2ecf20Sopenharmony_ci */ 15138c2ecf20Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_LEDS 15148c2ecf20Sopenharmony_ci value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); 15178c2ecf20Sopenharmony_ci if (value == LED_MODE_TXRX_ACTIVITY || 15188c2ecf20Sopenharmony_ci value == LED_MODE_DEFAULT || 15198c2ecf20Sopenharmony_ci value == LED_MODE_ASUS) 15208c2ecf20Sopenharmony_ci rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_qual, 15218c2ecf20Sopenharmony_ci LED_TYPE_ACTIVITY); 15228c2ecf20Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_LEDS */ 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci /* 15258c2ecf20Sopenharmony_ci * Detect if this device has an hardware controlled radio. 15268c2ecf20Sopenharmony_ci */ 15278c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) 15288c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci /* 15318c2ecf20Sopenharmony_ci * Check if the BBP tuning should be enabled. 15328c2ecf20Sopenharmony_ci */ 15338c2ecf20Sopenharmony_ci if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING)) 15348c2ecf20Sopenharmony_ci __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci return 0; 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci/* 15408c2ecf20Sopenharmony_ci * RF value list for RF2420 & RF2421 15418c2ecf20Sopenharmony_ci * Supports: 2.4 GHz 15428c2ecf20Sopenharmony_ci */ 15438c2ecf20Sopenharmony_cistatic const struct rf_channel rf_vals_b[] = { 15448c2ecf20Sopenharmony_ci { 1, 0x00022058, 0x000c1fda, 0x00000101, 0 }, 15458c2ecf20Sopenharmony_ci { 2, 0x00022058, 0x000c1fee, 0x00000101, 0 }, 15468c2ecf20Sopenharmony_ci { 3, 0x00022058, 0x000c2002, 0x00000101, 0 }, 15478c2ecf20Sopenharmony_ci { 4, 0x00022058, 0x000c2016, 0x00000101, 0 }, 15488c2ecf20Sopenharmony_ci { 5, 0x00022058, 0x000c202a, 0x00000101, 0 }, 15498c2ecf20Sopenharmony_ci { 6, 0x00022058, 0x000c203e, 0x00000101, 0 }, 15508c2ecf20Sopenharmony_ci { 7, 0x00022058, 0x000c2052, 0x00000101, 0 }, 15518c2ecf20Sopenharmony_ci { 8, 0x00022058, 0x000c2066, 0x00000101, 0 }, 15528c2ecf20Sopenharmony_ci { 9, 0x00022058, 0x000c207a, 0x00000101, 0 }, 15538c2ecf20Sopenharmony_ci { 10, 0x00022058, 0x000c208e, 0x00000101, 0 }, 15548c2ecf20Sopenharmony_ci { 11, 0x00022058, 0x000c20a2, 0x00000101, 0 }, 15558c2ecf20Sopenharmony_ci { 12, 0x00022058, 0x000c20b6, 0x00000101, 0 }, 15568c2ecf20Sopenharmony_ci { 13, 0x00022058, 0x000c20ca, 0x00000101, 0 }, 15578c2ecf20Sopenharmony_ci { 14, 0x00022058, 0x000c20fa, 0x00000101, 0 }, 15588c2ecf20Sopenharmony_ci}; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_cistatic int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) 15618c2ecf20Sopenharmony_ci{ 15628c2ecf20Sopenharmony_ci struct hw_mode_spec *spec = &rt2x00dev->spec; 15638c2ecf20Sopenharmony_ci struct channel_info *info; 15648c2ecf20Sopenharmony_ci char *tx_power; 15658c2ecf20Sopenharmony_ci unsigned int i; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci /* 15688c2ecf20Sopenharmony_ci * Initialize all hw fields. 15698c2ecf20Sopenharmony_ci */ 15708c2ecf20Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK); 15718c2ecf20Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS); 15728c2ecf20Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING); 15738c2ecf20Sopenharmony_ci ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); 15768c2ecf20Sopenharmony_ci SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, 15778c2ecf20Sopenharmony_ci rt2x00_eeprom_addr(rt2x00dev, 15788c2ecf20Sopenharmony_ci EEPROM_MAC_ADDR_0)); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* 15818c2ecf20Sopenharmony_ci * Initialize hw_mode information. 15828c2ecf20Sopenharmony_ci */ 15838c2ecf20Sopenharmony_ci spec->supported_bands = SUPPORT_BAND_2GHZ; 15848c2ecf20Sopenharmony_ci spec->supported_rates = SUPPORT_RATE_CCK; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci spec->num_channels = ARRAY_SIZE(rf_vals_b); 15878c2ecf20Sopenharmony_ci spec->channels = rf_vals_b; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci /* 15908c2ecf20Sopenharmony_ci * Create channel information array 15918c2ecf20Sopenharmony_ci */ 15928c2ecf20Sopenharmony_ci info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); 15938c2ecf20Sopenharmony_ci if (!info) 15948c2ecf20Sopenharmony_ci return -ENOMEM; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci spec->channels_info = info; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); 15998c2ecf20Sopenharmony_ci for (i = 0; i < 14; i++) { 16008c2ecf20Sopenharmony_ci info[i].max_power = TXPOWER_FROM_DEV(MAX_TXPOWER); 16018c2ecf20Sopenharmony_ci info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci return 0; 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_cistatic int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) 16088c2ecf20Sopenharmony_ci{ 16098c2ecf20Sopenharmony_ci int retval; 16108c2ecf20Sopenharmony_ci u32 reg; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* 16138c2ecf20Sopenharmony_ci * Allocate eeprom data. 16148c2ecf20Sopenharmony_ci */ 16158c2ecf20Sopenharmony_ci retval = rt2400pci_validate_eeprom(rt2x00dev); 16168c2ecf20Sopenharmony_ci if (retval) 16178c2ecf20Sopenharmony_ci return retval; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci retval = rt2400pci_init_eeprom(rt2x00dev); 16208c2ecf20Sopenharmony_ci if (retval) 16218c2ecf20Sopenharmony_ci return retval; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci /* 16248c2ecf20Sopenharmony_ci * Enable rfkill polling by setting GPIO direction of the 16258c2ecf20Sopenharmony_ci * rfkill switch GPIO pin correctly. 16268c2ecf20Sopenharmony_ci */ 16278c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); 16288c2ecf20Sopenharmony_ci rt2x00_set_field32(®, GPIOCSR_DIR0, 1); 16298c2ecf20Sopenharmony_ci rt2x00mmio_register_write(rt2x00dev, GPIOCSR, reg); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci /* 16328c2ecf20Sopenharmony_ci * Initialize hw specifications. 16338c2ecf20Sopenharmony_ci */ 16348c2ecf20Sopenharmony_ci retval = rt2400pci_probe_hw_mode(rt2x00dev); 16358c2ecf20Sopenharmony_ci if (retval) 16368c2ecf20Sopenharmony_ci return retval; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci /* 16398c2ecf20Sopenharmony_ci * This device requires the atim queue and DMA-mapped skbs. 16408c2ecf20Sopenharmony_ci */ 16418c2ecf20Sopenharmony_ci __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); 16428c2ecf20Sopenharmony_ci __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); 16438c2ecf20Sopenharmony_ci __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci /* 16468c2ecf20Sopenharmony_ci * Set the rssi offset. 16478c2ecf20Sopenharmony_ci */ 16488c2ecf20Sopenharmony_ci rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci return 0; 16518c2ecf20Sopenharmony_ci} 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci/* 16548c2ecf20Sopenharmony_ci * IEEE80211 stack callback functions. 16558c2ecf20Sopenharmony_ci */ 16568c2ecf20Sopenharmony_cistatic int rt2400pci_conf_tx(struct ieee80211_hw *hw, 16578c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, u16 queue, 16588c2ecf20Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 16598c2ecf20Sopenharmony_ci{ 16608c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci /* 16638c2ecf20Sopenharmony_ci * We don't support variating cw_min and cw_max variables 16648c2ecf20Sopenharmony_ci * per queue. So by default we only configure the TX queue, 16658c2ecf20Sopenharmony_ci * and ignore all other configurations. 16668c2ecf20Sopenharmony_ci */ 16678c2ecf20Sopenharmony_ci if (queue != 0) 16688c2ecf20Sopenharmony_ci return -EINVAL; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci if (rt2x00mac_conf_tx(hw, vif, queue, params)) 16718c2ecf20Sopenharmony_ci return -EINVAL; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci /* 16748c2ecf20Sopenharmony_ci * Write configuration to register. 16758c2ecf20Sopenharmony_ci */ 16768c2ecf20Sopenharmony_ci rt2400pci_config_cw(rt2x00dev, 16778c2ecf20Sopenharmony_ci rt2x00dev->tx->cw_min, rt2x00dev->tx->cw_max); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci return 0; 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_cistatic u64 rt2400pci_get_tsf(struct ieee80211_hw *hw, 16838c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 16848c2ecf20Sopenharmony_ci{ 16858c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 16868c2ecf20Sopenharmony_ci u64 tsf; 16878c2ecf20Sopenharmony_ci u32 reg; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR17); 16908c2ecf20Sopenharmony_ci tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32; 16918c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR16); 16928c2ecf20Sopenharmony_ci tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci return tsf; 16958c2ecf20Sopenharmony_ci} 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_cistatic int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 17008c2ecf20Sopenharmony_ci u32 reg; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci reg = rt2x00mmio_register_read(rt2x00dev, CSR15); 17038c2ecf20Sopenharmony_ci return rt2x00_get_field32(reg, CSR15_BEACON_SENT); 17048c2ecf20Sopenharmony_ci} 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_cistatic const struct ieee80211_ops rt2400pci_mac80211_ops = { 17078c2ecf20Sopenharmony_ci .tx = rt2x00mac_tx, 17088c2ecf20Sopenharmony_ci .start = rt2x00mac_start, 17098c2ecf20Sopenharmony_ci .stop = rt2x00mac_stop, 17108c2ecf20Sopenharmony_ci .add_interface = rt2x00mac_add_interface, 17118c2ecf20Sopenharmony_ci .remove_interface = rt2x00mac_remove_interface, 17128c2ecf20Sopenharmony_ci .config = rt2x00mac_config, 17138c2ecf20Sopenharmony_ci .configure_filter = rt2x00mac_configure_filter, 17148c2ecf20Sopenharmony_ci .sw_scan_start = rt2x00mac_sw_scan_start, 17158c2ecf20Sopenharmony_ci .sw_scan_complete = rt2x00mac_sw_scan_complete, 17168c2ecf20Sopenharmony_ci .get_stats = rt2x00mac_get_stats, 17178c2ecf20Sopenharmony_ci .bss_info_changed = rt2x00mac_bss_info_changed, 17188c2ecf20Sopenharmony_ci .conf_tx = rt2400pci_conf_tx, 17198c2ecf20Sopenharmony_ci .get_tsf = rt2400pci_get_tsf, 17208c2ecf20Sopenharmony_ci .tx_last_beacon = rt2400pci_tx_last_beacon, 17218c2ecf20Sopenharmony_ci .rfkill_poll = rt2x00mac_rfkill_poll, 17228c2ecf20Sopenharmony_ci .flush = rt2x00mac_flush, 17238c2ecf20Sopenharmony_ci .set_antenna = rt2x00mac_set_antenna, 17248c2ecf20Sopenharmony_ci .get_antenna = rt2x00mac_get_antenna, 17258c2ecf20Sopenharmony_ci .get_ringparam = rt2x00mac_get_ringparam, 17268c2ecf20Sopenharmony_ci .tx_frames_pending = rt2x00mac_tx_frames_pending, 17278c2ecf20Sopenharmony_ci}; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { 17308c2ecf20Sopenharmony_ci .irq_handler = rt2400pci_interrupt, 17318c2ecf20Sopenharmony_ci .txstatus_tasklet = rt2400pci_txstatus_tasklet, 17328c2ecf20Sopenharmony_ci .tbtt_tasklet = rt2400pci_tbtt_tasklet, 17338c2ecf20Sopenharmony_ci .rxdone_tasklet = rt2400pci_rxdone_tasklet, 17348c2ecf20Sopenharmony_ci .probe_hw = rt2400pci_probe_hw, 17358c2ecf20Sopenharmony_ci .initialize = rt2x00mmio_initialize, 17368c2ecf20Sopenharmony_ci .uninitialize = rt2x00mmio_uninitialize, 17378c2ecf20Sopenharmony_ci .get_entry_state = rt2400pci_get_entry_state, 17388c2ecf20Sopenharmony_ci .clear_entry = rt2400pci_clear_entry, 17398c2ecf20Sopenharmony_ci .set_device_state = rt2400pci_set_device_state, 17408c2ecf20Sopenharmony_ci .rfkill_poll = rt2400pci_rfkill_poll, 17418c2ecf20Sopenharmony_ci .link_stats = rt2400pci_link_stats, 17428c2ecf20Sopenharmony_ci .reset_tuner = rt2400pci_reset_tuner, 17438c2ecf20Sopenharmony_ci .link_tuner = rt2400pci_link_tuner, 17448c2ecf20Sopenharmony_ci .start_queue = rt2400pci_start_queue, 17458c2ecf20Sopenharmony_ci .kick_queue = rt2400pci_kick_queue, 17468c2ecf20Sopenharmony_ci .stop_queue = rt2400pci_stop_queue, 17478c2ecf20Sopenharmony_ci .flush_queue = rt2x00mmio_flush_queue, 17488c2ecf20Sopenharmony_ci .write_tx_desc = rt2400pci_write_tx_desc, 17498c2ecf20Sopenharmony_ci .write_beacon = rt2400pci_write_beacon, 17508c2ecf20Sopenharmony_ci .fill_rxdone = rt2400pci_fill_rxdone, 17518c2ecf20Sopenharmony_ci .config_filter = rt2400pci_config_filter, 17528c2ecf20Sopenharmony_ci .config_intf = rt2400pci_config_intf, 17538c2ecf20Sopenharmony_ci .config_erp = rt2400pci_config_erp, 17548c2ecf20Sopenharmony_ci .config_ant = rt2400pci_config_ant, 17558c2ecf20Sopenharmony_ci .config = rt2400pci_config, 17568c2ecf20Sopenharmony_ci}; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_cistatic void rt2400pci_queue_init(struct data_queue *queue) 17598c2ecf20Sopenharmony_ci{ 17608c2ecf20Sopenharmony_ci switch (queue->qid) { 17618c2ecf20Sopenharmony_ci case QID_RX: 17628c2ecf20Sopenharmony_ci queue->limit = 24; 17638c2ecf20Sopenharmony_ci queue->data_size = DATA_FRAME_SIZE; 17648c2ecf20Sopenharmony_ci queue->desc_size = RXD_DESC_SIZE; 17658c2ecf20Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 17668c2ecf20Sopenharmony_ci break; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci case QID_AC_VO: 17698c2ecf20Sopenharmony_ci case QID_AC_VI: 17708c2ecf20Sopenharmony_ci case QID_AC_BE: 17718c2ecf20Sopenharmony_ci case QID_AC_BK: 17728c2ecf20Sopenharmony_ci queue->limit = 24; 17738c2ecf20Sopenharmony_ci queue->data_size = DATA_FRAME_SIZE; 17748c2ecf20Sopenharmony_ci queue->desc_size = TXD_DESC_SIZE; 17758c2ecf20Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 17768c2ecf20Sopenharmony_ci break; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci case QID_BEACON: 17798c2ecf20Sopenharmony_ci queue->limit = 1; 17808c2ecf20Sopenharmony_ci queue->data_size = MGMT_FRAME_SIZE; 17818c2ecf20Sopenharmony_ci queue->desc_size = TXD_DESC_SIZE; 17828c2ecf20Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 17838c2ecf20Sopenharmony_ci break; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci case QID_ATIM: 17868c2ecf20Sopenharmony_ci queue->limit = 8; 17878c2ecf20Sopenharmony_ci queue->data_size = DATA_FRAME_SIZE; 17888c2ecf20Sopenharmony_ci queue->desc_size = TXD_DESC_SIZE; 17898c2ecf20Sopenharmony_ci queue->priv_size = sizeof(struct queue_entry_priv_mmio); 17908c2ecf20Sopenharmony_ci break; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci default: 17938c2ecf20Sopenharmony_ci BUG(); 17948c2ecf20Sopenharmony_ci break; 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci} 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_cistatic const struct rt2x00_ops rt2400pci_ops = { 17998c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 18008c2ecf20Sopenharmony_ci .max_ap_intf = 1, 18018c2ecf20Sopenharmony_ci .eeprom_size = EEPROM_SIZE, 18028c2ecf20Sopenharmony_ci .rf_size = RF_SIZE, 18038c2ecf20Sopenharmony_ci .tx_queues = NUM_TX_QUEUES, 18048c2ecf20Sopenharmony_ci .queue_init = rt2400pci_queue_init, 18058c2ecf20Sopenharmony_ci .lib = &rt2400pci_rt2x00_ops, 18068c2ecf20Sopenharmony_ci .hw = &rt2400pci_mac80211_ops, 18078c2ecf20Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_DEBUGFS 18088c2ecf20Sopenharmony_ci .debugfs = &rt2400pci_rt2x00debug, 18098c2ecf20Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ 18108c2ecf20Sopenharmony_ci}; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci/* 18138c2ecf20Sopenharmony_ci * RT2400pci module information. 18148c2ecf20Sopenharmony_ci */ 18158c2ecf20Sopenharmony_cistatic const struct pci_device_id rt2400pci_device_table[] = { 18168c2ecf20Sopenharmony_ci { PCI_DEVICE(0x1814, 0x0101) }, 18178c2ecf20Sopenharmony_ci { 0, } 18188c2ecf20Sopenharmony_ci}; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRV_PROJECT); 18228c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 18238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver."); 18248c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards"); 18258c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rt2400pci_device_table); 18268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_cistatic int rt2400pci_probe(struct pci_dev *pci_dev, 18298c2ecf20Sopenharmony_ci const struct pci_device_id *id) 18308c2ecf20Sopenharmony_ci{ 18318c2ecf20Sopenharmony_ci return rt2x00pci_probe(pci_dev, &rt2400pci_ops); 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_cistatic struct pci_driver rt2400pci_driver = { 18358c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 18368c2ecf20Sopenharmony_ci .id_table = rt2400pci_device_table, 18378c2ecf20Sopenharmony_ci .probe = rt2400pci_probe, 18388c2ecf20Sopenharmony_ci .remove = rt2x00pci_remove, 18398c2ecf20Sopenharmony_ci .driver.pm = &rt2x00pci_pm_ops, 18408c2ecf20Sopenharmony_ci}; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_cimodule_pci_driver(rt2400pci_driver); 1843