Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH v2 08/29] wl12xx: configure sleep_policy according to active roles
From: Eliad Peller @ 2011-10-11 10:46 UTC (permalink / raw)
  To: Arik Nemtsov; +Cc: Luciano Coelho, linux-wireless
In-Reply-To: <CA+XVXfdM7=G1YdWVYpzfKajRYu+sAJcfKSFkbtgneUPTPabQ=w@mail.gmail.com>

On Tue, Oct 11, 2011 at 12:16 PM, Arik Nemtsov <anamtsov@gmail.com> wrote:
> On Tue, Oct 11, 2011 at 11:49, Eliad Peller <eliad@wizery.com> wrote:
>> If there is an active AP role, stay always on.
>> Otherwise, allow chip to enter elp.
>>
>> (Note that this is a global configuration, so if the
>> device is already configured according to our policy,
>> we don't have to configure it again)
>>
>> Signed-off-by: Eliad Peller <eliad@wizery.com>
>> ---
>> v2: use ap_count/sta_count instead of iterating
>> +       if (!wl->ap_count) {
>> +               if (is_ap) {
>> +                       /* Configure for power always on */
>> +                       ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
>> +                       if (ret < 0)
>> +                               return ret;
>> +               } else if (!wl->sta_count) {
>> +                       /* Configure for ELP power saving */
>> +                       ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
>> +                       if (ret < 0)
>> +                               return ret;
>> +               }
>> +       }
>
> Probably need to add a symmetric part on remove_interface(). If ap was
> shutdown we can return to normal ELP.
>
right. that's why i added:
+       /*
+        * consider all existing roles before configuring psm.
+        * TODO: reconfigure on interface removal.
+        */

> btw, elp_work() still gets called even in AP-mode. I'm guessing it has
> no effect, but if you want to prevent the SDIO transaction from taking
> place (like you said on IRC), you can check for it :)
> (Just nitpicking here)

we are not in idle-on while beaconing, so elp_work should return
before configuring the chip.

Eliad.

^ permalink raw reply

* [PATCH] iw: fix HT PHY BSS Membership selector value encoding
From: Christian Lamparter @ 2011-10-11 11:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

IEEE 802.11n 7.3.2.2 extended the supported rate IE to
support a special encoding for HT rate support.

iw needs to be updated in order to recognize
the magic value and parse it accordingly.

e.g.:

> Extended supported rates: 63.5* 

now becomes:

> Extended supported rates: HT* 

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
diff --git a/scan.c b/scan.c
index d083591..2220f26 100644
--- a/scan.c
+++ b/scan.c
@@ -158,6 +158,8 @@ static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data)
 	printf("\n");
 }
 
+#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+
 static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data)
 {
 	int i;
@@ -166,7 +168,13 @@ static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data
 
 	for (i = 0; i < len; i++) {
 		int r = data[i] & 0x7f;
-		printf("%d.%d%s ", r/2, 5*(r&1), data[i] & 0x80 ? "*":"");
+
+		if (r == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
+			printf("HT");
+		else
+			printf("%d.%d", r/2, 5*(r&1));
+
+		printf("%s ", data[i] & 0x80 ? "*" : "");
 	}
 	printf("\n");
 }

^ permalink raw reply related

* Re: [PATCH 1/1] ath6kl: Add WSC IE on the associate message
From: Kalle Valo @ 2011-10-11 11:24 UTC (permalink / raw)
  To: Kevin Fang; +Cc: linux-wireless
In-Reply-To: <1317948679-10299-1-git-send-email-kevin.fang@qca.qualcomm.com>

On 10/07/2011 03:51 AM, Kevin Fang wrote:
> For some WPS test items, such as item "5.1.14"
> STAUT must include the WSC IE in the 802.11 Association Request frame.
> Therefore, add the corresponding IE in association message.

Applied, thanks!

Kalle

^ permalink raw reply

* Re: [PATCH] ath6kl: fix null skb dereference in ath6kl_rx()
From: Kalle Valo @ 2011-10-11 11:23 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless
In-Reply-To: <20111006113232.24700.12168.stgit@localhost6.localdomain6>

On 10/06/2011 02:32 PM, Kalle Valo wrote:
> smatch found that skb might be null in some cases in ath6kl_rx():
> 
> ath6kl/txrx.c +1252 ath6kl_rx(222) error: potential null derefence 'skb'.
> 
> This will happen when ath6kl is in AP mode and two clients send traffic
> to each other.

Applied to ath6kl.git.

Kalle

^ permalink raw reply

* [PATCH] mac80211: Populate radiotap header with MCS info for tx'ed frames
From: Helmut Schaa @ 2011-10-11 11:28 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, johannes, Helmut Schaa

mac80211 already filled in the MCS rate info for rx'ed frames but tx'ed
frames that are sent to a monitor interface during the status callback
lack this information.

Add the radiotap fields for MCS info to ieee80211_tx_status_rtap_hdr
and populate them when sending tx'ed frames to the monitors.

One minor flaw is that the radiotap header now includes both, the rate
field and the mcs field. For HT frames the rate field will be zero and
for legacy frames the mcs fields will be zero but still this could
be improved.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
---

Wireshark will display the MCS rate correctly but will show the zero'd rate
field as well with 0Mbps. For legacy frames the MCS field won't be shown
since IEEE80211_RADIOTAP_MCS_HAVE_MCS isn't set. Only the MCS flags will be
shown (all zero of course).

I still think it is justified to use it like this as otherwise we would have
to build the radiotap header in a more generic fashion and we won't be able to
easily catch build bugs like

        BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM !=
                        sizeof(struct ieee80211_tx_status_rtap_hdr));

 include/net/mac80211.h     |    2 +-
 net/mac80211/ieee80211_i.h |    3 +++
 net/mac80211/status.c      |   26 +++++++++++++++++++++-----
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cd108df..a500c7b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2520,7 +2520,7 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
  * The TX headroom reserved by mac80211 for its own tx_status functions.
  * This is enough for the radiotap header.
  */
-#define IEEE80211_TX_STATUS_HEADROOM	13
+#define IEEE80211_TX_STATUS_HEADROOM	16
 
 /**
  * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9fa5f8a..41dc565 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1187,6 +1187,9 @@ struct ieee80211_tx_status_rtap_hdr {
 	u8 padding_for_rate;
 	__le16 tx_flags;
 	u8 data_retries;
+	u8 mcs_known;
+	u8 mcs_flags;
+	u8 mcs;
 } __packed;
 
 
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 864a9c3..34319fe 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -475,7 +475,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 	rthdr->hdr.it_present =
 		cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
 			    (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
-			    (1 << IEEE80211_RADIOTAP_RATE));
+			    (1 << IEEE80211_RADIOTAP_RATE) |
+			    (1 << IEEE80211_RADIOTAP_MCS));
 
 	if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
 	    !is_multicast_ether_addr(hdr->addr1))
@@ -491,10 +492,25 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
 	else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
 		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
-	if (info->status.rates[0].idx >= 0 &&
-	    !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
-		rthdr->rate = sband->bitrates[
-				info->status.rates[0].idx].bitrate / 5;
+	if (info->status.rates[0].idx >= 0) {
+    		if (!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) {
+			/* legacy rate */
+			rthdr->rate = sband->bitrates[
+					info->status.rates[0].idx].bitrate / 5;
+		} else {
+			/* HT rate */
+			rthdr->mcs_known = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
+					   IEEE80211_RADIOTAP_MCS_HAVE_GI |
+			   		   IEEE80211_RADIOTAP_MCS_HAVE_BW;
+			if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
+				rthdr->mcs_flags |= IEEE80211_RADIOTAP_MCS_SGI;
+			if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+				rthdr->mcs_flags |= IEEE80211_RADIOTAP_MCS_BW_40;
+			if (info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)
+				rthdr->mcs_flags |= IEEE80211_RADIOTAP_MCS_FMT_GF;
+			rthdr->mcs = info->status.rates[0].idx;
+		}
+	}
 
 	/* for now report the total retry_count */
 	rthdr->data_retries = retry_count;
-- 
1.7.3.4


^ permalink raw reply related

* Re: [PATCH] mac80211: Populate radiotap header with MCS info for tx'ed frames
From: Johannes Berg @ 2011-10-11 11:35 UTC (permalink / raw)
  To: Helmut Schaa; +Cc: linux-wireless, linville
In-Reply-To: <1318332535-8815-1-git-send-email-helmut.schaa@googlemail.com>

On Tue, 2011-10-11 at 13:28 +0200, Helmut Schaa wrote:
> mac80211 already filled in the MCS rate info for rx'ed frames but tx'ed
> frames that are sent to a monitor interface during the status callback
> lack this information.
> 
> Add the radiotap fields for MCS info to ieee80211_tx_status_rtap_hdr
> and populate them when sending tx'ed frames to the monitors.
> 
> One minor flaw is that the radiotap header now includes both, the rate
> field and the mcs field. For HT frames the rate field will be zero and
> for legacy frames the mcs fields will be zero but still this could
> be improved.


> Wireshark will display the MCS rate correctly but will show the zero'd rate
> field as well with 0Mbps. For legacy frames the MCS field won't be shown
> since IEEE80211_RADIOTAP_MCS_HAVE_MCS isn't set. Only the MCS flags will be
> shown (all zero of course).
> 
> I still think it is justified to use it like this as otherwise we would have
> to build the radiotap header in a more generic fashion and we won't be able to
> easily catch build bugs like
> 
>         BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM !=
>                         sizeof(struct ieee80211_tx_status_rtap_hdr));

Hmm. I don't like it much, but it's a bug right now too. Too bad the
rate field doesn't just fit into the padding :-)

Actually though, the MCS field is three bytes. So using something like
this would allow us to save some space as well:

struct ieee80211_tx_status_rtap_hdr {
        struct ieee80211_radiotap_header hdr;
	union {
		struct {
			u8 rate;
			u8 padding_for_rate;
			__le16 tx_flags;
			u8 data_retries;
		} non_mcs;
		struct {
			__le16 tx_flags;
			u8 data_retries;
			u8 mcs_known, mcs_flags, mcs;
		} mcs;
	}
} __packed;

johannes


^ permalink raw reply

* Re: [PATCH 2/5] ath6kl: Add debugfs file for target roam table
From: Kalle Valo @ 2011-10-11 11:39 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: linux-wireless
In-Reply-To: <1318243411-16110-3-git-send-email-jouni@qca.qualcomm.com>

On 10/10/2011 01:43 PM, Jouni Malinen wrote:
> The new roam_table debugfs file can be used to display the current
> roam table from the target.

One comment:

> +static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len)
> +{
> +#ifdef CONFIG_ATH6KL_DEBUG
> +	struct ath6kl *ar = wmi->parent_dev;
> +	struct wmi_target_roam_tbl *tbl;
> +	u16 num_entries;
> +
> +	if (len < sizeof(*tbl))
> +		return -EINVAL;
> +
> +	tbl = (struct wmi_target_roam_tbl *) datap;
> +	num_entries = le16_to_cpu(tbl->num_entries);
> +	if (sizeof(*tbl) + num_entries * sizeof(struct wmi_bss_roam_info) > len)
> +		return -EINVAL;
> +
> +	if (ar->debug.roam_tbl == NULL ||
> +	    ar->debug.roam_tbl_len < (unsigned int) len) {
> +		kfree(ar->debug.roam_tbl);
> +		ar->debug.roam_tbl = kmalloc(len, GFP_ATOMIC);
> +		if (ar->debug.roam_tbl == NULL)
> +			return -ENOMEM;
> +	}
> +
> +	memcpy(ar->debug.roam_tbl, datap, len);
> +	ar->debug.roam_tbl_len = len;
> +
> +	if (test_bit(ROAM_TBL_PEND, &ar->flag)) {
> +		clear_bit(ROAM_TBL_PEND, &ar->flag);
> +		wake_up(&ar->event_wq);
> +	}
> +#endif /* CONFIG_ATH6KL_DEBUG */
> +
> +	return 0;
> +}

I would prefer to have the part inside ifdef in debug.c, for example
like ath6kl_debug_fwlog_event() is implemented. That way we can get rid
of the ifdef inside code and related functinality would be in the same file.

Kalle

^ permalink raw reply

* Re: [PATCH] mac80211: Populate radiotap header with MCS info for tx'ed frames
From: Helmut Schaa @ 2011-10-11 11:48 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linville
In-Reply-To: <1318332927.3965.9.camel@jlt3.sipsolutions.net>

On Tue, Oct 11, 2011 at 1:35 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> So using something like
> this would allow us to save some space as well:
>
> struct ieee80211_tx_status_rtap_hdr {
>        struct ieee80211_radiotap_header hdr;
>        union {
>                struct {
>                        u8 rate;
>                        u8 padding_for_rate;
>                        __le16 tx_flags;
>                        u8 data_retries;
>                } non_mcs;
>                struct {
>                        __le16 tx_flags;
>                        u8 data_retries;
>                        u8 mcs_known, mcs_flags, mcs;
>                } mcs;
>        }
> } __packed;

I thought about the same but this means we have to fill in
different fields (non_mcs.tx_flags vs mcs.tx_flags) for the MCS
vs legacy path and set the radiotap header len differently in
both cases.

Or should we just get rid of the whole struct and fill in the
rtap header dynamically like it is done in the rx path and
drop the build-bug-on thing?

Helmut

^ permalink raw reply

* Re: [PATCH] mac80211: Populate radiotap header with MCS info for tx'ed frames
From: Johannes Berg @ 2011-10-11 11:51 UTC (permalink / raw)
  To: Helmut Schaa; +Cc: linux-wireless, linville
In-Reply-To: <CAGXE3d8cuBg28PfMYQcAJ96oTEqUg6rG8ExUr+Sezq51eM2J_Q@mail.gmail.com>

On Tue, 2011-10-11 at 13:48 +0200, Helmut Schaa wrote:
> On Tue, Oct 11, 2011 at 1:35 PM, Johannes Berg
> <johannes@sipsolutions.net> wrote:
> > So using something like
> > this would allow us to save some space as well:
> >
> > struct ieee80211_tx_status_rtap_hdr {
> >        struct ieee80211_radiotap_header hdr;
> >        union {
> >                struct {
> >                        u8 rate;
> >                        u8 padding_for_rate;
> >                        __le16 tx_flags;
> >                        u8 data_retries;
> >                } non_mcs;
> >                struct {
> >                        __le16 tx_flags;
> >                        u8 data_retries;
> >                        u8 mcs_known, mcs_flags, mcs;
> >                } mcs;
> >        }
> > } __packed;
> 
> I thought about the same but this means we have to fill in
> different fields (non_mcs.tx_flags vs mcs.tx_flags) for the MCS
> vs legacy path and set the radiotap header len differently in
> both cases.

Good point.

> Or should we just get rid of the whole struct and fill in the
> rtap header dynamically like it is done in the rx path and
> drop the build-bug-on thing?

I wouldn't mind that either, but we'll want to have a WARN_ON_ONCE()
somewhere if we run out of space.

johannes


^ permalink raw reply

* [PATCH] wl12xx: handle injected packets
From: Eliad Peller @ 2011-10-11 11:52 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

Injected packets are sent with no vif, causing the wl12xx
to NULL-dereference in multiple places.

Furthermore, injected packets are currently not sent at all,
as system_hlid doesn't belong to any specific role, so
wl1271_skb_dequeue() never return its packets.

Handle both these problems.

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
thanks Johannes for providing a testing app

 drivers/net/wireless/wl12xx/main.c |    7 +++++--
 drivers/net/wireless/wl12xx/tx.c   |   27 +++++++++++++--------------
 2 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 692a275..fc652c4 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1517,11 +1517,14 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	struct wl1271 *wl = hw->priv;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_vif *vif = info->control.vif;
-	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+	struct wl12xx_vif *wlvif = NULL;
 	unsigned long flags;
 	int q, mapping;
 	u8 hlid;
 
+	if (vif)
+		wlvif = wl12xx_vif_to_data(vif);
+
 	mapping = skb_get_queue_mapping(skb);
 	q = wl1271_tx_get_queue(mapping);
 
@@ -1531,7 +1534,7 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 	/* queue the packet */
 	if (hlid == WL12XX_INVALID_LINK_ID ||
-	    !test_bit(hlid, wlvif->links_map)) {
+	    (wlvif && !test_bit(hlid, wlvif->links_map))) {
 		wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
 		dev_kfree_skb(skb);
 		goto out;
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 02d606f..33b800d 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -180,7 +180,7 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
-	if (wl12xx_is_dummy_packet(wl, skb))
+	if (!wlvif || wl12xx_is_dummy_packet(wl, skb))
 		return wl->system_hlid;
 
 	if (wlvif->bss_type == BSS_TYPE_AP_BSS)
@@ -259,7 +259,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
 		wl->tx_allocated_pkts[ac]++;
 
-		if (!is_dummy && wlvif->bss_type == BSS_TYPE_AP_BSS &&
+		if (!is_dummy && wlvif &&
+		    wlvif->bss_type == BSS_TYPE_AP_BSS &&
 		    test_bit(hlid, wlvif->ap.sta_hlid_map))
 			wl->links[hlid].allocated_pkts++;
 
@@ -302,7 +303,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 	desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
 
 	is_dummy = wl12xx_is_dummy_packet(wl, skb);
-	if (is_dummy || wlvif->bss_type != BSS_TYPE_AP_BSS)
+	if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS)
 		desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
 	else
 		desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
@@ -321,14 +322,14 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			   TX_HW_ATTR_SESSION_COUNTER;
 
 		tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
-	} else {
+	} else if (wlvif) {
 		/* configure the tx attributes */
 		tx_attr = wlvif->session_counter <<
 			  TX_HW_ATTR_OFST_SESSION_COUNTER;
 	}
 
 	desc->hlid = hlid;
-	if (is_dummy)
+	if (is_dummy || !wlvif)
 		rate_idx = 0;
 	else if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
 		/* if the packets are destined for AP (have a STA entry)
@@ -433,7 +434,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
 	wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid);
 
-	if (!is_dummy && wlvif->bss_type == BSS_TYPE_AP_BSS) {
+	if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) {
 		wl1271_tx_ap_update_inconnection_sta(wl, skb);
 		wl1271_tx_regulate_link(wl, wlvif, hlid);
 	}
@@ -610,6 +611,9 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
 		}
 	}
 
+	if (!skb)
+		skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
+
 	if (!skb &&
 	    test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
 		int q;
@@ -703,19 +707,14 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
 		return;
 
 	while ((skb = wl1271_skb_dequeue(wl))) {
+		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 		bool has_data = false;
 
 		wlvif = NULL;
-		if (!wl12xx_is_dummy_packet(wl, skb)) {
-			struct ieee80211_tx_info *info;
-			struct ieee80211_vif *vif;
+		if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif)
+			wlvif = wl12xx_vif_to_data(info->control.vif);
 
-			info = IEEE80211_SKB_CB(skb);
-			vif = info->control.vif;
-			wlvif = wl12xx_vif_to_data(vif);
-		}
 		has_data = wlvif && wl1271_tx_is_data_present(skb);
-
 		ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset);
 		if (ret == -EAGAIN) {
 			/*
-- 
1.7.6.401.g6a319


^ permalink raw reply related

* Re: [PATCH] mac80211: Populate radiotap header with MCS info for tx'ed frames
From: Helmut Schaa @ 2011-10-11 11:52 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linville
In-Reply-To: <1318333875.3965.10.camel@jlt3.sipsolutions.net>

On Tue, Oct 11, 2011 at 1:51 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
>> Or should we just get rid of the whole struct and fill in the
>> rtap header dynamically like it is done in the rx path and
>> drop the build-bug-on thing?
>
> I wouldn't mind that either, but we'll want to have a WARN_ON_ONCE()
> somewhere if we run out of space.

Ok, let's try it that way. John please drop this one, I'll do a v2.

Helmut

^ permalink raw reply

* Re: [PATCH 4/5] ath6kl: Add debugfs control for keepalive and disconnection timeout
From: Kalle Valo @ 2011-10-11 11:55 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: linux-wireless
In-Reply-To: <1318243411-16110-5-git-send-email-jouni@qca.qualcomm.com>

On 10/10/2011 01:43 PM, Jouni Malinen wrote:
> The new debugfs files keepalive and disconnect_timeout can be used to
> fetch the current values and to change the values for keepalive and
> disconnect event timeout (both in seconds).

[...]

> --- a/drivers/net/wireless/ath/ath6kl/wmi.c
> +++ b/drivers/net/wireless/ath/ath6kl/wmi.c
> @@ -1940,6 +1940,10 @@ int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout)
>  
>  	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_DISC_TIMEOUT_CMDID,
>  				  NO_SYNC_WMIFLAG);
> +#ifdef CONFIG_ATH6KL_DEBUG
> +	if (ret == 0)
> +		wmi->parent_dev->debug.disc_timeout = timeout;
> +#endif /* CONFIG_ATH6KL_DEBUG */
>  	return ret;
>  }
>  
> @@ -2524,6 +2528,10 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl)
>  
>  	ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_KEEPALIVE_CMDID,
>  				  NO_SYNC_WMIFLAG);
> +#ifdef CONFIG_ATH6KL_DEBUG
> +	if (ret == 0)
> +		wmi->parent_dev->debug.keepalive = keep_alive_intvl;
> +#endif /* CONFIG_ATH6KL_DEBUG */

Similar comment for these two as well. It would better to have the code
in debug.c (or .h) and add functions for providing this information.

Kalle

^ permalink raw reply

* Re: [PATCH 17/34] iwlagn: fix a race in the unmapping of the TFDs
From: Stanislaw Gruszka @ 2011-10-11 12:22 UTC (permalink / raw)
  To: Wey-Yi Guy; +Cc: linville, linux-wireless, Emmanuel Grumbach
In-Reply-To: <1318256839-31837-18-git-send-email-wey-yi.w.guy@intel.com>

On Mon, Oct 10, 2011 at 07:27:02AM -0700, Wey-Yi Guy wrote:
> While inspecting the code, I saw that iwl_tx_queue_unmap modifies
> the read pointer of the Tx queue without taking any locks. This means
> that it can race with the reclaim flow. This can possibly lead to
> a DMA warning complaining that we unmap the same buffer twice.
> 
> This is more a W/A than a fix since it is really weird to take
> sta_lock inside iwl_tx_queue_unmap, but it can help until we revamp
> the locking model in the transport layer.
> 
> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> ---
>  drivers/net/wireless/iwlwifi/iwl-trans-pcie.c |    3 +++
>  1 files changed, 3 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> index 60067c7..f69aecb 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> @@ -406,6 +406,7 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
>  	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
>  	struct iwl_queue *q = &txq->q;
>  	enum dma_data_direction dma_dir;
> +	unsigned long flags;
>  
>  	if (!q->n_bd)
>  		return;
> @@ -418,12 +419,14 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
>  	else
>  		dma_dir = DMA_TO_DEVICE;
>  
> +	spin_lock_irqsave(&trans->shrd->sta_lock, flags);
sta_lock does not look like right lock to use.

Stanislaw

^ permalink raw reply

* RE: [PATCH 17/34] iwlagn: fix a race in the unmapping of the TFDs
From: Grumbach, Emmanuel @ 2011-10-11 12:26 UTC (permalink / raw)
  To: Stanislaw Gruszka, Guy, Wey-Yi W
  Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org
In-Reply-To: <20111011122216.GA2218@redhat.com>

> 
> On Mon, Oct 10, 2011 at 07:27:02AM -0700, Wey-Yi Guy wrote:
> > While inspecting the code, I saw that iwl_tx_queue_unmap modifies
> > the read pointer of the Tx queue without taking any locks. This means
> > that it can race with the reclaim flow. This can possibly lead to
> > a DMA warning complaining that we unmap the same buffer twice.
> >
> > This is more a W/A than a fix since it is really weird to take
> > sta_lock inside iwl_tx_queue_unmap, but it can help until we revamp
> > the locking model in the transport layer.
> >
> > Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
> > Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> > ---
> >  drivers/net/wireless/iwlwifi/iwl-trans-pcie.c |    3 +++
> >  1 files changed, 3 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > index 60067c7..f69aecb 100644
> > --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > @@ -406,6 +406,7 @@ static void iwl_tx_queue_unmap(struct iwl_trans
> *trans, int txq_id)
> >  	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
> >  	struct iwl_queue *q = &txq->q;
> >  	enum dma_data_direction dma_dir;
> > +	unsigned long flags;
> >
> >  	if (!q->n_bd)
> >  		return;
> > @@ -418,12 +419,14 @@ static void iwl_tx_queue_unmap(struct iwl_trans
> *trans, int txq_id)
> >  	else
> >  		dma_dir = DMA_TO_DEVICE;
> >
> > +	spin_lock_irqsave(&trans->shrd->sta_lock, flags);
> sta_lock does not look like right lock to use.
> 
True. And I wrote in the commit message that this is a W/A until we revamp the locking model.

---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


^ permalink raw reply

* Re: [PATCH 17/34] iwlagn: fix a race in the unmapping of the TFDs
From: Stanislaw Gruszka @ 2011-10-11 12:36 UTC (permalink / raw)
  To: Grumbach, Emmanuel
  Cc: Guy, Wey-Yi W, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org
In-Reply-To: <4825B8A2C4E264489E57869F0DCFB2234457A944D0@hasmsx502.ger.corp.intel.com>

On Tue, Oct 11, 2011 at 02:26:30PM +0200, Grumbach, Emmanuel wrote:
> > 
> > On Mon, Oct 10, 2011 at 07:27:02AM -0700, Wey-Yi Guy wrote:
> > > While inspecting the code, I saw that iwl_tx_queue_unmap modifies
> > > the read pointer of the Tx queue without taking any locks. This means
> > > that it can race with the reclaim flow. This can possibly lead to
> > > a DMA warning complaining that we unmap the same buffer twice.
> > >
> > > This is more a W/A than a fix since it is really weird to take
> > > sta_lock inside iwl_tx_queue_unmap, but it can help until we revamp
> > > the locking model in the transport layer.
> > >
> > > Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
> > > Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> > > ---
> > >  drivers/net/wireless/iwlwifi/iwl-trans-pcie.c |    3 +++
> > >  1 files changed, 3 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > > index 60067c7..f69aecb 100644
> > > --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > > +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > > @@ -406,6 +406,7 @@ static void iwl_tx_queue_unmap(struct iwl_trans
> > *trans, int txq_id)
> > >  	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
> > >  	struct iwl_queue *q = &txq->q;
> > >  	enum dma_data_direction dma_dir;
> > > +	unsigned long flags;
> > >
> > >  	if (!q->n_bd)
> > >  		return;
> > > @@ -418,12 +419,14 @@ static void iwl_tx_queue_unmap(struct iwl_trans
> > *trans, int txq_id)
> > >  	else
> > >  		dma_dir = DMA_TO_DEVICE;
> > >
> > > +	spin_lock_irqsave(&trans->shrd->sta_lock, flags);
> > sta_lock does not look like right lock to use.
> > 
> True. And I wrote in the commit message that this is a W/A until we revamp the locking model.

Why not simply take hcmd_lock?


^ permalink raw reply

* RE: [PATCH 17/34] iwlagn: fix a race in the unmapping of the TFDs
From: Grumbach, Emmanuel @ 2011-10-11 12:38 UTC (permalink / raw)
  To: Stanislaw Gruszka
  Cc: Guy, Wey-Yi W, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org
In-Reply-To: <20111011123630.GB2218@redhat.com>

> > > > While inspecting the code, I saw that iwl_tx_queue_unmap modifies
> > > > the read pointer of the Tx queue without taking any locks. This means
> > > > that it can race with the reclaim flow. This can possibly lead to
> > > > a DMA warning complaining that we unmap the same buffer twice.
> > > >
> > > > This is more a W/A than a fix since it is really weird to take
> > > > sta_lock inside iwl_tx_queue_unmap, but it can help until we revamp
> > > > the locking model in the transport layer.
> > > >
> > > > Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
> > > > Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
> > > > ---
> > > >  drivers/net/wireless/iwlwifi/iwl-trans-pcie.c |    3 +++
> > > >  1 files changed, 3 insertions(+), 0 deletions(-)
> > > >
> > > > diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > > b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > > > index 60067c7..f69aecb 100644
> > > > --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > > > +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
> > > > @@ -406,6 +406,7 @@ static void iwl_tx_queue_unmap(struct iwl_trans
> > > *trans, int txq_id)
> > > >  	struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
> > > >  	struct iwl_queue *q = &txq->q;
> > > >  	enum dma_data_direction dma_dir;
> > > > +	unsigned long flags;
> > > >
> > > >  	if (!q->n_bd)
> > > >  		return;
> > > > @@ -418,12 +419,14 @@ static void iwl_tx_queue_unmap(struct iwl_trans
> > > *trans, int txq_id)
> > > >  	else
> > > >  		dma_dir = DMA_TO_DEVICE;
> > > >
> > > > +	spin_lock_irqsave(&trans->shrd->sta_lock, flags);
> > > sta_lock does not look like right lock to use.
> > >
> > True. And I wrote in the commit message that this is a W/A until we
> revamp the locking model.
> 
> Why not simply take hcmd_lock?

Hcmd_lock is related to the host command queue only, it won't work for Tx queues.
---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


^ permalink raw reply

* Re: [PATCH 00/29] make the driver ready for multi-vif support
From: Luciano Coelho @ 2011-10-11 12:52 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless
In-Reply-To: <1318234397-21081-1-git-send-email-eliad@wizery.com>

On Mon, 2011-10-10 at 10:12 +0200, Eliad Peller wrote: 
> This patchset finishes adding multiple vif support to the
> wl12xx driver.
> 
> The driver still allows only a single vif, as the current
> fw only supports a single vif.
> 
> This patchset doesn't break compatibility with the current fw.

Applied, thanks! With the following small changes:

* used v2 of 08/29;
* used '(foo - bar) & 0xff' instead of '(foo - bar + 256) % 256'.


-- 
Cheers,
Luca.


^ permalink raw reply

* Re: [PATCH 17/34] iwlagn: fix a race in the unmapping of the TFDs
From: Stanislaw Gruszka @ 2011-10-11 12:58 UTC (permalink / raw)
  To: Grumbach, Emmanuel
  Cc: Guy, Wey-Yi W, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org
In-Reply-To: <4825B8A2C4E264489E57869F0DCFB2234457A944F2@hasmsx502.ger.corp.intel.com>

On Tue, Oct 11, 2011 at 02:38:52PM +0200, Grumbach, Emmanuel wrote:
> > Why not simply take hcmd_lock?
> 
> Hcmd_lock is related to the host command queue only, it won't work for Tx queues.

So you only fix reces between
iwl_trans_pcie_tx()/iwl_tx_queue_reclaim() and iwl_tx_queue_unmap().
Races between
iwl_enqueue_hcmd()/iwl_cmd_queue_reclaim() and iwl_tx_queue_unmap()
are unresolved.

Stanislaw

^ permalink raw reply

* Re: [PATCH 0/8] wl12xx: forward ported Balbi's bus driver refactor
From: Luciano Coelho @ 2011-10-11 13:05 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1317928259-26437-1-git-send-email-coelho@ti.com>

On Thu, 2011-10-06 at 22:10 +0300, Luciano Coelho wrote: 
> Hi,
> 
> Felipe sent this series of patches a long time ago with very good
> suggestion on how to avoid the duplicate code we have in the sdio and
> spi drivers.
> 
> With this, we create a platform device that is handled by a platform
> driver.  The bus-specific module, creates a platform device and the
> core module implements the driver that supports both platform devices
> (namely "wl12xx-sdio" and "wl12xx-spi").
> 
> I didn't apply this earlier because I had concerns about the change in
> the platform data, but now I'm convinced it's not a real problem.  It
> may affect compat-wireless, but it's easy to solve.
> 
> I have now forward-ported the patches, fixed some bugs, removed some
> style changes and moved some other things around.  For the changes I
> made, see the commit message of each patch.  Some changes are not in
> the commit message, but are explained in the patch emails, after the
> Signed-off-by area.
> 
> I'm keeping Felipe as the author, since most of the work is his.  I
> have just tested and fixed it up.
> 
> Cheers,
> Luca.
> 
> Felipe Balbi (8):
>   wl12xx: add an sdio glue struct to keep wl and device side-by-side
>   wl12xx: add an spi glue struct to keep wl and device side-by-side
>   wl12xx: add a platform device to the sdio module
>   wl12xx: add a platform device to the spi module
>   wl12xx: add platform driver to the core module
>   wl12xx: move common init code from bus modules to main
>   wl12xx: mark some symbols static
>   wl12xx: drop unneeded plat_dev

Applied the whole series.

-- 
Cheers,
Luca.


^ permalink raw reply

* Re: [PATCH] wl12xx: move debugging definitions to a separate file
From: Luciano Coelho @ 2011-10-11 13:20 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1318085047.9690.32.camel@cumari>

On Sat, 2011-10-08 at 17:44 +0300, Luciano Coelho wrote: 
> On Fri, 2011-10-07 at 11:13 +0300, Luciano Coelho wrote: 
> > Separate the debugging macros and other definitions to a new debug.h
> > file.  This is be needed because the sdio and spi modules don't need
> > to depend on the wl12xx module anymore, but still need to include
> > wl12xx.h.  Currently they do depend on it, because of the debugging
> > global that wl12xx exports.  A future patch will remove this
> > dependency.
> > 
> > Signed-off-by: Luciano Coelho <coelho@ti.com>
> > ---
> 
> These defines should be in debug.h as well:
> 
> #define DRIVER_NAME "wl1271"
> #define DRIVER_PREFIX DRIVER_NAME ": "
> 
> I'll move them too and rename wl1271 to wl12xx when I apply.

Applied.

-- 
Cheers,
Luca.


^ permalink raw reply

* Re: [PATCH 1/2] wl12xx: sdio: use dev_dbg instead of wl1271_debug
From: Luciano Coelho @ 2011-10-11 13:22 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <1317987297-18172-1-git-send-email-coelho@ti.com>

On Fri, 2011-10-07 at 14:34 +0300, Luciano Coelho wrote: 
> To prevent a useless dependency between the sdio module and the wl12xx
> module, we need to replace the wl1271_debug macros (and friends) for
> dev_dbg and other equivalents.
> 
> At the same time, remove the SDIO data hexdump, since this produces
> way too much data and is not particularly useful.  There's not
> print_hex_dump() equivalent for dynamic debug, so it's hard to control
> when the dumps are printed out.
> 
> Signed-off-by: Luciano Coelho <coelho@ti.com>
> ---

Applied both.

-- 
Cheers,
Luca.


^ permalink raw reply

* [PATCH v2 1/5] ath6kl: Add endpoint_stats debugfs file
From: Jouni Malinen @ 2011-10-11 14:31 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, Jouni Malinen
In-Reply-To: <1318343517-15292-1-git-send-email-jouni@qca.qualcomm.com>

This file can be used to fetch endpoint statistics counters and
to clear them by writing 0 to it.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath6kl/debug.c |  102 +++++++++++++++++++++++++++++++
 1 files changed, 102 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index ba3f23d..b9bf28d 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -595,6 +595,105 @@ static const struct file_operations fops_credit_dist_stats = {
 	.llseek = default_llseek,
 };
 
+static unsigned int print_endpoint_stat(struct htc_target *target, char *buf,
+					unsigned int buf_len, unsigned int len,
+					int offset, const char *name)
+{
+	int i;
+	struct htc_endpoint_stats *ep_st;
+	u32 *counter;
+
+	len += scnprintf(buf + len, buf_len - len, "%s:", name);
+	for (i = 0; i < ENDPOINT_MAX; i++) {
+		ep_st = &target->endpoint[i].ep_st;
+		counter = ((u32 *) ep_st) + (offset / 4);
+		len += scnprintf(buf + len, buf_len - len, " %u", *counter);
+	}
+	len += scnprintf(buf + len, buf_len - len, "\n");
+
+	return len;
+}
+
+static ssize_t ath6kl_endpoint_stats_read(struct file *file,
+					  char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	struct ath6kl *ar = file->private_data;
+	struct htc_target *target = ar->htc_target;
+	char *buf;
+	unsigned int buf_len, len = 0;
+	ssize_t ret_cnt;
+
+	buf_len = 1000 + ENDPOINT_MAX * 100;
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+#define EPSTAT(name)							\
+	len = print_endpoint_stat(target, buf, buf_len, len,		\
+				  offsetof(struct htc_endpoint_stats, name), \
+				  #name)
+	EPSTAT(cred_low_indicate);
+	EPSTAT(tx_issued);
+	EPSTAT(tx_pkt_bundled);
+	EPSTAT(tx_bundles);
+	EPSTAT(tx_dropped);
+	EPSTAT(tx_cred_rpt);
+	EPSTAT(cred_rpt_from_rx);
+	EPSTAT(cred_rpt_ep0);
+	EPSTAT(cred_from_rx);
+	EPSTAT(cred_from_other);
+	EPSTAT(cred_from_ep0);
+	EPSTAT(cred_cosumd);
+	EPSTAT(cred_retnd);
+	EPSTAT(rx_pkts);
+	EPSTAT(rx_lkahds);
+	EPSTAT(rx_bundl);
+	EPSTAT(rx_bundle_lkahd);
+	EPSTAT(rx_bundle_from_hdr);
+	EPSTAT(rx_alloc_thresh_hit);
+	EPSTAT(rxalloc_thresh_byte);
+#undef EPSTAT
+
+	if (len > buf_len)
+		len = buf_len;
+
+	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+	return ret_cnt;
+}
+
+static ssize_t ath6kl_endpoint_stats_write(struct file *file,
+					   const char __user *user_buf,
+					   size_t count, loff_t *ppos)
+{
+	struct ath6kl *ar = file->private_data;
+	struct htc_target *target = ar->htc_target;
+	int ret, i;
+	u32 val;
+	struct htc_endpoint_stats *ep_st;
+
+	ret = kstrtou32_from_user(user_buf, count, 0, &val);
+	if (ret)
+		return ret;
+	if (val == 0) {
+		for (i = 0; i < ENDPOINT_MAX; i++) {
+			ep_st = &target->endpoint[i].ep_st;
+			memset(ep_st, 0, sizeof(*ep_st));
+		}
+	}
+
+	return count;
+}
+
+static const struct file_operations fops_endpoint_stats = {
+	.open = ath6kl_debugfs_open,
+	.read = ath6kl_endpoint_stats_read,
+	.write = ath6kl_endpoint_stats_write,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static unsigned long ath6kl_get_num_reg(void)
 {
 	int i;
@@ -901,6 +1000,9 @@ int ath6kl_debug_init(struct ath6kl *ar)
 	debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar,
 			    &fops_credit_dist_stats);
 
+	debugfs_create_file("endpoint_stats", S_IRUSR | S_IWUSR,
+			    ar->debugfs_phy, ar, &fops_endpoint_stats);
+
 	debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
 			    &fops_fwlog);
 
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH v2 2/5] ath6kl: Add debugfs file for target roam table
From: Jouni Malinen @ 2011-10-11 14:31 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, Jouni Malinen
In-Reply-To: <1318343517-15292-1-git-send-email-jouni@qca.qualcomm.com>

The new roam_table debugfs file can be used to display the current
roam table from the target.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath6kl/core.h  |    4 +
 drivers/net/wireless/ath/ath6kl/debug.c |  109 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath6kl/debug.h |    8 ++
 drivers/net/wireless/ath/ath6kl/wmi.c   |   11 +++
 drivers/net/wireless/ath/ath6kl/wmi.h   |    7 ++
 5 files changed, 139 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 6d8a484..c58cfad 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -397,6 +397,7 @@ struct ath6kl_req_key {
 #define TESTMODE	     13
 #define CLEAR_BSSFILTER_ON_BEACON 14
 #define DTIM_PERIOD_AVAIL    15
+#define ROAM_TBL_PEND        16
 
 struct ath6kl {
 	struct device *dev;
@@ -529,6 +530,9 @@ struct ath6kl {
 		struct {
 			unsigned int invalid_rate;
 		} war_stats;
+
+		u8 *roam_tbl;
+		unsigned int roam_tbl_len;
 	} debug;
 #endif /* CONFIG_ATH6KL_DEBUG */
 };
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index b9bf28d..cec958a 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -966,6 +966,111 @@ static const struct file_operations fops_diag_reg_write = {
 	.llseek = default_llseek,
 };
 
+int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
+				size_t len)
+{
+	const struct wmi_target_roam_tbl *tbl;
+	u16 num_entries;
+
+	if (len < sizeof(*tbl))
+		return -EINVAL;
+
+	tbl = (const struct wmi_target_roam_tbl *) buf;
+	num_entries = le16_to_cpu(tbl->num_entries);
+	if (sizeof(*tbl) + num_entries * sizeof(struct wmi_bss_roam_info) >
+	    len)
+		return -EINVAL;
+
+	if (ar->debug.roam_tbl == NULL ||
+	    ar->debug.roam_tbl_len < (unsigned int) len) {
+		kfree(ar->debug.roam_tbl);
+		ar->debug.roam_tbl = kmalloc(len, GFP_ATOMIC);
+		if (ar->debug.roam_tbl == NULL)
+			return -ENOMEM;
+	}
+
+	memcpy(ar->debug.roam_tbl, buf, len);
+	ar->debug.roam_tbl_len = len;
+
+	if (test_bit(ROAM_TBL_PEND, &ar->flag)) {
+		clear_bit(ROAM_TBL_PEND, &ar->flag);
+		wake_up(&ar->event_wq);
+	}
+
+	return 0;
+}
+
+static ssize_t ath6kl_roam_table_read(struct file *file, char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath6kl *ar = file->private_data;
+	int ret;
+	long left;
+	struct wmi_target_roam_tbl *tbl;
+	u16 num_entries, i;
+	char *buf;
+	unsigned int len, buf_len;
+	ssize_t ret_cnt;
+
+	if (down_interruptible(&ar->sem))
+		return -EBUSY;
+
+	set_bit(ROAM_TBL_PEND, &ar->flag);
+
+	ret = ath6kl_wmi_get_roam_tbl_cmd(ar->wmi);
+	if (ret) {
+		up(&ar->sem);
+		return ret;
+	}
+
+	left = wait_event_interruptible_timeout(
+		ar->event_wq, !test_bit(ROAM_TBL_PEND, &ar->flag), WMI_TIMEOUT);
+	up(&ar->sem);
+
+	if (left <= 0)
+		return -ETIMEDOUT;
+
+	if (ar->debug.roam_tbl == NULL)
+		return -ENOMEM;
+
+	tbl = (struct wmi_target_roam_tbl *) ar->debug.roam_tbl;
+	num_entries = le16_to_cpu(tbl->num_entries);
+
+	buf_len = 100 + num_entries * 100;
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+	len = 0;
+	len += scnprintf(buf + len, buf_len - len,
+			 "roam_mode=%u\n\n"
+			 "# roam_util bssid rssi rssidt last_rssi util bias\n",
+			 le16_to_cpu(tbl->roam_mode));
+
+	for (i = 0; i < num_entries; i++) {
+		struct wmi_bss_roam_info *info = &tbl->info[i];
+		len += scnprintf(buf + len, buf_len - len,
+				 "%d %pM %d %d %d %d %d\n",
+				 a_sle32_to_cpu(info->roam_util), info->bssid,
+				 info->rssi, info->rssidt, info->last_rssi,
+				 info->util, info->bias);
+	}
+
+	if (len > buf_len)
+		len = buf_len;
+
+	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+	kfree(buf);
+	return ret_cnt;
+}
+
+static const struct file_operations fops_roam_table = {
+	.read = ath6kl_roam_table_read,
+	.open = ath6kl_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 int ath6kl_debug_init(struct ath6kl *ar)
 {
 	ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE);
@@ -1024,6 +1129,9 @@ int ath6kl_debug_init(struct ath6kl *ar)
 	debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar,
 			    &fops_war_stats);
 
+	debugfs_create_file("roam_table", S_IRUSR, ar->debugfs_phy, ar,
+			    &fops_roam_table);
+
 	return 0;
 }
 
@@ -1031,6 +1139,7 @@ void ath6kl_debug_cleanup(struct ath6kl *ar)
 {
 	vfree(ar->debug.fwlog_buf.buf);
 	kfree(ar->debug.fwlog_tmp);
+	kfree(ar->debug.roam_tbl);
 }
 
 #endif
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h
index e3740b0..f73bf15 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.h
+++ b/drivers/net/wireless/ath/ath6kl/debug.h
@@ -90,6 +90,8 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
 void dump_cred_dist_stats(struct htc_target *target);
 void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len);
 void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war);
+int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
+				size_t len);
 int ath6kl_debug_init(struct ath6kl *ar);
 void ath6kl_debug_cleanup(struct ath6kl *ar);
 
@@ -125,6 +127,12 @@ static inline void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
 {
 }
 
+static inline int ath6kl_debug_roam_tbl_event(struct ath6kl *ar,
+					      const void *buf, size_t len)
+{
+	return 0;
+}
+
 static inline int ath6kl_debug_init(struct ath6kl *ar)
 {
 	return 0;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index ab782d7..4021527 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2407,6 +2407,11 @@ int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi)
 	return ath6kl_wmi_simple_cmd(wmi, WMI_GET_TX_PWR_CMDID);
 }
 
+int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi)
+{
+	return ath6kl_wmi_simple_cmd(wmi, WMI_GET_ROAM_TBL_CMDID);
+}
+
 int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, u8 preamble_policy)
 {
 	struct sk_buff *skb;
@@ -2844,6 +2849,11 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
 	return ret;
 }
 
+static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+	return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len);
+}
+
 /* Control Path */
 int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
 {
@@ -2948,6 +2958,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
 		break;
 	case WMI_REPORT_ROAM_TBL_EVENTID:
 		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n");
+		ret = ath6kl_wmi_roam_tbl_event_rx(wmi, datap, len);
 		break;
 	case WMI_EXTENSION_EVENTID:
 		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 96102c6..f986da1 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1624,6 +1624,12 @@ struct wmi_bss_roam_info {
 	u8 reserved;
 } __packed;
 
+struct wmi_target_roam_tbl {
+	__le16 roam_mode;
+	__le16 num_entries;
+	struct wmi_bss_roam_info info[];
+} __packed;
+
 /* WMI_CAC_EVENTID */
 enum cac_indication {
 	CAC_INDICATION_ADMISSION = 0x00,
@@ -2221,6 +2227,7 @@ int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid,
 			    const u8 *pmkid, bool set);
 int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM);
 int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi);
+int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi);
 
 int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg);
 int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl);
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH v2 0/5] ath6kl: Debugging and roaming
From: Jouni Malinen @ 2011-10-11 14:31 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, Jouni Malinen

This set of patches adds some more ath6kl debugging information and
control to debugfs and enables additional roaming functionality.

v2 addresses the comments from Kalle to move debug functionality in
patches 2 and 4 to debug.c.

Jouni Malinen (5):
  ath6kl: Add endpoint_stats debugfs file
  ath6kl: Add debugfs file for target roam table
  ath6kl: Add debugfs files for roaming control
  ath6kl: Add debugfs control for keepalive and disconnection timeout
  ath6kl: Allow CCKM AKM and KRK to be configured

 drivers/net/wireless/ath/ath6kl/cfg80211.c |   14 +
 drivers/net/wireless/ath/ath6kl/core.h     |    7 +
 drivers/net/wireless/ath/ath6kl/debug.c    |  390 ++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath6kl/debug.h    |   19 ++
 drivers/net/wireless/ath/ath6kl/wmi.c      |   55 ++++
 drivers/net/wireless/ath/ath6kl/wmi.h      |   28 ++-
 6 files changed, 507 insertions(+), 6 deletions(-)

-- 
1.7.4.1


^ permalink raw reply

* [PATCH v2 3/5] ath6kl: Add debugfs files for roaming control
From: Jouni Malinen @ 2011-10-11 14:31 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, Jouni Malinen
In-Reply-To: <1318343517-15292-1-git-send-email-jouni@qca.qualcomm.com>

Roaming mode can be changed by writing roam mode (default, bssbias, or
lock) to roam_mode. Forced roam can be requested by writing the BSSID
into force_roam.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath6kl/debug.c |   84 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath6kl/wmi.c   |   40 +++++++++++++++
 drivers/net/wireless/ath/ath6kl/wmi.h   |   21 ++++++--
 3 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index cec958a..41161ca 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -1071,6 +1071,84 @@ static const struct file_operations fops_roam_table = {
 	.llseek = default_llseek,
 };
 
+static ssize_t ath6kl_force_roam_write(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct ath6kl *ar = file->private_data;
+	int ret;
+	char buf[20];
+	size_t len;
+	u8 bssid[ETH_ALEN];
+	int i;
+	int addr[ETH_ALEN];
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+	buf[len] = '\0';
+
+	if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+		   &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5])
+	    != ETH_ALEN)
+		return -EINVAL;
+	for (i = 0; i < ETH_ALEN; i++)
+		bssid[i] = addr[i];
+
+	ret = ath6kl_wmi_force_roam_cmd(ar->wmi, bssid);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations fops_force_roam = {
+	.write = ath6kl_force_roam_write,
+	.open = ath6kl_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath6kl_roam_mode_write(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath6kl *ar = file->private_data;
+	int ret;
+	char buf[20];
+	size_t len;
+	enum wmi_roam_mode mode;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+	buf[len] = '\0';
+	if (len > 0 && buf[len - 1] == '\n')
+		buf[len - 1] = '\0';
+
+	if (strcasecmp(buf, "default") == 0)
+		mode = WMI_DEFAULT_ROAM_MODE;
+	else if (strcasecmp(buf, "bssbias") == 0)
+		mode = WMI_HOST_BIAS_ROAM_MODE;
+	else if (strcasecmp(buf, "lock") == 0)
+		mode = WMI_LOCK_BSS_MODE;
+	else
+		return -EINVAL;
+
+	ret = ath6kl_wmi_set_roam_mode_cmd(ar->wmi, mode);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations fops_roam_mode = {
+	.write = ath6kl_roam_mode_write,
+	.open = ath6kl_debugfs_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 int ath6kl_debug_init(struct ath6kl *ar)
 {
 	ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE);
@@ -1132,6 +1210,12 @@ int ath6kl_debug_init(struct ath6kl *ar)
 	debugfs_create_file("roam_table", S_IRUSR, ar->debugfs_phy, ar,
 			    &fops_roam_table);
 
+	debugfs_create_file("force_roam", S_IWUSR, ar->debugfs_phy, ar,
+			    &fops_force_roam);
+
+	debugfs_create_file("roam_mode", S_IWUSR, ar->debugfs_phy, ar,
+			    &fops_roam_mode);
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 4021527..3fb2702 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -682,6 +682,46 @@ int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi)
 	return 0;
 }
 
+int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
+{
+	struct sk_buff *skb;
+	struct roam_ctrl_cmd *cmd;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct roam_ctrl_cmd *) skb->data;
+	memset(cmd, 0, sizeof(*cmd));
+
+	memcpy(cmd->info.bssid, bssid, ETH_ALEN);
+	cmd->roam_ctrl = WMI_FORCE_ROAM;
+
+	ath6kl_dbg(ATH6KL_DBG_WMI, "force roam to %pM\n", bssid);
+	return ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_ROAM_CTRL_CMDID,
+				   NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
+{
+	struct sk_buff *skb;
+	struct roam_ctrl_cmd *cmd;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct roam_ctrl_cmd *) skb->data;
+	memset(cmd, 0, sizeof(*cmd));
+
+	cmd->info.roam_mode = mode;
+	cmd->roam_ctrl = WMI_SET_ROAM_MODE;
+
+	ath6kl_dbg(ATH6KL_DBG_WMI, "set roam mode %d\n", mode);
+	return ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_ROAM_CTRL_CMDID,
+				   NO_SYNC_WMIFLAG);
+}
+
 static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len)
 {
 	struct wmi_connect_event *ev;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index f986da1..f0ca899 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1354,14 +1354,20 @@ enum wmi_roam_ctrl {
 	WMI_SET_LRSSI_SCAN_PARAMS,
 };
 
+enum wmi_roam_mode {
+	WMI_DEFAULT_ROAM_MODE = 1, /* RSSI based roam */
+	WMI_HOST_BIAS_ROAM_MODE = 2, /* Host bias based roam */
+	WMI_LOCK_BSS_MODE = 3, /* Lock to the current BSS */
+};
+
 struct bss_bias {
 	u8 bssid[ETH_ALEN];
-	u8  bias;
+	s8 bias;
 } __packed;
 
 struct bss_bias_info {
 	u8 num_bss;
-	struct bss_bias bss_bias[1];
+	struct bss_bias bss_bias[0];
 } __packed;
 
 struct low_rssi_scan_params {
@@ -1374,10 +1380,11 @@ struct low_rssi_scan_params {
 
 struct roam_ctrl_cmd {
 	union {
-		u8 bssid[ETH_ALEN];
-		u8 roam_mode;
-		struct bss_bias_info bss;
-		struct low_rssi_scan_params params;
+		u8 bssid[ETH_ALEN]; /* WMI_FORCE_ROAM */
+		u8 roam_mode; /* WMI_SET_ROAM_MODE */
+		struct bss_bias_info bss; /* WMI_SET_HOST_BIAS */
+		struct low_rssi_scan_params params; /* WMI_SET_LRSSI_SCAN_PARAMS
+						     */
 	} __packed info;
 	u8 roam_ctrl;
 } __packed;
@@ -2237,6 +2244,8 @@ s32 ath6kl_wmi_get_rate(s8 rate_index);
 
 int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd);
 int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
+int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
+int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode);
 
 /* AP mode */
 int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p);
-- 
1.7.4.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox