diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx')
51 files changed, 941 insertions, 10882 deletions
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 2f98058be45..b447559f1db 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -5,40 +5,6 @@ menuconfig WL12XX This will enable TI wl12xx driver support. The drivers make use of the mac80211 stack. -config WL1251 - tristate "TI wl1251 support" - depends on WL12XX && GENERIC_HARDIRQS - select FW_LOADER - select CRC7 - ---help--- - This module adds support for wireless adapters based on - TI wl1251 chipset. - - If you choose to build a module, it'll be called wl1251. Say - N if unsure. - -config WL1251_SPI - tristate "TI wl1251 SPI support" - depends on WL1251 && SPI_MASTER - ---help--- - This module adds support for the SPI interface of adapters using - TI wl1251 chipset. Select this if your platform is using - the SPI bus. - - If you choose to build a module, it'll be called wl1251_spi. - Say N if unsure. - -config WL1251_SDIO - tristate "TI wl1251 SDIO support" - depends on WL1251 && MMC - ---help--- - This module adds support for the SDIO interface of adapters using - TI wl1251 chipset. Select this if your platform is using - the SDIO bus. - - If you choose to build a module, it'll be called - wl1251_sdio. Say N if unsure. - config WL1271 tristate "TI wl1271 support" depends on WL12XX && GENERIC_HARDIRQS @@ -74,4 +40,7 @@ config WL1271_SDIO If you choose to build a module, it'll be called wl1271_sdio. Say N if unsure. - +config WL12XX_PLATFORM_DATA + bool + depends on WL1271_SDIO != n + default y diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 078b4398ac1..3a807444b2a 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,12 +1,3 @@ -wl1251-objs = wl1251_main.o wl1251_event.o \ - wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ - wl1251_acx.o wl1251_boot.o wl1251_init.o \ - wl1251_debugfs.o wl1251_io.o - -obj-$(CONFIG_WL1251) += wl1251.o -obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o -obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o - wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \ wl1271_event.o wl1271_tx.o wl1271_rx.o \ wl1271_ps.o wl1271_acx.o wl1271_boot.o \ @@ -16,3 +7,6 @@ wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o obj-$(CONFIG_WL1271) += wl1271.o obj-$(CONFIG_WL1271_SPI) += wl1271_spi.o obj-$(CONFIG_WL1271_SDIO) += wl1271_sdio.o + +# small builtin driver bit +obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h deleted file mode 100644 index 6b942a28e6a..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ /dev/null @@ -1,432 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_H__ -#define __WL1251_H__ - -#include <linux/mutex.h> -#include <linux/list.h> -#include <linux/bitops.h> -#include <net/mac80211.h> - -#define DRIVER_NAME "wl1251" -#define DRIVER_PREFIX DRIVER_NAME ": " - -enum { - DEBUG_NONE = 0, - DEBUG_IRQ = BIT(0), - DEBUG_SPI = BIT(1), - DEBUG_BOOT = BIT(2), - DEBUG_MAILBOX = BIT(3), - DEBUG_NETLINK = BIT(4), - DEBUG_EVENT = BIT(5), - DEBUG_TX = BIT(6), - DEBUG_RX = BIT(7), - DEBUG_SCAN = BIT(8), - DEBUG_CRYPT = BIT(9), - DEBUG_PSM = BIT(10), - DEBUG_MAC80211 = BIT(11), - DEBUG_CMD = BIT(12), - DEBUG_ACX = BIT(13), - DEBUG_ALL = ~0, -}; - -#define DEBUG_LEVEL (DEBUG_NONE) - -#define DEBUG_DUMP_LIMIT 1024 - -#define wl1251_error(fmt, arg...) \ - printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) - -#define wl1251_warning(fmt, arg...) \ - printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) - -#define wl1251_notice(fmt, arg...) \ - printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1251_info(fmt, arg...) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1251_debug(level, fmt, arg...) \ - do { \ - if (level & DEBUG_LEVEL) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ - } while (0) - -#define wl1251_dump(level, prefix, buf, len) \ - do { \ - if (level & DEBUG_LEVEL) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - 0); \ - } while (0) - -#define wl1251_dump_ascii(level, prefix, buf, len) \ - do { \ - if (level & DEBUG_LEVEL) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - true); \ - } while (0) - -#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ - CFG_BSSID_FILTER_EN) - -#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ - CFG_RX_MGMT_EN | \ - CFG_RX_DATA_EN | \ - CFG_RX_CTL_EN | \ - CFG_RX_BCN_EN | \ - CFG_RX_AUTH_EN | \ - CFG_RX_ASSOC_EN) - -#define WL1251_BUSY_WORD_LEN 8 - -struct boot_attr { - u32 radio_type; - u8 mac_clock; - u8 arm_clock; - int firmware_debug; - u32 minor; - u32 major; - u32 bugfix; -}; - -enum wl1251_state { - WL1251_STATE_OFF, - WL1251_STATE_ON, - WL1251_STATE_PLT, -}; - -enum wl1251_partition_type { - PART_DOWN, - PART_WORK, - PART_DRPW, - - PART_TABLE_LEN -}; - -struct wl1251_partition { - u32 size; - u32 start; -}; - -struct wl1251_partition_set { - struct wl1251_partition mem; - struct wl1251_partition reg; -}; - -struct wl1251; - -struct wl1251_stats { - struct acx_statistics *fw_stats; - unsigned long fw_stats_update; - - unsigned int retry_count; - unsigned int excessive_retries; -}; - -struct wl1251_debugfs { - struct dentry *rootdir; - struct dentry *fw_statistics; - - struct dentry *tx_internal_desc_overflow; - - struct dentry *rx_out_of_mem; - struct dentry *rx_hdr_overflow; - struct dentry *rx_hw_stuck; - struct dentry *rx_dropped; - struct dentry *rx_fcs_err; - struct dentry *rx_xfr_hint_trig; - struct dentry *rx_path_reset; - struct dentry *rx_reset_counter; - - struct dentry *dma_rx_requested; - struct dentry *dma_rx_errors; - struct dentry *dma_tx_requested; - struct dentry *dma_tx_errors; - - struct dentry *isr_cmd_cmplt; - struct dentry *isr_fiqs; - struct dentry *isr_rx_headers; - struct dentry *isr_rx_mem_overflow; - struct dentry *isr_rx_rdys; - struct dentry *isr_irqs; - struct dentry *isr_tx_procs; - struct dentry *isr_decrypt_done; - struct dentry *isr_dma0_done; - struct dentry *isr_dma1_done; - struct dentry *isr_tx_exch_complete; - struct dentry *isr_commands; - struct dentry *isr_rx_procs; - struct dentry *isr_hw_pm_mode_changes; - struct dentry *isr_host_acknowledges; - struct dentry *isr_pci_pm; - struct dentry *isr_wakeups; - struct dentry *isr_low_rssi; - - struct dentry *wep_addr_key_count; - struct dentry *wep_default_key_count; - /* skipping wep.reserved */ - struct dentry *wep_key_not_found; - struct dentry *wep_decrypt_fail; - struct dentry *wep_packets; - struct dentry *wep_interrupt; - - struct dentry *pwr_ps_enter; - struct dentry *pwr_elp_enter; - struct dentry *pwr_missing_bcns; - struct dentry *pwr_wake_on_host; - struct dentry *pwr_wake_on_timer_exp; - struct dentry *pwr_tx_with_ps; - struct dentry *pwr_tx_without_ps; - struct dentry *pwr_rcvd_beacons; - struct dentry *pwr_power_save_off; - struct dentry *pwr_enable_ps; - struct dentry *pwr_disable_ps; - struct dentry *pwr_fix_tsf_ps; - /* skipping cont_miss_bcns_spread for now */ - struct dentry *pwr_rcvd_awake_beacons; - - struct dentry *mic_rx_pkts; - struct dentry *mic_calc_failure; - - struct dentry *aes_encrypt_fail; - struct dentry *aes_decrypt_fail; - struct dentry *aes_encrypt_packets; - struct dentry *aes_decrypt_packets; - struct dentry *aes_encrypt_interrupt; - struct dentry *aes_decrypt_interrupt; - - struct dentry *event_heart_beat; - struct dentry *event_calibration; - struct dentry *event_rx_mismatch; - struct dentry *event_rx_mem_empty; - struct dentry *event_rx_pool; - struct dentry *event_oom_late; - struct dentry *event_phy_transmit_error; - struct dentry *event_tx_stuck; - - struct dentry *ps_pspoll_timeouts; - struct dentry *ps_upsd_timeouts; - struct dentry *ps_upsd_max_sptime; - struct dentry *ps_upsd_max_apturn; - struct dentry *ps_pspoll_max_apturn; - struct dentry *ps_pspoll_utilization; - struct dentry *ps_upsd_utilization; - - struct dentry *rxpipe_rx_prep_beacon_drop; - struct dentry *rxpipe_descr_host_int_trig_rx_data; - struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; - struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; - struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; - - struct dentry *tx_queue_len; - struct dentry *tx_queue_status; - - struct dentry *retry_count; - struct dentry *excessive_retries; -}; - -struct wl1251_if_operations { - void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); - void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); - void (*read_elp)(struct wl1251 *wl, int addr, u32 *val); - void (*write_elp)(struct wl1251 *wl, int addr, u32 val); - void (*reset)(struct wl1251 *wl); - void (*enable_irq)(struct wl1251 *wl); - void (*disable_irq)(struct wl1251 *wl); -}; - -struct wl1251 { - struct ieee80211_hw *hw; - bool mac80211_registered; - - void *if_priv; - const struct wl1251_if_operations *if_ops; - - void (*set_power)(bool enable); - int irq; - bool use_eeprom; - - enum wl1251_state state; - struct mutex mutex; - - int physical_mem_addr; - int physical_reg_addr; - int virtual_mem_addr; - int virtual_reg_addr; - - int cmd_box_addr; - int event_box_addr; - struct boot_attr boot_attr; - - u8 *fw; - size_t fw_len; - u8 *nvs; - size_t nvs_len; - - u8 bssid[ETH_ALEN]; - u8 mac_addr[ETH_ALEN]; - u8 bss_type; - u8 listen_int; - int channel; - - void *target_mem_map; - struct acx_data_path_params_resp *data_path; - - /* Number of TX packets transferred to the FW, modulo 16 */ - u32 data_in_count; - - /* Frames scheduled for transmission, not handled yet */ - struct sk_buff_head tx_queue; - bool tx_queue_stopped; - - struct work_struct tx_work; - struct work_struct filter_work; - - /* Pending TX frames */ - struct sk_buff *tx_frames[16]; - - /* - * Index pointing to the next TX complete entry - * in the cyclic XT complete array we get from - * the FW. - */ - u32 next_tx_complete; - - /* FW Rx counter */ - u32 rx_counter; - - /* Rx frames handled */ - u32 rx_handled; - - /* Current double buffer */ - u32 rx_current_buffer; - u32 rx_last_id; - - /* The target interrupt mask */ - u32 intr_mask; - struct work_struct irq_work; - - /* The mbox event mask */ - u32 event_mask; - - /* Mailbox pointers */ - u32 mbox_ptr[2]; - - /* Are we currently scanning */ - bool scanning; - - /* Default key (for WEP) */ - u32 default_key; - - unsigned int tx_mgmt_frm_rate; - unsigned int tx_mgmt_frm_mod; - - unsigned int rx_config; - unsigned int rx_filter; - - /* is firmware in elp mode */ - bool elp; - - struct delayed_work elp_work; - - /* we can be in psm, but not in elp, we have to differentiate */ - bool psm; - - /* PSM mode requested */ - bool psm_requested; - - u16 beacon_int; - u8 dtim_period; - - /* in dBm */ - int power_level; - - struct wl1251_stats stats; - struct wl1251_debugfs debugfs; - - u32 buffer_32; - u32 buffer_cmd; - u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; - struct wl1251_rx_descriptor *rx_descriptor; - - struct ieee80211_vif *vif; - - u32 chip_id; - char fw_ver[21]; - - /* Most recently reported noise in dBm */ - s8 noise; -}; - -int wl1251_plt_start(struct wl1251 *wl); -int wl1251_plt_stop(struct wl1251 *wl); - -struct ieee80211_hw *wl1251_alloc_hw(void); -int wl1251_free_hw(struct wl1251 *wl); -int wl1251_init_ieee80211(struct wl1251 *wl); -void wl1251_enable_interrupts(struct wl1251 *wl); -void wl1251_disable_interrupts(struct wl1251 *wl); - -#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ -#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS -#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ - -#define WL1251_DEFAULT_POWER_LEVEL 20 - -#define WL1251_TX_QUEUE_MAX_LENGTH 20 - -#define WL1251_DEFAULT_BEACON_INT 100 -#define WL1251_DEFAULT_DTIM_PERIOD 1 - -#define WL1251_DEFAULT_CHANNEL 0 - -#define CHIP_ID_1251_PG10 (0x7010101) -#define CHIP_ID_1251_PG11 (0x7020101) -#define CHIP_ID_1251_PG12 (0x7030101) -#define CHIP_ID_1271_PG10 (0x4030101) -#define CHIP_ID_1271_PG20 (0x4030111) - -#define WL1251_FW_NAME "wl1251-fw.bin" -#define WL1251_NVS_NAME "wl1251-nvs.bin" - -#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ - -#define WL1251_PART_DOWN_MEM_START 0x0 -#define WL1251_PART_DOWN_MEM_SIZE 0x16800 -#define WL1251_PART_DOWN_REG_START REGISTERS_BASE -#define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE - -#define WL1251_PART_WORK_MEM_START 0x28000 -#define WL1251_PART_WORK_MEM_SIZE 0x14000 -#define WL1251_PART_WORK_REG_START REGISTERS_BASE -#define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c deleted file mode 100644 index 91891f92807..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ /dev/null @@ -1,1048 +0,0 @@ -#include "wl1251_acx.h" - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/crc7.h> - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_cmd.h" -#include "wl1251_ps.h" - -int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, - u8 mgt_rate, u8 mgt_mod) -{ - struct acx_fw_gen_frame_rates *rates; - int ret; - - wl1251_debug(DEBUG_ACX, "acx frame rates"); - - rates = kzalloc(sizeof(*rates), GFP_KERNEL); - if (!rates) { - ret = -ENOMEM; - goto out; - } - - rates->tx_ctrl_frame_rate = ctrl_rate; - rates->tx_ctrl_frame_mod = ctrl_mod; - rates->tx_mgt_frame_rate = mgt_rate; - rates->tx_mgt_frame_mod = mgt_mod; - - ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, - rates, sizeof(*rates)); - if (ret < 0) { - wl1251_error("Failed to set FW rates and modulation"); - goto out; - } - -out: - kfree(rates); - return ret; -} - - -int wl1251_acx_station_id(struct wl1251 *wl) -{ - struct acx_dot11_station_id *mac; - int ret, i; - - wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); - - mac = kzalloc(sizeof(*mac), GFP_KERNEL); - if (!mac) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < ETH_ALEN; i++) - mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; - - ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); - if (ret < 0) - goto out; - -out: - kfree(mac); - return ret; -} - -int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) -{ - struct acx_dot11_default_key *default_key; - int ret; - - wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); - - default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); - if (!default_key) { - ret = -ENOMEM; - goto out; - } - - default_key->id = key_id; - - ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, - default_key, sizeof(*default_key)); - if (ret < 0) { - wl1251_error("Couldn't set default key"); - goto out; - } - - wl->default_key = key_id; - -out: - kfree(default_key); - return ret; -} - -int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, - u8 listen_interval) -{ - struct acx_wake_up_condition *wake_up; - int ret; - - wl1251_debug(DEBUG_ACX, "acx wake up conditions"); - - wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); - if (!wake_up) { - ret = -ENOMEM; - goto out; - } - - wake_up->wake_up_event = wake_up_event; - wake_up->listen_interval = listen_interval; - - ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, - wake_up, sizeof(*wake_up)); - if (ret < 0) { - wl1251_warning("could not set wake up conditions: %d", ret); - goto out; - } - -out: - kfree(wake_up); - return ret; -} - -int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) -{ - struct acx_sleep_auth *auth; - int ret; - - wl1251_debug(DEBUG_ACX, "acx sleep auth"); - - auth = kzalloc(sizeof(*auth), GFP_KERNEL); - if (!auth) { - ret = -ENOMEM; - goto out; - } - - auth->sleep_auth = sleep_auth; - - ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); - if (ret < 0) - return ret; - -out: - kfree(auth); - return ret; -} - -int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len) -{ - struct acx_revision *rev; - int ret; - - wl1251_debug(DEBUG_ACX, "acx fw rev"); - - rev = kzalloc(sizeof(*rev), GFP_KERNEL); - if (!rev) { - ret = -ENOMEM; - goto out; - } - - ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); - if (ret < 0) { - wl1251_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - /* be careful with the buffer sizes */ - strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); - - /* - * if the firmware version string is exactly - * sizeof(rev->fw_version) long or fw_len is less than - * sizeof(rev->fw_version) it won't be null terminated - */ - buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; - -out: - kfree(rev); - return ret; -} - -int wl1251_acx_tx_power(struct wl1251 *wl, int power) -{ - struct acx_current_tx_power *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); - - if (power < 0 || power > 25) - return -EINVAL; - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->current_tx_power = power * 10; - - ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("configure of tx power failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_feature_cfg(struct wl1251 *wl) -{ - struct acx_feature_config *feature; - int ret; - - wl1251_debug(DEBUG_ACX, "acx feature cfg"); - - feature = kzalloc(sizeof(*feature), GFP_KERNEL); - if (!feature) { - ret = -ENOMEM; - goto out; - } - - /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ - feature->data_flow_options = 0; - feature->options = 0; - - ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, - feature, sizeof(*feature)); - if (ret < 0) { - wl1251_error("Couldn't set HW encryption"); - goto out; - } - -out: - kfree(feature); - return ret; -} - -int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, - size_t len) -{ - int ret; - - wl1251_debug(DEBUG_ACX, "acx mem map"); - - ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_acx_data_path_params(struct wl1251 *wl, - struct acx_data_path_params_resp *resp) -{ - struct acx_data_path_params *params; - int ret; - - wl1251_debug(DEBUG_ACX, "acx data path params"); - - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - ret = -ENOMEM; - goto out; - } - - params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; - params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; - - params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; - params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; - - params->tx_complete_threshold = 1; - - params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; - - params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; - - ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS, - params, sizeof(*params)); - if (ret < 0) - goto out; - - /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ - ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, - resp, sizeof(*resp)); - - if (ret < 0) { - wl1251_warning("failed to read data path parameters: %d", ret); - goto out; - } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { - wl1251_warning("data path parameter acx status failed"); - ret = -EIO; - goto out; - } - -out: - kfree(params); - return ret; -} - -int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time) -{ - struct acx_rx_msdu_lifetime *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx rx msdu life time"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->lifetime = life_time; - ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, - acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("failed to set rx msdu life time: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter) -{ - struct acx_rx_config *rx_config; - int ret; - - wl1251_debug(DEBUG_ACX, "acx rx config"); - - rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); - if (!rx_config) { - ret = -ENOMEM; - goto out; - } - - rx_config->config_options = config; - rx_config->filter_options = filter; - - ret = wl1251_cmd_configure(wl, ACX_RX_CFG, - rx_config, sizeof(*rx_config)); - if (ret < 0) { - wl1251_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(rx_config); - return ret; -} - -int wl1251_acx_pd_threshold(struct wl1251 *wl) -{ - struct acx_packet_detection *pd; - int ret; - - wl1251_debug(DEBUG_ACX, "acx data pd threshold"); - - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - ret = -ENOMEM; - goto out; - } - - /* FIXME: threshold value not set */ - - ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); - if (ret < 0) { - wl1251_warning("failed to set pd threshold: %d", ret); - goto out; - } - -out: - kfree(pd); - return 0; -} - -int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time) -{ - struct acx_slot *slot; - int ret; - - wl1251_debug(DEBUG_ACX, "acx slot"); - - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) { - ret = -ENOMEM; - goto out; - } - - slot->wone_index = STATION_WONE_INDEX; - slot->slot_time = slot_time; - - ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); - if (ret < 0) { - wl1251_warning("failed to set slot time: %d", ret); - goto out; - } - -out: - kfree(slot); - return ret; -} - -int wl1251_acx_group_address_tbl(struct wl1251 *wl) -{ - struct acx_dot11_grp_addr_tbl *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx group address tbl"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* MAC filtering */ - acx->enabled = 0; - acx->num_groups = 0; - memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); - - ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, - acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("failed to set group addr table: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_service_period_timeout(struct wl1251 *wl) -{ - struct acx_rx_timeout *rx_timeout; - int ret; - - rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); - if (!rx_timeout) { - ret = -ENOMEM; - goto out; - } - - wl1251_debug(DEBUG_ACX, "acx service period timeout"); - - rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; - rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; - - ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, - rx_timeout, sizeof(*rx_timeout)); - if (ret < 0) { - wl1251_warning("failed to set service period timeout: %d", - ret); - goto out; - } - -out: - kfree(rx_timeout); - return ret; -} - -int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold) -{ - struct acx_rts_threshold *rts; - int ret; - - wl1251_debug(DEBUG_ACX, "acx rts threshold"); - - rts = kzalloc(sizeof(*rts), GFP_KERNEL); - if (!rts) { - ret = -ENOMEM; - goto out; - } - - rts->threshold = rts_threshold; - - ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); - if (ret < 0) { - wl1251_warning("failed to set rts threshold: %d", ret); - goto out; - } - -out: - kfree(rts); - return ret; -} - -int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter) -{ - struct acx_beacon_filter_option *beacon_filter; - int ret; - - wl1251_debug(DEBUG_ACX, "acx beacon filter opt"); - - beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); - if (!beacon_filter) { - ret = -ENOMEM; - goto out; - } - - beacon_filter->enable = enable_filter; - beacon_filter->max_num_beacons = 0; - - ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT, - beacon_filter, sizeof(*beacon_filter)); - if (ret < 0) { - wl1251_warning("failed to set beacon filter opt: %d", ret); - goto out; - } - -out: - kfree(beacon_filter); - return ret; -} - -int wl1251_acx_beacon_filter_table(struct wl1251 *wl) -{ - struct acx_beacon_filter_ie_table *ie_table; - int idx = 0; - int ret; - - wl1251_debug(DEBUG_ACX, "acx beacon filter table"); - - ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); - if (!ie_table) { - ret = -ENOMEM; - goto out; - } - - /* configure default beacon pass-through rules */ - ie_table->num_ie = 1; - ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN; - ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE; - - ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, - ie_table, sizeof(*ie_table)); - if (ret < 0) { - wl1251_warning("failed to set beacon filter table: %d", ret); - goto out; - } - -out: - kfree(ie_table); - return ret; -} - -int wl1251_acx_conn_monit_params(struct wl1251 *wl) -{ - struct acx_conn_monit_params *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx connection monitor parameters"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; - acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; - - ret = wl1251_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, - acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("failed to set connection monitor " - "parameters: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_sg_enable(struct wl1251 *wl) -{ - struct acx_bt_wlan_coex *pta; - int ret; - - wl1251_debug(DEBUG_ACX, "acx sg enable"); - - pta = kzalloc(sizeof(*pta), GFP_KERNEL); - if (!pta) { - ret = -ENOMEM; - goto out; - } - - pta->enable = SG_ENABLE; - - ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); - if (ret < 0) { - wl1251_warning("failed to set softgemini enable: %d", ret); - goto out; - } - -out: - kfree(pta); - return ret; -} - -int wl1251_acx_sg_cfg(struct wl1251 *wl) -{ - struct acx_bt_wlan_coex_param *param; - int ret; - - wl1251_debug(DEBUG_ACX, "acx sg cfg"); - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) { - ret = -ENOMEM; - goto out; - } - - /* BT-WLAN coext parameters */ - param->min_rate = RATE_INDEX_24MBPS; - param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; - param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; - param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; - param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; - param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; - param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; - param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; - param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; - param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; - param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; - param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; - param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; - param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; - param->antenna_type = PTA_ANTENNA_TYPE_DEF; - param->signal_type = PTA_SIGNALING_TYPE_DEF; - param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; - param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; - param->max_cts = PTA_MAX_NUM_CTS_DEF; - param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; - param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; - param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; - param->wlan_elp_hp = PTA_ELP_HP_DEF; - param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; - param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; - param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; - param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; - param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; - - ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); - if (ret < 0) { - wl1251_warning("failed to set sg config: %d", ret); - goto out; - } - -out: - kfree(param); - return ret; -} - -int wl1251_acx_cca_threshold(struct wl1251 *wl) -{ - struct acx_energy_detection *detection; - int ret; - - wl1251_debug(DEBUG_ACX, "acx cca threshold"); - - detection = kzalloc(sizeof(*detection), GFP_KERNEL); - if (!detection) { - ret = -ENOMEM; - goto out; - } - - detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; - detection->tx_energy_detection = 0; - - ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD, - detection, sizeof(*detection)); - if (ret < 0) { - wl1251_warning("failed to set cca threshold: %d", ret); - return ret; - } - -out: - kfree(detection); - return ret; -} - -int wl1251_acx_bcn_dtim_options(struct wl1251 *wl) -{ - struct acx_beacon_broadcast *bb; - int ret; - - wl1251_debug(DEBUG_ACX, "acx bcn dtim options"); - - bb = kzalloc(sizeof(*bb), GFP_KERNEL); - if (!bb) { - ret = -ENOMEM; - goto out; - } - - bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; - bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; - bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; - bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; - - ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); - if (ret < 0) { - wl1251_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(bb); - return ret; -} - -int wl1251_acx_aid(struct wl1251 *wl, u16 aid) -{ - struct acx_aid *acx_aid; - int ret; - - wl1251_debug(DEBUG_ACX, "acx aid"); - - acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); - if (!acx_aid) { - ret = -ENOMEM; - goto out; - } - - acx_aid->aid = aid; - - ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); - if (ret < 0) { - wl1251_warning("failed to set aid: %d", ret); - goto out; - } - -out: - kfree(acx_aid); - return ret; -} - -int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask) -{ - struct acx_event_mask *mask; - int ret; - - wl1251_debug(DEBUG_ACX, "acx event mbox mask"); - - mask = kzalloc(sizeof(*mask), GFP_KERNEL); - if (!mask) { - ret = -ENOMEM; - goto out; - } - - /* high event mask is unused */ - mask->high_event_mask = 0xffffffff; - - mask->event_mask = event_mask; - - ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK, - mask, sizeof(*mask)); - if (ret < 0) { - wl1251_warning("failed to set acx_event_mbox_mask: %d", ret); - goto out; - } - -out: - kfree(mask); - return ret; -} - -int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) -{ - struct acx_preamble *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx_set_preamble"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->preamble = preamble; - - ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("Setting of preamble failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_cts_protect(struct wl1251 *wl, - enum acx_ctsprotect_type ctsprotect) -{ - struct acx_ctsprotect *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ctsprotect = ctsprotect; - - ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("Setting of ctsprotect failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) -{ - struct acx_tsf_info *tsf_info; - int ret; - - tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); - if (!tsf_info) { - ret = -ENOMEM; - goto out; - } - - ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO, - tsf_info, sizeof(*tsf_info)); - if (ret < 0) { - wl1251_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - *mactime = tsf_info->current_tsf_lsb | - (tsf_info->current_tsf_msb << 31); - -out: - kfree(tsf_info); - return ret; -} - -int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) -{ - int ret; - - wl1251_debug(DEBUG_ACX, "acx statistics"); - - ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats, - sizeof(*stats)); - if (ret < 0) { - wl1251_warning("acx statistics failed: %d", ret); - return -ENOMEM; - } - - return 0; -} - -int wl1251_acx_rate_policies(struct wl1251 *wl) -{ - struct acx_rate_policy *acx; - int ret = 0; - - wl1251_debug(DEBUG_ACX, "acx rate policies"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* configure one default (one-size-fits-all) rate class */ - acx->rate_class_cnt = 1; - acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; - acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; - acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; - acx->rate_class[0].aflags = 0; - - ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("Setting of rate policies failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_mem_cfg(struct wl1251 *wl) -{ - struct wl1251_acx_config_memory *mem_conf; - int ret, i; - - wl1251_debug(DEBUG_ACX, "acx mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - /* memory config */ - mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); - mem_conf->mem_config.rx_mem_block_num = 35; - mem_conf->mem_config.tx_min_mem_block_num = 64; - mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; - mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; - mem_conf->mem_config.num_ssid_profiles = 1; - mem_conf->mem_config.debug_buffer_size = - cpu_to_le16(TRACE_BUFFER_MAX_SIZE); - - /* RX queue config */ - mem_conf->rx_queue_config.dma_address = 0; - mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; - mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; - mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; - - /* TX queue config */ - for (i = 0; i < MAX_TX_QUEUES; i++) { - mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; - mem_conf->tx_queue_config[i].attributes = i; - } - - ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, - sizeof(*mem_conf)); - if (ret < 0) { - wl1251_warning("wl1251 mem config failed: %d", ret); - goto out; - } - -out: - kfree(mem_conf); - return ret; -} - -int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim) -{ - struct wl1251_acx_wr_tbtt_and_dtim *acx; - int ret; - - wl1251_debug(DEBUG_ACX, "acx tbtt and dtim"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->tbtt = tbtt; - acx->dtim = dtim; - - ret = wl1251_cmd_configure(wl, ACX_WR_TBTT_AND_DTIM, - acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("failed to set tbtt and dtim: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifs, u16 txop) -{ - struct wl1251_acx_ac_cfg *acx; - int ret = 0; - - wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " - "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ac = ac; - acx->cw_min = cw_min; - acx->cw_max = cw_max; - acx->aifsn = aifs; - acx->txop_limit = txop; - - ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("acx ac cfg failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, - enum wl1251_acx_channel_type type, - u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, - enum wl1251_acx_ack_policy ack_policy) -{ - struct wl1251_acx_tid_cfg *acx; - int ret = 0; - - wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d " - "ps_scheme %d ack_policy %d", queue, type, tsid, - ps_scheme, ack_policy); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->queue = queue; - acx->type = type; - acx->tsid = tsid; - acx->ps_scheme = ps_scheme; - acx->ack_policy = ack_policy; - - ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("acx tid cfg failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h deleted file mode 100644 index 842df310d92..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ /dev/null @@ -1,1413 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_ACX_H__ -#define __WL1251_ACX_H__ - -#include "wl1251.h" -#include "wl1251_cmd.h" - -/* Target's information element */ -struct acx_header { - struct wl1251_cmd_header cmd; - - /* acx (or information element) header */ - u16 id; - - /* payload length (not including headers */ - u16 len; -}; - -struct acx_error_counter { - struct acx_header header; - - /* The number of PLCP errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - u32 PLCP_error; - - /* The number of FCS errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - u32 FCS_error; - - /* The number of MPDUs without PLCP header errors received*/ - /* since the last time this information element was interrogated. */ - /* This field is automatically cleared when it is interrogated.*/ - u32 valid_frame; - - /* the number of missed sequence numbers in the squentially */ - /* values of frames seq numbers */ - u32 seq_num_miss; -} __packed; - -struct acx_revision { - struct acx_header header; - - /* - * The WiLink firmware version, an ASCII string x.x.x.x, - * that uniquely identifies the current firmware. - * The left most digit is incremented each time a - * significant change is made to the firmware, such as - * code redesign or new platform support. - * The second digit is incremented when major enhancements - * are added or major fixes are made. - * The third digit is incremented for each GA release. - * The fourth digit is incremented for each build. - * The first two digits identify a firmware release version, - * in other words, a unique set of features. - * The first three digits identify a GA release. - */ - char fw_version[20]; - - /* - * This 4 byte field specifies the WiLink hardware version. - * bits 0 - 15: Reserved. - * bits 16 - 23: Version ID - The WiLink version ID - * (1 = first spin, 2 = second spin, and so on). - * bits 24 - 31: Chip ID - The WiLink chip ID. - */ - u32 hw_version; -} __packed; - -enum wl1251_psm_mode { - /* Active mode */ - WL1251_PSM_CAM = 0, - - /* Power save mode */ - WL1251_PSM_PS = 1, - - /* Extreme low power */ - WL1251_PSM_ELP = 2, -}; - -struct acx_sleep_auth { - struct acx_header header; - - /* The sleep level authorization of the device. */ - /* 0 - Always active*/ - /* 1 - Power down mode: light / fast sleep*/ - /* 2 - ELP mode: Deep / Max sleep*/ - u8 sleep_auth; - u8 padding[3]; -} __packed; - -enum { - HOSTIF_PCI_MASTER_HOST_INDIRECT, - HOSTIF_PCI_MASTER_HOST_DIRECT, - HOSTIF_SLAVE, - HOSTIF_PKT_RING, - HOSTIF_DONTCARE = 0xFF -}; - -#define DEFAULT_UCAST_PRIORITY 0 -#define DEFAULT_RX_Q_PRIORITY 0 -#define DEFAULT_NUM_STATIONS 1 -#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ -#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ -#define TRACE_BUFFER_MAX_SIZE 256 - -#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_RX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_COMPLETE_TIME_OUT 20 -#define FW_TX_CMPLT_BLOCK_SIZE 16 - -struct acx_data_path_params { - struct acx_header header; - - u16 rx_packet_ring_chunk_size; - u16 tx_packet_ring_chunk_size; - - u8 rx_packet_ring_chunk_num; - u8 tx_packet_ring_chunk_num; - - /* - * Maximum number of packets that can be gathered - * in the TX complete ring before an interrupt - * is generated. - */ - u8 tx_complete_threshold; - - /* Number of pending TX complete entries in cyclic ring.*/ - u8 tx_complete_ring_depth; - - /* - * Max num microseconds since a packet enters the TX - * complete ring until an interrupt is generated. - */ - u32 tx_complete_timeout; -} __packed; - - -struct acx_data_path_params_resp { - struct acx_header header; - - u16 rx_packet_ring_chunk_size; - u16 tx_packet_ring_chunk_size; - - u8 rx_packet_ring_chunk_num; - u8 tx_packet_ring_chunk_num; - - u8 pad[2]; - - u32 rx_packet_ring_addr; - u32 tx_packet_ring_addr; - - u32 rx_control_addr; - u32 tx_control_addr; - - u32 tx_complete_addr; -} __packed; - -#define TX_MSDU_LIFETIME_MIN 0 -#define TX_MSDU_LIFETIME_MAX 3000 -#define TX_MSDU_LIFETIME_DEF 512 -#define RX_MSDU_LIFETIME_MIN 0 -#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF -#define RX_MSDU_LIFETIME_DEF 512000 - -struct acx_rx_msdu_lifetime { - struct acx_header header; - - /* - * The maximum amount of time, in TU, before the - * firmware discards the MSDU. - */ - u32 lifetime; -} __packed; - -/* - * RX Config Options Table - * Bit Definition - * === ========== - * 31:14 Reserved - * 13 Copy RX Status - when set, write three receive status words - * to top of rx'd MPDUs. - * When cleared, do not write three status words (added rev 1.5) - * 12 Reserved - * 11 RX Complete upon FCS error - when set, give rx complete - * interrupt for FCS errors, after the rx filtering, e.g. unicast - * frames not to us with FCS error will not generate an interrupt. - * 10 SSID Filter Enable - When set, the WiLink discards all beacon, - * probe request, and probe response frames with an SSID that does - * not match the SSID specified by the host in the START/JOIN - * command. - * When clear, the WiLink receives frames with any SSID. - * 9 Broadcast Filter Enable - When set, the WiLink discards all - * broadcast frames. When clear, the WiLink receives all received - * broadcast frames. - * 8:6 Reserved - * 5 BSSID Filter Enable - When set, the WiLink discards any frames - * with a BSSID that does not match the BSSID specified by the - * host. - * When clear, the WiLink receives frames from any BSSID. - * 4 MAC Addr Filter - When set, the WiLink discards any frames - * with a destination address that does not match the MAC address - * of the adaptor. - * When clear, the WiLink receives frames destined to any MAC - * address. - * 3 Promiscuous - When set, the WiLink receives all valid frames - * (i.e., all frames that pass the FCS check). - * When clear, only frames that pass the other filters specified - * are received. - * 2 FCS - When set, the WiLink includes the FCS with the received - * frame. - * When cleared, the FCS is discarded. - * 1 PLCP header - When set, write all data from baseband to frame - * buffer including PHY header. - * 0 Reserved - Always equal to 0. - * - * RX Filter Options Table - * Bit Definition - * === ========== - * 31:12 Reserved - Always equal to 0. - * 11 Association - When set, the WiLink receives all association - * related frames (association request/response, reassocation - * request/response, and disassociation). When clear, these frames - * are discarded. - * 10 Auth/De auth - When set, the WiLink receives all authentication - * and de-authentication frames. When clear, these frames are - * discarded. - * 9 Beacon - When set, the WiLink receives all beacon frames. - * When clear, these frames are discarded. - * 8 Contention Free - When set, the WiLink receives all contention - * free frames. - * When clear, these frames are discarded. - * 7 Control - When set, the WiLink receives all control frames. - * When clear, these frames are discarded. - * 6 Data - When set, the WiLink receives all data frames. - * When clear, these frames are discarded. - * 5 FCS Error - When set, the WiLink receives frames that have FCS - * errors. - * When clear, these frames are discarded. - * 4 Management - When set, the WiLink receives all management - * frames. - * When clear, these frames are discarded. - * 3 Probe Request - When set, the WiLink receives all probe request - * frames. - * When clear, these frames are discarded. - * 2 Probe Response - When set, the WiLink receives all probe - * response frames. - * When clear, these frames are discarded. - * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK - * frames. - * When clear, these frames are discarded. - * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames - * that have reserved frame types and sub types as defined by the - * 802.11 specification. - * When clear, these frames are discarded. - */ -struct acx_rx_config { - struct acx_header header; - - u32 config_options; - u32 filter_options; -} __packed; - -enum { - QOS_AC_BE = 0, - QOS_AC_BK, - QOS_AC_VI, - QOS_AC_VO, - QOS_HIGHEST_AC_INDEX = QOS_AC_VO, -}; - -#define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) -#define FIRST_AC_INDEX QOS_AC_BE -#define MAX_NUM_OF_802_1d_TAGS 8 -#define AC_PARAMS_MAX_TSID 15 -#define MAX_APSD_CONF 0xffff - -#define QOS_TX_HIGH_MIN (0) -#define QOS_TX_HIGH_MAX (100) - -#define QOS_TX_HIGH_BK_DEF (25) -#define QOS_TX_HIGH_BE_DEF (35) -#define QOS_TX_HIGH_VI_DEF (35) -#define QOS_TX_HIGH_VO_DEF (35) - -#define QOS_TX_LOW_BK_DEF (15) -#define QOS_TX_LOW_BE_DEF (25) -#define QOS_TX_LOW_VI_DEF (25) -#define QOS_TX_LOW_VO_DEF (25) - -struct acx_tx_queue_qos_config { - struct acx_header header; - - u8 qid; - u8 pad[3]; - - /* Max number of blocks allowd in the queue */ - u16 high_threshold; - - /* Lowest memory blocks guaranteed for this queue */ - u16 low_threshold; -} __packed; - -struct acx_packet_detection { - struct acx_header header; - - u32 threshold; -} __packed; - - -enum acx_slot_type { - SLOT_TIME_LONG = 0, - SLOT_TIME_SHORT = 1, - DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, - MAX_SLOT_TIMES = 0xFF -}; - -#define STATION_WONE_INDEX 0 - -struct acx_slot { - struct acx_header header; - - u8 wone_index; /* Reserved */ - u8 slot_time; - u8 reserved[6]; -} __packed; - - -#define ADDRESS_GROUP_MAX (8) -#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) - -struct acx_dot11_grp_addr_tbl { - struct acx_header header; - - u8 enabled; - u8 num_groups; - u8 pad[2]; - u8 mac_table[ADDRESS_GROUP_MAX_LEN]; -} __packed; - - -#define RX_TIMEOUT_PS_POLL_MIN 0 -#define RX_TIMEOUT_PS_POLL_MAX (200000) -#define RX_TIMEOUT_PS_POLL_DEF (15) -#define RX_TIMEOUT_UPSD_MIN 0 -#define RX_TIMEOUT_UPSD_MAX (200000) -#define RX_TIMEOUT_UPSD_DEF (15) - -struct acx_rx_timeout { - struct acx_header header; - - /* - * The longest time the STA will wait to receive - * traffic from the AP after a PS-poll has been - * transmitted. - */ - u16 ps_poll_timeout; - - /* - * The longest time the STA will wait to receive - * traffic from the AP after a frame has been sent - * from an UPSD enabled queue. - */ - u16 upsd_timeout; -} __packed; - -#define RTS_THRESHOLD_MIN 0 -#define RTS_THRESHOLD_MAX 4096 -#define RTS_THRESHOLD_DEF 2347 - -struct acx_rts_threshold { - struct acx_header header; - - u16 threshold; - u8 pad[2]; -} __packed; - -struct acx_beacon_filter_option { - struct acx_header header; - - u8 enable; - - /* - * The number of beacons without the unicast TIM - * bit set that the firmware buffers before - * signaling the host about ready frames. - * When set to 0 and the filter is enabled, beacons - * without the unicast TIM bit set are dropped. - */ - u8 max_num_beacons; - u8 pad[2]; -} __packed; - -/* - * ACXBeaconFilterEntry (not 221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * - * ACXBeaconFilterEntry (221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * 2 3 OUI - * 5 1 Type - * 6 2 Version - * - * - * Treatment bit mask - The information element handling: - * bit 0 - The information element is compared and transferred - * in case of change. - * bit 1 - The information element is transferred to the host - * with each appearance or disappearance. - * Note that both bits can be set at the same time. - */ -#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) -#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) -#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) -#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) -#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ - BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ - (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ - BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) - -#define BEACON_RULE_PASS_ON_CHANGE BIT(0) -#define BEACON_RULE_PASS_ON_APPEARANCE BIT(1) - -#define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN (37) - -struct acx_beacon_filter_ie_table { - struct acx_header header; - - u8 num_ie; - u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; - u8 pad[3]; -} __packed; - -#define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */ -#define NO_BEACON_DEFAULT_TIMEOUT (500) /* in microseconds */ - -struct acx_conn_monit_params { - struct acx_header header; - - u32 synch_fail_thold; /* number of beacons missed */ - u32 bss_lose_timeout; /* number of TU's from synch fail */ -}; - -enum { - SG_ENABLE = 0, - SG_DISABLE, - SG_SENSE_NO_ACTIVITY, - SG_SENSE_ACTIVE -}; - -struct acx_bt_wlan_coex { - struct acx_header header; - - /* - * 0 -> PTA enabled - * 1 -> PTA disabled - * 2 -> sense no active mode, i.e. - * an interrupt is sent upon - * BT activity. - * 3 -> PTA is switched on in response - * to the interrupt sending. - */ - u8 enable; - u8 pad[3]; -} __packed; - -#define PTA_ANTENNA_TYPE_DEF (0) -#define PTA_BT_HP_MAXTIME_DEF (2000) -#define PTA_WLAN_HP_MAX_TIME_DEF (5000) -#define PTA_SENSE_DISABLE_TIMER_DEF (1350) -#define PTA_PROTECTIVE_RX_TIME_DEF (1500) -#define PTA_PROTECTIVE_TX_TIME_DEF (1500) -#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) -#define PTA_SIGNALING_TYPE_DEF (1) -#define PTA_AFH_LEVERAGE_ON_DEF (0) -#define PTA_NUMBER_QUIET_CYCLE_DEF (0) -#define PTA_MAX_NUM_CTS_DEF (3) -#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) -#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) -#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) -#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) -#define PTA_CYCLE_TIME_FAST_DEF (8700) -#define PTA_RX_FOR_AVALANCHE_DEF (5) -#define PTA_ELP_HP_DEF (0) -#define PTA_ANTI_STARVE_PERIOD_DEF (500) -#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) -#define PTA_ALLOW_PA_SD_DEF (1) -#define PTA_TIME_BEFORE_BEACON_DEF (6300) -#define PTA_HPDM_MAX_TIME_DEF (1600) -#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) -#define PTA_AUTO_MODE_NO_CTS_DEF (0) -#define PTA_BT_HP_RESPECTED_DEF (3) -#define PTA_WLAN_RX_MIN_RATE_DEF (24) -#define PTA_ACK_MODE_DEF (1) - -struct acx_bt_wlan_coex_param { - struct acx_header header; - - /* - * The minimum rate of a received WLAN packet in the STA, - * during protective mode, of which a new BT-HP request - * during this Rx will always be respected and gain the antenna. - */ - u32 min_rate; - - /* Max time the BT HP will be respected. */ - u16 bt_hp_max_time; - - /* Max time the WLAN HP will be respected. */ - u16 wlan_hp_max_time; - - /* - * The time between the last BT activity - * and the moment when the sense mode returns - * to SENSE_INACTIVE. - */ - u16 sense_disable_timer; - - /* Time before the next BT HP instance */ - u16 rx_time_bt_hp; - u16 tx_time_bt_hp; - - /* range: 10-20000 default: 1500 */ - u16 rx_time_bt_hp_fast; - u16 tx_time_bt_hp_fast; - - /* range: 2000-65535 default: 8700 */ - u16 wlan_cycle_fast; - - /* range: 0 - 15000 (Msec) default: 1000 */ - u16 bt_anti_starvation_period; - - /* range 400-10000(Usec) default: 3000 */ - u16 next_bt_lp_packet; - - /* Deafult: worst case for BT DH5 traffic */ - u16 wake_up_beacon; - - /* range: 0-50000(Usec) default: 1050 */ - u16 hp_dm_max_guard_time; - - /* - * This is to prevent both BT & WLAN antenna - * starvation. - * Range: 100-50000(Usec) default:2550 - */ - u16 next_wlan_packet; - - /* 0 -> shared antenna */ - u8 antenna_type; - - /* - * 0 -> TI legacy - * 1 -> Palau - */ - u8 signal_type; - - /* - * BT AFH status - * 0 -> no AFH - * 1 -> from dedicated GPIO - * 2 -> AFH on (from host) - */ - u8 afh_leverage_on; - - /* - * The number of cycles during which no - * TX will be sent after 1 cycle of RX - * transaction in protective mode - */ - u8 quiet_cycle_num; - - /* - * The maximum number of CTSs that will - * be sent for receiving RX packet in - * protective mode - */ - u8 max_cts; - - /* - * The number of WLAN packets - * transferred in common mode before - * switching to BT. - */ - u8 wlan_packets_num; - - /* - * The number of BT packets - * transferred in common mode before - * switching to WLAN. - */ - u8 bt_packets_num; - - /* range: 1-255 default: 5 */ - u8 missed_rx_avalanche; - - /* range: 0-1 default: 1 */ - u8 wlan_elp_hp; - - /* range: 0 - 15 default: 4 */ - u8 bt_anti_starvation_cycles; - - u8 ack_mode_dual_ant; - - /* - * Allow PA_SD assertion/de-assertion - * during enabled BT activity. - */ - u8 pa_sd_enable; - - /* - * Enable/Disable PTA in auto mode: - * Support Both Active & P.S modes - */ - u8 pta_auto_mode_enable; - - /* range: 0 - 20 default: 1 */ - u8 bt_hp_respected_num; -} __packed; - -#define CCA_THRSH_ENABLE_ENERGY_D 0x140A -#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF - -struct acx_energy_detection { - struct acx_header header; - - /* The RX Clear Channel Assessment threshold in the PHY */ - u16 rx_cca_threshold; - u8 tx_energy_detection; - u8 pad; -} __packed; - -#define BCN_RX_TIMEOUT_DEF_VALUE 10000 -#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 -#define RX_BROADCAST_IN_PS_DEF_VALUE 1 -#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 - -struct acx_beacon_broadcast { - struct acx_header header; - - u16 beacon_rx_timeout; - u16 broadcast_timeout; - - /* Enables receiving of broadcast packets in PS mode */ - u8 rx_broadcast_in_ps; - - /* Consecutive PS Poll failures before updating the host */ - u8 ps_poll_threshold; - u8 pad[2]; -} __packed; - -struct acx_event_mask { - struct acx_header header; - - u32 event_mask; - u32 high_event_mask; /* Unused */ -} __packed; - -#define CFG_RX_FCS BIT(2) -#define CFG_RX_ALL_GOOD BIT(3) -#define CFG_UNI_FILTER_EN BIT(4) -#define CFG_BSSID_FILTER_EN BIT(5) -#define CFG_MC_FILTER_EN BIT(6) -#define CFG_MC_ADDR0_EN BIT(7) -#define CFG_MC_ADDR1_EN BIT(8) -#define CFG_BC_REJECT_EN BIT(9) -#define CFG_SSID_FILTER_EN BIT(10) -#define CFG_RX_INT_FCS_ERROR BIT(11) -#define CFG_RX_INT_ENCRYPTED BIT(12) -#define CFG_RX_WR_RX_STATUS BIT(13) -#define CFG_RX_FILTER_NULTI BIT(14) -#define CFG_RX_RESERVE BIT(15) -#define CFG_RX_TIMESTAMP_TSF BIT(16) - -#define CFG_RX_RSV_EN BIT(0) -#define CFG_RX_RCTS_ACK BIT(1) -#define CFG_RX_PRSP_EN BIT(2) -#define CFG_RX_PREQ_EN BIT(3) -#define CFG_RX_MGMT_EN BIT(4) -#define CFG_RX_FCS_ERROR BIT(5) -#define CFG_RX_DATA_EN BIT(6) -#define CFG_RX_CTL_EN BIT(7) -#define CFG_RX_CF_EN BIT(8) -#define CFG_RX_BCN_EN BIT(9) -#define CFG_RX_AUTH_EN BIT(10) -#define CFG_RX_ASSOC_EN BIT(11) - -#define SCAN_PASSIVE BIT(0) -#define SCAN_5GHZ_BAND BIT(1) -#define SCAN_TRIGGERED BIT(2) -#define SCAN_PRIORITY_HIGH BIT(3) - -struct acx_fw_gen_frame_rates { - struct acx_header header; - - u8 tx_ctrl_frame_rate; /* RATE_* */ - u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ - u8 tx_mgt_frame_rate; - u8 tx_mgt_frame_mod; -} __packed; - -/* STA MAC */ -struct acx_dot11_station_id { - struct acx_header header; - - u8 mac[ETH_ALEN]; - u8 pad[2]; -} __packed; - -struct acx_feature_config { - struct acx_header header; - - u32 options; - u32 data_flow_options; -} __packed; - -struct acx_current_tx_power { - struct acx_header header; - - u8 current_tx_power; - u8 padding[3]; -} __packed; - -struct acx_dot11_default_key { - struct acx_header header; - - u8 id; - u8 pad[3]; -} __packed; - -struct acx_tsf_info { - struct acx_header header; - - u32 current_tsf_msb; - u32 current_tsf_lsb; - u32 last_TBTT_msb; - u32 last_TBTT_lsb; - u8 last_dtim_count; - u8 pad[3]; -} __packed; - -enum acx_wake_up_event { - WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ - WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ - WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ - WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ - WAKE_UP_EVENT_BITS_MASK = 0x0F -}; - -struct acx_wake_up_condition { - struct acx_header header; - - u8 wake_up_event; /* Only one bit can be set */ - u8 listen_interval; - u8 pad[2]; -} __packed; - -struct acx_aid { - struct acx_header header; - - /* - * To be set when associated with an AP. - */ - u16 aid; - u8 pad[2]; -} __packed; - -enum acx_preamble_type { - ACX_PREAMBLE_LONG = 0, - ACX_PREAMBLE_SHORT = 1 -}; - -struct acx_preamble { - struct acx_header header; - - /* - * When set, the WiLink transmits the frames with a short preamble and - * when cleared, the WiLink transmits the frames with a long preamble. - */ - u8 preamble; - u8 padding[3]; -} __packed; - -enum acx_ctsprotect_type { - CTSPROTECT_DISABLE = 0, - CTSPROTECT_ENABLE = 1 -}; - -struct acx_ctsprotect { - struct acx_header header; - u8 ctsprotect; - u8 padding[3]; -} __packed; - -struct acx_tx_statistics { - u32 internal_desc_overflow; -} __packed; - -struct acx_rx_statistics { - u32 out_of_mem; - u32 hdr_overflow; - u32 hw_stuck; - u32 dropped; - u32 fcs_err; - u32 xfr_hint_trig; - u32 path_reset; - u32 reset_counter; -} __packed; - -struct acx_dma_statistics { - u32 rx_requested; - u32 rx_errors; - u32 tx_requested; - u32 tx_errors; -} __packed; - -struct acx_isr_statistics { - /* host command complete */ - u32 cmd_cmplt; - - /* fiqisr() */ - u32 fiqs; - - /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ - u32 rx_headers; - - /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ - u32 rx_completes; - - /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ - u32 rx_mem_overflow; - - /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ - u32 rx_rdys; - - /* irqisr() */ - u32 irqs; - - /* (INT_STS_ND & INT_TRIG_TX_PROC) */ - u32 tx_procs; - - /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ - u32 decrypt_done; - - /* (INT_STS_ND & INT_TRIG_DMA0) */ - u32 dma0_done; - - /* (INT_STS_ND & INT_TRIG_DMA1) */ - u32 dma1_done; - - /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ - u32 tx_exch_complete; - - /* (INT_STS_ND & INT_TRIG_COMMAND) */ - u32 commands; - - /* (INT_STS_ND & INT_TRIG_RX_PROC) */ - u32 rx_procs; - - /* (INT_STS_ND & INT_TRIG_PM_802) */ - u32 hw_pm_mode_changes; - - /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ - u32 host_acknowledges; - - /* (INT_STS_ND & INT_TRIG_PM_PCI) */ - u32 pci_pm; - - /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ - u32 wakeups; - - /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ - u32 low_rssi; -} __packed; - -struct acx_wep_statistics { - /* WEP address keys configured */ - u32 addr_key_count; - - /* default keys configured */ - u32 default_key_count; - - u32 reserved; - - /* number of times that WEP key not found on lookup */ - u32 key_not_found; - - /* number of times that WEP key decryption failed */ - u32 decrypt_fail; - - /* WEP packets decrypted */ - u32 packets; - - /* WEP decrypt interrupts */ - u32 interrupt; -} __packed; - -#define ACX_MISSED_BEACONS_SPREAD 10 - -struct acx_pwr_statistics { - /* the amount of enters into power save mode (both PD & ELP) */ - u32 ps_enter; - - /* the amount of enters into ELP mode */ - u32 elp_enter; - - /* the amount of missing beacon interrupts to the host */ - u32 missing_bcns; - - /* the amount of wake on host-access times */ - u32 wake_on_host; - - /* the amount of wake on timer-expire */ - u32 wake_on_timer_exp; - - /* the number of packets that were transmitted with PS bit set */ - u32 tx_with_ps; - - /* the number of packets that were transmitted with PS bit clear */ - u32 tx_without_ps; - - /* the number of received beacons */ - u32 rcvd_beacons; - - /* the number of entering into PowerOn (power save off) */ - u32 power_save_off; - - /* the number of entries into power save mode */ - u16 enable_ps; - - /* - * the number of exits from power save, not including failed PS - * transitions - */ - u16 disable_ps; - - /* - * the number of times the TSF counter was adjusted because - * of drift - */ - u32 fix_tsf_ps; - - /* Gives statistics about the spread continuous missed beacons. - * The 16 LSB are dedicated for the PS mode. - * The 16 MSB are dedicated for the PS mode. - * cont_miss_bcns_spread[0] - single missed beacon. - * cont_miss_bcns_spread[1] - two continuous missed beacons. - * cont_miss_bcns_spread[2] - three continuous missed beacons. - * ... - * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. - */ - u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; - - /* the number of beacons in awake mode */ - u32 rcvd_awake_beacons; -} __packed; - -struct acx_mic_statistics { - u32 rx_pkts; - u32 calc_failure; -} __packed; - -struct acx_aes_statistics { - u32 encrypt_fail; - u32 decrypt_fail; - u32 encrypt_packets; - u32 decrypt_packets; - u32 encrypt_interrupt; - u32 decrypt_interrupt; -} __packed; - -struct acx_event_statistics { - u32 heart_beat; - u32 calibration; - u32 rx_mismatch; - u32 rx_mem_empty; - u32 rx_pool; - u32 oom_late; - u32 phy_transmit_error; - u32 tx_stuck; -} __packed; - -struct acx_ps_statistics { - u32 pspoll_timeouts; - u32 upsd_timeouts; - u32 upsd_max_sptime; - u32 upsd_max_apturn; - u32 pspoll_max_apturn; - u32 pspoll_utilization; - u32 upsd_utilization; -} __packed; - -struct acx_rxpipe_statistics { - u32 rx_prep_beacon_drop; - u32 descr_host_int_trig_rx_data; - u32 beacon_buffer_thres_host_int_trig_rx_data; - u32 missed_beacon_host_int_trig_rx_data; - u32 tx_xfr_host_int_trig_rx_data; -} __packed; - -struct acx_statistics { - struct acx_header header; - - struct acx_tx_statistics tx; - struct acx_rx_statistics rx; - struct acx_dma_statistics dma; - struct acx_isr_statistics isr; - struct acx_wep_statistics wep; - struct acx_pwr_statistics pwr; - struct acx_aes_statistics aes; - struct acx_mic_statistics mic; - struct acx_event_statistics event; - struct acx_ps_statistics ps; - struct acx_rxpipe_statistics rxpipe; -} __packed; - -#define ACX_MAX_RATE_CLASSES 8 -#define ACX_RATE_MASK_UNSPECIFIED 0 -#define ACX_RATE_RETRY_LIMIT 10 - -struct acx_rate_class { - u32 enabled_rates; - u8 short_retry_limit; - u8 long_retry_limit; - u8 aflags; - u8 reserved; -}; - -struct acx_rate_policy { - struct acx_header header; - - u32 rate_class_cnt; - struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; -} __packed; - -struct wl1251_acx_memory { - __le16 num_stations; /* number of STAs to be supported. */ - u16 reserved_1; - - /* - * Nmber of memory buffers for the RX mem pool. - * The actual number may be less if there are - * not enough blocks left for the minimum num - * of TX ones. - */ - u8 rx_mem_block_num; - u8 reserved_2; - u8 num_tx_queues; /* From 1 to 16 */ - u8 host_if_options; /* HOST_IF* */ - u8 tx_min_mem_block_num; - u8 num_ssid_profiles; - __le16 debug_buffer_size; -} __packed; - - -#define ACX_RX_DESC_MIN 1 -#define ACX_RX_DESC_MAX 127 -#define ACX_RX_DESC_DEF 32 -struct wl1251_acx_rx_queue_config { - u8 num_descs; - u8 pad; - u8 type; - u8 priority; - __le32 dma_address; -} __packed; - -#define ACX_TX_DESC_MIN 1 -#define ACX_TX_DESC_MAX 127 -#define ACX_TX_DESC_DEF 16 -struct wl1251_acx_tx_queue_config { - u8 num_descs; - u8 pad[2]; - u8 attributes; -} __packed; - -#define MAX_TX_QUEUE_CONFIGS 5 -#define MAX_TX_QUEUES 4 -struct wl1251_acx_config_memory { - struct acx_header header; - - struct wl1251_acx_memory mem_config; - struct wl1251_acx_rx_queue_config rx_queue_config; - struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; -} __packed; - -struct wl1251_acx_mem_map { - struct acx_header header; - - void *code_start; - void *code_end; - - void *wep_defkey_start; - void *wep_defkey_end; - - void *sta_table_start; - void *sta_table_end; - - void *packet_template_start; - void *packet_template_end; - - void *queue_memory_start; - void *queue_memory_end; - - void *packet_memory_pool_start; - void *packet_memory_pool_end; - - void *debug_buffer1_start; - void *debug_buffer1_end; - - void *debug_buffer2_start; - void *debug_buffer2_end; - - /* Number of blocks FW allocated for TX packets */ - u32 num_tx_mem_blocks; - - /* Number of blocks FW allocated for RX packets */ - u32 num_rx_mem_blocks; -} __packed; - - -struct wl1251_acx_wr_tbtt_and_dtim { - - struct acx_header header; - - /* Time in TUs between two consecutive beacons */ - u16 tbtt; - - /* - * DTIM period - * For BSS: Number of TBTTs in a DTIM period (range: 1-10) - * For IBSS: value shall be set to 1 - */ - u8 dtim; - u8 padding; -} __packed; - -struct wl1251_acx_ac_cfg { - struct acx_header header; - - /* - * Access Category - The TX queue's access category - * (refer to AccessCategory_enum) - */ - u8 ac; - - /* - * The contention window minimum size (in slots) for - * the access class. - */ - u8 cw_min; - - /* - * The contention window maximum size (in slots) for - * the access class. - */ - u16 cw_max; - - /* The AIF value (in slots) for the access class. */ - u8 aifsn; - - u8 reserved; - - /* The TX Op Limit (in microseconds) for the access class. */ - u16 txop_limit; -} __packed; - - -enum wl1251_acx_channel_type { - CHANNEL_TYPE_DCF = 0, - CHANNEL_TYPE_EDCF = 1, - CHANNEL_TYPE_HCCA = 2, -}; - -enum wl1251_acx_ps_scheme { - /* regular ps: simple sending of packets */ - WL1251_ACX_PS_SCHEME_LEGACY = 0, - - /* sending a packet triggers a unscheduled apsd downstream */ - WL1251_ACX_PS_SCHEME_UPSD_TRIGGER = 1, - - /* a pspoll packet will be sent before every data packet */ - WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, - - /* scheduled apsd mode */ - WL1251_ACX_PS_SCHEME_SAPSD = 3, -}; - -enum wl1251_acx_ack_policy { - WL1251_ACX_ACK_POLICY_LEGACY = 0, - WL1251_ACX_ACK_POLICY_NO_ACK = 1, - WL1251_ACX_ACK_POLICY_BLOCK = 2, -}; - -struct wl1251_acx_tid_cfg { - struct acx_header header; - - /* tx queue id number (0-7) */ - u8 queue; - - /* channel access type for the queue, enum wl1251_acx_channel_type */ - u8 type; - - /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */ - u8 tsid; - - /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */ - u8 ps_scheme; - - /* the tx queue ack policy, enum wl1251_acx_ack_policy */ - u8 ack_policy; - - u8 padding[3]; - - /* not supported */ - u32 apsdconf[2]; -} __packed; - -/************************************************************************* - - Host Interrupt Register (WiLink -> Host) - -**************************************************************************/ - -/* RX packet is ready in Xfer buffer #0 */ -#define WL1251_ACX_INTR_RX0_DATA BIT(0) - -/* TX result(s) are in the TX complete buffer */ -#define WL1251_ACX_INTR_TX_RESULT BIT(1) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_TX_XFR BIT(2) - -/* RX packet is ready in Xfer buffer #1 */ -#define WL1251_ACX_INTR_RX1_DATA BIT(3) - -/* Event was entered to Event MBOX #A */ -#define WL1251_ACX_INTR_EVENT_A BIT(4) - -/* Event was entered to Event MBOX #B */ -#define WL1251_ACX_INTR_EVENT_B BIT(5) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) - -/* Trace meassge on MBOX #A */ -#define WL1251_ACX_INTR_TRACE_A BIT(7) - -/* Trace meassge on MBOX #B */ -#define WL1251_ACX_INTR_TRACE_B BIT(8) - -/* Command processing completion */ -#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) - -/* Init sequence is done */ -#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) - -#define WL1251_ACX_INTR_ALL 0xFFFFFFFF - -enum { - ACX_WAKE_UP_CONDITIONS = 0x0002, - ACX_MEM_CFG = 0x0003, - ACX_SLOT = 0x0004, - ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ - ACX_AC_CFG = 0x0007, - ACX_MEM_MAP = 0x0008, - ACX_AID = 0x000A, - ACX_RADIO_PARAM = 0x000B, /* Not used */ - ACX_CFG = 0x000C, /* Not used */ - ACX_FW_REV = 0x000D, - ACX_MEDIUM_USAGE = 0x000F, - ACX_RX_CFG = 0x0010, - ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ - ACX_BSS_IN_PS = 0x0012, /* for AP only */ - ACX_STATISTICS = 0x0013, /* Debug API */ - ACX_FEATURE_CFG = 0x0015, - ACX_MISC_CFG = 0x0017, /* Not used */ - ACX_TID_CFG = 0x001A, - ACX_BEACON_FILTER_OPT = 0x001F, - ACX_LOW_RSSI = 0x0020, - ACX_NOISE_HIST = 0x0021, - ACX_HDK_VERSION = 0x0022, /* ??? */ - ACX_PD_THRESHOLD = 0x0023, - ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ - ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ - ACX_CCA_THRESHOLD = 0x0025, - ACX_EVENT_MBOX_MASK = 0x0026, -#ifdef FW_RUNNING_AS_AP - ACX_DTIM_PERIOD = 0x0027, /* for AP only */ -#else - ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ -#endif - ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ - ACX_GPIO_CFG = 0x002A, /* Not used */ - ACX_GPIO_SET = 0x002B, /* Not used */ - ACX_PM_CFG = 0x002C, /* To Be Documented */ - ACX_CONN_MONIT_PARAMS = 0x002D, - ACX_AVERAGE_RSSI = 0x002E, /* Not used */ - ACX_CONS_TX_FAILURE = 0x002F, - ACX_BCN_DTIM_OPTIONS = 0x0031, - ACX_SG_ENABLE = 0x0032, - ACX_SG_CFG = 0x0033, - ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ - ACX_LOW_SNR = 0x0037, /* To Be Documented */ - ACX_BEACON_FILTER_TABLE = 0x0038, - ACX_ARP_IP_FILTER = 0x0039, - ACX_ROAMING_STATISTICS_TBL = 0x003B, - ACX_RATE_POLICY = 0x003D, - ACX_CTS_PROTECTION = 0x003E, - ACX_SLEEP_AUTH = 0x003F, - ACX_PREAMBLE_TYPE = 0x0040, - ACX_ERROR_CNT = 0x0041, - ACX_FW_GEN_FRAME_RATES = 0x0042, - ACX_IBSS_FILTER = 0x0044, - ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, - ACX_TSF_INFO = 0x0046, - ACX_CONFIG_PS_WMM = 0x0049, - ACX_ENABLE_RX_DATA_FILTER = 0x004A, - ACX_SET_RX_DATA_FILTER = 0x004B, - ACX_GET_DATA_FILTER_STATISTICS = 0x004C, - ACX_POWER_LEVEL_TABLE = 0x004D, - ACX_BET_ENABLE = 0x0050, - DOT11_STATION_ID = 0x1001, - DOT11_RX_MSDU_LIFE_TIME = 0x1004, - DOT11_CUR_TX_PWR = 0x100D, - DOT11_DEFAULT_KEY = 0x1010, - DOT11_RX_DOT11_MODE = 0x1012, - DOT11_RTS_THRESHOLD = 0x1013, - DOT11_GROUP_ADDRESS_TBL = 0x1014, - - MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, - - MAX_IE = 0xFFFF -}; - - -int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, - u8 mgt_rate, u8 mgt_mod); -int wl1251_acx_station_id(struct wl1251 *wl); -int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id); -int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, - u8 listen_interval); -int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth); -int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len); -int wl1251_acx_tx_power(struct wl1251 *wl, int power); -int wl1251_acx_feature_cfg(struct wl1251 *wl); -int wl1251_acx_mem_map(struct wl1251 *wl, - struct acx_header *mem_map, size_t len); -int wl1251_acx_data_path_params(struct wl1251 *wl, - struct acx_data_path_params_resp *data_path); -int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); -int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); -int wl1251_acx_pd_threshold(struct wl1251 *wl); -int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); -int wl1251_acx_group_address_tbl(struct wl1251 *wl); -int wl1251_acx_service_period_timeout(struct wl1251 *wl); -int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); -int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); -int wl1251_acx_beacon_filter_table(struct wl1251 *wl); -int wl1251_acx_conn_monit_params(struct wl1251 *wl); -int wl1251_acx_sg_enable(struct wl1251 *wl); -int wl1251_acx_sg_cfg(struct wl1251 *wl); -int wl1251_acx_cca_threshold(struct wl1251 *wl); -int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); -int wl1251_acx_aid(struct wl1251 *wl, u16 aid); -int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); -int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); -int wl1251_acx_cts_protect(struct wl1251 *wl, - enum acx_ctsprotect_type ctsprotect); -int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); -int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); -int wl1251_acx_rate_policies(struct wl1251 *wl); -int wl1251_acx_mem_cfg(struct wl1251 *wl); -int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); -int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, - u8 aifs, u16 txop); -int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, - enum wl1251_acx_channel_type type, - u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, - enum wl1251_acx_ack_policy ack_policy); - -#endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c deleted file mode 100644 index 65e0416be5b..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/gpio.h> -#include <linux/slab.h> - -#include "wl1251_reg.h" -#include "wl1251_boot.h" -#include "wl1251_io.h" -#include "wl1251_spi.h" -#include "wl1251_event.h" -#include "wl1251_acx.h" - -void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) -{ - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); -} - -int wl1251_boot_soft_reset(struct wl1251 *wl) -{ - unsigned long timeout; - u32 boot_data; - - /* perform soft reset */ - wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); - - /* SOFT_RESET is self clearing */ - timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); - while (1) { - boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); - wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); - if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) - break; - - if (time_after(jiffies, timeout)) { - /* 1.2 check pWhalBus->uSelfClearTime if the - * timeout was reached */ - wl1251_error("soft reset timeout"); - return -1; - } - - udelay(SOFT_RESET_STALL_TIME); - } - - /* disable Rx/Tx */ - wl1251_reg_write32(wl, ENABLE, 0x0); - - /* disable auto calibration on start*/ - wl1251_reg_write32(wl, SPARE_A2, 0xffff); - - return 0; -} - -int wl1251_boot_init_seq(struct wl1251 *wl) -{ - u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; - - /* - * col #1: INTEGER_DIVIDER - * col #2: FRACTIONAL_DIVIDER - * col #3: ATTN_BB - * col #4: ALPHA_BB - * col #5: STOP_TIME_BB - * col #6: BB_PLL_LOOP_FILTER - */ - static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { - - { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ - { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ - { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ - { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ - { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ - }; - - /* read NVS params */ - scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6); - wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); - - /* read ELP_CMD */ - elp_cmd = wl1251_reg_read32(wl, ELP_CMD); - wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); - - /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ - ref_freq = scr_pad6 & 0x000000FF; - wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); - - wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9); - - /* - * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) - */ - wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6); - - /* - * set the clock detect feature to work in the restart wu procedure - * (ELP_CFG_MODE[14]) and Select the clock source type - * (ELP_CFG_MODE[13:12]) - */ - tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; - wl1251_reg_write32(wl, ELP_CFG_MODE, tmp); - - /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ - elp_cmd |= 0x00000040; - wl1251_reg_write32(wl, ELP_CMD, elp_cmd); - - /* PG 1.2: Set the BB PLL stable time to be 1000usec - * (PLL_STABLE_TIME) */ - wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); - - /* PG 1.2: read clock request time */ - init_data = wl1251_reg_read32(wl, CLK_REQ_TIME); - - /* - * PG 1.2: set the clock request time to be ref_clk_settling_time - - * 1ms = 4ms - */ - if (init_data > 0x21) - tmp = init_data - 0x21; - else - tmp = 0; - wl1251_reg_write32(wl, CLK_REQ_TIME, tmp); - - /* set BB PLL configurations in RF AFE */ - wl1251_reg_write32(wl, 0x003058cc, 0x4B5); - - /* set RF_AFE_REG_5 */ - wl1251_reg_write32(wl, 0x003058d4, 0x50); - - /* set RF_AFE_CTRL_REG_2 */ - wl1251_reg_write32(wl, 0x00305948, 0x11c001); - - /* - * change RF PLL and BB PLL divider for VCO clock and adjust VCO - * bais current(RF_AFE_REG_13) - */ - wl1251_reg_write32(wl, 0x003058f4, 0x1e); - - /* set BB PLL configurations */ - tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; - wl1251_reg_write32(wl, 0x00305840, tmp); - - /* set fractional divider according to Appendix C-BB PLL - * Calculations - */ - tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; - wl1251_reg_write32(wl, 0x00305844, tmp); - - /* set the initial data for the sigma delta */ - wl1251_reg_write32(wl, 0x00305848, 0x3039); - - /* - * set the accumulator attenuation value, calibration loop1 - * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and - * the VCO gain - */ - tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | - (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; - wl1251_reg_write32(wl, 0x00305854, tmp); - - /* - * set the calibration stop time after holdoff time expires and set - * settling time HOLD_OFF_TIME_BB - */ - tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; - wl1251_reg_write32(wl, 0x00305858, tmp); - - /* - * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL - * constant leakage current to linearize PFD to 0uA - - * BB_ILOOPF[7:3] - */ - tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; - wl1251_reg_write32(wl, 0x003058f8, tmp); - - /* - * set regulator output voltage for n divider to - * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], - * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB - * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] - */ - wl1251_reg_write32(wl, 0x003058f0, 0x29); - - /* enable restart wakeup sequence (ELP_CMD[0]) */ - wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); - - /* restart sequence completed */ - udelay(2000); - - return 0; -} - -static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) -{ - u32 cpu_ctrl; - - /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - /* 10.5.1 run the firmware (II) */ - cpu_ctrl &= ~flag; - wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); -} - -int wl1251_boot_run_firmware(struct wl1251 *wl) -{ - int loop, ret; - u32 chip_id, acx_intr; - - wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - - chip_id = wl1251_reg_read32(wl, CHIP_ID_B); - - wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); - - if (chip_id != wl->chip_id) { - wl1251_error("chip id doesn't match after firmware boot"); - return -EIO; - } - - /* wait for init to complete */ - loop = 0; - while (loop++ < INIT_LOOP) { - udelay(INIT_LOOP_DELAY); - acx_intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - - if (acx_intr == 0xffffffff) { - wl1251_error("error reading hardware complete " - "init indication"); - return -EIO; - } - /* check that ACX_INTR_INIT_COMPLETE is enabled */ - else if (acx_intr & WL1251_ACX_INTR_INIT_COMPLETE) { - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1251_ACX_INTR_INIT_COMPLETE); - break; - } - } - - if (loop > INIT_LOOP) { - wl1251_error("timeout waiting for the hardware to " - "complete initialization"); - return -EIO; - } - - /* get hardware config command mail box */ - wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); - - /* get hardware config event mail box */ - wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); - - /* set the working partition to its "running" mode offset */ - wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START, - WL1251_PART_WORK_MEM_SIZE, - WL1251_PART_WORK_REG_START, - WL1251_PART_WORK_REG_SIZE); - - wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", - wl->cmd_box_addr, wl->event_box_addr); - - wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver)); - - /* - * in case of full asynchronous mode the firmware event must be - * ready to receive event from the command mailbox - */ - - /* enable gpio interrupts */ - wl1251_enable_interrupts(wl); - - /* Enable target's interrupts */ - wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | - WL1251_ACX_INTR_RX1_DATA | - WL1251_ACX_INTR_TX_RESULT | - WL1251_ACX_INTR_EVENT_A | - WL1251_ACX_INTR_EVENT_B | - WL1251_ACX_INTR_INIT_COMPLETE; - wl1251_boot_target_enable_interrupts(wl); - - wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID | - SYNCHRONIZATION_TIMEOUT_EVENT_ID | - ROAMING_TRIGGER_LOW_RSSI_EVENT_ID | - ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID | - REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID | - BT_PTA_PREDICTION_EVENT_ID; - - ret = wl1251_event_unmask(wl); - if (ret < 0) { - wl1251_error("EVENT mask setting failed"); - return ret; - } - - wl1251_event_mbox_config(wl); - - /* firmware startup completed */ - return 0; -} - -static int wl1251_boot_upload_firmware(struct wl1251 *wl) -{ - int addr, chunk_num, partition_limit; - size_t fw_data_len, len; - u8 *p, *buf; - - /* whal_FwCtrl_LoadFwImageSm() */ - - wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", - wl1251_reg_read32(wl, CHIP_ID_B)); - - /* 10.0 check firmware length and set partition */ - fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | - (wl->fw[6] << 8) | (wl->fw[7]); - - wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, - CHUNK_SIZE); - - if ((fw_data_len % 4) != 0) { - wl1251_error("firmware length not multiple of four"); - return -EIO; - } - - buf = kmalloc(CHUNK_SIZE, GFP_KERNEL); - if (!buf) { - wl1251_error("allocation for firmware upload chunk failed"); - return -ENOMEM; - } - - wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, - WL1251_PART_DOWN_MEM_SIZE, - WL1251_PART_DOWN_REG_START, - WL1251_PART_DOWN_REG_SIZE); - - /* 10.1 set partition limit and chunk num */ - chunk_num = 0; - partition_limit = WL1251_PART_DOWN_MEM_SIZE; - - while (chunk_num < fw_data_len / CHUNK_SIZE) { - /* 10.2 update partition, if needed */ - addr = WL1251_PART_DOWN_MEM_START + - (chunk_num + 2) * CHUNK_SIZE; - if (addr > partition_limit) { - addr = WL1251_PART_DOWN_MEM_START + - chunk_num * CHUNK_SIZE; - partition_limit = chunk_num * CHUNK_SIZE + - WL1251_PART_DOWN_MEM_SIZE; - wl1251_set_partition(wl, - addr, - WL1251_PART_DOWN_MEM_SIZE, - WL1251_PART_DOWN_REG_START, - WL1251_PART_DOWN_REG_SIZE); - } - - /* 10.3 upload the chunk */ - addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", - p, addr); - - /* need to copy the chunk for dma */ - len = CHUNK_SIZE; - memcpy(buf, p, len); - wl1251_mem_write(wl, addr, buf, len); - - chunk_num++; - } - - /* 10.4 upload the last chunk */ - addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - - /* need to copy the chunk for dma */ - len = fw_data_len % CHUNK_SIZE; - memcpy(buf, p, len); - - wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", - len, p, addr); - wl1251_mem_write(wl, addr, buf, len); - - kfree(buf); - - return 0; -} - -static int wl1251_boot_upload_nvs(struct wl1251 *wl) -{ - size_t nvs_len, nvs_bytes_written, burst_len; - int nvs_start, i; - u32 dest_addr, val; - u8 *nvs_ptr, *nvs; - - nvs = wl->nvs; - if (nvs == NULL) - return -ENODEV; - - nvs_ptr = nvs; - - nvs_len = wl->nvs_len; - nvs_start = wl->fw_len; - - /* - * Layout before the actual NVS tables: - * 1 byte : burst length. - * 2 bytes: destination address. - * n bytes: data to burst copy. - * - * This is ended by a 0 length, then the NVS tables. - */ - - while (nvs_ptr[0]) { - burst_len = nvs_ptr[0]; - dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - - /* We move our pointer to the data */ - nvs_ptr += 3; - - for (i = 0; i < burst_len; i++) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - wl1251_debug(DEBUG_BOOT, - "nvs burst write 0x%x: 0x%x", - dest_addr, val); - wl1251_mem_write32(wl, dest_addr, val); - - nvs_ptr += 4; - dest_addr += 4; - } - } - - /* - * We've reached the first zero length, the first NVS table - * is 7 bytes further. - */ - nvs_ptr += 7; - nvs_len -= nvs_ptr - nvs; - nvs_len = ALIGN(nvs_len, 4); - - /* Now we must set the partition correctly */ - wl1251_set_partition(wl, nvs_start, - WL1251_PART_DOWN_MEM_SIZE, - WL1251_PART_DOWN_REG_START, - WL1251_PART_DOWN_REG_SIZE); - - /* And finally we upload the NVS tables */ - nvs_bytes_written = 0; - while (nvs_bytes_written < nvs_len) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - val = cpu_to_le32(val); - - wl1251_debug(DEBUG_BOOT, - "nvs write table 0x%x: 0x%x", - nvs_start, val); - wl1251_mem_write32(wl, nvs_start, val); - - nvs_ptr += 4; - nvs_bytes_written += 4; - nvs_start += 4; - } - - return 0; -} - -int wl1251_boot(struct wl1251 *wl) -{ - int ret = 0, minor_minor_e2_ver; - u32 tmp, boot_data; - - /* halt embedded ARM CPU while loading firmware */ - wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT); - - ret = wl1251_boot_soft_reset(wl); - if (ret < 0) - goto out; - - /* 2. start processing NVS file */ - if (wl->use_eeprom) { - wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR); - /* Wait for EEPROM NVS burst read to complete */ - msleep(40); - wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM); - } else { - ret = wl1251_boot_upload_nvs(wl); - if (ret < 0) - goto out; - - /* write firmware's last address (ie. it's length) to - * ACX_EEPROMLESS_IND_REG */ - wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); - } - - /* 6. read the EEPROM parameters */ - tmp = wl1251_reg_read32(wl, SCR_PAD2); - - /* 7. read bootdata */ - wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; - wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; - tmp = wl1251_reg_read32(wl, SCR_PAD3); - - /* 8. check bootdata and call restart sequence */ - wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; - minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; - - wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " - "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", - wl->boot_attr.radio_type, wl->boot_attr.major, - wl->boot_attr.minor, minor_minor_e2_ver); - - ret = wl1251_boot_init_seq(wl); - if (ret < 0) - goto out; - - /* 9. NVS processing done */ - boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); - - /* 10. check that ECPU_CONTROL_HALT bits are set in - * pWhalBus->uBootData and start uploading firmware - */ - if ((boot_data & ECPU_CONTROL_HALT) == 0) { - wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); - ret = -EIO; - goto out; - } - - ret = wl1251_boot_upload_firmware(wl); - if (ret < 0) - goto out; - - /* 10.5 start firmware */ - ret = wl1251_boot_run_firmware(wl); - if (ret < 0) - goto out; - -out: - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h deleted file mode 100644 index 90063697e8f..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __BOOT_H__ -#define __BOOT_H__ - -#include "wl1251.h" - -int wl1251_boot_soft_reset(struct wl1251 *wl); -int wl1251_boot_init_seq(struct wl1251 *wl); -int wl1251_boot_run_firmware(struct wl1251 *wl); -void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); -int wl1251_boot(struct wl1251 *wl); - -/* number of times we try to read the INIT interrupt */ -#define INIT_LOOP 20000 - -/* delay between retries */ -#define INIT_LOOP_DELAY 50 - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c deleted file mode 100644 index ce3722f4c3e..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ /dev/null @@ -1,496 +0,0 @@ -#include "wl1251_cmd.h" - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/crc7.h> - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_ps.h" -#include "wl1251_acx.h" - -/** - * send command to firmware - * - * @wl: wl struct - * @id: command id - * @buf: buffer containing the command, must work with dma - * @len: length of the buffer - */ -int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) -{ - struct wl1251_cmd_header *cmd; - unsigned long timeout; - u32 intr; - int ret = 0; - - cmd = buf; - cmd->id = id; - cmd->status = 0; - - WARN_ON(len % 4 != 0); - - wl1251_mem_write(wl, wl->cmd_box_addr, buf, len); - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); - - timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) { - if (time_after(jiffies, timeout)) { - wl1251_error("command complete timeout"); - ret = -ETIMEDOUT; - goto out; - } - - msleep(1); - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - } - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1251_ACX_INTR_CMD_COMPLETE); - -out: - return ret; -} - -/** - * send test command to firmware - * - * @wl: wl struct - * @buf: buffer containing the command, with all headers, must work with dma - * @len: length of the buffer - * @answer: is answer needed - */ -int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) -{ - int ret; - - wl1251_debug(DEBUG_CMD, "cmd test"); - - ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len); - - if (ret < 0) { - wl1251_warning("TEST command failed"); - return ret; - } - - if (answer) { - struct wl1251_command *cmd_answer; - - /* - * The test command got in, we can read the answer. - * The answer would be a wl1251_command, where the - * parameter array contains the actual answer. - */ - wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); - - cmd_answer = buf; - - if (cmd_answer->header.status != CMD_STATUS_SUCCESS) - wl1251_error("TEST command answer error: %d", - cmd_answer->header.status); - } - - return 0; -} - -/** - * read acx from firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer for the response, including all headers, must work with dma - * @len: lenght of buf - */ -int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl1251_debug(DEBUG_CMD, "cmd interrogate"); - - acx->id = id; - - /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); - - ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_error("INTERROGATE command failed"); - goto out; - } - - /* the interrogate command got in, we can read the answer */ - wl1251_mem_read(wl, wl->cmd_box_addr, buf, len); - - acx = buf; - if (acx->cmd.status != CMD_STATUS_SUCCESS) - wl1251_error("INTERROGATE command error: %d", - acx->cmd.status); - -out: - return ret; -} - -/** - * write acx value to firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer containing acx, including all headers, must work with dma - * @len: length of buf - */ -int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl1251_debug(DEBUG_CMD, "cmd configure"); - - acx->id = id; - - /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); - - ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len); - if (ret < 0) { - wl1251_warning("CONFIGURE command NOK"); - return ret; - } - - return 0; -} - -int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, - void *bitmap, u16 bitmap_len, u8 bitmap_control) -{ - struct wl1251_cmd_vbm_update *vbm; - int ret; - - wl1251_debug(DEBUG_CMD, "cmd vbm"); - - vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); - if (!vbm) { - ret = -ENOMEM; - goto out; - } - - /* Count and period will be filled by the target */ - vbm->tim.bitmap_ctrl = bitmap_control; - if (bitmap_len > PARTIAL_VBM_MAX) { - wl1251_warning("cmd vbm len is %d B, truncating to %d", - bitmap_len, PARTIAL_VBM_MAX); - bitmap_len = PARTIAL_VBM_MAX; - } - memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); - vbm->tim.identity = identity; - vbm->tim.length = bitmap_len + 3; - - vbm->len = cpu_to_le16(bitmap_len + 5); - - ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); - if (ret < 0) { - wl1251_error("VBM command failed"); - goto out; - } - -out: - kfree(vbm); - return 0; -} - -int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) -{ - struct cmd_enabledisable_path *cmd; - int ret; - u16 cmd_rx, cmd_tx; - - wl1251_debug(DEBUG_CMD, "cmd data path"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->channel = channel; - - if (enable) { - cmd_rx = CMD_ENABLE_RX; - cmd_tx = CMD_ENABLE_TX; - } else { - cmd_rx = CMD_DISABLE_RX; - cmd_tx = CMD_DISABLE_TX; - } - - ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("rx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); - goto out; - } - - wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", - enable ? "start" : "stop", channel); - - ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("tx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); - return ret; - } - - wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", - enable ? "start" : "stop", channel); - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, - u16 beacon_interval, u8 dtim_interval) -{ - struct cmd_join *join; - int ret, i; - u8 *bssid; - - join = kzalloc(sizeof(*join), GFP_KERNEL); - if (!join) { - ret = -ENOMEM; - goto out; - } - - wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", - bss_type == BSS_TYPE_IBSS ? " ibss" : "", - channel, beacon_interval, dtim_interval); - - /* Reverse order BSSID */ - bssid = (u8 *) &join->bssid_lsb; - for (i = 0; i < ETH_ALEN; i++) - bssid[i] = wl->bssid[ETH_ALEN - i - 1]; - - join->rx_config_options = wl->rx_config; - join->rx_filter_options = wl->rx_filter; - - /* - * FIXME: disable temporarily all filters because after commit - * 9cef8737 "mac80211: fix managed mode BSSID handling" broke - * association. The filter logic needs to be implemented properly - * and once that is done, this hack can be removed. - */ - join->rx_config_options = 0; - join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; - - join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | - RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; - - join->beacon_interval = beacon_interval; - join->dtim_interval = dtim_interval; - join->bss_type = bss_type; - join->channel = channel; - join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; - - ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); - if (ret < 0) { - wl1251_error("failed to initiate cmd join"); - goto out; - } - -out: - kfree(join); - return ret; -} - -int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) -{ - struct wl1251_cmd_ps_params *ps_params = NULL; - int ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd set ps mode"); - - ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); - if (!ps_params) { - ret = -ENOMEM; - goto out; - } - - ps_params->ps_mode = ps_mode; - ps_params->send_null_data = 1; - ps_params->retries = 5; - ps_params->hang_over_period = 128; - ps_params->null_data_rate = 1; /* 1 Mbps */ - - ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params, - sizeof(*ps_params)); - if (ret < 0) { - wl1251_error("cmd set_ps_mode failed"); - goto out; - } - -out: - kfree(ps_params); - return ret; -} - -int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, - size_t len) -{ - struct cmd_read_write_memory *cmd; - int ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd read memory"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - WARN_ON(len > MAX_READ_SIZE); - len = min_t(size_t, len, MAX_READ_SIZE); - - cmd->addr = addr; - cmd->size = len; - - ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("read memory command failed: %d", ret); - goto out; - } - - /* the read command got in, we can now read the answer */ - wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - - if (cmd->header.status != CMD_STATUS_SUCCESS) - wl1251_error("error in read command result: %d", - cmd->header.status); - - memcpy(answer, cmd->value, len); - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, - void *buf, size_t buf_len) -{ - struct wl1251_cmd_packet_template *cmd; - size_t cmd_len; - int ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id); - - WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE); - buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE); - cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); - - cmd = kzalloc(cmd_len, GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->size = cpu_to_le16(buf_len); - - if (buf) - memcpy(cmd->data, buf, buf_len); - - ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len); - if (ret < 0) { - wl1251_warning("cmd set_template failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, - struct ieee80211_channel *channels[], - unsigned int n_channels, unsigned int n_probes) -{ - struct wl1251_cmd_scan *cmd; - int i, ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd scan"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); - cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | - CFG_RX_MGMT_EN | - CFG_RX_BCN_EN); - cmd->params.scan_options = 0; - cmd->params.num_channels = n_channels; - cmd->params.num_probe_requests = n_probes; - cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ - cmd->params.tid_trigger = 0; - - for (i = 0; i < n_channels; i++) { - cmd->channels[i].min_duration = - cpu_to_le32(WL1251_SCAN_MIN_DURATION); - cmd->channels[i].max_duration = - cpu_to_le32(WL1251_SCAN_MAX_DURATION); - memset(&cmd->channels[i].bssid_lsb, 0xff, 4); - memset(&cmd->channels[i].bssid_msb, 0xff, 2); - cmd->channels[i].early_termination = 0; - cmd->channels[i].tx_power_att = 0; - cmd->channels[i].channel = channels[i]->hw_value; - } - - cmd->params.ssid_len = ssid_len; - if (ssid) - memcpy(cmd->params.ssid, ssid, ssid_len); - - ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("cmd scan failed: %d", ret); - goto out; - } - - wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - - if (cmd->header.status != CMD_STATUS_SUCCESS) { - wl1251_error("cmd scan status wasn't success: %d", - cmd->header.status); - ret = -EIO; - goto out; - } - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) -{ - struct wl1251_cmd_trigger_scan_to *cmd; - int ret; - - wl1251_debug(DEBUG_CMD, "cmd trigger scan to"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->timeout = timeout; - - ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("cmd trigger scan to failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h deleted file mode 100644 index a9e4991369b..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ /dev/null @@ -1,417 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_CMD_H__ -#define __WL1251_CMD_H__ - -#include "wl1251.h" - -#include <net/cfg80211.h> - -struct acx_header; - -int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); -int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer); -int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len); -int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); -int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, - void *bitmap, u16 bitmap_len, u8 bitmap_control); -int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, - u16 beacon_interval, u8 dtim_interval); -int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); -int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, - size_t len); -int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, - void *buf, size_t buf_len); -int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, - struct ieee80211_channel *channels[], - unsigned int n_channels, unsigned int n_probes); -int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); - -/* unit ms */ -#define WL1251_COMMAND_TIMEOUT 2000 - -enum wl1251_commands { - CMD_RESET = 0, - CMD_INTERROGATE = 1, /*use this to read information elements*/ - CMD_CONFIGURE = 2, /*use this to write information elements*/ - CMD_ENABLE_RX = 3, - CMD_ENABLE_TX = 4, - CMD_DISABLE_RX = 5, - CMD_DISABLE_TX = 6, - CMD_SCAN = 8, - CMD_STOP_SCAN = 9, - CMD_VBM = 10, - CMD_START_JOIN = 11, - CMD_SET_KEYS = 12, - CMD_READ_MEMORY = 13, - CMD_WRITE_MEMORY = 14, - CMD_BEACON = 19, - CMD_PROBE_RESP = 20, - CMD_NULL_DATA = 21, - CMD_PROBE_REQ = 22, - CMD_TEST = 23, - CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ - CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ - CMD_NOISE_HIST = 28, - CMD_RX_RESET = 29, - CMD_PS_POLL = 30, - CMD_QOS_NULL_DATA = 31, - CMD_LNA_CONTROL = 32, - CMD_SET_BCN_MODE = 33, - CMD_MEASUREMENT = 34, - CMD_STOP_MEASUREMENT = 35, - CMD_DISCONNECT = 36, - CMD_SET_PS_MODE = 37, - CMD_CHANNEL_SWITCH = 38, - CMD_STOP_CHANNEL_SWICTH = 39, - CMD_AP_DISCOVERY = 40, - CMD_STOP_AP_DISCOVERY = 41, - CMD_SPS_SCAN = 42, - CMD_STOP_SPS_SCAN = 43, - CMD_HEALTH_CHECK = 45, - CMD_DEBUG = 46, - CMD_TRIGGER_SCAN_TO = 47, - - NUM_COMMANDS, - MAX_COMMAND_ID = 0xFFFF, -}; - -#define MAX_CMD_PARAMS 572 - -struct wl1251_cmd_header { - u16 id; - u16 status; - /* payload */ - u8 data[0]; -} __packed; - -struct wl1251_command { - struct wl1251_cmd_header header; - u8 parameters[MAX_CMD_PARAMS]; -}; - -enum { - CMD_MAILBOX_IDLE = 0, - CMD_STATUS_SUCCESS = 1, - CMD_STATUS_UNKNOWN_CMD = 2, - CMD_STATUS_UNKNOWN_IE = 3, - CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, - CMD_STATUS_RX_BUSY = 13, - CMD_STATUS_INVALID_PARAM = 14, - CMD_STATUS_TEMPLATE_TOO_LARGE = 15, - CMD_STATUS_OUT_OF_MEMORY = 16, - CMD_STATUS_STA_TABLE_FULL = 17, - CMD_STATUS_RADIO_ERROR = 18, - CMD_STATUS_WRONG_NESTING = 19, - CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ - CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ - MAX_COMMAND_STATUS = 0xff -}; - - -/* - * CMD_READ_MEMORY - * - * The host issues this command to read the WiLink device memory/registers. - * - * Note: The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -/* - * CMD_WRITE_MEMORY - * - * The host issues this command to write the WiLink device memory/registers. - * - * The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -#define MAX_READ_SIZE 256 - -struct cmd_read_write_memory { - struct wl1251_cmd_header header; - - /* The address of the memory to read from or write to.*/ - u32 addr; - - /* The amount of data in bytes to read from or write to the WiLink - * device.*/ - u32 size; - - /* The actual value read from or written to the Wilink. The source - of this field is the Host in WRITE command or the Wilink in READ - command. */ - u8 value[MAX_READ_SIZE]; -}; - -#define CMDMBOX_HEADER_LEN 4 -#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 - -#define WL1251_SCAN_MIN_DURATION 30000 -#define WL1251_SCAN_MAX_DURATION 60000 - -#define WL1251_SCAN_NUM_PROBES 3 - -struct wl1251_scan_parameters { - __le32 rx_config_options; - __le32 rx_filter_options; - - /* - * Scan options: - * bit 0: When this bit is set, passive scan. - * bit 1: Band, when this bit is set we scan - * in the 5Ghz band. - * bit 2: voice mode, 0 for normal scan. - * bit 3: scan priority, 1 for high priority. - */ - __le16 scan_options; - - /* Number of channels to scan */ - u8 num_channels; - - /* Number opf probe requests to send, per channel */ - u8 num_probe_requests; - - /* Rate and modulation for probe requests */ - __le16 tx_rate; - - u8 tid_trigger; - u8 ssid_len; - u8 ssid[32]; - -} __packed; - -struct wl1251_scan_ch_parameters { - __le32 min_duration; /* in TU */ - __le32 max_duration; /* in TU */ - u32 bssid_lsb; - u16 bssid_msb; - - /* - * bits 0-3: Early termination count. - * bits 4-5: Early termination condition. - */ - u8 early_termination; - - u8 tx_power_att; - u8 channel; - u8 pad[3]; -} __packed; - -/* SCAN parameters */ -#define SCAN_MAX_NUM_OF_CHANNELS 16 - -struct wl1251_cmd_scan { - struct wl1251_cmd_header header; - - struct wl1251_scan_parameters params; - struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; -} __packed; - -enum { - BSS_TYPE_IBSS = 0, - BSS_TYPE_STA_BSS = 2, - BSS_TYPE_AP_BSS = 3, - MAX_BSS_TYPE = 0xFF -}; - -#define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ -#define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ - - -struct cmd_join { - struct wl1251_cmd_header header; - - u32 bssid_lsb; - u16 bssid_msb; - u16 beacon_interval; /* in TBTTs */ - u32 rx_config_options; - u32 rx_filter_options; - - /* - * The target uses this field to determine the rate at - * which to transmit control frame responses (such as - * ACK or CTS frames). - */ - u16 basic_rate_set; - u8 dtim_interval; - u8 tx_ctrl_frame_rate; /* OBSOLETE */ - u8 tx_ctrl_frame_mod; /* OBSOLETE */ - /* - * bits 0-2: This bitwise field specifies the type - * of BSS to start or join (BSS_TYPE_*). - * bit 4: Band - The radio band in which to join - * or start. - * 0 - 2.4GHz band - * 1 - 5GHz band - * bits 3, 5-7: Reserved - */ - u8 bss_type; - u8 channel; - u8 ssid_len; - u8 ssid[IW_ESSID_MAX_SIZE]; - u8 ctrl; /* JOIN_CMD_CTRL_* */ - u8 tx_mgt_frame_rate; /* OBSOLETE */ - u8 tx_mgt_frame_mod; /* OBSOLETE */ - u8 reserved; -} __packed; - -struct cmd_enabledisable_path { - struct wl1251_cmd_header header; - - u8 channel; - u8 padding[3]; -} __packed; - -#define WL1251_MAX_TEMPLATE_SIZE 300 - -struct wl1251_cmd_packet_template { - struct wl1251_cmd_header header; - - __le16 size; - u8 data[0]; -} __packed; - -#define TIM_ELE_ID 5 -#define PARTIAL_VBM_MAX 251 - -struct wl1251_tim { - u8 identity; - u8 length; - u8 dtim_count; - u8 dtim_period; - u8 bitmap_ctrl; - u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ -} __packed; - -/* Virtual Bit Map update */ -struct wl1251_cmd_vbm_update { - struct wl1251_cmd_header header; - __le16 len; - u8 padding[2]; - struct wl1251_tim tim; -} __packed; - -enum wl1251_cmd_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE -}; - -struct wl1251_cmd_ps_params { - struct wl1251_cmd_header header; - - u8 ps_mode; /* STATION_* */ - u8 send_null_data; /* Do we have to send NULL data packet ? */ - u8 retries; /* Number of retires for the initial NULL data packet */ - - /* - * TUs during which the target stays awake after switching - * to power save mode. - */ - u8 hang_over_period; - u16 null_data_rate; - u8 pad[2]; -} __packed; - -struct wl1251_cmd_trigger_scan_to { - struct wl1251_cmd_header header; - - u32 timeout; -}; - -/* HW encryption keys */ -#define NUM_ACCESS_CATEGORIES_COPY 4 -#define MAX_KEY_SIZE 32 - -/* When set, disable HW encryption */ -#define DF_ENCRYPTION_DISABLE 0x01 -/* When set, disable HW decryption */ -#define DF_SNIFF_MODE_ENABLE 0x80 - -enum wl1251_cmd_key_action { - KEY_ADD_OR_REPLACE = 1, - KEY_REMOVE = 2, - KEY_SET_ID = 3, - MAX_KEY_ACTION = 0xffff, -}; - -enum wl1251_cmd_key_type { - KEY_WEP_DEFAULT = 0, - KEY_WEP_ADDR = 1, - KEY_AES_GROUP = 4, - KEY_AES_PAIRWISE = 5, - KEY_WEP_GROUP = 6, - KEY_TKIP_MIC_GROUP = 10, - KEY_TKIP_MIC_PAIRWISE = 11, -}; - -/* - * - * key_type_e key size key format - * ---------- --------- ---------- - * 0x00 5, 13, 29 Key data - * 0x01 5, 13, 29 Key data - * 0x04 16 16 bytes of key data - * 0x05 16 16 bytes of key data - * 0x0a 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * 0x0b 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * - */ - -struct wl1251_cmd_set_keys { - struct wl1251_cmd_header header; - - /* Ignored for default WEP key */ - u8 addr[ETH_ALEN]; - - /* key_action_e */ - u16 key_action; - - u16 reserved_1; - - /* key size in bytes */ - u8 key_size; - - /* key_type_e */ - u8 key_type; - u8 ssid_profile; - - /* - * TKIP, AES: frame's key id field. - * For WEP default key: key id; - */ - u8 id; - u8 reserved_2[6]; - u8 key[MAX_KEY_SIZE]; - u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; -} __packed; - - -#endif /* __WL1251_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c deleted file mode 100644 index fa620a5e530..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ /dev/null @@ -1,547 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl1251_debugfs.h" - -#include <linux/skbuff.h> -#include <linux/slab.h> - -#include "wl1251.h" -#include "wl1251_acx.h" -#include "wl1251_ps.h" - -/* ms */ -#define WL1251_DEBUGFS_STATS_LIFETIME 1000 - -/* debugfs macros idea from mac80211 */ - -#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ -static ssize_t name## _read(struct file *file, char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl1251 *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ - \ - res = scnprintf(buf, buflen, fmt "\n", ##value); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ -} \ - \ -static const struct file_operations name## _ops = { \ - .read = name## _read, \ - .open = wl1251_open_file_generic, \ - .llseek = generic_file_llseek, \ -}; - -#define DEBUGFS_ADD(name, parent) \ - wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ - wl, &name## _ops); \ - if (IS_ERR(wl->debugfs.name)) { \ - ret = PTR_ERR(wl->debugfs.name); \ - wl->debugfs.name = NULL; \ - goto out; \ - } - -#define DEBUGFS_DEL(name) \ - do { \ - debugfs_remove(wl->debugfs.name); \ - wl->debugfs.name = NULL; \ - } while (0) - -#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ -static ssize_t sub## _ ##name## _read(struct file *file, \ - char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl1251 *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ - \ - wl1251_debugfs_update_stats(wl); \ - \ - res = scnprintf(buf, buflen, fmt "\n", \ - wl->stats.fw_stats->sub.name); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ -} \ - \ -static const struct file_operations sub## _ ##name## _ops = { \ - .read = sub## _ ##name## _read, \ - .open = wl1251_open_file_generic, \ - .llseek = generic_file_llseek, \ -}; - -#define DEBUGFS_FWSTATS_ADD(sub, name) \ - DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) - -#define DEBUGFS_FWSTATS_DEL(sub, name) \ - DEBUGFS_DEL(sub## _ ##name) - -static void wl1251_debugfs_update_stats(struct wl1251 *wl) -{ - int ret; - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (wl->state == WL1251_STATE_ON && - time_after(jiffies, wl->stats.fw_stats_update + - msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) { - wl1251_acx_statistics(wl, wl->stats.fw_stats); - wl->stats.fw_stats_update = jiffies; - } - - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); -/* skipping wep.reserved */ -DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); -/* skipping cont_miss_bcns_spread for now */ -DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, - 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); - -DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); -DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", - wl->stats.excessive_retries); - -static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct wl1251 *wl = file->private_data; - u32 queue_len; - char buf[20]; - int res; - - queue_len = skb_queue_len(&wl->tx_queue); - - res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); - return simple_read_from_buffer(userbuf, count, ppos, buf, res); -} - -static const struct file_operations tx_queue_len_ops = { - .read = tx_queue_len_read, - .open = wl1251_open_file_generic, - .llseek = generic_file_llseek, -}; - -static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct wl1251 *wl = file->private_data; - char buf[3], status; - int len; - - if (wl->tx_queue_stopped) - status = 's'; - else - status = 'r'; - - len = scnprintf(buf, sizeof(buf), "%c\n", status); - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -static const struct file_operations tx_queue_status_ops = { - .read = tx_queue_status_read, - .open = wl1251_open_file_generic, - .llseek = generic_file_llseek, -}; - -static void wl1251_debugfs_delete_files(struct wl1251 *wl) -{ - DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); - - DEBUGFS_FWSTATS_DEL(rx, out_of_mem); - DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); - DEBUGFS_FWSTATS_DEL(rx, hw_stuck); - DEBUGFS_FWSTATS_DEL(rx, dropped); - DEBUGFS_FWSTATS_DEL(rx, fcs_err); - DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); - DEBUGFS_FWSTATS_DEL(rx, path_reset); - DEBUGFS_FWSTATS_DEL(rx, reset_counter); - - DEBUGFS_FWSTATS_DEL(dma, rx_requested); - DEBUGFS_FWSTATS_DEL(dma, rx_errors); - DEBUGFS_FWSTATS_DEL(dma, tx_requested); - DEBUGFS_FWSTATS_DEL(dma, tx_errors); - - DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); - DEBUGFS_FWSTATS_DEL(isr, fiqs); - DEBUGFS_FWSTATS_DEL(isr, rx_headers); - DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); - DEBUGFS_FWSTATS_DEL(isr, rx_rdys); - DEBUGFS_FWSTATS_DEL(isr, irqs); - DEBUGFS_FWSTATS_DEL(isr, tx_procs); - DEBUGFS_FWSTATS_DEL(isr, decrypt_done); - DEBUGFS_FWSTATS_DEL(isr, dma0_done); - DEBUGFS_FWSTATS_DEL(isr, dma1_done); - DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); - DEBUGFS_FWSTATS_DEL(isr, commands); - DEBUGFS_FWSTATS_DEL(isr, rx_procs); - DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); - DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); - DEBUGFS_FWSTATS_DEL(isr, pci_pm); - DEBUGFS_FWSTATS_DEL(isr, wakeups); - DEBUGFS_FWSTATS_DEL(isr, low_rssi); - - DEBUGFS_FWSTATS_DEL(wep, addr_key_count); - DEBUGFS_FWSTATS_DEL(wep, default_key_count); - /* skipping wep.reserved */ - DEBUGFS_FWSTATS_DEL(wep, key_not_found); - DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); - DEBUGFS_FWSTATS_DEL(wep, packets); - DEBUGFS_FWSTATS_DEL(wep, interrupt); - - DEBUGFS_FWSTATS_DEL(pwr, ps_enter); - DEBUGFS_FWSTATS_DEL(pwr, elp_enter); - DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); - DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); - DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); - DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); - DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); - DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); - DEBUGFS_FWSTATS_DEL(pwr, power_save_off); - DEBUGFS_FWSTATS_DEL(pwr, enable_ps); - DEBUGFS_FWSTATS_DEL(pwr, disable_ps); - DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); - /* skipping cont_miss_bcns_spread for now */ - DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); - - DEBUGFS_FWSTATS_DEL(mic, rx_pkts); - DEBUGFS_FWSTATS_DEL(mic, calc_failure); - - DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); - DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); - DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); - DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); - DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); - DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); - - DEBUGFS_FWSTATS_DEL(event, heart_beat); - DEBUGFS_FWSTATS_DEL(event, calibration); - DEBUGFS_FWSTATS_DEL(event, rx_mismatch); - DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); - DEBUGFS_FWSTATS_DEL(event, rx_pool); - DEBUGFS_FWSTATS_DEL(event, oom_late); - DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); - DEBUGFS_FWSTATS_DEL(event, tx_stuck); - - DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); - DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); - DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); - DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); - DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); - DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); - DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); - - DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); - DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); - - DEBUGFS_DEL(tx_queue_len); - DEBUGFS_DEL(tx_queue_status); - DEBUGFS_DEL(retry_count); - DEBUGFS_DEL(excessive_retries); -} - -static int wl1251_debugfs_add_files(struct wl1251 *wl) -{ - int ret = 0; - - DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); - - DEBUGFS_FWSTATS_ADD(rx, out_of_mem); - DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); - DEBUGFS_FWSTATS_ADD(rx, hw_stuck); - DEBUGFS_FWSTATS_ADD(rx, dropped); - DEBUGFS_FWSTATS_ADD(rx, fcs_err); - DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); - DEBUGFS_FWSTATS_ADD(rx, path_reset); - DEBUGFS_FWSTATS_ADD(rx, reset_counter); - - DEBUGFS_FWSTATS_ADD(dma, rx_requested); - DEBUGFS_FWSTATS_ADD(dma, rx_errors); - DEBUGFS_FWSTATS_ADD(dma, tx_requested); - DEBUGFS_FWSTATS_ADD(dma, tx_errors); - - DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); - DEBUGFS_FWSTATS_ADD(isr, fiqs); - DEBUGFS_FWSTATS_ADD(isr, rx_headers); - DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); - DEBUGFS_FWSTATS_ADD(isr, rx_rdys); - DEBUGFS_FWSTATS_ADD(isr, irqs); - DEBUGFS_FWSTATS_ADD(isr, tx_procs); - DEBUGFS_FWSTATS_ADD(isr, decrypt_done); - DEBUGFS_FWSTATS_ADD(isr, dma0_done); - DEBUGFS_FWSTATS_ADD(isr, dma1_done); - DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); - DEBUGFS_FWSTATS_ADD(isr, commands); - DEBUGFS_FWSTATS_ADD(isr, rx_procs); - DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); - DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); - DEBUGFS_FWSTATS_ADD(isr, pci_pm); - DEBUGFS_FWSTATS_ADD(isr, wakeups); - DEBUGFS_FWSTATS_ADD(isr, low_rssi); - - DEBUGFS_FWSTATS_ADD(wep, addr_key_count); - DEBUGFS_FWSTATS_ADD(wep, default_key_count); - /* skipping wep.reserved */ - DEBUGFS_FWSTATS_ADD(wep, key_not_found); - DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); - DEBUGFS_FWSTATS_ADD(wep, packets); - DEBUGFS_FWSTATS_ADD(wep, interrupt); - - DEBUGFS_FWSTATS_ADD(pwr, ps_enter); - DEBUGFS_FWSTATS_ADD(pwr, elp_enter); - DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); - DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); - DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); - DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); - DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); - DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); - DEBUGFS_FWSTATS_ADD(pwr, power_save_off); - DEBUGFS_FWSTATS_ADD(pwr, enable_ps); - DEBUGFS_FWSTATS_ADD(pwr, disable_ps); - DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); - /* skipping cont_miss_bcns_spread for now */ - DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); - - DEBUGFS_FWSTATS_ADD(mic, rx_pkts); - DEBUGFS_FWSTATS_ADD(mic, calc_failure); - - DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); - DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); - DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); - DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); - DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); - DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); - - DEBUGFS_FWSTATS_ADD(event, heart_beat); - DEBUGFS_FWSTATS_ADD(event, calibration); - DEBUGFS_FWSTATS_ADD(event, rx_mismatch); - DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); - DEBUGFS_FWSTATS_ADD(event, rx_pool); - DEBUGFS_FWSTATS_ADD(event, oom_late); - DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); - DEBUGFS_FWSTATS_ADD(event, tx_stuck); - - DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); - DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); - DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); - DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); - DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); - DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); - DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); - - DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); - DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); - - DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); - DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir); - DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); - DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); - -out: - if (ret < 0) - wl1251_debugfs_delete_files(wl); - - return ret; -} - -void wl1251_debugfs_reset(struct wl1251 *wl) -{ - if (wl->stats.fw_stats != NULL) - memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); - wl->stats.retry_count = 0; - wl->stats.excessive_retries = 0; -} - -int wl1251_debugfs_init(struct wl1251 *wl) -{ - int ret; - - wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); - - if (IS_ERR(wl->debugfs.rootdir)) { - ret = PTR_ERR(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - goto err; - } - - wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", - wl->debugfs.rootdir); - - if (IS_ERR(wl->debugfs.fw_statistics)) { - ret = PTR_ERR(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - goto err_root; - } - - wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), - GFP_KERNEL); - - if (!wl->stats.fw_stats) { - ret = -ENOMEM; - goto err_fw; - } - - wl->stats.fw_stats_update = jiffies; - - ret = wl1251_debugfs_add_files(wl); - - if (ret < 0) - goto err_file; - - return 0; - -err_file: - kfree(wl->stats.fw_stats); - wl->stats.fw_stats = NULL; - -err_fw: - debugfs_remove(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - -err_root: - debugfs_remove(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - -err: - return ret; -} - -void wl1251_debugfs_exit(struct wl1251 *wl) -{ - wl1251_debugfs_delete_files(wl); - - kfree(wl->stats.fw_stats); - wl->stats.fw_stats = NULL; - - debugfs_remove(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - - debugfs_remove(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - -} diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h deleted file mode 100644 index 6dc3d080853..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef WL1251_DEBUGFS_H -#define WL1251_DEBUGFS_H - -#include "wl1251.h" - -int wl1251_debugfs_init(struct wl1251 *wl); -void wl1251_debugfs_exit(struct wl1251 *wl); -void wl1251_debugfs_reset(struct wl1251 *wl); - -#endif /* WL1251_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c deleted file mode 100644 index 020d764f9c1..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_event.h" -#include "wl1251_ps.h" - -static int wl1251_event_scan_complete(struct wl1251 *wl, - struct event_mailbox *mbox) -{ - wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", - mbox->scheduled_scan_status, - mbox->scheduled_scan_channels); - - if (wl->scanning) { - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, false); - mutex_lock(&wl->mutex); - wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); - wl->scanning = false; - } - - return 0; -} - -static void wl1251_event_mbox_dump(struct event_mailbox *mbox) -{ - wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); - wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); - wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); -} - -static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) -{ - int ret; - u32 vector; - - wl1251_event_mbox_dump(mbox); - - vector = mbox->events_vector & ~(mbox->events_mask); - wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector); - - if (vector & SCAN_COMPLETE_EVENT_ID) { - ret = wl1251_event_scan_complete(wl, mbox); - if (ret < 0) - return ret; - } - - if (vector & BSS_LOSE_EVENT_ID) { - wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); - - if (wl->psm_requested && wl->psm) { - ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - } - } - - if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { - wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); - - /* indicate to the stack, that beacons have been lost */ - ieee80211_beacon_loss(wl->vif); - } - - if (vector & REGAINED_BSS_EVENT_ID) { - if (wl->psm_requested) { - ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); - if (ret < 0) - return ret; - } - } - - return 0; -} - -int wl1251_event_unmask(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask)); - if (ret < 0) - return ret; - - return 0; -} - -void wl1251_event_mbox_config(struct wl1251 *wl) -{ - wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); - wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); - - wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", - wl->mbox_ptr[0], wl->mbox_ptr[1]); -} - -int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) -{ - struct event_mailbox mbox; - int ret; - - wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); - - if (mbox_num > 1) - return -EINVAL; - - /* first we read the mbox descriptor */ - wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, - sizeof(struct event_mailbox)); - - /* process the descriptor */ - ret = wl1251_event_process(wl, &mbox); - if (ret < 0) - return ret; - - /* then we let the firmware know it can go on...*/ - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); - - return 0; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h deleted file mode 100644 index f48a2b66bc5..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_event.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_EVENT_H__ -#define __WL1251_EVENT_H__ - -/* - * Mbox events - * - * The event mechanism is based on a pair of event buffers (buffers A and - * B) at fixed locations in the target's memory. The host processes one - * buffer while the other buffer continues to collect events. If the host - * is not processing events, an interrupt is issued to signal that a buffer - * is ready. Once the host is done with processing events from one buffer, - * it signals the target (with an ACK interrupt) that the event buffer is - * free. - */ - -enum { - RESERVED1_EVENT_ID = BIT(0), - RESERVED2_EVENT_ID = BIT(1), - MEASUREMENT_START_EVENT_ID = BIT(2), - SCAN_COMPLETE_EVENT_ID = BIT(3), - CALIBRATION_COMPLETE_EVENT_ID = BIT(4), - ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), - PS_REPORT_EVENT_ID = BIT(6), - SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), - HEALTH_REPORT_EVENT_ID = BIT(8), - ACI_DETECTION_EVENT_ID = BIT(9), - DEBUG_REPORT_EVENT_ID = BIT(10), - MAC_STATUS_EVENT_ID = BIT(11), - DISCONNECT_EVENT_COMPLETE_ID = BIT(12), - JOIN_EVENT_COMPLETE_ID = BIT(13), - CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), - BSS_LOSE_EVENT_ID = BIT(15), - ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), - MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), - AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), - SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), - PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), - RESET_BSS_EVENT_ID = BIT(21), - REGAINED_BSS_EVENT_ID = BIT(22), - ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), - ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), - ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), - - DBG_EVENT_ID = BIT(26), - BT_PTA_SENSE_EVENT_ID = BIT(27), - BT_PTA_PREDICTION_EVENT_ID = BIT(28), - BT_PTA_AVALANCHE_EVENT_ID = BIT(29), - - PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), - - EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, -}; - -struct event_debug_report { - u8 debug_event_id; - u8 num_params; - u16 pad; - u32 report_1; - u32 report_2; - u32 report_3; -} __packed; - -struct event_mailbox { - u32 events_vector; - u32 events_mask; - u32 reserved_1; - u32 reserved_2; - - char average_rssi_level; - u8 ps_status; - u8 channel_switch_status; - u8 scheduled_scan_status; - - /* Channels scanned by the scheduled scan */ - u16 scheduled_scan_channels; - - /* If bit 0 is set -> target's fatal error */ - u16 health_report; - u16 bad_fft_counter; - u8 bt_pta_sense_info; - u8 bt_pta_protective_info; - u32 reserved; - u32 debug_report[2]; - - /* Number of FCS errors since last event */ - u32 fcs_err_counter; - - struct event_debug_report report; - u8 average_snr_level; - u8 padding[19]; -} __packed; - -int wl1251_event_unmask(struct wl1251 *wl); -void wl1251_event_mbox_config(struct wl1251 *wl); -int wl1251_event_handle(struct wl1251 *wl, u8 mbox); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c deleted file mode 100644 index b538bdd7b32..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> - -#include "wl1251_init.h" -#include "wl12xx_80211.h" -#include "wl1251_acx.h" -#include "wl1251_cmd.h" -#include "wl1251_reg.h" - -int wl1251_hw_init_hwenc_config(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_feature_cfg(wl); - if (ret < 0) { - wl1251_warning("couldn't set feature config"); - return ret; - } - - ret = wl1251_acx_default_key(wl, wl->default_key); - if (ret < 0) { - wl1251_warning("couldn't set default key"); - return ret; - } - - return 0; -} - -int wl1251_hw_init_templates_config(struct wl1251 *wl) -{ - int ret; - u8 partial_vbm[PARTIAL_VBM_MAX]; - - /* send empty templates for fw memory reservation */ - ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL, - sizeof(struct wl12xx_probe_req_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL, - sizeof(struct wl12xx_null_data_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL, - sizeof(struct wl12xx_ps_poll_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, - sizeof - (struct wl12xx_qos_null_data_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL, - sizeof - (struct wl12xx_probe_resp_template)); - if (ret < 0) - return ret; - - ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL, - sizeof - (struct wl12xx_beacon_template)); - if (ret < 0) - return ret; - - /* tim templates, first reserve space then allocate an empty one */ - memset(partial_vbm, 0, PARTIAL_VBM_MAX); - ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); - if (ret < 0) - return ret; - - ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter) -{ - int ret; - - ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); - if (ret < 0) - return ret; - - ret = wl1251_acx_rx_config(wl, config, filter); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_phy_config(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_pd_threshold(wl); - if (ret < 0) - return ret; - - ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME); - if (ret < 0) - return ret; - - ret = wl1251_acx_group_address_tbl(wl); - if (ret < 0) - return ret; - - ret = wl1251_acx_service_period_timeout(wl); - if (ret < 0) - return ret; - - ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_beacon_filter(struct wl1251 *wl) -{ - int ret; - - /* disable beacon filtering at this stage */ - ret = wl1251_acx_beacon_filter_opt(wl, false); - if (ret < 0) - return ret; - - ret = wl1251_acx_beacon_filter_table(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_pta(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_sg_enable(wl); - if (ret < 0) - return ret; - - ret = wl1251_acx_sg_cfg(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_energy_detection(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_cca_threshold(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_bcn_dtim_options(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_hw_init_power_auth(struct wl1251 *wl) -{ - return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); -} - -int wl1251_hw_init_mem_config(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_acx_mem_cfg(wl); - if (ret < 0) - return ret; - - wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), - GFP_KERNEL); - if (!wl->target_mem_map) { - wl1251_error("couldn't allocate target memory map"); - return -ENOMEM; - } - - /* we now ask for the firmware built memory map */ - ret = wl1251_acx_mem_map(wl, wl->target_mem_map, - sizeof(struct wl1251_acx_mem_map)); - if (ret < 0) { - wl1251_error("couldn't retrieve firmware memory map"); - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - return ret; - } - - return 0; -} - -static int wl1251_hw_init_txq_fill(u8 qid, - struct acx_tx_queue_qos_config *config, - u32 num_blocks) -{ - config->qid = qid; - - switch (qid) { - case QOS_AC_BE: - config->high_threshold = - (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BE_DEF * num_blocks) / 100; - break; - case QOS_AC_BK: - config->high_threshold = - (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BK_DEF * num_blocks) / 100; - break; - case QOS_AC_VI: - config->high_threshold = - (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VI_DEF * num_blocks) / 100; - break; - case QOS_AC_VO: - config->high_threshold = - (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VO_DEF * num_blocks) / 100; - break; - default: - wl1251_error("Invalid TX queue id: %d", qid); - return -EINVAL; - } - - return 0; -} - -static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) -{ - struct acx_tx_queue_qos_config *config; - struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; - int ret, i; - - wl1251_debug(DEBUG_ACX, "acx tx queue config"); - - config = kzalloc(sizeof(*config), GFP_KERNEL); - if (!config) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < MAX_NUM_OF_AC; i++) { - ret = wl1251_hw_init_txq_fill(i, config, - wl_mem_map->num_tx_mem_blocks); - if (ret < 0) - goto out; - - ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, - config, sizeof(*config)); - if (ret < 0) - goto out; - } - - wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE); - wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK); - wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI); - wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO); - -out: - kfree(config); - return ret; -} - -static int wl1251_hw_init_data_path_config(struct wl1251 *wl) -{ - int ret; - - /* asking for the data path parameters */ - wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), - GFP_KERNEL); - if (!wl->data_path) { - wl1251_error("Couldnt allocate data path parameters"); - return -ENOMEM; - } - - ret = wl1251_acx_data_path_params(wl, wl->data_path); - if (ret < 0) { - kfree(wl->data_path); - wl->data_path = NULL; - return ret; - } - - return 0; -} - - -int wl1251_hw_init(struct wl1251 *wl) -{ - struct wl1251_acx_mem_map *wl_mem_map; - int ret; - - ret = wl1251_hw_init_hwenc_config(wl); - if (ret < 0) - return ret; - - /* Template settings */ - ret = wl1251_hw_init_templates_config(wl); - if (ret < 0) - return ret; - - /* Default memory configuration */ - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - /* Default data path configuration */ - ret = wl1251_hw_init_data_path_config(wl); - if (ret < 0) - goto out_free_memmap; - - /* RX config */ - ret = wl1251_hw_init_rx_config(wl, - RX_CFG_PROMISCUOUS | RX_CFG_TSF, - RX_FILTER_OPTION_DEF); - /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, - RX_FILTER_OPTION_FILTER_ALL); */ - if (ret < 0) - goto out_free_data_path; - - /* TX queues config */ - ret = wl1251_hw_init_tx_queue_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* PHY layer config */ - ret = wl1251_hw_init_phy_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* Initialize connection monitoring thresholds */ - ret = wl1251_acx_conn_monit_params(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacon filtering */ - ret = wl1251_hw_init_beacon_filter(wl); - if (ret < 0) - goto out_free_data_path; - - /* Bluetooth WLAN coexistence */ - ret = wl1251_hw_init_pta(wl); - if (ret < 0) - goto out_free_data_path; - - /* Energy detection */ - ret = wl1251_hw_init_energy_detection(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacons and boradcast settings */ - ret = wl1251_hw_init_beacon_broadcast(wl); - if (ret < 0) - goto out_free_data_path; - - /* Enable data path */ - ret = wl1251_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - goto out_free_data_path; - - /* Default power state */ - ret = wl1251_hw_init_power_auth(wl); - if (ret < 0) - goto out_free_data_path; - - wl_mem_map = wl->target_mem_map; - wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", - wl_mem_map->num_tx_mem_blocks, - wl->data_path->tx_control_addr, - wl_mem_map->num_rx_mem_blocks, - wl->data_path->rx_control_addr); - - return 0; - - out_free_data_path: - kfree(wl->data_path); - - out_free_memmap: - kfree(wl->target_mem_map); - - return ret; -} diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h deleted file mode 100644 index 269cefb3e7d..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_INIT_H__ -#define __WL1251_INIT_H__ - -#include "wl1251.h" - -enum { - /* best effort/legacy */ - AC_BE = 0, - - /* background */ - AC_BK = 1, - - /* video */ - AC_VI = 2, - - /* voice */ - AC_VO = 3, - - /* broadcast dummy access category */ - AC_BCAST = 4, - - NUM_ACCESS_CATEGORIES = 4 -}; - -/* following are defult values for the IE fields*/ -#define CWMIN_BK 15 -#define CWMIN_BE 15 -#define CWMIN_VI 7 -#define CWMIN_VO 3 -#define CWMAX_BK 1023 -#define CWMAX_BE 63 -#define CWMAX_VI 15 -#define CWMAX_VO 7 - -/* slot number setting to start transmission at PIFS interval */ -#define AIFS_PIFS 1 - -/* - * slot number setting to start transmission at DIFS interval - normal DCF - * access - */ -#define AIFS_DIFS 2 - -#define AIFSN_BK 7 -#define AIFSN_BE 3 -#define AIFSN_VI AIFS_PIFS -#define AIFSN_VO AIFS_PIFS -#define TXOP_BK 0 -#define TXOP_BE 0 -#define TXOP_VI 3008 -#define TXOP_VO 1504 - -int wl1251_hw_init_hwenc_config(struct wl1251 *wl); -int wl1251_hw_init_templates_config(struct wl1251 *wl); -int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); -int wl1251_hw_init_phy_config(struct wl1251 *wl); -int wl1251_hw_init_beacon_filter(struct wl1251 *wl); -int wl1251_hw_init_pta(struct wl1251 *wl); -int wl1251_hw_init_energy_detection(struct wl1251 *wl); -int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); -int wl1251_hw_init_power_auth(struct wl1251 *wl); -int wl1251_hw_init_mem_config(struct wl1251 *wl); -int wl1251_hw_init(struct wl1251 *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c deleted file mode 100644 index f1c232e0887..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" - -/* FIXME: this is static data nowadays and the table can be removed */ -static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { - [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), - [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), - [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), - [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), - [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), - [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), - [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), - [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), - [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), - [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), - [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) -}; - -static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) -{ - /* If the address is lower than REGISTERS_BASE, it means that this is - * a chip-specific register address, so look it up in the registers - * table */ - if (addr < REGISTERS_BASE) { - /* Make sure we don't go over the table */ - if (addr >= ACX_REG_TABLE_LEN) { - wl1251_error("address out of range (%d)", addr); - return -EINVAL; - } - addr = wl1251_io_reg_table[addr]; - } - - return addr - wl->physical_reg_addr + wl->virtual_reg_addr; -} - -static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) -{ - return addr - wl->physical_mem_addr + wl->virtual_mem_addr; -} - -void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) -{ - int physical; - - physical = wl1251_translate_mem_addr(wl, addr); - - wl->if_ops->read(wl, physical, buf, len); -} - -void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) -{ - int physical; - - physical = wl1251_translate_mem_addr(wl, addr); - - wl->if_ops->write(wl, physical, buf, len); -} - -u32 wl1251_mem_read32(struct wl1251 *wl, int addr) -{ - return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); -} - -void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); -} - -u32 wl1251_reg_read32(struct wl1251 *wl, int addr) -{ - return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); -} - -void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); -} - -/* Set the partitions to access the chip addresses. - * - * There are two VIRTUAL partitions (the memory partition and the - * registers partition), which are mapped to two different areas of the - * PHYSICAL (hardware) memory. This function also makes other checks to - * ensure that the partitions are not overlapping. In the diagram below, the - * memory partition comes before the register partition, but the opposite is - * also supported. - * - * PHYSICAL address - * space - * - * | | - * ...+----+--> mem_start - * VIRTUAL address ... | | - * space ... | | [PART_0] - * ... | | - * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size - * | | ... | | - * |MEM | ... | | - * | | ... | | - * part_size <--+----+... | | {unused area) - * | | ... | | - * |REG | ... | | - * part_size | | ... | | - * + <--+----+... ...+----+--> reg_start - * reg_size ... | | - * ... | | [PART_1] - * ... | | - * ...+----+--> reg_start + reg_size - * | | - * - */ -void wl1251_set_partition(struct wl1251 *wl, - u32 mem_start, u32 mem_size, - u32 reg_start, u32 reg_size) -{ - struct wl1251_partition partition[2]; - - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - - /* Make sure that the two partitions together don't exceed the - * address range */ - if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { - wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" - " address range. Truncating partition[0]."); - mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - if ((mem_start < reg_start) && - ((mem_start + mem_size) > reg_start)) { - /* Guarantee that the memory partition doesn't overlap the - * registers partition */ - wl1251_debug(DEBUG_SPI, "End of partition[0] is " - "overlapping partition[1]. Adjusted."); - mem_size = reg_start - mem_start; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } else if ((reg_start < mem_start) && - ((reg_start + reg_size) > mem_start)) { - /* Guarantee that the register partition doesn't overlap the - * memory partition */ - wl1251_debug(DEBUG_SPI, "End of partition[1] is" - " overlapping partition[0]. Adjusted."); - reg_size = mem_start - reg_start; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - partition[0].start = mem_start; - partition[0].size = mem_size; - partition[1].start = reg_start; - partition[1].size = reg_size; - - wl->physical_mem_addr = mem_start; - wl->physical_reg_addr = reg_start; - - wl->virtual_mem_addr = 0; - wl->virtual_reg_addr = mem_size; - - wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, - sizeof(partition)); -} diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h deleted file mode 100644 index c545e9d5f51..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_io.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#ifndef __WL1251_IO_H__ -#define __WL1251_IO_H__ - -#include "wl1251.h" - -#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 - -#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 -#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 -#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 -#define HW_ACCESS_PART1_START_ADDR 0x1FFCC - -#define HW_ACCESS_REGISTER_SIZE 4 - -#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 - -static inline u32 wl1251_read32(struct wl1251 *wl, int addr) -{ - u32 response; - - wl->if_ops->read(wl, addr, &response, sizeof(u32)); - - return response; -} - -static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl->if_ops->write(wl, addr, &val, sizeof(u32)); -} - -static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr) -{ - u32 response; - - if (wl->if_ops->read_elp) - wl->if_ops->read_elp(wl, addr, &response); - else - wl->if_ops->read(wl, addr, &response, sizeof(u32)); - - return response; -} - -static inline void wl1251_write_elp(struct wl1251 *wl, int addr, u32 val) -{ - if (wl->if_ops->write_elp) - wl->if_ops->write_elp(wl, addr, val); - else - wl->if_ops->write(wl, addr, &val, sizeof(u32)); -} - -/* Memory target IO, address is translated to partition 0 */ -void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); -u32 wl1251_mem_read32(struct wl1251 *wl, int addr); -void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); -/* Registers IO */ -u32 wl1251_reg_read32(struct wl1251 *wl, int addr); -void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); - -void wl1251_set_partition(struct wl1251 *wl, - u32 part_start, u32 part_size, - u32 reg_start, u32 reg_size); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c deleted file mode 100644 index 861a5f33761..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ /dev/null @@ -1,1442 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/firmware.h> -#include <linux/delay.h> -#include <linux/irq.h> -#include <linux/crc32.h> -#include <linux/etherdevice.h> -#include <linux/vmalloc.h> -#include <linux/slab.h> - -#include "wl1251.h" -#include "wl12xx_80211.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_cmd.h" -#include "wl1251_event.h" -#include "wl1251_tx.h" -#include "wl1251_rx.h" -#include "wl1251_ps.h" -#include "wl1251_init.h" -#include "wl1251_debugfs.h" -#include "wl1251_boot.h" - -void wl1251_enable_interrupts(struct wl1251 *wl) -{ - wl->if_ops->enable_irq(wl); -} - -void wl1251_disable_interrupts(struct wl1251 *wl) -{ - wl->if_ops->disable_irq(wl); -} - -static void wl1251_power_off(struct wl1251 *wl) -{ - wl->set_power(false); -} - -static void wl1251_power_on(struct wl1251 *wl) -{ - wl->set_power(true); -} - -static int wl1251_fetch_firmware(struct wl1251 *wl) -{ - const struct firmware *fw; - struct device *dev = wiphy_dev(wl->hw->wiphy); - int ret; - - ret = request_firmware(&fw, WL1251_FW_NAME, dev); - - if (ret < 0) { - wl1251_error("could not get firmware: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl1251_error("firmware size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->fw_len = fw->size; - wl->fw = vmalloc(wl->fw_len); - - if (!wl->fw) { - wl1251_error("could not allocate memory for the firmware"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->fw, fw->data, wl->fw_len); - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static int wl1251_fetch_nvs(struct wl1251 *wl) -{ - const struct firmware *fw; - struct device *dev = wiphy_dev(wl->hw->wiphy); - int ret; - - ret = request_firmware(&fw, WL1251_NVS_NAME, dev); - - if (ret < 0) { - wl1251_error("could not get nvs file: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl1251_error("nvs size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->nvs_len = fw->size; - wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL); - - if (!wl->nvs) { - wl1251_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static void wl1251_fw_wakeup(struct wl1251 *wl) -{ - u32 elp_reg; - - elp_reg = ELPCTRL_WAKE_UP; - wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); - elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - - if (!(elp_reg & ELPCTRL_WLAN_READY)) - wl1251_warning("WLAN not ready"); -} - -static int wl1251_chip_wakeup(struct wl1251 *wl) -{ - int ret = 0; - - wl1251_power_on(wl); - msleep(WL1251_POWER_ON_SLEEP); - wl->if_ops->reset(wl); - - /* We don't need a real memory partition here, because we only want - * to use the registers at this point. */ - wl1251_set_partition(wl, - 0x00000000, - 0x00000000, - REGISTERS_BASE, - REGISTERS_DOWN_SIZE); - - /* ELP module wake up */ - wl1251_fw_wakeup(wl); - - /* whal_FwCtrl_BootSm() */ - - /* 0. read chip id from CHIP_ID */ - wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B); - - /* 1. check if chip id is valid */ - - switch (wl->chip_id) { - case CHIP_ID_1251_PG12: - wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", - wl->chip_id); - break; - case CHIP_ID_1251_PG11: - wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)", - wl->chip_id); - break; - case CHIP_ID_1251_PG10: - default: - wl1251_error("unsupported chip id: 0x%x", wl->chip_id); - ret = -ENODEV; - goto out; - } - - if (wl->fw == NULL) { - ret = wl1251_fetch_firmware(wl); - if (ret < 0) - goto out; - } - - if (wl->nvs == NULL && !wl->use_eeprom) { - /* No NVS from netlink, try to get it from the filesystem */ - ret = wl1251_fetch_nvs(wl); - if (ret < 0) - goto out; - } - -out: - return ret; -} - -#define WL1251_IRQ_LOOP_COUNT 10 -static void wl1251_irq_work(struct work_struct *work) -{ - u32 intr, ctr = WL1251_IRQ_LOOP_COUNT; - struct wl1251 *wl = - container_of(work, struct wl1251, irq_work); - int ret; - - mutex_lock(&wl->mutex); - - wl1251_debug(DEBUG_IRQ, "IRQ work"); - - if (wl->state == WL1251_STATE_OFF) - goto out; - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); - - do { - if (wl->data_path) { - wl->rx_counter = wl1251_mem_read32( - wl, wl->data_path->rx_control_addr); - - /* We handle a frmware bug here */ - switch ((wl->rx_counter - wl->rx_handled) & 0xf) { - case 0: - wl1251_debug(DEBUG_IRQ, - "RX: FW and host in sync"); - intr &= ~WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 1: - wl1251_debug(DEBUG_IRQ, "RX: FW +1"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 2: - wl1251_debug(DEBUG_IRQ, "RX: FW +2"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr |= WL1251_ACX_INTR_RX1_DATA; - break; - default: - wl1251_warning( - "RX: FW and host out of sync: %d", - wl->rx_counter - wl->rx_handled); - break; - } - - wl->rx_handled = wl->rx_counter; - - wl1251_debug(DEBUG_IRQ, "RX counter: %d", - wl->rx_counter); - } - - intr &= wl->intr_mask; - - if (intr == 0) { - wl1251_debug(DEBUG_IRQ, "INTR is 0"); - goto out_sleep; - } - - if (intr & WL1251_ACX_INTR_RX0_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); - wl1251_rx(wl); - } - - if (intr & WL1251_ACX_INTR_RX1_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); - wl1251_rx(wl); - } - - if (intr & WL1251_ACX_INTR_TX_RESULT) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); - wl1251_tx_complete(wl); - } - - if (intr & (WL1251_ACX_INTR_EVENT_A | - WL1251_ACX_INTR_EVENT_B)) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", - intr); - if (intr & WL1251_ACX_INTR_EVENT_A) - wl1251_event_handle(wl, 0); - else - wl1251_event_handle(wl, 1); - } - - if (intr & WL1251_ACX_INTR_INIT_COMPLETE) - wl1251_debug(DEBUG_IRQ, - "WL1251_ACX_INTR_INIT_COMPLETE"); - - if (--ctr == 0) - break; - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - } while (intr); - -out_sleep: - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, - u16 beacon_interval, u8 dtim_period) -{ - int ret; - - ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, - DEFAULT_HW_GEN_MODULATION_TYPE, - wl->tx_mgmt_frm_rate, - wl->tx_mgmt_frm_mod); - if (ret < 0) - goto out; - - - ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, - dtim_period); - if (ret < 0) - goto out; - - /* - * FIXME: we should wait for JOIN_EVENT_COMPLETE_ID but to simplify - * locking we just sleep instead, for now - */ - msleep(10); - -out: - return ret; -} - -static void wl1251_filter_work(struct work_struct *work) -{ - struct wl1251 *wl = - container_of(work, struct wl1251, filter_work); - int ret; - - mutex_lock(&wl->mutex); - - if (wl->state == WL1251_STATE_OFF) - goto out; - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, - wl->dtim_period); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct wl1251 *wl = hw->priv; - - skb_queue_tail(&wl->tx_queue, skb); - - /* - * The chip specific setup must run before the first TX packet - - * before that, the tx_work will not be initialized! - */ - - ieee80211_queue_work(wl->hw, &wl->tx_work); - - /* - * The workqueue is slow to process the tx_queue and we need stop - * the queue here, otherwise the queue will get too long. - */ - if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) { - wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues"); - ieee80211_stop_queues(wl->hw); - - /* - * FIXME: this is racy, the variable is not properly - * protected. Maybe fix this by removing the stupid - * variable altogether and checking the real queue state? - */ - wl->tx_queue_stopped = true; - } - - return NETDEV_TX_OK; -} - -static int wl1251_op_start(struct ieee80211_hw *hw) -{ - struct wl1251 *wl = hw->priv; - struct wiphy *wiphy = hw->wiphy; - int ret = 0; - - wl1251_debug(DEBUG_MAC80211, "mac80211 start"); - - mutex_lock(&wl->mutex); - - if (wl->state != WL1251_STATE_OFF) { - wl1251_error("cannot start because not in off state: %d", - wl->state); - ret = -EBUSY; - goto out; - } - - ret = wl1251_chip_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1251_boot(wl); - if (ret < 0) - goto out; - - ret = wl1251_hw_init(wl); - if (ret < 0) - goto out; - - ret = wl1251_acx_station_id(wl); - if (ret < 0) - goto out; - - wl->state = WL1251_STATE_ON; - - wl1251_info("firmware booted (%s)", wl->fw_ver); - - /* update hw/fw version info in wiphy struct */ - wiphy->hw_version = wl->chip_id; - strncpy(wiphy->fw_version, wl->fw_ver, sizeof(wiphy->fw_version)); - -out: - if (ret < 0) - wl1251_power_off(wl); - - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl1251_op_stop(struct ieee80211_hw *hw) -{ - struct wl1251 *wl = hw->priv; - - wl1251_info("down"); - - wl1251_debug(DEBUG_MAC80211, "mac80211 stop"); - - mutex_lock(&wl->mutex); - - WARN_ON(wl->state != WL1251_STATE_ON); - - if (wl->scanning) { - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, true); - mutex_lock(&wl->mutex); - wl->scanning = false; - } - - wl->state = WL1251_STATE_OFF; - - wl1251_disable_interrupts(wl); - - mutex_unlock(&wl->mutex); - - cancel_work_sync(&wl->irq_work); - cancel_work_sync(&wl->tx_work); - cancel_work_sync(&wl->filter_work); - - mutex_lock(&wl->mutex); - - /* let's notify MAC80211 about the remaining pending TX frames */ - wl1251_tx_flush(wl); - wl1251_power_off(wl); - - memset(wl->bssid, 0, ETH_ALEN); - wl->listen_int = 1; - wl->bss_type = MAX_BSS_TYPE; - - wl->data_in_count = 0; - wl->rx_counter = 0; - wl->rx_handled = 0; - wl->rx_current_buffer = 0; - wl->rx_last_id = 0; - wl->next_tx_complete = 0; - wl->elp = false; - wl->psm = 0; - wl->tx_queue_stopped = false; - wl->power_level = WL1251_DEFAULT_POWER_LEVEL; - wl->channel = WL1251_DEFAULT_CHANNEL; - - wl1251_debugfs_reset(wl); - - mutex_unlock(&wl->mutex); -} - -static int wl1251_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1251 *wl = hw->priv; - int ret = 0; - - wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - vif->type, vif->addr); - - mutex_lock(&wl->mutex); - if (wl->vif) { - ret = -EBUSY; - goto out; - } - - wl->vif = vif; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - wl->bss_type = BSS_TYPE_STA_BSS; - break; - case NL80211_IFTYPE_ADHOC: - wl->bss_type = BSS_TYPE_IBSS; - break; - default: - ret = -EOPNOTSUPP; - goto out; - } - - if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) { - memcpy(wl->mac_addr, vif->addr, ETH_ALEN); - SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - ret = wl1251_acx_station_id(wl); - if (ret < 0) - goto out; - } - -out: - mutex_unlock(&wl->mutex); - return ret; -} - -static void wl1251_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1251 *wl = hw->priv; - - mutex_lock(&wl->mutex); - wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); - wl->vif = NULL; - mutex_unlock(&wl->mutex); -} - -static int wl1251_build_qos_null_data(struct wl1251 *wl) -{ - struct ieee80211_qos_hdr template; - - memset(&template, 0, sizeof(template)); - - memcpy(template.addr1, wl->bssid, ETH_ALEN); - memcpy(template.addr2, wl->mac_addr, ETH_ALEN); - memcpy(template.addr3, wl->bssid, ETH_ALEN); - - template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_QOS_NULLFUNC | - IEEE80211_FCTL_TODS); - - /* FIXME: not sure what priority to use here */ - template.qos_ctrl = cpu_to_le16(0); - - return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template, - sizeof(template)); -} - -static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct wl1251 *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - int channel, ret = 0; - - channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - - wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", - channel, - conf->flags & IEEE80211_CONF_PS ? "on" : "off", - conf->power_level); - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (channel != wl->channel) { - wl->channel = channel; - - ret = wl1251_join(wl, wl->bss_type, wl->channel, - wl->beacon_int, wl->dtim_period); - if (ret < 0) - goto out_sleep; - } - - if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl1251_debug(DEBUG_PSM, "psm enabled"); - - wl->psm_requested = true; - - wl->dtim_period = conf->ps_dtim_period; - - ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, - wl->dtim_period); - - /* - * mac80211 enables PSM only if we're already associated. - */ - ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); - if (ret < 0) - goto out_sleep; - } else if (!(conf->flags & IEEE80211_CONF_PS) && - wl->psm_requested) { - wl1251_debug(DEBUG_PSM, "psm disabled"); - - wl->psm_requested = false; - - if (wl->psm) { - ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - goto out_sleep; - } - } - - if (conf->power_level != wl->power_level) { - ret = wl1251_acx_tx_power(wl, conf->power_level); - if (ret < 0) - goto out_sleep; - - wl->power_level = conf->power_level; - } - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_FCSFAIL | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_CONTROL | \ - FIF_OTHER_BSS) - -static void wl1251_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, - unsigned int *total,u64 multicast) -{ - struct wl1251 *wl = hw->priv; - - wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); - - *total &= WL1251_SUPPORTED_FILTERS; - changed &= WL1251_SUPPORTED_FILTERS; - - if (changed == 0) - /* no filters which we support changed */ - return; - - /* FIXME: wl->rx_config and wl->rx_filter are not protected */ - - wl->rx_config = WL1251_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1251_DEFAULT_RX_FILTER; - - if (*total & FIF_PROMISC_IN_BSS) { - wl->rx_config |= CFG_BSSID_FILTER_EN; - wl->rx_config |= CFG_RX_ALL_GOOD; - } - if (*total & FIF_ALLMULTI) - /* - * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive - * all multicast frames - */ - wl->rx_config &= ~CFG_MC_FILTER_EN; - if (*total & FIF_FCSFAIL) - wl->rx_filter |= CFG_RX_FCS_ERROR; - if (*total & FIF_BCN_PRBRESP_PROMISC) { - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - wl->rx_config &= ~CFG_SSID_FILTER_EN; - } - if (*total & FIF_CONTROL) - wl->rx_filter |= CFG_RX_CTL_EN; - if (*total & FIF_OTHER_BSS) - wl->rx_filter &= ~CFG_BSSID_FILTER_EN; - - /* - * FIXME: workqueues need to be properly cancelled on stop(), for - * now let's just disable changing the filter settings. They will - * be updated any on config(). - */ - /* schedule_work(&wl->filter_work); */ -} - -/* HW encryption */ -static int wl1251_set_key_type(struct wl1251 *wl, - struct wl1251_cmd_set_keys *key, - enum set_key_cmd cmd, - struct ieee80211_key_conf *mac80211_key, - const u8 *addr) -{ - switch (mac80211_key->alg) { - case ALG_WEP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_WEP_DEFAULT; - else - key->key_type = KEY_WEP_ADDR; - - mac80211_key->hw_key_idx = mac80211_key->keyidx; - break; - case ALG_TKIP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_TKIP_MIC_GROUP; - else - key->key_type = KEY_TKIP_MIC_PAIRWISE; - - mac80211_key->hw_key_idx = mac80211_key->keyidx; - break; - case ALG_CCMP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_AES_GROUP; - else - key->key_type = KEY_AES_PAIRWISE; - mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - break; - default: - wl1251_error("Unknown key algo 0x%x", mac80211_key->alg); - return -EOPNOTSUPP; - } - - return 0; -} - -static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct wl1251 *wl = hw->priv; - struct wl1251_cmd_set_keys *wl_cmd; - const u8 *addr; - int ret; - - static const u8 bcast_addr[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - wl1251_debug(DEBUG_MAC80211, "mac80211 set key"); - - wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); - if (!wl_cmd) { - ret = -ENOMEM; - goto out; - } - - addr = sta ? sta->addr : bcast_addr; - - wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); - wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); - wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", - key->alg, key->keyidx, key->keylen, key->flags); - wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); - - if (is_zero_ether_addr(addr)) { - /* We dont support TX only encryption */ - ret = -EOPNOTSUPP; - goto out; - } - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - - switch (cmd) { - case SET_KEY: - wl_cmd->key_action = KEY_ADD_OR_REPLACE; - break; - case DISABLE_KEY: - wl_cmd->key_action = KEY_REMOVE; - break; - default: - wl1251_error("Unsupported key cmd 0x%x", cmd); - break; - } - - ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr); - if (ret < 0) { - wl1251_error("Set KEY type failed"); - goto out_sleep; - } - - if (wl_cmd->key_type != KEY_WEP_DEFAULT) - memcpy(wl_cmd->addr, addr, ETH_ALEN); - - if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || - (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { - /* - * We get the key in the following form: - * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) - * but the target is expecting: - * TKIP - RX MIC - TX MIC - */ - memcpy(wl_cmd->key, key->key, 16); - memcpy(wl_cmd->key + 16, key->key + 24, 8); - memcpy(wl_cmd->key + 24, key->key + 16, 8); - - } else { - memcpy(wl_cmd->key, key->key, key->keylen); - } - wl_cmd->key_size = key->keylen; - - wl_cmd->id = key->keyidx; - wl_cmd->ssid_profile = 0; - - wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); - - ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); - if (ret < 0) { - wl1251_warning("could not set keys"); - goto out_sleep; - } - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out_unlock: - mutex_unlock(&wl->mutex); - -out: - kfree(wl_cmd); - - return ret; -} - -static int wl1251_op_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) -{ - struct wl1251 *wl = hw->priv; - struct sk_buff *skb; - size_t ssid_len = 0; - u8 *ssid = NULL; - int ret; - - wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); - - if (req->n_ssids) { - ssid = req->ssids[0].ssid; - ssid_len = req->ssids[0].ssid_len; - } - - mutex_lock(&wl->mutex); - - if (wl->scanning) { - wl1251_debug(DEBUG_SCAN, "scan already in progress"); - ret = -EINVAL; - goto out; - } - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, - req->ie, req->ie_len); - if (!skb) { - ret = -ENOMEM; - goto out; - } - - ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, - skb->len); - dev_kfree_skb(skb); - if (ret < 0) - goto out_sleep; - - ret = wl1251_cmd_trigger_scan_to(wl, 0); - if (ret < 0) - goto out_sleep; - - wl->scanning = true; - - ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, - req->n_channels, WL1251_SCAN_NUM_PROBES); - if (ret < 0) { - wl->scanning = false; - goto out_sleep; - } - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wl1251 *wl = hw->priv; - int ret; - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1251_acx_rts_threshold(wl, (u16) value); - if (ret < 0) - wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret); - - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct wl1251 *wl = hw->priv; - struct sk_buff *beacon, *skb; - int ret; - - wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); - - mutex_lock(&wl->mutex); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (changed & BSS_CHANGED_BSSID) { - memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - - skb = ieee80211_nullfunc_get(wl->hw, wl->vif); - if (!skb) - goto out_sleep; - - ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, - skb->data, skb->len); - dev_kfree_skb(skb); - if (ret < 0) - goto out_sleep; - - ret = wl1251_build_qos_null_data(wl); - if (ret < 0) - goto out; - - if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_join(wl, wl->bss_type, wl->channel, - wl->beacon_int, wl->dtim_period); - if (ret < 0) - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { - wl->beacon_int = bss_conf->beacon_int; - - skb = ieee80211_pspoll_get(wl->hw, wl->vif); - if (!skb) - goto out_sleep; - - ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, - skb->data, - skb->len); - dev_kfree_skb(skb); - if (ret < 0) - goto out_sleep; - - ret = wl1251_acx_aid(wl, bss_conf->aid); - if (ret < 0) - goto out_sleep; - } else { - /* use defaults when not associated */ - wl->beacon_int = WL1251_DEFAULT_BEACON_INT; - wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; - } - } - if (changed & BSS_CHANGED_ERP_SLOT) { - if (bss_conf->use_short_slot) - ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT); - else - ret = wl1251_acx_slot(wl, SLOT_TIME_LONG); - if (ret < 0) { - wl1251_warning("Set slot time failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - if (bss_conf->use_short_preamble) - wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); - else - wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG); - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - if (bss_conf->use_cts_prot) - ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE); - else - ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); - if (ret < 0) { - wl1251_warning("Set ctsprotect failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_BEACON) { - beacon = ieee80211_beacon_get(hw, vif); - ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data, - beacon->len); - - if (ret < 0) { - dev_kfree_skb(beacon); - goto out_sleep; - } - - ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, - beacon->len); - - dev_kfree_skb(beacon); - - if (ret < 0) - goto out_sleep; - - ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, - wl->channel, wl->dtim_period); - - if (ret < 0) - goto out_sleep; - } - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_rate wl1251_rates[] = { - { .bitrate = 10, - .hw_value = 0x1, - .hw_value_short = 0x1, }, - { .bitrate = 20, - .hw_value = 0x2, - .hw_value_short = 0x2, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, - .hw_value = 0x4, - .hw_value_short = 0x4, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, - .hw_value = 0x20, - .hw_value_short = 0x20, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60, - .hw_value = 0x8, - .hw_value_short = 0x8, }, - { .bitrate = 90, - .hw_value = 0x10, - .hw_value_short = 0x10, }, - { .bitrate = 120, - .hw_value = 0x40, - .hw_value_short = 0x40, }, - { .bitrate = 180, - .hw_value = 0x80, - .hw_value_short = 0x80, }, - { .bitrate = 240, - .hw_value = 0x200, - .hw_value_short = 0x200, }, - { .bitrate = 360, - .hw_value = 0x400, - .hw_value_short = 0x400, }, - { .bitrate = 480, - .hw_value = 0x800, - .hw_value_short = 0x800, }, - { .bitrate = 540, - .hw_value = 0x1000, - .hw_value_short = 0x1000, }, -}; - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_channel wl1251_channels[] = { - { .hw_value = 1, .center_freq = 2412}, - { .hw_value = 2, .center_freq = 2417}, - { .hw_value = 3, .center_freq = 2422}, - { .hw_value = 4, .center_freq = 2427}, - { .hw_value = 5, .center_freq = 2432}, - { .hw_value = 6, .center_freq = 2437}, - { .hw_value = 7, .center_freq = 2442}, - { .hw_value = 8, .center_freq = 2447}, - { .hw_value = 9, .center_freq = 2452}, - { .hw_value = 10, .center_freq = 2457}, - { .hw_value = 11, .center_freq = 2462}, - { .hw_value = 12, .center_freq = 2467}, - { .hw_value = 13, .center_freq = 2472}, -}; - -static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - enum wl1251_acx_ps_scheme ps_scheme; - struct wl1251 *wl = hw->priv; - int ret; - - mutex_lock(&wl->mutex); - - wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - /* mac80211 uses units of 32 usec */ - ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop * 32); - if (ret < 0) - goto out_sleep; - - if (params->uapsd) - ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER; - else - ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY; - - ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), - CHANNEL_TYPE_EDCF, - wl1251_tx_get_queue(queue), ps_scheme, - WL1251_ACX_ACK_POLICY_LEGACY); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1251_op_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) -{ - struct wl1251 *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - - if (idx != 0) - return -ENOENT; - - survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = wl->noise; - - return 0; -} - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_supported_band wl1251_band_2ghz = { - .channels = wl1251_channels, - .n_channels = ARRAY_SIZE(wl1251_channels), - .bitrates = wl1251_rates, - .n_bitrates = ARRAY_SIZE(wl1251_rates), -}; - -static const struct ieee80211_ops wl1251_ops = { - .start = wl1251_op_start, - .stop = wl1251_op_stop, - .add_interface = wl1251_op_add_interface, - .remove_interface = wl1251_op_remove_interface, - .config = wl1251_op_config, - .configure_filter = wl1251_op_configure_filter, - .tx = wl1251_op_tx, - .set_key = wl1251_op_set_key, - .hw_scan = wl1251_op_hw_scan, - .bss_info_changed = wl1251_op_bss_info_changed, - .set_rts_threshold = wl1251_op_set_rts_threshold, - .conf_tx = wl1251_op_conf_tx, - .get_survey = wl1251_op_get_survey, -}; - -static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data) -{ - unsigned long timeout; - - wl1251_reg_write32(wl, EE_ADDR, offset); - wl1251_reg_write32(wl, EE_CTL, EE_CTL_READ); - - /* EE_CTL_READ clears when data is ready */ - timeout = jiffies + msecs_to_jiffies(100); - while (1) { - if (!(wl1251_reg_read32(wl, EE_CTL) & EE_CTL_READ)) - break; - - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - - msleep(1); - } - - *data = wl1251_reg_read32(wl, EE_DATA); - return 0; -} - -static int wl1251_read_eeprom(struct wl1251 *wl, off_t offset, - u8 *data, size_t len) -{ - size_t i; - int ret; - - wl1251_reg_write32(wl, EE_START, 0); - - for (i = 0; i < len; i++) { - ret = wl1251_read_eeprom_byte(wl, offset + i, &data[i]); - if (ret < 0) - return ret; - } - - return 0; -} - -static int wl1251_read_eeprom_mac(struct wl1251 *wl) -{ - u8 mac[ETH_ALEN]; - int i, ret; - - wl1251_set_partition(wl, 0, 0, REGISTERS_BASE, REGISTERS_DOWN_SIZE); - - ret = wl1251_read_eeprom(wl, 0x1c, mac, sizeof(mac)); - if (ret < 0) { - wl1251_warning("failed to read MAC address from EEPROM"); - return ret; - } - - /* MAC is stored in reverse order */ - for (i = 0; i < ETH_ALEN; i++) - wl->mac_addr[i] = mac[ETH_ALEN - i - 1]; - - return 0; -} - -static int wl1251_register_hw(struct wl1251 *wl) -{ - int ret; - - if (wl->mac80211_registered) - return 0; - - SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - - ret = ieee80211_register_hw(wl->hw); - if (ret < 0) { - wl1251_error("unable to register mac80211 hw: %d", ret); - return ret; - } - - wl->mac80211_registered = true; - - wl1251_notice("loaded"); - - return 0; -} - -int wl1251_init_ieee80211(struct wl1251 *wl) -{ - int ret; - - /* The tx descriptor buffer and the TKIP space */ - wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) - + WL1251_TKIP_IV_SPACE; - - /* unit us */ - /* FIXME: find a proper value */ - wl->hw->channel_change_time = 10000; - - wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_BEACON_FILTER | - IEEE80211_HW_SUPPORTS_UAPSD; - - wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; - - wl->hw->queues = 4; - - if (wl->use_eeprom) - wl1251_read_eeprom_mac(wl); - - ret = wl1251_register_hw(wl); - if (ret) - goto out; - - wl1251_debugfs_init(wl); - wl1251_notice("initialized"); - - ret = 0; - -out: - return ret; -} -EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); - -struct ieee80211_hw *wl1251_alloc_hw(void) -{ - struct ieee80211_hw *hw; - struct wl1251 *wl; - int i; - static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; - - hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); - if (!hw) { - wl1251_error("could not alloc ieee80211_hw"); - return ERR_PTR(-ENOMEM); - } - - wl = hw->priv; - memset(wl, 0, sizeof(*wl)); - - wl->hw = hw; - - wl->data_in_count = 0; - - skb_queue_head_init(&wl->tx_queue); - - INIT_WORK(&wl->filter_work, wl1251_filter_work); - INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); - wl->channel = WL1251_DEFAULT_CHANNEL; - wl->scanning = false; - wl->default_key = 0; - wl->listen_int = 1; - wl->rx_counter = 0; - wl->rx_handled = 0; - wl->rx_current_buffer = 0; - wl->rx_last_id = 0; - wl->rx_config = WL1251_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1251_DEFAULT_RX_FILTER; - wl->elp = false; - wl->psm = 0; - wl->psm_requested = false; - wl->tx_queue_stopped = false; - wl->power_level = WL1251_DEFAULT_POWER_LEVEL; - wl->beacon_int = WL1251_DEFAULT_BEACON_INT; - wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; - wl->vif = NULL; - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - wl->tx_frames[i] = NULL; - - wl->next_tx_complete = 0; - - INIT_WORK(&wl->irq_work, wl1251_irq_work); - INIT_WORK(&wl->tx_work, wl1251_tx_work); - - /* - * In case our MAC address is not correctly set, - * we use a random but Nokia MAC. - */ - memcpy(wl->mac_addr, nokia_oui, 3); - get_random_bytes(wl->mac_addr + 3, 3); - - wl->state = WL1251_STATE_OFF; - mutex_init(&wl->mutex); - - wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; - wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; - - wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); - if (!wl->rx_descriptor) { - wl1251_error("could not allocate memory for rx descriptor"); - ieee80211_free_hw(hw); - return ERR_PTR(-ENOMEM); - } - - return hw; -} -EXPORT_SYMBOL_GPL(wl1251_alloc_hw); - -int wl1251_free_hw(struct wl1251 *wl) -{ - ieee80211_unregister_hw(wl->hw); - - wl1251_debugfs_exit(wl); - - kfree(wl->target_mem_map); - kfree(wl->data_path); - vfree(wl->fw); - wl->fw = NULL; - kfree(wl->nvs); - wl->nvs = NULL; - - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - - ieee80211_free_hw(wl->hw); - - return 0; -} -EXPORT_SYMBOL_GPL(wl1251_free_hw); - -MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); -MODULE_FIRMWARE(WL1251_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c deleted file mode 100644 index b55cb2bd459..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl1251_reg.h" -#include "wl1251_ps.h" -#include "wl1251_cmd.h" -#include "wl1251_io.h" - -/* in ms */ -#define WL1251_WAKEUP_TIMEOUT 100 - -void wl1251_elp_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1251 *wl; - - dwork = container_of(work, struct delayed_work, work); - wl = container_of(dwork, struct wl1251, elp_work); - - wl1251_debug(DEBUG_PSM, "elp work"); - - mutex_lock(&wl->mutex); - - if (wl->elp || !wl->psm) - goto out; - - wl1251_debug(DEBUG_PSM, "chip to elp"); - wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - wl->elp = true; - -out: - mutex_unlock(&wl->mutex); -} - -#define ELP_ENTRY_DELAY 5 - -/* Routines to toggle sleep mode while in ELP */ -void wl1251_ps_elp_sleep(struct wl1251 *wl) -{ - unsigned long delay; - - if (wl->psm) { - cancel_delayed_work(&wl->elp_work); - delay = msecs_to_jiffies(ELP_ENTRY_DELAY); - ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); - } -} - -int wl1251_ps_elp_wakeup(struct wl1251 *wl) -{ - unsigned long timeout, start; - u32 elp_reg; - - if (!wl->elp) - return 0; - - wl1251_debug(DEBUG_PSM, "waking up chip from elp"); - - start = jiffies; - timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); - - wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); - - elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - - /* - * FIXME: we should wait for irq from chip but, as a temporary - * solution to simplify locking, let's poll instead - */ - while (!(elp_reg & ELPCTRL_WLAN_READY)) { - if (time_after(jiffies, timeout)) { - wl1251_error("elp wakeup timeout"); - return -ETIMEDOUT; - } - msleep(1); - elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - } - - wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", - jiffies_to_msecs(jiffies - start)); - - wl->elp = false; - - return 0; -} - -static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable) -{ - int ret; - - if (enable) { - wl1251_debug(DEBUG_PSM, "sleep auth psm/elp"); - - ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); - if (ret < 0) - return ret; - - wl1251_ps_elp_sleep(wl); - } else { - wl1251_debug(DEBUG_PSM, "sleep auth cam"); - - /* - * When the target is in ELP, we can only - * access the ELP control register. Thus, - * we have to wake the target up before - * changing the power authorization. - */ - - wl1251_ps_elp_wakeup(wl); - - ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); - if (ret < 0) - return ret; - } - - return 0; -} - -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) -{ - int ret; - - switch (mode) { - case STATION_POWER_SAVE_MODE: - wl1251_debug(DEBUG_PSM, "entering psm"); - - /* enable beacon filtering */ - ret = wl1251_acx_beacon_filter_opt(wl, true); - if (ret < 0) - return ret; - - ret = wl1251_acx_wake_up_conditions(wl, - WAKE_UP_EVENT_DTIM_BITMAP, - wl->listen_int); - if (ret < 0) - return ret; - - ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); - if (ret < 0) - return ret; - - ret = wl1251_ps_set_elp(wl, true); - if (ret < 0) - return ret; - - wl->psm = 1; - break; - case STATION_ACTIVE_MODE: - default: - wl1251_debug(DEBUG_PSM, "leaving psm"); - ret = wl1251_ps_set_elp(wl, false); - if (ret < 0) - return ret; - - /* disable beacon filtering */ - ret = wl1251_acx_beacon_filter_opt(wl, false); - if (ret < 0) - return ret; - - ret = wl1251_acx_wake_up_conditions(wl, - WAKE_UP_EVENT_DTIM_BITMAP, - wl->listen_int); - if (ret < 0) - return ret; - - ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - - wl->psm = 0; - break; - } - - return ret; -} - diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h deleted file mode 100644 index c688ac57aee..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_ps.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __WL1251_PS_H__ -#define __WL1251_PS_H__ - -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl1251.h" -#include "wl1251_acx.h" - -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); -void wl1251_ps_elp_sleep(struct wl1251 *wl); -int wl1251_ps_elp_wakeup(struct wl1251 *wl); -void wl1251_elp_work(struct work_struct *work); - - -#endif /* __WL1251_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h deleted file mode 100644 index d16edd9bf06..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_reg.h +++ /dev/null @@ -1,657 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __REG_H__ -#define __REG_H__ - -#include <linux/bitops.h> - -#define REGISTERS_BASE 0x00300000 -#define DRPW_BASE 0x00310000 - -#define REGISTERS_DOWN_SIZE 0x00008800 -#define REGISTERS_WORK_SIZE 0x0000b000 - -#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC - -/* ELP register commands */ -#define ELPCTRL_WAKE_UP 0x1 -#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 -#define ELPCTRL_SLEEP 0x0 -/* ELP WLAN_READY bit */ -#define ELPCTRL_WLAN_READY 0x2 - -/* Device Configuration registers*/ -#define SOR_CFG (REGISTERS_BASE + 0x0800) -#define ECPU_CTRL (REGISTERS_BASE + 0x0804) -#define HI_CFG (REGISTERS_BASE + 0x0808) - -/* EEPROM registers */ -#define EE_START (REGISTERS_BASE + 0x080C) -#define EE_CTL (REGISTERS_BASE + 0x2000) -#define EE_DATA (REGISTERS_BASE + 0x2004) -#define EE_ADDR (REGISTERS_BASE + 0x2008) - -#define EE_CTL_READ 2 - -#define CHIP_ID_B (REGISTERS_BASE + 0x5674) - -#define CHIP_ID_1251_PG10 (0x7010101) -#define CHIP_ID_1251_PG11 (0x7020101) -#define CHIP_ID_1251_PG12 (0x7030101) - -#define ENABLE (REGISTERS_BASE + 0x5450) - -/* Power Management registers */ -#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) -#define ELP_CMD (REGISTERS_BASE + 0x5808) -#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) -#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) -#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) - -#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) - -/* Scratch Pad registers*/ -#define SCR_PAD0 (REGISTERS_BASE + 0x5608) -#define SCR_PAD1 (REGISTERS_BASE + 0x560C) -#define SCR_PAD2 (REGISTERS_BASE + 0x5610) -#define SCR_PAD3 (REGISTERS_BASE + 0x5614) -#define SCR_PAD4 (REGISTERS_BASE + 0x5618) -#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) -#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) -#define SCR_PAD5 (REGISTERS_BASE + 0x5624) -#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) -#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) -#define SCR_PAD6 (REGISTERS_BASE + 0x5630) -#define SCR_PAD7 (REGISTERS_BASE + 0x5634) -#define SCR_PAD8 (REGISTERS_BASE + 0x5638) -#define SCR_PAD9 (REGISTERS_BASE + 0x563C) - -/* Spare registers*/ -#define SPARE_A1 (REGISTERS_BASE + 0x0994) -#define SPARE_A2 (REGISTERS_BASE + 0x0998) -#define SPARE_A3 (REGISTERS_BASE + 0x099C) -#define SPARE_A4 (REGISTERS_BASE + 0x09A0) -#define SPARE_A5 (REGISTERS_BASE + 0x09A4) -#define SPARE_A6 (REGISTERS_BASE + 0x09A8) -#define SPARE_A7 (REGISTERS_BASE + 0x09AC) -#define SPARE_A8 (REGISTERS_BASE + 0x09B0) -#define SPARE_B1 (REGISTERS_BASE + 0x5420) -#define SPARE_B2 (REGISTERS_BASE + 0x5424) -#define SPARE_B3 (REGISTERS_BASE + 0x5428) -#define SPARE_B4 (REGISTERS_BASE + 0x542C) -#define SPARE_B5 (REGISTERS_BASE + 0x5430) -#define SPARE_B6 (REGISTERS_BASE + 0x5434) -#define SPARE_B7 (REGISTERS_BASE + 0x5438) -#define SPARE_B8 (REGISTERS_BASE + 0x543C) - -enum wl12xx_acx_int_reg { - ACX_REG_INTERRUPT_TRIG, - ACX_REG_INTERRUPT_TRIG_H, - -/*============================================= - Host Interrupt Mask Register - 32bit (RW) - ------------------------------------------ - Setting a bit in this register masks the - corresponding interrupt to the host. - 0 - RX0 - Rx first dubble buffer Data Interrupt - 1 - TXD - Tx Data Interrupt - 2 - TXXFR - Tx Transfer Interrupt - 3 - RX1 - Rx second dubble buffer Data Interrupt - 4 - RXXFR - Rx Transfer Interrupt - 5 - EVENT_A - Event Mailbox interrupt - 6 - EVENT_B - Event Mailbox interrupt - 7 - WNONHST - Wake On Host Interrupt - 8 - TRACE_A - Debug Trace interrupt - 9 - TRACE_B - Debug Trace interrupt - 10 - CDCMP - Command Complete Interrupt - 11 - - 12 - - 13 - - 14 - ICOMP - Initialization Complete Interrupt - 16 - SG SE - Soft Gemini - Sense enable interrupt - 17 - SG SD - Soft Gemini - Sense disable interrupt - 18 - - - 19 - - - 20 - - - 21- - - Default: 0x0001 -*==============================================*/ - ACX_REG_INTERRUPT_MASK, - -/*============================================= - Host Interrupt Mask Set 16bit, (Write only) - ------------------------------------------ - Setting a bit in this register sets - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -==============================================*/ - ACX_REG_HINT_MASK_SET, - -/*============================================= - Host Interrupt Mask Clear 16bit,(Write only) - ------------------------------------------ - Setting a bit in this register clears - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -=============================================*/ - ACX_REG_HINT_MASK_CLR, - -/*============================================= - Host Interrupt Status Nondestructive Read - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register doesn't - effect its content. -=============================================*/ - ACX_REG_INTERRUPT_NO_CLEAR, - -/*============================================= - Host Interrupt Status Clear on Read Register - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register clears it, - thus making all interrupts inactive. -==============================================*/ - ACX_REG_INTERRUPT_CLEAR, - -/*============================================= - Host Interrupt Acknowledge Register - 16bit,(Write only) - ------------------------------------------ - The host can set individual bits in this - register to clear (acknowledge) the corresp. - interrupt status bits in the HINT_STS_CLR and - HINT_STS_ND registers, thus making the - assotiated interrupt inactive. (0-no effect) -==============================================*/ - ACX_REG_INTERRUPT_ACK, - -/*=============================================== - Host Software Reset - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 SOFT_RESET Soft Reset - When this bit is set, - it holds the Wlan hardware in a soft reset state. - This reset disables all MAC and baseband processor - clocks except the CardBus/PCI interface clock. - It also initializes all MAC state machines except - the host interface. It does not reload the - contents of the EEPROM. When this bit is cleared - (not self-clearing), the Wlan hardware - exits the software reset state. -===============================================*/ - ACX_REG_SLV_SOFT_RESET, - -/*=============================================== - EEPROM Burst Read Start - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 ACX_EE_START - EEPROM Burst Read Start 0 - Setting this bit starts a burst read from - the external EEPROM. - If this bit is set (after reset) before an EEPROM read/write, - the burst read starts at EEPROM address 0. - Otherwise, it starts at the address - following the address of the previous access. - TheWlan hardware hardware clears this bit automatically. - - Default: 0x00000000 -*================================================*/ - ACX_REG_EE_START, - -/* Embedded ARM CPU Control */ - -/*=============================================== - Halt eCPU - 32bit RW - ------------------------------------------ - 0 HALT_ECPU Halt Embedded CPU - This bit is the - compliment of bit 1 (MDATA2) in the SOR_CFG register. - During a hardware reset, this bit holds - the inverse of MDATA2. - When downloading firmware from the host, - set this bit (pull down MDATA2). - The host clears this bit after downloading the firmware into - zero-wait-state SSRAM. - When loading firmware from Flash, clear this bit (pull up MDATA2) - so that the eCPU can run the bootloader code in Flash - HALT_ECPU eCPU State - -------------------- - 1 halt eCPU - 0 enable eCPU - ===============================================*/ - ACX_REG_ECPU_CONTROL, - - ACX_REG_TABLE_LEN -}; - -#define ACX_SLV_SOFT_RESET_BIT BIT(0) -#define ACX_REG_EEPROM_START_BIT BIT(0) - -/* Command/Information Mailbox Pointers */ - -/*=============================================== - Command Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the command mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to - find the location of the command mailbox. - The Wlan hardware initializes the command mailbox - pointer with the default address of the command mailbox. - The command mailbox pointer is not valid until after - the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) - -/*=============================================== - Information Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the information mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to find - the location of the information mailbox. - The Wlan hardware initializes the information mailbox pointer - with the default address of the information mailbox. - The information mailbox pointer is not valid - until after the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) - - -/* Misc */ - -#define REG_ENABLE_TX_RX (ENABLE) -/* - * Rx configuration (filter) information element - * --------------------------------------------- - */ -#define REG_RX_CONFIG (RX_CFG) -#define REG_RX_FILTER (RX_FILTER_CFG) - - -#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 - -/* promiscuous - receives all valid frames */ -#define RX_CFG_PROMISCUOUS 0x0008 - -/* receives frames from any BSSID */ -#define RX_CFG_BSSID 0x0020 - -/* receives frames destined to any MAC address */ -#define RX_CFG_MAC 0x0010 - -#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 -#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 -#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 -#define RX_CFG_ENABLE_ANY_BSSID 0x0000 - -/* discards all broadcast frames */ -#define RX_CFG_DISABLE_BCAST 0x0200 - -#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 -#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 -#define RX_CFG_COPY_RX_STATUS 0x2000 -#define RX_CFG_TSF 0x10000 - -#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ - | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ - | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) - -#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ - | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) - -#define RX_FILTER_OPTION_FILTER_ALL 0 - -#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ - | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) - -#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ - | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ - | CFG_RX_PRSP_EN) - - -/*=============================================== - EEPROM Read/Write Request 32bit RW - ------------------------------------------ - 1 EE_READ - EEPROM Read Request 1 - Setting this bit - loads a single byte of data into the EE_DATA - register from the EEPROM location specified in - the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. - EE_DATA is valid when this bit is cleared. - - 0 EE_WRITE - EEPROM Write Request - Setting this bit - writes a single byte of data from the EE_DATA register into the - EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. -*===============================================*/ -#define EE_CTL (REGISTERS_BASE + 0x2000) -#define ACX_EE_CTL_REG EE_CTL -#define EE_WRITE 0x00000001ul -#define EE_READ 0x00000002ul - -/*=============================================== - EEPROM Address - 32bit RW - ------------------------------------------ - This register specifies the address - within the EEPROM from/to which to read/write data. - ===============================================*/ -#define EE_ADDR (REGISTERS_BASE + 0x2008) -#define ACX_EE_ADDR_REG EE_ADDR - -/*=============================================== - EEPROM Data - 32bit RW - ------------------------------------------ - This register either holds the read 8 bits of - data from the EEPROM or the write data - to be written to the EEPROM. - ===============================================*/ -#define EE_DATA (REGISTERS_BASE + 0x2004) -#define ACX_EE_DATA_REG EE_DATA - -#define EEPROM_ACCESS_TO 10000 /* timeout counter */ -#define START_EEPROM_MGR 0x00000001 - -/*=============================================== - EEPROM Base Address - 32bit RW - ------------------------------------------ - This register holds the upper nine bits - [23:15] of the 24-bit Wlan hardware memory - address for burst reads from EEPROM accesses. - The EEPROM provides the lower 15 bits of this address. - The MSB of the address from the EEPROM is ignored. - ===============================================*/ -#define ACX_EE_CFG EE_CFG - -/*=============================================== - GPIO Output Values -32bit, RW - ------------------------------------------ - [31:16] Reserved - [15: 0] Specify the output values (at the output driver inputs) for - GPIO[15:0], respectively. - ===============================================*/ -#define ACX_GPIO_OUT_REG GPIO_OUT -#define ACX_MAX_GPIO_LINES 15 - -/*=============================================== - Contention window -32bit, RW - ------------------------------------------ - [31:26] Reserved - [25:16] Max (0x3ff) - [15:07] Reserved - [06:00] Current contention window value - default is 0x1F - ===============================================*/ -#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG -#define ACX_CONT_WIND_MIN_MASK 0x0000007f -#define ACX_CONT_WIND_MAX 0x03ff0000 - -/*=============================================== - HI_CFG Interface Configuration Register Values - ------------------------------------------ - ===============================================*/ -#define HI_CFG_UART_ENABLE 0x00000004 -#define HI_CFG_RST232_ENABLE 0x00000008 -#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 -#define HI_CFG_HOST_INT_ENABLE 0x00000020 -#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 -#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 -#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 -#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 -#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 - -/* - * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile - * for platforms using active high interrupt level - */ -#ifdef USE_ACTIVE_HIGH -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) -#else -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) - -#endif - -#define REF_FREQ_19_2 0 -#define REF_FREQ_26_0 1 -#define REF_FREQ_38_4 2 -#define REF_FREQ_40_0 3 -#define REF_FREQ_33_6 4 -#define REF_FREQ_NUM 5 - -#define LUT_PARAM_INTEGER_DIVIDER 0 -#define LUT_PARAM_FRACTIONAL_DIVIDER 1 -#define LUT_PARAM_ATTN_BB 2 -#define LUT_PARAM_ALPHA_BB 3 -#define LUT_PARAM_STOP_TIME_BB 4 -#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 -#define LUT_PARAM_NUM 6 - -#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) -#define USE_EEPROM 0 -#define SOFT_RESET_MAX_TIME 1000000 -#define SOFT_RESET_STALL_TIME 1000 -#define NVS_DATA_BUNDARY_ALIGNMENT 4 - - -/* Firmware image load chunk size */ -#define CHUNK_SIZE 512 - -/* Firmware image header size */ -#define FW_HDR_SIZE 8 - -#define ECPU_CONTROL_HALT 0x00000101 - - -/****************************************************************************** - - CHANNELS, BAND & REG DOMAINS definitions - -******************************************************************************/ - - -enum { - RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ - RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ - RADIO_BAND_JAPAN_4_9_GHZ = 2, - DEFAULT_BAND = RADIO_BAND_2_4GHZ, - INVALID_BAND = 0xFE, - MAX_RADIO_BANDS = 0xFF -}; - -enum { - NO_RATE = 0, - RATE_1MBPS = 0x0A, - RATE_2MBPS = 0x14, - RATE_5_5MBPS = 0x37, - RATE_6MBPS = 0x0B, - RATE_9MBPS = 0x0F, - RATE_11MBPS = 0x6E, - RATE_12MBPS = 0x0A, - RATE_18MBPS = 0x0E, - RATE_22MBPS = 0xDC, - RATE_24MBPS = 0x09, - RATE_36MBPS = 0x0D, - RATE_48MBPS = 0x08, - RATE_54MBPS = 0x0C -}; - -enum { - RATE_INDEX_1MBPS = 0, - RATE_INDEX_2MBPS = 1, - RATE_INDEX_5_5MBPS = 2, - RATE_INDEX_6MBPS = 3, - RATE_INDEX_9MBPS = 4, - RATE_INDEX_11MBPS = 5, - RATE_INDEX_12MBPS = 6, - RATE_INDEX_18MBPS = 7, - RATE_INDEX_22MBPS = 8, - RATE_INDEX_24MBPS = 9, - RATE_INDEX_36MBPS = 10, - RATE_INDEX_48MBPS = 11, - RATE_INDEX_54MBPS = 12, - RATE_INDEX_MAX = RATE_INDEX_54MBPS, - MAX_RATE_INDEX, - INVALID_RATE_INDEX = MAX_RATE_INDEX, - RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF -}; - -enum { - RATE_MASK_1MBPS = 0x1, - RATE_MASK_2MBPS = 0x2, - RATE_MASK_5_5MBPS = 0x4, - RATE_MASK_11MBPS = 0x20, -}; - -#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ -#define OFDM_RATE_BIT BIT(6) -#define PBCC_RATE_BIT BIT(7) - -enum { - CCK_LONG = 0, - CCK_SHORT = SHORT_PREAMBLE_BIT, - PBCC_LONG = PBCC_RATE_BIT, - PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, - OFDM = OFDM_RATE_BIT -}; - -/****************************************************************************** - -Transmit-Descriptor RATE-SET field definitions... - -Define a new "Rate-Set" for TX path that incorporates the -Rate & Modulation info into a single 16-bit field. - -TxdRateSet_t: -b15 - Indicates Preamble type (1=SHORT, 0=LONG). - Notes: - Must be LONG (0) for 1Mbps rate. - Does not apply (set to 0) for RevG-OFDM rates. -b14 - Indicates PBCC encoding (1=PBCC, 0=not). - Notes: - Does not apply (set to 0) for rates 1 and 2 Mbps. - Does not apply (set to 0) for RevG-OFDM rates. -b13 - Unused (set to 0). -b12-b0 - Supported Rate indicator bits as defined below. - -******************************************************************************/ - - -/************************************************************************* - - Interrupt Trigger Register (Host -> WiLink) - -**************************************************************************/ - -/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ - -/* - * Host Command Interrupt. Setting this bit masks - * the interrupt that the host issues to inform - * the FW that it has sent a command - * to the Wlan hardware Command Mailbox. - */ -#define INTR_TRIG_CMD BIT(0) - -/* - * Host Event Acknowlegde Interrupt. The host - * sets this bit to acknowledge that it received - * the unsolicited information from the event - * mailbox. - */ -#define INTR_TRIG_EVENT_ACK BIT(1) - -/* - * The host sets this bit to inform the Wlan - * FW that a TX packet is in the XFER - * Buffer #0. - */ -#define INTR_TRIG_TX_PROC0 BIT(2) - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #0. - */ -#define INTR_TRIG_RX_PROC0 BIT(3) - -#define INTR_TRIG_DEBUG_ACK BIT(4) - -#define INTR_TRIG_STATE_CHANGED BIT(5) - - -/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #1. - */ -#define INTR_TRIG_RX_PROC1 BIT(17) - -/* - * The host sets this bit to inform the Wlan - * hardware that a TX packet is in the XFER - * Buffer #1. - */ -#define INTR_TRIG_TX_PROC1 BIT(18) - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c deleted file mode 100644 index 1b6294b3b99..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/skbuff.h> -#include <linux/gfp.h> -#include <net/mac80211.h> - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_io.h" -#include "wl1251_rx.h" -#include "wl1251_cmd.h" -#include "wl1251_acx.h" - -static void wl1251_rx_header(struct wl1251 *wl, - struct wl1251_rx_descriptor *desc) -{ - u32 rx_packet_ring_addr; - - rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; - if (wl->rx_current_buffer) - rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - - wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); -} - -static void wl1251_rx_status(struct wl1251 *wl, - struct wl1251_rx_descriptor *desc, - struct ieee80211_rx_status *status, - u8 beacon) -{ - u64 mactime; - int ret; - - memset(status, 0, sizeof(struct ieee80211_rx_status)); - - status->band = IEEE80211_BAND_2GHZ; - status->mactime = desc->timestamp; - - /* - * The rx status timestamp is a 32 bits value while the TSF is a - * 64 bits one. - * For IBSS merging, TSF is mandatory, so we have to get it - * somehow, so we ask for ACX_TSF_INFO. - * That could be moved to the get_tsf() hook, but unfortunately, - * this one must be atomic, while our SPI routines can sleep. - */ - if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { - ret = wl1251_acx_tsf_info(wl, &mactime); - if (ret == 0) - status->mactime = mactime; - } - - status->signal = desc->rssi; - - /* - * FIXME: guessing that snr needs to be divided by two, otherwise - * the values don't make any sense - */ - wl->noise = desc->rssi - desc->snr / 2; - - status->freq = ieee80211_channel_to_frequency(desc->channel); - - status->flag |= RX_FLAG_TSFT; - - if (desc->flags & RX_DESC_ENCRYPTION_MASK) { - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; - - if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) - status->flag |= RX_FLAG_DECRYPTED; - - if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) - status->flag |= RX_FLAG_MMIC_ERROR; - } - - if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) - status->flag |= RX_FLAG_FAILED_FCS_CRC; - - - /* FIXME: set status->rate_idx */ -} - -static void wl1251_rx_body(struct wl1251 *wl, - struct wl1251_rx_descriptor *desc) -{ - struct sk_buff *skb; - struct ieee80211_rx_status status; - u8 *rx_buffer, beacon = 0; - u16 length, *fc; - u32 curr_id, last_id_inc, rx_packet_ring_addr; - - length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); - curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; - last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); - - if (last_id_inc != curr_id) { - wl1251_warning("curr ID:%d, last ID inc:%d", - curr_id, last_id_inc); - wl->rx_last_id = curr_id; - } else { - wl->rx_last_id = last_id_inc; - } - - rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + - sizeof(struct wl1251_rx_descriptor) + 20; - if (wl->rx_current_buffer) - rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - - skb = __dev_alloc_skb(length, GFP_KERNEL); - if (!skb) { - wl1251_error("Couldn't allocate RX frame"); - return; - } - - rx_buffer = skb_put(skb, length); - wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); - - /* The actual lenght doesn't include the target's alignment */ - skb->len = desc->length - PLCP_HEADER_LENGTH; - - fc = (u16 *)skb->data; - - if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) - beacon = 1; - - wl1251_rx_status(wl, desc, &status, beacon); - - wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, - beacon ? "beacon" : ""); - - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx_ni(wl->hw, skb); -} - -static void wl1251_rx_ack(struct wl1251 *wl) -{ - u32 data, addr; - - if (wl->rx_current_buffer) { - addr = ACX_REG_INTERRUPT_TRIG_H; - data = INTR_TRIG_RX_PROC1; - } else { - addr = ACX_REG_INTERRUPT_TRIG; - data = INTR_TRIG_RX_PROC0; - } - - wl1251_reg_write32(wl, addr, data); - - /* Toggle buffer ring */ - wl->rx_current_buffer = !wl->rx_current_buffer; -} - - -void wl1251_rx(struct wl1251 *wl) -{ - struct wl1251_rx_descriptor *rx_desc; - - if (wl->state != WL1251_STATE_ON) - return; - - rx_desc = wl->rx_descriptor; - - /* We first read the frame's header */ - wl1251_rx_header(wl, rx_desc); - - /* Now we can read the body */ - wl1251_rx_body(wl, rx_desc); - - /* Finally, we need to ACK the RX */ - wl1251_rx_ack(wl); -} diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h deleted file mode 100644 index da4e53406a0..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_rx.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_RX_H__ -#define __WL1251_RX_H__ - -#include <linux/bitops.h> - -#include "wl1251.h" - -/* - * RX PATH - * - * The Rx path uses a double buffer and an rx_contro structure, each located - * at a fixed address in the device memory. The host keeps track of which - * buffer is available and alternates between them on a per packet basis. - * The size of each of the two buffers is large enough to hold the longest - * 802.3 packet. - * The RX path goes like that: - * 1) The target generates an interrupt each time a new packet is received. - * There are 2 RX interrupts, one for each buffer. - * 2) The host reads the received packet from one of the double buffers. - * 3) The host triggers a target interrupt. - * 4) The target prepares the next RX packet. - */ - -#define WL1251_RX_MAX_RSSI -30 -#define WL1251_RX_MIN_RSSI -95 - -#define WL1251_RX_ALIGN_TO 4 -#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \ - ~(WL1251_RX_ALIGN_TO - 1)) - -#define SHORT_PREAMBLE_BIT BIT(0) -#define OFDM_RATE_BIT BIT(6) -#define PBCC_RATE_BIT BIT(7) - -#define PLCP_HEADER_LENGTH 8 -#define RX_DESC_PACKETID_SHIFT 11 -#define RX_MAX_PACKET_ID 3 - -#define RX_DESC_VALID_FCS 0x0001 -#define RX_DESC_MATCH_RXADDR1 0x0002 -#define RX_DESC_MCAST 0x0004 -#define RX_DESC_STAINTIM 0x0008 -#define RX_DESC_VIRTUAL_BM 0x0010 -#define RX_DESC_BCAST 0x0020 -#define RX_DESC_MATCH_SSID 0x0040 -#define RX_DESC_MATCH_BSSID 0x0080 -#define RX_DESC_ENCRYPTION_MASK 0x0300 -#define RX_DESC_MEASURMENT 0x0400 -#define RX_DESC_SEQNUM_MASK 0x1800 -#define RX_DESC_MIC_FAIL 0x2000 -#define RX_DESC_DECRYPT_FAIL 0x4000 - -struct wl1251_rx_descriptor { - u32 timestamp; /* In microseconds */ - u16 length; /* Paylod length, including headers */ - u16 flags; - - /* - * 0 - 802.11 - * 1 - 802.3 - * 2 - IP - * 3 - Raw Codec - */ - u8 type; - - /* - * Received Rate: - * 0x0A - 1MBPS - * 0x14 - 2MBPS - * 0x37 - 5_5MBPS - * 0x0B - 6MBPS - * 0x0F - 9MBPS - * 0x6E - 11MBPS - * 0x0A - 12MBPS - * 0x0E - 18MBPS - * 0xDC - 22MBPS - * 0x09 - 24MBPS - * 0x0D - 36MBPS - * 0x08 - 48MBPS - * 0x0C - 54MBPS - */ - u8 rate; - - u8 mod_pre; /* Modulation and preamble */ - u8 channel; - - /* - * 0 - 2.4 Ghz - * 1 - 5 Ghz - */ - u8 band; - - s8 rssi; /* in dB */ - u8 rcpi; /* in dB */ - u8 snr; /* in dB */ -} __packed; - -void wl1251_rx(struct wl1251 *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c deleted file mode 100644 index b901b613565..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * wl12xx SDIO routines - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * Copyright (C) 2005 Texas Instruments Incorporated - * Copyright (C) 2008 Google Inc - * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) - */ -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/sdio_ids.h> -#include <linux/platform_device.h> -#include <linux/spi/wl12xx.h> -#include <linux/irq.h> - -#include "wl1251.h" - -#ifndef SDIO_VENDOR_ID_TI -#define SDIO_VENDOR_ID_TI 0x104c -#endif - -#ifndef SDIO_DEVICE_ID_TI_WL1251 -#define SDIO_DEVICE_ID_TI_WL1251 0x9066 -#endif - -struct wl1251_sdio { - struct sdio_func *func; - u32 elp_val; -}; - -static struct wl12xx_platform_data *wl12xx_board_data; - -static struct sdio_func *wl_to_func(struct wl1251 *wl) -{ - struct wl1251_sdio *wl_sdio = wl->if_priv; - return wl_sdio->func; -} - -static void wl1251_sdio_interrupt(struct sdio_func *func) -{ - struct wl1251 *wl = sdio_get_drvdata(func); - - wl1251_debug(DEBUG_IRQ, "IRQ"); - - /* FIXME should be synchronous for sdio */ - ieee80211_queue_work(wl->hw, &wl->irq_work); -} - -static const struct sdio_device_id wl1251_devices[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) }, - {} -}; -MODULE_DEVICE_TABLE(sdio, wl1251_devices); - - -static void wl1251_sdio_read(struct wl1251 *wl, int addr, - void *buf, size_t len) -{ - int ret; - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - ret = sdio_memcpy_fromio(func, buf, addr, len); - if (ret) - wl1251_error("sdio read failed (%d)", ret); - sdio_release_host(func); -} - -static void wl1251_sdio_write(struct wl1251 *wl, int addr, - void *buf, size_t len) -{ - int ret; - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - ret = sdio_memcpy_toio(func, addr, buf, len); - if (ret) - wl1251_error("sdio write failed (%d)", ret); - sdio_release_host(func); -} - -static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) -{ - int ret = 0; - struct wl1251_sdio *wl_sdio = wl->if_priv; - struct sdio_func *func = wl_sdio->func; - - /* - * The hardware only supports RAW (read after write) access for - * reading, regular sdio_readb won't work here (it interprets - * the unused bits of CMD52 as write data even if we send read - * request). - */ - sdio_claim_host(func); - *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret); - sdio_release_host(func); - - if (ret) - wl1251_error("sdio_readb failed (%d)", ret); -} - -static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) -{ - int ret = 0; - struct wl1251_sdio *wl_sdio = wl->if_priv; - struct sdio_func *func = wl_sdio->func; - - sdio_claim_host(func); - sdio_writeb(func, val, addr, &ret); - sdio_release_host(func); - - if (ret) - wl1251_error("sdio_writeb failed (%d)", ret); - else - wl_sdio->elp_val = val; -} - -static void wl1251_sdio_reset(struct wl1251 *wl) -{ -} - -static void wl1251_sdio_enable_irq(struct wl1251 *wl) -{ - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - sdio_claim_irq(func, wl1251_sdio_interrupt); - sdio_release_host(func); -} - -static void wl1251_sdio_disable_irq(struct wl1251 *wl) -{ - struct sdio_func *func = wl_to_func(wl); - - sdio_claim_host(func); - sdio_release_irq(func); - sdio_release_host(func); -} - -/* Interrupts when using dedicated WLAN_IRQ pin */ -static irqreturn_t wl1251_line_irq(int irq, void *cookie) -{ - struct wl1251 *wl = cookie; - - ieee80211_queue_work(wl->hw, &wl->irq_work); - - return IRQ_HANDLED; -} - -static void wl1251_enable_line_irq(struct wl1251 *wl) -{ - return enable_irq(wl->irq); -} - -static void wl1251_disable_line_irq(struct wl1251 *wl) -{ - return disable_irq(wl->irq); -} - -static void wl1251_sdio_set_power(bool enable) -{ -} - -static struct wl1251_if_operations wl1251_sdio_ops = { - .read = wl1251_sdio_read, - .write = wl1251_sdio_write, - .write_elp = wl1251_sdio_write_elp, - .read_elp = wl1251_sdio_read_elp, - .reset = wl1251_sdio_reset, -}; - -static int wl1251_platform_probe(struct platform_device *pdev) -{ - if (pdev->id != -1) { - wl1251_error("can only handle single device"); - return -ENODEV; - } - - wl12xx_board_data = pdev->dev.platform_data; - return 0; -} - -/* - * Dummy platform_driver for passing platform_data to this driver, - * until we have a way to pass this through SDIO subsystem or - * some other way. - */ -static struct platform_driver wl1251_platform_driver = { - .driver = { - .name = "wl1251_data", - .owner = THIS_MODULE, - }, - .probe = wl1251_platform_probe, -}; - -static int wl1251_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - int ret; - struct wl1251 *wl; - struct ieee80211_hw *hw; - struct wl1251_sdio *wl_sdio; - - hw = wl1251_alloc_hw(); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - wl = hw->priv; - - wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL); - if (wl_sdio == NULL) { - ret = -ENOMEM; - goto out_free_hw; - } - - sdio_claim_host(func); - ret = sdio_enable_func(func); - if (ret) - goto release; - - sdio_set_block_size(func, 512); - sdio_release_host(func); - - SET_IEEE80211_DEV(hw, &func->dev); - wl_sdio->func = func; - wl->if_priv = wl_sdio; - wl->if_ops = &wl1251_sdio_ops; - wl->set_power = wl1251_sdio_set_power; - - if (wl12xx_board_data != NULL) { - wl->set_power = wl12xx_board_data->set_power; - wl->irq = wl12xx_board_data->irq; - wl->use_eeprom = wl12xx_board_data->use_eeprom; - } - - if (wl->irq) { - ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); - if (ret < 0) { - wl1251_error("request_irq() failed: %d", ret); - goto disable; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - disable_irq(wl->irq); - - wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; - wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq; - - wl1251_info("using dedicated interrupt line"); - } else { - wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq; - wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq; - - wl1251_info("using SDIO interrupt"); - } - - ret = wl1251_init_ieee80211(wl); - if (ret) - goto out_free_irq; - - sdio_set_drvdata(func, wl); - return ret; - -out_free_irq: - if (wl->irq) - free_irq(wl->irq, wl); -disable: - sdio_claim_host(func); - sdio_disable_func(func); -release: - sdio_release_host(func); - kfree(wl_sdio); -out_free_hw: - wl1251_free_hw(wl); - return ret; -} - -static void __devexit wl1251_sdio_remove(struct sdio_func *func) -{ - struct wl1251 *wl = sdio_get_drvdata(func); - struct wl1251_sdio *wl_sdio = wl->if_priv; - - if (wl->irq) - free_irq(wl->irq, wl); - kfree(wl_sdio); - wl1251_free_hw(wl); - - sdio_claim_host(func); - sdio_release_irq(func); - sdio_disable_func(func); - sdio_release_host(func); -} - -static struct sdio_driver wl1251_sdio_driver = { - .name = "wl1251_sdio", - .id_table = wl1251_devices, - .probe = wl1251_sdio_probe, - .remove = __devexit_p(wl1251_sdio_remove), -}; - -static int __init wl1251_sdio_init(void) -{ - int err; - - err = platform_driver_register(&wl1251_platform_driver); - if (err) { - wl1251_error("failed to register platform driver: %d", err); - return err; - } - - err = sdio_register_driver(&wl1251_sdio_driver); - if (err) - wl1251_error("failed to register sdio driver: %d", err); - return err; -} - -static void __exit wl1251_sdio_exit(void) -{ - sdio_unregister_driver(&wl1251_sdio_driver); - platform_driver_unregister(&wl1251_platform_driver); - wl1251_notice("unloaded"); -} - -module_init(wl1251_sdio_init); -module_exit(wl1251_sdio_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c deleted file mode 100644 index 27fdfaaeb07..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/irq.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/crc7.h> -#include <linux/spi/spi.h> -#include <linux/spi/wl12xx.h> - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_spi.h" - -static irqreturn_t wl1251_irq(int irq, void *cookie) -{ - struct wl1251 *wl; - - wl1251_debug(DEBUG_IRQ, "IRQ"); - - wl = cookie; - - ieee80211_queue_work(wl->hw, &wl->irq_work); - - return IRQ_HANDLED; -} - -static struct spi_device *wl_to_spi(struct wl1251 *wl) -{ - return wl->if_priv; -} - -static void wl1251_spi_reset(struct wl1251 *wl) -{ - u8 *cmd; - struct spi_transfer t; - struct spi_message m; - - cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); - if (!cmd) { - wl1251_error("could not allocate cmd for spi reset"); - return; - } - - memset(&t, 0, sizeof(t)); - spi_message_init(&m); - - memset(cmd, 0xff, WSPI_INIT_CMD_LEN); - - t.tx_buf = cmd; - t.len = WSPI_INIT_CMD_LEN; - spi_message_add_tail(&t, &m); - - spi_sync(wl_to_spi(wl), &m); - - wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); -} - -static void wl1251_spi_wake(struct wl1251 *wl) -{ - u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; - struct spi_transfer t; - struct spi_message m; - - cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); - if (!cmd) { - wl1251_error("could not allocate cmd for spi init"); - return; - } - - memset(crc, 0, sizeof(crc)); - memset(&t, 0, sizeof(t)); - spi_message_init(&m); - - /* - * Set WSPI_INIT_COMMAND - * the data is being send from the MSB to LSB - */ - cmd[2] = 0xff; - cmd[3] = 0xff; - cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; - cmd[0] = 0; - cmd[7] = 0; - cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; - cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; - - if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) - cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; - else - cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; - - cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS - | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; - - crc[0] = cmd[1]; - crc[1] = cmd[0]; - crc[2] = cmd[7]; - crc[3] = cmd[6]; - crc[4] = cmd[5]; - - cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; - cmd[4] |= WSPI_INIT_CMD_END; - - t.tx_buf = cmd; - t.len = WSPI_INIT_CMD_LEN; - spi_message_add_tail(&t, &m); - - spi_sync(wl_to_spi(wl), &m); - - wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); -} - -static void wl1251_spi_reset_wake(struct wl1251 *wl) -{ - wl1251_spi_reset(wl); - wl1251_spi_wake(wl); -} - -static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, - size_t len) -{ - struct spi_transfer t[3]; - struct spi_message m; - u8 *busy_buf; - u32 *cmd; - - cmd = &wl->buffer_cmd; - busy_buf = wl->buffer_busyword; - - *cmd = 0; - *cmd |= WSPI_CMD_READ; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].tx_buf = cmd; - t[0].len = 4; - spi_message_add_tail(&t[0], &m); - - /* Busy and non busy words read */ - t[1].rx_buf = busy_buf; - t[1].len = WL1251_BUSY_WORD_LEN; - spi_message_add_tail(&t[1], &m); - - t[2].rx_buf = buf; - t[2].len = len; - spi_message_add_tail(&t[2], &m); - - spi_sync(wl_to_spi(wl), &m); - - /* FIXME: check busy words */ - - wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); -} - -static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, - size_t len) -{ - struct spi_transfer t[2]; - struct spi_message m; - u32 *cmd; - - cmd = &wl->buffer_cmd; - - *cmd = 0; - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].tx_buf = cmd; - t[0].len = sizeof(*cmd); - spi_message_add_tail(&t[0], &m); - - t[1].tx_buf = buf; - t[1].len = len; - spi_message_add_tail(&t[1], &m); - - spi_sync(wl_to_spi(wl), &m); - - wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); -} - -static void wl1251_spi_enable_irq(struct wl1251 *wl) -{ - return enable_irq(wl->irq); -} - -static void wl1251_spi_disable_irq(struct wl1251 *wl) -{ - return disable_irq(wl->irq); -} - -static const struct wl1251_if_operations wl1251_spi_ops = { - .read = wl1251_spi_read, - .write = wl1251_spi_write, - .reset = wl1251_spi_reset_wake, - .enable_irq = wl1251_spi_enable_irq, - .disable_irq = wl1251_spi_disable_irq, -}; - -static int __devinit wl1251_spi_probe(struct spi_device *spi) -{ - struct wl12xx_platform_data *pdata; - struct ieee80211_hw *hw; - struct wl1251 *wl; - int ret; - - pdata = spi->dev.platform_data; - if (!pdata) { - wl1251_error("no platform data"); - return -ENODEV; - } - - hw = wl1251_alloc_hw(); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - wl = hw->priv; - - SET_IEEE80211_DEV(hw, &spi->dev); - dev_set_drvdata(&spi->dev, wl); - wl->if_priv = spi; - wl->if_ops = &wl1251_spi_ops; - - /* This is the only SPI value that we need to set here, the rest - * comes from the board-peripherals file */ - spi->bits_per_word = 32; - - ret = spi_setup(spi); - if (ret < 0) { - wl1251_error("spi_setup failed"); - goto out_free; - } - - wl->set_power = pdata->set_power; - if (!wl->set_power) { - wl1251_error("set power function missing in platform data"); - return -ENODEV; - } - - wl->irq = spi->irq; - if (wl->irq < 0) { - wl1251_error("irq missing in platform data"); - return -ENODEV; - } - - wl->use_eeprom = pdata->use_eeprom; - - ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); - if (ret < 0) { - wl1251_error("request_irq() failed: %d", ret); - goto out_free; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - - disable_irq(wl->irq); - - ret = wl1251_init_ieee80211(wl); - if (ret) - goto out_irq; - - return 0; - - out_irq: - free_irq(wl->irq, wl); - - out_free: - ieee80211_free_hw(hw); - - return ret; -} - -static int __devexit wl1251_spi_remove(struct spi_device *spi) -{ - struct wl1251 *wl = dev_get_drvdata(&spi->dev); - - free_irq(wl->irq, wl); - wl1251_free_hw(wl); - - return 0; -} - -static struct spi_driver wl1251_spi_driver = { - .driver = { - .name = DRIVER_NAME, - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - - .probe = wl1251_spi_probe, - .remove = __devexit_p(wl1251_spi_remove), -}; - -static int __init wl1251_spi_init(void) -{ - int ret; - - ret = spi_register_driver(&wl1251_spi_driver); - if (ret < 0) { - wl1251_error("failed to register spi driver: %d", ret); - goto out; - } - -out: - return ret; -} - -static void __exit wl1251_spi_exit(void) -{ - spi_unregister_driver(&wl1251_spi_driver); - - wl1251_notice("unloaded"); -} - -module_init(wl1251_spi_init); -module_exit(wl1251_spi_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); -MODULE_ALIAS("spi:wl1251"); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h deleted file mode 100644 index 2e273a97e7f..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_SPI_H__ -#define __WL1251_SPI_H__ - -#include "wl1251_cmd.h" -#include "wl1251_acx.h" -#include "wl1251_reg.h" - -#define WSPI_CMD_READ 0x40000000 -#define WSPI_CMD_WRITE 0x00000000 -#define WSPI_CMD_FIXED 0x20000000 -#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 -#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 -#define WSPI_CMD_BYTE_ADDR 0x0001FFFF - -#define WSPI_INIT_CMD_CRC_LEN 5 - -#define WSPI_INIT_CMD_START 0x00 -#define WSPI_INIT_CMD_TX 0x40 -/* the extra bypass bit is sampled by the TNET as '1' */ -#define WSPI_INIT_CMD_BYPASS_BIT 0x80 -#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 -#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 -#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 -#define WSPI_INIT_CMD_IOD 0x40 -#define WSPI_INIT_CMD_IP 0x20 -#define WSPI_INIT_CMD_CS 0x10 -#define WSPI_INIT_CMD_WS 0x08 -#define WSPI_INIT_CMD_WSPI 0x01 -#define WSPI_INIT_CMD_END 0x01 - -#define WSPI_INIT_CMD_LEN 8 - -#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ - ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) -#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 - -#endif /* __WL1251_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c deleted file mode 100644 index a38ec199187..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> - -#include "wl1251.h" -#include "wl1251_reg.h" -#include "wl1251_tx.h" -#include "wl1251_ps.h" -#include "wl1251_io.h" - -static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) -{ - int used, data_in_count; - - data_in_count = wl->data_in_count; - - if (data_in_count < data_out_count) - /* data_in_count has wrapped */ - data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; - - used = data_in_count - data_out_count; - - WARN_ON(used < 0); - WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); - - if (used >= DP_TX_PACKET_RING_CHUNK_NUM) - return true; - else - return false; -} - -static int wl1251_tx_path_status(struct wl1251 *wl) -{ - u32 status, addr, data_out_count; - bool busy; - - addr = wl->data_path->tx_control_addr; - status = wl1251_mem_read32(wl, addr); - data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; - busy = wl1251_tx_double_buffer_busy(wl, data_out_count); - - if (busy) - return -EBUSY; - - return 0; -} - -static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb) -{ - int i; - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - if (wl->tx_frames[i] == NULL) { - wl->tx_frames[i] = skb; - return i; - } - - return -EBUSY; -} - -static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr, - struct ieee80211_tx_info *control, u16 fc) -{ - *(u16 *)&tx_hdr->control = 0; - - tx_hdr->control.rate_policy = 0; - - /* 802.11 packets */ - tx_hdr->control.packet_type = 0; - - if (control->flags & IEEE80211_TX_CTL_NO_ACK) - tx_hdr->control.ack_policy = 1; - - tx_hdr->control.tx_complete = 1; - - if ((fc & IEEE80211_FTYPE_DATA) && - ((fc & IEEE80211_STYPE_QOS_DATA) || - (fc & IEEE80211_STYPE_QOS_NULLFUNC))) - tx_hdr->control.qos = 1; -} - -/* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ -#define MAX_MSDU_SECURITY_LENGTH 16 -#define MAX_MPDU_SECURITY_LENGTH 16 -#define WLAN_QOS_HDR_LEN 26 -#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ - WLAN_QOS_HDR_LEN) -#define HW_BLOCK_SIZE 252 -static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) -{ - u16 payload_len, frag_threshold, mem_blocks; - u16 num_mpdus, mem_blocks_per_frag; - - frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); - - payload_len = le16_to_cpu(tx_hdr->length) + MAX_MSDU_SECURITY_LENGTH; - - if (payload_len > frag_threshold) { - mem_blocks_per_frag = - ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / - HW_BLOCK_SIZE) + 1; - num_mpdus = payload_len / frag_threshold; - mem_blocks = num_mpdus * mem_blocks_per_frag; - payload_len -= num_mpdus * frag_threshold; - num_mpdus++; - - } else { - mem_blocks_per_frag = 0; - mem_blocks = 0; - num_mpdus = 1; - } - - mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; - - if (num_mpdus > 1) - mem_blocks += min(num_mpdus, mem_blocks_per_frag); - - tx_hdr->num_mem_blocks = mem_blocks; -} - -static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - struct tx_double_buffer_desc *tx_hdr; - struct ieee80211_rate *rate; - int id; - u16 fc; - - if (!skb) - return -EINVAL; - - id = wl1251_tx_id(wl, skb); - if (id < 0) - return id; - - fc = *(u16 *)skb->data; - tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, - sizeof(*tx_hdr)); - - tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); - rate = ieee80211_get_tx_rate(wl->hw, control); - tx_hdr->rate = cpu_to_le16(rate->hw_value); - tx_hdr->expiry_time = cpu_to_le32(1 << 16); - tx_hdr->id = id; - - tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb)); - - wl1251_tx_control(tx_hdr, control, fc); - wl1251_tx_frag_block_num(tx_hdr); - - return 0; -} - -/* We copy the packet to the target */ -static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - struct tx_double_buffer_desc *tx_hdr; - int len; - u32 addr; - - if (!skb) - return -EINVAL; - - tx_hdr = (struct tx_double_buffer_desc *) skb->data; - - if (control->control.hw_key && - control->control.hw_key->alg == ALG_TKIP) { - int hdrlen; - __le16 fc; - u16 length; - u8 *pos; - - fc = *(__le16 *)(skb->data + sizeof(*tx_hdr)); - length = le16_to_cpu(tx_hdr->length) + WL1251_TKIP_IV_SPACE; - tx_hdr->length = cpu_to_le16(length); - - hdrlen = ieee80211_hdrlen(fc); - - pos = skb_push(skb, WL1251_TKIP_IV_SPACE); - memmove(pos, pos + WL1251_TKIP_IV_SPACE, - sizeof(*tx_hdr) + hdrlen); - } - - /* Revisit. This is a workaround for getting non-aligned packets. - This happens at least with EAPOL packets from the user space. - Our DMA requires packets to be aligned on a 4-byte boundary. - */ - if (unlikely((long)skb->data & 0x03)) { - int offset = (4 - (long)skb->data) & 0x03; - wl1251_debug(DEBUG_TX, "skb offset %d", offset); - - /* check whether the current skb can be used */ - if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { - unsigned char *src = skb->data; - - /* align the buffer on a 4-byte boundary */ - skb_reserve(skb, offset); - memmove(skb->data, src, skb->len); - tx_hdr = (struct tx_double_buffer_desc *) skb->data; - } else { - wl1251_info("No handler, fixme!"); - return -EINVAL; - } - } - - /* Our skb->data at this point includes the HW header */ - len = WL1251_TX_ALIGN(skb->len); - - if (wl->data_in_count & 0x1) - addr = wl->data_path->tx_packet_ring_addr + - wl->data_path->tx_packet_ring_chunk_size; - else - addr = wl->data_path->tx_packet_ring_addr; - - wl1251_mem_write(wl, addr, skb->data, len); - - wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x " - "queue %d", tx_hdr->id, skb, tx_hdr->length, - tx_hdr->rate, tx_hdr->xmit_queue); - - return 0; -} - -static void wl1251_tx_trigger(struct wl1251 *wl) -{ - u32 data, addr; - - if (wl->data_in_count & 0x1) { - addr = ACX_REG_INTERRUPT_TRIG_H; - data = INTR_TRIG_TX_PROC1; - } else { - addr = ACX_REG_INTERRUPT_TRIG; - data = INTR_TRIG_TX_PROC0; - } - - wl1251_reg_write32(wl, addr, data); - - /* Bumping data in */ - wl->data_in_count = (wl->data_in_count + 1) & - TX_STATUS_DATA_OUT_COUNT_MASK; -} - -/* caller must hold wl->mutex */ -static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info; - int ret = 0; - u8 idx; - - info = IEEE80211_SKB_CB(skb); - - if (info->control.hw_key) { - idx = info->control.hw_key->hw_key_idx; - if (unlikely(wl->default_key != idx)) { - ret = wl1251_acx_default_key(wl, idx); - if (ret < 0) - return ret; - } - } - - ret = wl1251_tx_path_status(wl); - if (ret < 0) - return ret; - - ret = wl1251_tx_fill_hdr(wl, skb, info); - if (ret < 0) - return ret; - - ret = wl1251_tx_send_packet(wl, skb, info); - if (ret < 0) - return ret; - - wl1251_tx_trigger(wl); - - return ret; -} - -void wl1251_tx_work(struct work_struct *work) -{ - struct wl1251 *wl = container_of(work, struct wl1251, tx_work); - struct sk_buff *skb; - bool woken_up = false; - int ret; - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1251_STATE_OFF)) - goto out; - - while ((skb = skb_dequeue(&wl->tx_queue))) { - if (!woken_up) { - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - woken_up = true; - } - - ret = wl1251_tx_frame(wl, skb); - if (ret == -EBUSY) { - /* firmware buffer is full, stop queues */ - wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, " - "stop queues"); - ieee80211_stop_queues(wl->hw); - wl->tx_queue_stopped = true; - skb_queue_head(&wl->tx_queue, skb); - goto out; - } else if (ret < 0) { - dev_kfree_skb(skb); - goto out; - } - } - -out: - if (woken_up) - wl1251_ps_elp_sleep(wl); - - mutex_unlock(&wl->mutex); -} - -static const char *wl1251_tx_parse_status(u8 status) -{ - /* 8 bit status field, one character per bit plus null */ - static char buf[9]; - int i = 0; - - memset(buf, 0, sizeof(buf)); - - if (status & TX_DMA_ERROR) - buf[i++] = 'm'; - if (status & TX_DISABLED) - buf[i++] = 'd'; - if (status & TX_RETRY_EXCEEDED) - buf[i++] = 'r'; - if (status & TX_TIMEOUT) - buf[i++] = 't'; - if (status & TX_KEY_NOT_FOUND) - buf[i++] = 'k'; - if (status & TX_ENCRYPT_FAIL) - buf[i++] = 'e'; - if (status & TX_UNAVAILABLE_PRIORITY) - buf[i++] = 'p'; - - /* bit 0 is unused apparently */ - - return buf; -} - -static void wl1251_tx_packet_cb(struct wl1251 *wl, - struct tx_result *result) -{ - struct ieee80211_tx_info *info; - struct sk_buff *skb; - int hdrlen, ret; - u8 *frame; - - skb = wl->tx_frames[result->id]; - if (skb == NULL) { - wl1251_error("SKB for packet %d is NULL", result->id); - return; - } - - info = IEEE80211_SKB_CB(skb); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (result->status == TX_SUCCESS)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.rates[0].count = result->ack_failures + 1; - wl->stats.retry_count += result->ack_failures; - - /* - * We have to remove our private TX header before pushing - * the skb back to mac80211. - */ - frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); - if (info->control.hw_key && - info->control.hw_key->alg == ALG_TKIP) { - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen); - skb_pull(skb, WL1251_TKIP_IV_SPACE); - } - - wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" - " status 0x%x (%s)", - result->id, skb, result->ack_failures, result->rate, - result->status, wl1251_tx_parse_status(result->status)); - - - ieee80211_tx_status(wl->hw, skb); - - wl->tx_frames[result->id] = NULL; - - if (wl->tx_queue_stopped) { - wl1251_debug(DEBUG_TX, "cb: queue was stopped"); - - skb = skb_dequeue(&wl->tx_queue); - - /* The skb can be NULL because tx_work might have been - scheduled before the queue was stopped making the - queue empty */ - - if (skb) { - ret = wl1251_tx_frame(wl, skb); - if (ret == -EBUSY) { - /* firmware buffer is still full */ - wl1251_debug(DEBUG_TX, "cb: fw buffer " - "still full"); - skb_queue_head(&wl->tx_queue, skb); - return; - } else if (ret < 0) { - dev_kfree_skb(skb); - return; - } - } - - wl1251_debug(DEBUG_TX, "cb: waking queues"); - ieee80211_wake_queues(wl->hw); - wl->tx_queue_stopped = false; - } -} - -/* Called upon reception of a TX complete interrupt */ -void wl1251_tx_complete(struct wl1251 *wl) -{ - int i, result_index, num_complete = 0; - struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; - - if (unlikely(wl->state != WL1251_STATE_ON)) - return; - - /* First we read the result */ - wl1251_mem_read(wl, wl->data_path->tx_complete_addr, - result, sizeof(result)); - - result_index = wl->next_tx_complete; - - for (i = 0; i < ARRAY_SIZE(result); i++) { - result_ptr = &result[result_index]; - - if (result_ptr->done_1 == 1 && - result_ptr->done_2 == 1) { - wl1251_tx_packet_cb(wl, result_ptr); - - result_ptr->done_1 = 0; - result_ptr->done_2 = 0; - - result_index = (result_index + 1) & - (FW_TX_CMPLT_BLOCK_SIZE - 1); - num_complete++; - } else { - break; - } - } - - /* Every completed frame needs to be acknowledged */ - if (num_complete) { - /* - * If we've wrapped, we have to clear - * the results in 2 steps. - */ - if (result_index > wl->next_tx_complete) { - /* Only 1 write is needed */ - wl1251_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - num_complete * - sizeof(struct tx_result)); - - - } else if (result_index < wl->next_tx_complete) { - /* 2 writes are needed */ - wl1251_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - (FW_TX_CMPLT_BLOCK_SIZE - - wl->next_tx_complete) * - sizeof(struct tx_result)); - - wl1251_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - (num_complete - - FW_TX_CMPLT_BLOCK_SIZE + - wl->next_tx_complete) * - sizeof(struct tx_result)); - - } else { - /* We have to write the whole array */ - wl1251_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - FW_TX_CMPLT_BLOCK_SIZE * - sizeof(struct tx_result)); - } - - } - - wl->next_tx_complete = result_index; -} - -/* caller must hold wl->mutex */ -void wl1251_tx_flush(struct wl1251 *wl) -{ - int i; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - - /* TX failure */ -/* control->flags = 0; FIXME */ - - while ((skb = skb_dequeue(&wl->tx_queue))) { - info = IEEE80211_SKB_CB(skb); - - wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb); - - if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) - continue; - - ieee80211_tx_status(wl->hw, skb); - } - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - if (wl->tx_frames[i] != NULL) { - skb = wl->tx_frames[i]; - info = IEEE80211_SKB_CB(skb); - - if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) - continue; - - ieee80211_tx_status(wl->hw, skb); - wl->tx_frames[i] = NULL; - } -} diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h deleted file mode 100644 index f40eeb37f5a..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_tx.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo <kalle.valo@nokia.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_TX_H__ -#define __WL1251_TX_H__ - -#include <linux/bitops.h> -#include "wl1251_acx.h" - -/* - * - * TX PATH - * - * The Tx path uses a double buffer and a tx_control structure, each located - * at a fixed address in the device's memory. On startup, the host retrieves - * the pointers to these addresses. A double buffer allows for continuous data - * flow towards the device. The host keeps track of which buffer is available - * and alternates between these two buffers on a per packet basis. - * - * The size of each of the two buffers is large enough to hold the longest - * 802.3 packet - maximum size Ethernet packet + header + descriptor. - * TX complete indication will be received a-synchronously in a TX done cyclic - * buffer which is composed of 16 tx_result descriptors structures and is used - * in a cyclic manner. - * - * The TX (HOST) procedure is as follows: - * 1. Read the Tx path status, that will give the data_out_count. - * 2. goto 1, if not possible. - * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double - * buffer). - * 3. Copy the packet (preceded by double_buffer_desc), if possible. - * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double - * buffer). - * 4. increment data_in_count. - * 5. Inform the firmware by generating a firmware internal interrupt. - * 6. FW will increment data_out_count after it reads the buffer. - * - * The TX Complete procedure: - * 1. To get a TX complete indication the host enables the tx_complete flag in - * the TX descriptor Structure. - * 2. For each packet with a Tx Complete field set, the firmware adds the - * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 - * and done_2 to 1 to indicate driver ownership. - * 3. The firmware sends a Tx Complete interrupt to the host to trigger the - * host to process the new data. Note: interrupt will be send per packet if - * TX complete indication was requested in tx_control or per crossing - * aggregation threshold. - * 4. After receiving the Tx Complete interrupt, the host reads the - * TxDescriptorDone information in a cyclic manner and clears both done_1 - * and done_2 fields. - * - */ - -#define TX_COMPLETE_REQUIRED_BIT 0x80 -#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf - -#define WL1251_TX_ALIGN_TO 4 -#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \ - ~(WL1251_TX_ALIGN_TO - 1)) -#define WL1251_TKIP_IV_SPACE 4 - -struct tx_control { - /* Rate Policy (class) index */ - unsigned rate_policy:3; - - /* When set, no ack policy is expected */ - unsigned ack_policy:1; - - /* - * Packet type: - * 0 -> 802.11 - * 1 -> 802.3 - * 2 -> IP - * 3 -> raw codec - */ - unsigned packet_type:2; - - /* If set, this is a QoS-Null or QoS-Data frame */ - unsigned qos:1; - - /* - * If set, the target triggers the tx complete INT - * upon frame sending completion. - */ - unsigned tx_complete:1; - - /* 2 bytes padding before packet header */ - unsigned xfer_pad:1; - - unsigned reserved:7; -} __packed; - - -struct tx_double_buffer_desc { - /* Length of payload, including headers. */ - __le16 length; - - /* - * A bit mask that specifies the initial rate to be used - * Possible values are: - * 0x0001 - 1Mbits - * 0x0002 - 2Mbits - * 0x0004 - 5.5Mbits - * 0x0008 - 6Mbits - * 0x0010 - 9Mbits - * 0x0020 - 11Mbits - * 0x0040 - 12Mbits - * 0x0080 - 18Mbits - * 0x0100 - 22Mbits - * 0x0200 - 24Mbits - * 0x0400 - 36Mbits - * 0x0800 - 48Mbits - * 0x1000 - 54Mbits - */ - __le16 rate; - - /* Time in us that a packet can spend in the target */ - __le32 expiry_time; - - /* index of the TX queue used for this packet */ - u8 xmit_queue; - - /* Used to identify a packet */ - u8 id; - - struct tx_control control; - - /* - * The FW should cut the packet into fragments - * of this size. - */ - __le16 frag_threshold; - - /* Numbers of HW queue blocks to be allocated */ - u8 num_mem_blocks; - - u8 reserved; -} __packed; - -enum { - TX_SUCCESS = 0, - TX_DMA_ERROR = BIT(7), - TX_DISABLED = BIT(6), - TX_RETRY_EXCEEDED = BIT(5), - TX_TIMEOUT = BIT(4), - TX_KEY_NOT_FOUND = BIT(3), - TX_ENCRYPT_FAIL = BIT(2), - TX_UNAVAILABLE_PRIORITY = BIT(1), -}; - -struct tx_result { - /* - * Ownership synchronization between the host and - * the firmware. If done_1 and done_2 are cleared, - * owned by the FW (no info ready). - */ - u8 done_1; - - /* same as double_buffer_desc->id */ - u8 id; - - /* - * Total air access duration consumed by this - * packet, including all retries and overheads. - */ - u16 medium_usage; - - /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ - u32 medium_delay; - - /* Time between host xfer and tx complete */ - u32 fw_hnadling_time; - - /* The LS-byte of the last TKIP sequence number. */ - u8 lsb_seq_num; - - /* Retry count */ - u8 ack_failures; - - /* At which rate we got a ACK */ - u16 rate; - - u16 reserved; - - /* TX_* */ - u8 status; - - /* See done_1 */ - u8 done_2; -} __packed; - -static inline int wl1251_tx_get_queue(int queue) -{ - switch (queue) { - case 0: - return QOS_AC_VO; - case 1: - return QOS_AC_VI; - case 2: - return QOS_AC_BE; - case 3: - return QOS_AC_BK; - default: - return QOS_AC_BE; - } -} - -void wl1251_tx_work(struct work_struct *work); -void wl1251_tx_complete(struct wl1251 *wl); -void wl1251_tx_flush(struct wl1251 *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index dd3cee6ea5b..8a4cd763e5a 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -117,10 +117,7 @@ enum { #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) -/* - * Enable/disable 802.11a support for WL1273 - */ -#undef WL1271_80211A_ENABLED +#define WL1271_CIPHER_SUITE_GEM 0x00147201 #define WL1271_BUSY_WORD_CNT 1 #define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) @@ -133,6 +130,8 @@ enum { #define ACX_TX_DESCRIPTORS 32 +#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) + enum wl1271_state { WL1271_STATE_OFF, WL1271_STATE_ON, @@ -301,6 +300,7 @@ struct wl1271_rx_mem_pool_addr { struct wl1271_scan { struct cfg80211_scan_request *req; bool *scanned_ch; + bool failed; u8 state; u8 ssid[IW_ESSID_MAX_SIZE+1]; size_t ssid_len; @@ -313,7 +313,7 @@ struct wl1271_if_operations { bool fixed); void (*reset)(struct wl1271 *wl); void (*init)(struct wl1271 *wl); - void (*power)(struct wl1271 *wl, bool enable); + int (*power)(struct wl1271 *wl, bool enable); struct device* (*dev)(struct wl1271 *wl); void (*enable_irq)(struct wl1271 *wl); void (*disable_irq)(struct wl1271 *wl); @@ -330,6 +330,7 @@ struct wl1271 { void (*set_power)(bool enable); int irq; + int ref_clock; spinlock_t wl_lock; @@ -349,6 +350,7 @@ struct wl1271 { #define WL1271_FLAG_IDLE (10) #define WL1271_FLAG_IDLE_REQUESTED (11) #define WL1271_FLAG_PSPOLL_FAILURE (12) +#define WL1271_FLAG_STA_STATE_SENT (13) unsigned long flags; struct wl1271_partition_set part; @@ -361,6 +363,7 @@ struct wl1271 { u8 *fw; size_t fw_len; struct wl1271_nvs_file *nvs; + size_t nvs_len; s8 hw_pg_ver; @@ -407,9 +410,15 @@ struct wl1271 { /* Rx memory pool address */ struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; + /* Intermediate buffer, used for packet aggregation */ + u8 *aggr_buf; + /* The target interrupt mask */ struct work_struct irq_work; + /* Hardware recovery work */ + struct work_struct recovery_work; + /* The mbox event mask */ u32 event_mask; @@ -418,6 +427,7 @@ struct wl1271 { /* Are we currently scanning */ struct wl1271_scan scan; + struct delayed_work scan_complete_work; /* Our association ID */ u16 aid; @@ -474,6 +484,8 @@ struct wl1271 { bool sg_enabled; + bool enable_11a; + struct list_head list; /* Most recently reported noise in dBm */ @@ -497,14 +509,4 @@ int wl1271_plt_stop(struct wl1271 *wl); #define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ -static inline bool wl1271_11a_enabled(void) -{ - /* FIXME: this could be determined based on the NVS-INI file */ -#ifdef WL1271_80211A_ENABLED - return true; -#else - return false; -#endif -} - #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index bb245f05af4..61899340526 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -86,40 +86,6 @@ out: return ret; } -int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len) -{ - struct acx_revision *rev; - int ret; - - wl1271_debug(DEBUG_ACX, "acx fw rev"); - - rev = kzalloc(sizeof(*rev), GFP_KERNEL); - if (!rev) { - ret = -ENOMEM; - goto out; - } - - ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); - if (ret < 0) { - wl1271_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - /* be careful with the buffer sizes */ - strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); - - /* - * if the firmware version string is exactly - * sizeof(rev->fw_version) long or fw_len is less than - * sizeof(rev->fw_version) it won't be null terminated - */ - buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; - -out: - kfree(rev); - return ret; -} - int wl1271_acx_tx_power(struct wl1271 *wl, int power) { struct acx_current_tx_power *acx; @@ -269,7 +235,7 @@ int wl1271_acx_pd_threshold(struct wl1271 *wl) out: kfree(pd); - return 0; + return ret; } int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 4235bc56f75..ebb341d36e8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -100,35 +100,6 @@ struct acx_error_counter { __le32 seq_num_miss; } __packed; -struct acx_revision { - struct acx_header header; - - /* - * The WiLink firmware version, an ASCII string x.x.x.x, - * that uniquely identifies the current firmware. - * The left most digit is incremented each time a - * significant change is made to the firmware, such as - * code redesign or new platform support. - * The second digit is incremented when major enhancements - * are added or major fixes are made. - * The third digit is incremented for each GA release. - * The fourth digit is incremented for each build. - * The first two digits identify a firmware release version, - * in other words, a unique set of features. - * The first three digits identify a GA release. - */ - char fw_version[20]; - - /* - * This 4 byte field specifies the WiLink hardware version. - * bits 0 - 15: Reserved. - * bits 16 - 23: Version ID - The WiLink version ID - * (1 = first spin, 2 = second spin, and so on). - * bits 24 - 31: Chip ID - The WiLink chip ID. - */ - __le32 hw_version; -} __packed; - enum wl1271_psm_mode { /* Active mode */ WL1271_PSM_CAM = 0, @@ -1060,7 +1031,6 @@ enum { ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, - ACX_SET_SMART_REFLEX_DEBUG = 0x005A, ACX_SET_DCO_ITRIM_PARAMS = 0x0061, DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_CUR_TX_PWR = 0x100D, @@ -1077,7 +1047,6 @@ enum { int wl1271_acx_wake_up_conditions(struct wl1271 *wl); int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); -int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len); int wl1271_acx_tx_power(struct wl1271 *wl, int power); int wl1271_acx_feature_cfg(struct wl1271 *wl); int wl1271_acx_mem_map(struct wl1271 *wl, diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index f36430b0336..b9102124209 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -225,6 +225,28 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) if (wl->nvs == NULL) return -ENODEV; + /* + * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band + * configurations) can be removed when those NVS files stop floating + * around. + */ + if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || + wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { + if (wl->nvs->general_params.dual_mode_select) + wl->enable_11a = true; + } + + if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && + (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || + wl->enable_11a)) { + wl1271_error("nvs size is not as expected: %zu != %zu", + wl->nvs_len, sizeof(struct wl1271_nvs_file)); + kfree(wl->nvs); + wl->nvs = NULL; + wl->nvs_len = 0; + return -EILSEQ; + } + /* only the first part of the NVS needs to be uploaded */ nvs_len = sizeof(wl->nvs->nvs); nvs_ptr = (u8 *)wl->nvs->nvs; @@ -251,8 +273,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) burst_len = nvs_ptr[0]; dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - /* FIXME: Due to our new wl1271_translate_reg_addr function, - we need to add the REGISTER_BASE to the destination */ + /* + * Due to our new wl1271_translate_reg_addr function, + * we need to add the REGISTER_BASE to the destination + */ dest_addr += REGISTERS_BASE; /* We move our pointer to the data */ @@ -274,31 +298,21 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) /* * We've reached the first zero length, the first NVS table - * is 7 bytes further. + * is located at an aligned offset which is at least 7 bytes further. */ - nvs_ptr += 7; + nvs_ptr = (u8 *)wl->nvs->nvs + + ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; - nvs_len = ALIGN(nvs_len, 4); - /* FIXME: The driver sets the partition here, but this is not needed, - since it sets to the same one as currently in use */ /* Now we must set the partition correctly */ wl1271_set_partition(wl, &part_table[PART_WORK]); /* Copy the NVS tables to a new block to ensure alignment */ - /* FIXME: We jump 3 more bytes before uploading the NVS. It seems - that our NVS files have three extra zeros here. I'm not sure whether - the problem is in our NVS generation or we should really jumpt these - 3 bytes here */ - nvs_ptr += 3; - - nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if - (!nvs_aligned) return -ENOMEM; + nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); + if (!nvs_aligned) + return -ENOMEM; /* And finally we upload the NVS tables */ - /* FIXME: In wl1271, we upload everything at once. - No endianness handling needed here?! The ref driver doesn't do - anything about it at this point */ wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); kfree(nvs_aligned); @@ -457,17 +471,20 @@ int wl1271_boot(struct wl1271 *wl) { int ret = 0; u32 tmp, clk, pause; + int ref_clock = wl->ref_clock; wl1271_boot_hw_version(wl); - if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4) + if (ref_clock == 0 || ref_clock == 2 || ref_clock == 4) /* ref clk: 19.2/38.4/38.4-XTAL */ clk = 0x3; - else if (REF_CLOCK == 1 || REF_CLOCK == 3) + else if (ref_clock == 1 || ref_clock == 3) /* ref clk: 26/52 */ clk = 0x5; + else + return -EINVAL; - if (REF_CLOCK != 0) { + if (ref_clock != 0) { u16 val; /* Set clock type (open drain) */ val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); @@ -493,10 +510,7 @@ int wl1271_boot(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); - pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be - * WU_COUNTER_PAUSE_VAL instead of - * 0x3ff (magic number ). How does - * this work?! */ + pause &= ~(WU_COUNTER_PAUSE_VAL); pause |= WU_COUNTER_PAUSE_VAL; wl1271_write32(wl, WU_COUNTER_PAUSE, pause); @@ -516,7 +530,7 @@ int wl1271_boot(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); /* 2 */ - clk |= (REF_CLOCK << 1) << 4; + clk |= (ref_clock << 1) << 4; wl1271_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); @@ -550,7 +564,6 @@ int wl1271_boot(struct wl1271 *wl) if (ret < 0) goto out; - /* FIXME: Need to check whether this is really what we want */ wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR); diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h index f829699d597..f73b0b15a28 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.h +++ b/drivers/net/wireless/wl12xx/wl1271_boot.h @@ -46,7 +46,6 @@ struct wl1271_static_data { /* delay between retries */ #define INIT_LOOP_DELAY 50 -#define REF_CLOCK 2 #define WU_COUNTER_PAUSE_VAL 0x3FF #define WELP_ARM_COMMAND_VAL 0x4 diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index ce503ddd5a4..5d3e8485ea4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, status = le16_to_cpu(cmd->status); if (status != CMD_STATUS_SUCCESS) { wl1271_error("command execute failure %d", status); + ieee80211_queue_work(wl->hw, &wl->recovery_work); ret = -EIO; } @@ -107,6 +108,8 @@ out: int wl1271_cmd_general_parms(struct wl1271 *wl) { struct wl1271_general_parms_cmd *gen_parms; + struct wl1271_ini_general_params *gp = &wl->nvs->general_params; + bool answer = false; int ret; if (!wl->nvs) @@ -118,13 +121,24 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; - memcpy(&gen_parms->general_params, &wl->nvs->general_params, - sizeof(struct wl1271_ini_general_params)); + memcpy(&gen_parms->general_params, gp, sizeof(*gp)); - ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); - if (ret < 0) + if (gp->tx_bip_fem_auto_detect) + answer = true; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); + if (ret < 0) { wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + goto out; + } + + gp->tx_bip_fem_manufacturer = + gen_parms->general_params.tx_bip_fem_manufacturer; + + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", + answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); +out: kfree(gen_parms); return ret; } @@ -170,6 +184,39 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) return ret; } +int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) +{ + struct wl1271_ext_radio_parms_cmd *ext_radio_parms; + struct conf_rf_settings *rf = &wl->conf.rf; + int ret; + + if (!wl->nvs) + return -ENODEV; + + ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); + if (!ext_radio_parms) + return -ENOMEM; + + ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; + + memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, + rf->tx_per_channel_power_compensation_2, + CONF_TX_PWR_COMPENSATION_LEN_2); + memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, + rf->tx_per_channel_power_compensation_5, + CONF_TX_PWR_COMPENSATION_LEN_5); + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", + ext_radio_parms, sizeof(*ext_radio_parms)); + + ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); + + kfree(ext_radio_parms); + return ret; +} + /* * Poll the mailbox event field until any of the bits in the mask is set or a * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) @@ -182,8 +229,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); do { - if (time_after(jiffies, timeout)) + if (time_after(jiffies, timeout)) { + ieee80211_queue_work(wl->hw, &wl->recovery_work); return -ETIMEDOUT; + } msleep(1); @@ -390,18 +439,11 @@ out: return ret; } -int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send) { struct wl1271_cmd_ps_params *ps_params = NULL; int ret = 0; - /* FIXME: this should be in ps.c */ - ret = wl1271_acx_wake_up_conditions(wl); - if (ret < 0) { - wl1271_error("couldn't set wake up conditions"); - goto out; - } - wl1271_debug(DEBUG_CMD, "cmd set ps mode"); ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); @@ -412,9 +454,9 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) ps_params->ps_mode = ps_mode; ps_params->send_null_data = send; - ps_params->retries = 5; - ps_params->hang_over_period = 1; - ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set); + ps_params->retries = wl->conf.conn.psm_entry_nullfunc_retries; + ps_params->hang_over_period = wl->conf.conn.psm_entry_hangover_period; + ps_params->null_data_rate = cpu_to_le32(rates); ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, sizeof(*ps_params), 0); @@ -428,41 +470,6 @@ out: return ret; } -int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, - size_t len) -{ - struct cmd_read_write_memory *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd read memory"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - WARN_ON(len > MAX_READ_SIZE); - len = min_t(size_t, len, MAX_READ_SIZE); - - cmd->addr = cpu_to_le32(addr); - cmd->size = cpu_to_le32(len); - - ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd), - sizeof(*cmd)); - if (ret < 0) { - wl1271_error("read memory command failed: %d", ret); - goto out; - } - - /* the read command got in */ - memcpy(answer, cmd->value, len); - -out: - kfree(cmd); - return ret; -} - int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, void *buf, size_t buf_len, int index, u32 rates) { @@ -523,7 +530,7 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl) } ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, - WL1271_RATE_AUTOMATIC); + wl->basic_rate); out: dev_kfree_skb(skb); @@ -546,7 +553,7 @@ int wl1271_cmd_build_klv_null_data(struct wl1271 *wl) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, skb->data, skb->len, CMD_TEMPL_KLV_IDX_NULL_DATA, - WL1271_RATE_AUTOMATIC); + wl->basic_rate); out: dev_kfree_skb(skb); @@ -623,7 +630,7 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, sizeof(template), 0, - WL1271_RATE_AUTOMATIC); + wl->basic_rate); } int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) @@ -746,3 +753,31 @@ out_free: out: return ret; } + +int wl1271_cmd_set_sta_state(struct wl1271 *wl) +{ + struct wl1271_cmd_set_sta_state *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set sta state"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->state = WL1271_CMD_STA_STATE_CONNECTED; + + ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send set STA state command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index af577ee8eb0..a0caf4fc37b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -33,12 +33,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len); int wl1271_cmd_general_parms(struct wl1271 *wl); int wl1271_cmd_radio_parms(struct wl1271 *wl); +int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); -int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send); +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send); int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, size_t len); int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, @@ -55,6 +56,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16); int wl1271_cmd_disconnect(struct wl1271 *wl); +int wl1271_cmd_set_sta_state(struct wl1271 *wl); enum wl1271_commands { CMD_INTERROGATE = 1, /*use this to read information elements*/ @@ -160,41 +162,6 @@ enum { MAX_COMMAND_STATUS = 0xff }; - -/* - * CMD_READ_MEMORY - * - * The host issues this command to read the WiLink device memory/registers. - * - * Note: The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -/* - * CMD_WRITE_MEMORY - * - * The host issues this command to write the WiLink device memory/registers. - * - * The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -#define MAX_READ_SIZE 256 - -struct cmd_read_write_memory { - struct wl1271_cmd_header header; - - /* The address of the memory to read from or write to.*/ - __le32 addr; - - /* The amount of data in bytes to read from or write to the WiLink - * device.*/ - __le32 size; - - /* The actual value read from or written to the Wilink. The source - of this field is the Host in WRITE command or the Wilink in READ - command. */ - u8 value[MAX_READ_SIZE]; -} __packed; - #define CMDMBOX_HEADER_LEN 4 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 @@ -313,7 +280,7 @@ enum wl1271_cmd_key_type { KEY_WEP = 1, KEY_TKIP = 2, KEY_AES = 3, - KEY_GEM = 4 + KEY_GEM = 4, }; /* FIXME: Add description for key-types */ @@ -358,13 +325,14 @@ enum wl1271_channel_tune_bands { WL1271_CHANNEL_TUNE_BAND_4_9 }; -#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 +#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 -#define TEST_CMD_P2G_CAL 0x02 -#define TEST_CMD_CHANNEL_TUNE 0x0d -#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d -#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 -#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E +#define TEST_CMD_P2G_CAL 0x02 +#define TEST_CMD_CHANNEL_TUNE 0x0d +#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d +#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 +#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E +#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26 struct wl1271_general_parms_cmd { struct wl1271_cmd_header header; @@ -397,6 +365,16 @@ struct wl1271_radio_parms_cmd { u8 padding3[2]; } __packed; +struct wl1271_ext_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; + u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; + u8 padding[3]; +} __packed; + struct wl1271_cmd_cal_channel_tune { struct wl1271_cmd_header header; @@ -469,4 +447,13 @@ struct wl1271_cmd_disconnect { u8 padding; } __packed; +#define WL1271_CMD_STA_STATE_CONNECTED 1 + +struct wl1271_cmd_set_sta_state { + struct wl1271_cmd_header header; + + u8 state; + u8 padding[3]; +} __packed; + #endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 0435ffda8f7..5f78a6cb143 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -595,7 +595,7 @@ struct conf_tx_ac_category { u16 tx_op_limit; }; -#define CONF_TX_MAX_TID_COUNT 7 +#define CONF_TX_MAX_TID_COUNT 8 enum { CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ @@ -912,6 +912,22 @@ struct conf_conn_settings { u8 psm_entry_retries; /* + * Specifies the maximum number of times to try transmit the PSM entry + * null-func frame for each PSM entry attempt + * + * Range 0 - 255 + */ + u8 psm_entry_nullfunc_retries; + + /* + * Specifies the time to linger in active mode after successfully + * transmitting the PSM entry null-func frame. + * + * Range 0 - 255 TU's + */ + u8 psm_entry_hangover_period; + + /* * * Specifies the interval of the connection keep-alive null-func * frame in ms. @@ -1016,6 +1032,64 @@ struct conf_roam_trigger_settings { u8 avg_weight_snr_data; }; +struct conf_scan_settings { + /* + * The minimum time to wait on each channel for active scans + * + * Range: 0 - 65536 tu + */ + u16 min_dwell_time_active; + + /* + * The maximum time to wait on each channel for active scans + * + * Range: 0 - 65536 tu + */ + u16 max_dwell_time_active; + + /* + * The maximum time to wait on each channel for passive scans + * + * Range: 0 - 65536 tu + */ + u16 min_dwell_time_passive; + + /* + * The maximum time to wait on each channel for passive scans + * + * Range: 0 - 65536 tu + */ + u16 max_dwell_time_passive; + + /* + * Number of probe requests to transmit on each active scan channel + * + * Range: u8 + */ + u16 num_probe_reqs; + +}; + +/* these are number of channels on the band divided by two, rounded up */ +#define CONF_TX_PWR_COMPENSATION_LEN_2 7 +#define CONF_TX_PWR_COMPENSATION_LEN_5 18 + +struct conf_rf_settings { + /* + * Per channel power compensation for 2.4GHz + * + * Range: s8 + */ + u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; + + /* + * Per channel power compensation for 5GHz + * + * Range: s8 + */ + u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1024,6 +1098,8 @@ struct conf_drv_settings { struct conf_itrim_settings itrim; struct conf_pm_config_settings pm_config; struct conf_roam_trigger_settings roam_trigger; + struct conf_scan_settings scan; + struct conf_rf_settings rf; }; #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 25ce2cd5e3f..7b3f5038296 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -41,6 +41,9 @@ void wl1271_pspoll_work(struct work_struct *work) mutex_lock(&wl->mutex); + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags)) goto out; @@ -52,7 +55,7 @@ void wl1271_pspoll_work(struct work_struct *work) * delivery failure occurred, and no-one changed state since, so * we should go back to powersave. */ - wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true); + wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); out: mutex_unlock(&wl->mutex); @@ -70,7 +73,8 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl) /* force active mode receive data from the AP */ if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true); + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, + wl->basic_rate, true); if (ret < 0) return; set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); @@ -91,6 +95,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl, bool *beacon_loss) { int ret = 0; + u32 total_retries = wl->conf.conn.psm_entry_retries; wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); @@ -104,10 +109,10 @@ static int wl1271_event_ps_report(struct wl1271 *wl, break; } - if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) { + if (wl->psm_entry_retry < total_retries) { wl->psm_entry_retry++; ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - true); + wl->basic_rate, true); } else { wl1271_info("No ack to nullfunc from AP."); wl->psm_entry_retry = 0; @@ -143,7 +148,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl, /* make sure the firmware goes to active mode - the frame to be sent next will indicate to the AP, that we are active. */ ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - false); + wl->basic_rate, false); break; case EVENT_EXIT_POWER_SAVE_SUCCESS: default: diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 4447af1557f..8044bba70ee 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -53,6 +53,7 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl) int wl1271_init_templates_config(struct wl1271 *wl) { int ret, i; + size_t size; /* send empty templates for fw memory reservation */ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, @@ -61,14 +62,12 @@ int wl1271_init_templates_config(struct wl1271 *wl) if (ret < 0) return ret; - if (wl1271_11a_enabled()) { - size_t size = sizeof(struct wl12xx_probe_req_template); - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - NULL, size, 0, - WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - } + size = sizeof(struct wl12xx_probe_req_template); + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, + NULL, size, 0, + WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template), @@ -223,6 +222,10 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + /* Template settings */ ret = wl1271_init_templates_config(wl); if (ret < 0) @@ -291,8 +294,16 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* Default TID configuration */ + /* Default TID/AC configuration */ + BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { + conf_ac = &wl->conf.tx.ac_conf[i]; + ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, + conf_ac->cw_max, conf_ac->aifsn, + conf_ac->tx_op_limit); + if (ret < 0) + goto out_free_memmap; + conf_tid = &wl->conf.tx.tid_conf[i]; ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, conf_tid->channel_type, @@ -305,16 +316,6 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; } - /* Default AC configuration */ - for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { - conf_ac = &wl->conf.tx.ac_conf[i]; - ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, - conf_ac->cw_max, conf_ac->aifsn, - conf_ac->tx_op_limit); - if (ret < 0) - goto out_free_memmap; - } - /* Configure TX rate classes */ ret = wl1271_acx_rate_policies(wl); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h index bc806c74c63..c1f92e65ded 100644 --- a/drivers/net/wireless/wl12xx/wl1271_io.h +++ b/drivers/net/wireless/wl12xx/wl1271_io.h @@ -144,10 +144,13 @@ static inline void wl1271_power_off(struct wl1271 *wl) clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } -static inline void wl1271_power_on(struct wl1271 *wl) +static inline int wl1271_power_on(struct wl1271 *wl) { - wl->if_ops->power(wl, true); - set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + int ret = wl->if_ops->power(wl, true); + if (ret == 0) + set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + + return ret; } diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 9d68f0012f0..48a4b9961ae 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -124,28 +124,28 @@ static struct conf_drv_settings default_conf = { }, .ac_conf_count = 4, .ac_conf = { - [0] = { + [CONF_TX_AC_BE] = { .ac = CONF_TX_AC_BE, .cw_min = 15, .cw_max = 63, .aifsn = 3, .tx_op_limit = 0, }, - [1] = { + [CONF_TX_AC_BK] = { .ac = CONF_TX_AC_BK, .cw_min = 15, .cw_max = 63, .aifsn = 7, .tx_op_limit = 0, }, - [2] = { + [CONF_TX_AC_VI] = { .ac = CONF_TX_AC_VI, .cw_min = 15, .cw_max = 63, .aifsn = CONF_TX_AIFS_PIFS, .tx_op_limit = 3008, }, - [3] = { + [CONF_TX_AC_VO] = { .ac = CONF_TX_AC_VO, .cw_min = 15, .cw_max = 63, @@ -153,64 +153,40 @@ static struct conf_drv_settings default_conf = { .tx_op_limit = 1504, }, }, - .tid_conf_count = 7, + .tid_conf_count = 4, .tid_conf = { - [0] = { - .queue_id = 0, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [1] = { - .queue_id = 1, - .channel_type = CONF_CHANNEL_TYPE_DCF, + [CONF_TX_AC_BE] = { + .queue_id = CONF_TX_AC_BE, + .channel_type = CONF_CHANNEL_TYPE_EDCF, .tsid = CONF_TX_AC_BE, .ps_scheme = CONF_PS_SCHEME_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY, .apsd_conf = {0, 0}, }, - [2] = { - .queue_id = 2, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, + [CONF_TX_AC_BK] = { + .queue_id = CONF_TX_AC_BK, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_BK, .ps_scheme = CONF_PS_SCHEME_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY, .apsd_conf = {0, 0}, }, - [3] = { - .queue_id = 3, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [4] = { - .queue_id = 4, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, + [CONF_TX_AC_VI] = { + .queue_id = CONF_TX_AC_VI, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_VI, .ps_scheme = CONF_PS_SCHEME_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY, .apsd_conf = {0, 0}, }, - [5] = { - .queue_id = 5, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, + [CONF_TX_AC_VO] = { + .queue_id = CONF_TX_AC_VO, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_VO, .ps_scheme = CONF_PS_SCHEME_LEGACY, .ack_policy = CONF_ACK_POLICY_LEGACY, .apsd_conf = {0, 0}, }, - [6] = { - .queue_id = 6, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - } }, .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, .tx_compl_timeout = 700, @@ -238,7 +214,9 @@ static struct conf_drv_settings default_conf = { .ps_poll_recovery_period = 700, .bet_enable = CONF_BET_MODE_ENABLE, .bet_max_consecutive = 10, - .psm_entry_retries = 3, + .psm_entry_retries = 5, + .psm_entry_nullfunc_retries = 3, + .psm_entry_hangover_period = 1, .keep_alive_interval = 55000, .max_listen_interval = 20, }, @@ -251,15 +229,34 @@ static struct conf_drv_settings default_conf = { .host_fast_wakeup_support = false }, .roam_trigger = { - /* FIXME: due to firmware bug, must use value 1 for now */ .trigger_pacing = 1, .avg_weight_rssi_beacon = 20, .avg_weight_rssi_data = 10, .avg_weight_snr_beacon = 20, .avg_weight_snr_data = 10 - } + }, + .scan = { + .min_dwell_time_active = 7500, + .max_dwell_time_active = 30000, + .min_dwell_time_passive = 30000, + .max_dwell_time_passive = 60000, + .num_probe_reqs = 2, + }, + .rf = { + .tx_per_channel_power_compensation_2 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .tx_per_channel_power_compensation_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, }; +static void __wl1271_op_remove_interface(struct wl1271 *wl); + + static void wl1271_device_release(struct device *dev) { @@ -277,6 +274,67 @@ static struct platform_device wl1271_device = { static LIST_HEAD(wl_list); +static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, + void *arg) +{ + struct net_device *dev = arg; + struct wireless_dev *wdev; + struct wiphy *wiphy; + struct ieee80211_hw *hw; + struct wl1271 *wl; + struct wl1271 *wl_temp; + int ret = 0; + + /* Check that this notification is for us. */ + if (what != NETDEV_CHANGE) + return NOTIFY_DONE; + + wdev = dev->ieee80211_ptr; + if (wdev == NULL) + return NOTIFY_DONE; + + wiphy = wdev->wiphy; + if (wiphy == NULL) + return NOTIFY_DONE; + + hw = wiphy_priv(wiphy); + if (hw == NULL) + return NOTIFY_DONE; + + wl_temp = hw->priv; + list_for_each_entry(wl, &wl_list, list) { + if (wl == wl_temp) + break; + } + if (wl != wl_temp) + return NOTIFY_DONE; + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if ((dev->operstate == IF_OPER_UP) && + !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) { + wl1271_cmd_set_sta_state(wl); + wl1271_info("Association completed."); + } + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return NOTIFY_OK; +} + static void wl1271_conf_init(struct wl1271 *wl) { @@ -309,6 +367,10 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) return ret; + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + ret = wl1271_init_templates_config(wl); if (ret < 0) return ret; @@ -346,8 +408,16 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* Default TID configuration */ + /* Default TID/AC configuration */ + BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { + conf_ac = &wl->conf.tx.ac_conf[i]; + ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, + conf_ac->cw_max, conf_ac->aifsn, + conf_ac->tx_op_limit); + if (ret < 0) + goto out_free_memmap; + conf_tid = &wl->conf.tx.tid_conf[i]; ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, conf_tid->channel_type, @@ -360,16 +430,6 @@ static int wl1271_plt_init(struct wl1271 *wl) goto out_free_memmap; } - /* Default AC configuration */ - for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { - conf_ac = &wl->conf.tx.ac_conf[i]; - ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, - conf_ac->cw_max, conf_ac->aifsn, - conf_ac->tx_op_limit); - if (ret < 0) - goto out_free_memmap; - } - /* Enable data path */ ret = wl1271_cmd_data_path(wl, 1); if (ret < 0) @@ -562,20 +622,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) return ret; } - /* - * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band - * configurations) can be removed when those NVS files stop floating - * around. - */ - if (fw->size != sizeof(struct wl1271_nvs_file) && - (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE || - wl1271_11a_enabled())) { - wl1271_error("nvs size is not as expected: %zu != %zu", - fw->size, sizeof(struct wl1271_nvs_file)); - ret = -EILSEQ; - goto out; - } - wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); if (!wl->nvs) { @@ -584,12 +630,37 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) goto out; } + wl->nvs_len = fw->size; + out: release_firmware(fw); return ret; } +static void wl1271_recovery_work(struct work_struct *work) +{ + struct wl1271 *wl = + container_of(work, struct wl1271, recovery_work); + + mutex_lock(&wl->mutex); + + if (wl->state != WL1271_STATE_ON) + goto out; + + wl1271_info("Hardware recovery in progress."); + + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + ieee80211_connection_loss(wl->vif); + + /* reboot the chipset */ + __wl1271_op_remove_interface(wl); + ieee80211_restart_hw(wl->hw); + +out: + mutex_unlock(&wl->mutex); +} + static void wl1271_fw_wakeup(struct wl1271 *wl) { u32 elp_reg; @@ -610,8 +681,6 @@ static int wl1271_setup(struct wl1271 *wl) return -ENOMEM; } - INIT_WORK(&wl->irq_work, wl1271_irq_work); - INIT_WORK(&wl->tx_work, wl1271_tx_work); return 0; } @@ -621,7 +690,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) int ret = 0; msleep(WL1271_PRE_POWER_ON_SLEEP); - wl1271_power_on(wl); + ret = wl1271_power_on(wl); + if (ret < 0) + goto out; msleep(WL1271_POWER_ON_SLEEP); wl1271_io_reset(wl); wl1271_io_init(wl); @@ -766,10 +837,12 @@ int wl1271_plt_stop(struct wl1271 *wl) out: mutex_unlock(&wl->mutex); + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->recovery_work); + return ret; } - static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1271 *wl = hw->priv; @@ -812,6 +885,10 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } +static struct notifier_block wl1271_dev_notifier = { + .notifier_call = wl1271_dev_notify, +}; + static int wl1271_op_start(struct ieee80211_hw *hw) { wl1271_debug(DEBUG_MAC80211, "mac80211 start"); @@ -928,13 +1005,10 @@ out: return ret; } -static void wl1271_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void __wl1271_op_remove_interface(struct wl1271 *wl) { - struct wl1271 *wl = hw->priv; int i; - mutex_lock(&wl->mutex); wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); wl1271_info("down"); @@ -948,12 +1022,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, ieee80211_enable_dyn_ps(wl->vif); if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, true); - mutex_lock(&wl->mutex); wl->scan.state = WL1271_SCAN_STATE_IDLE; kfree(wl->scan.scanned_ch); wl->scan.scanned_ch = NULL; + ieee80211_scan_completed(wl->hw, true); } wl->state = WL1271_STATE_OFF; @@ -962,9 +1034,11 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); + cancel_delayed_work_sync(&wl->scan_complete_work); cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); cancel_delayed_work_sync(&wl->pspoll_work); + cancel_delayed_work_sync(&wl->elp_work); mutex_lock(&wl->mutex); @@ -1006,8 +1080,19 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, wl->tx_res_if = NULL; kfree(wl->target_mem_map); wl->target_mem_map = NULL; +} +static void wl1271_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + + mutex_lock(&wl->mutex); + WARN_ON(wl->vif != vif); + __wl1271_op_remove_interface(wl); mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->recovery_work); } static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) @@ -1289,7 +1374,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { wl1271_debug(DEBUG_PSM, "psm enabled"); ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, - true); + wl->basic_rate, true); } } else if (!(conf->flags & IEEE80211_CONF_PS) && test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { @@ -1299,7 +1384,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (test_bit(WL1271_FLAG_PSM, &wl->flags)) ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - true); + wl->basic_rate, true); } if (conf->power_level != wl->power_level) { @@ -1439,7 +1524,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", - key_conf->alg, key_conf->keyidx, + key_conf->cipher, key_conf->keyidx, key_conf->keylen, key_conf->flags); wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); @@ -1455,28 +1540,34 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (ret < 0) goto out_unlock; - switch (key_conf->alg) { - case ALG_WEP: + switch (key_conf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: key_type = KEY_WEP; key_conf->hw_key_idx = key_conf->keyidx; break; - case ALG_TKIP: + case WLAN_CIPHER_SUITE_TKIP: key_type = KEY_TKIP; key_conf->hw_key_idx = key_conf->keyidx; tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); break; - case ALG_CCMP: + case WLAN_CIPHER_SUITE_CCMP: key_type = KEY_AES; key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); break; + case WL1271_CIPHER_SUITE_GEM: + key_type = KEY_GEM; + tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq); + break; default: - wl1271_error("Unknown key algo 0x%x", key_conf->alg); + wl1271_error("Unknown key algo 0x%x", key_conf->cipher); ret = -EOPNOTSUPP; goto out_sleep; @@ -1558,10 +1649,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, if (ret < 0) goto out; - if (wl1271_11a_enabled()) - ret = wl1271_scan(hw->priv, ssid, len, req); - else - ret = wl1271_scan(hw->priv, ssid, len, req); + ret = wl1271_scan(hw->priv, ssid, len, req); wl1271_ps_elp_sleep(wl); @@ -1633,7 +1721,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - if ((changed && BSS_CHANGED_BEACON_INT) && + if ((changed & BSS_CHANGED_BEACON_INT) && (wl->bss_type == BSS_TYPE_IBSS)) { wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d", bss_conf->beacon_int); @@ -1642,7 +1730,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, do_join = true; } - if ((changed && BSS_CHANGED_BEACON) && + if ((changed & BSS_CHANGED_BEACON) && (wl->bss_type == BSS_TYPE_IBSS)) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); @@ -1776,12 +1864,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && !test_bit(WL1271_FLAG_PSM, &wl->flags)) { mode = STATION_POWER_SAVE_MODE; - ret = wl1271_ps_set_mode(wl, mode, true); + ret = wl1271_ps_set_mode(wl, mode, + wl->basic_rate, + true); if (ret < 0) goto out_sleep; } } else { /* use defaults when not associated */ + clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags); clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); wl->aid = 0; @@ -1993,21 +2084,24 @@ static struct ieee80211_rate wl1271_rates[] = { .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, }; -/* can't be const, mac80211 writes to this */ +/* + * Can't be const, mac80211 writes to this. The order of the channels here + * is designed to improve scanning. + */ static struct ieee80211_channel wl1271_channels[] = { { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, - { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, - { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, - { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, - { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, - { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, - { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, - { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, - { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, - { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, + { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, + { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, + { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, + { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, + { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, + { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, + { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, + { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, + { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, }; /* mapping to indexes for wl1271_rates */ @@ -2076,49 +2170,52 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, }; -/* 5 GHz band channels for WL1273 */ +/* + * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this. + * The order of the channels here is designed to improve scanning. + */ static struct ieee80211_channel wl1271_channels_5ghz[] = { { .hw_value = 183, .center_freq = 4915}, - { .hw_value = 184, .center_freq = 4920}, - { .hw_value = 185, .center_freq = 4925}, - { .hw_value = 187, .center_freq = 4935}, { .hw_value = 188, .center_freq = 4940}, - { .hw_value = 189, .center_freq = 4945}, - { .hw_value = 192, .center_freq = 4960}, - { .hw_value = 196, .center_freq = 4980}, - { .hw_value = 7, .center_freq = 5035}, { .hw_value = 8, .center_freq = 5040}, - { .hw_value = 9, .center_freq = 5045}, - { .hw_value = 11, .center_freq = 5055}, - { .hw_value = 12, .center_freq = 5060}, - { .hw_value = 16, .center_freq = 5080}, { .hw_value = 34, .center_freq = 5170}, - { .hw_value = 36, .center_freq = 5180}, - { .hw_value = 38, .center_freq = 5190}, - { .hw_value = 40, .center_freq = 5200}, - { .hw_value = 42, .center_freq = 5210}, { .hw_value = 44, .center_freq = 5220}, - { .hw_value = 46, .center_freq = 5230}, - { .hw_value = 48, .center_freq = 5240}, - { .hw_value = 52, .center_freq = 5260}, - { .hw_value = 56, .center_freq = 5280}, { .hw_value = 60, .center_freq = 5300}, - { .hw_value = 64, .center_freq = 5320}, - { .hw_value = 100, .center_freq = 5500}, - { .hw_value = 104, .center_freq = 5520}, - { .hw_value = 108, .center_freq = 5540}, { .hw_value = 112, .center_freq = 5560}, - { .hw_value = 116, .center_freq = 5580}, - { .hw_value = 120, .center_freq = 5600}, - { .hw_value = 124, .center_freq = 5620}, - { .hw_value = 128, .center_freq = 5640}, { .hw_value = 132, .center_freq = 5660}, + { .hw_value = 157, .center_freq = 5785}, + { .hw_value = 184, .center_freq = 4920}, + { .hw_value = 189, .center_freq = 4945}, + { .hw_value = 9, .center_freq = 5045}, + { .hw_value = 36, .center_freq = 5180}, + { .hw_value = 46, .center_freq = 5230}, + { .hw_value = 64, .center_freq = 5320}, + { .hw_value = 116, .center_freq = 5580}, { .hw_value = 136, .center_freq = 5680}, + { .hw_value = 192, .center_freq = 4960}, + { .hw_value = 11, .center_freq = 5055}, + { .hw_value = 38, .center_freq = 5190}, + { .hw_value = 48, .center_freq = 5240}, + { .hw_value = 100, .center_freq = 5500}, + { .hw_value = 120, .center_freq = 5600}, { .hw_value = 140, .center_freq = 5700}, + { .hw_value = 185, .center_freq = 4925}, + { .hw_value = 196, .center_freq = 4980}, + { .hw_value = 12, .center_freq = 5060}, + { .hw_value = 40, .center_freq = 5200}, + { .hw_value = 52, .center_freq = 5260}, + { .hw_value = 104, .center_freq = 5520}, + { .hw_value = 124, .center_freq = 5620}, { .hw_value = 149, .center_freq = 5745}, - { .hw_value = 153, .center_freq = 5765}, - { .hw_value = 157, .center_freq = 5785}, { .hw_value = 161, .center_freq = 5805}, + { .hw_value = 187, .center_freq = 4935}, + { .hw_value = 7, .center_freq = 5035}, + { .hw_value = 16, .center_freq = 5080}, + { .hw_value = 42, .center_freq = 5210}, + { .hw_value = 56, .center_freq = 5280}, + { .hw_value = 108, .center_freq = 5540}, + { .hw_value = 128, .center_freq = 5640}, + { .hw_value = 153, .center_freq = 5765}, { .hw_value = 165, .center_freq = 5825}, }; @@ -2211,8 +2308,7 @@ static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, struct wl1271 *wl = dev_get_drvdata(dev); ssize_t len; - /* FIXME: what's the maximum length of buf? page size?*/ - len = 500; + len = PAGE_SIZE; mutex_lock(&wl->mutex); len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", @@ -2273,8 +2369,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, struct wl1271 *wl = dev_get_drvdata(dev); ssize_t len; - /* FIXME: what's the maximum length of buf? page size?*/ - len = 500; + len = PAGE_SIZE; mutex_lock(&wl->mutex); if (wl->hw_pg_ver >= 0) @@ -2306,6 +2401,8 @@ int wl1271_register_hw(struct wl1271 *wl) wl->mac80211_registered = true; + register_netdevice_notifier(&wl1271_dev_notifier); + wl1271_notice("loaded"); return 0; @@ -2314,6 +2411,7 @@ EXPORT_SYMBOL_GPL(wl1271_register_hw); void wl1271_unregister_hw(struct wl1271 *wl) { + unregister_netdevice_notifier(&wl1271_dev_notifier); ieee80211_unregister_hw(wl->hw); wl->mac80211_registered = false; @@ -2322,6 +2420,14 @@ EXPORT_SYMBOL_GPL(wl1271_unregister_hw); int wl1271_init_ieee80211(struct wl1271 *wl) { + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WL1271_CIPHER_SUITE_GEM, + }; + /* The tx descriptor buffer and the TKIP space. */ wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + sizeof(struct wl1271_tx_hw_descr); @@ -2339,13 +2445,14 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI; + wl->hw->wiphy->cipher_suites = cipher_suites; + wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; - - if (wl1271_11a_enabled()) - wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; + wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; wl->hw->queues = 4; wl->hw->max_rates = 1; @@ -2364,6 +2471,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) struct platform_device *plat_dev = NULL; struct wl1271 *wl; int i, ret; + unsigned int order; hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); if (!hw) { @@ -2391,6 +2499,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void) INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); + INIT_WORK(&wl->irq_work, wl1271_irq_work); + INIT_WORK(&wl->tx_work, wl1271_tx_work); + INIT_WORK(&wl->recovery_work, wl1271_recovery_work); + INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); wl->channel = WL1271_DEFAULT_CHANNEL; wl->beacon_int = WL1271_DEFAULT_BEACON_INT; wl->default_key = 0; @@ -2422,11 +2534,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl1271_debugfs_init(wl); + order = get_order(WL1271_AGGR_BUFFER_SIZE); + wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); + if (!wl->aggr_buf) { + ret = -ENOMEM; + goto err_hw; + } + /* Register platform device */ ret = platform_device_register(wl->plat_dev); if (ret) { wl1271_error("couldn't register platform device"); - goto err_hw; + goto err_aggr; } dev_set_drvdata(&wl->plat_dev->dev, wl); @@ -2452,6 +2571,9 @@ err_bt_coex_state: err_platform: platform_device_unregister(wl->plat_dev); +err_aggr: + free_pages((unsigned long)wl->aggr_buf, order); + err_hw: wl1271_debugfs_exit(wl); kfree(plat_dev); @@ -2468,6 +2590,8 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw); int wl1271_free_hw(struct wl1271 *wl) { platform_device_unregister(wl->plat_dev); + free_pages((unsigned long)wl->aggr_buf, + get_order(WL1271_AGGR_BUFFER_SIZE)); kfree(wl->plat_dev); wl1271_debugfs_exit(wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index a5e60e0403e..e3c332e2f97 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -39,6 +39,9 @@ void wl1271_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || (!test_bit(WL1271_FLAG_PSM, &wl->flags) && !test_bit(WL1271_FLAG_IDLE, &wl->flags))) @@ -61,7 +64,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) test_bit(WL1271_FLAG_IDLE, &wl->flags)) { cancel_delayed_work(&wl->elp_work); ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, - msecs_to_jiffies(ELP_ENTRY_DELAY)); + msecs_to_jiffies(ELP_ENTRY_DELAY)); } } @@ -96,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); if (ret == 0) { wl1271_error("ELP wakeup timeout!"); + ieee80211_queue_work(wl->hw, &wl->recovery_work); ret = -ETIMEDOUT; goto err; } else if (ret < 0) { @@ -121,7 +125,7 @@ out: } int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - bool send) + u32 rates, bool send) { int ret; @@ -129,7 +133,14 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, case STATION_POWER_SAVE_MODE: wl1271_debug(DEBUG_PSM, "entering psm"); - ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send); + ret = wl1271_acx_wake_up_conditions(wl); + if (ret < 0) { + wl1271_error("couldn't set wake up conditions"); + return ret; + } + + ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, + rates, send); if (ret < 0) return ret; @@ -152,7 +163,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, if (ret < 0) return ret; - ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send); + ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, + rates, send); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h index 940276f517a..6ba7b032736 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.h +++ b/drivers/net/wireless/wl12xx/wl1271_ps.h @@ -28,7 +28,7 @@ #include "wl1271_acx.h" int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, - bool send); + u32 rates, bool send); void wl1271_ps_elp_sleep(struct wl1271 *wl); int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); void wl1271_elp_work(struct work_struct *work); diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 019aa79cd9d..bea133b6e48 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -74,9 +74,8 @@ static void wl1271_rx_status(struct wl1271 *wl, } } -static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) +static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) { - struct ieee80211_rx_status rx_status; struct wl1271_rx_descriptor *desc; struct sk_buff *skb; u16 *fc; @@ -88,16 +87,16 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) * workaround this by not retrieving them at all. */ if (unlikely(wl->state == WL1271_STATE_PLT)) - return; + return -EINVAL; skb = __dev_alloc_skb(length, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); - return; + return -ENOMEM; } buf = skb_put(skb, length); - wl1271_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); + memcpy(buf, data, length); /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) buf; @@ -109,15 +108,16 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) beacon = 1; - wl1271_rx_status(wl, desc, &rx_status, beacon); + wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, beacon ? "beacon" : ""); skb_trim(skb, skb->len - desc->pad_len); - memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_ni(wl->hw, skb); + + return 0; } void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) @@ -126,31 +126,60 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) u32 buf_size; u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 rx_counter; u32 mem_block; + u32 pkt_length; + u32 pkt_offset; while (drv_rx_counter != fw_rx_counter) { - mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); - buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter); + buf_size = 0; + rx_counter = drv_rx_counter; + while (rx_counter != fw_rx_counter) { + pkt_length = wl1271_rx_get_buf_size(status, rx_counter); + if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) + break; + buf_size += pkt_length; + rx_counter++; + rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; + } if (buf_size == 0) { wl1271_warning("received empty data"); break; } + /* + * Choose the block we want to read + * For aggregated packets, only the first memory block should + * be retrieved. The FW takes care of the rest. + */ + mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); wl->rx_mem_pool_addr.addr = (mem_block << 8) + le32_to_cpu(wl_mem_map->packet_memory_pool_start); wl->rx_mem_pool_addr.addr_extra = wl->rx_mem_pool_addr.addr + 4; - - /* Choose the block we want to read */ wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, - sizeof(wl->rx_mem_pool_addr), false); - - wl1271_rx_handle_data(wl, buf_size); - - wl->rx_counter++; - drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + sizeof(wl->rx_mem_pool_addr), false); + + /* Read all available packets at once */ + wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, + buf_size, true); + + /* Split data into separate packets */ + pkt_offset = 0; + while (pkt_offset < buf_size) { + pkt_length = wl1271_rx_get_buf_size(status, + drv_rx_counter); + if (wl1271_rx_handle_data(wl, + wl->aggr_buf + pkt_offset, + pkt_length) < 0) + break; + wl->rx_counter++; + drv_rx_counter++; + drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; + pkt_offset += pkt_length; + } } - - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); + wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, + cpu_to_le32(wl->rx_counter)); } diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index fec43eed8c5..909bb47995b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -28,11 +28,43 @@ #include "wl1271_scan.h" #include "wl1271_acx.h" +void wl1271_scan_complete_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wl1271 *wl; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, scan_complete_work); + + wl1271_debug(DEBUG_SCAN, "Scanning complete"); + + mutex_lock(&wl->mutex); + + if (wl->scan.state == WL1271_SCAN_STATE_IDLE) { + mutex_unlock(&wl->mutex); + return; + } + + wl->scan.state = WL1271_SCAN_STATE_IDLE; + kfree(wl->scan.scanned_ch); + wl->scan.scanned_ch = NULL; + mutex_unlock(&wl->mutex); + + ieee80211_scan_completed(wl->hw, false); + + if (wl->scan.failed) { + wl1271_info("Scan completed due to error."); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + } +} + + static int wl1271_get_scan_channels(struct wl1271 *wl, struct cfg80211_scan_request *req, struct basic_scan_channel_params *channels, enum ieee80211_band band, bool passive) { + struct conf_scan_settings *c = &wl->conf.scan; int i, j; u32 flags; @@ -60,10 +92,17 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, wl1271_debug(DEBUG_SCAN, "beacon_found %d", req->channels[i]->beacon_found); - channels[j].min_duration = - cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); - channels[j].max_duration = - cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); + if (!passive) { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_active); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_active); + } else { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_passive); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_passive); + } channels[j].early_termination = 0; channels[j].tx_power_att = req->channels[i]->max_power; channels[j].channel = req->channels[i]->hw_value; @@ -100,8 +139,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, /* We always use high priority scans */ scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; - if(passive) + + /* No SSIDs means that we have a forced passive scan */ + if (passive || wl->scan.req->n_ssids == 0) scan_options |= WL1271_SCAN_OPT_PASSIVE; + cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, @@ -117,7 +159,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); - cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS; + cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.tid_trigger = 0; cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; @@ -165,7 +207,7 @@ out: void wl1271_scan_stm(struct wl1271 *wl) { - int ret; + int ret = 0; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: @@ -185,7 +227,7 @@ void wl1271_scan_stm(struct wl1271 *wl) ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, wl->conf.tx.basic_rate); if (ret == WL1271_NOTHING_TO_SCAN) { - if (wl1271_11a_enabled()) + if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; else wl->scan.state = WL1271_SCAN_STATE_DONE; @@ -215,20 +257,22 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_DONE: - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, false); - mutex_lock(&wl->mutex); - - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; - - wl->scan.state = WL1271_SCAN_STATE_IDLE; + wl->scan.failed = false; + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); break; default: wl1271_error("invalid scan state"); break; } + + if (ret < 0) { + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); + } } int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, @@ -248,9 +292,14 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, wl->scan.req = req; - wl->scan.scanned_ch = kzalloc(req->n_channels * + wl->scan.scanned_ch = kcalloc(req->n_channels, sizeof(*wl->scan.scanned_ch), GFP_KERNEL); + /* we assume failure so that timeout scenarios are handled correctly */ + wl->scan.failed = true; + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); + wl1271_scan_stm(wl); return 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h index f1815700f5f..6d57127b5e6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.h +++ b/drivers/net/wireless/wl12xx/wl1271_scan.h @@ -32,6 +32,7 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u8 band); void wl1271_scan_stm(struct wl1271 *wl); +void wl1271_scan_complete_work(struct work_struct *work); #define WL1271_SCAN_MAX_CHANNELS 24 #define WL1271_SCAN_DEFAULT_TAG 1 @@ -39,11 +40,10 @@ void wl1271_scan_stm(struct wl1271 *wl); #define WL1271_SCAN_OPT_ACTIVE 0 #define WL1271_SCAN_OPT_PASSIVE 1 #define WL1271_SCAN_OPT_PRIORITY_HIGH 4 -#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */ -#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */ #define WL1271_SCAN_BAND_2_4_GHZ 0 #define WL1271_SCAN_BAND_5_GHZ 1 -#define WL1271_SCAN_PROBE_REQS 3 + +#define WL1271_SCAN_TIMEOUT 10000 /* msec */ enum { WL1271_SCAN_STATE_IDLE, diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c index 7059b5cccf0..784ef343264 100644 --- a/drivers/net/wireless/wl12xx/wl1271_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c @@ -29,14 +29,13 @@ #include <linux/mmc/sdio_ids.h> #include <linux/mmc/card.h> #include <linux/gpio.h> +#include <linux/wl12xx.h> +#include <linux/pm_runtime.h> #include "wl1271.h" #include "wl12xx_80211.h" #include "wl1271_io.h" - -#define RX71_WL1271_IRQ_GPIO 42 - #ifndef SDIO_VENDOR_ID_TI #define SDIO_VENDOR_ID_TI 0x0097 #endif @@ -107,6 +106,8 @@ static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, int ret; struct sdio_func *func = wl_to_func(wl); + sdio_claim_host(func); + if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x", @@ -122,9 +123,10 @@ static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); } + sdio_release_host(func); + if (ret) wl1271_error("sdio read failed (%d)", ret); - } static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, @@ -133,6 +135,8 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, int ret; struct sdio_func *func = wl_to_func(wl); + sdio_claim_host(func); + if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x", @@ -147,26 +151,49 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, else ret = sdio_memcpy_toio(func, addr, buf, len); } + + sdio_release_host(func); + if (ret) wl1271_error("sdio write failed (%d)", ret); +} +static int wl1271_sdio_power_on(struct wl1271 *wl) +{ + struct sdio_func *func = wl_to_func(wl); + int ret; + + /* Power up the card */ + ret = pm_runtime_get_sync(&func->dev); + if (ret < 0) + goto out; + + sdio_claim_host(func); + sdio_enable_func(func); + sdio_release_host(func); + +out: + return ret; } -static void wl1271_sdio_set_power(struct wl1271 *wl, bool enable) +static int wl1271_sdio_power_off(struct wl1271 *wl) { struct sdio_func *func = wl_to_func(wl); - /* Let the SDIO stack handle wlan_enable control, so we - * keep host claimed while wlan is in use to keep wl1271 - * alive. - */ - if (enable) { - sdio_claim_host(func); - sdio_enable_func(func); - } else { - sdio_disable_func(func); - sdio_release_host(func); - } + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + + /* Power down the card */ + return pm_runtime_put_sync(&func->dev); +} + +static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) +{ + if (enable) + return wl1271_sdio_power_on(wl); + else + return wl1271_sdio_power_off(wl); } static struct wl1271_if_operations sdio_ops = { @@ -184,6 +211,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { struct ieee80211_hw *hw; + const struct wl12xx_platform_data *wlan_data; struct wl1271 *wl; int ret; @@ -203,13 +231,16 @@ static int __devinit wl1271_probe(struct sdio_func *func, /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; - wl->irq = gpio_to_irq(RX71_WL1271_IRQ_GPIO); - if (wl->irq < 0) { - ret = wl->irq; - wl1271_error("could not get irq!"); + wlan_data = wl12xx_get_platform_data(); + if (IS_ERR(wlan_data)) { + ret = PTR_ERR(wlan_data); + wl1271_error("missing wlan platform data: %d", ret); goto out_free; } + wl->irq = wlan_data->irq; + wl->ref_clock = wlan_data->board_ref_clock; + ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); @@ -230,6 +261,9 @@ static int __devinit wl1271_probe(struct sdio_func *func, sdio_set_drvdata(func, wl); + /* Tell PM core that we don't need the card to be powered now */ + pm_runtime_put_noidle(&func->dev); + wl1271_notice("initialized"); return 0; @@ -248,17 +282,39 @@ static void __devexit wl1271_remove(struct sdio_func *func) { struct wl1271 *wl = sdio_get_drvdata(func); - free_irq(wl->irq, wl); + /* Undo decrement done above in wl1271_probe */ + pm_runtime_get_noresume(&func->dev); wl1271_unregister_hw(wl); + free_irq(wl->irq, wl); wl1271_free_hw(wl); } +static int wl1271_suspend(struct device *dev) +{ + /* Tell MMC/SDIO core it's OK to power down the card + * (if it isn't already), but not to remove it completely */ + return 0; +} + +static int wl1271_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops wl1271_sdio_pm_ops = { + .suspend = wl1271_suspend, + .resume = wl1271_resume, +}; + static struct sdio_driver wl1271_sdio_driver = { .name = "wl1271_sdio", .id_table = wl1271_devices, .probe = wl1271_probe, .remove = __devexit_p(wl1271_remove), + .drv = { + .pm = &wl1271_sdio_pm_ops, + }, }; static int __init wl1271_init(void) diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 4cb99c541e2..ef801680773 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -25,7 +25,7 @@ #include <linux/module.h> #include <linux/crc7.h> #include <linux/spi/spi.h> -#include <linux/spi/wl12xx.h> +#include <linux/wl12xx.h> #include <linux/slab.h> #include "wl1271.h" @@ -63,6 +63,11 @@ ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 +/* HW limitation: maximum possible chunk size is 4095 bytes */ +#define WSPI_MAX_CHUNK_SIZE 4092 + +#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + static inline struct spi_device *wl_to_spi(struct wl1271 *wl) { return wl->if_priv; @@ -202,90 +207,117 @@ static int wl1271_spi_read_busy(struct wl1271 *wl) static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { - struct spi_transfer t[3]; + struct spi_transfer t[2]; struct spi_message m; u32 *busy_buf; u32 *cmd; + u32 chunk_len; - cmd = &wl->buffer_cmd; - busy_buf = wl->buffer_busyword; + while (len > 0) { + chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); - *cmd = 0; - *cmd |= WSPI_CMD_READ; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; + cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; - if (fixed) - *cmd |= WSPI_CMD_FIXED; + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & + WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; - spi_message_init(&m); - memset(t, 0, sizeof(t)); + if (fixed) + *cmd |= WSPI_CMD_FIXED; - t[0].tx_buf = cmd; - t[0].len = 4; - t[0].cs_change = true; - spi_message_add_tail(&t[0], &m); + spi_message_init(&m); + memset(t, 0, sizeof(t)); - /* Busy and non busy words read */ - t[1].rx_buf = busy_buf; - t[1].len = WL1271_BUSY_WORD_LEN; - t[1].cs_change = true; - spi_message_add_tail(&t[1], &m); + t[0].tx_buf = cmd; + t[0].len = 4; + t[0].cs_change = true; + spi_message_add_tail(&t[0], &m); - spi_sync(wl_to_spi(wl), &m); + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = WL1271_BUSY_WORD_LEN; + t[1].cs_change = true; + spi_message_add_tail(&t[1], &m); - if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && - wl1271_spi_read_busy(wl)) { - memset(buf, 0, len); - return; - } + spi_sync(wl_to_spi(wl), &m); - spi_message_init(&m); - memset(t, 0, sizeof(t)); + if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && + wl1271_spi_read_busy(wl)) { + memset(buf, 0, chunk_len); + return; + } - t[0].rx_buf = buf; - t[0].len = len; - t[0].cs_change = true; - spi_message_add_tail(&t[0], &m); + spi_message_init(&m); + memset(t, 0, sizeof(t)); - spi_sync(wl_to_spi(wl), &m); + t[0].rx_buf = buf; + t[0].len = chunk_len; + t[0].cs_change = true; + spi_message_add_tail(&t[0], &m); - wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); + spi_sync(wl_to_spi(wl), &m); + + wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len); + + if (!fixed) + addr += chunk_len; + buf += chunk_len; + len -= chunk_len; + } } static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { - struct spi_transfer t[2]; + struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_message m; + u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; u32 *cmd; + u32 chunk_len; + int i; - cmd = &wl->buffer_cmd; - - *cmd = 0; - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - if (fixed) - *cmd |= WSPI_CMD_FIXED; + WARN_ON(len > WL1271_AGGR_BUFFER_SIZE); spi_message_init(&m); memset(t, 0, sizeof(t)); - t[0].tx_buf = cmd; - t[0].len = sizeof(*cmd); - spi_message_add_tail(&t[0], &m); + cmd = &commands[0]; + i = 0; + while (len > 0) { + chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); - t[1].tx_buf = buf; - t[1].len = len; - spi_message_add_tail(&t[1], &m); + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & + WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; - spi_sync(wl_to_spi(wl), &m); + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + t[i].tx_buf = cmd; + t[i].len = sizeof(*cmd); + spi_message_add_tail(&t[i++], &m); + + t[i].tx_buf = buf; + t[i].len = chunk_len; + spi_message_add_tail(&t[i++], &m); - wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); + wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len); + + if (!fixed) + addr += chunk_len; + buf += chunk_len; + len -= chunk_len; + cmd++; + } + + spi_sync(wl_to_spi(wl), &m); } static irqreturn_t wl1271_irq(int irq, void *cookie) @@ -312,10 +344,12 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) return IRQ_HANDLED; } -static void wl1271_spi_set_power(struct wl1271 *wl, bool enable) +static int wl1271_spi_set_power(struct wl1271 *wl, bool enable) { if (wl->set_power) wl->set_power(enable); + + return 0; } static struct wl1271_if_operations spi_ops = { @@ -370,6 +404,8 @@ static int __devinit wl1271_probe(struct spi_device *spi) goto out_free; } + wl->ref_clock = pdata->board_ref_clock; + wl->irq = spi->irq; if (wl->irq < 0) { wl1271_error("irq missing in platform data"); @@ -412,9 +448,8 @@ static int __devexit wl1271_remove(struct spi_device *spi) { struct wl1271 *wl = dev_get_drvdata(&spi->dev); - free_irq(wl->irq, wl); - wl1271_unregister_hw(wl); + free_irq(wl->irq, wl); wl1271_free_hw(wl); return 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c index 6e0952f79e9..a3aa84386c8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_testmode.c +++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c @@ -199,19 +199,6 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) buf = nla_data(tb[WL1271_TM_ATTR_DATA]); len = nla_len(tb[WL1271_TM_ATTR_DATA]); - /* - * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band - * configurations) can be removed when those NVS files stop floating - * around. - */ - if (len != sizeof(struct wl1271_nvs_file) && - (len != WL1271_INI_LEGACY_NVS_FILE_SIZE || - wl1271_11a_enabled())) { - wl1271_error("nvs size is not as expected: %zu != %zu", - len, sizeof(struct wl1271_nvs_file)); - return -EMSGSIZE; - } - mutex_lock(&wl->mutex); kfree(wl->nvs); @@ -224,6 +211,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) } memcpy(wl->nvs, buf, len); + wl->nvs_len = len; wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs"); diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index c592cc2e9fe..e3dc13c4d01 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -43,13 +43,17 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) return -EBUSY; } -static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) +static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, + u32 buf_offset) { struct wl1271_tx_hw_descr *desc; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 total_blocks; int id, ret = -EBUSY; + if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) + return -EBUSY; + /* allocate free identifier for the packet */ id = wl1271_tx_id(wl, skb); if (id < 0) @@ -82,7 +86,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) return ret; } -static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, +static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control) { struct timespec ts; @@ -110,9 +114,9 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, /* configure the tx attributes */ tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; - /* queue */ + /* queue (we use same identifiers for tid's and ac's */ ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - desc->tid = wl1271_tx_ac_to_tid(ac); + desc->tid = ac; desc->aid = TX_HW_DEFAULT_AID; desc->reserved = 0; @@ -133,59 +137,17 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, desc->tx_attr = cpu_to_le16(tx_attr); wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); - return 0; -} - -static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - - struct wl1271_tx_hw_descr *desc; - int len; - - /* FIXME: This is a workaround for getting non-aligned packets. - This happens at least with EAPOL packets from the user space. - Our DMA requires packets to be aligned on a 4-byte boundary. - */ - if (unlikely((long)skb->data & 0x03)) { - int offset = (4 - (long)skb->data) & 0x03; - wl1271_debug(DEBUG_TX, "skb offset %d", offset); - - /* check whether the current skb can be used */ - if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { - unsigned char *src = skb->data; - - /* align the buffer on a 4-byte boundary */ - skb_reserve(skb, offset); - memmove(skb->data, src, skb->len); - } else { - wl1271_info("No handler, fixme!"); - return -EINVAL; - } - } - - len = WL1271_TX_ALIGN(skb->len); - - /* perform a fixed address block write with the packet */ - wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); - - /* write packet new counter into the write access register */ - wl->tx_packets_count++; - - desc = (struct wl1271_tx_hw_descr *) skb->data; - wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", - desc->id, skb, len, desc->length); - - return 0; } /* caller must hold wl->mutex */ -static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) +static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, + u32 buf_offset) { struct ieee80211_tx_info *info; u32 extra = 0; int ret = 0; u8 idx; + u32 total_len; if (!skb) return -EINVAL; @@ -193,7 +155,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) info = IEEE80211_SKB_CB(skb); if (info->control.hw_key && - info->control.hw_key->alg == ALG_TKIP) + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) extra = WL1271_TKIP_IV_SPACE; if (info->control.hw_key) { @@ -208,19 +170,22 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) } } - ret = wl1271_tx_allocate(wl, skb, extra); + ret = wl1271_tx_allocate(wl, skb, extra, buf_offset); if (ret < 0) return ret; - ret = wl1271_tx_fill_hdr(wl, skb, extra, info); - if (ret < 0) - return ret; + wl1271_tx_fill_hdr(wl, skb, extra, info); - ret = wl1271_tx_send_packet(wl, skb, info); - if (ret < 0) - return ret; + /* + * The length of each packet is stored in terms of words. Thus, we must + * pad the skb data to make sure its length is aligned. + * The number of padding bytes is computed and set in wl1271_tx_fill_hdr + */ + total_len = WL1271_TX_ALIGN(skb->len); + memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); + memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); - return ret; + return total_len; } u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) @@ -245,7 +210,7 @@ void wl1271_tx_work(struct work_struct *work) struct sk_buff *skb; bool woken_up = false; u32 sta_rates = 0; - u32 prev_tx_packets_count; + u32 buf_offset; int ret; /* check if the rates supported by the AP have changed */ @@ -262,14 +227,15 @@ void wl1271_tx_work(struct work_struct *work) if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; - prev_tx_packets_count = wl->tx_packets_count; - /* if rates have changed, re-configure the rate policy */ if (unlikely(sta_rates)) { wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); wl1271_acx_rate_policies(wl); } + /* Prepare the transfer buffer, by aggregating all + * available packets */ + buf_offset = 0; while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { ret = wl1271_ps_elp_wakeup(wl, false); @@ -278,21 +244,30 @@ void wl1271_tx_work(struct work_struct *work) woken_up = true; } - ret = wl1271_tx_frame(wl, skb); + ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); if (ret == -EBUSY) { - /* firmware buffer is full, lets stop transmitting. */ + /* + * Either the firmware buffer is full, or the + * aggregation buffer is. + * Queue back last skb, and stop aggregating. + */ skb_queue_head(&wl->tx_queue, skb); goto out_ack; } else if (ret < 0) { dev_kfree_skb(skb); goto out_ack; } + buf_offset += ret; + wl->tx_packets_count++; } out_ack: - /* interrupt the firmware with the new packets */ - if (prev_tx_packets_count != wl->tx_packets_count) + if (buf_offset) { + wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, + buf_offset, true); + /* interrupt the firmware with the new packets */ wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + } out: if (woken_up) @@ -347,7 +322,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, /* remove TKIP header space if present */ if (info->control.hw_key && - info->control.hw_key->alg == ALG_TKIP) { + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { int hdrlen = ieee80211_get_hdrlen_from_skb(skb); memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); skb_pull(skb, WL1271_TKIP_IV_SPACE); @@ -422,8 +397,6 @@ void wl1271_tx_reset(struct wl1271 *wl) struct sk_buff *skb; /* TX failure */ -/* control->flags = 0; FIXME */ - while ((skb = skb_dequeue(&wl->tx_queue))) { wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); ieee80211_tx_status(wl->hw, skb); diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h index 48bf92621c0..d12a129ad11 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.h +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h @@ -139,23 +139,6 @@ static inline int wl1271_tx_get_queue(int queue) } } -/* wl1271 tx descriptor needs the tid and we need to convert it from ac */ -static inline int wl1271_tx_ac_to_tid(int ac) -{ - switch (ac) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 4; - case 3: - return 6; - default: - return 0; - } -} - void wl1271_tx_work(struct work_struct *work); void wl1271_tx_complete(struct wl1271 *wl); void wl1271_tx_reset(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl12xx_platform_data.c b/drivers/net/wireless/wl12xx/wl12xx_platform_data.c new file mode 100644 index 00000000000..973b11060a8 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl12xx_platform_data.c @@ -0,0 +1,28 @@ +#include <linux/module.h> +#include <linux/err.h> +#include <linux/wl12xx.h> + +static const struct wl12xx_platform_data *platform_data; + +int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data) +{ + if (platform_data) + return -EBUSY; + if (!data) + return -EINVAL; + + platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); + if (!platform_data) + return -ENOMEM; + + return 0; +} + +const struct wl12xx_platform_data *wl12xx_get_platform_data(void) +{ + if (!platform_data) + return ERR_PTR(-ENODEV); + + return platform_data; +} +EXPORT_SYMBOL(wl12xx_get_platform_data); |