diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-27 16:32:45 +0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-27 16:32:45 +0300 |
commit | b3e5ced63e051e8f911b795ac5b06229a5328f7b (patch) | |
tree | e63badb76509839ec948431859255923b6e2a09c /drivers/net/wireless/mwifiex | |
parent | e183201b9e917daf2530b637b2f34f1d5afb934d (diff) | |
parent | b787f68c36d49bb1d9236f403813641efa74a031 (diff) | |
download | linux-b3e5ced63e051e8f911b795ac5b06229a5328f7b.tar.xz |
Merge tag 'v4.1-rc1' into patchwork
Linux 4.1-rc1
* tag 'v4.1-rc1': (11651 commits)
Linux 4.1-rc1
x86_64, asm: Work around AMD SYSRET SS descriptor attribute issue
v4l: xilinx: fix for include file movement
platform/chrome: chromeos_laptop - instantiate Atmel at primary address
RCU pathwalk breakage when running into a symlink overmounting something
fix I_DIO_WAKEUP definition
direct-io: only inc/dec inode->i_dio_count for file systems
fs/9p: fix readdir()
Btrfs: prevent list corruption during free space cache processing
toshiba_acpi: Do not register vendor backlight when acpi_video bl is available
x86: fix special __probe_kernel_write() tail zeroing case
crypto: img-hash - CRYPTO_DEV_IMGTEC_HASH should depend on HAS_DMA
crypto: x86/sha512_ssse3 - fixup for asm function prototype change
nios2: rework cache
nios2: Add types.h header required for __u32 type
ALSA: hda - fix headset mic detection problem for one more machine
eth: bf609 eth clock: add pclk clock for stmmac driver probe
blackfin: Wire up missing syscalls
Btrfs: fix inode cache writeout
ACPI / scan: Add a scan handler for PRP0001
...
Diffstat (limited to 'drivers/net/wireless/mwifiex')
22 files changed, 822 insertions, 296 deletions
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 543148d27b01..433bd6837c79 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -159,6 +159,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, int tid; struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp; struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; + struct mwifiex_ra_list_tbl *ra_list; u16 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) @@ -166,7 +167,13 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) >> BLOCKACKPARAM_TID_POS; + ra_list = mwifiex_wmm_get_ralist_node(priv, tid, add_ba_rsp-> + peer_mac_addr); if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { + if (ra_list) { + ra_list->ba_status = BA_SETUP_NONE; + ra_list->amsdu_in_ampdu = false; + } mwifiex_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr, TYPE_DELBA_SENT, true); if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) @@ -185,6 +192,10 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, tx_ba_tbl->amsdu = true; else tx_ba_tbl->amsdu = false; + if (ra_list) { + ra_list->amsdu_in_ampdu = tx_ba_tbl->amsdu; + ra_list->ba_status = BA_SETUP_COMPLETE; + } } else { dev_err(priv->adapter->dev, "BA stream not created\n"); } @@ -515,6 +526,7 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, enum mwifiex_ba_status ba_status) { struct mwifiex_tx_ba_stream_tbl *new_node; + struct mwifiex_ra_list_tbl *ra_list; unsigned long flags; if (!mwifiex_get_ba_tbl(priv, tid, ra)) { @@ -522,7 +534,11 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, GFP_ATOMIC); if (!new_node) return; - + ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra); + if (ra_list) { + ra_list->ba_status = ba_status; + ra_list->amsdu_in_ampdu = false; + } INIT_LIST_HEAD(&new_node->list); new_node->tid = tid; diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 8e2e39422ad8..afdd58aa90de 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -77,22 +77,6 @@ mwifiex_is_station_ampdu_allowed(struct mwifiex_private *priv, return (node->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED) ? true : false; } -/* This function checks whether AMSDU is allowed for BA stream. */ -static inline u8 -mwifiex_is_amsdu_in_ampdu_allowed(struct mwifiex_private *priv, - struct mwifiex_ra_list_tbl *ptr, int tid) -{ - struct mwifiex_tx_ba_stream_tbl *tx_tbl; - - if (is_broadcast_ether_addr(ptr->ra)) - return false; - tx_tbl = mwifiex_get_ba_tbl(priv, tid, ptr->ra); - if (tx_tbl) - return tx_tbl->amsdu; - - return false; -} - /* This function checks whether AMPDU is allowed or not for a particular TID. */ static inline u8 mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, @@ -182,22 +166,6 @@ mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid, } /* - * This function checks whether BA stream is set up or not. - */ -static inline int -mwifiex_is_ba_stream_setup(struct mwifiex_private *priv, - struct mwifiex_ra_list_tbl *ptr, int tid) -{ - struct mwifiex_tx_ba_stream_tbl *tx_tbl; - - tx_tbl = mwifiex_get_ba_tbl(priv, tid, ptr->ra); - if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl)) - return true; - - return false; -} - -/* * This function checks whether associated station is 11n enabled */ static inline int mwifiex_is_sta_11n_enabled(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 9b983b5cebbd..6183e255e62a 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -170,7 +170,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct sk_buff *skb_aggr, *skb_src; struct mwifiex_txinfo *tx_info_aggr, *tx_info_src; - int pad = 0, ret; + int pad = 0, aggr_num = 0, ret; struct mwifiex_tx_param tx_param; struct txpd *ptx_pd = NULL; struct timeval tv; @@ -184,7 +184,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, } tx_info_src = MWIFIEX_SKB_TXCB(skb_src); - skb_aggr = dev_alloc_skb(adapter->tx_buf_size); + skb_aggr = mwifiex_alloc_dma_align_buf(adapter->tx_buf_size, + GFP_ATOMIC | GFP_DMA); if (!skb_aggr) { dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, @@ -200,6 +201,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, if (tx_info_src->flags & MWIFIEX_BUF_FLAG_TDLS_PKT) tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; + tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_AGGR_PKT; skb_aggr->priority = skb_src->priority; do_gettimeofday(&tv); @@ -211,11 +213,9 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, break; skb_src = skb_dequeue(&pra_list->skb_head); - pra_list->total_pkt_count--; - atomic_dec(&priv->wmm.tx_pkts_queued); - + aggr_num++; spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad); @@ -251,6 +251,12 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, ptx_pd = (struct txpd *)skb_aggr->data; skb_push(skb_aggr, headroom); + tx_info_aggr->aggr_num = aggr_num * 2; + if (adapter->data_sent || adapter->tx_lock_flag) { + atomic_add(aggr_num * 2, &adapter->tx_queued); + skb_queue_tail(&adapter->tx_data_q, skb_aggr); + return 0; + } if (adapter->iface_type == MWIFIEX_USB) { adapter->data_sent = true; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index a2e8817b56d8..f75f8acfaca0 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -659,6 +659,7 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac, { struct mwifiex_rx_reorder_tbl *tbl; struct mwifiex_tx_ba_stream_tbl *ptx_tbl; + struct mwifiex_ra_list_tbl *ra_list; u8 cleanup_rx_reorder_tbl; unsigned long flags; @@ -686,7 +687,11 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac, "event: TID, RA not found in table\n"); return; } - + ra_list = mwifiex_wmm_get_ralist_node(priv, tid, peer_mac); + if (ra_list) { + ra_list->amsdu_in_ampdu = false; + ra_list->ba_status = BA_SETUP_NONE; + } spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 41c8e25df954..bf9020ff2d33 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -717,6 +717,9 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv) static int mwifiex_deinit_priv_params(struct mwifiex_private *priv) { + struct mwifiex_adapter *adapter = priv->adapter; + unsigned long flags; + priv->mgmt_frame_mask = 0; if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, HostCmd_ACT_GEN_SET, 0, @@ -727,6 +730,25 @@ static int mwifiex_deinit_priv_params(struct mwifiex_private *priv) } mwifiex_deauthenticate(priv, NULL); + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + adapter->main_locked = true; + if (adapter->mwifiex_processing) { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + flush_workqueue(adapter->workqueue); + } else { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + } + + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + adapter->rx_locked = true; + if (adapter->rx_processing) { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + flush_workqueue(adapter->rx_workqueue); + } else { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + } + mwifiex_free_priv(priv); priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; @@ -740,6 +762,9 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, struct net_device *dev, enum nl80211_iftype type) { + struct mwifiex_adapter *adapter = priv->adapter; + unsigned long flags; + mwifiex_init_priv(priv); priv->bss_mode = type; @@ -770,6 +795,14 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, return -EOPNOTSUPP; } + spin_lock_irqsave(&adapter->main_proc_lock, flags); + adapter->main_locked = false; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + adapter->rx_locked = false; + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + return 0; } @@ -1563,7 +1596,7 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, params->mac); - memset(deauth_mac, 0, ETH_ALEN); + eth_zero_addr(deauth_mac); spin_lock_irqsave(&priv->sta_list_spinlock, flags); sta_node = mwifiex_get_sta_entry(priv, params->mac); @@ -1786,7 +1819,7 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" " reason code %d\n", priv->cfg_bssid, reason_code); - memset(priv->cfg_bssid, 0, ETH_ALEN); + eth_zero_addr(priv->cfg_bssid); priv->hs2_enabled = false; return 0; @@ -1954,13 +1987,13 @@ done: if (mode == NL80211_IFTYPE_ADHOC) bss = cfg80211_get_bss(priv->wdev.wiphy, channel, bssid, ssid, ssid_len, - WLAN_CAPABILITY_IBSS, - WLAN_CAPABILITY_IBSS); + IEEE80211_BSS_TYPE_IBSS, + IEEE80211_PRIVACY_ANY); else bss = cfg80211_get_bss(priv->wdev.wiphy, channel, bssid, ssid, ssid_len, - WLAN_CAPABILITY_ESS, - WLAN_CAPABILITY_ESS); + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); if (!bss) { if (is_scanning_required) { @@ -2046,7 +2079,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, dev_dbg(priv->adapter->dev, "info: association to bssid %pM failed\n", priv->cfg_bssid); - memset(priv->cfg_bssid, 0, ETH_ALEN); + eth_zero_addr(priv->cfg_bssid); if (ret > 0) cfg80211_connect_result(priv->netdev, priv->cfg_bssid, @@ -2194,7 +2227,7 @@ mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; - memset(priv->cfg_bssid, 0, ETH_ALEN); + eth_zero_addr(priv->cfg_bssid); return 0; } @@ -2397,12 +2430,12 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } -#define MWIFIEX_MAX_WQ_LEN 30 /* - * create a new virtual interface with the given name + * create a new virtual interface with the given name and name assign type */ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params) @@ -2411,7 +2444,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, struct mwifiex_private *priv; struct net_device *dev; void *mdev_priv; - char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN]; if (!adapter) return ERR_PTR(-EFAULT); @@ -2523,7 +2555,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, } dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name, - NET_NAME_UNKNOWN, ether_setup, + name_assign_type, ether_setup, IEEE80211_NUM_ACS, 1); if (!dev) { wiphy_err(wiphy, "no memory available for netdevice\n"); @@ -2576,12 +2608,10 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-EFAULT); } - strcpy(dfs_cac_str, "MWIFIEX_DFS_CAC"); - strcat(dfs_cac_str, name); - priv->dfs_cac_workqueue = alloc_workqueue(dfs_cac_str, + priv->dfs_cac_workqueue = alloc_workqueue("MWIFIEX_DFS_CAC%s", WQ_HIGHPRI | WQ_MEM_RECLAIM | - WQ_UNBOUND, 1); + WQ_UNBOUND, 1, name); if (!priv->dfs_cac_workqueue) { wiphy_err(wiphy, "cannot register virtual network device\n"); free_netdev(dev); @@ -2594,11 +2624,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue); - strcpy(dfs_chsw_str, "MWIFIEX_DFS_CHSW"); - strcat(dfs_chsw_str, name); - priv->dfs_chan_sw_workqueue = alloc_workqueue(dfs_chsw_str, + priv->dfs_chan_sw_workqueue = alloc_workqueue("MWIFIEX_DFS_CHSW%s", WQ_HIGHPRI | WQ_UNBOUND | - WQ_MEM_RECLAIM, 1); + WQ_MEM_RECLAIM, 1, name); if (!priv->dfs_chan_sw_workqueue) { wiphy_err(wiphy, "cannot register virtual network device\n"); free_netdev(dev); @@ -2738,24 +2766,71 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, } #ifdef CONFIG_PM -static int mwifiex_set_mef_filter(struct mwifiex_private *priv, - struct cfg80211_wowlan *wowlan) +static void mwifiex_set_auto_arp_mef_entry(struct mwifiex_private *priv, + struct mwifiex_mef_entry *mef_entry) +{ + int i, filt_num = 0, num_ipv4 = 0; + struct in_device *in_dev; + struct in_ifaddr *ifa; + __be32 ips[MWIFIEX_MAX_SUPPORTED_IPADDR]; + struct mwifiex_adapter *adapter = priv->adapter; + + mef_entry->mode = MEF_MODE_HOST_SLEEP; + mef_entry->action = MEF_ACTION_AUTO_ARP; + + /* Enable ARP offload feature */ + memset(ips, 0, sizeof(ips)); + for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { + if (adapter->priv[i]->netdev) { + in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev); + if (!in_dev) + continue; + ifa = in_dev->ifa_list; + if (!ifa || !ifa->ifa_local) + continue; + ips[i] = ifa->ifa_local; + num_ipv4++; + } + } + + for (i = 0; i < num_ipv4; i++) { + if (!ips[i]) + continue; + mef_entry->filter[filt_num].repeat = 1; + memcpy(mef_entry->filter[filt_num].byte_seq, + (u8 *)&ips[i], sizeof(ips[i])); + mef_entry->filter[filt_num]. + byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = + sizeof(ips[i]); + mef_entry->filter[filt_num].offset = 46; + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + if (filt_num) { + mef_entry->filter[filt_num].filt_action = + TYPE_OR; + } + filt_num++; + } + + mef_entry->filter[filt_num].repeat = 1; + mef_entry->filter[filt_num].byte_seq[0] = 0x08; + mef_entry->filter[filt_num].byte_seq[1] = 0x06; + mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = 2; + mef_entry->filter[filt_num].offset = 20; + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + mef_entry->filter[filt_num].filt_action = TYPE_AND; +} + +static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, + struct mwifiex_ds_mef_cfg *mef_cfg, + struct mwifiex_mef_entry *mef_entry, + struct cfg80211_wowlan *wowlan) { int i, filt_num = 0, ret = 0; bool first_pat = true; u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1]; const u8 ipv4_mc_mac[] = {0x33, 0x33}; const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; - struct mwifiex_ds_mef_cfg mef_cfg; - struct mwifiex_mef_entry *mef_entry; - mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL); - if (!mef_entry) - return -ENOMEM; - - memset(&mef_cfg, 0, sizeof(mef_cfg)); - mef_cfg.num_entries = 1; - mef_cfg.mef_entry = mef_entry; mef_entry->mode = MEF_MODE_HOST_SLEEP; mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST; @@ -2772,20 +2847,19 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, if (!wowlan->patterns[i].pkt_offset) { if (!(byte_seq[0] & 0x01) && (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) { - mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; + mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST; continue; } else if (is_broadcast_ether_addr(byte_seq)) { - mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST; + mef_cfg->criteria |= MWIFIEX_CRITERIA_BROADCAST; continue; } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 2)) || (!memcmp(byte_seq, ipv6_mc_mac, 3) && (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 3))) { - mef_cfg.criteria |= MWIFIEX_CRITERIA_MULTICAST; + mef_cfg->criteria |= MWIFIEX_CRITERIA_MULTICAST; continue; } } - mef_entry->filter[filt_num].repeat = 1; mef_entry->filter[filt_num].offset = wowlan->patterns[i].pkt_offset; @@ -2802,7 +2876,7 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, } if (wowlan->magic_pkt) { - mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; + mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST; mef_entry->filter[filt_num].repeat = 16; memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, ETH_ALEN); @@ -2823,6 +2897,34 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, mef_entry->filter[filt_num].filt_type = TYPE_EQ; mef_entry->filter[filt_num].filt_action = TYPE_OR; } + return ret; +} + +static int mwifiex_set_mef_filter(struct mwifiex_private *priv, + struct cfg80211_wowlan *wowlan) +{ + int ret = 0, num_entries = 1; + struct mwifiex_ds_mef_cfg mef_cfg; + struct mwifiex_mef_entry *mef_entry; + + if (wowlan->n_patterns || wowlan->magic_pkt) + num_entries++; + + mef_entry = kcalloc(num_entries, sizeof(*mef_entry), GFP_KERNEL); + if (!mef_entry) + return -ENOMEM; + + memset(&mef_cfg, 0, sizeof(mef_cfg)); + mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST | + MWIFIEX_CRITERIA_UNICAST; + mef_cfg.num_entries = num_entries; + mef_cfg.mef_entry = mef_entry; + + mwifiex_set_auto_arp_mef_entry(priv, &mef_entry[0]); + + if (wowlan->n_patterns || wowlan->magic_pkt) + ret = mwifiex_set_wowlan_mef_entry(priv, &mef_cfg, + &mef_entry[1], wowlan); if (!mef_cfg.criteria) mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | @@ -2830,8 +2932,8 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, MWIFIEX_CRITERIA_MULTICAST; ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, - HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); - + HostCmd_ACT_GEN_SET, 0, + &mef_cfg, true); kfree(mef_entry); return ret; } @@ -2841,27 +2943,33 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_ds_hs_cfg hs_cfg; - int ret = 0; - struct mwifiex_private *priv = - mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + int i, ret = 0; + struct mwifiex_private *priv; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + mwifiex_abort_cac(priv); + } + + mwifiex_cancel_all_pending_cmd(adapter); if (!wowlan) { dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n"); return 0; } + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + if (!priv->media_connected) { dev_warn(adapter->dev, "Can not configure WOWLAN in disconnected state\n"); return 0; } - if (wowlan->n_patterns || wowlan->magic_pkt) { - ret = mwifiex_set_mef_filter(priv, wowlan); - if (ret) { - dev_err(adapter->dev, "Failed to set MEF filter\n"); - return ret; - } + ret = mwifiex_set_mef_filter(priv, wowlan); + if (ret) { + dev_err(adapter->dev, "Failed to set MEF filter\n"); + return ret; } if (wowlan->disconnect) { diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 88d0eade6bb1..38f24e0427d2 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -33,6 +33,7 @@ #define MWIFIEX_MAX_BSS_NUM (3) #define MWIFIEX_DMA_ALIGN_SZ 64 +#define MWIFIEX_RX_HEADROOM 64 #define MAX_TXPD_SZ 32 #define INTF_HDR_ALIGN 4 @@ -82,6 +83,7 @@ #define MWIFIEX_BUF_FLAG_TDLS_PKT BIT(2) #define MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS BIT(3) #define MWIFIEX_BUF_FLAG_ACTION_TX_STATUS BIT(4) +#define MWIFIEX_BUF_FLAG_AGGR_PKT BIT(5) #define MWIFIEX_BRIDGED_PKTS_THR_HIGH 1024 #define MWIFIEX_BRIDGED_PKTS_THR_LOW 128 @@ -110,6 +112,11 @@ #define MWIFIEX_A_BAND_START_FREQ 5000 +/* SDIO Aggr data packet special info */ +#define SDIO_MAX_AGGR_BUF_SIZE (256 * 255) +#define BLOCK_NUMBER_OFFSET 15 +#define SDIO_HEADER_OFFSET 28 + enum mwifiex_bss_type { MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_UAP = 1, @@ -167,10 +174,11 @@ struct mwifiex_wait_queue { }; struct mwifiex_rxinfo { + struct sk_buff *parent; u8 bss_num; u8 bss_type; - struct sk_buff *parent; u8 use_count; + u8 buf_type; }; struct mwifiex_txinfo { @@ -178,6 +186,7 @@ struct mwifiex_txinfo { u8 flags; u8 bss_num; u8 bss_type; + u8 aggr_num; u32 pkt_len; u8 ack_frame_id; u64 cookie; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index df553e86a0ad..59d8964dd0dc 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -197,6 +197,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) #define ISSUPP_TDLS_ENABLED(FwCapInfo) (FwCapInfo & BIT(14)) +#define ISSUPP_SDIO_SPA_ENABLED(FwCapInfo) (FwCapInfo & BIT(16)) #define MWIFIEX_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \ @@ -353,6 +354,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 #define HostCmd_CMD_TDLS_OPER 0x0122 +#define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 #define PROTOCOL_NO_SECURITY 0x01 #define PROTOCOL_STATIC_WEP 0x02 @@ -523,9 +525,11 @@ enum P2P_MODES { #define TYPE_OR (MAX_OPERAND+5) #define MEF_MODE_HOST_SLEEP 1 #define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3 +#define MEF_ACTION_AUTO_ARP 0x10 #define MWIFIEX_CRITERIA_BROADCAST BIT(0) #define MWIFIEX_CRITERIA_UNICAST BIT(1) #define MWIFIEX_CRITERIA_MULTICAST BIT(3) +#define MWIFIEX_MAX_SUPPORTED_IPADDR 4 #define ACT_TDLS_DELETE 0x00 #define ACT_TDLS_CREATE 0x01 @@ -1240,6 +1244,12 @@ struct host_cmd_ds_chan_rpt_event { u8 tlvbuf[0]; } __packed; +struct host_cmd_sdio_sp_rx_aggr_cfg { + u8 action; + u8 enable; + __le16 block_size; +} __packed; + struct mwifiex_fixed_bcn_param { __le64 timestamp; __le16 beacon_period; @@ -1962,6 +1972,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_coalesce_cfg coalesce_cfg; struct host_cmd_ds_tdls_oper tdls_oper; struct host_cmd_ds_chan_rpt_req chan_rpt_req; + struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index b77ba743e1c4..e12192f5cfad 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -76,7 +76,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv) u32 i; priv->media_connected = false; - memset(priv->curr_addr, 0xff, ETH_ALEN); + eth_broadcast_addr(priv->curr_addr); priv->pkt_tx_ctrl = 0; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; @@ -266,18 +266,15 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) mwifiex_wmm_init(adapter); - if (adapter->sleep_cfm) { - sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *) - adapter->sleep_cfm->data; - memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len); - sleep_cfm_buf->command = - cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); - sleep_cfm_buf->size = - cpu_to_le16(adapter->sleep_cfm->len); - sleep_cfm_buf->result = 0; - sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM); - sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED); - } + sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *) + adapter->sleep_cfm->data; + memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len); + sleep_cfm_buf->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); + sleep_cfm_buf->size = cpu_to_le16(adapter->sleep_cfm->len); + sleep_cfm_buf->result = 0; + sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM); + sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED); + memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params)); memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period)); adapter->tx_lock_flag = false; @@ -296,10 +293,9 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); adapter->arp_filter_size = 0; adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; - adapter->ext_scan = false; adapter->key_api_major_ver = 0; adapter->key_api_minor_ver = 0; - memset(adapter->perm_addr, 0xff, ETH_ALEN); + eth_broadcast_addr(adapter->perm_addr); adapter->iface_limit.sta_intf = MWIFIEX_MAX_STA_NUM; adapter->iface_limit.uap_intf = MWIFIEX_MAX_UAP_NUM; adapter->iface_limit.p2p_intf = MWIFIEX_MAX_P2P_NUM; @@ -482,6 +478,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) spin_lock_init(&adapter->rx_proc_lock); skb_queue_head_init(&adapter->rx_data_q); + skb_queue_head_init(&adapter->tx_data_q); for (i = 0; i < adapter->priv_num; ++i) { INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); @@ -689,6 +686,10 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) } } + atomic_set(&adapter->tx_queued, 0); + while ((skb = skb_dequeue(&adapter->tx_data_q))) + mwifiex_write_data_complete(adapter, skb, 0, 0); + spin_lock_irqsave(&adapter->rx_proc_lock, flags); while ((skb = skb_dequeue(&adapter->rx_data_q))) { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 7e74b4fccddd..03a95c7d34bf 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -131,10 +131,39 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) return 0; } +void mwifiex_queue_main_work(struct mwifiex_adapter *adapter) +{ + unsigned long flags; + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + if (adapter->mwifiex_processing) { + adapter->more_task_flag = true; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + } else { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + queue_work(adapter->workqueue, &adapter->main_work); + } +} +EXPORT_SYMBOL_GPL(mwifiex_queue_main_work); + +static void mwifiex_queue_rx_work(struct mwifiex_adapter *adapter) +{ + unsigned long flags; + + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + if (adapter->rx_processing) { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + } else { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + queue_work(adapter->rx_workqueue, &adapter->rx_work); + } +} + static int mwifiex_process_rx(struct mwifiex_adapter *adapter) { unsigned long flags; struct sk_buff *skb; + struct mwifiex_rxinfo *rx_info; spin_lock_irqsave(&adapter->rx_proc_lock, flags); if (adapter->rx_processing || adapter->rx_locked) { @@ -154,9 +183,16 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter) if (adapter->if_ops.submit_rem_rx_urbs) adapter->if_ops.submit_rem_rx_urbs(adapter); adapter->delay_main_work = false; - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_queue_main_work(adapter); + } + rx_info = MWIFIEX_SKB_RXCB(skb); + if (rx_info->buf_type == MWIFIEX_TYPE_AGGR_DATA) { + if (adapter->if_ops.deaggr_pkt) + adapter->if_ops.deaggr_pkt(adapter, skb); + dev_kfree_skb_any(skb); + } else { + mwifiex_handle_rx_packet(adapter, skb); } - mwifiex_handle_rx_packet(adapter, skb); } spin_lock_irqsave(&adapter->rx_proc_lock, flags); adapter->rx_processing = false; @@ -189,15 +225,17 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) spin_lock_irqsave(&adapter->main_proc_lock, flags); /* Check if already processing */ - if (adapter->mwifiex_processing) { + if (adapter->mwifiex_processing || adapter->main_locked) { + adapter->more_task_flag = true; spin_unlock_irqrestore(&adapter->main_proc_lock, flags); goto exit_main_proc; } else { adapter->mwifiex_processing = true; - spin_unlock_irqrestore(&adapter->main_proc_lock, flags); } process_start: do { + adapter->more_task_flag = false; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) || (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) break; @@ -212,9 +250,7 @@ process_start: if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING && adapter->iface_type != MWIFIEX_USB) { adapter->delay_main_work = true; - if (!adapter->rx_processing) - queue_work(adapter->rx_workqueue, - &adapter->rx_work); + mwifiex_queue_rx_work(adapter); break; } @@ -227,24 +263,26 @@ process_start: } if (adapter->rx_work_enabled && adapter->data_received) - queue_work(adapter->rx_workqueue, &adapter->rx_work); + mwifiex_queue_rx_work(adapter); /* Need to wake up the card ? */ if ((adapter->ps_state == PS_STATE_SLEEP) && (adapter->pm_wakeup_card_req && !adapter->pm_wakeup_fw_try) && (is_command_pending(adapter) || + !skb_queue_empty(&adapter->tx_data_q) || !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); adapter->if_ops.wakeup(adapter); + spin_lock_irqsave(&adapter->main_proc_lock, flags); continue; } if (IS_CARD_RX_RCVD(adapter)) { adapter->data_received = false; adapter->pm_wakeup_fw_try = false; - del_timer_sync(&adapter->wakeup_timer); + del_timer(&adapter->wakeup_timer); if (adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; } else { @@ -257,7 +295,8 @@ process_start: if ((!adapter->scan_chan_gap_enabled && adapter->scan_processing) || adapter->data_sent || - mwifiex_wmm_lists_empty(adapter)) { + (mwifiex_wmm_lists_empty(adapter) && + skb_queue_empty(&adapter->tx_data_q))) { if (adapter->cmd_sent || adapter->curr_cmd || (!is_command_pending(adapter))) break; @@ -295,8 +334,10 @@ process_start: if ((adapter->ps_state == PS_STATE_SLEEP) || (adapter->ps_state == PS_STATE_PRE_SLEEP) || (adapter->ps_state == PS_STATE_SLEEP_CFM) || - adapter->tx_lock_flag) + adapter->tx_lock_flag){ + spin_lock_irqsave(&adapter->main_proc_lock, flags); continue; + } if (!adapter->cmd_sent && !adapter->curr_cmd) { if (mwifiex_exec_next_cmd(adapter) == -1) { @@ -307,6 +348,20 @@ process_start: if ((adapter->scan_chan_gap_enabled || !adapter->scan_processing) && + !adapter->data_sent && + !skb_queue_empty(&adapter->tx_data_q)) { + mwifiex_process_tx_queue(adapter); + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event + (mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + false); + } + } + + if ((adapter->scan_chan_gap_enabled || + !adapter->scan_processing) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { @@ -320,7 +375,8 @@ process_start: if (adapter->delay_null_pkt && !adapter->cmd_sent && !adapter->curr_cmd && !is_command_pending(adapter) && - mwifiex_wmm_lists_empty(adapter)) { + (mwifiex_wmm_lists_empty(adapter) && + skb_queue_empty(&adapter->tx_data_q))) { if (!mwifiex_send_null_packet (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | @@ -330,15 +386,12 @@ process_start: } break; } + spin_lock_irqsave(&adapter->main_proc_lock, flags); } while (true); spin_lock_irqsave(&adapter->main_proc_lock, flags); - if (!adapter->delay_main_work && - (adapter->int_status || IS_CARD_RX_RCVD(adapter))) { - spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + if (adapter->more_task_flag) goto process_start; - } - adapter->mwifiex_processing = false; spin_unlock_irqrestore(&adapter->main_proc_lock, flags); @@ -466,7 +519,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) rtnl_lock(); /* Create station interface by default */ - wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", + wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM, NL80211_IFTYPE_STATION, NULL, NULL); if (IS_ERR(wdev)) { dev_err(adapter->dev, "cannot create default STA interface\n"); @@ -475,7 +528,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) } if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) { - wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", + wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM, NL80211_IFTYPE_AP, NULL, NULL); if (IS_ERR(wdev)) { dev_err(adapter->dev, "cannot create AP interface\n"); @@ -485,7 +538,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) } if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) { - wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", + wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", NET_NAME_ENUM, NL80211_IFTYPE_P2P_CLIENT, NULL, NULL); if (IS_ERR(wdev)) { @@ -604,7 +657,7 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) atomic_inc(&priv->adapter->tx_pending); mwifiex_wmm_add_buf_txqueue(priv, skb); - queue_work(priv->adapter->workqueue, &priv->adapter->main_work); + mwifiex_queue_main_work(priv->adapter); return 0; } @@ -1096,9 +1149,6 @@ mwifiex_add_card(void *card, struct semaphore *sem, INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue); } - if (adapter->if_ops.iface_work) - INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work); - /* Register the device. Fill up the private data structure with relevant information from the card. */ if (adapter->if_ops.register_dev(adapter)) { diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index f0a6af179af0..fe1256044a6c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -35,6 +35,7 @@ #include <linux/ctype.h> #include <linux/of.h> #include <linux/idr.h> +#include <linux/inetdevice.h> #include "decl.h" #include "ioctl.h" @@ -58,6 +59,8 @@ enum { #define MWIFIEX_MAX_AP 64 +#define MWIFIEX_MAX_PKTS_TXQ 16 + #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) #define MWIFIEX_TIMER_10S 10000 @@ -118,6 +121,7 @@ enum { #define MWIFIEX_TYPE_CMD 1 #define MWIFIEX_TYPE_DATA 0 +#define MWIFIEX_TYPE_AGGR_DATA 10 #define MWIFIEX_TYPE_EVENT 3 #define MAX_BITMAP_RATES_SIZE 18 @@ -140,6 +144,9 @@ enum { #define MWIFIEX_DRV_INFO_SIZE_MAX 0x40000 +/* Address alignment */ +#define MWIFIEX_ALIGN_ADDR(p, a) (((long)(p) + (a) - 1) & ~((a) - 1)) + struct mwifiex_dbg { u32 num_cmd_host_to_card_failure; u32 num_cmd_sleep_cfm_host_to_card_failure; @@ -207,6 +214,12 @@ struct mwifiex_tx_aggr { u8 amsdu; }; +enum mwifiex_ba_status { + BA_SETUP_NONE = 0, + BA_SETUP_INPROGRESS, + BA_SETUP_COMPLETE +}; + struct mwifiex_ra_list_tbl { struct list_head list; struct sk_buff_head skb_head; @@ -215,6 +228,8 @@ struct mwifiex_ra_list_tbl { u16 max_amsdu; u16 ba_pkt_count; u8 ba_packet_thr; + enum mwifiex_ba_status ba_status; + u8 amsdu_in_ampdu; u16 total_pkt_count; bool tdls_link; }; @@ -598,11 +613,6 @@ struct mwifiex_private { struct mwifiex_11h_intf_state state_11h; }; -enum mwifiex_ba_status { - BA_SETUP_NONE = 0, - BA_SETUP_INPROGRESS, - BA_SETUP_COMPLETE -}; struct mwifiex_tx_ba_stream_tbl { struct list_head list; @@ -735,6 +745,7 @@ struct mwifiex_if_ops { int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); void (*iface_work)(struct work_struct *work); void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter); + void (*deaggr_pkt)(struct mwifiex_adapter *, struct sk_buff *); }; struct mwifiex_adapter { @@ -768,14 +779,18 @@ struct mwifiex_adapter { bool rx_processing; bool delay_main_work; bool rx_locked; + bool main_locked; struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; /* spin lock for init/shutdown */ spinlock_t mwifiex_lock; /* spin lock for main process */ spinlock_t main_proc_lock; u32 mwifiex_processing; + u8 more_task_flag; u16 tx_buf_size; u16 curr_tx_buf_size; + bool sdio_rx_aggr_enable; + u16 sdio_rx_block_size; u32 ioport; enum MWIFIEX_HARDWARE_STATUS hw_status; u16 number_of_antenna; @@ -810,6 +825,8 @@ struct mwifiex_adapter { spinlock_t scan_pending_q_lock; /* spin lock for RX processing routine */ spinlock_t rx_proc_lock; + struct sk_buff_head tx_data_q; + atomic_t tx_queued; u32 scan_processing; u16 region_code; struct mwifiex_802_11d_domain_reg domain_reg; @@ -881,8 +898,6 @@ struct mwifiex_adapter { bool ext_scan; u8 fw_api_ver; u8 key_api_major_ver, key_api_minor_ver; - struct work_struct iface_work; - unsigned long iface_work_flags; struct memory_type_mapping *mem_type_mapping_tbl; u8 num_mem_types; u8 curr_mem_idx; @@ -896,6 +911,8 @@ struct mwifiex_adapter { bool auto_tdls; }; +void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); + int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); void mwifiex_set_trans_start(struct net_device *dev); @@ -1318,6 +1335,7 @@ u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type); struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params); @@ -1417,6 +1435,8 @@ u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, u8 rx_rate, u8 ht_info); void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter); +void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags); +void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index a5828da59365..bcc7751d883c 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -203,7 +203,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, card->pcie.reg = data->reg; card->pcie.blksz_fw_dl = data->blksz_fw_dl; card->pcie.tx_buf_size = data->tx_buf_size; - card->pcie.supports_fw_dump = data->supports_fw_dump; + card->pcie.can_dump_fw = data->can_dump_fw; card->pcie.can_ext_scan = data->can_ext_scan; } @@ -234,8 +234,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) if (!adapter || !adapter->priv_num) return; - cancel_work_sync(&adapter->iface_work); - if (user_rmmod) { #ifdef CONFIG_PM_SLEEP if (adapter->is_suspended) @@ -498,7 +496,8 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter) for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { /* Allocate skb here so that firmware can DMA data from it */ - skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); + skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE, + GFP_KERNEL | GFP_DMA); if (!skb) { dev_err(adapter->dev, "Unable to allocate skb for RX ring.\n"); @@ -1297,7 +1296,8 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) } } - skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); + skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE, + GFP_KERNEL | GFP_DMA); if (!skb_tmp) { dev_err(adapter->dev, "Unable to allocate skb.\n"); @@ -2099,7 +2099,7 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) goto exit; mwifiex_interrupt_status(adapter); - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_queue_main_work(adapter); exit: return IRQ_HANDLED; @@ -2271,7 +2271,7 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter) int ret; static char *env[] = { "DRIVER=mwifiex_pcie", "EVENT=fw_dump", NULL }; - if (!card->pcie.supports_fw_dump) + if (!card->pcie.can_dump_fw) return; for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) { @@ -2371,25 +2371,26 @@ done: adapter->curr_mem_idx = 0; } +static unsigned long iface_work_flags; +static struct mwifiex_adapter *save_adapter; static void mwifiex_pcie_work(struct work_struct *work) { - struct mwifiex_adapter *adapter = - container_of(work, struct mwifiex_adapter, iface_work); - if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP, - &adapter->iface_work_flags)) - mwifiex_pcie_fw_dump_work(adapter); + &iface_work_flags)) + mwifiex_pcie_fw_dump_work(save_adapter); } +static DECLARE_WORK(pcie_work, mwifiex_pcie_work); /* This function dumps FW information */ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) { - if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags)) + save_adapter = adapter; + if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags)) return; - set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags); + set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags); - schedule_work(&adapter->iface_work); + schedule_work(&pcie_work); } /* @@ -2617,7 +2618,6 @@ static struct mwifiex_if_ops pcie_ops = { .init_fw_port = mwifiex_pcie_init_fw_port, .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, .fw_dump = mwifiex_pcie_fw_dump, - .iface_work = mwifiex_pcie_work, }; /* @@ -2663,6 +2663,7 @@ static void mwifiex_pcie_cleanup_module(void) /* Set the flag as user is removing this module. */ user_rmmod = 1; + cancel_work_sync(&pcie_work); pci_unregister_driver(&mwifiex_pcie); } diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index 666d40e9dbc3..0e7ee8b72358 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -205,7 +205,7 @@ struct mwifiex_pcie_device { const struct mwifiex_pcie_card_reg *reg; u16 blksz_fw_dl; u16 tx_buf_size; - bool supports_fw_dump; + bool can_dump_fw; bool can_ext_scan; }; @@ -214,7 +214,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8766 = { .reg = &mwifiex_reg_8766, .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, - .supports_fw_dump = false, + .can_dump_fw = false, .can_ext_scan = true, }; @@ -223,7 +223,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = { .reg = &mwifiex_reg_8897, .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, - .supports_fw_dump = true, + .can_dump_fw = true, .can_ext_scan = true, }; diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 91e36cda9543..d10320f89bc1 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -47,6 +47,7 @@ static u8 user_rmmod; static struct mwifiex_if_ops sdio_ops; +static unsigned long iface_work_flags; static struct semaphore add_remove_card_sem; @@ -105,8 +106,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) card->tx_buf_size = data->tx_buf_size; card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; - card->supports_fw_dump = data->supports_fw_dump; - card->auto_tdls = data->auto_tdls; + card->can_dump_fw = data->can_dump_fw; + card->can_auto_tdls = data->can_auto_tdls; card->can_ext_scan = data->can_ext_scan; } @@ -200,8 +201,6 @@ mwifiex_sdio_remove(struct sdio_func *func) if (!adapter || !adapter->priv_num) return; - cancel_work_sync(&adapter->iface_work); - if (user_rmmod) { if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); @@ -1043,6 +1042,59 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, } /* + * This function decode sdio aggreation pkt. + * + * Based on the the data block size and pkt_len, + * skb data will be decoded to few packets. + */ +static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + u32 total_pkt_len, pkt_len; + struct sk_buff *skb_deaggr; + u32 pkt_type; + u16 blk_size; + u8 blk_num; + u8 *data; + + data = skb->data; + total_pkt_len = skb->len; + + while (total_pkt_len >= (SDIO_HEADER_OFFSET + INTF_HEADER_LEN)) { + if (total_pkt_len < adapter->sdio_rx_block_size) + break; + blk_num = *(data + BLOCK_NUMBER_OFFSET); + blk_size = adapter->sdio_rx_block_size * blk_num; + if (blk_size > total_pkt_len) { + dev_err(adapter->dev, "%s: error in pkt,\t" + "blk_num=%d, blk_size=%d, total_pkt_len=%d\n", + __func__, blk_num, blk_size, total_pkt_len); + break; + } + pkt_len = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET)); + pkt_type = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET + + 2)); + if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) { + dev_err(adapter->dev, "%s: error in pkt,\t" + "pkt_len=%d, blk_size=%d\n", + __func__, pkt_len, blk_size); + break; + } + skb_deaggr = mwifiex_alloc_dma_align_buf(pkt_len, + GFP_KERNEL | GFP_DMA); + if (!skb_deaggr) + break; + skb_put(skb_deaggr, pkt_len); + memcpy(skb_deaggr->data, data + SDIO_HEADER_OFFSET, pkt_len); + skb_pull(skb_deaggr, INTF_HEADER_LEN); + + mwifiex_handle_rx_packet(adapter, skb_deaggr); + data += blk_size; + total_pkt_len -= blk_size; + } +} + +/* * This function decodes a received packet. * * Based on the type, the packet is treated as either a data, or @@ -1055,11 +1107,28 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, u8 *cmd_buf; __le16 *curr_ptr = (__le16 *)skb->data; u16 pkt_len = le16_to_cpu(*curr_ptr); + struct mwifiex_rxinfo *rx_info; - skb_trim(skb, pkt_len); - skb_pull(skb, INTF_HEADER_LEN); + if (upld_typ != MWIFIEX_TYPE_AGGR_DATA) { + skb_trim(skb, pkt_len); + skb_pull(skb, INTF_HEADER_LEN); + } switch (upld_typ) { + case MWIFIEX_TYPE_AGGR_DATA: + dev_dbg(adapter->dev, "info: --- Rx: Aggr Data packet ---\n"); + rx_info = MWIFIEX_SKB_RXCB(skb); + rx_info->buf_type = MWIFIEX_TYPE_AGGR_DATA; + if (adapter->rx_work_enabled) { + skb_queue_tail(&adapter->rx_data_q, skb); + atomic_inc(&adapter->rx_pending); + adapter->data_received = true; + } else { + mwifiex_deaggr_sdio_pkt(adapter, skb); + dev_kfree_skb_any(skb); + } + break; + case MWIFIEX_TYPE_DATA: dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); if (adapter->rx_work_enabled) { @@ -1127,17 +1196,17 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, * provided there is space left, processed and finally uploaded. */ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, - struct sk_buff *skb, u8 port) + u16 rx_len, u8 port) { struct sdio_mmc_card *card = adapter->card; s32 f_do_rx_aggr = 0; s32 f_do_rx_cur = 0; s32 f_aggr_cur = 0; + s32 f_post_aggr_cur = 0; struct sk_buff *skb_deaggr; - u32 pind; - u32 pkt_len, pkt_type, mport; + struct sk_buff *skb = NULL; + u32 pkt_len, pkt_type, mport, pind; u8 *curr_ptr; - u32 rx_len = skb->len; if ((card->has_control_mask) && (port == CTRL_PORT)) { /* Read the command Resp without aggr */ @@ -1164,12 +1233,12 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { - if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { + if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) { f_aggr_cur = 1; } else { /* No room in Aggr buf, do rx aggr now */ f_do_rx_aggr = 1; - f_do_rx_cur = 1; + f_post_aggr_cur = 1; } } else { /* Rx aggr not in progress */ @@ -1182,7 +1251,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, if (MP_RX_AGGR_IN_PROGRESS(card)) { f_do_rx_aggr = 1; - if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) + if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) f_aggr_cur = 1; else /* No room in Aggr buf, do rx aggr now */ @@ -1195,7 +1264,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, if (f_aggr_cur) { dev_dbg(adapter->dev, "info: current packet aggregation\n"); /* Curr pkt can be aggregated */ - mp_rx_aggr_setup(card, skb, port); + mp_rx_aggr_setup(card, rx_len, port); if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || mp_rx_aggr_port_limit_reached(card)) { @@ -1238,16 +1307,29 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, curr_ptr = card->mpa_rx.buf; for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { + u32 *len_arr = card->mpa_rx.len_arr; /* get curr PKT len & type */ pkt_len = le16_to_cpu(*(__le16 *) &curr_ptr[0]); pkt_type = le16_to_cpu(*(__le16 *) &curr_ptr[2]); /* copy pkt to deaggr buf */ - skb_deaggr = card->mpa_rx.skb_arr[pind]; + skb_deaggr = mwifiex_alloc_dma_align_buf(len_arr[pind], + GFP_KERNEL | + GFP_DMA); + if (!skb_deaggr) { + dev_err(adapter->dev, "skb allocation failure drop pkt len=%d type=%d\n", + pkt_len, pkt_type); + curr_ptr += len_arr[pind]; + continue; + } - if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= - card->mpa_rx.len_arr[pind])) { + skb_put(skb_deaggr, len_arr[pind]); + + if ((pkt_type == MWIFIEX_TYPE_DATA || + (pkt_type == MWIFIEX_TYPE_AGGR_DATA && + adapter->sdio_rx_aggr_enable)) && + (pkt_len <= len_arr[pind])) { memcpy(skb_deaggr->data, curr_ptr, pkt_len); @@ -1257,13 +1339,15 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, mwifiex_decode_rx_packet(adapter, skb_deaggr, pkt_type); } else { - dev_err(adapter->dev, "wrong aggr pkt:" - " type=%d len=%d max_len=%d\n", + dev_err(adapter->dev, " drop wrong aggr pkt:\t" + "sdio_single_port_rx_aggr=%d\t" + "type=%d len=%d max_len=%d\n", + adapter->sdio_rx_aggr_enable, pkt_type, pkt_len, - card->mpa_rx.len_arr[pind]); + len_arr[pind]); dev_kfree_skb_any(skb_deaggr); } - curr_ptr += card->mpa_rx.len_arr[pind]; + curr_ptr += len_arr[pind]; } MP_RX_AGGR_BUF_RESET(card); } @@ -1273,28 +1357,46 @@ rx_curr_single: dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", port, rx_len); + skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); + if (!skb) { + dev_err(adapter->dev, "single skb allocated fail,\t" + "drop pkt port=%d len=%d\n", port, rx_len); + if (mwifiex_sdio_card_to_host(adapter, &pkt_type, + card->mpa_rx.buf, rx_len, + adapter->ioport + port)) + goto error; + return 0; + } + + skb_put(skb, rx_len); + if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, skb->len, adapter->ioport + port)) goto error; + if (!adapter->sdio_rx_aggr_enable && + pkt_type == MWIFIEX_TYPE_AGGR_DATA) { + dev_err(adapter->dev, "drop wrong pkt type %d\t" + "current SDIO RX Aggr not enabled\n", + pkt_type); + dev_kfree_skb_any(skb); + return 0; + } mwifiex_decode_rx_packet(adapter, skb, pkt_type); } + if (f_post_aggr_cur) { + dev_dbg(adapter->dev, "info: current packet aggregation\n"); + /* Curr pkt can be aggregated */ + mp_rx_aggr_setup(card, rx_len, port); + } return 0; - error: - if (MP_RX_AGGR_IN_PROGRESS(card)) { - /* Multiport-aggregation transfer failed - cleanup */ - for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { - /* copy pkt to deaggr buf */ - skb_deaggr = card->mpa_rx.skb_arr[pind]; - dev_kfree_skb_any(skb_deaggr); - } + if (MP_RX_AGGR_IN_PROGRESS(card)) MP_RX_AGGR_BUF_RESET(card); - } - if (f_do_rx_cur) + if (f_do_rx_cur && skb) /* Single transfer pending. Free curr buff also */ dev_kfree_skb_any(skb); @@ -1356,8 +1458,9 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) MWIFIEX_RX_DATA_BUF_SIZE) return -1; rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); + dev_dbg(adapter->dev, "info: rx_len = %d\n", rx_len); - skb = dev_alloc_skb(rx_len); + skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); if (!skb) return -1; @@ -1447,27 +1550,16 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) 1) / MWIFIEX_SDIO_BLOCK_SIZE; if (rx_len <= INTF_HEADER_LEN || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > - MWIFIEX_RX_DATA_BUF_SIZE) { + card->mpa_rx.buf_size) { dev_err(adapter->dev, "invalid rx_len=%d\n", rx_len); return -1; } - rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); - - skb = dev_alloc_skb(rx_len); - - if (!skb) { - dev_err(adapter->dev, "%s: failed to alloc skb", - __func__); - return -1; - } - skb_put(skb, rx_len); - - dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n", - rx_len, skb->len); + rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); + dev_dbg(adapter->dev, "info: rx_len = %d\n", rx_len); - if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, + if (mwifiex_sdio_card_to_host_mp_aggr(adapter, rx_len, port)) { dev_err(adapter->dev, "card_to_host_mpa failed:" " int status=%#x\n", sdio_ireg); @@ -1735,6 +1827,7 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) { struct sdio_mmc_card *card = adapter->card; + u32 rx_buf_size; int ret = 0; card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); @@ -1745,13 +1838,15 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, card->mpa_tx.buf_size = mpa_tx_buf_size; - card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL); + rx_buf_size = max_t(u32, mpa_rx_buf_size, + (u32)SDIO_MAX_AGGR_BUF_SIZE); + card->mpa_rx.buf = kzalloc(rx_buf_size, GFP_KERNEL); if (!card->mpa_rx.buf) { ret = -1; goto error; } - card->mpa_rx.buf_size = mpa_rx_buf_size; + card->mpa_rx.buf_size = rx_buf_size; error: if (ret) { @@ -1887,7 +1982,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) return -1; } - adapter->auto_tdls = card->auto_tdls; + adapter->auto_tdls = card->can_auto_tdls; adapter->ext_scan = card->can_ext_scan; return ret; } @@ -1950,6 +2045,7 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) port, card->mp_data_port_mask); } +static struct mwifiex_adapter *save_adapter; static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; @@ -2018,10 +2114,8 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, } /* This function dump firmware memory to file */ -static void mwifiex_sdio_fw_dump_work(struct work_struct *work) +static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter) { - struct mwifiex_adapter *adapter = - container_of(work, struct mwifiex_adapter, iface_work); struct sdio_mmc_card *card = adapter->card; int ret = 0; unsigned int reg, reg_start, reg_end; @@ -2032,7 +2126,7 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work) mwifiex_dump_drv_info(adapter); - if (!card->supports_fw_dump) + if (!card->can_dump_fw) return; for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) { @@ -2143,36 +2237,36 @@ done: static void mwifiex_sdio_work(struct work_struct *work) { - struct mwifiex_adapter *adapter = - container_of(work, struct mwifiex_adapter, iface_work); - - if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, - &adapter->iface_work_flags)) - mwifiex_sdio_card_reset_work(adapter); if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP, - &adapter->iface_work_flags)) - mwifiex_sdio_fw_dump_work(work); + &iface_work_flags)) + mwifiex_sdio_fw_dump_work(save_adapter); + if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, + &iface_work_flags)) + mwifiex_sdio_card_reset_work(save_adapter); } +static DECLARE_WORK(sdio_work, mwifiex_sdio_work); /* This function resets the card */ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) { - if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags)) + save_adapter = adapter; + if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &iface_work_flags)) return; - set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags); + set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &iface_work_flags); - schedule_work(&adapter->iface_work); + schedule_work(&sdio_work); } /* This function dumps FW information */ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter) { - if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags)) + save_adapter = adapter; + if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags)) return; - set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags); - schedule_work(&adapter->iface_work); + set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags); + schedule_work(&sdio_work); } /* Function to dump SDIO function registers and SDIO scratch registers in case @@ -2288,9 +2382,9 @@ static struct mwifiex_if_ops sdio_ops = { .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, .event_complete = mwifiex_sdio_event_complete, .card_reset = mwifiex_sdio_card_reset, - .iface_work = mwifiex_sdio_work, .fw_dump = mwifiex_sdio_fw_dump, .reg_dump = mwifiex_sdio_reg_dump, + .deaggr_pkt = mwifiex_deaggr_sdio_pkt, }; /* @@ -2327,6 +2421,7 @@ mwifiex_sdio_cleanup_module(void) /* Set the flag as user is removing this module. */ user_rmmod = 1; + cancel_work_sync(&sdio_work); sdio_unregister_driver(&mwifiex_sdio); } diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 957cca246618..6f645cf47369 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -67,6 +67,8 @@ #define MWIFIEX_MP_AGGR_BUF_SIZE_16K (16384) #define MWIFIEX_MP_AGGR_BUF_SIZE_32K (32768) +/* we leave one block of 256 bytes for DMA alignment*/ +#define MWIFIEX_MP_AGGR_BUF_SIZE_MAX (65280) /* Misc. Config Register : Auto Re-enable interrupts */ #define AUTO_RE_ENABLE_INT BIT(4) @@ -238,9 +240,6 @@ struct sdio_mmc_card { const struct mwifiex_sdio_card_reg *reg; u8 max_ports; u8 mp_agg_pkt_limit; - bool supports_sdio_new_mode; - bool has_control_mask; - bool supports_fw_dump; u16 tx_buf_size; u32 mp_tx_agg_buf_size; u32 mp_rx_agg_buf_size; @@ -255,7 +254,10 @@ struct sdio_mmc_card { u8 curr_wr_port; u8 *mp_regs; - u8 auto_tdls; + bool supports_sdio_new_mode; + bool has_control_mask; + bool can_dump_fw; + bool can_auto_tdls; bool can_ext_scan; struct mwifiex_sdio_mpa_tx mpa_tx; @@ -267,13 +269,13 @@ struct mwifiex_sdio_device { const struct mwifiex_sdio_card_reg *reg; u8 max_ports; u8 mp_agg_pkt_limit; - bool supports_sdio_new_mode; - bool has_control_mask; - bool supports_fw_dump; u16 tx_buf_size; u32 mp_tx_agg_buf_size; u32 mp_rx_agg_buf_size; - u8 auto_tdls; + bool supports_sdio_new_mode; + bool has_control_mask; + bool can_dump_fw; + bool can_auto_tdls; bool can_ext_scan; }; @@ -412,13 +414,13 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { .reg = &mwifiex_reg_sd87xx, .max_ports = 16, .mp_agg_pkt_limit = 8, - .supports_sdio_new_mode = false, - .has_control_mask = true, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, - .supports_fw_dump = false, - .auto_tdls = false, + .supports_sdio_new_mode = false, + .has_control_mask = true, + .can_dump_fw = false, + .can_auto_tdls = false, .can_ext_scan = false, }; @@ -427,13 +429,13 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { .reg = &mwifiex_reg_sd87xx, .max_ports = 16, .mp_agg_pkt_limit = 8, - .supports_sdio_new_mode = false, - .has_control_mask = true, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, - .supports_fw_dump = false, - .auto_tdls = false, + .supports_sdio_new_mode = false, + .has_control_mask = true, + .can_dump_fw = false, + .can_auto_tdls = false, .can_ext_scan = true, }; @@ -442,13 +444,13 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { .reg = &mwifiex_reg_sd87xx, .max_ports = 16, .mp_agg_pkt_limit = 8, - .supports_sdio_new_mode = false, - .has_control_mask = true, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, - .supports_fw_dump = false, - .auto_tdls = false, + .supports_sdio_new_mode = false, + .has_control_mask = true, + .can_dump_fw = false, + .can_auto_tdls = false, .can_ext_scan = true, }; @@ -457,13 +459,13 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { .reg = &mwifiex_reg_sd8897, .max_ports = 32, .mp_agg_pkt_limit = 16, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, + .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, + .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, .supports_sdio_new_mode = true, .has_control_mask = false, - .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, - .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, - .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, - .supports_fw_dump = true, - .auto_tdls = false, + .can_dump_fw = true, + .can_auto_tdls = false, .can_ext_scan = true, }; @@ -472,13 +474,13 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { .reg = &mwifiex_reg_sd8887, .max_ports = 32, .mp_agg_pkt_limit = 16, - .supports_sdio_new_mode = true, - .has_control_mask = false, - .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, - .supports_fw_dump = false, - .auto_tdls = true, + .supports_sdio_new_mode = true, + .has_control_mask = false, + .can_dump_fw = false, + .can_auto_tdls = true, .can_ext_scan = true, }; @@ -492,8 +494,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = { .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, - .supports_fw_dump = false, - .auto_tdls = false, + .can_dump_fw = false, + .can_auto_tdls = false, .can_ext_scan = true, }; @@ -571,9 +573,9 @@ mp_tx_aggr_port_limit_reached(struct sdio_mmc_card *card) /* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ static inline void mp_rx_aggr_setup(struct sdio_mmc_card *card, - struct sk_buff *skb, u8 port) + u16 rx_len, u8 port) { - card->mpa_rx.buf_len += skb->len; + card->mpa_rx.buf_len += rx_len; if (!card->mpa_rx.pkt_cnt) card->mpa_rx.start_port = port; @@ -586,8 +588,8 @@ static inline void mp_rx_aggr_setup(struct sdio_mmc_card *card, else card->mpa_rx.ports |= 1 << (card->mpa_rx.pkt_cnt + 1); } - card->mpa_rx.skb_arr[card->mpa_rx.pkt_cnt] = skb; - card->mpa_rx.len_arr[card->mpa_rx.pkt_cnt] = skb->len; + card->mpa_rx.skb_arr[card->mpa_rx.pkt_cnt] = NULL; + card->mpa_rx.len_arr[card->mpa_rx.pkt_cnt] = rx_len; card->mpa_rx.pkt_cnt++; } #endif /* _MWIFIEX_SDIO_H */ diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index f7d204ffd6e9..49422f2a5380 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1370,22 +1370,29 @@ mwifiex_cmd_mef_cfg(struct mwifiex_private *priv, struct mwifiex_ds_mef_cfg *mef) { struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg; + struct mwifiex_fw_mef_entry *mef_entry = NULL; u8 *pos = (u8 *)mef_cfg; + u16 i; cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG); mef_cfg->criteria = cpu_to_le32(mef->criteria); mef_cfg->num_entries = cpu_to_le16(mef->num_entries); pos += sizeof(*mef_cfg); - mef_cfg->mef_entry->mode = mef->mef_entry->mode; - mef_cfg->mef_entry->action = mef->mef_entry->action; - pos += sizeof(*(mef_cfg->mef_entry)); - if (mwifiex_cmd_append_rpn_expression(priv, mef->mef_entry, &pos)) - return -1; + for (i = 0; i < mef->num_entries; i++) { + mef_entry = (struct mwifiex_fw_mef_entry *)pos; + mef_entry->mode = mef->mef_entry[i].mode; + mef_entry->action = mef->mef_entry[i].action; + pos += sizeof(*mef_cfg->mef_entry); + + if (mwifiex_cmd_append_rpn_expression(priv, + &mef->mef_entry[i], &pos)) + return -1; - mef_cfg->mef_entry->exprsize = - cpu_to_le16(pos - mef_cfg->mef_entry->expr); + mef_entry->exprsize = + cpu_to_le16(pos - mef_entry->expr); + } cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN); return 0; @@ -1664,6 +1671,25 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, return 0; } + +/* This function prepares command of sdio rx aggr info. */ +static int mwifiex_cmd_sdio_rx_aggr_cfg(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_sdio_sp_rx_aggr_cfg *cfg = + &cmd->params.sdio_rx_aggr_cfg; + + cmd->command = cpu_to_le16(HostCmd_CMD_SDIO_SP_RX_AGGR_CFG); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_sdio_sp_rx_aggr_cfg) + + S_DS_GEN); + cfg->action = cmd_action; + if (cmd_action == HostCmd_ACT_GEN_SET) + cfg->enable = *(u8 *)data_buf; + + return 0; +} + /* * This function prepares the commands before sending them to the firmware. * @@ -1901,6 +1927,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr, data_buf); break; + case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: + ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action, + data_buf); + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -1940,6 +1970,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) struct mwifiex_ds_auto_ds auto_ds; enum state_11d_t state_11d; struct mwifiex_ds_11n_tx_cfg tx_cfg; + u8 sdio_sp_rx_aggr_enable; if (first_sta) { if (priv->adapter->iface_type == MWIFIEX_PCIE) { @@ -1983,6 +2014,22 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) if (ret) return -1; + /** Set SDIO Single Port RX Aggr Info */ + if (priv->adapter->iface_type == MWIFIEX_SDIO && + ISSUPP_SDIO_SPA_ENABLED(priv->adapter->fw_cap_info)) { + sdio_sp_rx_aggr_enable = true; + ret = mwifiex_send_cmd(priv, + HostCmd_CMD_SDIO_SP_RX_AGGR_CFG, + HostCmd_ACT_GEN_SET, 0, + &sdio_sp_rx_aggr_enable, + true); + if (ret) { + dev_err(priv->adapter->dev, + "error while enabling SP aggregation..disable it"); + adapter->sdio_rx_aggr_enable = false; + } + } + /* Reconfigure tx buf size */ ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, HostCmd_ACT_GEN_SET, 0, diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 5f8da5924666..88dc6b672ef4 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -90,6 +90,10 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, case HostCmd_CMD_MAC_CONTROL: break; + case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: + dev_err(priv->adapter->dev, "SDIO RX single-port aggregation Not support\n"); + break; + default: break; } @@ -943,6 +947,20 @@ static int mwifiex_ret_cfg_data(struct mwifiex_private *priv, return 0; } +/** This Function handles the command response of sdio rx aggr */ +static int mwifiex_ret_sdio_rx_aggr_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_sdio_sp_rx_aggr_cfg *cfg = + &resp->params.sdio_rx_aggr_cfg; + + adapter->sdio_rx_aggr_enable = cfg->enable; + adapter->sdio_rx_block_size = le16_to_cpu(cfg->block_size); + + return 0; +} + /* * This function handles the command responses. * @@ -1124,6 +1142,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_CHAN_REPORT_REQUEST: break; + case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: + ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp); + break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", resp->command); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 80ffe7412496..0dc7a1d3993d 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -135,7 +135,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) cfg80211_disconnected(priv->netdev, reason_code, NULL, 0, GFP_KERNEL); } - memset(priv->cfg_bssid, 0, ETH_ALEN); + eth_zero_addr(priv->cfg_bssid); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) @@ -312,7 +312,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; - del_timer_sync(&adapter->wakeup_timer); + del_timer(&adapter->wakeup_timer); break; } if (!mwifiex_send_null_packet @@ -327,7 +327,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; - del_timer_sync(&adapter->wakeup_timer); + del_timer(&adapter->wakeup_timer); break; diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index ac93557cbdc9..a245f444aeec 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -80,23 +80,29 @@ EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, struct mwifiex_tx_param *tx_param) { - int ret = -1; + int hroom, ret = -1; struct mwifiex_adapter *adapter = priv->adapter; u8 *head_ptr; struct txpd *local_tx_pd = NULL; + hroom = (adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN; + if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) head_ptr = mwifiex_process_uap_txpd(priv, skb); else head_ptr = mwifiex_process_sta_txpd(priv, skb); + if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) { + skb_queue_tail(&adapter->tx_data_q, skb); + atomic_inc(&adapter->tx_queued); + return 0; + } + if (head_ptr) { if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) - local_tx_pd = - (struct txpd *) (head_ptr + INTF_HEADER_LEN); + local_tx_pd = (struct txpd *)(head_ptr + hroom); if (adapter->iface_type == MWIFIEX_USB) { adapter->data_sent = true; - skb_pull(skb, INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA, skb, NULL); @@ -142,6 +148,123 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, return ret; } +static int mwifiex_host_to_card(struct mwifiex_adapter *adapter, + struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + struct txpd *local_tx_pd = NULL; + u8 *head_ptr = skb->data; + int ret = 0; + struct mwifiex_private *priv; + struct mwifiex_txinfo *tx_info; + + tx_info = MWIFIEX_SKB_TXCB(skb); + priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num, + tx_info->bss_type); + if (!priv) { + dev_err(adapter->dev, "data: priv not found. Drop TX packet\n"); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, 0, 0); + return ret; + } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { + if (adapter->iface_type == MWIFIEX_USB) + local_tx_pd = (struct txpd *)head_ptr; + else + local_tx_pd = (struct txpd *) (head_ptr + + INTF_HEADER_LEN); + } + + if (adapter->iface_type == MWIFIEX_USB) { + adapter->data_sent = true; + ret = adapter->if_ops.host_to_card(adapter, + MWIFIEX_USB_EP_DATA, + skb, NULL); + } else { + ret = adapter->if_ops.host_to_card(adapter, + MWIFIEX_TYPE_DATA, + skb, tx_param); + } + switch (ret) { + case -ENOSR: + dev_err(adapter->dev, "data: -ENOSR is returned\n"); + break; + case -EBUSY: + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (adapter->pps_uapsd_mode) && + (adapter->tx_lock_flag)) { + priv->adapter->tx_lock_flag = false; + if (local_tx_pd) + local_tx_pd->flags = 0; + } + skb_queue_head(&adapter->tx_data_q, skb); + if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) + atomic_add(tx_info->aggr_num, &adapter->tx_queued); + else + atomic_inc(&adapter->tx_queued); + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + break; + case -1: + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; + dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", + ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, 0, ret); + break; + case -EINPROGRESS: + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb, 0, ret); + break; + default: + break; + } + return ret; +} + +static int +mwifiex_dequeue_tx_queue(struct mwifiex_adapter *adapter) +{ + struct sk_buff *skb, *skb_next; + struct mwifiex_txinfo *tx_info; + struct mwifiex_tx_param tx_param; + + skb = skb_dequeue(&adapter->tx_data_q); + if (!skb) + return -1; + + tx_info = MWIFIEX_SKB_TXCB(skb); + if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) + atomic_sub(tx_info->aggr_num, &adapter->tx_queued); + else + atomic_dec(&adapter->tx_queued); + + if (!skb_queue_empty(&adapter->tx_data_q)) + skb_next = skb_peek(&adapter->tx_data_q); + else + skb_next = NULL; + tx_param.next_pkt_len = ((skb_next) ? skb_next->len : 0); + if (!tx_param.next_pkt_len) { + if (!mwifiex_wmm_lists_empty(adapter)) + tx_param.next_pkt_len = 1; + } + return mwifiex_host_to_card(adapter, skb, &tx_param); +} + +void +mwifiex_process_tx_queue(struct mwifiex_adapter *adapter) +{ + do { + if (adapter->data_sent || adapter->tx_lock_flag) + break; + if (mwifiex_dequeue_tx_queue(adapter)) + break; + } while (!skb_queue_empty(&adapter->tx_data_q)); +} + /* * Packet send completion callback handler. * @@ -179,8 +302,11 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, priv->stats.tx_errors++; } - if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) + if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) { atomic_dec_return(&adapter->pending_bridged_pkts); + if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) + goto done; + } if (aggr) /* For skb_aggr, do not wake up tx queue */ diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 223873022ffe..fd8027f200a0 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -193,7 +193,7 @@ static void mwifiex_usb_rx_complete(struct urb *urb) dev_dbg(adapter->dev, "info: recv_length=%d, status=%d\n", recv_length, status); if (status == -EINPROGRESS) { - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_queue_main_work(adapter); /* urb for data_ep is re-submitted now; * urb for cmd_ep will be re-submitted in callback @@ -262,7 +262,7 @@ static void mwifiex_usb_tx_complete(struct urb *urb) urb->status ? -1 : 0); } - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_queue_main_work(adapter); return; } @@ -1006,7 +1006,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) { /* Simulation of HS_AWAKE event */ adapter->pm_wakeup_fw_try = false; - del_timer_sync(&adapter->wakeup_timer); + del_timer(&adapter->wakeup_timer); adapter->pm_wakeup_card_req = false; adapter->ps_state = PS_STATE_AWAKE; diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 308550611f22..b8a45872354d 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -367,6 +367,13 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, if (!skb) return -1; + if (!priv->mgmt_frame_mask || + priv->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) { + dev_dbg(priv->adapter->dev, + "do not receive mgmt frames on uninitialized intf"); + return -1; + } + rx_pd = (struct rxpd *)skb->data; skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset)); @@ -624,3 +631,26 @@ void mwifiex_hist_data_reset(struct mwifiex_private *priv) for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++) atomic_set(&phist_data->sig_str[ix], 0); } + +void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags) +{ + struct sk_buff *skb; + int buf_len, pad; + + buf_len = rx_len + MWIFIEX_RX_HEADROOM + MWIFIEX_DMA_ALIGN_SZ; + + skb = __dev_alloc_skb(buf_len, flags); + + if (!skb) + return NULL; + + skb_reserve(skb, MWIFIEX_RX_HEADROOM); + + pad = MWIFIEX_ALIGN_ADDR(skb->data, MWIFIEX_DMA_ALIGN_SZ) - + (long)skb->data; + + skb_reserve(skb, pad); + + return skb; +} +EXPORT_SYMBOL_GPL(mwifiex_alloc_dma_align_buf); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index ef717acec8b7..b2e99569a0f8 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -157,6 +157,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra) ra_list->is_11n_enabled = 0; ra_list->tdls_link = false; + ra_list->ba_status = BA_SETUP_NONE; + ra_list->amsdu_in_ampdu = false; if (!mwifiex_queuing_ra_based(priv)) { if (mwifiex_get_tdls_link_status(priv, ra) == TDLS_SETUP_COMPLETE) { @@ -574,7 +576,7 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) * This function retrieves a particular RA list node, matching with the * given TID and RA address. */ -static struct mwifiex_ra_list_tbl * +struct mwifiex_ra_list_tbl * mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr) { @@ -730,7 +732,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, } else { memcpy(ra, skb->data, ETH_ALEN); if (ra[0] & 0x01 || mwifiex_is_skb_mgmt_frame(skb)) - memset(ra, 0xff, ETH_ALEN); + eth_broadcast_addr(ra); ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); } @@ -942,14 +944,11 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, struct mwifiex_ra_list_tbl *ptr; struct mwifiex_tid_tbl *tid_ptr; atomic_t *hqp; - unsigned long flags_bss, flags_ra; + unsigned long flags_ra; int i, j; /* check the BSS with highest priority first */ for (j = adapter->priv_num - 1; j >= 0; --j) { - spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock, - flags_bss); - /* iterate over BSS with the equal priority */ list_for_each_entry(adapter->bss_prio_tbl[j].bss_prio_cur, &adapter->bss_prio_tbl[j].bss_prio_head, @@ -985,19 +984,15 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, } } - spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock, - flags_bss); } return NULL; found: - /* holds bss_prio_lock / ra_list_spinlock */ + /* holds ra_list_spinlock */ if (atomic_read(hqp) > i) atomic_set(hqp, i); spin_unlock_irqrestore(&priv_tmp->wmm.ra_list_spinlock, flags_ra); - spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock, - flags_bss); *priv = priv_tmp; *tid = tos_to_tid[i]; @@ -1179,6 +1174,14 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, skb = skb_dequeue(&ptr->skb_head); + if (adapter->data_sent || adapter->tx_lock_flag) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + skb_queue_tail(&adapter->tx_data_q, skb); + atomic_inc(&adapter->tx_queued); + return; + } + if (!skb_queue_empty(&ptr->skb_head)) skb_next = skb_peek(&ptr->skb_head); else @@ -1276,13 +1279,13 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) } if (!ptr->is_11n_enabled || - mwifiex_is_ba_stream_setup(priv, ptr, tid) || - priv->wps.session_enable) { + ptr->ba_status || + priv->wps.session_enable) { if (ptr->is_11n_enabled && - mwifiex_is_ba_stream_setup(priv, ptr, tid) && - mwifiex_is_amsdu_in_ampdu_allowed(priv, ptr, tid) && - mwifiex_is_amsdu_allowed(priv, tid) && - mwifiex_is_11n_aggragation_possible(priv, ptr, + ptr->ba_status && + ptr->amsdu_in_ampdu && + mwifiex_is_amsdu_allowed(priv, tid) && + mwifiex_is_11n_aggragation_possible(priv, ptr, adapter->tx_buf_size)) mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags); /* ra_list_spinlock has been freed in @@ -1329,11 +1332,16 @@ void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter) { do { - /* Check if busy */ - if (adapter->data_sent || adapter->tx_lock_flag) - break; - if (mwifiex_dequeue_tx_packet(adapter)) break; + if (adapter->iface_type != MWIFIEX_SDIO) { + if (adapter->data_sent || + adapter->tx_lock_flag) + break; + } else { + if (atomic_read(&adapter->tx_queued) >= + MWIFIEX_MAX_PKTS_TXQ) + break; + } } while (!mwifiex_wmm_lists_empty(adapter)); } diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 569bd73f33c5..48ece0b35591 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -127,4 +127,6 @@ mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid); +struct mwifiex_ra_list_tbl *mwifiex_wmm_get_ralist_node(struct mwifiex_private + *priv, u8 tid, const u8 *ra_addr); #endif /* !_MWIFIEX_WMM_H_ */ |