@@ -123,13 +123,15 @@ struct device;
* enum ieee80211_max_queues - maximum number of queues
*
* @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
- * @IEEE80211_MAX_QUEUE_MAP: bitmap with maximum queues set
*/
enum ieee80211_max_queues {
- IEEE80211_MAX_QUEUES = 16,
- IEEE80211_MAX_QUEUE_MAP = BIT(IEEE80211_MAX_QUEUES) - 1,
+ IEEE80211_MAX_QUEUES = 65,
};
+/* bitmap with maximum queues set */
+#define IEEE80211_MAX_QUEUE_MAP_CNT 3
+extern unsigned long IEEE80211_MAX_QUEUE_MAP[IEEE80211_MAX_QUEUE_MAP_CNT];
+
#define IEEE80211_INVAL_HW_QUEUE 0xff
/**
@@ -789,7 +789,7 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local)
static inline void drv_flush(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- u32 queues, bool drop)
+ unsigned long *queues, bool drop)
{
struct ieee80211_vif *vif = sdata ? &sdata->vif : NULL;
@@ -798,9 +798,16 @@ static inline void drv_flush(struct ieee80211_local *local,
if (sdata && !check_sdata_in_driver(sdata))
return;
- trace_drv_flush(local, queues, drop);
+ trace_drv_flush(local, queues[0], drop);
+ /* NOTE: Only ath10k might want more queues than fits in 32-bits,
+ * and currently it pays no attention to the queues argument. So,
+ * just passing first value here is safe. If other drivers ever
+ * do need to see the array, then can create a flushA member
+ * and use it if it exists, falling back to old flush() for
+ * other drivers.
+ */
if (local->ops->flush)
- local->ops->flush(&local->hw, vif, queues, drop);
+ local->ops->flush(&local->hw, vif, queues[0], drop);
trace_drv_return_void(local);
}
@@ -1910,9 +1910,12 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr, bool ack, u16 tx_time);
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
- unsigned long queues,
+ unsigned long *queues,
enum queue_stop_reason reason,
bool refcounted);
+void ieee80211_get_vif_queues(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ unsigned long *queues);
void ieee80211_stop_vif_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum queue_stop_reason reason);
@@ -1920,7 +1923,7 @@ void ieee80211_wake_vif_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum queue_stop_reason reason);
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
- unsigned long queues,
+ unsigned long *queues,
enum queue_stop_reason reason,
bool refcounted);
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
@@ -1938,7 +1941,7 @@ void ieee80211_flush_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, bool drop);
void __ieee80211_flush_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int queues, bool drop);
+ unsigned long *queues, bool drop);
static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
{
@@ -3819,7 +3819,10 @@ int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid)
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
int ret;
- u32 queues;
+ unsigned long queues[IEEE80211_MAX_QUEUE_MAP_CNT] = { 0, 0, 0 };
+ int idx, bit;
+
+ ieee80211_get_vif_queues(local, sdata, queues);
lockdep_assert_held(&local->sta_mtx);
@@ -3860,7 +3863,9 @@ int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid)
AGG_STOP_LOCAL_REQUEST);
}
- queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]);
+ idx = sdata->vif.hw_queue[ieee802_1d_to_ac[tid]] / BITS_PER_LONG;
+ bit = sdata->vif.hw_queue[ieee802_1d_to_ac[tid]] - (idx * BITS_PER_LONG);
+ queues[idx] = 1L << bit;
__ieee80211_flush_queues(local, sdata, queues, false);
sta->reserved_tid = tid;
@@ -47,6 +47,9 @@ struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
}
EXPORT_SYMBOL(wiphy_to_ieee80211_hw);
+unsigned long IEEE80211_MAX_QUEUE_MAP[3] = { -1L, -1L, -1L };
+EXPORT_SYMBOL(IEEE80211_MAX_QUEUE_MAP);
+
/**
* ieee80211_check_disabled_rates: Calculate which rate-sets are disabled
* in all bands.
@@ -396,8 +399,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
trace_wake_queue(local, queue, reason);
- if (WARN_ON(queue >= hw->queues))
+ if (WARN_ON(queue >= hw->queues)) {
+ pr_err("wake-queue, queue: %d > hw->queues: %d\n",
+ queue, hw->queues);
return;
+ }
if (!test_bit(reason, &local->queue_stop_reasons[queue]))
return;
@@ -558,7 +564,7 @@ void ieee80211_add_pending_skbs(struct ieee80211_local *local,
}
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
- unsigned long queues,
+ unsigned long *queues,
enum queue_stop_reason reason,
bool refcounted)
{
@@ -568,7 +574,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- for_each_set_bit(i, &queues, hw->queues)
+ for_each_set_bit(i, queues, hw->queues)
__ieee80211_stop_queue(hw, i, reason, refcounted);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
@@ -600,7 +606,7 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
EXPORT_SYMBOL(ieee80211_queue_stopped);
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
- unsigned long queues,
+ unsigned long *queues,
enum queue_stop_reason reason,
bool refcounted)
{
@@ -610,7 +616,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- for_each_set_bit(i, &queues, hw->queues)
+ for_each_set_bit(i, queues, hw->queues)
__ieee80211_wake_queue(hw, i, reason, refcounted);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
@@ -624,42 +630,63 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(ieee80211_wake_queues);
-static unsigned int
+void
ieee80211_get_vif_queues(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
+ struct ieee80211_sub_if_data *sdata,
+ unsigned long *queues)
{
- unsigned int queues;
+ int idx;
+ memset(queues, 0, sizeof(IEEE80211_MAX_QUEUE_MAP));
if (sdata && ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
int ac;
- queues = 0;
-
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- queues |= BIT(sdata->vif.hw_queue[ac]);
- if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
- queues |= BIT(sdata->vif.cab_queue);
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ idx = sdata->vif.hw_queue[ac] / BITS_PER_LONG;
+ queues[idx] |= (1L << (sdata->vif.hw_queue[ac] - idx * BITS_PER_LONG));
+ }
+ if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE) {
+ idx = sdata->vif.cab_queue / BITS_PER_LONG;
+ queues[idx] |= (1L << (sdata->vif.cab_queue - idx * BITS_PER_LONG));
+ }
} else {
/* all queues */
- queues = BIT(local->hw.queues) - 1;
- }
+ int i;
- return queues;
+ for (i = 0; i<local->hw.queues; i++) {
+ idx = i / BITS_PER_LONG;
+ queues[idx] |= (1L << (i - idx * BITS_PER_LONG));
+ }
+ }
}
void __ieee80211_flush_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int queues, bool drop)
+ unsigned long *_queues, bool drop)
{
+ unsigned long queues[IEEE80211_MAX_QUEUE_MAP_CNT] = { 0, 0, 0 };
+ bool empty = true;
+ int i;
+
if (!local->ops->flush)
return;
+ if (_queues)
+ memcpy(queues, _queues, sizeof(queues));
+
+ for (i = 0; i<IEEE80211_MAX_QUEUE_MAP_CNT; i++) {
+ if (queues[i]) {
+ empty = false;
+ break;
+ }
+ }
+
/*
* If no queue was set, or if the HW doesn't support
* IEEE80211_HW_QUEUE_CONTROL - flush all queues
*/
- if (!queues || !ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
- queues = ieee80211_get_vif_queues(local, sdata);
+ if (empty || !ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
+ ieee80211_get_vif_queues(local, sdata, queues);
ieee80211_stop_queues_by_reason(&local->hw, queues,
IEEE80211_QUEUE_STOP_REASON_FLUSH,
@@ -682,8 +709,11 @@ void ieee80211_stop_vif_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum queue_stop_reason reason)
{
+ unsigned long queues[IEEE80211_MAX_QUEUE_MAP_CNT];
+
+ ieee80211_get_vif_queues(local, sdata, queues);
ieee80211_stop_queues_by_reason(&local->hw,
- ieee80211_get_vif_queues(local, sdata),
+ queues,
reason, true);
}
@@ -691,8 +721,11 @@ void ieee80211_wake_vif_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum queue_stop_reason reason)
{
+ unsigned long queues[IEEE80211_MAX_QUEUE_MAP_CNT];
+
+ ieee80211_get_vif_queues(local, sdata, queues);
ieee80211_wake_queues_by_reason(&local->hw,
- ieee80211_get_vif_queues(local, sdata),
+ queues,
reason, true);
}