diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8fefed2342d78bfb39e52295963235944e06c448..9db66d58f0efb05ce1b2e7536b685e51dac0604c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -86,6 +86,7 @@ MODULE_PARM_DESC(ap_mode_default, #define MWL8K_RX_QUEUES 1 #define MWL8K_TX_QUEUES 4 +#define MWL8K_MAX_AMPDU_QUEUES 8 struct rxd_ops { int rxd_size; @@ -159,6 +160,9 @@ struct mwl8k_priv { u32 ap_macids_supported; u32 sta_macids_supported; + /* Ampdu stream information */ + u8 num_ampdu_queues; + /* firmware access */ struct mutex fw_mutex; struct task_struct *fw_mutex_owner; @@ -190,8 +194,8 @@ struct mwl8k_priv { int pending_tx_pkts; struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; - struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; - u32 txq_offset[MWL8K_TX_QUEUES]; + struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES + MWL8K_MAX_AMPDU_QUEUES]; + u32 txq_offset[MWL8K_TX_QUEUES + MWL8K_MAX_AMPDU_QUEUES]; bool radio_on; bool radio_short_preamble; @@ -1322,7 +1326,7 @@ struct mwl8k_tx_desc { __le16 pkt_len; __u8 dest_MAC_addr[ETH_ALEN]; __le32 next_txd_phys_addr; - __le32 reserved; + __le32 timestamp; __le16 rate_info; __u8 peer_id; __u8 tx_frag_cnt; @@ -2023,13 +2027,16 @@ struct mwl8k_cmd_get_hw_spec_ap { __le32 wcbbase2; __le32 wcbbase3; __le32 fw_api_version; + __le32 caps; + __le32 num_of_ampdu_queues; + __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; } __packed; static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_get_hw_spec_ap *cmd; - int rc; + int rc, i; u32 api_version; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2061,10 +2068,17 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - mwl8k_setup_2ghz_band(hw); + mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); priv->ap_macids_supported = 0x000000ff; priv->sta_macids_supported = 0x00000000; - + priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); + if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { + wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" + " but we only support %d.\n", + priv->num_ampdu_queues, + MWL8K_MAX_AMPDU_QUEUES); + priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES; + } off = le32_to_cpu(cmd->rxwrptr) & 0xffff; iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); @@ -2075,6 +2089,10 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; + + for (i = 0; i < priv->num_ampdu_queues; i++) + priv->txq_offset[i + MWL8K_TX_QUEUES] = + le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; } done: @@ -2103,6 +2121,14 @@ struct mwl8k_cmd_set_hw_spec { __le32 total_rxd; } __packed; +/* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause + * packets to expire 500 ms after the timestamp in the tx descriptor. That is, + * the packets that are queued for more than 500ms, will be dropped in the + * hardware. This helps minimizing the issues caused due to head-of-line + * blocking where a slow client can hog the bandwidth and affect traffic to a + * faster client. + */ +#define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 @@ -4434,7 +4460,7 @@ enum { MWL8366, }; -#define MWL8K_8366_AP_FW_API 1 +#define MWL8K_8366_AP_FW_API 2 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) @@ -4650,6 +4676,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) * total number of queues from the result CMD_GET_HW_SPEC, so for this * case we must initialize the tx queues after. */ + priv->num_ampdu_queues = 0; if (!priv->ap_fw) { rc = mwl8k_init_txqs(hw); if (rc)