This series applies on top of part 2 sent a couple days ago.
The main addition is support for mac80211 HW queues and further
optimizations for Tx in the multi-channel case.
Arik Nemtsov (11):
wlcore: remove support for injected Tx
wlcore: improve handling for Rx errors
wlcore: set 5Ghz probe-req template for DFS channels
wlcore/wl18xx: change priority calculations for links
wl18xx: limit Tx for the AP single-STA-in-PSM case
wlcore: use link count for single-STA-PSM optimization
wlcore: use separate HW queue for each AC in each vif
wlcore: don't take mutex before stopping queues
wlcore: consolidate Rx BA bitmap management to links struct
wl18xx: support MIMO only if HT mode is not forced to SISO
wl18xx: count HW block spare based correctly on keys
Eliad Peller (1):
wlcore: add ACX_PEER_CAP command
Eyal Shapira (2):
wlcore: increase scan dwell times if no activity
wlcore: support scan reports during periodic scan
Ido Reis (1):
wl12xx/wl18xx: update default fw logger's settings
Ido Yariv (1):
wlcore: Always pass DMA-able buffers to mmc functions
Igal Chernobelsky (1):
wlcore/wl18xx/wl12xx: FW log params per chip arch
Yair Shapira (3):
wlcore: add new plt power-mode: CHIP_AWAKE
wlcore: disable elp sleep while in plt mode
wl18xx: fix a bug in wl->num_rx_desc initialization
drivers/net/wireless/ti/wl12xx/event.c | 10 +-
drivers/net/wireless/ti/wl12xx/main.c | 82 +++++++++--
drivers/net/wireless/ti/wl12xx/wl12xx.h | 2 +
drivers/net/wireless/ti/wl18xx/acx.c | 54 ++++++++
drivers/net/wireless/ti/wl18xx/acx.h | 33 +++++
drivers/net/wireless/ti/wl18xx/event.c | 8 ++
drivers/net/wireless/ti/wl18xx/event.h | 1 +
drivers/net/wireless/ti/wl18xx/main.c | 138 ++++++++++++++-----
drivers/net/wireless/ti/wl18xx/scan.c | 56 ++++----
drivers/net/wireless/ti/wl18xx/scan.h | 20 ++-
drivers/net/wireless/ti/wl18xx/wl18xx.h | 48 ++++++-
drivers/net/wireless/ti/wlcore/acx.c | 2 +
drivers/net/wireless/ti/wlcore/cmd.c | 11 +-
drivers/net/wireless/ti/wlcore/conf.h | 20 ++-
drivers/net/wireless/ti/wlcore/debugfs.c | 1 -
drivers/net/wireless/ti/wlcore/event.c | 15 +-
drivers/net/wireless/ti/wlcore/event.h | 2 -
drivers/net/wireless/ti/wlcore/hw_ops.h | 41 ++++++
drivers/net/wireless/ti/wlcore/io.h | 14 +-
drivers/net/wireless/ti/wlcore/main.c | 212 ++++++++++++++++++++++-------
drivers/net/wireless/ti/wlcore/ps.c | 4 +
drivers/net/wireless/ti/wlcore/rx.c | 29 ++--
drivers/net/wireless/ti/wlcore/rx.h | 3 +-
drivers/net/wireless/ti/wlcore/scan.c | 32 ++++-
drivers/net/wireless/ti/wlcore/scan.h | 2 +-
drivers/net/wireless/ti/wlcore/testmode.c | 13 +-
drivers/net/wireless/ti/wlcore/tx.c | 158 +++++++++++----------
drivers/net/wireless/ti/wlcore/tx.h | 20 ++-
drivers/net/wireless/ti/wlcore/wlcore.h | 23 +++-
drivers/net/wireless/ti/wlcore/wlcore_i.h | 14 +-
30 files changed, 811 insertions(+), 257 deletions(-)
--
1.7.9.5
Don't use MIMO rates when HT mode is forced to SISO, even if we have
multiple antennas.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl18xx/main.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index ada4616..ed44ba6 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1109,7 +1109,13 @@ static bool wl18xx_is_mimo_supported(struct wl1271 *wl)
{
struct wl18xx_priv *priv = wl->priv;
- return priv->conf.phy.number_of_assembled_ant2_4 >= 2;
+ /*
+ * only support MIMO with multiple antennas, and when SISO
+ * is not forced through config
+ */
+ return (priv->conf.phy.number_of_assembled_ant2_4 >= 2) &&
+ (priv->conf.ht.mode != HT_MODE_WIDE) &&
+ (priv->conf.ht.mode != HT_MODE_SISO20);
}
/*
--
1.7.9.5
On Wed, 2012-11-28 at 21:12 +0200, Arik Nemtsov wrote:
> On Wed, Nov 28, 2012 at 8:25 PM, Luciano Coelho <[email protected]> wrote:
> > On Wed, 2012-11-28 at 19:46 +0200, Arik Nemtsov wrote:
> >> On Wed, Nov 28, 2012 at 4:34 PM, Luciano Coelho <[email protected]> wrote:
> >> > On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> >> >> From: Ido Reis <[email protected]>
> >> >>
> >> >> update the fw logger mode to continuous, and output to dbgpins (uart).
> >> >>
> >> >> Signed-off-by: Ido Reis <[email protected]>
> >> >> Signed-off-by: Arik Nemtsov <[email protected]>
> >> >> ---
> >> >
> >> > I think for upstream it's best to keep it as it was? Most people won't
> >> > have the debug pins and won't want to get them continuously. Sending to
> >> > the host and only on demand seems more reasonable to me.
> >>
> >> I think the default settings should be the ones the dev people are
> >> using. For production a customer can (and will) change this via a
> >> wlconf file.
> >
> > I disagree. What goes upstream is not for the developers, but for the
> > users. Developers can more easily change the wlconf file (they know
> > about it), end-users can just send us what we ask, without having to
> > mangle with wlconf.
>
> I think the users won't know what to do with this anyway without some
> guidance from TI during debugging, so this argument is pretty moot
> IMHO.
Yeah, no use to keep arguing.
> I guess we also differ in our point of view about this stuff. When I'm
> constantly working with an evolving driver, it helps to have the
> default tuned to my needs.
Your needs, so keep a patch in your tree. Or, the proper way, fine-tune
your wlconf binary file! :)
> >> I also know firsthand that the SDIO logger is pretty bad (misses
> >> logs). The only way to get decent logging is via the dbg pins.
> >
> > The dbg pins also miss logs sometimes, when they come too fast. For
> > "real life" (ie. mainline) we should assume that most users won't have a
> > board with dbg pins exposed.
> >
> > We can keep this patch in our internal tree.
>
> I'm for keeping as little stuff as possible in the internal tree.
I'm for avoiding patches changing this configuration all the time in the
mainline. In fact, this whole hardcoded wlconf struct was not supposed
to be there at all (did you notice that the driver prints out an *error*
if you don't have a proper wlconf file?).
--
Luca.
On Wed, Nov 28, 2012 at 4:34 PM, Luciano Coelho <[email protected]> wrote:
> On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
>> From: Ido Reis <[email protected]>
>>
>> update the fw logger mode to continuous, and output to dbgpins (uart).
>>
>> Signed-off-by: Ido Reis <[email protected]>
>> Signed-off-by: Arik Nemtsov <[email protected]>
>> ---
>
> I think for upstream it's best to keep it as it was? Most people won't
> have the debug pins and won't want to get them continuously. Sending to
> the host and only on demand seems more reasonable to me.
I think the default settings should be the ones the dev people are
using. For production a customer can (and will) change this via a
wlconf file.
I also know firsthand that the SDIO logger is pretty bad (misses
logs). The only way to get decent logging is via the dbg pins.
Arik
Start using the new hw_queue mechanism in mac80211 and give each AC in
each vif its own hw_queue number. This allows us to stop an AC in a vif
independently from other vifs.
Change the Tx watermark handling functions to count packets per AC in
vif. From now on fast links should not be able to hurt the throughput
of slow links on the same AC but on different vifs.
Change internal queue mgmt functions to operate per vif, to support the
new Tx watermark granularity. Make the global versions of the queue
stop/start functions to use the global mac80211 API for queue mgmt. This
helps in situations where the driver currently doesn't know all the vifs
that reside in mac80211. Recovery is a good example for such a case.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wlcore/main.c | 101 +++++++++++++++++++++++++--
drivers/net/wireless/ti/wlcore/tx.c | 107 +++++++++++++++++------------
drivers/net/wireless/ti/wlcore/tx.h | 15 ++--
drivers/net/wireless/ti/wlcore/wlcore.h | 3 +-
drivers/net/wireless/ti/wlcore/wlcore_i.h | 9 +++
5 files changed, 175 insertions(+), 60 deletions(-)
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index b0d0d6d..9d7f059 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1224,8 +1224,8 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
*/
if (hlid == WL12XX_INVALID_LINK_ID ||
(!test_bit(hlid, wlvif->links_map)) ||
- (wlcore_is_queue_stopped(wl, q) &&
- !wlcore_is_queue_stopped_by_reason(wl, q,
+ (wlcore_is_queue_stopped(wl, wlvif, q) &&
+ !wlcore_is_queue_stopped_by_reason(wl, wlvif, q,
WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
ieee80211_free_txskb(hw, skb);
@@ -1243,11 +1243,11 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK &&
- !wlcore_is_queue_stopped_by_reason(wl, q,
+ if (wlvif->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK &&
+ !wlcore_is_queue_stopped_by_reason(wl, wlvif, q,
WLCORE_QUEUE_STOP_REASON_WATERMARK)) {
wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
- wlcore_stop_queue_locked(wl, q,
+ wlcore_stop_queue_locked(wl, wlvif, q,
WLCORE_QUEUE_STOP_REASON_WATERMARK);
}
@@ -2314,6 +2314,81 @@ static void wl12xx_force_active_psm(struct wl1271 *wl)
}
}
+struct wlcore_hw_queue_iter_data {
+ unsigned long hw_queue_map[BITS_TO_LONGS(WLCORE_NUM_MAC_ADDRESSES)];
+ /* current vif */
+ struct ieee80211_vif *vif;
+ /* is the current vif among those iterated */
+ bool cur_running;
+};
+
+static void wlcore_hw_queue_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct wlcore_hw_queue_iter_data *iter_data = data;
+
+ if (WARN_ON(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE))
+ return;
+
+ if (iter_data->cur_running || vif == iter_data->vif) {
+ iter_data->cur_running = true;
+ return;
+ }
+
+ __set_bit(vif->hw_queue[0] / NUM_TX_QUEUES, iter_data->hw_queue_map);
+}
+
+static int wlcore_allocate_hw_queue_base(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif)
+{
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+ struct wlcore_hw_queue_iter_data iter_data = {};
+ int i, q_base;
+
+ iter_data.vif = vif;
+
+ /* mark all bits taken by active interfaces */
+ ieee80211_iterate_active_interfaces_atomic(wl->hw,
+ wlcore_hw_queue_iter,
+ &iter_data);
+
+ /* the current vif is already running in mac80211 (resume/recovery) */
+ if (iter_data.cur_running) {
+ wlvif->hw_queue_base = vif->hw_queue[0];
+ wl1271_debug(DEBUG_MAC80211,
+ "using pre-allocated hw queue base %d",
+ wlvif->hw_queue_base);
+
+ /* interface type might have changed type */
+ goto adjust_cab_queue;
+ }
+
+ q_base = find_first_zero_bit(iter_data.hw_queue_map,
+ WLCORE_NUM_MAC_ADDRESSES);
+ if (q_base >= WLCORE_NUM_MAC_ADDRESSES)
+ return -EBUSY;
+
+ wlvif->hw_queue_base = q_base * NUM_TX_QUEUES;
+ wl1271_debug(DEBUG_MAC80211, "allocating hw queue base: %d",
+ wlvif->hw_queue_base);
+
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ wl->queue_stop_reasons[wlvif->hw_queue_base + i] = 0;
+ /* register hw queues in mac80211 */
+ vif->hw_queue[i] = wlvif->hw_queue_base + i;
+ }
+
+adjust_cab_queue:
+ /* the last places are reserved for cab queues per interface */
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS)
+ vif->cab_queue = NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES +
+ wlvif->hw_queue_base / NUM_TX_QUEUES;
+ else
+ vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+
+ return 0;
+}
+
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -2365,6 +2440,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+ ret = wlcore_allocate_hw_queue_base(wl, wlvif);
+ if (ret < 0)
+ goto out;
+
if (wl12xx_need_fw_change(wl, vif_count, true)) {
wl12xx_force_active_psm(wl);
set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
@@ -5594,7 +5673,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_AP_LINK_PS |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
- IEEE80211_HW_SCAN_WHILE_IDLE;
+ IEEE80211_HW_SCAN_WHILE_IDLE |
+ IEEE80211_HW_QUEUE_CONTROL;
wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -5661,7 +5741,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&wl->bands[IEEE80211_BAND_5GHZ];
- wl->hw->queues = 4;
+ /*
+ * allow 4 queues per mac address we support +
+ * 1 cab queue per mac + one global offchannel Tx queue
+ */
+ wl->hw->queues = (NUM_TX_QUEUES + 1) * WLCORE_NUM_MAC_ADDRESSES + 1;
+
+ /* the last queue is the offchannel queue */
+ wl->hw->offchannel_tx_hw_queue = wl->hw->queues - 1;
wl->hw->max_rates = 1;
wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index d799fc9..dbc1721 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -447,14 +447,17 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
{
int i;
+ struct wl12xx_vif *wlvif;
- for (i = 0; i < NUM_TX_QUEUES; i++) {
- if (wlcore_is_queue_stopped_by_reason(wl, i,
- WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
- wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
- /* firmware buffer has space, restart queues */
- wlcore_wake_queue(wl, i,
- WLCORE_QUEUE_STOP_REASON_WATERMARK);
+ wl12xx_for_each_wlvif(wl, wlvif) {
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ if (wlcore_is_queue_stopped_by_reason(wl, wlvif, i,
+ WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
+ wlvif->tx_queue_count[i] <=
+ WL1271_TX_QUEUE_LOW_WATERMARK)
+ /* firmware buffer has space, restart queues */
+ wlcore_wake_queue(wl, wlvif, i,
+ WLCORE_QUEUE_STOP_REASON_WATERMARK);
}
}
}
@@ -1189,44 +1192,45 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
}
EXPORT_SYMBOL_GPL(wl1271_tx_min_rate_get);
-void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
- enum wlcore_queue_stop_reason reason)
+void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 queue, enum wlcore_queue_stop_reason reason)
{
- bool stopped = !!wl->queue_stop_reasons[queue];
+ int hwq = wlvif->hw_queue_base + wl1271_tx_get_mac80211_queue(queue);
+ bool stopped = !!wl->queue_stop_reasons[hwq];
/* queue should not be stopped for this reason */
- WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue]));
+ WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[hwq]));
if (stopped)
return;
- ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+ ieee80211_stop_queue(wl->hw, hwq);
}
-void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason)
{
unsigned long flags;
spin_lock_irqsave(&wl->wl_lock, flags);
- wlcore_stop_queue_locked(wl, queue, reason);
+ wlcore_stop_queue_locked(wl, wlvif, queue, reason);
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
-void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason)
{
unsigned long flags;
+ int hwq = wlvif->hw_queue_base + wl1271_tx_get_mac80211_queue(queue);
spin_lock_irqsave(&wl->wl_lock, flags);
-
/* queue should not be clear for this reason */
- WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue]));
+ WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[hwq]));
- if (wl->queue_stop_reasons[queue])
+ if (wl->queue_stop_reasons[hwq])
goto out;
- ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+ ieee80211_wake_queue(wl->hw, hwq);
out:
spin_unlock_irqrestore(&wl->wl_lock, flags);
@@ -1235,49 +1239,62 @@ out:
void wlcore_stop_queues(struct wl1271 *wl,
enum wlcore_queue_stop_reason reason)
{
- int i;
+ int i, q_base;
+ unsigned long flags;
- for (i = 0; i < NUM_TX_QUEUES; i++)
- wlcore_stop_queue(wl, i, reason);
-}
-EXPORT_SYMBOL_GPL(wlcore_stop_queues);
+ spin_lock_irqsave(&wl->wl_lock, flags);
-void wlcore_wake_queues(struct wl1271 *wl,
- enum wlcore_queue_stop_reason reason)
-{
- int i;
+ for (q_base = 0; q_base < WLCORE_NUM_MAC_ADDRESSES; q_base++)
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ int h = q_base * NUM_TX_QUEUES + i;
+ WARN_ON(test_and_set_bit(reason,
+ &wl->queue_stop_reasons[h]));
+ }
- for (i = 0; i < NUM_TX_QUEUES; i++)
- wlcore_wake_queue(wl, i, reason);
+ /*
+ * use the global version to make sure all vifs in mac80211 we don't
+ * know are stopped.
+ */
+ ieee80211_stop_queues(wl->hw);
+
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
}
-EXPORT_SYMBOL_GPL(wlcore_wake_queues);
-void wlcore_reset_stopped_queues(struct wl1271 *wl)
+void wlcore_wake_queues(struct wl1271 *wl,
+ enum wlcore_queue_stop_reason reason)
{
- int i;
+ int i, q_base;
unsigned long flags;
spin_lock_irqsave(&wl->wl_lock, flags);
- for (i = 0; i < NUM_TX_QUEUES; i++) {
- if (!wl->queue_stop_reasons[i])
- continue;
+ for (q_base = 0; q_base < WLCORE_NUM_MAC_ADDRESSES; q_base++)
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ int h = q_base * NUM_TX_QUEUES + i;
+ WARN_ON(!test_and_clear_bit(reason,
+ &wl->queue_stop_reasons[h]));
+ }
- wl->queue_stop_reasons[i] = 0;
- ieee80211_wake_queue(wl->hw,
- wl1271_tx_get_mac80211_queue(i));
- }
+ /*
+ * use the global version to make sure all vifs in mac80211 we don't
+ * know are woken up.
+ */
+ ieee80211_wake_queues(wl->hw);
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
-bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
- enum wlcore_queue_stop_reason reason)
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif, u8 queue,
+ enum wlcore_queue_stop_reason reason)
{
- return test_bit(reason, &wl->queue_stop_reasons[queue]);
+ int hwq = wlvif->hw_queue_base + wl1271_tx_get_mac80211_queue(queue);
+ return test_bit(reason, &wl->queue_stop_reasons[hwq]);
}
-bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue)
+bool wlcore_is_queue_stopped(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 queue)
{
- return !!wl->queue_stop_reasons[queue];
+ int hwq = wlvif->hw_queue_base + wl1271_tx_get_mac80211_queue(queue);
+ return !!wl->queue_stop_reasons[hwq];
}
diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h
index 349520d..3d854e5 100644
--- a/drivers/net/wireless/ti/wlcore/tx.h
+++ b/drivers/net/wireless/ti/wlcore/tx.h
@@ -252,20 +252,21 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length);
void wl1271_free_tx_id(struct wl1271 *wl, int id);
-void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
- enum wlcore_queue_stop_reason reason);
-void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 queue, enum wlcore_queue_stop_reason reason);
+void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason);
-void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason);
void wlcore_stop_queues(struct wl1271 *wl,
enum wlcore_queue_stop_reason reason);
void wlcore_wake_queues(struct wl1271 *wl,
enum wlcore_queue_stop_reason reason);
-void wlcore_reset_stopped_queues(struct wl1271 *wl);
-bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason);
-bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue);
+bool wlcore_is_queue_stopped(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 queue);
/* from main.c */
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 81c14ce..8877d73 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -256,7 +256,8 @@ struct wl1271 {
/* Frames scheduled for transmission, not handled yet */
int tx_queue_count[NUM_TX_QUEUES];
- unsigned long queue_stop_reasons[NUM_TX_QUEUES];
+ unsigned long queue_stop_reasons[
+ NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES];
/* Frames received, not handled yet by mac80211 */
struct sk_buff_head deferred_rx_queue;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index 41a58ff..99b19e2 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -442,6 +442,15 @@ struct wl12xx_vif {
int inconn_count;
/*
+ * This vif's queues are mapped to mac80211 HW queues as:
+ * VO - hw_queue_base
+ * VI - hw_queue_base + 1
+ * BE - hw_queue_base + 2
+ * BK - hw_queue_base + 3
+ */
+ int hw_queue_base;
+
+ /*
* This struct must be last!
* data that has to be saved acrossed reconfigs (e.g. recovery)
* should be declared in this struct.
--
1.7.9.5
Update the 18xx FW status private part to include Tx related link
priorities. Introduce new HW ops to determine link priority per chip
family.
For 18xx the changes are:
- Suspended links are at most low priority and Tx for them is stopped
beyond the suspend threshold.
- Active links now get their thresholds directly from FW
- There's a new "stop" threshold for active links, at which point a link
stops receiving new packets.
Update the min 18xx FW version required to make sure suspended links
bitmap is advertised by the FW.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl12xx/main.c | 22 ++++++++++++++++
drivers/net/wireless/ti/wl18xx/main.c | 41 ++++++++++++++++++++++++++++
drivers/net/wireless/ti/wl18xx/wl18xx.h | 44 ++++++++++++++++++++++++++++++-
drivers/net/wireless/ti/wlcore/hw_ops.h | 19 +++++++++++++
drivers/net/wireless/ti/wlcore/tx.c | 18 +++----------
drivers/net/wireless/ti/wlcore/wlcore.h | 4 +++
6 files changed, 132 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index a03a847..be26d35 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -1642,6 +1642,26 @@ static u32 wl12xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
return hwaddr << 5;
}
+static bool wl12xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ u8 thold;
+
+ if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
+ thold = wl->conf.tx.fast_link_thold;
+ else
+ thold = wl->conf.tx.slow_link_thold;
+
+ return lnk->allocated_pkts < thold;
+}
+
+static bool wl12xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ /* any link is good for low priority */
+ return true;
+}
+
static int wl12xx_setup(struct wl1271 *wl);
static struct wlcore_ops wl12xx_ops = {
@@ -1680,6 +1700,8 @@ static struct wlcore_ops wl12xx_ops = {
.pre_pkt_send = NULL,
.set_peer_cap = wl12xx_set_peer_cap,
.convert_hwaddr = wl12xx_convert_hwaddr,
+ .lnk_high_prio = wl12xx_lnk_high_prio,
+ .lnk_low_prio = wl12xx_lnk_low_prio,
};
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index dc73f8a..3836dbd 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1433,6 +1433,45 @@ static u32 wl18xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
return hwaddr & ~0x80000000;
}
+static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ u8 thold;
+ struct wl18xx_fw_status_priv *status_priv =
+ (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+ u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+
+ /* suspended links are never high priority */
+ if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
+ return false;
+
+ /* the priority thresholds are taken from FW */
+ if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
+ thold = status_priv->tx_fast_link_prio_threshold;
+ else
+ thold = status_priv->tx_slow_link_prio_threshold;
+
+ return lnk->allocated_pkts < thold;
+}
+
+static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ u8 thold;
+ struct wl18xx_fw_status_priv *status_priv =
+ (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+ u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+
+ if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
+ thold = status_priv->tx_suspend_threshold;
+ else if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
+ thold = status_priv->tx_fast_stop_threshold;
+ else
+ thold = status_priv->tx_slow_stop_threshold;
+
+ return lnk->allocated_pkts < thold;
+}
+
static int wl18xx_setup(struct wl1271 *wl);
static struct wlcore_ops wl18xx_ops = {
@@ -1471,6 +1510,8 @@ static struct wlcore_ops wl18xx_ops = {
.sta_rc_update = wl18xx_sta_rc_update,
.set_peer_cap = wl18xx_set_peer_cap,
.convert_hwaddr = wl18xx_convert_hwaddr,
+ .lnk_high_prio = wl18xx_lnk_high_prio,
+ .lnk_low_prio = wl18xx_lnk_low_prio,
};
/* HT cap appropriate for wide channels in 2Ghz */
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index 4d295a5..53bae22 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -68,7 +68,49 @@ struct wl18xx_fw_status_priv {
*/
u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC];
- u8 padding[2];
+ /*
+ * A bitmap representing the currently suspended links. The suspend
+ * is short lived, for multi-channel Tx requirements.
+ */
+ __le32 link_suspend_bitmap;
+
+ /*
+ * packet threshold for an "almost empty" AC,
+ * for Tx schedulng purposes
+ */
+ u8 tx_ac_threshold;
+
+ /* number of packets to queue up for a link in PS */
+ u8 tx_ps_threshold;
+
+ /* number of packet to queue up for a suspended link */
+ u8 tx_suspend_threshold;
+
+ /*
+ * Should have less than this number of packets in queue of a slow
+ * link to qualify as high priority link
+ */
+ u8 tx_slow_link_prio_threshold;
+
+ /*
+ * Should have less than this number of packets in queue of a fast
+ * link to qualify as high priority link
+ */
+ u8 tx_fast_link_prio_threshold;
+
+ /*
+ * Should have less than this number of packets in queue of a slow
+ * link before we stop queuing up packets for it.
+ */
+ u8 tx_slow_stop_threshold;
+
+ /*
+ * Should have less than this number of packets in queue of a fast
+ * link before we stop queuing up packets for it.
+ */
+ u8 tx_fast_stop_threshold;
+
+ u8 padding[3];
};
#define WL18XX_PHY_VERSION_MAX_LEN 20
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 802a345..58aa848 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -231,4 +231,23 @@ wlcore_hw_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
return wl->ops->convert_hwaddr(wl, hwaddr);
}
+static inline bool
+wlcore_hw_lnk_high_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ if (!wl->ops->lnk_high_prio)
+ BUG_ON(1);
+
+ return wl->ops->lnk_high_prio(wl, hlid, lnk);
+}
+
+static inline bool
+wlcore_hw_lnk_low_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ if (!wl->ops->lnk_low_prio)
+ BUG_ON(1);
+
+ return wl->ops->lnk_low_prio(wl, hlid, lnk);
+}
#endif
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index d34945a..3a56a87 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -504,28 +504,16 @@ static struct sk_buff *wlcore_lnk_dequeue(struct wl1271 *wl,
return skb;
}
-static bool wlcore_lnk_high_prio(struct wl1271 *wl, u8 hlid,
- struct wl1271_link *lnk)
-{
- u8 thold;
-
- if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
- thold = wl->conf.tx.fast_link_thold;
- else
- thold = wl->conf.tx.slow_link_thold;
-
- return lnk->allocated_pkts < thold;
-}
-
static struct sk_buff *wlcore_lnk_dequeue_high_prio(struct wl1271 *wl,
u8 hlid, u8 ac,
u8 *low_prio_hlid)
{
struct wl1271_link *lnk = &wl->links[hlid];
- if (!wlcore_lnk_high_prio(wl, hlid, lnk)) {
+ if (!wlcore_hw_lnk_high_prio(wl, hlid, lnk)) {
if (*low_prio_hlid == WL12XX_INVALID_LINK_ID &&
- !skb_queue_empty(&lnk->tx_queue[ac]))
+ !skb_queue_empty(&lnk->tx_queue[ac]) &&
+ wlcore_hw_lnk_low_prio(wl, hlid, lnk))
/* we found the first non-empty low priority queue */
*low_prio_hlid = hlid;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index f48f57a..cf0290a 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -111,6 +111,10 @@ struct wlcore_ops {
bool allow_ht_operation,
u32 rate_set, u8 hlid);
u32 (*convert_hwaddr)(struct wl1271 *wl, u32 hwaddr);
+ bool (*lnk_high_prio)(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk);
+ bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk);
};
enum wlcore_partitions {
--
1.7.9.5
On Wed, Nov 28, 2012 at 8:25 PM, Luciano Coelho <[email protected]> wrote:
> On Wed, 2012-11-28 at 19:46 +0200, Arik Nemtsov wrote:
>> On Wed, Nov 28, 2012 at 4:34 PM, Luciano Coelho <[email protected]> wrote:
>> > On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
>> >> From: Ido Reis <[email protected]>
>> >>
>> >> update the fw logger mode to continuous, and output to dbgpins (uart).
>> >>
>> >> Signed-off-by: Ido Reis <[email protected]>
>> >> Signed-off-by: Arik Nemtsov <[email protected]>
>> >> ---
>> >
>> > I think for upstream it's best to keep it as it was? Most people won't
>> > have the debug pins and won't want to get them continuously. Sending to
>> > the host and only on demand seems more reasonable to me.
>>
>> I think the default settings should be the ones the dev people are
>> using. For production a customer can (and will) change this via a
>> wlconf file.
>
> I disagree. What goes upstream is not for the developers, but for the
> users. Developers can more easily change the wlconf file (they know
> about it), end-users can just send us what we ask, without having to
> mangle with wlconf.
I think the users won't know what to do with this anyway without some
guidance from TI during debugging, so this argument is pretty moot
IMHO.
I guess we also differ in our point of view about this stuff. When I'm
constantly working with an evolving driver, it helps to have the
default tuned to my needs.
>
>
>> I also know firsthand that the SDIO logger is pretty bad (misses
>> logs). The only way to get decent logging is via the dbg pins.
>
> The dbg pins also miss logs sometimes, when they come too fast. For
> "real life" (ie. mainline) we should assume that most users won't have a
> board with dbg pins exposed.
>
> We can keep this patch in our internal tree.
I'm for keeping as little stuff as possible in the internal tree.
Treat a single connected STA in PSM as a slow link and regulate Tx speed
according to slow link priority/stop thresholds.
This allows us to avoid flooding the FW, while delivering decent
throughput to a peer in forced-PSM.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl18xx/main.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 3836dbd..ada4616 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1446,10 +1446,11 @@ static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
return false;
/* the priority thresholds are taken from FW */
- if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
- thold = status_priv->tx_fast_link_prio_threshold;
- else
+ if (!test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) ||
+ test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
thold = status_priv->tx_slow_link_prio_threshold;
+ else
+ thold = status_priv->tx_fast_link_prio_threshold;
return lnk->allocated_pkts < thold;
}
@@ -1464,10 +1465,11 @@ static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
thold = status_priv->tx_suspend_threshold;
- else if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
- thold = status_priv->tx_fast_stop_threshold;
- else
+ else if (!test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) ||
+ test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
thold = status_priv->tx_slow_stop_threshold;
+ else
+ thold = status_priv->tx_fast_stop_threshold;
return lnk->allocated_pkts < thold;
}
--
1.7.9.5
From: Yair Shapira <[email protected]>
We now disable elp sleep during plt mode to allow normal operation of
plt tools such as calibrator.
Having elp_sleep enabled during plt mode is actually not required and
in fact it disrupt plt operations such as rx statistics etc...
This is based on wl12xx (R5) commit 5cf0fe31ab
Signed-off-by: Yair Shapira <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wlcore/ps.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index 9b7b6e2..db7d902 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -82,6 +82,10 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
struct wl12xx_vif *wlvif;
u32 timeout;
+ /* We do not enter elp sleep in PLT mode */
+ if (wl->plt)
+ return;
+
if (wl->sleep_auth != WL1271_PSM_ELP)
return;
--
1.7.9.5
From: Yair Shapira <[email protected]>
wl->num_rx_desc was mistakenly initialized with WL18XX_NUM_TX_DESCRIPTORS
but it should use WL18XX_NUM_RX_DESCRIPTORS instead.
This bug was passed unnoticed because currently both RX and TX descriptors
are initialized to the same value (32).
Signed-off-by: Yair Shapira <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl18xx/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 9685fc3..dc73f8a 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1538,7 +1538,7 @@ static int wl18xx_setup(struct wl1271 *wl)
wl->rtable = wl18xx_rtable;
wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
- wl->num_rx_desc = WL18XX_NUM_TX_DESCRIPTORS;
+ wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
wl->num_channels = 2;
wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
--
1.7.9.5
From: Igal Chernobelsky <[email protected]>
FW memory block size and FW log end marker parameters
are added to wl structure and are initialized per
chip architecture. convert_hwaddr hw operation is added
to convert chip dependent FW internal address.
Copy from FW log is also simplified to copy the entire
memory block as FW logger utility is repsponsible
for parsing of FW log content.
Signed-off-by: Igal Chernobelsky <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl12xx/main.c | 9 ++++++
drivers/net/wireless/ti/wl18xx/main.c | 9 ++++++
drivers/net/wireless/ti/wlcore/hw_ops.h | 9 ++++++
drivers/net/wireless/ti/wlcore/io.h | 4 +--
drivers/net/wireless/ti/wlcore/main.c | 44 ++++++++++++++++-------------
drivers/net/wireless/ti/wlcore/wlcore.h | 8 +++++-
drivers/net/wireless/ti/wlcore/wlcore_i.h | 2 --
7 files changed, 61 insertions(+), 24 deletions(-)
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index 951b88c..5e3c808 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -706,6 +706,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
goto out;
}
+ wl->fw_mem_block_size = 256;
+ wl->fwlog_end = 0x2000000;
+
/* common settings */
wl->scan_templ_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY;
wl->scan_templ_id_5 = CMD_TEMPL_APP_PROBE_REQ_5_LEGACY;
@@ -1632,6 +1635,11 @@ static int wl12xx_set_peer_cap(struct wl1271 *wl,
hlid);
}
+static u32 wl12xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
+{
+ return hwaddr << 5;
+}
+
static int wl12xx_setup(struct wl1271 *wl);
static struct wlcore_ops wl12xx_ops = {
@@ -1669,6 +1677,7 @@ static struct wlcore_ops wl12xx_ops = {
.channel_switch = wl12xx_cmd_channel_switch,
.pre_pkt_send = NULL,
.set_peer_cap = wl12xx_set_peer_cap,
+ .convert_hwaddr = wl12xx_convert_hwaddr,
};
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index df8de71..d806241 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -667,6 +667,9 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
goto out;
}
+ wl->fw_mem_block_size = 272;
+ wl->fwlog_end = 0x40000000;
+
wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
@@ -1423,6 +1426,11 @@ static int wl18xx_set_peer_cap(struct wl1271 *wl,
rate_set, hlid);
}
+static u32 wl18xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
+{
+ return hwaddr & ~0x80000000;
+}
+
static int wl18xx_setup(struct wl1271 *wl);
static struct wlcore_ops wl18xx_ops = {
@@ -1460,6 +1468,7 @@ static struct wlcore_ops wl18xx_ops = {
.pre_pkt_send = wl18xx_pre_pkt_send,
.sta_rc_update = wl18xx_sta_rc_update,
.set_peer_cap = wl18xx_set_peer_cap,
+ .convert_hwaddr = wl18xx_convert_hwaddr,
};
/* HT cap appropriate for wide channels in 2Ghz */
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 4db03e1..802a345 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -222,4 +222,13 @@ wlcore_hw_set_peer_cap(struct wl1271 *wl,
return 0;
}
+static inline u32
+wlcore_hw_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
+{
+ if (!wl->ops->convert_hwaddr)
+ BUG_ON(1);
+
+ return wl->ops->convert_hwaddr(wl, hwaddr);
+}
+
#endif
diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
index f48530f..5897747 100644
--- a/drivers/net/wireless/ti/wlcore/io.h
+++ b/drivers/net/wireless/ti/wlcore/io.h
@@ -165,8 +165,8 @@ static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr,
int physical;
int addr;
- /* Addresses are stored internally as addresses to 32 bytes blocks */
- addr = hwaddr << 5;
+ /* Convert from FW internal address which is chip arch dependent */
+ addr = wl->ops->convert_hwaddr(wl, hwaddr);
physical = wlcore_translate_addr(wl, addr);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 4ef7ea7..5e070ff 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -787,19 +787,10 @@ void wl12xx_queue_recovery_work(struct wl1271 *wl)
size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
{
- size_t len = 0;
-
- /* The FW log is a length-value list, find where the log end */
- while (len < maxlen) {
- if (memblock[len] == 0)
- break;
- if (len + memblock[len] + 1 > maxlen)
- break;
- len += memblock[len] + 1;
- }
+ size_t len;
/* Make sure we have enough room */
- len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
+ len = min(maxlen, (size_t)(PAGE_SIZE - wl->fwlog_size));
/* Fill the FW log file, consumed by the sysfs fwlog entry */
memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
@@ -808,10 +799,9 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
return len;
}
-#define WLCORE_FW_LOG_END 0x2000000
-
static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
{
+ struct wlcore_partition_set part, old_part;
u32 addr;
u32 offset;
u32 end_of_log;
@@ -824,7 +814,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
wl1271_info("Reading FW panic log");
- block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
+ block = kmalloc(wl->fw_mem_block_size, GFP_KERNEL);
if (!block)
return;
@@ -850,17 +840,31 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {
offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor);
- end_of_log = WLCORE_FW_LOG_END;
+ end_of_log = wl->fwlog_end;
} else {
offset = sizeof(addr);
end_of_log = addr;
}
+ old_part = wl->curr_part;
+ memset(&part, 0, sizeof(part));
+
/* Traverse the memory blocks linked list */
do {
- memset(block, 0, WL12XX_HW_BLOCK_SIZE);
- ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
- false);
+ part.mem.start = wlcore_hw_convert_hwaddr(wl, addr);
+ part.mem.size = PAGE_SIZE;
+
+ ret = wlcore_set_partition(wl, &part);
+ if (ret < 0) {
+ wl1271_error("%s: set_partition start=0x%X size=%d",
+ __func__, part.mem.start, part.mem.size);
+ goto out;
+ }
+
+ memset(block, 0, wl->fw_mem_block_size);
+ ret = wlcore_read_hwaddr(wl, addr, block,
+ wl->fw_mem_block_size, false);
+
if (ret < 0)
goto out;
@@ -871,8 +875,9 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
* on demand mode and is equal to 0x2000000 in continuous mode.
*/
addr = le32_to_cpup((__le32 *)block);
+
if (!wl12xx_copy_fwlog(wl, block + offset,
- WL12XX_HW_BLOCK_SIZE - offset))
+ wl->fw_mem_block_size - offset))
break;
} while (addr && (addr != end_of_log));
@@ -880,6 +885,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
out:
kfree(block);
+ wlcore_set_partition(wl, &old_part);
}
static void wlcore_print_recovery(struct wl1271 *wl)
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index ecdd5e6..f48f57a 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -110,7 +110,7 @@ struct wlcore_ops {
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
u32 rate_set, u8 hlid);
-
+ u32 (*convert_hwaddr)(struct wl1271 *wl, u32 hwaddr);
};
enum wlcore_partitions {
@@ -287,6 +287,12 @@ struct wl1271 {
/* Number of valid bytes in the FW log buffer */
ssize_t fwlog_size;
+ /* FW log end marker */
+ u32 fwlog_end;
+
+ /* FW memory block size */
+ u32 fw_mem_block_size;
+
/* Sysfs FW log entry readers wait queue */
wait_queue_head_t fwlog_waitq;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index a664662..a8647bd 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -523,6 +523,4 @@ void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
#define HW_HT_RATES_OFFSET 16
#define HW_MIMO_RATES_OFFSET 24
-#define WL12XX_HW_BLOCK_SIZE 256
-
#endif /* __WLCORE_I_H__ */
--
1.7.9.5
Even passive scans on DFS channels require us to send probe requests, so
configure the probe-req in this case.
Also use this opportunity to prevent the code from crashing in case no
SSIDs are sent from above. This will likely happen in the DFS case
introduced. Even a passive scan might need the probe request configured
because of DFS channels.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl18xx/scan.c | 52 ++++++++++++++++-----------------
1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
index daaebad..1df88d5 100644
--- a/drivers/net/wireless/ti/wl18xx/scan.c
+++ b/drivers/net/wireless/ti/wl18xx/scan.c
@@ -108,27 +108,27 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (cmd->active[0]) {
u8 band = IEEE80211_BAND_2GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
- cmd->role_id, band,
- req->ssids[0].ssid,
- req->ssids[0].ssid_len,
- req->ie,
- req->ie_len,
- false);
+ cmd->role_id, band,
+ req->ssids ? req->ssids[0].ssid : NULL,
+ req->ssids ? req->ssids[0].ssid_len : 0,
+ req->ie,
+ req->ie_len,
+ false);
if (ret < 0) {
wl1271_error("2.4GHz PROBE request template failed");
goto out;
}
}
- if (cmd->active[1]) {
+ if (cmd->active[1] || cmd->dfs) {
u8 band = IEEE80211_BAND_5GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
- cmd->role_id, band,
- req->ssids[0].ssid,
- req->ssids[0].ssid_len,
- req->ie,
- req->ie_len,
- false);
+ cmd->role_id, band,
+ req->ssids ? req->ssids[0].ssid : NULL,
+ req->ssids ? req->ssids[0].ssid_len : 0,
+ req->ie,
+ req->ie_len,
+ false);
if (ret < 0) {
wl1271_error("5GHz PROBE request template failed");
goto out;
@@ -230,27 +230,27 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
if (cmd->active[0]) {
u8 band = IEEE80211_BAND_2GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
- cmd->role_id, band,
- req->ssids[0].ssid,
- req->ssids[0].ssid_len,
- ies->ie[band],
- ies->len[band],
- true);
+ cmd->role_id, band,
+ req->ssids ? req->ssids[0].ssid : NULL,
+ req->ssids ? req->ssids[0].ssid_len : 0,
+ ies->ie[band],
+ ies->len[band],
+ true);
if (ret < 0) {
wl1271_error("2.4GHz PROBE request template failed");
goto out;
}
}
- if (cmd->active[1]) {
+ if (cmd->active[1] || cmd->dfs) {
u8 band = IEEE80211_BAND_5GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
- cmd->role_id, band,
- req->ssids[0].ssid,
- req->ssids[0].ssid_len,
- ies->ie[band],
- ies->len[band],
- true);
+ cmd->role_id, band,
+ req->ssids ? req->ssids[0].ssid : NULL,
+ req->ssids ? req->ssids[0].ssid_len : 0,
+ ies->ie[band],
+ ies->len[band],
+ true);
if (ret < 0) {
wl1271_error("5GHz PROBE request template failed");
goto out;
--
1.7.9.5
From: Ido Reis <[email protected]>
update the fw logger mode to continuous, and output to dbgpins (uart).
Signed-off-by: Ido Reis <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl12xx/main.c | 4 ++--
drivers/net/wireless/ti/wl18xx/main.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index 9ac042b..0218edd 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -331,11 +331,11 @@ static struct wlcore_conf wl12xx_conf = {
.always = 0,
},
.fwlog = {
- .mode = WL12XX_FWLOG_ON_DEMAND,
+ .mode = WL12XX_FWLOG_CONTINUOUS,
.mem_blocks = 2,
.severity = 0,
.timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
- .output = WL12XX_FWLOG_OUTPUT_HOST,
+ .output = WL12XX_FWLOG_OUTPUT_DBG_PINS,
.threshold = 0,
},
.rate = {
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 53f4ba8..3f9504c 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -453,11 +453,11 @@ static struct wlcore_conf wl18xx_conf = {
.always = 0,
},
.fwlog = {
- .mode = WL12XX_FWLOG_ON_DEMAND,
+ .mode = WL12XX_FWLOG_CONTINUOUS,
.mem_blocks = 2,
.severity = 0,
.timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
- .output = WL12XX_FWLOG_OUTPUT_HOST,
+ .output = WL12XX_FWLOG_OUTPUT_DBG_PINS,
.threshold = 0,
},
.rate = {
--
1.7.9.5
From: Eyal Shapira <[email protected]>
FW API changed and now PERIODIC_SCAN_REPORT_EVENT is sent
in case results were found at the end of each sched scan
cycle. Previous FW was missing that and broke sched scan.
This API change is available from 18xx FW 8.5.0.0.27
[Arik - move changes to 18xx specific files, align FW structures to
latest for scan command]
Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl12xx/event.c | 10 +++++++---
drivers/net/wireless/ti/wl18xx/event.c | 8 ++++++++
drivers/net/wireless/ti/wl18xx/event.h | 1 +
drivers/net/wireless/ti/wl18xx/main.c | 1 +
drivers/net/wireless/ti/wl18xx/scan.c | 4 ++++
drivers/net/wireless/ti/wl18xx/scan.h | 20 +++++++++++++++++---
drivers/net/wireless/ti/wlcore/event.c | 10 ----------
drivers/net/wireless/ti/wlcore/event.h | 2 --
drivers/net/wireless/ti/wlcore/scan.c | 3 ++-
drivers/net/wireless/ti/wlcore/scan.h | 2 +-
10 files changed, 41 insertions(+), 20 deletions(-)
diff --git a/drivers/net/wireless/ti/wl12xx/event.c b/drivers/net/wireless/ti/wl12xx/event.c
index 6437dac..6ac0ed7 100644
--- a/drivers/net/wireless/ti/wl12xx/event.c
+++ b/drivers/net/wireless/ti/wl12xx/event.c
@@ -64,9 +64,13 @@ int wl12xx_process_mailbox_events(struct wl1271 *wl)
wl12xx_scan_completed(wl, wl->scan_wlvif);
}
- if (vector & PERIODIC_SCAN_REPORT_EVENT_ID)
- wlcore_event_sched_scan_report(wl,
- mbox->scheduled_scan_status);
+ if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT,
+ "PERIODIC_SCAN_REPORT_EVENT (status 0x%0x)",
+ mbox->scheduled_scan_status);
+
+ wlcore_scan_sched_scan_results(wl);
+ }
if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID)
wlcore_event_sched_scan_completed(wl,
diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c
index 02ef5aa..c9199d7 100644
--- a/drivers/net/wireless/ti/wl18xx/event.c
+++ b/drivers/net/wireless/ti/wl18xx/event.c
@@ -61,6 +61,14 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl)
wl18xx_scan_completed(wl, wl->scan_wlvif);
}
+ if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT,
+ "PERIODIC_SCAN_REPORT_EVENT (results %d)",
+ mbox->number_of_sched_scan_results);
+
+ wlcore_scan_sched_scan_results(wl);
+ }
+
if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID)
wlcore_event_sched_scan_completed(wl, 1);
diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h
index b55fd31..398f3d2 100644
--- a/drivers/net/wireless/ti/wl18xx/event.h
+++ b/drivers/net/wireless/ti/wl18xx/event.h
@@ -37,6 +37,7 @@ enum {
BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(17),
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18),
DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19),
+ PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20),
};
struct wl18xx_event_mailbox {
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index ed44ba6..5529c4b 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -921,6 +921,7 @@ static int wl18xx_boot(struct wl1271 *wl)
SCAN_COMPLETE_EVENT_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PERIODIC_SCAN_COMPLETE_EVENT_ID |
+ PERIODIC_SCAN_REPORT_EVENT_ID |
DUMMY_PACKET_EVENT_ID |
PEER_REMOVE_COMPLETE_EVENT_ID |
BA_SESSION_RX_CONSTRAINT_EVENT_ID |
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
index 1df88d5..09d9445 100644
--- a/drivers/net/wireless/ti/wl18xx/scan.c
+++ b/drivers/net/wireless/ti/wl18xx/scan.c
@@ -227,6 +227,10 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
cmd->tag = WL1271_SCAN_DEFAULT_TAG;
+ /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
+ cmd->report_threshold = 1;
+ cmd->terminate_on_report = 0;
+
if (cmd->active[0]) {
u8 band = IEEE80211_BAND_2GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h
index 5eb8c7f..49d7d02 100644
--- a/drivers/net/wireless/ti/wl18xx/scan.h
+++ b/drivers/net/wireless/ti/wl18xx/scan.h
@@ -78,8 +78,7 @@ struct wl18xx_cmd_scan_params {
__le16 long_cycles_sec;
u8 short_cycles_count;
u8 total_cycles; /* 0 - infinite */
- u8 rate;
- u8 padding[1];
+ u8 padding[2];
union {
struct {
@@ -93,7 +92,22 @@ struct wl18xx_cmd_scan_params {
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */
u8 tag;
- u8 padding1[2];
+ u8 rate;
+
+ /*
+ * send SCAN_REPORT_EVENT in periodic scans after each cycle
+ * if number of results >= report_threshold. Must be 0 for
+ * non periodic scans
+ */
+ u8 report_threshold;
+
+ /*
+ * Should periodic scan stop after a report event was created.
+ * Must be 0 for non periodic scans.
+ */
+ u8 terminate_on_report;
+
+ u8 padding1[3];
} __packed;
struct wl18xx_cmd_scan_stop {
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 2776d95..70f289a 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -94,16 +94,6 @@ void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable)
}
EXPORT_SYMBOL_GPL(wlcore_event_soft_gemini_sense);
-void wlcore_event_sched_scan_report(struct wl1271 *wl,
- u8 status)
-{
- wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT (status 0x%0x)",
- status);
-
- wl1271_scan_sched_scan_results(wl);
-}
-EXPORT_SYMBOL_GPL(wlcore_event_sched_scan_report);
-
void wlcore_event_sched_scan_completed(struct wl1271 *wl,
u8 status)
{
diff --git a/drivers/net/wireless/ti/wlcore/event.h b/drivers/net/wireless/ti/wlcore/event.h
index b4353be..acc7a59 100644
--- a/drivers/net/wireless/ti/wlcore/event.h
+++ b/drivers/net/wireless/ti/wlcore/event.h
@@ -70,8 +70,6 @@ int wl1271_event_unmask(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable);
-void wlcore_event_sched_scan_report(struct wl1271 *wl,
- u8 status);
void wlcore_event_sched_scan_completed(struct wl1271 *wl,
u8 status);
void wlcore_event_ba_rx_constraint(struct wl1271 *wl,
diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c
index 2cbd5e8..c44a1c7 100644
--- a/drivers/net/wireless/ti/wlcore/scan.c
+++ b/drivers/net/wireless/ti/wlcore/scan.c
@@ -461,9 +461,10 @@ out:
}
EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list);
-void wl1271_scan_sched_scan_results(struct wl1271 *wl)
+void wlcore_scan_sched_scan_results(struct wl1271 *wl)
{
wl1271_debug(DEBUG_SCAN, "got periodic scan results");
ieee80211_sched_scan_results(wl->hw);
}
+EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_results);
diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h
index 9ae6065..a6ab24b 100644
--- a/drivers/net/wireless/ti/wlcore/scan.h
+++ b/drivers/net/wireless/ti/wlcore/scan.h
@@ -39,7 +39,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies);
int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl1271_scan_sched_scan_results(struct wl1271 *wl);
+void wlcore_scan_sched_scan_results(struct wl1271 *wl);
#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1
--
1.7.9.5
On Wed, 2012-11-28 at 19:46 +0200, Arik Nemtsov wrote:
> On Wed, Nov 28, 2012 at 4:34 PM, Luciano Coelho <[email protected]> wrote:
> > On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> >> From: Ido Reis <[email protected]>
> >>
> >> update the fw logger mode to continuous, and output to dbgpins (uart).
> >>
> >> Signed-off-by: Ido Reis <[email protected]>
> >> Signed-off-by: Arik Nemtsov <[email protected]>
> >> ---
> >
> > I think for upstream it's best to keep it as it was? Most people won't
> > have the debug pins and won't want to get them continuously. Sending to
> > the host and only on demand seems more reasonable to me.
>
> I think the default settings should be the ones the dev people are
> using. For production a customer can (and will) change this via a
> wlconf file.
I disagree. What goes upstream is not for the developers, but for the
users. Developers can more easily change the wlconf file (they know
about it), end-users can just send us what we ask, without having to
mangle with wlconf.
> I also know firsthand that the SDIO logger is pretty bad (misses
> logs). The only way to get decent logging is via the dbg pins.
The dbg pins also miss logs sometimes, when they come too fast. For
"real life" (ie. mainline) we should assume that most users won't have a
board with dbg pins exposed.
We can keep this patch in our internal tree.
--
Luca.
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> From: Ido Reis <[email protected]>
>
> update the fw logger mode to continuous, and output to dbgpins (uart).
>
> Signed-off-by: Ido Reis <[email protected]>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
I think for upstream it's best to keep it as it was? Most people won't
have the debug pins and won't want to get them continuously. Sending to
the host and only on demand seems more reasonable to me.
--
Luca.
Treat Rx error code as a bitmask. This allows sending MIC failures
when other error bit are on.
Align Rx descriptor status mask to the FW definition.
Ease debugging in case FW reports failure to decrypt on packets.
Discard corrupted packets early in Rx path to avoid reporting other
abnormalities with corrupted packets that also have other failure bytes on.
Namely - we don't want to get a MIC failure on a corrupted packet.
This is mandated by the WiFi specification - see
section 11.4.2.4.1 in 802.11-2012.
Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wlcore/rx.c | 29 ++++++++++++++---------------
drivers/net/wireless/ti/wlcore/rx.h | 3 +--
2 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c
index 4665b96..6791a1a 100644
--- a/drivers/net/wireless/ti/wlcore/rx.c
+++ b/drivers/net/wireless/ti/wlcore/rx.c
@@ -92,9 +92,10 @@ static void wl1271_rx_status(struct wl1271 *wl,
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
RX_FLAG_DECRYPTED;
- if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) {
+ if (unlikely(desc_err_code & WL1271_RX_DESC_MIC_FAIL)) {
status->flag |= RX_FLAG_MMIC_ERROR;
- wl1271_warning("Michael MIC error");
+ wl1271_warning("Michael MIC error. Desc: 0x%x",
+ desc_err_code);
}
}
@@ -112,7 +113,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
u8 *buf;
u8 beacon = 0;
u8 is_data = 0;
- u8 reserved = 0;
+ u8 reserved = 0, offset_to_data = 0;
u16 seq_num;
u32 pkt_data_len;
@@ -132,6 +133,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
if (rx_align == WLCORE_RX_BUF_UNALIGNED)
reserved = RX_BUF_ALIGN;
+ else if (rx_align == WLCORE_RX_BUF_PADDED)
+ offset_to_data = RX_BUF_ALIGN;
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) data;
@@ -143,19 +146,15 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return 0;
}
- switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
/* discard corrupted packets */
- case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
- case WL1271_RX_DESC_DECRYPT_FAIL:
- wl1271_warning("corrupted packet in RX with status: 0x%x",
- desc->status & WL1271_RX_DESC_STATUS_MASK);
- return -EINVAL;
- case WL1271_RX_DESC_SUCCESS:
- case WL1271_RX_DESC_MIC_FAIL:
- break;
- default:
- wl1271_error("invalid RX descriptor status: 0x%x",
- desc->status & WL1271_RX_DESC_STATUS_MASK);
+ if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) {
+ hdr = (void *)(data + sizeof(*desc) + offset_to_data);
+ wl1271_warning("corrupted packet in RX: status: 0x%x len: %d",
+ desc->status & WL1271_RX_DESC_STATUS_MASK,
+ pkt_data_len);
+ wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc),
+ min(pkt_data_len,
+ ieee80211_hdrlen(hdr->frame_control)));
return -EINVAL;
}
diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h
index 71eba18..3363f60 100644
--- a/drivers/net/wireless/ti/wlcore/rx.h
+++ b/drivers/net/wireless/ti/wlcore/rx.h
@@ -84,12 +84,11 @@
* Bits 3-5 - process_id tag (AP mode FW)
* Bits 6-7 - reserved
*/
-#define WL1271_RX_DESC_STATUS_MASK 0x03
+#define WL1271_RX_DESC_STATUS_MASK 0x07
#define WL1271_RX_DESC_SUCCESS 0x00
#define WL1271_RX_DESC_DECRYPT_FAIL 0x01
#define WL1271_RX_DESC_MIC_FAIL 0x02
-#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03
#define RX_MEM_BLOCK_MASK 0xFF
#define RX_BUF_SIZE_MASK 0xFFF00
--
1.7.9.5
From: Yair Shapira <[email protected]>
Under this mode the chip is powered on including sdio
but no FW is downloaded and run, interrupts are not enabled, etc...
This mode is intended to allow RTTT to bridge sdio as a transport
to the chip.
Driver only provides sdio access using the dev_mem debugfs file.
Some fixes done to the code that ensures that PLT mode and normal
driver power mode (ifconfig/add_interface) are mutually excluded.
Signed-off-by: Yair Shapira <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wlcore/main.c | 16 ++++++++++++----
drivers/net/wireless/ti/wlcore/testmode.c | 13 +++++++++++--
drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 +
3 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 6ad9fc5..37575d7 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1080,7 +1080,8 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
static const char* const PLT_MODE[] = {
"PLT_OFF",
"PLT_ON",
- "PLT_FEM_DETECT"
+ "PLT_FEM_DETECT",
+ "PLT_CHIP_AWAKE"
};
int ret;
@@ -1106,9 +1107,11 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
if (ret < 0)
goto power_off;
- ret = wl->ops->plt_init(wl);
- if (ret < 0)
- goto power_off;
+ if (plt_mode != PLT_CHIP_AWAKE) {
+ ret = wl->ops->plt_init(wl);
+ if (ret < 0)
+ goto power_off;
+ }
wl->state = WLCORE_STATE_ON;
wl1271_notice("firmware booted in PLT mode %s (%s)",
@@ -2320,6 +2323,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
u8 role_type;
bool booted = false;
+ if (wl->plt) {
+ wl1271_error("Adding Interface not allowed while in PLT mode");
+ return -EBUSY;
+ }
+
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c
index f344276..7f71d12 100644
--- a/drivers/net/wireless/ti/wlcore/testmode.c
+++ b/drivers/net/wireless/ti/wlcore/testmode.c
@@ -297,7 +297,8 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
ret = wl1271_plt_stop(wl);
break;
case PLT_ON:
- ret = wl1271_plt_start(wl, PLT_ON);
+ case PLT_CHIP_AWAKE:
+ ret = wl1271_plt_start(wl, val);
break;
case PLT_FEM_DETECT:
ret = wl1271_tm_detect_fem(wl, tb);
@@ -360,6 +361,7 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
{
struct wl1271 *wl = hw->priv;
struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
+ u32 nla_cmd;
int err;
err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
@@ -369,7 +371,14 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
if (!tb[WL1271_TM_ATTR_CMD_ID])
return -EINVAL;
- switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
+ nla_cmd = nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID]);
+
+ /* Only SET_PLT_MODE is allowed in case of mode PLT_CHIP_AWAKE */
+ if (wl->plt_mode == PLT_CHIP_AWAKE &&
+ nla_cmd != WL1271_TM_CMD_SET_PLT_MODE)
+ return -EOPNOTSUPP;
+
+ switch (nla_cmd) {
case WL1271_TM_CMD_TEST:
return wl1271_tm_cmd_test(wl, tb);
case WL1271_TM_CMD_INTERROGATE:
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index ba59879..41a58ff 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -306,6 +306,7 @@ enum plt_mode {
PLT_OFF = 0,
PLT_ON = 1,
PLT_FEM_DETECT = 2,
+ PLT_CHIP_AWAKE = 3
};
struct wl12xx_rx_filter_field {
--
1.7.9.5
Protect all functions touching queue_stop_reasons by spin-lock, since
they are accessed by op_tx. Now there's no need to take the mutex
before caling wlcore_queue_xxx functions.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wlcore/main.c | 9 +++------
drivers/net/wireless/ti/wlcore/tx.c | 21 ++++++++++++++++++++-
drivers/net/wireless/ti/wlcore/tx.h | 9 +++++++--
3 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 9d7f059..3ffbba3 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1224,8 +1224,8 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
*/
if (hlid == WL12XX_INVALID_LINK_ID ||
(!test_bit(hlid, wlvif->links_map)) ||
- (wlcore_is_queue_stopped(wl, wlvif, q) &&
- !wlcore_is_queue_stopped_by_reason(wl, wlvif, q,
+ (wlcore_is_queue_stopped_locked(wl, wlvif, q) &&
+ !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
ieee80211_free_txskb(hw, skb);
@@ -1244,7 +1244,7 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
* the queue here, otherwise the queue will get too long.
*/
if (wlvif->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK &&
- !wlcore_is_queue_stopped_by_reason(wl, wlvif, q,
+ !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
WLCORE_QUEUE_STOP_REASON_WATERMARK)) {
wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
wlcore_stop_queue_locked(wl, wlvif, q,
@@ -3258,10 +3258,7 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* stop the queues and flush to ensure the next packets are
* in sync with FW spare block accounting
*/
- mutex_lock(&wl->mutex);
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
- mutex_unlock(&wl->mutex);
-
wl1271_tx_flush(wl);
}
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index dbc1721..bbfa14a 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -1288,13 +1288,32 @@ bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl,
struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason)
{
+ unsigned long flags;
+ bool stopped;
+
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ stopped = wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, queue,
+ reason);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ return stopped;
+}
+
+bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif, u8 queue,
+ enum wlcore_queue_stop_reason reason)
+{
int hwq = wlvif->hw_queue_base + wl1271_tx_get_mac80211_queue(queue);
+
+ WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
return test_bit(reason, &wl->queue_stop_reasons[hwq]);
}
-bool wlcore_is_queue_stopped(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 queue)
{
int hwq = wlvif->hw_queue_base + wl1271_tx_get_mac80211_queue(queue);
+
+ WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
return !!wl->queue_stop_reasons[hwq];
}
diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h
index 3d854e5..cb19c24 100644
--- a/drivers/net/wireless/ti/wlcore/tx.h
+++ b/drivers/net/wireless/ti/wlcore/tx.h
@@ -265,8 +265,13 @@ void wlcore_wake_queues(struct wl1271 *wl,
bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl,
struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason);
-bool wlcore_is_queue_stopped(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- u8 queue);
+bool
+wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ u8 queue,
+ enum wlcore_queue_stop_reason reason);
+bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 queue);
/* from main.c */
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
--
1.7.9.5
Only allow a PSM STA to congest FW memory when it is the single active
link. Being a single STA doesn't imply a single link - there might be
other links on other roles.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wlcore/cmd.c | 4 ++++
drivers/net/wireless/ti/wlcore/main.c | 12 +++++++-----
drivers/net/wireless/ti/wlcore/tx.c | 10 +++++-----
drivers/net/wireless/ti/wlcore/wlcore.h | 3 +++
4 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 1fbee0d..28a3027 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -328,6 +328,8 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl->fw_status_2->counters.tx_lnk_free_pkts[link];
wl->links[link].wlvif = wlvif;
*hlid = link;
+
+ wl->active_link_count++;
return 0;
}
@@ -357,6 +359,8 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl->links[*hlid].wlvif = NULL;
*hlid = WL12XX_INVALID_LINK_ID;
+ wl->active_link_count--;
+ WARN_ON(wl->active_link_count < 0);
}
static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 37575d7..b0d0d6d 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -349,10 +349,10 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
u8 hlid, u8 tx_pkts)
{
- bool fw_ps, single_sta;
+ bool fw_ps, single_link;
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
- single_sta = (wl->active_sta_count == 1);
+ single_link = (wl->active_link_count == 1);
/*
* Wake up from high level PS if the STA is asleep with too little
@@ -363,10 +363,10 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
/*
* Start high-level PS if the STA is asleep with enough blocks in FW.
- * Make an exception if this is the only connected station. In this
- * case FW-memory congestion is not a problem.
+ * Make an exception if this is the only connected link. In this
+ * case FW-memory congestion is less of a problem.
*/
- else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ else if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
@@ -1914,6 +1914,7 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
memset(wl->roc_map, 0, sizeof(wl->roc_map));
memset(wl->session_ids, 0, sizeof(wl->session_ids));
wl->active_sta_count = 0;
+ wl->active_link_count = 0;
/* The system link is always allocated */
wl->links[WL12XX_SYSTEM_HLID].allocated_pkts = 0;
@@ -5758,6 +5759,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
wl->platform_quirks = 0;
wl->system_hlid = WL12XX_SYSTEM_HLID;
wl->active_sta_count = 0;
+ wl->active_link_count = 0;
wl->fwlog_size = 0;
init_waitqueue_head(&wl->fwlog_waitq);
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index 3a56a87..d799fc9 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -104,7 +104,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
u8 hlid)
{
- bool fw_ps, single_sta;
+ bool fw_ps, single_link;
u8 tx_pkts;
if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
@@ -112,15 +112,15 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
tx_pkts = wl->links[hlid].allocated_pkts;
- single_sta = (wl->active_sta_count == 1);
+ single_link = (wl->active_link_count == 1);
/*
* if in FW PS and there is enough data in FW we can put the link
* into high-level PS and clean out its TX queues.
- * Make an exception if this is the only connected station. In this
- * case FW-memory congestion is not a problem.
+ * Make an exception if this is the only connected link. In this
+ * case FW-memory congestion is less of a problem.
*/
- if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index cf0290a..81c14ce 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -376,6 +376,9 @@ struct wl1271 {
*/
struct wl1271_link links[WL12XX_MAX_LINKS];
+ /* number of currently active links */
+ int active_link_count;
+
/* Fast/slow links bitmap according to FW */
u32 fw_fast_lnk_map;
--
1.7.9.5
From: Ido Yariv <[email protected]>
Some of the mmc drivers initiate DMA transfers with buffers passed from
higher layers. This means that the driver shouldn't ever pass non
DMA-able buffers, such as ones that are unaligned, allocated on the
stack or static.
Fix a couple of calls to the mmc layer in which buffers which weren't
necessarily DMA-able were passed.
Signed-off-by: Ido Yariv <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl12xx/main.c | 31 +++++++++++++++++++++++++------
drivers/net/wireless/ti/wl12xx/wl12xx.h | 2 ++
drivers/net/wireless/ti/wlcore/io.h | 10 ++++------
drivers/net/wireless/ti/wlcore/main.c | 10 ++++++++++
drivers/net/wireless/ti/wlcore/wlcore.h | 2 +-
5 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index be26d35..be1b792 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -613,7 +613,7 @@ static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
if (wl->chip.id != CHIP_ID_1283_PG20) {
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
- struct wl127x_rx_mem_pool_addr rx_mem_addr;
+ struct wl12xx_priv *priv = wl->priv;
/*
* Choose the block we want to read
@@ -622,13 +622,13 @@ static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
*/
u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK;
- rx_mem_addr.addr = (mem_block << 8) +
+ priv->rx_mem_addr->addr = (mem_block << 8) +
le32_to_cpu(wl_mem_map->packet_memory_pool_start);
- rx_mem_addr.addr_extra = rx_mem_addr.addr + 4;
+ priv->rx_mem_addr->addr_extra = priv->rx_mem_addr->addr + 4;
- ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr,
- sizeof(rx_mem_addr), false);
+ ret = wlcore_write(wl, WL1271_SLV_REG_DATA, priv->rx_mem_addr,
+ sizeof(*priv->rx_mem_addr), false);
if (ret < 0)
return ret;
}
@@ -1778,6 +1778,10 @@ static int wl12xx_setup(struct wl1271 *wl)
wl1271_error("Invalid tcxo parameter %s", tcxo_param);
}
+ priv->rx_mem_addr = kmalloc(sizeof(*priv->rx_mem_addr), GFP_KERNEL);
+ if (!priv->rx_mem_addr)
+ return -ENOMEM;
+
return 0;
}
@@ -1811,6 +1815,21 @@ out:
return ret;
}
+static int __devexit wl12xx_remove(struct platform_device *pdev)
+{
+ struct wl1271 *wl = platform_get_drvdata(pdev);
+ struct wl12xx_priv *priv;
+
+ if (!wl)
+ goto out;
+ priv = wl->priv;
+
+ kfree(priv->rx_mem_addr);
+
+out:
+ return wlcore_remove(pdev);
+}
+
static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
{ "wl12xx", 0 },
{ } /* Terminating Entry */
@@ -1819,7 +1838,7 @@ MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
static struct platform_driver wl12xx_driver = {
.probe = wl12xx_probe,
- .remove = __devexit_p(wlcore_remove),
+ .remove = __devexit_p(wl12xx_remove),
.id_table = wl12xx_id_table,
.driver = {
.name = "wl12xx_driver",
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h
index b542bfd..9bb60de 100644
--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
@@ -55,6 +55,8 @@ struct wl12xx_priv {
int ref_clock;
int tcxo_clock;
+
+ struct wl127x_rx_mem_pool_addr *rx_mem_addr;
};
#endif /* __WL12XX_PRIV_H__ */
diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
index 5897747..70f9bdc 100644
--- a/drivers/net/wireless/ti/wlcore/io.h
+++ b/drivers/net/wireless/ti/wlcore/io.h
@@ -105,13 +105,12 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
{
int ret;
- ret = wlcore_raw_read(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
+ ret = wlcore_raw_read(wl, addr, wl->buffer_32, sizeof(u32), false);
if (ret < 0)
return ret;
if (val)
- *val = le32_to_cpu(wl->buffer_32);
+ *val = le32_to_cpu(*wl->buffer_32);
return 0;
}
@@ -119,9 +118,8 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr,
u32 val)
{
- wl->buffer_32 = cpu_to_le32(val);
- return wlcore_raw_write(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
+ *wl->buffer_32 = cpu_to_le32(val);
+ return wlcore_raw_write(wl, addr, wl->buffer_32, sizeof(u32), false);
}
static inline int __must_check wlcore_read(struct wl1271 *wl, int addr,
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 1793a82..e4ff66a 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -5890,8 +5890,17 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
goto err_fwlog;
}
+ wl->buffer_32 = kmalloc(sizeof(u32), GFP_KERNEL);
+ if (!wl->buffer_32) {
+ ret = -ENOMEM;
+ goto err_mbox;
+ }
+
return hw;
+err_mbox:
+ kfree(wl->mbox);
+
err_fwlog:
free_page((unsigned long)wl->fwlog);
@@ -5930,6 +5939,7 @@ int wlcore_free_hw(struct wl1271 *wl)
device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
+ kfree(wl->buffer_32);
kfree(wl->mbox);
free_page((unsigned long)wl->fwlog);
dev_kfree_skb(wl->dummy_packet);
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 8877d73..6e49105 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -341,7 +341,7 @@ struct wl1271 {
struct wl1271_stats stats;
- __le32 buffer_32;
+ __le32 *buffer_32;
u32 buffer_cmd;
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
--
1.7.9.5
From: Eliad Peller <[email protected]>
ACX_PEER_CAP command is just ACX_PEER_HT_CAP, but allows
configuring the peer's support rates as well.
this is needed because we start the station role when
the remote rates are not known yet.
the two commands should be unified in future fw versions,
but for now add a new set_peer_cap per-hw op, that will
use ACX_PEER_CAP for 18xx, and ACX_PEER_HT_CAP for 12xx.
Signed-off-by: Eliad Peller <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl12xx/main.c | 10 ++++++
drivers/net/wireless/ti/wl18xx/acx.c | 54 +++++++++++++++++++++++++++++++
drivers/net/wireless/ti/wl18xx/acx.h | 33 +++++++++++++++++++
drivers/net/wireless/ti/wl18xx/main.c | 9 ++++++
drivers/net/wireless/ti/wlcore/acx.c | 2 ++
drivers/net/wireless/ti/wlcore/cmd.c | 7 ++--
drivers/net/wireless/ti/wlcore/hw_ops.h | 13 ++++++++
drivers/net/wireless/ti/wlcore/main.c | 9 +++---
drivers/net/wireless/ti/wlcore/wlcore.h | 5 +++
9 files changed, 134 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index 0218edd..951b88c 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -1623,6 +1623,15 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
return wlcore_set_key(wl, cmd, vif, sta, key_conf);
}
+static int wl12xx_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid)
+{
+ return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation,
+ hlid);
+}
+
static int wl12xx_setup(struct wl1271 *wl);
static struct wlcore_ops wl12xx_ops = {
@@ -1659,6 +1668,7 @@ static struct wlcore_ops wl12xx_ops = {
.set_key = wl12xx_set_key,
.channel_switch = wl12xx_cmd_channel_switch,
.pre_pkt_send = NULL,
+ .set_peer_cap = wl12xx_set_peer_cap,
};
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
index 801d8af..a169bb5 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.c
+++ b/drivers/net/wireless/ti/wl18xx/acx.c
@@ -140,3 +140,57 @@ out:
return ret;
}
+
+/*
+ * this command is basically the same as wl1271_acx_ht_capabilities,
+ * with the addition of supported rates. they should be unified in
+ * the next fw api change
+ */
+int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid)
+{
+ struct wlcore_acx_peer_cap *acx;
+ int ret = 0;
+ u32 ht_capabilites = 0;
+
+ wl1271_debug(DEBUG_ACX,
+ "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x",
+ ht_cap->ht_supported, ht_cap->cap, rate_set);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (allow_ht_operation && ht_cap->ht_supported) {
+ /* no need to translate capabilities - use the spec values */
+ ht_capabilites = ht_cap->cap;
+
+ /*
+ * this bit is not employed by the spec but only by FW to
+ * indicate peer HT support
+ */
+ ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
+
+ /* get data from A-MPDU parameters field */
+ acx->ampdu_max_length = ht_cap->ampdu_factor;
+ acx->ampdu_min_spacing = ht_cap->ampdu_density;
+ }
+
+ acx->hlid = hlid;
+ acx->ht_capabilites = cpu_to_le32(ht_capabilites);
+ acx->supported_rates = cpu_to_le32(rate_set);
+
+ ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx ht capabilities setting failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
index b57e348..0e636de 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.h
+++ b/drivers/net/wireless/ti/wl18xx/acx.h
@@ -297,11 +297,44 @@ struct wlcore_peer_ht_operation_mode {
u8 padding[2];
};
+/*
+ * ACX_PEER_CAP
+ * this struct is very similar to wl1271_acx_ht_capabilities, with the
+ * addition of supported rates
+ */
+struct wlcore_acx_peer_cap {
+ struct acx_header header;
+
+ /* bitmask of capability bits supported by the peer */
+ __le32 ht_capabilites;
+
+ /* rates supported by the remote peer */
+ __le32 supported_rates;
+
+ /* Indicates to which link these capabilities apply. */
+ u8 hlid;
+
+ /*
+ * This the maximum A-MPDU length supported by the AP. The FW may not
+ * exceed this length when sending A-MPDUs
+ */
+ u8 ampdu_max_length;
+
+ /* This is the minimal spacing required when sending A-MPDUs to the AP*/
+ u8 ampdu_min_spacing;
+
+ u8 padding;
+} __packed;
+
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
u32 len_field_size);
int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
int wl18xx_acx_clear_statistics(struct wl1271 *wl);
int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide);
+int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid);
#endif /* __WL18XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 3f9504c..df8de71 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1414,6 +1414,14 @@ out:
mutex_unlock(&wl->mutex);
}
+static int wl18xx_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid)
+{
+ return wl18xx_acx_set_peer_cap(wl, ht_cap, allow_ht_operation,
+ rate_set, hlid);
+}
static int wl18xx_setup(struct wl1271 *wl);
@@ -1451,6 +1459,7 @@ static struct wlcore_ops wl18xx_ops = {
.channel_switch = wl18xx_cmd_channel_switch,
.pre_pkt_send = wl18xx_pre_pkt_send,
.sta_rc_update = wl18xx_sta_rc_update,
+ .set_peer_cap = wl18xx_set_peer_cap,
};
/* HT cap appropriate for wide channels in 2Ghz */
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index 9c32f0c..c796543 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -1340,6 +1340,8 @@ out:
kfree(acx);
return ret;
}
+EXPORT_SYMBOL_GPL(wl1271_acx_set_ht_capabilities);
+
int wl1271_acx_set_ht_information(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 56432c8..1fbee0d 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -506,11 +506,10 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd->sta.hlid = wlvif->sta.hlid;
cmd->sta.session = wl->session_ids[wlvif->sta.hlid];
/*
- * We don't have the correct remote rates in this stage, and there
- * is no way to update them later, so use our supported rates instead.
- * The fw will take the configured rate policies into account anyway.
+ * We don't have the correct remote rates in this stage. the rates
+ * will be reconfigured later, after authorization.
*/
- cmd->sta.remote_rates = cpu_to_le32(supported_rates);
+ cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set);
wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
"basic_rate_set: 0x%x, remote_rates: 0x%x",
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 0e0b656..4db03e1 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -209,4 +209,17 @@ wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif,
wl->ops->sta_rc_update(wl, wlvif, sta, changed);
}
+static inline int
+wlcore_hw_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid)
+{
+ if (wl->ops->set_peer_cap)
+ return wl->ops->set_peer_cap(wl, ht_cap, allow_ht_operation,
+ rate_set, hlid);
+
+ return 0;
+}
+
#endif
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 3834e9d..4ef7ea7 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -4147,10 +4147,11 @@ sta_not_found:
bool enabled =
bss_conf->channel_type != NL80211_CHAN_NO_HT;
- ret = wl1271_acx_set_ht_capabilities(wl,
- &sta_ht_cap,
- enabled,
- wlvif->sta.hlid);
+ ret = wlcore_hw_set_peer_cap(wl,
+ &sta_ht_cap,
+ enabled,
+ wlvif->rate_set,
+ wlvif->sta.hlid);
if (ret < 0) {
wl1271_warning("Set ht cap failed %d", ret);
goto out;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 71137aa..ecdd5e6 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -106,6 +106,11 @@ struct wlcore_ops {
u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta, u32 changed);
+ int (*set_peer_cap)(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid);
+
};
enum wlcore_partitions {
--
1.7.9.5
Remove the STA specific ba_rx_bitmap field and use the common links
structure. This simplifies code setting/checking the BA bitmap.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wlcore/debugfs.c | 1 -
drivers/net/wireless/ti/wlcore/event.c | 5 +++--
drivers/net/wireless/ti/wlcore/main.c | 4 ++--
drivers/net/wireless/ti/wlcore/tx.c | 1 -
drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 -
5 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index f115fba..e70a7c8 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -560,7 +560,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
wlvif->bss_type == BSS_TYPE_IBSS) {
VIF_STATE_PRINT_INT(sta.hlid);
- VIF_STATE_PRINT_INT(sta.ba_rx_bitmap);
VIF_STATE_PRINT_INT(sta.basic_rate_idx);
VIF_STATE_PRINT_INT(sta.ap_rate_idx);
VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index cb32c02..2776d95 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -58,9 +58,10 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
- if (!wlvif->sta.ba_rx_bitmap)
+ u8 hlid = wlvif->sta.hlid;
+ if (!wl->links[hlid].ba_bitmap)
return;
- ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap,
+ ieee80211_stop_rx_ba_session(vif, wl->links[hlid].ba_bitmap,
vif->bss_conf.bssid);
} else {
u8 hlid;
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 3ffbba3..1793a82 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -4793,18 +4793,18 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
hlid = wlvif->sta.hlid;
- ba_bitmap = &wlvif->sta.ba_rx_bitmap;
} else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
struct wl1271_station *wl_sta;
wl_sta = (struct wl1271_station *)sta->drv_priv;
hlid = wl_sta->hlid;
- ba_bitmap = &wl->links[hlid].ba_bitmap;
} else {
ret = -EINVAL;
goto out;
}
+ ba_bitmap = &wl->links[hlid].ba_bitmap;
+
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index bbfa14a..07bd1f4 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -1061,7 +1061,6 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wl1271_free_sta(wl, wlvif, i);
} else {
u8 hlid = i;
- wlvif->sta.ba_rx_bitmap = 0;
wl12xx_free_link(wl, wlvif, &hlid);
}
}
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index 99b19e2..d9313a3 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -342,7 +342,6 @@ struct wl12xx_vif {
union {
struct {
u8 hlid;
- u8 ba_rx_bitmap;
u8 basic_rate_idx;
u8 ap_rate_idx;
--
1.7.9.5
Require each incoming packet to have a valid vif. The injected Tx code
path was buggy (and unused), so disallow it altogether.
Cleanup a few places and add a warning so we can better discover
anomalies (corrupted skbs?) masquerading as injected Tx.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wlcore/main.c | 13 ++++++++-----
drivers/net/wireless/ti/wlcore/tx.c | 5 +----
drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 +
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 5e070ff..6ad9fc5 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1200,9 +1200,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
int q, mapping;
u8 hlid;
- if (vif)
- wlvif = wl12xx_vif_to_data(vif);
+ if (!vif) {
+ wl1271_debug(DEBUG_TX, "DROP skb with no vif");
+ ieee80211_free_txskb(hw, skb);
+ return;
+ }
+ wlvif = wl12xx_vif_to_data(vif);
mapping = skb_get_queue_mapping(skb);
q = wl1271_tx_get_queue(mapping);
@@ -1216,7 +1220,7 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
* allow these packets through.
*/
if (hlid == WL12XX_INVALID_LINK_ID ||
- (wlvif && !test_bit(hlid, wlvif->links_map)) ||
+ (!test_bit(hlid, wlvif->links_map)) ||
(wlcore_is_queue_stopped(wl, q) &&
!wlcore_is_queue_stopped_by_reason(wl, q,
WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
@@ -1230,8 +1234,7 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
wl->tx_queue_count[q]++;
- if (wlvif)
- wlvif->tx_queue_count[q]++;
+ wlvif->tx_queue_count[q]++;
/*
* The workqueue is slow to process the tx_queue and we need stop
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index dd05fab..d34945a 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -157,9 +157,6 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
{
struct ieee80211_tx_info *control;
- if (!wlvif || wl12xx_is_dummy_packet(wl, skb))
- return wl->system_hlid;
-
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta);
@@ -759,7 +756,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl)
bool has_data = false;
wlvif = NULL;
- if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif)
+ if (!wl12xx_is_dummy_packet(wl, skb))
wlvif = wl12xx_vif_to_data(info->control.vif);
else
hlid = wl->system_hlid;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index a8647bd..ba59879 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -462,6 +462,7 @@ struct wl12xx_vif {
static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif)
{
+ WARN_ON(!vif);
return (struct wl12xx_vif *)vif->drv_priv;
}
--
1.7.9.5
From: Eyal Shapira <[email protected]>
There's a limit on scan dwell times of max 30ms in order
to avoid degrading voip traffic which could be going on
while scanning. However these dwell times increase the
chance of missing out on nearby APs leading to partial
scan results. Allow configuration of longer dwell times
in case there no active interface (i.e. no STA associated
or AP up).
[Arik - count started vifs using an in-driver function]
Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl12xx/main.c | 6 ++++--
drivers/net/wireless/ti/wl18xx/main.c | 6 ++++--
drivers/net/wireless/ti/wlcore/conf.h | 20 +++++++++++++++++++-
drivers/net/wireless/ti/wlcore/scan.c | 29 +++++++++++++++++++++++++++--
4 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index 5e3c808..a03a847 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -267,8 +267,10 @@ static struct wlcore_conf wl12xx_conf = {
.avg_weight_snr_data = 10,
},
.scan = {
- .min_dwell_time_active = 7500,
- .max_dwell_time_active = 30000,
+ .min_dwell_time_active_conc = 7500,
+ .max_dwell_time_active_conc = 30000,
+ .min_dwell_time_active = 25000,
+ .max_dwell_time_active = 50000,
.dwell_time_passive = 100000,
.dwell_time_dfs = 150000,
.num_probe_reqs = 2,
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index d806241..9685fc3 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -394,8 +394,10 @@ static struct wlcore_conf wl18xx_conf = {
.avg_weight_snr_data = 10,
},
.scan = {
- .min_dwell_time_active = 7500,
- .max_dwell_time_active = 30000,
+ .min_dwell_time_active_conc = 7500,
+ .max_dwell_time_active_conc = 30000,
+ .min_dwell_time_active = 25000,
+ .max_dwell_time_active = 50000,
.dwell_time_passive = 100000,
.dwell_time_dfs = 150000,
.num_probe_reqs = 2,
diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h
index ad15cae..a4eb14c 100644
--- a/drivers/net/wireless/ti/wlcore/conf.h
+++ b/drivers/net/wireless/ti/wlcore/conf.h
@@ -1097,6 +1097,24 @@ struct conf_scan_settings {
*/
u32 max_dwell_time_active;
+ /*
+ * The minimum time to wait on each channel for active scans
+ * when there's a concurrent active interface. This should
+ * lower than min_dwell_time_active usually in order to avoid
+ * interfering with possible voip traffic on another interface.
+ *
+ * Range: u32 tu/1000
+ */
+ u32 min_dwell_time_active_conc;
+
+ /*
+ * The maximum time to wait on each channel for active scans
+ * See explanation about min_dwell_time_active_conc
+ *
+ * Range: u32 tu/1000
+ */
+ u32 max_dwell_time_active_conc;
+
/* time to wait on the channel for passive scans (in TU/1000) */
u32 dwell_time_passive;
@@ -1322,7 +1340,7 @@ struct conf_recovery_settings {
* version, the two LSB are the lower driver's private conf
* version.
*/
-#define WLCORE_CONF_VERSION (0x0005 << 16)
+#define WLCORE_CONF_VERSION (0x0006 << 16)
#define WLCORE_CONF_MASK 0xffff0000
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
sizeof(struct wlcore_conf))
diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c
index 7f42f8a..2cbd5e8 100644
--- a/drivers/net/wireless/ti/wlcore/scan.c
+++ b/drivers/net/wireless/ti/wlcore/scan.c
@@ -89,6 +89,25 @@ out:
}
+static void wlcore_started_vifs_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ int *count = (int *)data;
+
+ if (!vif->bss_conf.idle)
+ (*count)++;
+}
+
+static int wlcore_count_started_vifs(struct wl1271 *wl)
+{
+ int count = 0;
+
+ ieee80211_iterate_active_interfaces_atomic(wl->hw,
+ wlcore_started_vifs_iter,
+ &count);
+ return count;
+}
+
static int
wlcore_scan_get_channels(struct wl1271 *wl,
struct ieee80211_channel *req_channels[],
@@ -109,9 +128,15 @@ wlcore_scan_get_channels(struct wl1271 *wl,
/* configure dwell times according to scan type */
if (scan_type == SCAN_TYPE_SEARCH) {
struct conf_scan_settings *c = &wl->conf.scan;
+ bool active_vif_exists = !!wlcore_count_started_vifs(wl);
+
+ min_dwell_time_active = active_vif_exists ?
+ c->min_dwell_time_active_conc :
+ c->min_dwell_time_active;
+ max_dwell_time_active = active_vif_exists ?
+ c->max_dwell_time_active_conc :
+ c->max_dwell_time_active;
- min_dwell_time_active = c->min_dwell_time_active;
- max_dwell_time_active = c->max_dwell_time_active;
dwell_time_passive = c->dwell_time_passive;
dwell_time_dfs = c->dwell_time_dfs;
} else {
--
1.7.9.5
We have no idea how many VIFs there are requiring a special spare, we
know just about the number of keys set. Rename the counter appropriately
and toggle it whenever a special key is added/removed.
Previously this was only changed once, since it was toggled whenever
the actual spare was changed.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/ti/wl18xx/main.c | 56 +++++++++++++++++--------------
drivers/net/wireless/ti/wl18xx/wl18xx.h | 4 +--
2 files changed, 33 insertions(+), 27 deletions(-)
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 5529c4b..e4fa3f9 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1052,7 +1052,7 @@ static int wl18xx_hw_init(struct wl1271 *wl)
/* (re)init private structures. Relevant on recovery as well. */
priv->last_fw_rls_idx = 0;
- priv->extra_spare_vif_count = 0;
+ priv->extra_spare_key_count = 0;
/* set the default amount of spare blocks in the bitmap */
ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE);
@@ -1317,8 +1317,8 @@ static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
{
struct wl18xx_priv *priv = wl->priv;
- /* If we have VIFs requiring extra spare, indulge them */
- if (priv->extra_spare_vif_count)
+ /* If we have keys requiring extra spare, indulge them */
+ if (priv->extra_spare_key_count)
return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
return WL18XX_TX_HW_BLOCK_SPARE;
@@ -1330,42 +1330,48 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
struct ieee80211_key_conf *key_conf)
{
struct wl18xx_priv *priv = wl->priv;
- bool change_spare = false;
+ bool change_spare = false, special_enc;
int ret;
+ wl1271_debug(DEBUG_CRYPT, "extra spare keys before: %d",
+ priv->extra_spare_key_count);
+
+ special_enc = key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
+ key_conf->cipher == WLAN_CIPHER_SUITE_TKIP;
+
+ ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
+ if (ret < 0)
+ goto out;
+
/*
- * when adding the first or removing the last GEM/TKIP interface,
+ * when adding the first or removing the last GEM/TKIP key,
* we have to adjust the number of spare blocks.
*/
- change_spare = (key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
- key_conf->cipher == WLAN_CIPHER_SUITE_TKIP) &&
- ((priv->extra_spare_vif_count == 0 && cmd == SET_KEY) ||
- (priv->extra_spare_vif_count == 1 && cmd == DISABLE_KEY));
+ if (special_enc) {
+ if (cmd == SET_KEY) {
+ /* first key */
+ change_spare = (priv->extra_spare_key_count == 0);
+ priv->extra_spare_key_count++;
+ } else if (cmd == DISABLE_KEY) {
+ /* last key */
+ change_spare = (priv->extra_spare_key_count == 1);
+ priv->extra_spare_key_count--;
+ }
+ }
- /* no need to change spare - just regular set_key */
- if (!change_spare)
- return wlcore_set_key(wl, cmd, vif, sta, key_conf);
+ wl1271_debug(DEBUG_CRYPT, "extra spare keys after: %d",
+ priv->extra_spare_key_count);
- ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
- if (ret < 0)
+ if (!change_spare)
goto out;
/* key is now set, change the spare blocks */
- if (cmd == SET_KEY) {
+ if (priv->extra_spare_key_count)
ret = wl18xx_set_host_cfg_bitmap(wl,
WL18XX_TX_HW_EXTRA_BLOCK_SPARE);
- if (ret < 0)
- goto out;
-
- priv->extra_spare_vif_count++;
- } else {
+ else
ret = wl18xx_set_host_cfg_bitmap(wl,
WL18XX_TX_HW_BLOCK_SPARE);
- if (ret < 0)
- goto out;
-
- priv->extra_spare_vif_count--;
- }
out:
return ret;
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index 53bae22..a4c4374 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -49,8 +49,8 @@ struct wl18xx_priv {
/* Index of last released Tx desc in FW */
u8 last_fw_rls_idx;
- /* number of VIFs requiring extra spare mem-blocks */
- int extra_spare_vif_count;
+ /* number of keys requiring extra spare mem-blocks */
+ int extra_spare_key_count;
};
#define WL18XX_FW_MAX_TX_STATUS_DESC 33
--
1.7.9.5
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> From: Yair Shapira <[email protected]>
>
> Under this mode the chip is powered on including sdio
> but no FW is downloaded and run, interrupts are not enabled, etc...
>
> This mode is intended to allow RTTT to bridge sdio as a transport
> to the chip.
>
> Driver only provides sdio access using the dev_mem debugfs file.
>
> Some fixes done to the code that ensures that PLT mode and normal
> driver power mode (ifconfig/add_interface) are mutually excluded.
>
> Signed-off-by: Yair Shapira <[email protected]>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
Hmmm... I must admit that I didn't look very carefully in the previous
changes to this same code.
Anyway, we already have a similar functionality where we can power the
chip on without uploading the firmware. We have the gpio_power file in
debugfs to handle that. By using it, you can easily power the chip on
without uploading and running the firmware, so other tools (such as RTTT
and the calibrator) can take over.
Do we really need this?
--
Luca.
On Wed, 2012-12-05 at 14:19 +0200, Eyal Shapira wrote:
> On 5 December 2012 13:21, Luciano Coelho <[email protected]> wrote:
> >
> >
> > IMO it would have been nicer to keep the existing ones as they are and
> > not change the semantics. Then add the new ones with another name.
> > Maybe something like "max_dwell_time_active_long", which is more
> > generic.
> >
> > It is possible that we will find more scenarios where this long scans
> > could be used (eg. if it would be possible to identify whether there are
> > any low latency TIDs running or not).
> >
>
> Sure. I'll respin it.
Thanks a lot, dude! :)
--
Luca.
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> From: Ido Yariv <[email protected]>
>
> Some of the mmc drivers initiate DMA transfers with buffers passed from
> higher layers. This means that the driver shouldn't ever pass non
> DMA-able buffers, such as ones that are unaligned, allocated on the
> stack or static.
>
> Fix a couple of calls to the mmc layer in which buffers which weren't
> necessarily DMA-able were passed.
>
> Signed-off-by: Ido Yariv <[email protected]>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
[...]
> diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
> index 5897747..70f9bdc 100644
> --- a/drivers/net/wireless/ti/wlcore/io.h
> +++ b/drivers/net/wireless/ti/wlcore/io.h
> @@ -105,13 +105,12 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
> {
> int ret;
>
> - ret = wlcore_raw_read(wl, addr, &wl->buffer_32,
> - sizeof(wl->buffer_32), false);
> + ret = wlcore_raw_read(wl, addr, wl->buffer_32, sizeof(u32), false);
> if (ret < 0)
> return ret;
>
> if (val)
> - *val = le32_to_cpu(wl->buffer_32);
> + *val = le32_to_cpu(*wl->buffer_32);
>
> return 0;
> }
> @@ -119,9 +118,8 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
> static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr,
> u32 val)
> {
> - wl->buffer_32 = cpu_to_le32(val);
> - return wlcore_raw_write(wl, addr, &wl->buffer_32,
> - sizeof(wl->buffer_32), false);
> + *wl->buffer_32 = cpu_to_le32(val);
> + return wlcore_raw_write(wl, addr, wl->buffer_32, sizeof(u32), false);
> }
>
> static inline int __must_check wlcore_read(struct wl1271 *wl, int addr,
> diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
> index 1793a82..e4ff66a 100644
> --- a/drivers/net/wireless/ti/wlcore/main.c
> +++ b/drivers/net/wireless/ti/wlcore/main.c
> @@ -5890,8 +5890,17 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
> goto err_fwlog;
> }
>
> + wl->buffer_32 = kmalloc(sizeof(u32), GFP_KERNEL);
> + if (!wl->buffer_32) {
> + ret = -ENOMEM;
> + goto err_mbox;
> + }
> +
> return hw;
>
> +err_mbox:
> + kfree(wl->mbox);
> +
> err_fwlog:
> free_page((unsigned long)wl->fwlog);
Can't we change sizeof(u32) to sizeof(__le32) or sizeof(*wl->buffer_32)
just for consistency?
I'll change it to the latter if you agree.
--
Luca.
VGhhbmtzIEx1Y2EsIA0KDQpjb25maWd1cmluZyANCg0KYm9hcmRfcmVmX2Nsb2NrID0gV0wxMlhY
X1JFRkNMT0NLXzM4LCAvKiAzOC40IE1IeiAqLw0KDQpnYXZlIG1lIHRoZSBwb3NzaWJpbGl0eSB0
byBzY2FuIG5ldHdvcmsgYnV0IG9ubHkgZm9yIGFuIGVzc2lkIG9uIGNoYW5uZWwxIChkZWxpdmVy
ZWQgZnJvbSBvbmUgQVApLg0KDQpJIGNvdWxkbid0IHNjYW4gb3RoZXJzIGVzc2lkcyBvbiBvdGhl
ciBjaGFubmVscyAoZm9yIGV4YW1wbGUgY2hhbm5lbCA2KSBhbmQgSSBkb24ndCBrbm93IHdoeS4N
Cg0KSGF2ZSB5b3UgZ290IGFueSBpZGVhIGFib3V0IGl0ID8NCg0KUmVnYXJkcw0KDQpBbGJlcnRv
DQoNCnJvb3RAKG5vbmUpOn4jIGl3bGlzdCB3bGFuMCBzY2FuDQp3bGFuMCAgICAgU2NhbiBjb21w
bGV0ZWQgOg0KICAgICAgICAgIENlbGwgMDEgLSBBZGRyZXNzOiA5MDpGNjo1MjozRjpDNDpDQw0K
ICAgICAgICAgICAgICAgICAgICBDaGFubmVsOjENCiAgICAgICAgICAgICAgICAgICAgRnJlcXVl
bmN5OjIuNDEyIEdIeiAoQ2hhbm5lbCAxKQ0KICAgICAgICAgICAgICAgICAgICBRdWFsaXR5PTQy
LzcwICBTaWduYWwgbGV2ZWw9LTY4IGRCbQ0KICAgICAgICAgICAgICAgICAgICBFbmNyeXB0aW9u
IGtleTpvbg0KICAgICAgICAgICAgICAgICAgICBFU1NJRDoiSW5wZWNvLVJhZGl1cyINCiAgICAg
ICAgICAgICAgICAgICAgQml0IFJhdGVzOjEgTWIvczsgMiBNYi9zOyA1LjUgTWIvczsgMTEgTWIv
czsgNiBNYi9zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA5IE1iL3M7IDEyIE1iL3M7
IDE4IE1iL3MNCiAgICAgICAgICAgICAgICAgICAgQml0IFJhdGVzOjI0IE1iL3M7IDM2IE1iL3M7
IDQ4IE1iL3M7IDU0IE1iL3MNCiAgICAgICAgICAgICAgICAgICAgTW9kZTpNYXN0ZXINCiAgICAg
ICAgICAgICAgICAgICAgRXh0cmE6dHNmPTAwMDAwM2VhN2NjN2FkODANCiAgICAgICAgICAgICAg
ICAgICAgRXh0cmE6IExhc3QgYmVhY29uOiAxNTZtcyBhZ28NCiAgICAgICAgICAgICAgICAgICAg
SUU6IFVua25vd246IDAwMEQ0OTZFNzA2NTYzNkYyRDUyNjE2NDY5NzU3Mw0KICAgICAgICAgICAg
ICAgICAgICBJRTogVW5rbm93bjogMDEwODgyODQ4Qjk2MEMxMjE4MjQNCiAgICAgICAgICAgICAg
ICAgICAgSUU6IFVua25vd246IDAzMDEwMQ0KICAgICAgICAgICAgICAgICAgICBJRTogVW5rbm93
bjogMDUwNDAwMDEwMDAwDQogICAgICAgICAgICAgICAgICAgIElFOiBVbmtub3duOiAyQTAxMDAN
CiAgICAgICAgICAgICAgICAgICAgSUU6IElFRUUgODAyLjExaS9XUEEyIFZlcnNpb24gMQ0KICAg
ICAgICAgICAgICAgICAgICAgICAgR3JvdXAgQ2lwaGVyIDogQ0NNUA0KICAgICAgICAgICAgICAg
ICAgICAgICAgUGFpcndpc2UgQ2lwaGVycyAoMSkgOiBDQ01QDQogICAgICAgICAgICAgICAgICAg
ICAgICBBdXRoZW50aWNhdGlvbiBTdWl0ZXMgKDEpIDogODAyLjF4DQogICAgICAgICAgICAgICAg
ICAgICAgIFByZWF1dGhlbnRpY2F0aW9uIFN1cHBvcnRlZA0KICAgICAgICAgICAgICAgICAgICBJ
RTogVW5rbm93bjogMzIwNDMwNDg2MDZDDQogICAgICAgICAgICAgICAgICAgIElFOiBVbmtub3du
OiBERDE4MDA1MEYyMDIwMTAxODYwMDAzQTQwMDAwMjdBNDAwMDA0MjQzNUUwMDYyMzIyRjAwDQog
ICAgICAgICAgICAgICAgICAgIElFOiBVbmtub3duOiBERDFFMDA5MDRDMzM0RTExMUJGRjAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwDQogICAgICAgICAgICAgICAg
ICAgIElFOiBVbmtub3duOiAyRDFBNEUxMTFCRkYwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMA0KICAgICAgICAgICAgICAgICAgICBJRTogVW5rbm93bjogREQxQTAw
OTA0QzM0MDEwRDA4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDANCiAgICAg
ICAgICAgICAgICAgICAgSUU6IFVua25vd246IDNEMTYwMTBEMDgwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMA0KICAgICAgICAgICAgICAgICAgICBJRTogVW5rbm93bjogREQw
OTAwMDM3RjAxMDEwMDAwRkY3Rg0KICAgICAgICAgICAgICAgICAgICBJRTogVW5rbm93bjogREQw
QTAwMDM3RjA0MDEwMDAwMDA0MDAwDQoNCi0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQpGcm9t
OiBMdWNpYW5vIENvZWxobyBbbWFpbHRvOmNvZWxob0B0aS5jb21dIA0KU2VudDogbWFydGVkw6wg
MTEgZGljZW1icmUgMjAxMiAxMTo1MQ0KVG86IEFsYmVydG8gR2FyYXUNCkNjOiBsaW51eC13aXJl
bGVzc0B2Z2VyLmtlcm5lbC5vcmc7IElkbyBZYXJpdjsgQXJpayBOZW10c292DQpTdWJqZWN0OiBS
ZTogd2wxMnh4IG92ZXIgc3BpIHdpdGggbm8gc2NhbiByZXN1bHRzDQoNCk9uIFR1ZSwgMjAxMi0x
Mi0xMSBhdCAxMDozNSArMDAwMCwgQWxiZXJ0byBHYXJhdSB3cm90ZToNCj4gVGhhdCdzIGFuICph
bmNpZW50KiBrZXJuZWwuIDooIEFueSBjaGFuY2UgeW91IGNhbiB0cnkgaXQgd2l0aCBhIG5ld2Vy
IGtlcm5lbD8NCj4gDQo+IFVub3J0dW5hdGVseSBub3QsIHRoYXQncyBvdXIgcHJvZHVjdGlvbiBr
ZXJuZWwuIA0KDQpFdmVuIGlmIHlvdSBjYW4ndCB1c2UgaXQgaW4gcmVhbCBsaWZlLCBpdCBjb3Vs
ZCBiZSB3b3J0aCB0cnlpbmcgYSBuZXdlciBrZXJuZWwgaWYgeW91IGtlZXAgZ2V0dGluZyBwcm9i
bGVtcyB3aXRoIHRoYXQgb2xkIG9uZS4gIFlvdSBjb3VsZCBhbHNvIHRyeSBjb21wYXQtd2lyZWxl
c3MgdG8gZ2V0IGEgbmV3ZXIgd2lyZWxlc3Mgc3Vic3lzdGVtLCBhdCBsZWFzdC4NCg0KDQo+ID4g
QW55IG90aGVyIGlkZWEgYWJvdXQgd2h5IHRoZSBzY2FuIGNvbW1hbmQgaXQncyBub3QgcHJvcGVy
bHkgd29ya2luZyA/DQo+IA0KPiBBbm90aGVyIGNvbW1vbiBwcm9ibGVtIGlzIHRoZSBjbG9jayBz
ZXR0aW5ncy4gIEFyZSB5b3Ugc3VyZSB0aGUgY29ycmVjdCB2YWx1ZSBmb3IgYm9hcmRfcmVmX2Ns
b2NrIGluIHlvdXIgYm9hcmQgZmlsZT8NCj4gDQo+IEFyZSB5b3UgdGFsa2luZyBhYm91dCAid2wt
PnJlZl9jbG9jayA9IHBkYXRhLT5ib2FyZF9yZWZfY2xvY2s7IiBpbiB0aGUgcHJvYmUgPyBXaGlj
aCB2YWx1ZSBzaG91bGQgSSBwdXQgZm9yIDM4LjRNSHogZHVlIHRvIHRoZSBmYWN0IHRoYXQgaXQg
aXMgYW4gaW50ZWdlciBwYXJhbWV0ZXIgPw0KDQpZZXMsIHRoYXQncyB0aGUgdmFsdWUgSSdtIHRh
bGtpbmcgYWJvdXQuICBZb3Ugc2hvdWxkIHB1dCBpdCBpbiB5b3VyIGJvYXJkZmlsZSwgc29tZXRo
aW5nIGxpa2UgdGhpcyAoZnJvbSBwYW5kYSk6DQoNCnN0YXRpYyBzdHJ1Y3Qgd2wxMnh4X3BsYXRm
b3JtX2RhdGEgb21hcF9wYW5kYV93bGFuX2RhdGEgIF9faW5pdGRhdGEgPSB7DQoJLmJvYXJkX3Jl
Zl9jbG9jayA9IFdMMTJYWF9SRUZDTE9DS18zOCwgLyogMzguNCBNSHogKi8gfTsNCg0KWW91IGNh
biBmaW5kIHRoZXNlIHZhbHVlcyBpbiB0aGUgaW5jbHVkZS9saW51eC93bDEyeHguaCBmaWxlLg0K
DQotLQ0KTHVjYS4NCg0KDQo=
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> Only allow a PSM STA to congest FW memory when it is the single active
> link. Being a single STA doesn't imply a single link - there might be
> other links on other roles.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
[...]
> diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
> index 1fbee0d..28a3027 100644
> --- a/drivers/net/wireless/ti/wlcore/cmd.c
> +++ b/drivers/net/wireless/ti/wlcore/cmd.c
> @@ -328,6 +328,8 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
> wl->fw_status_2->counters.tx_lnk_free_pkts[link];
> wl->links[link].wlvif = wlvif;
> *hlid = link;
> +
> + wl->active_link_count++;
> return 0;
> }
>
> @@ -357,6 +359,8 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
> wl->links[*hlid].wlvif = NULL;
>
> *hlid = WL12XX_INVALID_LINK_ID;
> + wl->active_link_count--;
> + WARN_ON(wl->active_link_count < 0);
This could be WARN_ON_ONCE(). If we hit this once, it's highly likely
that we will keep hitting it later on, unless we have another bug that
would cancel this one out. ;)
I can convert this myself if you agree.
--
Luca.
SGkgQWxsLA0KDQp0aGFua3MgaW4gYWR2YW5jZSBmb3IgeW91ciBzdXBwb3J0Lg0KDQpJ4oCZbSB0
cnlpbmcgdG8gbWFrZSB3b3JraW5nIHRoZSBXTDEyNzEgVEkgTXVyYXRhIGNoaXAgd2l0aCBvdXIg
Y3VzdG9tIGJvYXJkLiAgVGhlIFNQSSBkcml2ZXIgc2VlbXMgdG8gYmUgcnVubmluZyBidXQgSSBj
YW5ub3Qgc2NhbiBmcm9tIG91ciBXaWZpIE5ldHdvcmsuIA0KDQpBZnRlciBib290aW5nIHRoZSBi
b2FyZCBJ4oCZbSBkb2luZzoNCg0K4oCiCWluc21vZCAvbWVkaWEvcmVkL3Jvb3Qvd2wxMjcxL3ds
MTI3MS5rbw0K4oCiCWluc21vZCAvbWVkaWEvcmVkL3Jvb3Qvd2wxMjcxL3dsMTI3MV9zcGkua28N
CuKAoglpd2NvbmZpZyB3bGFuMCBtb2RlIG1hbmFnZWQNCuKAoglpd2NvbmZpZyB3bGFuMCBlc3Np
ZCB4eHh4eHh4DQrigKIJaWZjb25maWcgd2xhbjAgaHcgZXRoZXIgMDA6ODA6RTE6MTI6MjY6MTcg
DQrigKIJaWZjb25maWcgd2xhbjAgMTkyLjE2OC40MC4xMDAgbmV0bWFzayAyNTUuMjU1LjI1NS4w
IHVwDQoNClRoZW4gSSBib3RhaW46DQoNCmNoaXBfaWQgcmVhZCBmcm9tIG1lbW9yeTogMDQwMzAx
MTENCndsMTI3MV9mZXRjaF9maXJtd2FyZSAtIGZldGNoaW5nIGZpcm13YXJlIHdsMTI3MS1mdy5i
aW4NCndsMTI3MV9mZXRjaF9udnMgLSBmZXRjaGluZyBmaXJtd2FyZSB3bDEyNzEtbnZzLmJpbg0K
d2wxMjcxOiBmaXJtd2FyZSBib290ZWQgKFJldiA2LjEuMC41MC4zNTApDQoNCmJ1dCB1bmZvcnR1
bmF0ZWx5IHRoZSB3aGVuIEkgcnVuIOKAnGl3bGlzdCB3bGFuMCBzY2Fu4oCdDQoNCkkgb2J0YWlu
IOKAnHdsYW4wIE5vIHNjYW4gcmVzdWx0c+KAnQ0KDQoNCkNvdWxkIHlvdSBwbGVhc2UgaGVscCB1
cyBpbiBmaXhpbmcgdGhpcyBpc3N1ZSA/DQoNClRoYW5rcyBhZ2Fpbi4NCg0KQWxiZXJ0bw0KDQot
LS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KRnJvbTogbGludXgtd2lyZWxlc3Mtb3duZXJAdmdl
ci5rZXJuZWwub3JnIFttYWlsdG86bGludXgtd2lyZWxlc3Mtb3duZXJAdmdlci5rZXJuZWwub3Jn
XSBPbiBCZWhhbGYgT2YgTHVjaWFubyBDb2VsaG8NClNlbnQ6IGx1bmVkw6wgMTAgZGljZW1icmUg
MjAxMiAxODowNw0KVG86IEFyaWsgTmVtdHNvdg0KQ2M6IGxpbnV4LXdpcmVsZXNzQHZnZXIua2Vy
bmVsLm9yZzsgSWRvIFlhcml2DQpTdWJqZWN0OiBSZTogW1BBVENIIDIwLzIwXSB3bGNvcmU6IEFs
d2F5cyBwYXNzIERNQS1hYmxlIGJ1ZmZlcnMgdG8gbW1jIGZ1bmN0aW9ucw0KDQpPbiBXZWQsIDIw
MTItMTEtMjggYXQgMTE6NDIgKzAyMDAsIEFyaWsgTmVtdHNvdiB3cm90ZToNCj4gRnJvbTogSWRv
IFlhcml2IDxpZG9Ad2l6ZXJ5LmNvbT4NCj4gDQo+IFNvbWUgb2YgdGhlIG1tYyBkcml2ZXJzIGlu
aXRpYXRlIERNQSB0cmFuc2ZlcnMgd2l0aCBidWZmZXJzIHBhc3NlZCANCj4gZnJvbSBoaWdoZXIg
bGF5ZXJzLiBUaGlzIG1lYW5zIHRoYXQgdGhlIGRyaXZlciBzaG91bGRuJ3QgZXZlciBwYXNzIG5v
biANCj4gRE1BLWFibGUgYnVmZmVycywgc3VjaCBhcyBvbmVzIHRoYXQgYXJlIHVuYWxpZ25lZCwg
YWxsb2NhdGVkIG9uIHRoZSANCj4gc3RhY2sgb3Igc3RhdGljLg0KPiANCj4gRml4IGEgY291cGxl
IG9mIGNhbGxzIHRvIHRoZSBtbWMgbGF5ZXIgaW4gd2hpY2ggYnVmZmVycyB3aGljaCB3ZXJlbid0
IA0KPiBuZWNlc3NhcmlseSBETUEtYWJsZSB3ZXJlIHBhc3NlZC4NCj4gDQo+IFNpZ25lZC1vZmYt
Ynk6IElkbyBZYXJpdiA8aWRvQHdpemVyeS5jb20+DQo+IFNpZ25lZC1vZmYtYnk6IEFyaWsgTmVt
dHNvdiA8YXJpa0B3aXplcnkuY29tPg0KPiAtLS0NCg0KWy4uLl0NCg0KPiBkaWZmIC0tZ2l0IGEv
ZHJpdmVycy9uZXQvd2lyZWxlc3MvdGkvd2xjb3JlL2lvLmggDQo+IGIvZHJpdmVycy9uZXQvd2ly
ZWxlc3MvdGkvd2xjb3JlL2lvLmgNCj4gaW5kZXggNTg5Nzc0Ny4uNzBmOWJkYyAxMDA2NDQNCj4g
LS0tIGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvdGkvd2xjb3JlL2lvLmgNCj4gKysrIGIvZHJpdmVy
cy9uZXQvd2lyZWxlc3MvdGkvd2xjb3JlL2lvLmgNCj4gQEAgLTEwNSwxMyArMTA1LDEyIEBAIHN0
YXRpYyBpbmxpbmUgaW50IF9fbXVzdF9jaGVjayANCj4gd2xjb3JlX3Jhd19yZWFkMzIoc3RydWN0
IHdsMTI3MSAqd2wsIGludCBhZGRyLCAgew0KPiAgCWludCByZXQ7DQo+ICANCj4gLQlyZXQgPSB3
bGNvcmVfcmF3X3JlYWQod2wsIGFkZHIsICZ3bC0+YnVmZmVyXzMyLA0KPiAtCQkJICAgICAgc2l6
ZW9mKHdsLT5idWZmZXJfMzIpLCBmYWxzZSk7DQo+ICsJcmV0ID0gd2xjb3JlX3Jhd19yZWFkKHds
LCBhZGRyLCB3bC0+YnVmZmVyXzMyLCBzaXplb2YodTMyKSwgZmFsc2UpOw0KPiAgCWlmIChyZXQg
PCAwKQ0KPiAgCQlyZXR1cm4gcmV0Ow0KPiAgDQo+ICAJaWYgKHZhbCkNCj4gLQkJKnZhbCA9IGxl
MzJfdG9fY3B1KHdsLT5idWZmZXJfMzIpOw0KPiArCQkqdmFsID0gbGUzMl90b19jcHUoKndsLT5i
dWZmZXJfMzIpOw0KPiAgDQo+ICAJcmV0dXJuIDA7DQo+ICB9DQo+IEBAIC0xMTksOSArMTE4LDgg
QEAgc3RhdGljIGlubGluZSBpbnQgX19tdXN0X2NoZWNrIA0KPiB3bGNvcmVfcmF3X3JlYWQzMihz
dHJ1Y3Qgd2wxMjcxICp3bCwgaW50IGFkZHIsICBzdGF0aWMgaW5saW5lIGludCBfX211c3RfY2hl
Y2sgd2xjb3JlX3Jhd193cml0ZTMyKHN0cnVjdCB3bDEyNzEgKndsLCBpbnQgYWRkciwNCj4gIAkJ
CQkJCSAgdTMyIHZhbCkNCj4gIHsNCj4gLQl3bC0+YnVmZmVyXzMyID0gY3B1X3RvX2xlMzIodmFs
KTsNCj4gLQlyZXR1cm4gd2xjb3JlX3Jhd193cml0ZSh3bCwgYWRkciwgJndsLT5idWZmZXJfMzIs
DQo+IC0JCQkJc2l6ZW9mKHdsLT5idWZmZXJfMzIpLCBmYWxzZSk7DQo+ICsJKndsLT5idWZmZXJf
MzIgPSBjcHVfdG9fbGUzMih2YWwpOw0KPiArCXJldHVybiB3bGNvcmVfcmF3X3dyaXRlKHdsLCBh
ZGRyLCB3bC0+YnVmZmVyXzMyLCBzaXplb2YodTMyKSwgDQo+ICtmYWxzZSk7DQo+ICB9DQo+ICAN
Cj4gIHN0YXRpYyBpbmxpbmUgaW50IF9fbXVzdF9jaGVjayB3bGNvcmVfcmVhZChzdHJ1Y3Qgd2wx
MjcxICp3bCwgaW50IA0KPiBhZGRyLCBkaWZmIC0tZ2l0IGEvZHJpdmVycy9uZXQvd2lyZWxlc3Mv
dGkvd2xjb3JlL21haW4uYyANCj4gYi9kcml2ZXJzL25ldC93aXJlbGVzcy90aS93bGNvcmUvbWFp
bi5jDQo+IGluZGV4IDE3OTNhODIuLmU0ZmY2NmEgMTAwNjQ0DQo+IC0tLSBhL2RyaXZlcnMvbmV0
L3dpcmVsZXNzL3RpL3dsY29yZS9tYWluLmMNCj4gKysrIGIvZHJpdmVycy9uZXQvd2lyZWxlc3Mv
dGkvd2xjb3JlL21haW4uYw0KPiBAQCAtNTg5MCw4ICs1ODkwLDE3IEBAIHN0cnVjdCBpZWVlODAy
MTFfaHcgKndsY29yZV9hbGxvY19odyhzaXplX3QgcHJpdl9zaXplLCB1MzIgYWdncl9idWZfc2l6
ZSwNCj4gIAkJZ290byBlcnJfZndsb2c7DQo+ICAJfQ0KPiAgDQo+ICsJd2wtPmJ1ZmZlcl8zMiA9
IGttYWxsb2Moc2l6ZW9mKHUzMiksIEdGUF9LRVJORUwpOw0KPiArCWlmICghd2wtPmJ1ZmZlcl8z
Mikgew0KPiArCQlyZXQgPSAtRU5PTUVNOw0KPiArCQlnb3RvIGVycl9tYm94Ow0KPiArCX0NCj4g
Kw0KPiAgCXJldHVybiBodzsNCj4gIA0KPiArZXJyX21ib3g6DQo+ICsJa2ZyZWUod2wtPm1ib3gp
Ow0KPiArDQo+ICBlcnJfZndsb2c6DQo+ICAJZnJlZV9wYWdlKCh1bnNpZ25lZCBsb25nKXdsLT5m
d2xvZyk7DQoNCg0KQ2FuJ3Qgd2UgY2hhbmdlIHNpemVvZih1MzIpIHRvIHNpemVvZihfX2xlMzIp
IG9yIHNpemVvZigqd2wtPmJ1ZmZlcl8zMikganVzdCBmb3IgY29uc2lzdGVuY3k/DQoNCkknbGwg
Y2hhbmdlIGl0IHRvIHRoZSBsYXR0ZXIgaWYgeW91IGFncmVlLg0KDQotLQ0KTHVjYS4NCg0KLS0N
ClRvIHVuc3Vic2NyaWJlIGZyb20gdGhpcyBsaXN0OiBzZW5kIHRoZSBsaW5lICJ1bnN1YnNjcmli
ZSBsaW51eC13aXJlbGVzcyIgaW4gdGhlIGJvZHkgb2YgYSBtZXNzYWdlIHRvIG1ham9yZG9tb0B2
Z2VyLmtlcm5lbC5vcmcgTW9yZSBtYWpvcmRvbW8gaW5mbyBhdCAgaHR0cDovL3ZnZXIua2VybmVs
Lm9yZy9tYWpvcmRvbW8taW5mby5odG1sDQoNCg==
SGkgTHVjYSwNCg0KLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCkZyb206IEx1Y2lhbm8gQ29l
bGhvIFttYWlsdG86Y29lbGhvQHRpLmNvbV0gDQpTZW50OiBsdW5lZMOsIDEwIGRpY2VtYnJlIDIw
MTIgMTg6NTANClRvOiBBbGJlcnRvIEdhcmF1DQpDYzogbGludXgtd2lyZWxlc3NAdmdlci5rZXJu
ZWwub3JnOyBJZG8gWWFyaXY7IEFyaWsgTmVtdHNvdg0KU3ViamVjdDogd2wxMnh4IG92ZXIgc3Bp
IHdpdGggbm8gc2NhbiByZXN1bHRzICh3YXM6IFJlOiBbUEFUQ0ggMjAvMjBdIHdsY29yZTogQWx3
YXlzIHBhc3MgRE1BLWFibGUgYnVmZmVycyB0byBtbWMgZnVuY3Rpb25zKQ0KDQpIaSBBbGJlcnRv
LA0KDQpPbiBNb24sIDIwMTItMTItMTAgYXQgMTc6MjQgKzAwMDAsIEFsYmVydG8gR2FyYXUgd3Jv
dGU6DQo+IEnigJltIHRyeWluZyB0byBtYWtlIHdvcmtpbmcgdGhlIFdMMTI3MSBUSSBNdXJhdGEg
Y2hpcCB3aXRoIG91ciBjdXN0b20gYm9hcmQuICBUaGUgU1BJIGRyaXZlciBzZWVtcyB0byBiZSBy
dW5uaW5nIGJ1dCBJIGNhbm5vdCBzY2FuIGZyb20gb3VyIFdpZmkgTmV0d29yay4gDQo+IA0KPiBB
ZnRlciBib290aW5nIHRoZSBib2FyZCBJ4oCZbSBkb2luZzoNCj4gDQo+IOKAoglpbnNtb2QgL21l
ZGlhL3JlZC9yb290L3dsMTI3MS93bDEyNzEua28NCj4g4oCiCWluc21vZCAvbWVkaWEvcmVkL3Jv
b3Qvd2wxMjcxL3dsMTI3MV9zcGkua28NCj4g4oCiCWl3Y29uZmlnIHdsYW4wIG1vZGUgbWFuYWdl
ZA0KPiDigKIJaXdjb25maWcgd2xhbjAgZXNzaWQgeHh4eHh4eA0KPiDigKIJaWZjb25maWcgd2xh
bjAgaHcgZXRoZXIgMDA6ODA6RTE6MTI6MjY6MTcgDQo+IOKAoglpZmNvbmZpZyB3bGFuMCAxOTIu
MTY4LjQwLjEwMCBuZXRtYXNrIDI1NS4yNTUuMjU1LjAgdXANCj4gDQo+IFRoZW4gSSBib3RhaW46
DQo+IA0KPiBjaGlwX2lkIHJlYWQgZnJvbSBtZW1vcnk6IDA0MDMwMTExDQo+IHdsMTI3MV9mZXRj
aF9maXJtd2FyZSAtIGZldGNoaW5nIGZpcm13YXJlIHdsMTI3MS1mdy5iaW4gDQo+IHdsMTI3MV9m
ZXRjaF9udnMgLSBmZXRjaGluZyBmaXJtd2FyZSB3bDEyNzEtbnZzLmJpbg0KPiB3bDEyNzE6IGZp
cm13YXJlIGJvb3RlZCAoUmV2IDYuMS4wLjUwLjM1MCkNCj4gDQo+IGJ1dCB1bmZvcnR1bmF0ZWx5
IHRoZSB3aGVuIEkgcnVuIOKAnGl3bGlzdCB3bGFuMCBzY2Fu4oCdDQo+IA0KPiBJIG9idGFpbiDi
gJx3bGFuMCBObyBzY2FuIHJlc3VsdHPigJ0NCj4gDQo+IA0KPiBDb3VsZCB5b3UgcGxlYXNlIGhl
bHAgdXMgaW4gZml4aW5nIHRoaXMgaXNzdWUgPw0KDQpUaGlzIGNvdWxkIGJlIG1hbnkgZGlmZmVy
ZW50IHRoaW5ncy4gIFRoZSBmaXJzdCB0aGluZyB0aGF0IGNvbWVzIHRvIG15IG1pbmQgaXMgdGhh
dCB0aGUgc2NhbiByZXN1bHRzIGFyZSB0aGUgZmlyc3QgdGhpbmcgdGhhdCBjb21lcyBhcyBhIHJl
YWwgaW50ZXJydXB0IChiZWZvcmUgdGhpcyBhbGwgdGhlIGludGVycnVwdHMgYXJlIHBvbGxlZCku
ICBTbyBhcmUgeW91IHN1cmUgdGhlIGludGVycnVwdCBsaW5lIGlzIHdvcmtpbmcgcHJvcGVybHk/
DQoNClRoZSBpbnRlcnJ1cHQgbGluZSBpdCBzZWVtcyB0byB3b3JrIHByb3Blcmx5LiBJIHB1dCBh
IHByaW50ayBpbiB0aGUgaW50ZXJydXB0IGhhbmRsZXIgYW5kIEkgc2VlIGl0IGFjdGl2YXRlZCAN
CkR1cmluZyB0aGUgZmlybXdhcmUgZmV0Y2ggYW5kIHdoZW4gSSBwZXJmb3JtIHRoZSAiaXdsaXN0
YSB3bGFuMCBzY2FuIi4gSSBrZXB0IHRoZSBJUlEgYXNzb2NpYXRpb24gdG8gSVJRX1RZUEVfRURH
RV9SSVNJTkcgYXMgeW91ciBzb3VyY2UgY29kZSB3YXMgaW4gMi42LjM3IGtlcm5lbC4NCkFueSBv
dGhlciBpZGVhIGFib3V0IHdoeSB0aGUgc2NhbiBjb21tYW5kIGl0J3Mgbm90IHByb3Blcmx5IHdv
cmtpbmcgPw0KDQpSZWdhcmRzDQoNCkFsYmVydG8NCg0KLS0NCkx1Y2EuDQoNCg0K
On Wed, 2012-12-05 at 12:17 +0200, Eliad Peller wrote:
> On Wed, Dec 5, 2012 at 11:35 AM, Luciano Coelho <[email protected]> wrote:
> > On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> >> From: Eliad Peller <[email protected]>
> >>
> >> ACX_PEER_CAP command is just ACX_PEER_HT_CAP, but allows
> >> configuring the peer's support rates as well.
> >>
> >> this is needed because we start the station role when
> >> the remote rates are not known yet.
> >>
> >> the two commands should be unified in future fw versions,
> >> but for now add a new set_peer_cap per-hw op, that will
> >> use ACX_PEER_CAP for 18xx, and ACX_PEER_HT_CAP for 12xx.
> >>
> >> Signed-off-by: Eliad Peller <[email protected]>
> >> Signed-off-by: Arik Nemtsov <[email protected]>
> >> ---
> >
> > [...]
> >
> >> diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
> >> index 0218edd..951b88c 100644
> >> --- a/drivers/net/wireless/ti/wl12xx/main.c
> >> +++ b/drivers/net/wireless/ti/wl12xx/main.c
> >> @@ -1623,6 +1623,15 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
> >> return wlcore_set_key(wl, cmd, vif, sta, key_conf);
> >> }
> >>
> >> +static int wl12xx_set_peer_cap(struct wl1271 *wl,
> >> + struct ieee80211_sta_ht_cap *ht_cap,
> >> + bool allow_ht_operation,
> >> + u32 rate_set, u8 hlid)
> >> +{
> >> + return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation,
> >> + hlid);
> >> +}
> >> +
> >
> > This is quite ugly, because you're just calling wlcore back to perform
> > this op.
> >
> right. but that's how it's been done in other places as well (e.g.
> wl12xx_set_key).
Ugliness doesn't justify more ugliness. :P
> >> diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
> >> index 801d8af..a169bb5 100644
> >> --- a/drivers/net/wireless/ti/wl18xx/acx.c
> >> +++ b/drivers/net/wireless/ti/wl18xx/acx.c
> >> @@ -140,3 +140,57 @@ out:
> >> return ret;
> >>
> >> }
> >> +
> >> +/*
> >> + * this command is basically the same as wl1271_acx_ht_capabilities,
> >> + * with the addition of supported rates. they should be unified in
> >> + * the next fw api change
> >> + */
> >
> > Has this been already unified? What's the status or plan for this new
> > API change? I guess we're only waiting for the change in the wl12xx
> > firmware to catch up with wl18xx, right?
> >
> it hasn't been unified yet.
> i don't know what is the future plan...
Too bad... probably will never happen.
> >> diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
> >> index b57e348..0e636de 100644
> >> --- a/drivers/net/wireless/ti/wl18xx/acx.h
> >> +++ b/drivers/net/wireless/ti/wl18xx/acx.h
> >> @@ -297,11 +297,44 @@ struct wlcore_peer_ht_operation_mode {
> >> u8 padding[2];
> >> };
> >>
> >> +/*
> >> + * ACX_PEER_CAP
> >> + * this struct is very similar to wl1271_acx_ht_capabilities, with the
> >> + * addition of supported rates
> >> + */
> >> +struct wlcore_acx_peer_cap {
> >> + struct acx_header header;
> >> +
> >> + /* bitmask of capability bits supported by the peer */
> >> + __le32 ht_capabilites;
> >> +
> >> + /* rates supported by the remote peer */
> >> + __le32 supported_rates;
> >> +
> >> + /* Indicates to which link these capabilities apply. */
> >> + u8 hlid;
> >> +
> >> + /*
> >> + * This the maximum A-MPDU length supported by the AP. The FW may not
> >> + * exceed this length when sending A-MPDUs
> >> + */
> >> + u8 ampdu_max_length;
> >> +
> >> + /* This is the minimal spacing required when sending A-MPDUs to the AP*/
> >> + u8 ampdu_min_spacing;
> >> +
> >> + u8 padding;
> >> +} __packed;
> >
> > If we're sure this will be also changed in the wl12xx firmware, maybe
> > this could already be in the wlcore acx.h? Otherwise we'll just be
> > moving this around...
> >
> unfortunately, we can't really be sure about it :/
As usual. :(
> >> diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
> >> index 71137aa..ecdd5e6 100644
> >> --- a/drivers/net/wireless/ti/wlcore/wlcore.h
> >> +++ b/drivers/net/wireless/ti/wlcore/wlcore.h
> >> @@ -106,6 +106,11 @@ struct wlcore_ops {
> >> u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
> >> void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
> >> struct ieee80211_sta *sta, u32 changed);
> >> + int (*set_peer_cap)(struct wl1271 *wl,
> >> + struct ieee80211_sta_ht_cap *ht_cap,
> >> + bool allow_ht_operation,
> >> + u32 rate_set, u8 hlid);
> >> +
> >
> > I think it would be much nicer to do all this with a quirk instead.
> > Then we don't need to add ops that will have to be removed later and
> > make all this ping-pong of calls between the modules.
> >
> i'm not sure what do you mean by using a quirk here.
> currently, this is 18xx-specific command, so we need this op.
I meant that the new ACX could be fully implemented in wlcore (because
the expectation was that it would also become available in wl12xx in the
future) and we would have a quirk to tell wlcore not to use the new ACX
for wl12xx until it becomes available (when we would disable the quirk).
With the quirk, we could even continue supporting older wl12xx firmware
versions quite easily.
--
Luca.
On Fri, Dec 7, 2012 at 2:08 PM, Luciano Coelho <[email protected]> wrote:
> On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
>> Treat a single connected STA in PSM as a slow link and regulate Tx speed
>> according to slow link priority/stop thresholds.
>> This allows us to avoid flooding the FW, while delivering decent
>> throughput to a peer in forced-PSM.
>>
>> Signed-off-by: Arik Nemtsov <[email protected]>
>> ---
>> drivers/net/wireless/ti/wl18xx/main.c | 14 ++++++++------
>> 1 file changed, 8 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
>> index 3836dbd..ada4616 100644
>> --- a/drivers/net/wireless/ti/wl18xx/main.c
>> +++ b/drivers/net/wireless/ti/wl18xx/main.c
>> @@ -1446,10 +1446,11 @@ static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
>> return false;
>>
>> /* the priority thresholds are taken from FW */
>> - if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
>> - thold = status_priv->tx_fast_link_prio_threshold;
>> - else
>> + if (!test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) ||
>> + test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
>> thold = status_priv->tx_slow_link_prio_threshold;
>> + else
>> + thold = status_priv->tx_fast_link_prio_threshold;
>
> Am I missing something or is this kind of inverted logic? For some
> reason I always think it is simpler to have something like this:
>
> if (fast_link && !ps)
> thold = fast;
> else
> thold = slow;
I guess it's a bit simpler. I really don't mind. You can change it on
commit I guess?
Arik
Hi Luca,
On 12/05/2012 12:55 PM, Luciano Coelho wrote:
> On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
>> From: Igal Chernobelsky<[email protected]>
>>
>> FW memory block size and FW log end marker parameters
>> are added to wl structure and are initialized per
>> chip architecture. convert_hwaddr hw operation is added
>> to convert chip dependent FW internal address.
>> Copy from FW log is also simplified to copy the entire
>> memory block as FW logger utility is repsponsible
>> for parsing of FW log content.
>>
>> Signed-off-by: Igal Chernobelsky<[email protected]>
>> Signed-off-by: Arik Nemtsov<[email protected]>
>> ---
> This commit log explains what has been done, which can quite easily be
> see in the patch itself. That's okay, but what I'm missing here is the
> explanation *why* this needs to be done.
I can add to commit that FW logger is supported by wlcore but
has different parameters per chip (actually written in commit header).
>
>> diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
>> index 951b88c..5e3c808 100644
>> --- a/drivers/net/wireless/ti/wl12xx/main.c
>> +++ b/drivers/net/wireless/ti/wl12xx/main.c
>> @@ -706,6 +706,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
>> goto out;
>> }
>>
>> + wl->fw_mem_block_size = 256;
>> + wl->fwlog_end = 0x2000000;
> This value used to be in a macro before (WLCORE_FW_LOG_END), why kill
> it? It should just be renamed to WL12XX_FW_LOG_END and a new one be
> created for WL18XX.
These values are used only in one place during initialization and
are assigned to variables with self explanation name.
Do you still prefer defines?
>> @@ -1632,6 +1635,11 @@ static int wl12xx_set_peer_cap(struct wl1271 *wl,
>> hlid);
>> }
>>
>> +static u32 wl12xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
>> +{
>> + return hwaddr<< 5;
>> +}
> There was a good comment about this calculation before, it should be
> moved here instead of deleted.
Sorry, I will restore the comment for wl12xx:
/* Addresses are stored internally as addresses to 32 bytes blocks */
>
>> @@ -1669,6 +1677,7 @@ static struct wlcore_ops wl12xx_ops = {
>> .channel_switch = wl12xx_cmd_channel_switch,
>> .pre_pkt_send = NULL,
>> .set_peer_cap = wl12xx_set_peer_cap,
>> + .convert_hwaddr = wl12xx_convert_hwaddr,
> No need to break the alignment here.
I will fix it.
>
>> static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
>> diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
>> index df8de71..d806241 100644
>> --- a/drivers/net/wireless/ti/wl18xx/main.c
>> +++ b/drivers/net/wireless/ti/wl18xx/main.c
>> @@ -667,6 +667,9 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
>> goto out;
>> }
>>
>> + wl->fw_mem_block_size = 272;
>> + wl->fwlog_end = 0x40000000;
> Again, the magic number here can be avoided.
The same as for wl12xx.
>> @@ -1423,6 +1426,11 @@ static int wl18xx_set_peer_cap(struct wl1271 *wl,
>> rate_set, hlid);
>> }
>>
>> +static u32 wl18xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
>> +{
>> + return hwaddr& ~0x80000000;
>> +}
> A small explanation here would be nice.
That is formula to convert from HW address ...
> [...]
>
>
>
>> /* Traverse the memory blocks linked list */
>> do {
>> - memset(block, 0, WL12XX_HW_BLOCK_SIZE);
>> - ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
>> - false);
>> + part.mem.start = wlcore_hw_convert_hwaddr(wl, addr);
>> + part.mem.size = PAGE_SIZE;
>> +
>> + ret = wlcore_set_partition(wl,&part);
>> + if (ret< 0) {
>> + wl1271_error("%s: set_partition start=0x%X size=%d",
>> + __func__, part.mem.start, part.mem.size);
> This could probably be a bit more descriptive, like saying that the
> fwlog seems to be corrupt because the address in the linked list can't
> be used for setting the partition.
Ok, will add the comment.
>
>> diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
>> index f48530f..5897747 100644
>> --- a/drivers/net/wireless/ti/wlcore/io.h
>> +++ b/drivers/net/wireless/ti/wlcore/io.h
>> @@ -165,8 +165,8 @@ static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr,
>> int physical;
>> int addr;
>>
>> - /* Addresses are stored internally as addresses to 32 bytes blocks */
>> - addr = hwaddr<< 5;
>> + /* Convert from FW internal address which is chip arch dependent */
>> + addr = wl->ops->convert_hwaddr(wl, hwaddr);
> This could be more descriptive. As I understand, this is converting an
> internal representation of pointers in the hardware to an address that
> can be used to set the partitions.
>
Ok, will add more comment: convert to address used for setting partition
and reading over SDIO
>
>> diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
>> index a664662..a8647bd 100644
>> --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
>> +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
>> @@ -523,6 +523,4 @@ void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
>> #define HW_HT_RATES_OFFSET 16
>> #define HW_MIMO_RATES_OFFSET 24
>>
>> -#define WL12XX_HW_BLOCK_SIZE 256
> I think this should also be created separately for wl12xx and wl18xx
> instead of deleting the macro and hardcoding the values.
See above comment for defines.
> --
> Luca.
>
--
Best regards
Igal
On 5 December 2012 13:21, Luciano Coelho <[email protected]> wrote:
>
>
> IMO it would have been nicer to keep the existing ones as they are and
> not change the semantics. Then add the new ones with another name.
> Maybe something like "max_dwell_time_active_long", which is more
> generic.
>
> It is possible that we will find more scenarios where this long scans
> could be used (eg. if it would be possible to identify whether there are
> any low latency TIDs running or not).
>
Sure. I'll respin it.
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> This series applies on top of part 2 sent a couple days ago.
>
> The main addition is support for mac80211 HW queues and further
> optimizations for Tx in the multi-channel case.
>
> Arik Nemtsov (11):
> wlcore: remove support for injected Tx
> wlcore: improve handling for Rx errors
> wlcore: set 5Ghz probe-req template for DFS channels
> wlcore/wl18xx: change priority calculations for links
> wl18xx: limit Tx for the AP single-STA-in-PSM case
> wlcore: use link count for single-STA-PSM optimization
> wlcore: use separate HW queue for each AC in each vif
> wlcore: don't take mutex before stopping queues
> wlcore: consolidate Rx BA bitmap management to links struct
> wl18xx: support MIMO only if HT mode is not forced to SISO
> wl18xx: count HW block spare based correctly on keys
>
> Eliad Peller (1):
> wlcore: add ACX_PEER_CAP command
>
> Eyal Shapira (2):
> wlcore: increase scan dwell times if no activity
> wlcore: support scan reports during periodic scan
>
> Ido Reis (1):
> wl12xx/wl18xx: update default fw logger's settings
>
> Ido Yariv (1):
> wlcore: Always pass DMA-able buffers to mmc functions
>
> Igal Chernobelsky (1):
> wlcore/wl18xx/wl12xx: FW log params per chip arch
>
> Yair Shapira (3):
> wlcore: add new plt power-mode: CHIP_AWAKE
> wlcore: disable elp sleep while in plt mode
> wl18xx: fix a bug in wl->num_rx_desc initialization
Applied the whole series, except 03/20, 08/20 and 09/20, for which I'm
waiting more information or rework, and 01/20, which I dropped entirely.
Some changes were made to some of the patches according to the
discussions on the respective threads. In all cases, I used the latest
version sent, when rework was needed.
Thanks!
--
Luca.
On Wed, 2012-12-05 at 14:29 +0200, Igal Chernobelsky wrote:
> Hi Luca,
>
> On 12/05/2012 12:55 PM, Luciano Coelho wrote:
> > On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> >> From: Igal Chernobelsky<[email protected]>
> >>
> >> FW memory block size and FW log end marker parameters
> >> are added to wl structure and are initialized per
> >> chip architecture. convert_hwaddr hw operation is added
> >> to convert chip dependent FW internal address.
> >> Copy from FW log is also simplified to copy the entire
> >> memory block as FW logger utility is repsponsible
> >> for parsing of FW log content.
> >>
> >> Signed-off-by: Igal Chernobelsky<[email protected]>
> >> Signed-off-by: Arik Nemtsov<[email protected]>
> >> ---
> > This commit log explains what has been done, which can quite easily be
> > see in the patch itself. That's okay, but what I'm missing here is the
> > explanation *why* this needs to be done.
>
> I can add to commit that FW logger is supported by wlcore but
> has different parameters per chip (actually written in commit header).
Yeah, could be something like "The FW log data format is slightly
different in the different chips. They use a different format in the
linked list to point to the address of the next block." Not necessary
exactly like this, but this kind of information is more important than
describing how it is done (because the latter can be seen in the commit
diff anyway).
> >
> >> diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
> >> index 951b88c..5e3c808 100644
> >> --- a/drivers/net/wireless/ti/wl12xx/main.c
> >> +++ b/drivers/net/wireless/ti/wl12xx/main.c
> >> @@ -706,6 +706,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
> >> goto out;
> >> }
> >>
> >> + wl->fw_mem_block_size = 256;
> >> + wl->fwlog_end = 0x2000000;
> > This value used to be in a macro before (WLCORE_FW_LOG_END), why kill
> > it? It should just be renamed to WL12XX_FW_LOG_END and a new one be
> > created for WL18XX.
> These values are used only in one place during initialization and
> are assigned to variables with self explanation name.
> Do you still prefer defines?
Yes, I prefer defines. I think they would be better placed in the reg.h
file, for instance. Then you have a single place where you can look up
everything about the hardware memory configuration, instead of having to
look everywhere around the code.
Also, I just noticed that you have added this to the identify_chip
function. This doesn't change between different chipsets of the same
family. So it should be set in the setup operation (eg. wl12xx_setup)
instead.
> >> @@ -1632,6 +1635,11 @@ static int wl12xx_set_peer_cap(struct wl1271 *wl,
> >> hlid);
> >> }
> >>
> >> +static u32 wl12xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
> >> +{
> >> + return hwaddr<< 5;
> >> +}
> > There was a good comment about this calculation before, it should be
> > moved here instead of deleted.
> Sorry, I will restore the comment for wl12xx:
> /* Addresses are stored internally as addresses to 32 bytes blocks */
>
> >
> >> @@ -1669,6 +1677,7 @@ static struct wlcore_ops wl12xx_ops = {
> >> .channel_switch = wl12xx_cmd_channel_switch,
> >> .pre_pkt_send = NULL,
> >> .set_peer_cap = wl12xx_set_peer_cap,
> >> + .convert_hwaddr = wl12xx_convert_hwaddr,
> > No need to break the alignment here.
> I will fix it.
> >
> >> static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
> >> diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
> >> index df8de71..d806241 100644
> >> --- a/drivers/net/wireless/ti/wl18xx/main.c
> >> +++ b/drivers/net/wireless/ti/wl18xx/main.c
> >> @@ -667,6 +667,9 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
> >> goto out;
> >> }
> >>
> >> + wl->fw_mem_block_size = 272;
> >> + wl->fwlog_end = 0x40000000;
> > Again, the magic number here can be avoided.
> The same as for wl12xx.
Same as my answer above. :)
> >> @@ -1423,6 +1426,11 @@ static int wl18xx_set_peer_cap(struct wl1271 *wl,
> >> rate_set, hlid);
> >> }
> >>
> >> +static u32 wl18xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
> >> +{
> >> + return hwaddr& ~0x80000000;
> >> +}
> > A small explanation here would be nice.
> That is formula to convert from HW address ...
What I mean is that, in practice, what you're doing here is masking out
bit 31. Do we know what they use that bit for?
> >> /* Traverse the memory blocks linked list */
> >> do {
> >> - memset(block, 0, WL12XX_HW_BLOCK_SIZE);
> >> - ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
> >> - false);
> >> + part.mem.start = wlcore_hw_convert_hwaddr(wl, addr);
> >> + part.mem.size = PAGE_SIZE;
> >> +
> >> + ret = wlcore_set_partition(wl,&part);
> >> + if (ret< 0) {
> >> + wl1271_error("%s: set_partition start=0x%X size=%d",
> >> + __func__, part.mem.start, part.mem.size);
> > This could probably be a bit more descriptive, like saying that the
> > fwlog seems to be corrupt because the address in the linked list can't
> > be used for setting the partition.
> Ok, will add the comment.
Maybe you could add something in the debug message itself? That way it
would be clear in the log and in the code at the same time. ;)
> >> diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
> >> index f48530f..5897747 100644
> >> --- a/drivers/net/wireless/ti/wlcore/io.h
> >> +++ b/drivers/net/wireless/ti/wlcore/io.h
> >> @@ -165,8 +165,8 @@ static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr,
> >> int physical;
> >> int addr;
> >>
> >> - /* Addresses are stored internally as addresses to 32 bytes blocks */
> >> - addr = hwaddr<< 5;
> >> + /* Convert from FW internal address which is chip arch dependent */
> >> + addr = wl->ops->convert_hwaddr(wl, hwaddr);
> > This could be more descriptive. As I understand, this is converting an
> > internal representation of pointers in the hardware to an address that
> > can be used to set the partitions.
> >
> Ok, will add more comment: convert to address used for setting partition
> and reading over SDIO
Yes, that would be nice, thanks!
--
Luca.
Hi Alberto,
On Mon, 2012-12-10 at 17:24 +0000, Alberto Garau wrote:
> I’m trying to make working the WL1271 TI Murata chip with our custom board. The SPI driver seems to be running but I cannot scan from our Wifi Network.
>
> After booting the board I’m doing:
>
> • insmod /media/red/root/wl1271/wl1271.ko
> • insmod /media/red/root/wl1271/wl1271_spi.ko
> • iwconfig wlan0 mode managed
> • iwconfig wlan0 essid xxxxxxx
> • ifconfig wlan0 hw ether 00:80:E1:12:26:17
> • ifconfig wlan0 192.168.40.100 netmask 255.255.255.0 up
>
> Then I botain:
>
> chip_id read from memory: 04030111
> wl1271_fetch_firmware - fetching firmware wl1271-fw.bin
> wl1271_fetch_nvs - fetching firmware wl1271-nvs.bin
> wl1271: firmware booted (Rev 6.1.0.50.350)
>
> but unfortunately the when I run “iwlist wlan0 scan”
>
> I obtain “wlan0 No scan results”
>
>
> Could you please help us in fixing this issue ?
This could be many different things. The first thing that comes to my
mind is that the scan results are the first thing that comes as a real
interrupt (before this all the interrupts are polled). So are you sure
the interrupt line is working properly?
--
Luca.
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> From: Eliad Peller <[email protected]>
>
> ACX_PEER_CAP command is just ACX_PEER_HT_CAP, but allows
> configuring the peer's support rates as well.
>
> this is needed because we start the station role when
> the remote rates are not known yet.
>
> the two commands should be unified in future fw versions,
> but for now add a new set_peer_cap per-hw op, that will
> use ACX_PEER_CAP for 18xx, and ACX_PEER_HT_CAP for 12xx.
>
> Signed-off-by: Eliad Peller <[email protected]>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
[...]
> diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
> index 0218edd..951b88c 100644
> --- a/drivers/net/wireless/ti/wl12xx/main.c
> +++ b/drivers/net/wireless/ti/wl12xx/main.c
> @@ -1623,6 +1623,15 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
> return wlcore_set_key(wl, cmd, vif, sta, key_conf);
> }
>
> +static int wl12xx_set_peer_cap(struct wl1271 *wl,
> + struct ieee80211_sta_ht_cap *ht_cap,
> + bool allow_ht_operation,
> + u32 rate_set, u8 hlid)
> +{
> + return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation,
> + hlid);
> +}
> +
This is quite ugly, because you're just calling wlcore back to perform
this op.
> diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
> index 801d8af..a169bb5 100644
> --- a/drivers/net/wireless/ti/wl18xx/acx.c
> +++ b/drivers/net/wireless/ti/wl18xx/acx.c
> @@ -140,3 +140,57 @@ out:
> return ret;
>
> }
> +
> +/*
> + * this command is basically the same as wl1271_acx_ht_capabilities,
> + * with the addition of supported rates. they should be unified in
> + * the next fw api change
> + */
Has this been already unified? What's the status or plan for this new
API change? I guess we're only waiting for the change in the wl12xx
firmware to catch up with wl18xx, right?
> diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
> index b57e348..0e636de 100644
> --- a/drivers/net/wireless/ti/wl18xx/acx.h
> +++ b/drivers/net/wireless/ti/wl18xx/acx.h
> @@ -297,11 +297,44 @@ struct wlcore_peer_ht_operation_mode {
> u8 padding[2];
> };
>
> +/*
> + * ACX_PEER_CAP
> + * this struct is very similar to wl1271_acx_ht_capabilities, with the
> + * addition of supported rates
> + */
> +struct wlcore_acx_peer_cap {
> + struct acx_header header;
> +
> + /* bitmask of capability bits supported by the peer */
> + __le32 ht_capabilites;
> +
> + /* rates supported by the remote peer */
> + __le32 supported_rates;
> +
> + /* Indicates to which link these capabilities apply. */
> + u8 hlid;
> +
> + /*
> + * This the maximum A-MPDU length supported by the AP. The FW may not
> + * exceed this length when sending A-MPDUs
> + */
> + u8 ampdu_max_length;
> +
> + /* This is the minimal spacing required when sending A-MPDUs to the AP*/
> + u8 ampdu_min_spacing;
> +
> + u8 padding;
> +} __packed;
If we're sure this will be also changed in the wl12xx firmware, maybe
this could already be in the wlcore acx.h? Otherwise we'll just be
moving this around...
> diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
> index 71137aa..ecdd5e6 100644
> --- a/drivers/net/wireless/ti/wlcore/wlcore.h
> +++ b/drivers/net/wireless/ti/wlcore/wlcore.h
> @@ -106,6 +106,11 @@ struct wlcore_ops {
> u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
> void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
> struct ieee80211_sta *sta, u32 changed);
> + int (*set_peer_cap)(struct wl1271 *wl,
> + struct ieee80211_sta_ht_cap *ht_cap,
> + bool allow_ht_operation,
> + u32 rate_set, u8 hlid);
> +
I think it would be much nicer to do all this with a quirk instead.
Then we don't need to add ops that will have to be removed later and
make all this ping-pong of calls between the modules.
--
Luca.
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> From: Eyal Shapira <[email protected]>
>
> There's a limit on scan dwell times of max 30ms in order
> to avoid degrading voip traffic which could be going on
> while scanning. However these dwell times increase the
> chance of missing out on nearby APs leading to partial
> scan results. Allow configuration of longer dwell times
> in case there no active interface (i.e. no STA associated
> or AP up).
>
> [Arik - count started vifs using an in-driver function]
>
> Signed-off-by: Eyal Shapira <[email protected]>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
[...]
> diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h
> index ad15cae..a4eb14c 100644
> --- a/drivers/net/wireless/ti/wlcore/conf.h
> +++ b/drivers/net/wireless/ti/wlcore/conf.h
> @@ -1097,6 +1097,24 @@ struct conf_scan_settings {
> */
> u32 max_dwell_time_active;
>
> + /*
> + * The minimum time to wait on each channel for active scans
> + * when there's a concurrent active interface. This should
> + * lower than min_dwell_time_active usually in order to avoid
> + * interfering with possible voip traffic on another interface.
> + *
> + * Range: u32 tu/1000
> + */
> + u32 min_dwell_time_active_conc;
> +
> + /*
> + * The maximum time to wait on each channel for active scans
> + * See explanation about min_dwell_time_active_conc
> + *
> + * Range: u32 tu/1000
> + */
> + u32 max_dwell_time_active_conc;
> +
IMO it would have been nicer to keep the existing ones as they are and
not change the semantics. Then add the new ones with another name.
Maybe something like "max_dwell_time_active_long", which is more
generic.
It is possible that we will find more scenarios where this long scans
could be used (eg. if it would be possible to identify whether there are
any low latency TIDs running or not).
Also, the "concurrent" name here sounds strange, because the first thing
that comes to mind is concurrent scans and not started vifs.
--
Luca.
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> From: Igal Chernobelsky <[email protected]>
>
> FW memory block size and FW log end marker parameters
> are added to wl structure and are initialized per
> chip architecture. convert_hwaddr hw operation is added
> to convert chip dependent FW internal address.
> Copy from FW log is also simplified to copy the entire
> memory block as FW logger utility is repsponsible
> for parsing of FW log content.
>
> Signed-off-by: Igal Chernobelsky <[email protected]>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
This commit log explains what has been done, which can quite easily be
see in the patch itself. That's okay, but what I'm missing here is the
explanation *why* this needs to be done.
> diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
> index 951b88c..5e3c808 100644
> --- a/drivers/net/wireless/ti/wl12xx/main.c
> +++ b/drivers/net/wireless/ti/wl12xx/main.c
> @@ -706,6 +706,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
> goto out;
> }
>
> + wl->fw_mem_block_size = 256;
> + wl->fwlog_end = 0x2000000;
This value used to be in a macro before (WLCORE_FW_LOG_END), why kill
it? It should just be renamed to WL12XX_FW_LOG_END and a new one be
created for WL18XX.
> @@ -1632,6 +1635,11 @@ static int wl12xx_set_peer_cap(struct wl1271 *wl,
> hlid);
> }
>
> +static u32 wl12xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
> +{
> + return hwaddr << 5;
> +}
There was a good comment about this calculation before, it should be
moved here instead of deleted.
> @@ -1669,6 +1677,7 @@ static struct wlcore_ops wl12xx_ops = {
> .channel_switch = wl12xx_cmd_channel_switch,
> .pre_pkt_send = NULL,
> .set_peer_cap = wl12xx_set_peer_cap,
> + .convert_hwaddr = wl12xx_convert_hwaddr,
No need to break the alignment here.
> static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
> diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
> index df8de71..d806241 100644
> --- a/drivers/net/wireless/ti/wl18xx/main.c
> +++ b/drivers/net/wireless/ti/wl18xx/main.c
> @@ -667,6 +667,9 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
> goto out;
> }
>
> + wl->fw_mem_block_size = 272;
> + wl->fwlog_end = 0x40000000;
Again, the magic number here can be avoided.
> @@ -1423,6 +1426,11 @@ static int wl18xx_set_peer_cap(struct wl1271 *wl,
> rate_set, hlid);
> }
>
> +static u32 wl18xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
> +{
> + return hwaddr & ~0x80000000;
> +}
A small explanation here would be nice.
[...]
> /* Traverse the memory blocks linked list */
> do {
> - memset(block, 0, WL12XX_HW_BLOCK_SIZE);
> - ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
> - false);
> + part.mem.start = wlcore_hw_convert_hwaddr(wl, addr);
> + part.mem.size = PAGE_SIZE;
> +
> + ret = wlcore_set_partition(wl, &part);
> + if (ret < 0) {
> + wl1271_error("%s: set_partition start=0x%X size=%d",
> + __func__, part.mem.start, part.mem.size);
This could probably be a bit more descriptive, like saying that the
fwlog seems to be corrupt because the address in the linked list can't
be used for setting the partition.
> diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
> index f48530f..5897747 100644
> --- a/drivers/net/wireless/ti/wlcore/io.h
> +++ b/drivers/net/wireless/ti/wlcore/io.h
> @@ -165,8 +165,8 @@ static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr,
> int physical;
> int addr;
>
> - /* Addresses are stored internally as addresses to 32 bytes blocks */
> - addr = hwaddr << 5;
> + /* Convert from FW internal address which is chip arch dependent */
> + addr = wl->ops->convert_hwaddr(wl, hwaddr);
This could be more descriptive. As I understand, this is converting an
internal representation of pointers in the hardware to an address that
can be used to set the partitions.
> diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
> index a664662..a8647bd 100644
> --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
> +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
> @@ -523,6 +523,4 @@ void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
> #define HW_HT_RATES_OFFSET 16
> #define HW_MIMO_RATES_OFFSET 24
>
> -#define WL12XX_HW_BLOCK_SIZE 256
I think this should also be created separately for wl12xx and wl18xx
instead of deleting the macro and hardcoding the values.
--
Luca.
On Tue, 2012-12-11 at 12:28 +0000, Alberto Garau wrote:
> Thanks Luca,
>
> configuring
>
> board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */
>
> gave me the possibility to scan network but only for an essid on channel1 (delivered from one AP).
Great! This is good progress. :)
> I couldn't scan others essids on other channels (for example channel 6) and I don't know why.
>
> Have you got any idea about it ?
Next I'd recommend you to start using the iw tool instead of iwlist and
friends, so things are more predictable and I can help you more easily.
--
Luca.
On Wed, 2012-12-05 at 12:33 +0200, Eliad Peller wrote:
> On Wed, Dec 5, 2012 at 12:22 PM, Luciano Coelho <[email protected]> wrote:
> > On Wed, 2012-12-05 at 12:17 +0200, Eliad Peller wrote:
> >> On Wed, Dec 5, 2012 at 11:35 AM, Luciano Coelho <[email protected]> wrote:
> >> > On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> >> >> From: Eliad Peller <[email protected]>
> >> >>
> >> >> ACX_PEER_CAP command is just ACX_PEER_HT_CAP, but allows
> >> >> configuring the peer's support rates as well.
> >> >>
> >> >> this is needed because we start the station role when
> >> >> the remote rates are not known yet.
> >> >>
> >> >> the two commands should be unified in future fw versions,
> >> >> but for now add a new set_peer_cap per-hw op, that will
> >> >> use ACX_PEER_CAP for 18xx, and ACX_PEER_HT_CAP for 12xx.
> >> >>
> >> >> Signed-off-by: Eliad Peller <[email protected]>
> >> >> Signed-off-by: Arik Nemtsov <[email protected]>
> >> >> ---
> >> >
> >> > [...]
> >> >
> >> >> diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
> >> >> index 71137aa..ecdd5e6 100644
> >> >> --- a/drivers/net/wireless/ti/wlcore/wlcore.h
> >> >> +++ b/drivers/net/wireless/ti/wlcore/wlcore.h
> >> >> @@ -106,6 +106,11 @@ struct wlcore_ops {
> >> >> u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
> >> >> void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
> >> >> struct ieee80211_sta *sta, u32 changed);
> >> >> + int (*set_peer_cap)(struct wl1271 *wl,
> >> >> + struct ieee80211_sta_ht_cap *ht_cap,
> >> >> + bool allow_ht_operation,
> >> >> + u32 rate_set, u8 hlid);
> >> >> +
> >> >
> >> > I think it would be much nicer to do all this with a quirk instead.
> >> > Then we don't need to add ops that will have to be removed later and
> >> > make all this ping-pong of calls between the modules.
> >> >
> >> i'm not sure what do you mean by using a quirk here.
> >> currently, this is 18xx-specific command, so we need this op.
> >
> > I meant that the new ACX could be fully implemented in wlcore (because
> > the expectation was that it would also become available in wl12xx in the
> > future) and we would have a quirk to tell wlcore not to use the new ACX
> > for wl12xx until it becomes available (when we would disable the quirk).
> >
> well, i don't think it fits our current abstraction.
> e.g. ACX_PEER_CAP is defined only in 18xx, so it means we'll have to
> separate the 18xx-specific commands into 2 enums.
Oh, crap! Now I see that this is already in the wl18xx-specific acx
enum.
> i agree this is all pretty ugly, but these are the fw interfaces that
> we were given...
Yes, it's very annoying. No matter how many zillions of times we ask
them to at least think about API consistency between the two firmwares.
But no, that seems to be way too difficult... :(
> > With the quirk, we could even continue supporting older wl12xx firmware
> > versions quite easily.
> we already support it quite easily...
Ahm, yeah there would be other ways to support older firmwares, but I
was thinking about checking the FW version and setting the quirk
accordingly (as we've already done in the past).
> i suggest keeping it that way for now, and if this command will be
> implemented in 12xx as well, we can easily remove this op, as you
> suggested.
I agree. In any case, that won't be 100% straight-forward, because the
new ACX is in the wl18xx-specific range. So we would probably have to
break both firmware APIs again to be able to use common code for
both. :(
I'll take this in as it is.
--
Luca.
On Fri, Dec 7, 2012 at 2:19 PM, Luciano Coelho <[email protected]> wrote:
> On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
>> Only allow a PSM STA to congest FW memory when it is the single active
>> link. Being a single STA doesn't imply a single link - there might be
>> other links on other roles.
>>
>> Signed-off-by: Arik Nemtsov <[email protected]>
>> ---
>
> [...]
>
>> diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
>> index 1fbee0d..28a3027 100644
>> --- a/drivers/net/wireless/ti/wlcore/cmd.c
>> +++ b/drivers/net/wireless/ti/wlcore/cmd.c
>> @@ -328,6 +328,8 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
>> wl->fw_status_2->counters.tx_lnk_free_pkts[link];
>> wl->links[link].wlvif = wlvif;
>> *hlid = link;
>> +
>> + wl->active_link_count++;
>> return 0;
>> }
>>
>> @@ -357,6 +359,8 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
>> wl->links[*hlid].wlvif = NULL;
>>
>> *hlid = WL12XX_INVALID_LINK_ID;
>> + wl->active_link_count--;
>> + WARN_ON(wl->active_link_count < 0);
>
> This could be WARN_ON_ONCE(). If we hit this once, it's highly likely
> that we will keep hitting it later on, unless we have another bug that
> would cancel this one out. ;)
>
> I can convert this myself if you agree.
Sounds right. Thanks.
On Tue, 2012-12-11 at 10:35 +0000, Alberto Garau wrote:
> That's an *ancient* kernel. :( Any chance you can try it with a newer kernel?
>
> Unortunately not, that's our production kernel.
Even if you can't use it in real life, it could be worth trying a newer
kernel if you keep getting problems with that old one. You could also
try compat-wireless to get a newer wireless subsystem, at least.
> > Any other idea about why the scan command it's not properly working ?
>
> Another common problem is the clock settings. Are you sure the correct value for board_ref_clock in your board file?
>
> Are you talking about "wl->ref_clock = pdata->board_ref_clock;" in the probe ? Which value should I put for 38.4MHz due to the fact that it is an integer parameter ?
Yes, that's the value I'm talking about. You should put it in your
boardfile, something like this (from panda):
static struct wl12xx_platform_data omap_panda_wlan_data __initdata = {
.board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */
};
You can find these values in the include/linux/wl12xx.h file.
--
Luca.
On Wed, Dec 5, 2012 at 11:35 AM, Luciano Coelho <[email protected]> wrote:
> On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
>> From: Eliad Peller <[email protected]>
>>
>> ACX_PEER_CAP command is just ACX_PEER_HT_CAP, but allows
>> configuring the peer's support rates as well.
>>
>> this is needed because we start the station role when
>> the remote rates are not known yet.
>>
>> the two commands should be unified in future fw versions,
>> but for now add a new set_peer_cap per-hw op, that will
>> use ACX_PEER_CAP for 18xx, and ACX_PEER_HT_CAP for 12xx.
>>
>> Signed-off-by: Eliad Peller <[email protected]>
>> Signed-off-by: Arik Nemtsov <[email protected]>
>> ---
>
> [...]
>
>> diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
>> index 0218edd..951b88c 100644
>> --- a/drivers/net/wireless/ti/wl12xx/main.c
>> +++ b/drivers/net/wireless/ti/wl12xx/main.c
>> @@ -1623,6 +1623,15 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
>> return wlcore_set_key(wl, cmd, vif, sta, key_conf);
>> }
>>
>> +static int wl12xx_set_peer_cap(struct wl1271 *wl,
>> + struct ieee80211_sta_ht_cap *ht_cap,
>> + bool allow_ht_operation,
>> + u32 rate_set, u8 hlid)
>> +{
>> + return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation,
>> + hlid);
>> +}
>> +
>
> This is quite ugly, because you're just calling wlcore back to perform
> this op.
>
right. but that's how it's been done in other places as well (e.g.
wl12xx_set_key).
>
>> diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
>> index 801d8af..a169bb5 100644
>> --- a/drivers/net/wireless/ti/wl18xx/acx.c
>> +++ b/drivers/net/wireless/ti/wl18xx/acx.c
>> @@ -140,3 +140,57 @@ out:
>> return ret;
>>
>> }
>> +
>> +/*
>> + * this command is basically the same as wl1271_acx_ht_capabilities,
>> + * with the addition of supported rates. they should be unified in
>> + * the next fw api change
>> + */
>
> Has this been already unified? What's the status or plan for this new
> API change? I guess we're only waiting for the change in the wl12xx
> firmware to catch up with wl18xx, right?
>
it hasn't been unified yet.
i don't know what is the future plan...
>
>> diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
>> index b57e348..0e636de 100644
>> --- a/drivers/net/wireless/ti/wl18xx/acx.h
>> +++ b/drivers/net/wireless/ti/wl18xx/acx.h
>> @@ -297,11 +297,44 @@ struct wlcore_peer_ht_operation_mode {
>> u8 padding[2];
>> };
>>
>> +/*
>> + * ACX_PEER_CAP
>> + * this struct is very similar to wl1271_acx_ht_capabilities, with the
>> + * addition of supported rates
>> + */
>> +struct wlcore_acx_peer_cap {
>> + struct acx_header header;
>> +
>> + /* bitmask of capability bits supported by the peer */
>> + __le32 ht_capabilites;
>> +
>> + /* rates supported by the remote peer */
>> + __le32 supported_rates;
>> +
>> + /* Indicates to which link these capabilities apply. */
>> + u8 hlid;
>> +
>> + /*
>> + * This the maximum A-MPDU length supported by the AP. The FW may not
>> + * exceed this length when sending A-MPDUs
>> + */
>> + u8 ampdu_max_length;
>> +
>> + /* This is the minimal spacing required when sending A-MPDUs to the AP*/
>> + u8 ampdu_min_spacing;
>> +
>> + u8 padding;
>> +} __packed;
>
> If we're sure this will be also changed in the wl12xx firmware, maybe
> this could already be in the wlcore acx.h? Otherwise we'll just be
> moving this around...
>
unfortunately, we can't really be sure about it :/
>
>> diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
>> index 71137aa..ecdd5e6 100644
>> --- a/drivers/net/wireless/ti/wlcore/wlcore.h
>> +++ b/drivers/net/wireless/ti/wlcore/wlcore.h
>> @@ -106,6 +106,11 @@ struct wlcore_ops {
>> u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
>> void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
>> struct ieee80211_sta *sta, u32 changed);
>> + int (*set_peer_cap)(struct wl1271 *wl,
>> + struct ieee80211_sta_ht_cap *ht_cap,
>> + bool allow_ht_operation,
>> + u32 rate_set, u8 hlid);
>> +
>
> I think it would be much nicer to do all this with a quirk instead.
> Then we don't need to add ops that will have to be removed later and
> make all this ping-pong of calls between the modules.
>
i'm not sure what do you mean by using a quirk here.
currently, this is 18xx-specific command, so we need this op.
Eliad.
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> Treat a single connected STA in PSM as a slow link and regulate Tx speed
> according to slow link priority/stop thresholds.
> This allows us to avoid flooding the FW, while delivering decent
> throughput to a peer in forced-PSM.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
> drivers/net/wireless/ti/wl18xx/main.c | 14 ++++++++------
> 1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
> index 3836dbd..ada4616 100644
> --- a/drivers/net/wireless/ti/wl18xx/main.c
> +++ b/drivers/net/wireless/ti/wl18xx/main.c
> @@ -1446,10 +1446,11 @@ static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
> return false;
>
> /* the priority thresholds are taken from FW */
> - if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
> - thold = status_priv->tx_fast_link_prio_threshold;
> - else
> + if (!test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) ||
> + test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
> thold = status_priv->tx_slow_link_prio_threshold;
> + else
> + thold = status_priv->tx_fast_link_prio_threshold;
Am I missing something or is this kind of inverted logic? For some
reason I always think it is simpler to have something like this:
if (fast_link && !ps)
thold = fast;
else
thold = slow;
But maybe it's just me...
--
Luca.
On Fri, Dec 7, 2012 at 11:23 AM, Luciano Coelho <[email protected]> wrote:
> On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
>> Update the 18xx FW status private part to include Tx related link
>> priorities. Introduce new HW ops to determine link priority per chip
>> family.
>>
>> For 18xx the changes are:
>> - Suspended links are at most low priority and Tx for them is stopped
>> beyond the suspend threshold.
>> - Active links now get their thresholds directly from FW
>> - There's a new "stop" threshold for active links, at which point a link
>> stops receiving new packets.
>>
>> Update the min 18xx FW version required to make sure suspended links
>> bitmap is advertised by the FW.
>
> This doesn't apply anymore, I'll remove it.
Sounds good. Thanks.
>
>
>> Signed-off-by: Arik Nemtsov <[email protected]>
>> ---
>
> Otherwise this patch looks good!
>
> Just to understand better, why is the firmware deciding on the
> thresholds? Does it make some internal magic itself to know the number
> of links (including multi-channel) and adjust the thresholds
> accordingly? Isn't this something we could (or should?) do in the kernel
> side?
Yes the FW decides on the thresholds based on the multi-channel state.
Basically links are suspended and resumed all the time.
The FW knows some stuff we don't know, for instance the real speed of
the link and if a BA session is ongoing. Makes it easy for them to
tweak these values.
Of course they could export all the information, but I don't think it
really matters one way or the other. It works well this way.
Arik
On Wed, 2012-12-05 at 14:19 +0200, Eyal Shapira wrote:
> On 5 December 2012 13:21, Luciano Coelho <[email protected]> wrote:
> >
> >
> > IMO it would have been nicer to keep the existing ones as they are and
> > not change the semantics. Then add the new ones with another name.
> > Maybe something like "max_dwell_time_active_long", which is more
> > generic.
> >
> > It is possible that we will find more scenarios where this long scans
> > could be used (eg. if it would be possible to identify whether there are
> > any low latency TIDs running or not).
> >
>
> Sure. I'll respin it.
BTW, please take Arik's v2 which was sent to the list on Nov 30th before
you make your updates. It has a mac80211 API change taken into account.
--
Luca.
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> Update the 18xx FW status private part to include Tx related link
> priorities. Introduce new HW ops to determine link priority per chip
> family.
>
> For 18xx the changes are:
> - Suspended links are at most low priority and Tx for them is stopped
> beyond the suspend threshold.
> - Active links now get their thresholds directly from FW
> - There's a new "stop" threshold for active links, at which point a link
> stops receiving new packets.
>
> Update the min 18xx FW version required to make sure suspended links
> bitmap is advertised by the FW.
This doesn't apply anymore, I'll remove it.
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
Otherwise this patch looks good!
Just to understand better, why is the firmware deciding on the
thresholds? Does it make some internal magic itself to know the number
of links (including multi-channel) and adjust the thresholds
accordingly? Isn't this something we could (or should?) do in the kernel
side?
--
Luca
SGkgTHVjYSwNCg0KLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCkZyb206IEx1Y2lhbm8gQ29l
bGhvIFttYWlsdG86Y29lbGhvQHRpLmNvbV0gDQpTZW50OiBtYXJ0ZWTDrCAxMSBkaWNlbWJyZSAy
MDEyIDEwOjM0DQpUbzogQWxiZXJ0byBHYXJhdQ0KQ2M6IGxpbnV4LXdpcmVsZXNzQHZnZXIua2Vy
bmVsLm9yZzsgSWRvIFlhcml2OyBBcmlrIE5lbXRzb3YNClN1YmplY3Q6IFJlOiB3bDEyeHggb3Zl
ciBzcGkgd2l0aCBubyBzY2FuIHJlc3VsdHMNCg0KT24gVHVlLCAyMDEyLTEyLTExIGF0IDA5OjE2
ICswMDAwLCBBbGJlcnRvIEdhcmF1IHdyb3RlOg0KPiBIaSBMdWNhLA0KPiANCj4gLS0tLS1Pcmln
aW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogTHVjaWFubyBDb2VsaG8gW21haWx0bzpjb2VsaG9A
dGkuY29tXQ0KPiBTZW50OiBsdW5lZMOsIDEwIGRpY2VtYnJlIDIwMTIgMTg6NTANCj4gVG86IEFs
YmVydG8gR2FyYXUNCj4gQ2M6IGxpbnV4LXdpcmVsZXNzQHZnZXIua2VybmVsLm9yZzsgSWRvIFlh
cml2OyBBcmlrIE5lbXRzb3YNCj4gU3ViamVjdDogd2wxMnh4IG92ZXIgc3BpIHdpdGggbm8gc2Nh
biByZXN1bHRzICh3YXM6IFJlOiBbUEFUQ0ggMjAvMjBdIA0KPiB3bGNvcmU6IEFsd2F5cyBwYXNz
IERNQS1hYmxlIGJ1ZmZlcnMgdG8gbW1jIGZ1bmN0aW9ucykNCj4gDQo+IEhpIEFsYmVydG8sDQo+
IA0KPiBPbiBNb24sIDIwMTItMTItMTAgYXQgMTc6MjQgKzAwMDAsIEFsYmVydG8gR2FyYXUgd3Jv
dGU6DQo+ID4gSeKAmW0gdHJ5aW5nIHRvIG1ha2Ugd29ya2luZyB0aGUgV0wxMjcxIFRJIE11cmF0
YSBjaGlwIHdpdGggb3VyIGN1c3RvbSBib2FyZC4gIFRoZSBTUEkgZHJpdmVyIHNlZW1zIHRvIGJl
IHJ1bm5pbmcgYnV0IEkgY2Fubm90IHNjYW4gZnJvbSBvdXIgV2lmaSBOZXR3b3JrLiANCj4gPiAN
Cj4gPiBBZnRlciBib290aW5nIHRoZSBib2FyZCBJ4oCZbSBkb2luZzoNCj4gPiANCj4gPiDigKIJ
aW5zbW9kIC9tZWRpYS9yZWQvcm9vdC93bDEyNzEvd2wxMjcxLmtvDQo+ID4g4oCiCWluc21vZCAv
bWVkaWEvcmVkL3Jvb3Qvd2wxMjcxL3dsMTI3MV9zcGkua28NCj4gPiDigKIJaXdjb25maWcgd2xh
bjAgbW9kZSBtYW5hZ2VkDQo+ID4g4oCiCWl3Y29uZmlnIHdsYW4wIGVzc2lkIHh4eHh4eHgNCj4g
PiDigKIJaWZjb25maWcgd2xhbjAgaHcgZXRoZXIgMDA6ODA6RTE6MTI6MjY6MTcgDQo+ID4g4oCi
CWlmY29uZmlnIHdsYW4wIDE5Mi4xNjguNDAuMTAwIG5ldG1hc2sgMjU1LjI1NS4yNTUuMCB1cA0K
PiA+IA0KPiA+IFRoZW4gSSBib3RhaW46DQo+ID4gDQo+ID4gY2hpcF9pZCByZWFkIGZyb20gbWVt
b3J5OiAwNDAzMDExMQ0KPiA+IHdsMTI3MV9mZXRjaF9maXJtd2FyZSAtIGZldGNoaW5nIGZpcm13
YXJlIHdsMTI3MS1mdy5iaW4gDQo+ID4gd2wxMjcxX2ZldGNoX252cyAtIGZldGNoaW5nIGZpcm13
YXJlIHdsMTI3MS1udnMuYmluDQo+ID4gd2wxMjcxOiBmaXJtd2FyZSBib290ZWQgKFJldiA2LjEu
MC41MC4zNTApDQo+ID4gDQo+ID4gYnV0IHVuZm9ydHVuYXRlbHkgdGhlIHdoZW4gSSBydW4g4oCc
aXdsaXN0IHdsYW4wIHNjYW7igJ0NCj4gPiANCj4gPiBJIG9idGFpbiDigJx3bGFuMCBObyBzY2Fu
IHJlc3VsdHPigJ0NCj4gPiANCj4gPiANCj4gPiBDb3VsZCB5b3UgcGxlYXNlIGhlbHAgdXMgaW4g
Zml4aW5nIHRoaXMgaXNzdWUgPw0KPiANCj4gVGhpcyBjb3VsZCBiZSBtYW55IGRpZmZlcmVudCB0
aGluZ3MuICBUaGUgZmlyc3QgdGhpbmcgdGhhdCBjb21lcyB0byBteSANCj4gbWluZCBpcyB0aGF0
IHRoZSBzY2FuIHJlc3VsdHMgYXJlIHRoZSBmaXJzdCB0aGluZyB0aGF0IGNvbWVzIGFzIGEgcmVh
bCANCj4gaW50ZXJydXB0IChiZWZvcmUgdGhpcyBhbGwgdGhlIGludGVycnVwdHMgYXJlIHBvbGxl
ZCkuICBTbyBhcmUgeW91IA0KPiBzdXJlIHRoZSBpbnRlcnJ1cHQgbGluZSBpcyB3b3JraW5nIHBy
b3Blcmx5Pw0KPiANCj4gVGhlIGludGVycnVwdCBsaW5lIGl0IHNlZW1zIHRvIHdvcmsgcHJvcGVy
bHkuIEkgcHV0IGEgcHJpbnRrIGluIHRoZSANCj4gaW50ZXJydXB0IGhhbmRsZXIgYW5kIEkgc2Vl
IGl0IGFjdGl2YXRlZA0KDQpPay4NCg0KDQo+IER1cmluZyB0aGUgZmlybXdhcmUgZmV0Y2ggYW5k
IHdoZW4gSSBwZXJmb3JtIHRoZSAiaXdsaXN0YSB3bGFuMCBzY2FuIi4NCj4gSSBrZXB0IHRoZSBJ
UlEgYXNzb2NpYXRpb24gdG8gSVJRX1RZUEVfRURHRV9SSVNJTkcgYXMgeW91ciBzb3VyY2UgY29k
ZSANCj4gd2FzIGluIDIuNi4zNyBrZXJuZWwuDQoNClRoYXQncyBhbiAqYW5jaWVudCoga2VybmVs
LiA6KCBBbnkgY2hhbmNlIHlvdSBjYW4gdHJ5IGl0IHdpdGggYSBuZXdlciBrZXJuZWw/DQoNClVu
b3J0dW5hdGVseSBub3QsIHRoYXQncyBvdXIgcHJvZHVjdGlvbiBrZXJuZWwuIA0KDQoNCj4gQW55
IG90aGVyIGlkZWEgYWJvdXQgd2h5IHRoZSBzY2FuIGNvbW1hbmQgaXQncyBub3QgcHJvcGVybHkg
d29ya2luZyA/DQoNCkFub3RoZXIgY29tbW9uIHByb2JsZW0gaXMgdGhlIGNsb2NrIHNldHRpbmdz
LiAgQXJlIHlvdSBzdXJlIHRoZSBjb3JyZWN0IHZhbHVlIGZvciBib2FyZF9yZWZfY2xvY2sgaW4g
eW91ciBib2FyZCBmaWxlPw0KDQpBcmUgeW91IHRhbGtpbmcgYWJvdXQgIndsLT5yZWZfY2xvY2sg
PSBwZGF0YS0+Ym9hcmRfcmVmX2Nsb2NrOyIgaW4gdGhlIHByb2JlID8gV2hpY2ggdmFsdWUgc2hv
dWxkIEkgcHV0IGZvciAzOC40TUh6IGR1ZSB0byB0aGUgZmFjdCB0aGF0IGl0IGlzIGFuIGludGVn
ZXIgcGFyYW1ldGVyID8NCg0KVGhhbmtzIGluIGFkdmFuY2UgDQoNCkFsYmVydG8NCg0KLS0NCkx1
Y2EuDQoNCg0K
On Wed, Dec 5, 2012 at 12:22 PM, Luciano Coelho <[email protected]> wrote:
> On Wed, 2012-12-05 at 12:17 +0200, Eliad Peller wrote:
>> On Wed, Dec 5, 2012 at 11:35 AM, Luciano Coelho <[email protected]> wrote:
>> > On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
>> >> From: Eliad Peller <[email protected]>
>> >>
>> >> ACX_PEER_CAP command is just ACX_PEER_HT_CAP, but allows
>> >> configuring the peer's support rates as well.
>> >>
>> >> this is needed because we start the station role when
>> >> the remote rates are not known yet.
>> >>
>> >> the two commands should be unified in future fw versions,
>> >> but for now add a new set_peer_cap per-hw op, that will
>> >> use ACX_PEER_CAP for 18xx, and ACX_PEER_HT_CAP for 12xx.
>> >>
>> >> Signed-off-by: Eliad Peller <[email protected]>
>> >> Signed-off-by: Arik Nemtsov <[email protected]>
>> >> ---
>> >
>> > [...]
>> >
>> >> diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
>> >> index 71137aa..ecdd5e6 100644
>> >> --- a/drivers/net/wireless/ti/wlcore/wlcore.h
>> >> +++ b/drivers/net/wireless/ti/wlcore/wlcore.h
>> >> @@ -106,6 +106,11 @@ struct wlcore_ops {
>> >> u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
>> >> void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
>> >> struct ieee80211_sta *sta, u32 changed);
>> >> + int (*set_peer_cap)(struct wl1271 *wl,
>> >> + struct ieee80211_sta_ht_cap *ht_cap,
>> >> + bool allow_ht_operation,
>> >> + u32 rate_set, u8 hlid);
>> >> +
>> >
>> > I think it would be much nicer to do all this with a quirk instead.
>> > Then we don't need to add ops that will have to be removed later and
>> > make all this ping-pong of calls between the modules.
>> >
>> i'm not sure what do you mean by using a quirk here.
>> currently, this is 18xx-specific command, so we need this op.
>
> I meant that the new ACX could be fully implemented in wlcore (because
> the expectation was that it would also become available in wl12xx in the
> future) and we would have a quirk to tell wlcore not to use the new ACX
> for wl12xx until it becomes available (when we would disable the quirk).
>
well, i don't think it fits our current abstraction.
e.g. ACX_PEER_CAP is defined only in 18xx, so it means we'll have to
separate the 18xx-specific commands into 2 enums.
i agree this is all pretty ugly, but these are the fw interfaces that
we were given...
> With the quirk, we could even continue supporting older wl12xx firmware
> versions quite easily.
we already support it quite easily...
i suggest keeping it that way for now, and if this command will be
implemented in 12xx as well, we can easily remove this op, as you
suggested.
Eliad.
On Wed, 2012-11-28 at 11:42 +0200, Arik Nemtsov wrote:
> From: Yair Shapira <[email protected]>
>
> We now disable elp sleep during plt mode to allow normal operation of
> plt tools such as calibrator.
>
> Having elp_sleep enabled during plt mode is actually not required and
> in fact it disrupt plt operations such as rx statistics etc...
Has this really been observed in practice? At least what I remember is
that we use CAM power mode in PLT (during init) so we never get to ELP
mode.
> This is based on wl12xx (R5) commit 5cf0fe31ab
This is residue from internal code and is meaningless in the mainline.
--
Luca.
On Tue, 2012-12-11 at 09:16 +0000, Alberto Garau wrote:
> Hi Luca,
>
> -----Original Message-----
> From: Luciano Coelho [mailto:[email protected]]
> Sent: lunedì 10 dicembre 2012 18:50
> To: Alberto Garau
> Cc: [email protected]; Ido Yariv; Arik Nemtsov
> Subject: wl12xx over spi with no scan results (was: Re: [PATCH 20/20] wlcore: Always pass DMA-able buffers to mmc functions)
>
> Hi Alberto,
>
> On Mon, 2012-12-10 at 17:24 +0000, Alberto Garau wrote:
> > I’m trying to make working the WL1271 TI Murata chip with our custom board. The SPI driver seems to be running but I cannot scan from our Wifi Network.
> >
> > After booting the board I’m doing:
> >
> > • insmod /media/red/root/wl1271/wl1271.ko
> > • insmod /media/red/root/wl1271/wl1271_spi.ko
> > • iwconfig wlan0 mode managed
> > • iwconfig wlan0 essid xxxxxxx
> > • ifconfig wlan0 hw ether 00:80:E1:12:26:17
> > • ifconfig wlan0 192.168.40.100 netmask 255.255.255.0 up
> >
> > Then I botain:
> >
> > chip_id read from memory: 04030111
> > wl1271_fetch_firmware - fetching firmware wl1271-fw.bin
> > wl1271_fetch_nvs - fetching firmware wl1271-nvs.bin
> > wl1271: firmware booted (Rev 6.1.0.50.350)
> >
> > but unfortunately the when I run “iwlist wlan0 scan”
> >
> > I obtain “wlan0 No scan results”
> >
> >
> > Could you please help us in fixing this issue ?
>
> This could be many different things. The first thing that comes to my
> mind is that the scan results are the first thing that comes as a real
> interrupt (before this all the interrupts are polled). So are you
> sure the interrupt line is working properly?
>
> The interrupt line it seems to work properly. I put a printk in the
> interrupt handler and I see it activated
Ok.
> During the firmware fetch and when I perform the "iwlista wlan0 scan".
> I kept the IRQ association to IRQ_TYPE_EDGE_RISING as your source code
> was in 2.6.37 kernel.
That's an *ancient* kernel. :( Any chance you can try it with a newer
kernel?
> Any other idea about why the scan command it's not properly working ?
Another common problem is the clock settings. Are you sure the correct
value for board_ref_clock in your board file?
--
Luca.