linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/9] iwmc3200wifi updates
@ 2009-09-01 13:13 Samuel Ortiz
  2009-09-01 13:13 ` [PATCH 1/9] iwmc3200wifi: invalidate profile when necessary before connect Samuel Ortiz
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:13 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

Hi John,

This 9 patches serie is the latest iwmc3200wifi update.
All of them are targeted for a wireless-testing inclusion, hoping it's not too
late to make it to the next merge window.

Samuel Ortiz (5):
  iwmc3200wifi: Set WEP key from connect
  iwmc3200wifi: Fix sparse warning
  iwmc3200wifi: New initial LMAC calibration
  iwmc3200wifi: Handle UMAC stalls and UMAC assert properly
  iwmc3200wifi: Add a last_fw_err debugfs entry

Zhu Yi (4):
  iwmc3200wifi: invalidate profile when necessary before connect
  iwmc3200wifi: use cfg80211_roamed to send roam event
  iwmc3200wifi: add disconnect work
  iwmc3200wifi: fix misuse of le16_to_cpu

 drivers/net/wireless/iwmc3200wifi/cfg80211.c |   66 ++++++++++++++--
 drivers/net/wireless/iwmc3200wifi/commands.c |    1 +
 drivers/net/wireless/iwmc3200wifi/debug.h    |    2 +
 drivers/net/wireless/iwmc3200wifi/debugfs.c  |  105 +++++++++++++++++++++++++-
 drivers/net/wireless/iwmc3200wifi/fw.c       |   56 ++++++++++----
 drivers/net/wireless/iwmc3200wifi/iwm.h      |    8 ++-
 drivers/net/wireless/iwmc3200wifi/lmac.h     |   15 ++++
 drivers/net/wireless/iwmc3200wifi/main.c     |   60 +++++++++++++--
 drivers/net/wireless/iwmc3200wifi/rx.c       |   87 +++++++++++++++++----
 9 files changed, 345 insertions(+), 55 deletions(-)


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/9] iwmc3200wifi: invalidate profile when necessary before connect
  2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
@ 2009-09-01 13:13 ` Samuel Ortiz
  2009-09-01 13:13 ` [PATCH 2/9] iwmc3200wifi: Set WEP key from connect Samuel Ortiz
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:13 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

From: Zhu Yi <yi.zhu@intel.com>

If cfg80211 requests to connect when we have already had an active
profile, invalidate the current profile first before sending a new
profile to UMAC.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index a6e852f..789ef5c 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -326,11 +326,8 @@ static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
 
 	iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
 
-	if (iwm->umac_profile_active) {
-		int ret = iwm_invalidate_mlme_profile(iwm);
-		if (ret < 0)
-			IWM_ERR(iwm, "Couldn't invalidate profile\n");
-	}
+	if (iwm->umac_profile_active)
+		iwm_invalidate_mlme_profile(iwm);
 
 	return 0;
 }
@@ -573,6 +570,14 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 	if (!sme->ssid)
 		return -EINVAL;
 
+	if (iwm->umac_profile_active) {
+		ret = iwm_invalidate_mlme_profile(iwm);
+		if (ret) {
+			IWM_ERR(iwm, "Couldn't invalidate profile\n");
+			return ret;
+		}
+	}
+
 	if (chan)
 		iwm->channel =
 			ieee80211_frequency_to_channel(chan->center_freq);
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/9] iwmc3200wifi: Set WEP key from connect
  2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
  2009-09-01 13:13 ` [PATCH 1/9] iwmc3200wifi: invalidate profile when necessary before connect Samuel Ortiz
@ 2009-09-01 13:13 ` Samuel Ortiz
  2009-09-01 13:14 ` [PATCH 3/9] iwmc3200wifi: Fix sparse warning Samuel Ortiz
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:13 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

When connect is called with the LEGACY_PSK authentication type set, and a
proper sme->key, we need to set the WEP key straight after setting the
profile otherwise the authentication will never start.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |   44 +++++++++++++++++++++++++-
 1 files changed, 43 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 789ef5c..d8bb723 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -562,6 +562,7 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 {
 	struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
 	struct ieee80211_channel *chan = sme->channel;
+	struct key_params key_param;
 	int ret;
 
 	if (!test_bit(IWM_STATUS_READY, &iwm->status))
@@ -619,7 +620,48 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 			return ret;
 	}
 
-	return iwm_send_mlme_profile(iwm);
+	/*
+	 * We save the WEP key in case we want to do shared authentication.
+	 * We have to do it so because UMAC will assert whenever it gets a
+	 * key before a profile.
+	 */
+	if (sme->key) {
+		key_param.key = kmemdup(sme->key, sme->key_len, GFP_KERNEL);
+		if (key_param.key == NULL)
+			return -ENOMEM;
+		key_param.key_len = sme->key_len;
+		key_param.seq_len = 0;
+		key_param.cipher = sme->crypto.ciphers_pairwise[0];
+
+		ret = iwm_key_init(&iwm->keys[sme->key_idx], sme->key_idx,
+				   NULL, &key_param);
+		kfree(key_param.key);
+		if (ret < 0) {
+			IWM_ERR(iwm, "Invalid key_params\n");
+			return ret;
+		}
+
+		iwm->default_key = sme->key_idx;
+	}
+
+	ret = iwm_send_mlme_profile(iwm);
+
+	if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK ||
+	    sme->key == NULL)
+		return ret;
+
+	/*
+	 * We want to do shared auth.
+	 * We need to actually set the key we previously cached,
+	 * and then tell the UMAC it's the default one.
+	 * That will trigger the auth+assoc UMAC machinery, and again,
+	 * this must be done after setting the profile.
+	 */
+	ret = iwm_set_key(iwm, 0, &iwm->keys[sme->key_idx]);
+	if (ret < 0)
+		return ret;
+
+	return iwm_set_tx_key(iwm, iwm->default_key);
 }
 
 static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/9] iwmc3200wifi: Fix sparse warning
  2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
  2009-09-01 13:13 ` [PATCH 1/9] iwmc3200wifi: invalidate profile when necessary before connect Samuel Ortiz
  2009-09-01 13:13 ` [PATCH 2/9] iwmc3200wifi: Set WEP key from connect Samuel Ortiz
@ 2009-09-01 13:14 ` Samuel Ortiz
  2009-09-01 13:14 ` [PATCH 4/9] iwmc3200wifi: use cfg80211_roamed to send roam event Samuel Ortiz
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:14 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

iwm_cfg80211_get_station() should be static.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index d8bb723..2784b08 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -238,8 +238,9 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 	return iwm_set_tx_key(iwm, key_index);
 }
 
-int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
-			     u8 *mac, struct station_info *sinfo)
+static int iwm_cfg80211_get_station(struct wiphy *wiphy,
+				    struct net_device *ndev,
+				    u8 *mac, struct station_info *sinfo)
 {
 	struct iwm_priv *iwm = ndev_to_iwm(ndev);
 
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/9] iwmc3200wifi: use cfg80211_roamed to send roam event
  2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
                   ` (2 preceding siblings ...)
  2009-09-01 13:14 ` [PATCH 3/9] iwmc3200wifi: Fix sparse warning Samuel Ortiz
@ 2009-09-01 13:14 ` Samuel Ortiz
  2009-09-01 13:14 ` [PATCH 5/9] iwmc3200wifi: add disconnect work Samuel Ortiz
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:14 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

From: Zhu Yi <yi.zhu@intel.com>

The device sends connection terminated and [re]association success
(or failure) events when roaming occours. The patch uses
cfg80211_roamed instead of cfg80211_connect_result to notify SME
for roaming.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/net/wireless/iwmc3200wifi/cfg80211.c |    2 +-
 drivers/net/wireless/iwmc3200wifi/commands.c |    1 +
 drivers/net/wireless/iwmc3200wifi/iwm.h      |    2 +-
 drivers/net/wireless/iwmc3200wifi/rx.c       |   26 ++++++++++++++++++++------
 4 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 2784b08..a56a2b0 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -673,7 +673,7 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
 	IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
 
 	if (iwm->umac_profile_active)
-		return iwm_invalidate_mlme_profile(iwm);
+		iwm_invalidate_mlme_profile(iwm);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index a68a2af..23b52fa 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -756,6 +756,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
 		return ret;
 	}
 
+	set_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
 	return 0;
 }
 
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 7a51bc3..f054cc8 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -175,7 +175,7 @@ struct iwm_key {
 #define IWM_STATUS_READY		0
 #define IWM_STATUS_SCANNING		1
 #define IWM_STATUS_SCAN_ABORTING	2
-#define IWM_STATUS_ASSOCIATING		3
+#define IWM_STATUS_SME_CONNECTING	3
 #define IWM_STATUS_ASSOCIATED		4
 
 struct iwm_tx_queue {
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 86079a1..9e6f2cd 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -487,8 +487,6 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf,
 
 	start = (struct iwm_umac_notif_assoc_start *)buf;
 
-	set_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
-
 	IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n",
 		     start->bssid, le32_to_cpu(start->roam_reason));
 
@@ -507,14 +505,23 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 	IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
 		     complete->bssid, complete->status);
 
-	clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
-
 	switch (le32_to_cpu(complete->status)) {
 	case UMAC_ASSOC_COMPLETE_SUCCESS:
 		set_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
 		memcpy(iwm->bssid, complete->bssid, ETH_ALEN);
 		iwm->channel = complete->channel;
 
+		/* Internal roaming state, avoid notifying SME. */
+		if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
+		    && iwm->conf.mode == UMAC_MODE_BSS) {
+			cfg80211_roamed(iwm_to_ndev(iwm),
+					complete->bssid,
+					iwm->req_ie, iwm->req_ie_len,
+					iwm->resp_ie, iwm->resp_ie_len,
+					GFP_KERNEL);
+			break;
+		}
+
 		iwm_link_on(iwm);
 
 		if (iwm->conf.mode == UMAC_MODE_IBSS)
@@ -531,6 +538,11 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 		memset(iwm->bssid, 0, ETH_ALEN);
 		iwm->channel = 0;
 
+		/* Internal roaming state, avoid notifying SME. */
+		if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
+		    && iwm->conf.mode == UMAC_MODE_BSS)
+			break;
+
 		iwm_link_off(iwm);
 
 		if (iwm->conf.mode == UMAC_MODE_IBSS)
@@ -540,6 +552,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 					NULL, 0, NULL, 0,
 					WLAN_STATUS_UNSPECIFIED_FAILURE,
 					GFP_KERNEL);
+		break;
 	default:
 		break;
 	}
@@ -562,7 +575,7 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
 	IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n",
 		     le32_to_cpu(invalid->reason));
 
-	clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
+	clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
 	clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
 
 	iwm->umac_profile_active = 0;
@@ -813,7 +826,8 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
 		iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
 				       iwm->resp_ie_len, GFP_KERNEL);
 	} else {
-		IWM_ERR(iwm, "Unsupported management frame");
+		IWM_ERR(iwm, "Unsupported management frame: 0x%x",
+			cpu_to_le16(mgt->frame_control));
 		return 0;
 	}
 
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/9] iwmc3200wifi: add disconnect work
  2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
                   ` (3 preceding siblings ...)
  2009-09-01 13:14 ` [PATCH 4/9] iwmc3200wifi: use cfg80211_roamed to send roam event Samuel Ortiz
@ 2009-09-01 13:14 ` Samuel Ortiz
  2009-09-01 13:14 ` [PATCH 6/9] iwmc3200wifi: fix misuse of le16_to_cpu Samuel Ortiz
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:14 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

From: Zhu Yi <yi.zhu@intel.com>

When the driver receives "connection terminated" event from device,
it could be caused by 2 reasons: the firmware is roaming or the
connection is lost (AP disappears). For the former, an association
complete event is supposed to come within 3 seconds. For the latter,
the driver won't receive any event except the connection terminated.
So we kick a delayed work (5*HZ) when we receive the connection
terminated event. It will be canceled if it turns out to be a roaming
event later. Otherwise we notify SME and userspace the disconnection.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/net/wireless/iwmc3200wifi/iwm.h  |    1 +
 drivers/net/wireless/iwmc3200wifi/main.c |   21 +++++++++++++++++++
 drivers/net/wireless/iwmc3200wifi/rx.c   |   32 +++++++++++++++++++++++++----
 3 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index f054cc8..da49df6 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -273,6 +273,7 @@ struct iwm_priv {
 
 	struct iw_statistics wstats;
 	struct delayed_work stats_request;
+	struct delayed_work disconnect;
 
 	struct iwm_debugfs dbg;
 
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index cf25744..c41fa8c 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -108,6 +108,26 @@ static void iwm_statistics_request(struct work_struct *work)
 	iwm_send_umac_stats_req(iwm, 0);
 }
 
+static void iwm_disconnect_work(struct work_struct *work)
+{
+	struct iwm_priv *iwm =
+		container_of(work, struct iwm_priv, disconnect.work);
+
+	if (iwm->umac_profile_active)
+		iwm_invalidate_mlme_profile(iwm);
+
+	clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
+	iwm->umac_profile_active = 0;
+	memset(iwm->bssid, 0, ETH_ALEN);
+	iwm->channel = 0;
+
+	iwm_link_off(iwm);
+
+	wake_up_interruptible(&iwm->mlme_queue);
+
+	cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
+}
+
 int __iwm_up(struct iwm_priv *iwm);
 int __iwm_down(struct iwm_priv *iwm);
 
@@ -198,6 +218,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
 	spin_lock_init(&iwm->cmd_lock);
 	iwm->scan_id = 1;
 	INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
+	INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
 	INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
 	INIT_LIST_HEAD(&iwm->bss_list);
 
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 9e6f2cd..4d9793e 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -514,6 +514,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 		/* Internal roaming state, avoid notifying SME. */
 		if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
 		    && iwm->conf.mode == UMAC_MODE_BSS) {
+			cancel_delayed_work(&iwm->disconnect);
 			cfg80211_roamed(iwm_to_ndev(iwm),
 					complete->bssid,
 					iwm->req_ie, iwm->req_ie_len,
@@ -540,8 +541,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 
 		/* Internal roaming state, avoid notifying SME. */
 		if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
-		    && iwm->conf.mode == UMAC_MODE_BSS)
+		    && iwm->conf.mode == UMAC_MODE_BSS) {
+			cancel_delayed_work(&iwm->disconnect);
 			break;
+		}
 
 		iwm_link_off(iwm);
 
@@ -569,11 +572,18 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
 				       struct iwm_wifi_cmd *cmd)
 {
 	struct iwm_umac_notif_profile_invalidate *invalid;
+	u32 reason;
 
 	invalid = (struct iwm_umac_notif_profile_invalidate *)buf;
+	reason = le32_to_cpu(invalid->reason);
+
+	IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason);
 
-	IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n",
-		     le32_to_cpu(invalid->reason));
+	if (reason != UMAC_PROFILE_INVALID_REQUEST &&
+	    test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status))
+		cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL,
+					0, WLAN_STATUS_UNSPECIFIED_FAILURE,
+					GFP_KERNEL);
 
 	clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
 	clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -589,6 +599,19 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
 	return 0;
 }
 
+#define IWM_DISCONNECT_INTERVAL	(5 * HZ)
+
+static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf,
+					  unsigned long buf_size,
+					  struct iwm_wifi_cmd *cmd)
+{
+	IWM_DBG_MLME(iwm, DBG, "Connection terminated\n");
+
+	schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL);
+
+	return 0;
+}
+
 static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf,
 				  unsigned long buf_size,
 				  struct iwm_wifi_cmd *cmd)
@@ -848,8 +871,7 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
 	case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE:
 		return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd);
 	case WIFI_IF_NTFY_CONNECTION_TERMINATED:
-		IWM_DBG_MLME(iwm, DBG, "Connection terminated\n");
-		break;
+		return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd);
 	case WIFI_IF_NTFY_SCAN_COMPLETE:
 		return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd);
 	case WIFI_IF_NTFY_STA_TABLE_CHANGE:
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/9] iwmc3200wifi: fix misuse of le16_to_cpu
  2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
                   ` (4 preceding siblings ...)
  2009-09-01 13:14 ` [PATCH 5/9] iwmc3200wifi: add disconnect work Samuel Ortiz
@ 2009-09-01 13:14 ` Samuel Ortiz
  2009-09-01 13:14 ` [PATCH 7/9] iwmc3200wifi: New initial LMAC calibration Samuel Ortiz
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:14 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

From: Zhu Yi <yi.zhu@intel.com>

Also mark some functions static.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/net/wireless/iwmc3200wifi/main.c |    8 ++++----
 drivers/net/wireless/iwmc3200wifi/rx.c   |    2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index c41fa8c..6cf2f0c 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -128,8 +128,8 @@ static void iwm_disconnect_work(struct work_struct *work)
 	cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
 }
 
-int __iwm_up(struct iwm_priv *iwm);
-int __iwm_down(struct iwm_priv *iwm);
+static int __iwm_up(struct iwm_priv *iwm);
+static int __iwm_down(struct iwm_priv *iwm);
 
 static void iwm_reset_worker(struct work_struct *work)
 {
@@ -559,7 +559,7 @@ static int iwm_channels_init(struct iwm_priv *iwm)
 	return 0;
 }
 
-int __iwm_up(struct iwm_priv *iwm)
+static int __iwm_up(struct iwm_priv *iwm)
 {
 	int ret;
 	struct iwm_notif *notif_reboot, *notif_ack = NULL;
@@ -693,7 +693,7 @@ int iwm_up(struct iwm_priv *iwm)
 	return ret;
 }
 
-int __iwm_down(struct iwm_priv *iwm)
+static int __iwm_down(struct iwm_priv *iwm)
 {
 	int ret;
 
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 4d9793e..2daa586 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -850,7 +850,7 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
 				       iwm->resp_ie_len, GFP_KERNEL);
 	} else {
 		IWM_ERR(iwm, "Unsupported management frame: 0x%x",
-			cpu_to_le16(mgt->frame_control));
+			le16_to_cpu(mgt->frame_control));
 		return 0;
 	}
 
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/9] iwmc3200wifi: New initial LMAC calibration
  2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
                   ` (5 preceding siblings ...)
  2009-09-01 13:14 ` [PATCH 6/9] iwmc3200wifi: fix misuse of le16_to_cpu Samuel Ortiz
@ 2009-09-01 13:14 ` Samuel Ortiz
  2009-09-01 13:14 ` [PATCH 8/9] iwmc3200wifi: Handle UMAC stalls and UMAC assert properly Samuel Ortiz
  2009-09-01 13:14 ` [PATCH 9/9] iwmc3200wifi: Add a last_fw_err debugfs entry Samuel Ortiz
  8 siblings, 0 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:14 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

The LMAC calibration API got broken mostly by having a configuration bitmap
being different than the result one.
This patch tries to address that issue by correctly running calibrations with
the newest firmwares, and keeping a backward compatibility fallback path for
older firmwares, where the configuration and result bitmaps were identical.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/net/wireless/iwmc3200wifi/fw.c   |   56 +++++++++++++++++++++---------
 drivers/net/wireless/iwmc3200wifi/iwm.h  |    1 +
 drivers/net/wireless/iwmc3200wifi/lmac.h |   15 ++++++++
 drivers/net/wireless/iwmc3200wifi/main.c |    7 +++-
 4 files changed, 61 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
index 0f32cab..6b0bcad 100644
--- a/drivers/net/wireless/iwmc3200wifi/fw.c
+++ b/drivers/net/wireless/iwmc3200wifi/fw.c
@@ -261,6 +261,33 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
 			cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0);
 }
 
+static int iwm_init_calib(struct iwm_priv *iwm, unsigned long cfg_bitmap,
+			  unsigned long expected_bitmap, u8 rx_iq_cmd)
+{
+	/* Read RX IQ calibration result from EEPROM */
+	if (test_bit(rx_iq_cmd, &cfg_bitmap)) {
+		iwm_store_rxiq_calib_result(iwm);
+		set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
+	}
+
+	iwm_send_prio_table(iwm);
+	iwm_send_init_calib_cfg(iwm, cfg_bitmap);
+
+	while (iwm->calib_done_map != expected_bitmap) {
+		if (iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
+				     IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT)) {
+			IWM_DBG_FW(iwm, DBG, "Initial calibration timeout\n");
+			return -ETIMEDOUT;
+		}
+
+		IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
+			   "0x%lx, expected calibrations: 0x%lx\n",
+			   iwm->calib_done_map, expected_bitmap);
+	}
+
+	return 0;
+}
+
 /*
  * We currently have to load 3 FWs:
  * 1) The UMAC (Upper MAC).
@@ -276,6 +303,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
 int iwm_load_fw(struct iwm_priv *iwm)
 {
 	unsigned long init_calib_map, periodic_calib_map;
+	unsigned long expected_calib_map;
 	int ret;
 
 	/* We first start downloading the UMAC */
@@ -317,27 +345,21 @@ int iwm_load_fw(struct iwm_priv *iwm)
 	}
 
 	init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK;
+	expected_calib_map = iwm->conf.expected_calib_map &
+		IWM_CALIB_MAP_INIT_MSK;
 	periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map);
 
-	/* Read RX IQ calibration result from EEPROM */
-	if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) {
-		iwm_store_rxiq_calib_result(iwm);
-		set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
-	}
-
-	iwm_send_prio_table(iwm);
-	iwm_send_init_calib_cfg(iwm, init_calib_map);
-
-	while (iwm->calib_done_map != init_calib_map) {
-		ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
-				       IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
-		if (ret) {
-			IWM_ERR(iwm, "Wait for calibration result timeout\n");
+	ret = iwm_init_calib(iwm, init_calib_map, expected_calib_map,
+			     CALIB_CFG_RX_IQ_IDX);
+	if (ret < 0) {
+		/* Let's try the old way */
+		ret = iwm_init_calib(iwm, expected_calib_map,
+				     expected_calib_map,
+				     PHY_CALIBRATE_RX_IQ_CMD);
+		if (ret < 0) {
+			IWM_ERR(iwm, "Calibration result timeout\n");
 			goto out;
 		}
-		IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
-			   "0x%lx, requested calibrations: 0x%lx\n",
-			   iwm->calib_done_map, init_calib_map);
 	}
 
 	/* Handle LMAC CALIBRATION_COMPLETE notification */
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index da49df6..74964ee 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -64,6 +64,7 @@
 struct iwm_conf {
 	u32 sdio_ior_timeout;
 	unsigned long calib_map;
+	unsigned long expected_calib_map;
 	bool reset_on_fatal_err;
 	bool auto_connect;
 	bool wimax_not_present;
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index 19213e1..6c1a14c 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -396,9 +396,24 @@ enum {
 	CALIBRATION_CMD_NUM,
 };
 
+enum {
+	CALIB_CFG_RX_BB_IDX       = 0,
+	CALIB_CFG_DC_IDX          = 1,
+	CALIB_CFG_LO_IDX          = 2,
+	CALIB_CFG_TX_IQ_IDX       = 3,
+	CALIB_CFG_RX_IQ_IDX       = 4,
+	CALIB_CFG_NOISE_IDX       = 5,
+	CALIB_CFG_CRYSTAL_IDX     = 6,
+	CALIB_CFG_TEMPERATURE_IDX = 7,
+	CALIB_CFG_PAPD_IDX        = 8,
+	CALIB_CFG_LAST_IDX        = CALIB_CFG_PAPD_IDX,
+	CALIB_CFG_MODULE_NUM,
+};
+
 #define IWM_CALIB_MAP_INIT_MSK		0xFFFF
 #define IWM_CALIB_MAP_PER_LMAC(m)	((m & 0xFF0000) >> 16)
 #define IWM_CALIB_MAP_PER_UMAC(m)	((m & 0xFF000000) >> 24)
+#define IWM_CALIB_OPCODE_TO_INDEX(op)   (op - PHY_CALIBRATE_OPCODES_NUM)
 
 struct iwm_lmac_calib_hdr {
 	u8 opcode;
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 6cf2f0c..fc7fce4 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -53,7 +53,12 @@
 static struct iwm_conf def_iwm_conf = {
 
 	.sdio_ior_timeout	= 5000,
-	.calib_map		= BIT(PHY_CALIBRATE_DC_CMD)	|
+	.calib_map		= BIT(CALIB_CFG_DC_IDX)	|
+				  BIT(CALIB_CFG_LO_IDX)	|
+				  BIT(CALIB_CFG_TX_IQ_IDX)	|
+				  BIT(CALIB_CFG_RX_IQ_IDX)	|
+				  BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
+	.expected_calib_map	= BIT(PHY_CALIBRATE_DC_CMD)	|
 				  BIT(PHY_CALIBRATE_LO_CMD)	|
 				  BIT(PHY_CALIBRATE_TX_IQ_CMD)	|
 				  BIT(PHY_CALIBRATE_RX_IQ_CMD)	|
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 8/9] iwmc3200wifi: Handle UMAC stalls and UMAC assert properly
  2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
                   ` (6 preceding siblings ...)
  2009-09-01 13:14 ` [PATCH 7/9] iwmc3200wifi: New initial LMAC calibration Samuel Ortiz
@ 2009-09-01 13:14 ` Samuel Ortiz
  2009-09-01 13:14 ` [PATCH 9/9] iwmc3200wifi: Add a last_fw_err debugfs entry Samuel Ortiz
  8 siblings, 0 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:14 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

When UMAC stalls or asserts, we want to reset the device. But when we're
associated, the current reset worker will end up calling
cfg80211_connect_result() with the cfg80211 sme layer knowing that we're
reassociating. That ends up with some ugly warnings.
With this patch we're telling the upper layer that we've roamed if
reassociation succeeds, and that we're disconnected if it fails.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/net/wireless/iwmc3200wifi/iwm.h  |    2 ++
 drivers/net/wireless/iwmc3200wifi/main.c |   18 +++++++++++++++---
 drivers/net/wireless/iwmc3200wifi/rx.c   |   29 +++++++++++++++++++++++------
 3 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 74964ee..f5c2d6f 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -178,6 +178,7 @@ struct iwm_key {
 #define IWM_STATUS_SCAN_ABORTING	2
 #define IWM_STATUS_SME_CONNECTING	3
 #define IWM_STATUS_ASSOCIATED		4
+#define IWM_STATUS_RESETTING		5
 
 struct iwm_tx_queue {
 	int id;
@@ -317,6 +318,7 @@ int iwm_mode_to_nl80211_iftype(int mode);
 int iwm_priv_init(struct iwm_priv *iwm);
 void iwm_priv_deinit(struct iwm_priv *iwm);
 void iwm_reset(struct iwm_priv *iwm);
+void iwm_resetting(struct iwm_priv *iwm);
 void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
 			      struct iwm_umac_notif_alive *alive);
 int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb);
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index fc7fce4..6a5b76a 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -187,7 +187,8 @@ static void iwm_reset_worker(struct work_struct *work)
 		memcpy(iwm->umac_profile, profile, sizeof(*profile));
 		iwm_send_mlme_profile(iwm);
 		kfree(profile);
-	}
+	} else
+		clear_bit(IWM_STATUS_RESETTING, &iwm->status);
 
  out:
 	mutex_unlock(&iwm->mutex);
@@ -200,7 +201,7 @@ static void iwm_watchdog(unsigned long data)
 	IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n");
 
 	if (modparam_reset)
-		schedule_work(&iwm->reset_worker);
+		iwm_resetting(iwm);
 }
 
 int iwm_priv_init(struct iwm_priv *iwm)
@@ -284,7 +285,11 @@ void iwm_reset(struct iwm_priv *iwm)
 	if (test_bit(IWM_STATUS_READY, &iwm->status))
 		iwm_target_reset(iwm);
 
-	iwm->status = 0;
+	if (test_bit(IWM_STATUS_RESETTING, &iwm->status)) {
+		iwm->status = 0;
+		set_bit(IWM_STATUS_RESETTING, &iwm->status);
+	} else
+		iwm->status = 0;
 	iwm->scan_id = 1;
 
 	list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) {
@@ -300,6 +305,13 @@ void iwm_reset(struct iwm_priv *iwm)
 	iwm_link_off(iwm);
 }
 
+void iwm_resetting(struct iwm_priv *iwm)
+{
+	set_bit(IWM_STATUS_RESETTING, &iwm->status);
+
+	schedule_work(&iwm->reset_worker);
+}
+
 /*
  * Notification code:
  *
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 2daa586..14950b1 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -118,6 +118,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
 	IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status));
 	IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status));
 
+	iwm_resetting(iwm);
+
 	return 0;
 }
 
@@ -528,11 +530,19 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 		if (iwm->conf.mode == UMAC_MODE_IBSS)
 			goto ibss;
 
-		cfg80211_connect_result(iwm_to_ndev(iwm),
+		if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
+			cfg80211_connect_result(iwm_to_ndev(iwm),
+						complete->bssid,
+						iwm->req_ie, iwm->req_ie_len,
+						iwm->resp_ie, iwm->resp_ie_len,
+						WLAN_STATUS_SUCCESS,
+						GFP_KERNEL);
+		else
+			cfg80211_roamed(iwm_to_ndev(iwm),
 					complete->bssid,
 					iwm->req_ie, iwm->req_ie_len,
 					iwm->resp_ie, iwm->resp_ie_len,
-					WLAN_STATUS_SUCCESS, GFP_KERNEL);
+					GFP_KERNEL);
 		break;
 	case UMAC_ASSOC_COMPLETE_FAILURE:
 		clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -551,19 +561,26 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 		if (iwm->conf.mode == UMAC_MODE_IBSS)
 			goto ibss;
 
-		cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
-					NULL, 0, NULL, 0,
-					WLAN_STATUS_UNSPECIFIED_FAILURE,
-					GFP_KERNEL);
+		if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
+			cfg80211_connect_result(iwm_to_ndev(iwm),
+						complete->bssid,
+						NULL, 0, NULL, 0,
+						WLAN_STATUS_UNSPECIFIED_FAILURE,
+						GFP_KERNEL);
+		else
+			cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0,
+					      GFP_KERNEL);
 		break;
 	default:
 		break;
 	}
 
+	clear_bit(IWM_STATUS_RESETTING, &iwm->status);
 	return 0;
 
  ibss:
 	cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
+	clear_bit(IWM_STATUS_RESETTING, &iwm->status);
 	return 0;
 }
 
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 9/9] iwmc3200wifi: Add a last_fw_err debugfs entry
  2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
                   ` (7 preceding siblings ...)
  2009-09-01 13:14 ` [PATCH 8/9] iwmc3200wifi: Handle UMAC stalls and UMAC assert properly Samuel Ortiz
@ 2009-09-01 13:14 ` Samuel Ortiz
  8 siblings, 0 replies; 10+ messages in thread
From: Samuel Ortiz @ 2009-09-01 13:14 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, Zhu Yi, Samuel Ortiz

In order to check what was the last fw error we got accross resets, we add
this debugfs entry. It displays the complete ASSERT information.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/net/wireless/iwmc3200wifi/debug.h   |    2 +
 drivers/net/wireless/iwmc3200wifi/debugfs.c |  105 ++++++++++++++++++++++++++-
 drivers/net/wireless/iwmc3200wifi/iwm.h     |    2 +
 drivers/net/wireless/iwmc3200wifi/main.c    |    6 ++
 drivers/net/wireless/iwmc3200wifi/rx.c      |    2 +
 5 files changed, 113 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h
index 8fbb42d..e35c9b6 100644
--- a/drivers/net/wireless/iwmc3200wifi/debug.h
+++ b/drivers/net/wireless/iwmc3200wifi/debug.h
@@ -108,6 +108,8 @@ struct iwm_debugfs {
 	struct dentry *txq_dentry;
 	struct dentry *tx_credit_dentry;
 	struct dentry *rx_ticket_dentry;
+
+	struct dentry *fw_err_dentry;
 };
 
 #ifdef CONFIG_IWM_DEBUG
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c
index 0fa7b91..1465379 100644
--- a/drivers/net/wireless/iwmc3200wifi/debugfs.c
+++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c
@@ -98,7 +98,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules,
 			iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write,
 			"%llu\n");
 
-static int iwm_txrx_open(struct inode *inode, struct file *filp)
+static int iwm_generic_open(struct inode *inode, struct file *filp)
 {
 	filp->private_data = inode->i_private;
 	return 0;
@@ -289,25 +289,111 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
 	return ret;
 }
 
+static ssize_t iwm_debugfs_fw_err_read(struct file *filp,
+				       char __user *buffer,
+				       size_t count, loff_t *ppos)
+{
+
+	struct iwm_priv *iwm = filp->private_data;
+	char buf[512];
+	int buf_len = 512;
+	size_t len = 0;
+
+	if (*ppos != 0)
+		return 0;
+	if (count < sizeof(buf))
+		return -ENOSPC;
+
+	if (!iwm->last_fw_err)
+		return -ENOMEM;
+
+	if (iwm->last_fw_err->line_num == 0)
+		goto out;
+
+	len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n",
+	     (le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC)
+			? 'L' : 'U');
+	len += snprintf(buf + len, buf_len - len,
+			"\tCategory:    %d\n",
+			le32_to_cpu(iwm->last_fw_err->category));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tStatus:      0x%x\n",
+			le32_to_cpu(iwm->last_fw_err->status));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tPC:          0x%x\n",
+			le32_to_cpu(iwm->last_fw_err->pc));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tblink1:      %d\n",
+			le32_to_cpu(iwm->last_fw_err->blink1));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tblink2:      %d\n",
+			le32_to_cpu(iwm->last_fw_err->blink2));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tilink1:      %d\n",
+			le32_to_cpu(iwm->last_fw_err->ilink1));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tilink2:      %d\n",
+			le32_to_cpu(iwm->last_fw_err->ilink2));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tData1:       0x%x\n",
+			le32_to_cpu(iwm->last_fw_err->data1));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tData2:       0x%x\n",
+			le32_to_cpu(iwm->last_fw_err->data2));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tLine number: %d\n",
+			le32_to_cpu(iwm->last_fw_err->line_num));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tUMAC status: 0x%x\n",
+			le32_to_cpu(iwm->last_fw_err->umac_status));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tLMAC status: 0x%x\n",
+			le32_to_cpu(iwm->last_fw_err->lmac_status));
+
+	len += snprintf(buf + len, buf_len - len,
+			"\tSDIO status: 0x%x\n",
+			le32_to_cpu(iwm->last_fw_err->sdio_status));
+
+out:
+
+	return simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
+}
 
 static const struct file_operations iwm_debugfs_txq_fops = {
 	.owner =	THIS_MODULE,
-	.open =		iwm_txrx_open,
+	.open =		iwm_generic_open,
 	.read =		iwm_debugfs_txq_read,
 };
 
 static const struct file_operations iwm_debugfs_tx_credit_fops = {
 	.owner =	THIS_MODULE,
-	.open =		iwm_txrx_open,
+	.open =		iwm_generic_open,
 	.read =		iwm_debugfs_tx_credit_read,
 };
 
 static const struct file_operations iwm_debugfs_rx_ticket_fops = {
 	.owner =	THIS_MODULE,
-	.open =		iwm_txrx_open,
+	.open =		iwm_generic_open,
 	.read =		iwm_debugfs_rx_ticket_read,
 };
 
+static const struct file_operations iwm_debugfs_fw_err_fops = {
+	.owner =	THIS_MODULE,
+	.open =		iwm_generic_open,
+	.read =		iwm_debugfs_fw_err_read,
+};
+
 int iwm_debugfs_init(struct iwm_priv *iwm)
 {
 	int i, result;
@@ -423,6 +509,16 @@ int iwm_debugfs_init(struct iwm_priv *iwm)
 		goto error;
 	}
 
+	iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200,
+						     iwm->dbg.dbgdir, iwm,
+						     &iwm_debugfs_fw_err_fops);
+	result = PTR_ERR(iwm->dbg.fw_err_dentry);
+	if (IS_ERR(iwm->dbg.fw_err_dentry) && (result != -ENODEV)) {
+		IWM_ERR(iwm, "Couldn't create last FW err: %d\n", result);
+		goto error;
+	}
+
+
 	return 0;
 
  error:
@@ -441,6 +537,7 @@ void iwm_debugfs_exit(struct iwm_priv *iwm)
 	debugfs_remove(iwm->dbg.txq_dentry);
 	debugfs_remove(iwm->dbg.tx_credit_dentry);
 	debugfs_remove(iwm->dbg.rx_ticket_dentry);
+	debugfs_remove(iwm->dbg.fw_err_dentry);
 	if (iwm->bus_ops->debugfs_exit)
 		iwm->bus_ops->debugfs_exit(iwm);
 
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index f5c2d6f..1b02a4e 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -289,6 +289,8 @@ struct iwm_priv {
 	u8 *resp_ie;
 	int resp_ie_len;
 
+	struct iwm_fw_error_hdr *last_fw_err;
+
 	char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
 
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 6a5b76a..d668e47 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -260,6 +260,11 @@ int iwm_priv_init(struct iwm_priv *iwm)
 	iwm->watchdog.data = (unsigned long)iwm;
 	mutex_init(&iwm->mutex);
 
+	iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr),
+				   GFP_KERNEL);
+	if (iwm->last_fw_err == NULL)
+		return -ENOMEM;
+
 	return 0;
 }
 
@@ -271,6 +276,7 @@ void iwm_priv_deinit(struct iwm_priv *iwm)
 		destroy_workqueue(iwm->txq[i].wq);
 
 	destroy_workqueue(iwm->rx_wq);
+	kfree(iwm->last_fw_err);
 }
 
 /*
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 14950b1..40dbcbc 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -102,6 +102,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
 	error = (struct iwm_umac_notif_error *)buf;
 	fw_err = &error->err;
 
+	memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr));
+
 	IWM_ERR(iwm, "%cMAC FW ERROR:\n",
 	 (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
 	IWM_ERR(iwm, "\tCategory:    %d\n", le32_to_cpu(fw_err->category));
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2009-09-01 13:13 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-01 13:13 [PATCH 0/9] iwmc3200wifi updates Samuel Ortiz
2009-09-01 13:13 ` [PATCH 1/9] iwmc3200wifi: invalidate profile when necessary before connect Samuel Ortiz
2009-09-01 13:13 ` [PATCH 2/9] iwmc3200wifi: Set WEP key from connect Samuel Ortiz
2009-09-01 13:14 ` [PATCH 3/9] iwmc3200wifi: Fix sparse warning Samuel Ortiz
2009-09-01 13:14 ` [PATCH 4/9] iwmc3200wifi: use cfg80211_roamed to send roam event Samuel Ortiz
2009-09-01 13:14 ` [PATCH 5/9] iwmc3200wifi: add disconnect work Samuel Ortiz
2009-09-01 13:14 ` [PATCH 6/9] iwmc3200wifi: fix misuse of le16_to_cpu Samuel Ortiz
2009-09-01 13:14 ` [PATCH 7/9] iwmc3200wifi: New initial LMAC calibration Samuel Ortiz
2009-09-01 13:14 ` [PATCH 8/9] iwmc3200wifi: Handle UMAC stalls and UMAC assert properly Samuel Ortiz
2009-09-01 13:14 ` [PATCH 9/9] iwmc3200wifi: Add a last_fw_err debugfs entry Samuel Ortiz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).