diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/tx.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.c | 140 |
1 files changed, 87 insertions, 53 deletions
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 48fde96ce0d4..08227e69616b 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -37,9 +37,10 @@ static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); if (is_ap) - ret = wl1271_cmd_set_ap_default_wep_key(wl, id); + ret = wl12xx_cmd_set_default_wep_key(wl, id, + wl->ap_bcast_hlid); else - ret = wl1271_cmd_set_sta_default_wep_key(wl, id); + ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid); if (ret < 0) return ret; @@ -77,6 +78,7 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, struct sk_buff *skb) { struct ieee80211_hdr *hdr; + int ret; hdr = (struct ieee80211_hdr *)(skb->data + sizeof(struct wl1271_tx_hw_descr)); @@ -90,9 +92,19 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, if (!ieee80211_is_auth(hdr->frame_control)) return 0; - wl1271_configure_filters(wl, FIF_OTHER_BSS); + if (wl->dev_hlid != WL12XX_INVALID_LINK_ID) + goto out; - return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); + wl1271_debug(DEBUG_CMD, "starting device role for roaming"); + ret = wl12xx_cmd_role_start_dev(wl); + if (ret < 0) + goto out; + + ret = wl12xx_roc(wl, wl->dev_role_id); + if (ret < 0) + goto out; +out: + return 0; } static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, @@ -114,24 +126,29 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) { bool fw_ps; - u8 tx_blks; + u8 tx_pkts; /* only regulate station links */ if (hlid < WL1271_AP_STA_HLID_START) return; fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); - tx_blks = wl->links[hlid].allocated_blks; + tx_pkts = wl->links[hlid].allocated_pkts; /* * if in FW PS and there is enough data in FW we can put the link * into high-level PS and clean out its TX queues. */ - if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) + if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_start(wl, hlid, true); } -u8 wl1271_tx_get_hlid(struct sk_buff *skb) +static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) +{ + return wl->dummy_packet == skb; +} + +u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb) { struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); @@ -144,14 +161,32 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb) } else { struct ieee80211_hdr *hdr; + if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) + return wl->system_hlid; + hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_mgmt(hdr->frame_control)) - return WL1271_AP_GLOBAL_HLID; + return wl->ap_global_hlid; else - return WL1271_AP_BROADCAST_HLID; + return wl->ap_bcast_hlid; } } +static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb) +{ + if (wl12xx_is_dummy_packet(wl, skb)) + return wl->system_hlid; + + if (wl->bss_type == BSS_TYPE_AP_BSS) + return wl12xx_tx_get_hlid_ap(wl, skb); + + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || + test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) + return wl->sta_hlid; + else + return wl->dev_hlid; +} + static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, unsigned int packet_length) { @@ -169,12 +204,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 len; u32 total_blocks; int id, ret = -EBUSY, ac; - u32 spare_blocks; - - if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) - spare_blocks = 2; - else - spare_blocks = 1; + u32 spare_blocks = wl->tx_spare_blocks; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) return -EAGAIN; @@ -188,6 +218,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, in the firmware */ len = wl12xx_calc_packet_alignment(wl, total_len); + /* in case of a dummy packet, use default amount of spare mem blocks */ + if (unlikely(wl12xx_is_dummy_packet(wl, skb))) + spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + spare_blocks; @@ -206,12 +240,14 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, desc->id = id; wl->tx_blocks_available -= total_blocks; + wl->tx_allocated_blocks += total_blocks; ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - wl->tx_allocated_blocks[ac] += total_blocks; + wl->tx_allocated_pkts[ac]++; - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->links[hlid].allocated_blks += total_blocks; + if (wl->bss_type == BSS_TYPE_AP_BSS && + hlid >= WL1271_AP_STA_HLID_START) + wl->links[hlid].allocated_pkts++; ret = 0; @@ -225,11 +261,6 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, return ret; } -static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) -{ - return wl->dummy_packet == skb; -} - static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control, u8 hlid) @@ -280,9 +311,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; } - if (wl->bss_type != BSS_TYPE_AP_BSS) { - desc->aid = hlid; + desc->hlid = hlid; + if (wl->bss_type != BSS_TYPE_AP_BSS) { /* if the packets are destined for AP (have a STA entry) send them with AP rate policies, otherwise use default basic rates */ @@ -291,18 +322,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, else rate_idx = ACX_TX_BASIC_RATE; } else { - desc->hlid = hlid; - switch (hlid) { - case WL1271_AP_GLOBAL_HLID: + if (hlid == wl->ap_global_hlid) rate_idx = ACX_TX_AP_MODE_MGMT_RATE; - break; - case WL1271_AP_BROADCAST_HLID: + else if (hlid == wl->ap_bcast_hlid) rate_idx = ACX_TX_AP_MODE_BCST_RATE; - break; - default: + else rate_idx = ac; - break; - } } tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; @@ -376,10 +401,11 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, } } - if (wl->bss_type == BSS_TYPE_AP_BSS) - hlid = wl1271_tx_get_hlid(skb); - else - hlid = TX_HW_DEFAULT_AID; + hlid = wl1271_tx_get_hlid(wl, skb); + if (hlid == WL12XX_INVALID_LINK_ID) { + wl1271_error("invalid hlid. dropping skb 0x%p", skb); + return -EINVAL; + } ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid); if (ret < 0) @@ -462,20 +488,24 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl) static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, struct sk_buff_head *queues) { - int i, q = -1; - u32 min_blks = 0xffffffff; + int i, q = -1, ac; + u32 min_pkts = 0xffffffff; /* * Find a non-empty ac where: * 1. There are packets to transmit * 2. The FW has the least allocated blocks + * + * We prioritize the ACs according to VO>VI>BE>BK */ - for (i = 0; i < NUM_TX_QUEUES; i++) - if (!skb_queue_empty(&queues[i]) && - (wl->tx_allocated_blocks[i] < min_blks)) { - q = i; - min_blks = wl->tx_allocated_blocks[q]; + for (i = 0; i < NUM_TX_QUEUES; i++) { + ac = wl1271_tx_get_queue(i); + if (!skb_queue_empty(&queues[ac]) && + (wl->tx_allocated_pkts[ac] < min_pkts)) { + q = ac; + min_pkts = wl->tx_allocated_pkts[q]; } + } if (q == -1) return NULL; @@ -579,7 +609,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) if (wl12xx_is_dummy_packet(wl, skb)) { set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); } else if (wl->bss_type == BSS_TYPE_AP_BSS) { - u8 hlid = wl1271_tx_get_hlid(skb); + u8 hlid = wl1271_tx_get_hlid(wl, skb); skb_queue_head(&wl->links[hlid].tx_queue[q], skb); /* make sure we dequeue the same packet next time */ @@ -826,10 +856,14 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) total[i] = 0; while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); - info = IEEE80211_SKB_CB(skb); - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - ieee80211_tx_status_ni(wl->hw, skb); + + if (!wl12xx_is_dummy_packet(wl, skb)) { + info = IEEE80211_SKB_CB(skb); + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + ieee80211_tx_status_ni(wl->hw, skb); + } + total[i]++; } } @@ -853,8 +887,8 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) if (wl->bss_type == BSS_TYPE_AP_BSS) { for (i = 0; i < AP_MAX_LINKS; i++) { wl1271_tx_reset_link_queues(wl, i); - wl->links[i].allocated_blks = 0; - wl->links[i].prev_freed_blks = 0; + wl->links[i].allocated_pkts = 0; + wl->links[i].prev_freed_pkts = 0; } wl->last_tx_hlid = 0; |