提交 a32d0cdf 编写于 作者: E Eliad Peller 提交者: Luciano Coelho

wl12xx: support multiple vifs in the tx path

Pass the wlvif associated with each skb as param.

Note that dummy packet doesn't belong to any
particular vif, so we pass NULL in this case.
Signed-off-by: NEliad Peller <eliad@wizery.com>
Signed-off-by: NLuciano Coelho <coelho@ti.com>
上级 87627214
...@@ -993,7 +993,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie) ...@@ -993,7 +993,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
* In order to avoid starvation of the TX path, * In order to avoid starvation of the TX path,
* call the work function directly. * call the work function directly.
*/ */
wl1271_tx_work_locked(wl, wl->vif); wl1271_tx_work_locked(wl);
} else { } else {
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
} }
...@@ -1537,7 +1537,7 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl) ...@@ -1537,7 +1537,7 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl)
/* The FW is low on RX memory blocks, so send the dummy packet asap */ /* The FW is low on RX memory blocks, so send the dummy packet asap */
if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
wl1271_tx_work_locked(wl, wl->vif); wl1271_tx_work_locked(wl);
/* /*
* If the FW TX is busy, TX work will be scheduled by the threaded * If the FW TX is busy, TX work will be scheduled by the threaded
...@@ -2413,7 +2413,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) ...@@ -2413,7 +2413,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
((wl->band != conf->channel->band) || ((wl->band != conf->channel->band) ||
(wl->channel != channel))) { (wl->channel != channel))) {
/* send all pending packets */ /* send all pending packets */
wl1271_tx_work_locked(wl, vif); wl1271_tx_work_locked(wl);
wl->band = conf->channel->band; wl->band = conf->channel->band;
wl->channel = channel; wl->channel = channel;
......
...@@ -210,17 +210,17 @@ static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, ...@@ -210,17 +210,17 @@ static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
return ALIGN(packet_length, WL1271_TX_ALIGN_TO); return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
} }
static int wl1271_tx_allocate(struct wl1271 *wl, struct ieee80211_vif *vif, static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct sk_buff *skb, u32 extra, u32 buf_offset, struct sk_buff *skb, u32 extra, u32 buf_offset,
u8 hlid) u8 hlid)
{ {
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct wl1271_tx_hw_descr *desc; struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
u32 len; u32 len;
u32 total_blocks; u32 total_blocks;
int id, ret = -EBUSY, ac; int id, ret = -EBUSY, ac;
u32 spare_blocks = wl->tx_spare_blocks; u32 spare_blocks = wl->tx_spare_blocks;
bool is_dummy = false;
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
return -EAGAIN; return -EAGAIN;
...@@ -235,8 +235,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -235,8 +235,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct ieee80211_vif *vif,
len = wl12xx_calc_packet_alignment(wl, total_len); len = wl12xx_calc_packet_alignment(wl, total_len);
/* in case of a dummy packet, use default amount of spare mem blocks */ /* in case of a dummy packet, use default amount of spare mem blocks */
if (unlikely(wl12xx_is_dummy_packet(wl, skb))) if (unlikely(wl12xx_is_dummy_packet(wl, skb))) {
is_dummy = true;
spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
}
total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE +
spare_blocks; spare_blocks;
...@@ -261,7 +263,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -261,7 +263,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct ieee80211_vif *vif,
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
wl->tx_allocated_pkts[ac]++; wl->tx_allocated_pkts[ac]++;
if (wlvif->bss_type == BSS_TYPE_AP_BSS && if (!is_dummy && wlvif->bss_type == BSS_TYPE_AP_BSS &&
test_bit(hlid, wlvif->ap.sta_hlid_map)) test_bit(hlid, wlvif->ap.sta_hlid_map))
wl->links[hlid].allocated_pkts++; wl->links[hlid].allocated_pkts++;
...@@ -277,16 +279,16 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -277,16 +279,16 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct ieee80211_vif *vif,
return ret; return ret;
} }
static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct ieee80211_vif *vif, static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct sk_buff *skb, u32 extra, struct sk_buff *skb, u32 extra,
struct ieee80211_tx_info *control, u8 hlid) struct ieee80211_tx_info *control, u8 hlid)
{ {
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct timespec ts; struct timespec ts;
struct wl1271_tx_hw_descr *desc; struct wl1271_tx_hw_descr *desc;
int aligned_len, ac, rate_idx; int aligned_len, ac, rate_idx;
s64 hosttime; s64 hosttime;
u16 tx_attr; u16 tx_attr;
bool is_dummy;
desc = (struct wl1271_tx_hw_descr *) skb->data; desc = (struct wl1271_tx_hw_descr *) skb->data;
...@@ -303,7 +305,8 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -303,7 +305,8 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct ieee80211_vif *vif,
hosttime = (timespec_to_ns(&ts) >> 10); hosttime = (timespec_to_ns(&ts) >> 10);
desc->start_time = cpu_to_le32(hosttime - wl->time_offset); desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
if (wlvif->bss_type != BSS_TYPE_AP_BSS) is_dummy = wl12xx_is_dummy_packet(wl, skb);
if (is_dummy || wlvif->bss_type != BSS_TYPE_AP_BSS)
desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
else else
desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
...@@ -312,7 +315,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -312,7 +315,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct ieee80211_vif *vif,
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
desc->tid = skb->priority; desc->tid = skb->priority;
if (wl12xx_is_dummy_packet(wl, skb)) { if (is_dummy) {
/* /*
* FW expects the dummy packet to have an invalid session id - * FW expects the dummy packet to have an invalid session id -
* any session id that is different than the one set in the join * any session id that is different than the one set in the join
...@@ -329,7 +332,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -329,7 +332,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct ieee80211_vif *vif,
} }
desc->hlid = hlid; desc->hlid = hlid;
if (wlvif->bss_type != BSS_TYPE_AP_BSS) { if (is_dummy)
rate_idx = 0;
else if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
/* if the packets are destined for AP (have a STA entry) /* if the packets are destined for AP (have a STA entry)
send them with AP rate policies, otherwise use default send them with AP rate policies, otherwise use default
basic rates */ basic rates */
...@@ -383,12 +388,10 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -383,12 +388,10 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct ieee80211_vif *vif,
} }
/* caller must hold wl->mutex */ /* caller must hold wl->mutex */
static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u32 buf_offset) struct sk_buff *skb, u32 buf_offset)
{ {
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
u32 extra = 0; u32 extra = 0;
int ret = 0; int ret = 0;
u32 total_len; u32 total_len;
...@@ -402,11 +405,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, ...@@ -402,11 +405,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
/* TODO: handle dummy packets on multi-vifs */ /* TODO: handle dummy packets on multi-vifs */
is_dummy = wl12xx_is_dummy_packet(wl, skb); is_dummy = wl12xx_is_dummy_packet(wl, skb);
if (is_dummy)
info->control.vif = wl->vif;
vif = info->control.vif;
wlvif = wl12xx_vif_to_data(vif);
if (info->control.hw_key && if (info->control.hw_key &&
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
...@@ -433,13 +431,13 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, ...@@ -433,13 +431,13 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
return -EINVAL; return -EINVAL;
} }
ret = wl1271_tx_allocate(wl, vif, skb, extra, buf_offset, hlid); ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid);
if (ret < 0) if (ret < 0)
return ret; return ret;
wl1271_tx_fill_hdr(wl, vif, skb, extra, info, hlid); wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid);
if (wlvif->bss_type == BSS_TYPE_AP_BSS && !is_dummy) { if (!is_dummy && wlvif->bss_type == BSS_TYPE_AP_BSS) {
wl1271_tx_ap_update_inconnection_sta(wl, skb); wl1271_tx_ap_update_inconnection_sta(wl, skb);
wl1271_tx_regulate_link(wl, wlvif, hlid); wl1271_tx_regulate_link(wl, wlvif, hlid);
} }
...@@ -589,13 +587,19 @@ static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, ...@@ -589,13 +587,19 @@ static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl,
return skb; return skb;
} }
static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
struct wl12xx_vif *wlvif)
{ {
unsigned long flags; unsigned long flags;
struct wl12xx_vif *wlvif;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
skb = wl12xx_vif_skb_dequeue(wl, wlvif); /* TODO: rememeber last vif and consider it */
wl12xx_for_each_wlvif(wl, wlvif) {
skb = wl12xx_vif_skb_dequeue(wl, wlvif);
if (skb)
break;
}
if (!skb && if (!skb &&
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
int q; int q;
...@@ -639,24 +643,35 @@ static bool wl1271_tx_is_data_present(struct sk_buff *skb) ...@@ -639,24 +643,35 @@ static bool wl1271_tx_is_data_present(struct sk_buff *skb)
return ieee80211_is_data_present(hdr->frame_control); return ieee80211_is_data_present(hdr->frame_control);
} }
void wl1271_tx_work_locked(struct wl1271 *wl, struct ieee80211_vif *vif) void wl1271_tx_work_locked(struct wl1271 *wl)
{ {
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl12xx_vif *wlvif;
struct sk_buff *skb; struct sk_buff *skb;
u32 buf_offset = 0; u32 buf_offset = 0;
bool sent_packets = false; bool sent_packets = false;
bool had_data = false; bool had_data = false;
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); /* TODO: save bitmap of relevant stations */
bool is_sta = false;
int ret; int ret;
if (unlikely(wl->state == WL1271_STATE_OFF)) if (unlikely(wl->state == WL1271_STATE_OFF))
return; return;
while ((skb = wl1271_skb_dequeue(wl, wlvif))) { while ((skb = wl1271_skb_dequeue(wl))) {
wlvif = NULL;
if (!wl12xx_is_dummy_packet(wl, skb)) {
struct ieee80211_tx_info *info;
struct ieee80211_vif *vif;
info = IEEE80211_SKB_CB(skb);
vif = info->control.vif;
wlvif = wl12xx_vif_to_data(vif);
}
if (wl1271_tx_is_data_present(skb)) if (wl1271_tx_is_data_present(skb))
had_data = true; had_data = true;
ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset);
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
/* /*
* Aggregation buffer is full. * Aggregation buffer is full.
...@@ -683,6 +698,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl, struct ieee80211_vif *vif) ...@@ -683,6 +698,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl, struct ieee80211_vif *vif)
} }
buf_offset += ret; buf_offset += ret;
wl->tx_packets_count++; wl->tx_packets_count++;
if (wlvif && wlvif->bss_type == BSS_TYPE_STA_BSS)
is_sta = true;
} }
out_ack: out_ack:
...@@ -702,7 +719,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl, struct ieee80211_vif *vif) ...@@ -702,7 +719,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl, struct ieee80211_vif *vif)
wl1271_handle_tx_low_watermark(wl); wl1271_handle_tx_low_watermark(wl);
} }
if (!is_ap && wl->conf.rx_streaming.interval && had_data && if (is_sta && wl->conf.rx_streaming.interval && had_data &&
(wl->conf.rx_streaming.always || (wl->conf.rx_streaming.always ||
test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) { test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) {
u32 timeout = wl->conf.rx_streaming.duration; u32 timeout = wl->conf.rx_streaming.duration;
...@@ -727,7 +744,7 @@ void wl1271_tx_work(struct work_struct *work) ...@@ -727,7 +744,7 @@ void wl1271_tx_work(struct work_struct *work)
if (ret < 0) if (ret < 0)
goto out; goto out;
wl1271_tx_work_locked(wl, wl->vif); wl1271_tx_work_locked(wl);
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out: out:
......
...@@ -204,7 +204,7 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl) ...@@ -204,7 +204,7 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl)
} }
void wl1271_tx_work(struct work_struct *work); void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_work_locked(struct wl1271 *wl, struct ieee80211_vif *vif); void wl1271_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl); void wl1271_tx_complete(struct wl1271 *wl);
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues); void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册