mirror of
https://github.com/adulau/aha.git
synced 2024-12-30 12:46:17 +00:00
ar9170: simplify & deBUG tx_status queueing and reporting
This patch simplifies the tx_status report code by using four tx_queues per station instead of only one. (the skb lookup should be in O(1) now :-p ). Also, it fixes a really obvious copy&paste bug in the janitor work code and adds back a few spilled bits to the hardware definition header about QoS. Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
04de838159
commit
4a48e2a484
3 changed files with 49 additions and 103 deletions
|
@ -159,7 +159,7 @@ struct ar9170 {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ar9170_sta_info {
|
struct ar9170_sta_info {
|
||||||
struct sk_buff_head tx_status;
|
struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IS_STARTED(a) (a->state >= AR9170_STARTED)
|
#define IS_STARTED(a) (a->state >= AR9170_STARTED)
|
||||||
|
|
|
@ -397,10 +397,21 @@ struct ar9170_cmd_response {
|
||||||
};
|
};
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/* QoS */
|
||||||
|
|
||||||
/* mac80211 queue to HW/FW map */
|
/* mac80211 queue to HW/FW map */
|
||||||
static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 };
|
static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 };
|
||||||
|
|
||||||
/* HW/FW queue to mac80211 map */
|
/* HW/FW queue to mac80211 map */
|
||||||
static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 };
|
static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 };
|
||||||
|
|
||||||
|
enum ar9170_txq {
|
||||||
|
AR9170_TXQ_BE,
|
||||||
|
AR9170_TXQ_BK,
|
||||||
|
AR9170_TXQ_VI,
|
||||||
|
AR9170_TXQ_VO,
|
||||||
|
|
||||||
|
__AR9170_NUM_TXQ,
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __AR9170_HW_H */
|
#endif /* __AR9170_HW_H */
|
||||||
|
|
|
@ -277,54 +277,6 @@ static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sk_buff *ar9170_find_skb_in_queue_by_mac(struct ar9170 *ar,
|
|
||||||
const u8 *mac,
|
|
||||||
struct sk_buff_head *q)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&q->lock, flags);
|
|
||||||
skb_queue_walk(q, skb) {
|
|
||||||
struct ar9170_tx_control *txc = (void *) skb->data;
|
|
||||||
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
|
|
||||||
|
|
||||||
if (compare_ether_addr(ieee80211_get_DA(hdr), mac))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
__skb_unlink(skb, q);
|
|
||||||
spin_unlock_irqrestore(&q->lock, flags);
|
|
||||||
return skb;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&q->lock, flags);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sk_buff *ar9170_find_skb_in_queue_by_txcq(struct ar9170 *ar,
|
|
||||||
const u32 queue,
|
|
||||||
struct sk_buff_head *q)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&q->lock, flags);
|
|
||||||
skb_queue_walk(q, skb) {
|
|
||||||
struct ar9170_tx_control *txc = (void *) skb->data;
|
|
||||||
u32 txc_queue = (le32_to_cpu(txc->phy_control) &
|
|
||||||
AR9170_TX_PHY_QOS_MASK) >>
|
|
||||||
AR9170_TX_PHY_QOS_SHIFT;
|
|
||||||
|
|
||||||
if (queue != txc_queue)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
__skb_unlink(skb, q);
|
|
||||||
spin_unlock_irqrestore(&q->lock, flags);
|
|
||||||
return skb;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&q->lock, flags);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
|
static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
|
||||||
const u32 queue)
|
const u32 queue)
|
||||||
{
|
{
|
||||||
|
@ -344,21 +296,21 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
|
||||||
|
|
||||||
if (likely(sta)) {
|
if (likely(sta)) {
|
||||||
struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv;
|
struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv;
|
||||||
skb = ar9170_find_skb_in_queue_by_txcq(ar, queue,
|
skb = skb_dequeue(&sta_priv->tx_status[queue]);
|
||||||
&sta_priv->tx_status);
|
rcu_read_unlock();
|
||||||
} else {
|
if (likely(skb))
|
||||||
/* STA is not in database (yet/anymore). */
|
return skb;
|
||||||
|
} else
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
/* scan the waste bin for likely candidates */
|
/* scan the waste queue for candidates */
|
||||||
|
skb = ar9170_find_skb_in_queue(ar, mac, queue,
|
||||||
|
&ar->global_tx_status_waste);
|
||||||
|
if (!skb) {
|
||||||
|
/* so it still _must_ be in the global list. */
|
||||||
skb = ar9170_find_skb_in_queue(ar, mac, queue,
|
skb = ar9170_find_skb_in_queue(ar, mac, queue,
|
||||||
&ar->global_tx_status_waste);
|
&ar->global_tx_status);
|
||||||
if (!skb) {
|
|
||||||
/* so it still _must_ be in the global list. */
|
|
||||||
skb = ar9170_find_skb_in_queue(ar, mac, queue,
|
|
||||||
&ar->global_tx_status);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
#ifdef AR9170_QUEUE_DEBUG
|
#ifdef AR9170_QUEUE_DEBUG
|
||||||
if (unlikely((!skb) && net_ratelimit())) {
|
if (unlikely((!skb) && net_ratelimit())) {
|
||||||
|
@ -367,7 +319,6 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
|
||||||
wiphy_name(ar->hw->wiphy), mac, queue);
|
wiphy_name(ar->hw->wiphy), mac, queue);
|
||||||
}
|
}
|
||||||
#endif /* AR9170_QUEUE_DEBUG */
|
#endif /* AR9170_QUEUE_DEBUG */
|
||||||
|
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,9 +332,13 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
|
||||||
static void ar9170_tx_status_janitor(struct work_struct *work)
|
static void ar9170_tx_status_janitor(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct ar9170 *ar = container_of(work, struct ar9170,
|
struct ar9170 *ar = container_of(work, struct ar9170,
|
||||||
filter_config_work);
|
tx_status_janitor.work);
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
if (unlikely(!IS_STARTED(ar)))
|
||||||
|
return ;
|
||||||
|
|
||||||
|
mutex_lock(&ar->mutex);
|
||||||
/* recycle the garbage back to mac80211... one by one. */
|
/* recycle the garbage back to mac80211... one by one. */
|
||||||
while ((skb = skb_dequeue(&ar->global_tx_status_waste))) {
|
while ((skb = skb_dequeue(&ar->global_tx_status_waste))) {
|
||||||
#ifdef AR9170_QUEUE_DEBUG
|
#ifdef AR9170_QUEUE_DEBUG
|
||||||
|
@ -395,8 +350,6 @@ static void ar9170_tx_status_janitor(struct work_struct *work)
|
||||||
AR9170_TX_STATUS_FAILED);
|
AR9170_TX_STATUS_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while ((skb = skb_dequeue(&ar->global_tx_status))) {
|
while ((skb = skb_dequeue(&ar->global_tx_status))) {
|
||||||
#ifdef AR9170_QUEUE_DEBUG
|
#ifdef AR9170_QUEUE_DEBUG
|
||||||
printk(KERN_DEBUG "%s: moving frame into waste queue =>\n",
|
printk(KERN_DEBUG "%s: moving frame into waste queue =>\n",
|
||||||
|
@ -411,6 +364,8 @@ static void ar9170_tx_status_janitor(struct work_struct *work)
|
||||||
if (skb_queue_len(&ar->global_tx_status_waste) > 0)
|
if (skb_queue_len(&ar->global_tx_status_waste) > 0)
|
||||||
queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
|
queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
|
||||||
msecs_to_jiffies(100));
|
msecs_to_jiffies(100));
|
||||||
|
|
||||||
|
mutex_unlock(&ar->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ar9170_handle_command_response(struct ar9170 *ar,
|
static void ar9170_handle_command_response(struct ar9170 *ar,
|
||||||
|
@ -1012,7 +967,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||||
|
|
||||||
if (info->control.sta) {
|
if (info->control.sta) {
|
||||||
sta_info = (void *) info->control.sta->drv_priv;
|
sta_info = (void *) info->control.sta->drv_priv;
|
||||||
skb_queue_tail(&sta_info->tx_status, skb);
|
skb_queue_tail(&sta_info->tx_status[queue], skb);
|
||||||
} else {
|
} else {
|
||||||
skb_queue_tail(&ar->global_tx_status, skb);
|
skb_queue_tail(&ar->global_tx_status, skb);
|
||||||
|
|
||||||
|
@ -1025,7 +980,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||||
err = ar->tx(ar, skb, tx_status, 0);
|
err = ar->tx(ar, skb, tx_status, 0);
|
||||||
if (unlikely(tx_status && err)) {
|
if (unlikely(tx_status && err)) {
|
||||||
if (info->control.sta)
|
if (info->control.sta)
|
||||||
skb_unlink(skb, &sta_info->tx_status);
|
skb_unlink(skb, &sta_info->tx_status[queue]);
|
||||||
else
|
else
|
||||||
skb_unlink(skb, &ar->global_tx_status);
|
skb_unlink(skb, &ar->global_tx_status);
|
||||||
}
|
}
|
||||||
|
@ -1479,55 +1434,35 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
|
||||||
struct ar9170 *ar = hw->priv;
|
struct ar9170 *ar = hw->priv;
|
||||||
struct ar9170_sta_info *info = (void *) sta->drv_priv;
|
struct ar9170_sta_info *info = (void *) sta->drv_priv;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case STA_NOTIFY_ADD:
|
case STA_NOTIFY_ADD:
|
||||||
skb_queue_head_init(&info->tx_status);
|
for (i = 0; i < ar->hw->queues; i++)
|
||||||
|
skb_queue_head_init(&info->tx_status[i]);
|
||||||
/*
|
|
||||||
* do we already have a frame that needs tx_status
|
|
||||||
* from this station in our queue?
|
|
||||||
* If so then transfer them to the new station queue.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* preserve the correct order - check the waste bin first */
|
|
||||||
while ((skb = ar9170_find_skb_in_queue_by_mac(ar, sta->addr,
|
|
||||||
&ar->global_tx_status_waste)))
|
|
||||||
skb_queue_tail(&info->tx_status, skb);
|
|
||||||
|
|
||||||
/* now the still pending frames */
|
|
||||||
while ((skb = ar9170_find_skb_in_queue_by_mac(ar, sta->addr,
|
|
||||||
&ar->global_tx_status)))
|
|
||||||
skb_queue_tail(&info->tx_status, skb);
|
|
||||||
|
|
||||||
#ifdef AR9170_QUEUE_DEBUG
|
|
||||||
printk(KERN_DEBUG "%s: STA[%pM] has %d queued frames =>\n",
|
|
||||||
wiphy_name(ar->hw->wiphy), sta->addr,
|
|
||||||
skb_queue_len(&info->tx_status));
|
|
||||||
|
|
||||||
ar9170_dump_station_tx_status_queue(ar, &info->tx_status);
|
|
||||||
#endif /* AR9170_QUEUE_DEBUG */
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STA_NOTIFY_REMOVE:
|
case STA_NOTIFY_REMOVE:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* transfer all outstanding frames that need a tx_status
|
* transfer all outstanding frames that need a tx_status
|
||||||
* reports to the fallback queue
|
* reports to the global tx_status queue
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while ((skb = skb_dequeue(&ar->global_tx_status))) {
|
for (i = 0; i < ar->hw->queues; i++) {
|
||||||
|
while ((skb = skb_dequeue(&info->tx_status[i]))) {
|
||||||
#ifdef AR9170_QUEUE_DEBUG
|
#ifdef AR9170_QUEUE_DEBUG
|
||||||
printk(KERN_DEBUG "%s: queueing frame in global "
|
printk(KERN_DEBUG "%s: queueing frame in "
|
||||||
"tx_status queue =>\n",
|
"global tx_status queue =>\n",
|
||||||
wiphy_name(ar->hw->wiphy));
|
wiphy_name(ar->hw->wiphy));
|
||||||
|
|
||||||
ar9170_print_txheader(ar, skb);
|
ar9170_print_txheader(ar, skb);
|
||||||
#endif /* AR9170_QUEUE_DEBUG */
|
#endif /* AR9170_QUEUE_DEBUG */
|
||||||
skb_queue_tail(&ar->global_tx_status_waste, skb);
|
skb_queue_tail(&ar->global_tx_status, skb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
|
||||||
|
msecs_to_jiffies(100));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1571,7 +1506,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&ar->mutex);
|
mutex_lock(&ar->mutex);
|
||||||
if ((param) && !(queue > 4)) {
|
if ((param) && !(queue > ar->hw->queues)) {
|
||||||
memcpy(&ar->edcf[ar9170_qos_hwmap[queue]],
|
memcpy(&ar->edcf[ar9170_qos_hwmap[queue]],
|
||||||
param, sizeof(*param));
|
param, sizeof(*param));
|
||||||
|
|
||||||
|
@ -1635,7 +1570,7 @@ void *ar9170_alloc(size_t priv_size)
|
||||||
IEEE80211_HW_SIGNAL_DBM |
|
IEEE80211_HW_SIGNAL_DBM |
|
||||||
IEEE80211_HW_NOISE_DBM;
|
IEEE80211_HW_NOISE_DBM;
|
||||||
|
|
||||||
ar->hw->queues = 4;
|
ar->hw->queues = __AR9170_NUM_TXQ;
|
||||||
ar->hw->extra_tx_headroom = 8;
|
ar->hw->extra_tx_headroom = 8;
|
||||||
ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
|
ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue