summaryrefslogtreecommitdiff
path: root/drivers/staging/cw1200/wsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/cw1200/wsm.c')
-rw-r--r--drivers/staging/cw1200/wsm.c48
1 files changed, 33 insertions, 15 deletions
diff --git a/drivers/staging/cw1200/wsm.c b/drivers/staging/cw1200/wsm.c
index 2ad3eceaf69..6514b9227a7 100644
--- a/drivers/staging/cw1200/wsm.c
+++ b/drivers/staging/cw1200/wsm.c
@@ -851,6 +851,7 @@ underflow:
}
static int wsm_receive_indication(struct cw1200_common *priv,
+ int link_id,
struct wsm_buf *buf,
struct sk_buff **skb_p)
{
@@ -865,6 +866,7 @@ static int wsm_receive_indication(struct cw1200_common *priv,
rx.rxedRate = WSM_GET8(buf);
rx.rcpiRssi = WSM_GET8(buf);
rx.flags = WSM_GET32(buf);
+ rx.link_id = link_id;
fctl = *(__le16 *)buf->data;
hdr_len = buf->data - buf->begin;
skb_pull(*skb_p, hdr_len);
@@ -1276,7 +1278,8 @@ int wsm_handle_rx(struct cw1200_common *priv, int id,
ret = wsm_startup_indication(priv, &wsm_buf);
break;
case 0x0804:
- ret = wsm_receive_indication(priv, &wsm_buf, skb_p);
+ ret = wsm_receive_indication(priv, link_id,
+ &wsm_buf, skb_p);
break;
case 0x0805:
ret = wsm_event_indication(priv, &wsm_buf);
@@ -1309,7 +1312,8 @@ out:
static bool wsm_handle_tx_data(struct cw1200_common *priv,
const struct wsm_tx *wsm,
- const struct ieee80211_tx_info *tx_info)
+ const struct ieee80211_tx_info *tx_info,
+ int *link_id)
{
bool handled = false;
const struct ieee80211_hdr *frame =
@@ -1344,6 +1348,24 @@ static bool wsm_handle_tx_data(struct cw1200_common *priv,
case NL80211_IFTYPE_AP:
if (unlikely(!priv->join_status))
action = doDrop;
+ if (*link_id == CW1200_LINK_ID_AFTER_DTIM)
+ *link_id = 0;
+ else if (WARN_ON(!(BIT(*link_id) &
+ (BIT(0) | priv->link_id_map))))
+ action = doDrop;
+ if (cw1200_queue_get_generation(wsm->packetID) >
+ CW1200_MAX_REQUEUE_ATTEMPTS) {
+ /* HACK!!! WSM324 firmware has tendency to requeue
+ * multicast frames in a loop, causing performance
+ * drop and high power consumption of the driver.
+ * In this situation it is better just to drop
+ * the problematic frame. */
+ wiphy_warn(priv->hw->wiphy,
+ "Too many attempts "
+ "to requeue a frame. "
+ "Frame is dropped.\n");
+ action = doDrop;
+ }
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
@@ -1550,8 +1572,8 @@ int wsm_get_tx(struct cw1200_common *priv, u8 **data,
struct wsm_tx *wsm = NULL;
struct ieee80211_tx_info *tx_info;
struct cw1200_queue *queue;
- struct cw1200_sta_priv *sta_priv;
u32 tx_allowed_mask = 0;
+ int link_id;
/*
* Count was intended as an input for wsm->more flag.
* During implementation it was found that wsm->more
@@ -1600,26 +1622,22 @@ int wsm_get_tx(struct cw1200_common *priv, u8 **data,
if (cw1200_queue_get(queue,
tx_allowed_mask,
- &wsm, &tx_info))
+ &wsm, &tx_info, &link_id))
continue;
- if (wsm_handle_tx_data(priv, wsm, tx_info))
+ if (wsm_handle_tx_data(priv, wsm, tx_info, &link_id))
continue; /* Handled by WSM */
- if (tx_info->control.sta) {
- /* Update link id */
- sta_priv = (struct cw1200_sta_priv *)
- &tx_info->control.sta->drv_priv;
- wsm->hdr.id &= __cpu_to_le16(
- ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX));
- wsm->hdr.id |= cpu_to_le16(
- WSM_TX_LINK_ID(sta_priv->link_id));
- priv->pspoll_mask &= ~BIT(sta_priv->link_id);
- }
+ wsm->hdr.id &= __cpu_to_le16(
+ ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX));
+ wsm->hdr.id |= cpu_to_le16(
+ WSM_TX_LINK_ID(link_id));
+ priv->pspoll_mask &= ~BIT(link_id);
*data = (u8 *)wsm;
*tx_len = __le16_to_cpu(wsm->hdr.len);
+
if (more) {
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *) &wsm[1];