Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 247117
b: refs/heads/master
c: 990f5de
h: refs/heads/master
i:
  247115: f8a0998
v: v3
  • Loading branch information
Ido Yariv authored and Luciano Coelho committed Apr 19, 2011
1 parent 4626813 commit b091b8d
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 40 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0da13da767cd568c1fe2a7b5b936e86e521b5ae7
refs/heads/master: 990f5de7384f9e5922e4c7c7572cbf4f29a9441e
79 changes: 54 additions & 25 deletions trunk/drivers/net/wireless/wl12xx/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1212,50 +1212,69 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
spin_unlock_irqrestore(&wl->wl_lock, flags);
}

#define TX_DUMMY_PACKET_SIZE 1400
int wl1271_tx_dummy_packet(struct wl1271 *wl)
{
struct sk_buff *skb = NULL;
unsigned long flags;

spin_lock_irqsave(&wl->wl_lock, flags);
set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
wl->tx_queue_count++;
spin_unlock_irqrestore(&wl->wl_lock, flags);

/* The FW is low on RX memory blocks, so send the dummy packet asap */
if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
wl1271_tx_work_locked(wl);

/*
* If the FW TX is busy, TX work will be scheduled by the threaded
* interrupt handler function
*/
return 0;
}

/*
* The size of the dummy packet should be at least 1400 bytes. However, in
* order to minimize the number of bus transactions, aligning it to 512 bytes
* boundaries could be beneficial, performance wise
*/
#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))

struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
{
struct sk_buff *skb;
struct ieee80211_hdr_3addr *hdr;
int ret = 0;
unsigned int dummy_packet_size;

dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);

skb = dev_alloc_skb(
sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) +
TX_DUMMY_PACKET_SIZE);
skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
if (!skb) {
wl1271_warning("failed to allocate buffer for dummy packet");
ret = -ENOMEM;
goto out;
wl1271_warning("Failed to allocate a dummy packet skb");
return NULL;
}

skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));

hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
memset(hdr, 0, sizeof(*hdr));
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_FCTL_TODS |
IEEE80211_STYPE_NULLFUNC);

memcpy(hdr->addr1, wl->bssid, ETH_ALEN);
memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN);
memcpy(hdr->addr3, wl->bssid, ETH_ALEN);
IEEE80211_STYPE_NULLFUNC |
IEEE80211_FCTL_TODS);

skb_put(skb, TX_DUMMY_PACKET_SIZE);
memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);

memset(skb->data, 0, TX_DUMMY_PACKET_SIZE);

skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ;
/* Dummy packets require the TID to be management */
skb->priority = WL1271_TID_MGMT;
/* CONF_TX_AC_VO */
skb->queue_mapping = 0;

wl1271_op_tx(wl->hw, skb);
/* Initialize all fields that might be used */
skb->queue_mapping = 0;
memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));

out:
return ret;
return skb;
}


static struct notifier_block wl1271_dev_notifier = {
.notifier_call = wl1271_dev_notify,
};
Expand Down Expand Up @@ -3653,11 +3672,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
goto err_hw;
}

wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
if (!wl->dummy_packet) {
ret = -ENOMEM;
goto err_aggr;
}

/* Register platform device */
ret = platform_device_register(wl->plat_dev);
if (ret) {
wl1271_error("couldn't register platform device");
goto err_aggr;
goto err_dummy_packet;
}
dev_set_drvdata(&wl->plat_dev->dev, wl);

Expand All @@ -3683,6 +3708,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
err_platform:
platform_device_unregister(wl->plat_dev);

err_dummy_packet:
dev_kfree_skb(wl->dummy_packet);

err_aggr:
free_pages((unsigned long)wl->aggr_buf, order);

Expand All @@ -3702,6 +3730,7 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
int wl1271_free_hw(struct wl1271 *wl)
{
platform_device_unregister(wl->plat_dev);
dev_kfree_skb(wl->dummy_packet);
free_pages((unsigned long)wl->aggr_buf,
get_order(WL1271_AGGR_BUFFER_SIZE));
kfree(wl->plat_dev);
Expand Down
43 changes: 31 additions & 12 deletions trunk/drivers/net/wireless/wl12xx/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ 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)
Expand Down Expand Up @@ -253,7 +258,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
desc->tid = skb->priority;

if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
if (wl12xx_is_dummy_packet(wl, skb)) {
/*
* FW expects the dummy packet to have an invalid session id -
* any session id that is different than the one set in the join
Expand Down Expand Up @@ -396,6 +401,10 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);

/* Revert side effects in the dummy packet skb, so it can be reused */
if (wl12xx_is_dummy_packet(wl, skb))
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));

return total_len;
}

Expand Down Expand Up @@ -508,18 +517,33 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)

static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
{
unsigned long flags;
struct sk_buff *skb = NULL;

if (wl->bss_type == BSS_TYPE_AP_BSS)
return wl1271_ap_skb_dequeue(wl);
skb = wl1271_ap_skb_dequeue(wl);
else
skb = wl1271_sta_skb_dequeue(wl);

return wl1271_sta_skb_dequeue(wl);
if (!skb &&
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
skb = wl->dummy_packet;
spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count--;
spin_unlock_irqrestore(&wl->wl_lock, flags);
}

return skb;
}

static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
{
unsigned long flags;
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));

if (wl->bss_type == BSS_TYPE_AP_BSS) {
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);
skb_queue_head(&wl->links[hlid].tx_queue[q], skb);

Expand Down Expand Up @@ -628,8 +652,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
skb = wl->tx_frames[id];
info = IEEE80211_SKB_CB(skb);

if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
dev_kfree_skb(skb);
if (wl12xx_is_dummy_packet(wl, skb)) {
wl1271_free_tx_id(wl, id);
return;
}
Expand Down Expand Up @@ -764,9 +787,7 @@ void wl1271_tx_reset(struct wl1271 *wl)
wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
skb);

if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
dev_kfree_skb(skb);
} else {
if (!wl12xx_is_dummy_packet(wl, skb)) {
info = IEEE80211_SKB_CB(skb);
info->status.rates[0].idx = -1;
info->status.rates[0].count = 0;
Expand All @@ -792,9 +813,7 @@ void wl1271_tx_reset(struct wl1271 *wl)
wl1271_free_tx_id(wl, i);
wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);

if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
dev_kfree_skb(skb);
} else {
if (!wl12xx_is_dummy_packet(wl, skb)) {
/*
* Remove private headers before passing the skb to
* mac80211
Expand Down
2 changes: 0 additions & 2 deletions trunk/drivers/net/wireless/wl12xx/tx.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@
#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12)
#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13)

#define TX_PKT_TYPE_DUMMY_REQ 5

#define TX_HW_ATTR_OFST_SAVE_RETRIES 0
#define TX_HW_ATTR_OFST_HEADER_PAD 1
#define TX_HW_ATTR_OFST_SESSION_COUNTER 2
Expand Down
4 changes: 4 additions & 0 deletions trunk/drivers/net/wireless/wl12xx/wl12xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ enum wl12xx_flags {
WL1271_FLAG_FW_TX_BUSY,
WL1271_FLAG_AP_STARTED,
WL1271_FLAG_IF_INITIALIZED,
WL1271_FLAG_DUMMY_PACKET_PENDING,
};

struct wl1271_link {
Expand Down Expand Up @@ -461,6 +462,9 @@ struct wl1271 {
/* Intermediate buffer, used for packet aggregation */
u8 *aggr_buf;

/* Reusable dummy packet template */
struct sk_buff *dummy_packet;

/* Network stack work */
struct work_struct netstack_work;

Expand Down

0 comments on commit b091b8d

Please sign in to comment.