#include "wl1251_tx.h"
#include "wl1251_ps.h"
#include "wl1251_io.h"
+#include "wl12xx_80211.h"
static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
{
return ret;
}
+static int wl1251_tx_pspoll(struct wl1251 *wl)
+{
+ struct wl12xx_ps_poll_template *pspoll;
+ struct ieee80211_tx_info *info;
+ struct sk_buff *skb;
+ int ret;
+ u16 fc;
+
+ skb = dev_alloc_skb(wl->hw->extra_tx_headroom + sizeof(*pspoll));
+ if (!skb) {
+ wl1251_warning("failed to allocate buffer for pspoll frame");
+ return -ENOMEM;
+ }
+ skb_reserve(skb, wl->hw->extra_tx_headroom);
+
+ pspoll = (struct wl12xx_ps_poll_template *) skb_put(skb,
+ sizeof(*pspoll));
+ memset(pspoll, 0, sizeof(*pspoll));
+ fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM;
+ pspoll->fc = cpu_to_le16(fc);
+ pspoll->aid = cpu_to_le16(wl->aid);
+
+ /* aid in PS-Poll has its two MSBs each set to 1 */
+ pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
+
+ memcpy(pspoll->bssid, wl->bssid, ETH_ALEN);
+ memcpy(pspoll->ta, wl->mac_addr, ETH_ALEN);
+
+ /* hack to inform that skb is not from mac80211 */
+ info = IEEE80211_SKB_CB(skb);
+ info->driver_data[0] = (void *) 1;
+
+ ret = wl1251_tx_frame(wl, skb);
+
+ if (ret == -EBUSY) {
+ /* firmware buffer is full, stop queues */
+ wl1251_debug(DEBUG_TX, "tx_pspoll: fw buffer full, "
+ "stop queues");
+ ieee80211_stop_queues(wl->hw);
+ wl->tx_queue_stopped = true;
+ }
+
+ if (ret < 0)
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
void wl1251_tx_work(struct work_struct *work)
{
struct wl1251 *wl = container_of(work, struct wl1251, tx_work);
woken_up = true;
}
+ if (wl->psm) {
+ ret = wl1251_tx_pspoll(wl);
+
+ if (ret < 0) {
+ /* ps poll failed, put skb back to queue */
+ skb_queue_head(&wl->tx_queue, skb);
+ goto out;
+ }
+ }
+
ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
skb_queue_head(&wl->tx_queue, skb);
return;
}
+ wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
+ " status 0x%x (%s)",
+ result->id, skb, result->ack_failures, result->rate,
+ result->status, wl1251_tx_parse_status(result->status));
+
info = IEEE80211_SKB_CB(skb);
+ /* hack: check if skb is not from mac80211 */
+ if ((unsigned long) info->driver_data[0] == 1) {
+ dev_kfree_skb(skb);
+ goto out;
+ }
+
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
(result->status == TX_SUCCESS))
info->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status(wl->hw, skb);
+out:
wl->tx_frames[result->id] = NULL;
if (wl->tx_queue_stopped) {