diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-09-28 13:49:21 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-09-28 13:49:21 -0400 |
commit | f1b98bb367f672ee78800fa62880b522bef86eed (patch) | |
tree | 5cb12a850dbc749fc593ecb4eacbb5abd02e89c2 /drivers | |
parent | 97ea6d0f3eb019891038cd2dfddb749d6bf219be (diff) | |
parent | af390f4dd35373b3ca32bafc12d7f2ad12840529 (diff) | |
download | linux-stable-f1b98bb367f672ee78800fa62880b522bef86eed.tar.gz linux-stable-f1b98bb367f672ee78800fa62880b522bef86eed.tar.bz2 linux-stable-f1b98bb367f672ee78800fa62880b522bef86eed.zip |
Merge branch 'for-linville' of git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
Diffstat (limited to 'drivers')
21 files changed, 476 insertions, 339 deletions
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index f429fc110cb0..dadf1dbb002a 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -32,7 +32,6 @@ #include "../wlcore/acx.h" #include "../wlcore/tx.h" #include "../wlcore/rx.h" -#include "../wlcore/io.h" #include "../wlcore/boot.h" #include "wl12xx.h" @@ -1185,9 +1184,16 @@ static int wl12xx_enable_interrupts(struct wl1271 *wl) ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK)); if (ret < 0) - goto out; + goto disable_interrupts; ret = wlcore_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL); + if (ret < 0) + goto disable_interrupts; + + return ret; + +disable_interrupts: + wlcore_disable_interrupts(wl); out: return ret; @@ -1583,7 +1589,10 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, return wlcore_set_key(wl, cmd, vif, sta, key_conf); } +static int wl12xx_setup(struct wl1271 *wl); + static struct wlcore_ops wl12xx_ops = { + .setup = wl12xx_setup, .identify_chip = wl12xx_identify_chip, .identify_fw = wl12xx_identify_fw, .boot = wl12xx_boot, @@ -1624,26 +1633,15 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { }, }; -static int __devinit wl12xx_probe(struct platform_device *pdev) +static int wl12xx_setup(struct wl1271 *wl) { - struct wl12xx_platform_data *pdata = pdev->dev.platform_data; - struct wl1271 *wl; - struct ieee80211_hw *hw; - struct wl12xx_priv *priv; - - hw = wlcore_alloc_hw(sizeof(*priv)); - if (IS_ERR(hw)) { - wl1271_error("can't allocate hw"); - return PTR_ERR(hw); - } + struct wl12xx_priv *priv = wl->priv; + struct wl12xx_platform_data *pdata = wl->pdev->dev.platform_data; - wl = hw->priv; - priv = wl->priv; - wl->ops = &wl12xx_ops; - wl->ptable = wl12xx_ptable; wl->rtable = wl12xx_rtable; - wl->num_tx_desc = 16; - wl->num_rx_desc = 8; + wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS; + wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS; + wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES; wl->band_rate_to_idx = wl12xx_band_rate_to_idx; wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX; wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0; @@ -1695,7 +1693,36 @@ static int __devinit wl12xx_probe(struct platform_device *pdev) wl1271_error("Invalid tcxo parameter %s", tcxo_param); } - return wlcore_probe(wl, pdev); + return 0; +} + +static int __devinit wl12xx_probe(struct platform_device *pdev) +{ + struct wl1271 *wl; + struct ieee80211_hw *hw; + int ret; + + hw = wlcore_alloc_hw(sizeof(struct wl12xx_priv), + WL12XX_AGGR_BUFFER_SIZE); + if (IS_ERR(hw)) { + wl1271_error("can't allocate hw"); + ret = PTR_ERR(hw); + goto out; + } + + wl = hw->priv; + wl->ops = &wl12xx_ops; + wl->ptable = wl12xx_ptable; + ret = wlcore_probe(wl, pdev); + if (ret) + goto out_free; + + return ret; + +out_free: + wlcore_free_hw(wl); +out: + return ret; } static const struct platform_device_id wl12xx_id_table[] __devinitconst = { @@ -1714,17 +1741,7 @@ static struct platform_driver wl12xx_driver = { } }; -static int __init wl12xx_init(void) -{ - return platform_driver_register(&wl12xx_driver); -} -module_init(wl12xx_init); - -static void __exit wl12xx_exit(void) -{ - platform_driver_unregister(&wl12xx_driver); -} -module_exit(wl12xx_exit); +module_platform_driver(wl12xx_driver); module_param_named(fref, fref_param, charp, 0); MODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52"); diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h index 26990fb4edea..7182bbf6625d 100644 --- a/drivers/net/wireless/ti/wl12xx/wl12xx.h +++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h @@ -38,6 +38,13 @@ #define WL128X_SUBTYPE_VER 2 #define WL128X_MINOR_VER 115 +#define WL12XX_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) + +#define WL12XX_NUM_TX_DESCRIPTORS 16 +#define WL12XX_NUM_RX_DESCRIPTORS 8 + +#define WL12XX_NUM_MAC_ADDRESSES 2 + struct wl127x_rx_mem_pool_addr { u32 addr; u32 addr_extra; diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 3ce6f1039af3..7f1669cdea09 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -220,7 +220,7 @@ static ssize_t clear_fw_stats_write(struct file *file, mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl18xx_acx_clear_statistics(wl); diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 31cf6eba3a9e..a39682a7c25f 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -45,7 +45,6 @@ static char *ht_mode_param = NULL; static char *board_type_param = NULL; static bool checksum_param = false; -static bool enable_11a_param = true; static int num_rx_desc_param = -1; /* phy paramters */ @@ -415,7 +414,7 @@ static struct wlcore_conf wl18xx_conf = { .snr_threshold = 0, }, .ht = { - .rx_ba_win_size = 10, + .rx_ba_win_size = 32, .tx_ba_win_size = 64, .inactivity_timeout = 10000, .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, @@ -505,8 +504,8 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = { .rdl = 0x01, .auto_detect = 0x00, .dedicated_fem = FEM_NONE, - .low_band_component = COMPONENT_2_WAY_SWITCH, - .low_band_component_type = 0x06, + .low_band_component = COMPONENT_3_WAY_SWITCH, + .low_band_component_type = 0x04, .high_band_component = COMPONENT_2_WAY_SWITCH, .high_band_component_type = 0x09, .tcxo_ldo_voltage = 0x00, @@ -812,6 +811,13 @@ static int wl18xx_enable_interrupts(struct wl1271 *wl) ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL & ~intr_mask); + if (ret < 0) + goto disable_interrupts; + + return ret; + +disable_interrupts: + wlcore_disable_interrupts(wl); out: return ret; @@ -1202,6 +1208,12 @@ static int wl18xx_handle_static_data(struct wl1271 *wl, struct wl18xx_static_data_priv *static_data_priv = (struct wl18xx_static_data_priv *) static_data->priv; + strncpy(wl->chip.phy_fw_ver_str, static_data_priv->phy_version, + sizeof(wl->chip.phy_fw_ver_str)); + + /* make sure the string is NULL-terminated */ + wl->chip.phy_fw_ver_str[sizeof(wl->chip.phy_fw_ver_str) - 1] = '\0'; + wl1271_info("PHY firmware version: %s", static_data_priv->phy_version); return 0; @@ -1240,13 +1252,6 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, if (!change_spare) return wlcore_set_key(wl, cmd, vif, sta, key_conf); - /* - * stop the queues and flush to ensure the next packets are - * in sync with FW spare block accounting - */ - wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); - wl1271_tx_flush(wl); - ret = wlcore_set_key(wl, cmd, vif, sta, key_conf); if (ret < 0) goto out; @@ -1269,7 +1274,6 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, } out: - wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); return ret; } @@ -1292,7 +1296,10 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl, return buf_offset; } +static int wl18xx_setup(struct wl1271 *wl); + static struct wlcore_ops wl18xx_ops = { + .setup = wl18xx_setup, .identify_chip = wl18xx_identify_chip, .boot = wl18xx_boot, .plt_init = wl18xx_plt_init, @@ -1373,27 +1380,15 @@ static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = { }, }; -static int __devinit wl18xx_probe(struct platform_device *pdev) +static int wl18xx_setup(struct wl1271 *wl) { - struct wl1271 *wl; - struct ieee80211_hw *hw; - struct wl18xx_priv *priv; + struct wl18xx_priv *priv = wl->priv; int ret; - hw = wlcore_alloc_hw(sizeof(*priv)); - if (IS_ERR(hw)) { - wl1271_error("can't allocate hw"); - ret = PTR_ERR(hw); - goto out; - } - - wl = hw->priv; - priv = wl->priv; - wl->ops = &wl18xx_ops; - wl->ptable = wl18xx_ptable; wl->rtable = wl18xx_rtable; - wl->num_tx_desc = 32; - wl->num_rx_desc = 32; + wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS; + wl->num_rx_desc = WL18XX_NUM_TX_DESCRIPTORS; + wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES; wl->band_rate_to_idx = wl18xx_band_rate_to_idx; wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX; wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0; @@ -1404,9 +1399,9 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) if (num_rx_desc_param != -1) wl->num_rx_desc = num_rx_desc_param; - ret = wl18xx_conf_init(wl, &pdev->dev); + ret = wl18xx_conf_init(wl, wl->dev); if (ret < 0) - goto out_free; + return ret; /* If the module param is set, update it in conf */ if (board_type_param) { @@ -1423,27 +1418,14 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) } else { wl1271_error("invalid board type '%s'", board_type_param); - ret = -EINVAL; - goto out_free; + return -EINVAL; } } - /* HACK! Just for now we hardcode COM8 and HDK to 0x06 */ - switch (priv->conf.phy.board_type) { - case BOARD_TYPE_HDK_18XX: - case BOARD_TYPE_COM8_18XX: - priv->conf.phy.low_band_component_type = 0x06; - break; - case BOARD_TYPE_FPGA_18XX: - case BOARD_TYPE_DVP_18XX: - case BOARD_TYPE_EVB_18XX: - priv->conf.phy.low_band_component_type = 0x05; - break; - default: + if (priv->conf.phy.board_type >= NUM_BOARD_TYPES) { wl1271_error("invalid board type '%d'", priv->conf.phy.board_type); - ret = -EINVAL; - goto out_free; + return -EINVAL; } if (low_band_component_param != -1) @@ -1475,22 +1457,21 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) priv->conf.ht.mode = HT_MODE_SISO20; else { wl1271_error("invalid ht_mode '%s'", ht_mode_param); - ret = -EINVAL; - goto out_free; + return -EINVAL; } } if (priv->conf.ht.mode == HT_MODE_DEFAULT) { /* * Only support mimo with multiple antennas. Fall back to - * siso20. + * siso40. */ if (wl18xx_is_mimo_supported(wl)) wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl18xx_mimo_ht_cap_2ghz); else wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, - &wl18xx_siso20_ht_cap); + &wl18xx_siso40_ht_cap_2ghz); /* 5Ghz is always wide */ wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, @@ -1512,9 +1493,34 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) wl18xx_ops.init_vif = NULL; } - wl->enable_11a = enable_11a_param; + /* Enable 11a Band only if we have 5G antennas */ + wl->enable_11a = (priv->conf.phy.number_of_assembled_ant5 != 0); + + return 0; +} - return wlcore_probe(wl, pdev); +static int __devinit wl18xx_probe(struct platform_device *pdev) +{ + struct wl1271 *wl; + struct ieee80211_hw *hw; + int ret; + + hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv), + WL18XX_AGGR_BUFFER_SIZE); + if (IS_ERR(hw)) { + wl1271_error("can't allocate hw"); + ret = PTR_ERR(hw); + goto out; + } + + wl = hw->priv; + wl->ops = &wl18xx_ops; + wl->ptable = wl18xx_ptable; + ret = wlcore_probe(wl, pdev); + if (ret) + goto out_free; + + return ret; out_free: wlcore_free_hw(wl); @@ -1538,18 +1544,7 @@ static struct platform_driver wl18xx_driver = { } }; -static int __init wl18xx_init(void) -{ - return platform_driver_register(&wl18xx_driver); -} -module_init(wl18xx_init); - -static void __exit wl18xx_exit(void) -{ - platform_driver_unregister(&wl18xx_driver); -} -module_exit(wl18xx_exit); - +module_platform_driver(wl18xx_driver); module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR); MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20"); @@ -1560,9 +1555,6 @@ MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or " module_param_named(checksum, checksum_param, bool, S_IRUSR); MODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)"); -module_param_named(enable_11a, enable_11a_param, bool, S_IRUSR); -MODULE_PARM_DESC(enable_11a, "Enable 11a (5GHz): boolean (defaults to true)"); - module_param_named(dc2dc, dc2dc_param, int, S_IRUSR); MODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)"); diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index 6452396fa1d4..96a1e438d677 100644 --- a/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h @@ -33,6 +33,13 @@ #define WL18XX_CMD_MAX_SIZE 740 +#define WL18XX_AGGR_BUFFER_SIZE (13 * PAGE_SIZE) + +#define WL18XX_NUM_TX_DESCRIPTORS 32 +#define WL18XX_NUM_RX_DESCRIPTORS 32 + +#define WL18XX_NUM_MAC_ADDRESSES 3 + struct wl18xx_priv { /* buffer for sending commands to FW */ u8 cmd_buf[WL18XX_CMD_MAX_SIZE]; diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 20e1bd923832..eaef3f41b252 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -59,6 +59,9 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, u16 status; u16 poll_count = 0; + if (WARN_ON(unlikely(wl->state == WLCORE_STATE_RESTARTING))) + return -EIO; + cmd = buf; cmd->id = cpu_to_le16(id); cmd->status = 0; @@ -990,7 +993,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV, skb->data, skb->len, - CMD_TEMPL_KLV_IDX_NULL_DATA, + wlvif->sta.klv_template_id, wlvif->basic_rate); out: @@ -1785,10 +1788,17 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) wlvif->bss_type == BSS_TYPE_IBSS))) return -EINVAL; - ret = wl12xx_cmd_role_start_dev(wl, wlvif); + ret = wl12xx_cmd_role_enable(wl, + wl12xx_wlvif_to_vif(wlvif)->addr, + WL1271_ROLE_DEVICE, + &wlvif->dev_role_id); if (ret < 0) goto out; + ret = wl12xx_cmd_role_start_dev(wl, wlvif); + if (ret < 0) + goto out_disable; + ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id); if (ret < 0) goto out_stop; @@ -1797,6 +1807,8 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) out_stop: wl12xx_cmd_role_stop_dev(wl, wlvif); +out_disable: + wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); out: return ret; } @@ -1824,6 +1836,11 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) ret = wl12xx_cmd_role_stop_dev(wl, wlvif); if (ret < 0) goto out; + + ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); + if (ret < 0) + goto out; + out: return ret; } diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 4ef0b095f0d6..2409f3d71f63 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -157,11 +157,6 @@ enum wl1271_commands { #define MAX_CMD_PARAMS 572 -enum { - CMD_TEMPL_KLV_IDX_NULL_DATA = 0, - CMD_TEMPL_KLV_IDX_MAX = 4 -}; - enum cmd_templ { CMD_TEMPL_NULL_DATA = 0, CMD_TEMPL_BEACON, diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index d77224f2ac6b..9e40760bafe1 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -412,8 +412,7 @@ struct conf_rx_settings { #define CONF_TX_RATE_RETRY_LIMIT 10 /* basic rates for p2p operations (probe req/resp, etc.) */ -#define CONF_TX_RATE_MASK_BASIC_P2P (CONF_HW_BIT_RATE_6MBPS | \ - CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS) +#define CONF_TX_RATE_MASK_BASIC_P2P CONF_HW_BIT_RATE_6MBPS /* * Rates supported for data packets when operating as AP. Note the absence diff --git a/drivers/net/wireless/ti/wlcore/debug.h b/drivers/net/wireless/ti/wlcore/debug.h index 6b800b3cbea5..db4bf5a68ce2 100644 --- a/drivers/net/wireless/ti/wlcore/debug.h +++ b/drivers/net/wireless/ti/wlcore/debug.h @@ -28,7 +28,7 @@ #include <linux/bitops.h> #include <linux/printk.h> -#define DRIVER_NAME "wl12xx" +#define DRIVER_NAME "wlcore" #define DRIVER_PREFIX DRIVER_NAME ": " enum { @@ -73,11 +73,21 @@ extern u32 wl12xx_debug_level; #define wl1271_info(fmt, arg...) \ pr_info(DRIVER_PREFIX fmt "\n", ##arg) +/* define the debug macro differently if dynamic debug is supported */ +#if defined(CONFIG_DYNAMIC_DEBUG) #define wl1271_debug(level, fmt, arg...) \ do { \ - if (level & wl12xx_debug_level) \ - pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \ + if (unlikely(level & wl12xx_debug_level)) \ + dynamic_pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) +#else +#define wl1271_debug(level, fmt, arg...) \ + do { \ + if (unlikely(level & wl12xx_debug_level)) \ + printk(KERN_DEBUG pr_fmt(DRIVER_PREFIX fmt "\n"), \ + ##arg); \ } while (0) +#endif /* TODO: use pr_debug_hex_dump when it becomes available */ #define wl1271_dump(level, prefix, buf, len) \ diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index 80dbc5304fac..c86bb00c2488 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -62,11 +62,14 @@ void wl1271_debugfs_update_stats(struct wl1271 *wl) mutex_lock(&wl->mutex); + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; - if (wl->state == WL1271_STATE_ON && !wl->plt && + if (!wl->plt && time_after(jiffies, wl->stats.fw_stats_update + msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) { wl1271_acx_statistics(wl, wl->stats.fw_stats); @@ -286,7 +289,7 @@ static ssize_t dynamic_ps_timeout_write(struct file *file, wl->conf.conn.dynamic_ps_timeout = value; - if (wl->state == WL1271_STATE_OFF) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl1271_ps_elp_wakeup(wl); @@ -353,7 +356,7 @@ static ssize_t forced_ps_write(struct file *file, wl->conf.conn.forced_ps = value; - if (wl->state == WL1271_STATE_OFF) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl1271_ps_elp_wakeup(wl); @@ -486,6 +489,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_HEX(platform_quirks); DRIVER_STATE_PRINT_HEX(chip.id); DRIVER_STATE_PRINT_STR(chip.fw_ver_str); + DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str); DRIVER_STATE_PRINT_INT(sched_scanning); #undef DRIVER_STATE_PRINT_INT @@ -999,7 +1003,7 @@ static ssize_t sleep_auth_write(struct file *file, wl->conf.conn.sta_sleep_auth = value; - if (wl->state == WL1271_STATE_OFF) { + if (unlikely(wl->state != WLCORE_STATE_ON)) { /* this will show up on "read" in case we are off */ wl->sleep_auth = value; goto out; @@ -1060,14 +1064,16 @@ static ssize_t dev_mem_read(struct file *file, mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) { + if (unlikely(wl->state == WLCORE_STATE_OFF)) { ret = -EFAULT; goto skip_read; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto skip_read; + /* + * Don't fail if elp_wakeup returns an error, so the device's memory + * could be read even if the FW crashed + */ + wl1271_ps_elp_wakeup(wl); /* store current partition and switch partition */ memcpy(&old_part, &wl->curr_part, sizeof(old_part)); @@ -1145,14 +1151,16 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf, mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) { + if (unlikely(wl->state == WLCORE_STATE_OFF)) { ret = -EFAULT; goto skip_write; } - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto skip_write; + /* + * Don't fail if elp_wakeup returns an error, so the device's memory + * could be read even if the FW crashed + */ + wl1271_ps_elp_wakeup(wl); /* store current partition and switch partition */ memcpy(&old_part, &wl->curr_part, sizeof(old_part)); diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index a3c867786df8..32d157f62f31 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -141,7 +141,7 @@ int wl1271_init_templates_config(struct wl1271 *wl) if (ret < 0) return ret; - for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { + for (i = 0; i < WLCORE_MAX_KLV_TEMPLATES; i++) { ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_KLV, NULL, sizeof(struct ieee80211_qos_hdr), @@ -371,15 +371,7 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret, i; - - /* disable all keep-alive templates */ - for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { - ret = wl1271_acx_keep_alive_config(wl, wlvif, i, - ACX_KEEP_ALIVE_TPL_INVALID); - if (ret < 0) - return ret; - } + int ret; /* disable the keep-alive feature */ ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index 259149f36fae..f48530fec14f 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h @@ -64,7 +64,7 @@ static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr, return -EIO; ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed); - if (ret && wl->state != WL1271_STATE_OFF) + if (ret && wl->state != WLCORE_STATE_OFF) set_bit(WL1271_FLAG_IO_FAILED, &wl->flags); return ret; @@ -80,7 +80,7 @@ static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr, return -EIO; ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed); - if (ret && wl->state != WL1271_STATE_OFF) + if (ret && wl->state != WLCORE_STATE_OFF) set_bit(WL1271_FLAG_IO_FAILED, &wl->flags); return ret; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ff830cf50c70..25530c8760cb 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -248,7 +248,7 @@ static void wl12xx_tx_watchdog_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; /* Tx went out in the meantime - everything is ok */ @@ -512,7 +512,7 @@ static int wlcore_irq_locked(struct wl1271 *wl) wl1271_debug(DEBUG_IRQ, "IRQ work"); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl1271_ps_elp_wakeup(wl); @@ -696,7 +696,7 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt) * we can't call wl12xx_get_vif_count() here because * wl->mutex is taken, so use the cached last_vif_count value */ - if (wl->last_vif_count > 1) { + if (wl->last_vif_count > 1 && wl->mr_fw_name) { fw_type = WL12XX_FW_TYPE_MULTI; fw_name = wl->mr_fw_name; } else { @@ -744,38 +744,14 @@ out: return ret; } -static void wl1271_fetch_nvs(struct wl1271 *wl) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev); - - if (ret < 0) { - wl1271_debug(DEBUG_BOOT, "could not get nvs file %s: %d", - WL12XX_NVS_NAME, ret); - return; - } - - wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); - - if (!wl->nvs) { - wl1271_error("could not allocate memory for the nvs file"); - goto out; - } - - wl->nvs_len = fw->size; - -out: - release_firmware(fw); -} - void wl12xx_queue_recovery_work(struct wl1271 *wl) { WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); /* Avoid a recursive recovery */ - if (!test_and_set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { + if (wl->state == WLCORE_STATE_ON) { + wl->state = WLCORE_STATE_RESTARTING; + set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); wlcore_disable_interrupts_nosync(wl); ieee80211_queue_work(wl->hw, &wl->recovery_work); } @@ -913,7 +889,7 @@ static void wl1271_recovery_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (wl->state != WL1271_STATE_ON || wl->plt) + if (wl->state == WLCORE_STATE_OFF || wl->plt) goto out_unlock; if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) { @@ -1081,7 +1057,7 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode) wl1271_notice("power up"); - if (wl->state != WL1271_STATE_OFF) { + if (wl->state != WLCORE_STATE_OFF) { wl1271_error("cannot go into PLT state because not " "in off state: %d", wl->state); ret = -EBUSY; @@ -1102,7 +1078,7 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode) if (ret < 0) goto power_off; - wl->state = WL1271_STATE_ON; + wl->state = WLCORE_STATE_ON; wl1271_notice("firmware booted in PLT mode %s (%s)", PLT_MODE[plt_mode], wl->chip.fw_ver_str); @@ -1171,7 +1147,7 @@ int wl1271_plt_stop(struct wl1271 *wl) wl1271_power_off(wl); wl->flags = 0; wl->sleep_auth = WL1271_PSM_ILLEGAL; - wl->state = WL1271_STATE_OFF; + wl->state = WLCORE_STATE_OFF; wl->plt = false; wl->plt_mode = PLT_OFF; wl->rx_counter = 0; @@ -1602,12 +1578,6 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) goto out; - if ((wl->conf.conn.suspend_wake_up_event == - wl->conf.conn.wake_up_event) && - (wl->conf.conn.suspend_listen_interval == - wl->conf.conn.listen_interval)) - goto out; - ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -1616,6 +1586,12 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (ret < 0) goto out_sleep; + if ((wl->conf.conn.suspend_wake_up_event == + wl->conf.conn.wake_up_event) && + (wl->conf.conn.suspend_listen_interval == + wl->conf.conn.listen_interval)) + goto out_sleep; + ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.suspend_wake_up_event, wl->conf.conn.suspend_listen_interval); @@ -1671,11 +1647,7 @@ static void wl1271_configure_resume(struct wl1271 *wl, if ((!is_ap) && (!is_sta)) return; - if (is_sta && - ((wl->conf.conn.suspend_wake_up_event == - wl->conf.conn.wake_up_event) && - (wl->conf.conn.suspend_listen_interval == - wl->conf.conn.listen_interval))) + if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) return; ret = wl1271_ps_elp_wakeup(wl); @@ -1685,6 +1657,12 @@ static void wl1271_configure_resume(struct wl1271 *wl, if (is_sta) { wl1271_configure_wowlan(wl, NULL); + if ((wl->conf.conn.suspend_wake_up_event == + wl->conf.conn.wake_up_event) && + (wl->conf.conn.suspend_listen_interval == + wl->conf.conn.listen_interval)) + goto out_sleep; + ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.wake_up_event, wl->conf.conn.listen_interval); @@ -1697,6 +1675,7 @@ static void wl1271_configure_resume(struct wl1271 *wl, ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); } +out_sleep: wl1271_ps_elp_sleep(wl); } @@ -1833,7 +1812,7 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) { int i; - if (wl->state == WL1271_STATE_OFF) { + if (wl->state == WLCORE_STATE_OFF) { if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) wlcore_enable_interrupts(wl); @@ -1845,7 +1824,7 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) * this must be before the cancel_work calls below, so that the work * functions don't perform further work. */ - wl->state = WL1271_STATE_OFF; + wl->state = WLCORE_STATE_OFF; /* * Use the nosync variant to disable interrupts, so the mutex could be @@ -1856,6 +1835,8 @@ static void wlcore_op_stop_locked(struct wl1271 *wl) mutex_unlock(&wl->mutex); wlcore_synchronize_interrupts(wl); + if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) + cancel_work_sync(&wl->recovery_work); wl1271_flush_deferred_work(wl); cancel_delayed_work_sync(&wl->scan_complete_work); cancel_work_sync(&wl->netstack_work); @@ -1958,6 +1939,27 @@ static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx) *idx = WL12XX_MAX_RATE_POLICIES; } +static int wlcore_allocate_klv_template(struct wl1271 *wl, u8 *idx) +{ + u8 policy = find_first_zero_bit(wl->klv_templates_map, + WLCORE_MAX_KLV_TEMPLATES); + if (policy >= WLCORE_MAX_KLV_TEMPLATES) + return -EBUSY; + + __set_bit(policy, wl->klv_templates_map); + *idx = policy; + return 0; +} + +static void wlcore_free_klv_template(struct wl1271 *wl, u8 *idx) +{ + if (WARN_ON(*idx >= WLCORE_MAX_KLV_TEMPLATES)) + return; + + __clear_bit(*idx, wl->klv_templates_map); + *idx = WLCORE_MAX_KLV_TEMPLATES; +} + static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif) { switch (wlvif->bss_type) { @@ -2022,6 +2024,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx); wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx); wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx); + wlcore_allocate_klv_template(wl, &wlvif->sta.klv_template_id); wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC; wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC; wlvif->rate_set = CONF_TX_RATE_MASK_BASIC; @@ -2098,7 +2101,7 @@ irq_disable: /* Unlocking the mutex in the middle of handling is inherently unsafe. In this case we deem it safe to do, because we need to let any possibly pending IRQ out of - the system (and while we are WL1271_STATE_OFF the IRQ + the system (and while we are WLCORE_STATE_OFF the IRQ work function will not do anything.) Also, any other possible concurrent operations will fail due to the current state, hence the wl1271 struct should be safe. */ @@ -2133,7 +2136,7 @@ power_off: wl1271_debug(DEBUG_MAC80211, "11a is %ssupported", wl->enable_11a ? "" : "not "); - wl->state = WL1271_STATE_ON; + wl->state = WLCORE_STATE_ON; out: return booted; } @@ -2167,7 +2170,11 @@ static bool wl12xx_need_fw_change(struct wl1271 *wl, wl->last_vif_count = vif_count; /* no need for fw change if the device is OFF */ - if (wl->state == WL1271_STATE_OFF) + if (wl->state == WLCORE_STATE_OFF) + return false; + + /* no need for fw change if a single fw is used */ + if (!wl->mr_fw_name) return false; if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL) @@ -2249,7 +2256,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, * TODO: after the nvs issue will be solved, move this block * to start(), and make sure here the driver is ON. */ - if (wl->state == WL1271_STATE_OFF) { + if (wl->state == WLCORE_STATE_OFF) { /* * we still need this in order to configure the fw * while uploading the nvs @@ -2263,21 +2270,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, } } - if (wlvif->bss_type == BSS_TYPE_STA_BSS || - wlvif->bss_type == BSS_TYPE_IBSS) { - /* - * The device role is a special role used for - * rx and tx frames prior to association (as - * the STA role can get packets only from - * its associated bssid) - */ - ret = wl12xx_cmd_role_enable(wl, vif->addr, - WL1271_ROLE_DEVICE, - &wlvif->dev_role_id); - if (ret < 0) - goto out; - } - ret = wl12xx_cmd_role_enable(wl, vif->addr, role_type, &wlvif->role_id); if (ret < 0) @@ -2316,7 +2308,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, return; /* because of hardware recovery, we may get here twice */ - if (wl->state != WL1271_STATE_ON) + if (wl->state == WLCORE_STATE_OFF) return; wl1271_info("down"); @@ -2346,10 +2338,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wlvif->bss_type == BSS_TYPE_IBSS) { if (wl12xx_dev_role_started(wlvif)) wl12xx_stop_dev(wl, wlvif); - - ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); - if (ret < 0) - goto deinit; } ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); @@ -2368,6 +2356,7 @@ deinit: wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx); wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx); wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx); + wlcore_free_klv_template(wl, &wlvif->sta.klv_template_id); } else { wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID; wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID; @@ -2432,12 +2421,11 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl12xx_vif *iter; struct vif_counter_data vif_count; - bool cancel_recovery = true; wl12xx_get_vif_count(hw, vif, &vif_count); mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF || + if (wl->state == WLCORE_STATE_OFF || !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) goto out; @@ -2457,12 +2445,9 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, wl12xx_force_active_psm(wl); set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); wl12xx_queue_recovery_work(wl); - cancel_recovery = false; } out: mutex_unlock(&wl->mutex); - if (cancel_recovery) - cancel_work_sync(&wl->recovery_work); } static int wl12xx_op_change_interface(struct ieee80211_hw *hw, @@ -2536,7 +2521,7 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, goto out; ret = wl1271_acx_keep_alive_config(wl, wlvif, - CMD_TEMPL_KLV_IDX_NULL_DATA, + wlvif->sta.klv_template_id, ACX_KEEP_ALIVE_TPL_VALID); if (ret < 0) goto out; @@ -2556,6 +2541,11 @@ static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif) ieee80211_chswitch_done(vif, false); } + /* invalidate keep-alive template */ + wl1271_acx_keep_alive_config(wl, wlvif, + wlvif->sta.klv_template_id, + ACX_KEEP_ALIVE_TPL_INVALID); + /* to stop listening to a channel, we disconnect */ ret = wl12xx_cmd_role_stop_sta(wl, wlvif); if (ret < 0) @@ -2596,11 +2586,6 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, ret = wl1271_acx_sta_rate_policies(wl, wlvif); if (ret < 0) goto out; - ret = wl1271_acx_keep_alive_config( - wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA, - ACX_KEEP_ALIVE_TPL_INVALID); - if (ret < 0) - goto out; clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); } else { /* The current firmware only supports sched_scan in idle */ @@ -2772,7 +2757,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_POWER) wl->power_level = conf->power_level; - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl1271_ps_elp_wakeup(wl); @@ -2806,10 +2791,6 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, { struct wl1271_filter_params *fp; struct netdev_hw_addr *ha; - struct wl1271 *wl = hw->priv; - - if (unlikely(wl->state == WL1271_STATE_OFF)) - return 0; fp = kzalloc(sizeof(*fp), GFP_ATOMIC); if (!fp) { @@ -2858,7 +2839,7 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, *total &= WL1271_SUPPORTED_FILTERS; changed &= WL1271_SUPPORTED_FILTERS; - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl1271_ps_elp_wakeup(wl); @@ -3082,8 +3063,45 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key_conf) { struct wl1271 *wl = hw->priv; + int ret; + bool might_change_spare = + key_conf->cipher == WL1271_CIPHER_SUITE_GEM || + key_conf->cipher == WLAN_CIPHER_SUITE_TKIP; - return wlcore_hw_set_key(wl, cmd, vif, sta, key_conf); + if (might_change_spare) { + /* + * stop the queues and flush to ensure the next packets are + * in sync with FW spare block accounting + */ + mutex_lock(&wl->mutex); + wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); + mutex_unlock(&wl->mutex); + + wl1271_tx_flush(wl); + } + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) { + ret = -EAGAIN; + goto out_wake_queues; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_wake_queues; + + ret = wlcore_hw_set_key(wl, cmd, vif, sta, key_conf); + + wl1271_ps_elp_sleep(wl); + +out_wake_queues: + if (might_change_spare) + wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); + + mutex_unlock(&wl->mutex); + + return ret; } int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, @@ -3105,17 +3123,6 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, key_conf->keylen, key_conf->flags); wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; - goto out_unlock; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - switch (key_conf->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: @@ -3145,8 +3152,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, default: wl1271_error("Unknown key algo 0x%x", key_conf->cipher); - ret = -EOPNOTSUPP; - goto out_sleep; + return -EOPNOTSUPP; } switch (cmd) { @@ -3157,7 +3163,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, tx_seq_32, tx_seq_16, sta); if (ret < 0) { wl1271_error("Could not add or replace key"); - goto out_sleep; + return ret; } /* @@ -3171,7 +3177,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, ret = wl1271_cmd_build_arp_rsp(wl, wlvif); if (ret < 0) { wl1271_warning("build arp rsp failed: %d", ret); - goto out_sleep; + return ret; } } break; @@ -3183,22 +3189,15 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, 0, 0, sta); if (ret < 0) { wl1271_error("Could not remove key"); - goto out_sleep; + return ret; } break; default: wl1271_error("Unsupported key cmd 0x%x", cmd); - ret = -EOPNOTSUPP; - break; + return -EOPNOTSUPP; } -out_sleep: - wl1271_ps_elp_sleep(wl); - -out_unlock: - mutex_unlock(&wl->mutex); - return ret; } EXPORT_SYMBOL_GPL(wlcore_set_key); @@ -3221,7 +3220,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) { + if (unlikely(wl->state != WLCORE_STATE_ON)) { /* * We cannot return -EBUSY here because cfg80211 will expect * a call to ieee80211_scan_completed if we do - in this case @@ -3261,7 +3260,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) @@ -3310,7 +3309,7 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) { + if (unlikely(wl->state != WLCORE_STATE_ON)) { ret = -EAGAIN; goto out; } @@ -3347,7 +3346,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl1271_ps_elp_wakeup(wl); @@ -3368,7 +3367,7 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) { + if (unlikely(wl->state != WLCORE_STATE_ON)) { ret = -EAGAIN; goto out; } @@ -3397,7 +3396,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) { + if (unlikely(wl->state != WLCORE_STATE_ON)) { ret = -EAGAIN; goto out; } @@ -4173,7 +4172,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) @@ -4257,7 +4256,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl1271_ps_elp_wakeup(wl); @@ -4456,7 +4455,7 @@ static int wl12xx_op_sta_state(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) { + if (unlikely(wl->state != WLCORE_STATE_ON)) { ret = -EBUSY; goto out; } @@ -4495,7 +4494,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) { + if (unlikely(wl->state != WLCORE_STATE_ON)) { ret = -EAGAIN; goto out; } @@ -4613,7 +4612,7 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, mask->control[i].legacy, i); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; if (wlvif->bss_type == BSS_TYPE_STA_BSS && @@ -4649,12 +4648,14 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) { + if (unlikely(wl->state == WLCORE_STATE_OFF)) { wl12xx_for_each_wlvif_sta(wl, wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); ieee80211_chswitch_done(vif, false); } goto out; + } else if (unlikely(wl->state != WLCORE_STATE_ON)) { + goto out; } ret = wl1271_ps_elp_wakeup(wl); @@ -4689,7 +4690,7 @@ static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; /* packets are considered pending if in the TX queue or the FW */ @@ -4938,7 +4939,7 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, wl->sg_enabled = res; - if (wl->state == WL1271_STATE_OFF) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl1271_ps_elp_wakeup(wl); @@ -5056,7 +5057,7 @@ static void wl1271_connection_loss_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; /* Call mac80211 connection loss */ @@ -5070,18 +5071,17 @@ out: mutex_unlock(&wl->mutex); } -static void wl12xx_derive_mac_addresses(struct wl1271 *wl, - u32 oui, u32 nic, int n) +static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic) { int i; - wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d", - oui, nic, n); + wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x", + oui, nic); - if (nic + n - 1 > 0xffffff) + if (nic + WLCORE_NUM_MAC_ADDRESSES - wl->num_mac_addr > 0xffffff) wl1271_warning("NIC part of the MAC address wraps around!"); - for (i = 0; i < n; i++) { + for (i = 0; i < wl->num_mac_addr; i++) { wl->addresses[i].addr[0] = (u8)(oui >> 16); wl->addresses[i].addr[1] = (u8)(oui >> 8); wl->addresses[i].addr[2] = (u8) oui; @@ -5091,7 +5091,22 @@ static void wl12xx_derive_mac_addresses(struct wl1271 *wl, nic++; } - wl->hw->wiphy->n_addresses = n; + /* we may be one address short at the most */ + WARN_ON(wl->num_mac_addr + 1 < WLCORE_NUM_MAC_ADDRESSES); + + /* + * turn on the LAA bit in the first address and use it as + * the last address. + */ + if (wl->num_mac_addr < WLCORE_NUM_MAC_ADDRESSES) { + int idx = WLCORE_NUM_MAC_ADDRESSES - 1; + memcpy(&wl->addresses[idx], &wl->addresses[0], + sizeof(wl->addresses[0])); + /* LAA bit */ + wl->addresses[idx].addr[2] |= BIT(1); + } + + wl->hw->wiphy->n_addresses = WLCORE_NUM_MAC_ADDRESSES; wl->hw->wiphy->addresses = wl->addresses; } @@ -5130,8 +5145,7 @@ static int wl1271_register_hw(struct wl1271 *wl) if (wl->mac80211_registered) return 0; - wl1271_fetch_nvs(wl); - if (wl->nvs != NULL) { + if (wl->nvs_len >= 12) { /* NOTE: The wl->nvs->nvs element must be first, in * order to simplify the casting, we assume it is at * the beginning of the wl->nvs structure. @@ -5151,7 +5165,7 @@ static int wl1271_register_hw(struct wl1271 *wl) nic_addr = wl->fuse_nic_addr + 1; } - wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2); + wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr); ret = ieee80211_register_hw(wl->hw); if (ret < 0) { @@ -5181,7 +5195,7 @@ static void wl1271_unregister_hw(struct wl1271 *wl) static const struct ieee80211_iface_limit wlcore_iface_limits[] = { { - .max = 2, + .max = 3, .types = BIT(NL80211_IFTYPE_STATION), }, { @@ -5196,7 +5210,7 @@ static const struct ieee80211_iface_combination wlcore_iface_combinations[] = { { .num_different_channels = 1, - .max_interfaces = 2, + .max_interfaces = 3, .limits = wlcore_iface_limits, .n_limits = ARRAY_SIZE(wlcore_iface_limits), }, @@ -5312,7 +5326,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) #define WL1271_DEFAULT_CHANNEL 0 -struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size) +struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size) { struct ieee80211_hw *hw; struct wl1271 *wl; @@ -5392,17 +5406,19 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size) spin_lock_init(&wl->wl_lock); - wl->state = WL1271_STATE_OFF; + wl->state = WLCORE_STATE_OFF; wl->fw_type = WL12XX_FW_TYPE_NONE; mutex_init(&wl->mutex); mutex_init(&wl->flush_mutex); + init_completion(&wl->nvs_loading_complete); - order = get_order(WL1271_AGGR_BUFFER_SIZE); + order = get_order(aggr_buf_size); wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); if (!wl->aggr_buf) { ret = -ENOMEM; goto err_wq; } + wl->aggr_buf_size = aggr_buf_size; wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); if (!wl->dummy_packet) { @@ -5465,8 +5481,7 @@ int wlcore_free_hw(struct wl1271 *wl) device_remove_file(wl->dev, &dev_attr_bt_coex_state); free_page((unsigned long)wl->fwlog); dev_kfree_skb(wl->dummy_packet); - free_pages((unsigned long)wl->aggr_buf, - get_order(WL1271_AGGR_BUFFER_SIZE)); + free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size)); wl1271_debugfs_exit(wl); @@ -5516,17 +5531,32 @@ static irqreturn_t wl12xx_hardirq(int irq, void *cookie) return IRQ_WAKE_THREAD; } -int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) +static void wlcore_nvs_cb(const struct firmware *fw, void *context) { + struct wl1271 *wl = context; + struct platform_device *pdev = wl->pdev; struct wl12xx_platform_data *pdata = pdev->dev.platform_data; unsigned long irqflags; int ret; - if (!wl->ops || !wl->ptable) { - ret = -EINVAL; - goto out_free_hw; + if (fw) { + wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); + if (!wl->nvs) { + wl1271_error("Could not allocate nvs data"); + goto out; + } + wl->nvs_len = fw->size; + } else { + wl1271_debug(DEBUG_BOOT, "Could not get nvs file %s", + WL12XX_NVS_NAME); + wl->nvs = NULL; + wl->nvs_len = 0; } + ret = wl->ops->setup(wl); + if (ret < 0) + goto out_free_nvs; + BUG_ON(wl->num_tx_desc > WLCORE_MAX_TX_DESCRIPTORS); /* adjust some runtime configuration parameters */ @@ -5535,11 +5565,8 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) wl->irq = platform_get_irq(pdev, 0); wl->platform_quirks = pdata->platform_quirks; wl->set_power = pdata->set_power; - wl->dev = &pdev->dev; wl->if_ops = pdata->ops; - platform_set_drvdata(pdev, wl); - if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) irqflags = IRQF_TRIGGER_RISING; else @@ -5550,7 +5577,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) pdev->name, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); - goto out_free_hw; + goto out_free_nvs; } #ifdef CONFIG_PM @@ -5609,6 +5636,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) goto out_hw_pg_ver; } + wl->initialized = true; goto out; out_hw_pg_ver: @@ -5623,10 +5651,33 @@ out_unreg: out_irq: free_irq(wl->irq, wl); -out_free_hw: - wlcore_free_hw(wl); +out_free_nvs: + kfree(wl->nvs); out: + release_firmware(fw); + complete_all(&wl->nvs_loading_complete); +} + +int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) +{ + int ret; + + if (!wl->ops || !wl->ptable) + return -EINVAL; + + wl->dev = &pdev->dev; + wl->pdev = pdev; + platform_set_drvdata(pdev, wl); + + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + WL12XX_NVS_NAME, &pdev->dev, GFP_KERNEL, + wl, wlcore_nvs_cb); + if (ret < 0) { + wl1271_error("request_firmware_nowait failed: %d", ret); + complete_all(&wl->nvs_loading_complete); + } + return ret; } EXPORT_SYMBOL_GPL(wlcore_probe); @@ -5635,6 +5686,10 @@ int __devexit wlcore_remove(struct platform_device *pdev) { struct wl1271 *wl = platform_get_drvdata(pdev); + wait_for_completion(&wl->nvs_loading_complete); + if (!wl->initialized) + return 0; + if (wl->irq_wake_enabled) { device_init_wakeup(wl->dev, 0); disable_irq_wake(wl->irq); @@ -5665,3 +5720,4 @@ MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck."); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); +MODULE_FIRMWARE(WL12XX_NVS_NAME); diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c index 46d36fd30eba..4d1414a673fb 100644 --- a/drivers/net/wireless/ti/wlcore/ps.c +++ b/drivers/net/wireless/ti/wlcore/ps.c @@ -28,7 +28,7 @@ #define WL1271_WAKEUP_TIMEOUT 500 -#define ELP_ENTRY_DELAY 5 +#define ELP_ENTRY_DELAY 30 void wl1271_elp_work(struct work_struct *work) { @@ -44,7 +44,7 @@ void wl1271_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; /* our work might have been already cancelled */ @@ -98,11 +98,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) return; } - if (wl->conf.conn.forced_ps) - timeout = ELP_ENTRY_DELAY; - else - timeout = wl->conf.conn.dynamic_ps_timeout; - + timeout = ELP_ENTRY_DELAY; ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, msecs_to_jiffies(timeout)); } diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index f55e2f9e7ac5..9ee0ec6fd1db 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -221,7 +221,7 @@ int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) pkt_len = wlcore_rx_get_buf_size(wl, des); align_pkt_len = wlcore_rx_get_align_buf_size(wl, pkt_len); - if (buf_size + align_pkt_len > WL1271_AGGR_BUFFER_SIZE) + if (buf_size + align_pkt_len > wl->aggr_buf_size) break; buf_size += align_pkt_len; rx_counter++; diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index dbeca1bfbb2c..d00501493dfe 100644 --- a/drivers/net/wireless/ti/wlcore/scan.c +++ b/drivers/net/wireless/ti/wlcore/scan.c @@ -46,7 +46,7 @@ void wl1271_scan_complete_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) + if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) @@ -184,11 +184,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; - if (wlvif->bss_type == BSS_TYPE_AP_BSS || - test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - cmd->params.role_id = wlvif->role_id; - else - cmd->params.role_id = wlvif->dev_role_id; + cmd->params.role_id = wlvif->role_id; if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; @@ -593,7 +589,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, goto out; } - cmd->role_id = wlvif->dev_role_id; + cmd->role_id = wlvif->role_id; if (!n_match_ssids) { /* No filter, with ssids */ type = SCAN_SSID_FILTER_DISABLED; @@ -683,7 +679,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, if (!cfg) return -ENOMEM; - cfg->role_id = wlvif->dev_role_id; + cfg->role_id = wlvif->role_id; cfg->rssi_threshold = c->rssi_threshold; cfg->snr_threshold = c->snr_threshold; cfg->n_probe_reqs = c->num_probe_reqs; @@ -718,7 +714,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, if (!force_passive && cfg->active[0]) { u8 band = IEEE80211_BAND_2GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, - wlvif->dev_role_id, band, + wlvif->role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[band], @@ -732,7 +728,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, if (!force_passive && cfg->active[1]) { u8 band = IEEE80211_BAND_5GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, - wlvif->dev_role_id, band, + wlvif->role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[band], @@ -774,7 +770,7 @@ int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) if (!start) return -ENOMEM; - start->role_id = wlvif->dev_role_id; + start->role_id = wlvif->role_id; start->tag = WL1271_SCAN_DEFAULT_TAG; ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start, @@ -810,7 +806,7 @@ void wl1271_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) return; } - stop->role_id = wlvif->dev_role_id; + stop->role_id = wlvif->role_id; stop->tag = WL1271_SCAN_DEFAULT_TAG; ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 8da4ed243ebc..a519bc3adec1 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -66,7 +66,13 @@ /* 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) +/* + * only support SPI for 12xx - this code should be reworked when 18xx + * support is introduced + */ +#define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) + +#define WSPI_MAX_NUM_OF_CHUNKS (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) struct wl12xx_spi_glue { struct device *dev; @@ -271,7 +277,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, u32 chunk_len; int i; - WARN_ON(len > WL1271_AGGR_BUFFER_SIZE); + WARN_ON(len > SPI_AGGR_BUFFER_SIZE); spi_message_init(&m); memset(t, 0, sizeof(t)); diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c index 49e5ee1525c9..f3442762d884 100644 --- a/drivers/net/wireless/ti/wlcore/testmode.c +++ b/drivers/net/wireless/ti/wlcore/testmode.c @@ -92,7 +92,7 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) { + if (unlikely(wl->state != WLCORE_STATE_ON)) { ret = -EINVAL; goto out; } @@ -164,7 +164,7 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) { + if (unlikely(wl->state != WLCORE_STATE_ON)) { ret = -EINVAL; goto out; } diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 1a2f31c289c5..a90d3cd09408 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -193,7 +193,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, int id, ret = -EBUSY, ac; u32 spare_blocks; - if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) + if (buf_offset + total_len > wl->aggr_buf_size) return -EAGAIN; spare_blocks = wlcore_hw_get_spare_blocks(wl, is_gem); @@ -319,8 +319,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (hlid == wlvif->ap.global_hlid) rate_idx = wlvif->ap.mgmt_rate_idx; else if (hlid == wlvif->ap.bcast_hlid || - skb->protocol == cpu_to_be16(ETH_P_PAE)) - /* send AP bcast and EAPOLs using the min basic rate */ + skb->protocol == cpu_to_be16(ETH_P_PAE) || + !ieee80211_is_data(frame_control)) + /* + * send non-data, bcast and EAPOLs using the + * min basic rate + */ rate_idx = wlvif->ap.bcast_rate_idx; else rate_idx = wlvif->ap.ucast_rate_idx[ac]; @@ -687,7 +691,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl) int bus_ret = 0; u8 hlid; - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state != WLCORE_STATE_ON)) return 0; while ((skb = wl1271_skb_dequeue(wl, &hlid))) { @@ -1072,39 +1076,54 @@ void wl12xx_tx_reset(struct wl1271 *wl) /* caller must *NOT* hold wl->mutex */ void wl1271_tx_flush(struct wl1271 *wl) { - unsigned long timeout; + unsigned long timeout, start_time; int i; - timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); + start_time = jiffies; + timeout = start_time + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); /* only one flush should be in progress, for consistent queue state */ mutex_lock(&wl->flush_mutex); + mutex_lock(&wl->mutex); + if (wl->tx_frames_cnt == 0 && wl1271_tx_total_queue_count(wl) == 0) { + mutex_unlock(&wl->mutex); + goto out; + } + wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH); while (!time_after(jiffies, timeout)) { - mutex_lock(&wl->mutex); - wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", + wl1271_debug(DEBUG_MAC80211, "flushing tx buffer: %d %d", wl->tx_frames_cnt, wl1271_tx_total_queue_count(wl)); + + /* force Tx and give the driver some time to flush data */ + mutex_unlock(&wl->mutex); + if (wl1271_tx_total_queue_count(wl)) + wl1271_tx_work(&wl->tx_work); + msleep(20); + mutex_lock(&wl->mutex); + if ((wl->tx_frames_cnt == 0) && (wl1271_tx_total_queue_count(wl) == 0)) { - mutex_unlock(&wl->mutex); - goto out; + wl1271_debug(DEBUG_MAC80211, "tx flush took %d ms", + jiffies_to_msecs(jiffies - start_time)); + goto out_wake; } - mutex_unlock(&wl->mutex); - msleep(1); } - wl1271_warning("Unable to flush all TX buffers, timed out."); + wl1271_warning("Unable to flush all TX buffers, " + "timed out (timeout %d ms", + WL1271_TX_FLUSH_TIMEOUT / 1000); /* forcibly flush all Tx buffers on our queues */ - mutex_lock(&wl->mutex); for (i = 0; i < WL12XX_MAX_LINKS; i++) wl1271_tx_reset_link_queues(wl, i); - mutex_unlock(&wl->mutex); -out: +out_wake: wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH); + mutex_unlock(&wl->mutex); +out: mutex_unlock(&wl->flush_mutex); } EXPORT_SYMBOL_GPL(wl1271_tx_flush); diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 0ce7a8ebbd46..68584aa0f2b0 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -31,12 +31,19 @@ /* The maximum number of Tx descriptors in all chip families */ #define WLCORE_MAX_TX_DESCRIPTORS 32 +/* + * We always allocate this number of mac addresses. If we don't + * have enough allocated addresses, the LAA bit is used + */ +#define WLCORE_NUM_MAC_ADDRESSES 3 + /* forward declaration */ struct wl1271_tx_hw_descr; enum wl_rx_buf_align; struct wl1271_rx_descriptor; struct wlcore_ops { + int (*setup)(struct wl1271 *wl); int (*identify_chip)(struct wl1271 *wl); int (*identify_fw)(struct wl1271 *wl); int (*boot)(struct wl1271 *wl); @@ -139,10 +146,12 @@ struct wl1271_stats { }; struct wl1271 { + bool initialized; struct ieee80211_hw *hw; bool mac80211_registered; struct device *dev; + struct platform_device *pdev; void *if_priv; @@ -153,7 +162,7 @@ struct wl1271 { spinlock_t wl_lock; - enum wl1271_state state; + enum wlcore_state state; enum wl12xx_fw_type fw_type; bool plt; enum plt_mode plt_mode; @@ -181,7 +190,7 @@ struct wl1271 { u32 fuse_nic_addr; /* we have up to 2 MAC addresses */ - struct mac_address addresses[2]; + struct mac_address addresses[WLCORE_NUM_MAC_ADDRESSES]; int channel; u8 system_hlid; @@ -190,6 +199,8 @@ struct wl1271 { unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; unsigned long rate_policies_map[ BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)]; + unsigned long klv_templates_map[ + BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)]; struct list_head wlvif_list; @@ -237,6 +248,7 @@ struct wl1271 { /* Intermediate buffer, used for packet aggregation */ u8 *aggr_buf; + u32 aggr_buf_size; /* Reusable dummy packet template */ struct sk_buff *dummy_packet; @@ -393,13 +405,18 @@ struct wl1271 { /* sleep auth value currently configured to FW */ int sleep_auth; + /* the number of allocated MAC addresses in this chip */ + int num_mac_addr; + /* the minimum FW version required for the driver to work */ unsigned int min_fw_ver[NUM_FW_VER]; + + struct completion nvs_loading_complete; }; int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); int __devexit wlcore_remove(struct platform_device *pdev); -struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size); +struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size); int wlcore_free_hw(struct wl1271 *wl); int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index c0505635bb00..6678d4b18611 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -66,6 +66,7 @@ #define WLCORE_NUM_BANDS 2 #define WL12XX_MAX_RATE_POLICIES 16 +#define WLCORE_MAX_KLV_TEMPLATES 4 /* Defined by FW as 0. Will not be freed or allocated. */ #define WL12XX_SYSTEM_HLID 0 @@ -83,11 +84,10 @@ #define WL1271_AP_BSS_INDEX 0 #define WL1271_AP_DEF_BEACON_EXP 20 -#define WL1271_AGGR_BUFFER_SIZE (5 * PAGE_SIZE) - -enum wl1271_state { - WL1271_STATE_OFF, - WL1271_STATE_ON, +enum wlcore_state { + WLCORE_STATE_OFF, + WLCORE_STATE_RESTARTING, + WLCORE_STATE_ON, }; enum wl12xx_fw_type { @@ -124,6 +124,7 @@ struct wl1271_chip { u32 id; char fw_ver_str[ETHTOOL_BUSINFO_LEN]; unsigned int fw_ver[NUM_FW_VER]; + char phy_fw_ver_str[ETHTOOL_BUSINFO_LEN]; }; #define NUM_TX_QUEUES 4 @@ -337,6 +338,8 @@ struct wl12xx_vif { u8 ap_rate_idx; u8 p2p_rate_idx; + u8 klv_template_id; + bool qos; } sta; struct { |