Bug? 2.6.29-rc1 on cat /proc/net/wireless

Jonathan Cameron jic23 at cam.ac.uk
Mon Jan 12 10:00:06 EST 2009


Jonathan Cameron wrote:
> Sorry all if this has already been fixed, but with 2.6.29-rc1 +
> Colin McCabe's alignment fix of the other day (can't see the
> relevance but that's what I'm running) just got the following
> with an sdio connected 8686. I'll try tracking this one down
> tomorrow if I don't hear anything.
> 
> cat /proc/net/wireless
> BUG: scheduling while atomic: cat/1272/0x00000002
> Modules linked in: max1363 ring_sw iio_trig_periodic_rtc industrialio rtc_pxa27x rtc_core libertas_sdio libertas lib80211 pxamci mmc_core
> [<c00227c8>] (dump_stack+0x0/0x14) from [<c00318f4>] (__schedule_bug+0x4c/0x58)
> [<c00318a8>] (__schedule_bug+0x0/0x58) from [<c020c61c>] (__sched_text_start+0x64/0x308)
>  r4:c1116000
> [<c020c5b8>] (__sched_text_start+0x0/0x308) from [<bf025b3c>] (__lbs_cmd+0xd8/0x154 [libertas])
> [<bf025a64>] (__lbs_cmd+0x0/0x154 [libertas]) from [<bf021eec>] (lbs_get_wireless_stats+0xec/0x26c [libertas])
> [<bf021e00>] (lbs_get_wireless_stats+0x0/0x26c [libertas]) from [<c020a0b4>] (get_wireless_stats+0x30/0x3c)
> [<c020a084>] (get_wireless_stats+0x0/0x3c) from [<c020a24c>] (wireless_seq_show+0x38/0x110)
> [<c020a214>] (wireless_seq_show+0x0/0x110) from [<c00a668c>] (seq_read+0x2ac/0x404)
>  r5:c1117ee8 r4:c1194000
> [<c00a63e0>] (seq_read+0x0/0x404) from [<c00c6ec4>] (proc_reg_read+0xac/0xc0)
> [<c00c6e18>] (proc_reg_read+0x0/0xc0) from [<c008d2f0>] (vfs_read+0xc8/0x14c)
> [<c008d228>] (vfs_read+0x0/0x14c) from [<c008d620>] (sys_read+0x4c/0x74)
>  r7:00000000 r6:c1117f78 r5:c1387c80 r4:c1387ca0
> [<c008d5d4>] (sys_read+0x0/0x74) from [<c001ef00>] (ret_fast_syscall+0x0/0x2c)
>  r8:c001f0a4 r7:00000003 r6:00000003 r5:bea33c64 r4:00001000
> Inter-| sta-|   Quality        |   Discarded packets               | Missed | WE
>  face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon | 22
>   eth0: 0002   95.  -36.  -81.       0    363      0   1179 236246        0
> 
A bit of googling suggests this has been a much discussed problem in other drivers.

How about the following patch as a work around? Bit messy at the mo, but I want
to check people are happy with basic form before cleaning up (and confirming
everything relevant has been set!)

Basically does the same as various other wireless drivers and actually gives you
the values from the last time it was queried rather than current.

--

diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index b1326e6..e51e1c5 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1345,7 +1345,7 @@ void lbs_set_mac_control(struct lbs_private *priv)
  *  @param cmd_action	command action: GET or SET
  *  @param wait_option	wait option: wait response or not
  *  @param cmd_oid	cmd oid: treated as sub command
- *  @param pdata_buf	A pointer to informaion buffer
+ *  @param pdata_buf	A pointer to information buffer
  *  @return 		0 or -1
  */
 int lbs_prepare_and_send_command(struct lbs_private *priv,
@@ -1487,6 +1487,13 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
 		ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
 		break;
 
+	case CMD_802_11_GET_LOG:
+		cmdptr->command = cpu_to_le16(CMD_802_11_GET_LOG);
+		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) +
+					    S_DS_GEN);
+		ret = 0;
+		break;
+
 	case CMD_GET_TSF:
 		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
 		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
@@ -1496,6 +1503,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
 	case CMD_802_11_BEACON_CTRL:
 		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
 		break;
+
 	default:
 		lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
 		ret = -1;
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 14f54ad..af18b5d 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -200,7 +200,21 @@ static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
 			get_unaligned_le16(&bcn_ctrl->beacon_period);
 	}
 
+	lbs_deb_leave(LBS_DEB_CMD);
+	return 0;
+}
+
+static int lbs_ret_802_11_get_log(struct lbs_private * priv,
+					struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_get_log *log = &resp->params.log;
+
 	lbs_deb_enter(LBS_DEB_CMD);
+	priv->wstats.discard.retries = get_unaligned_le32(&log->retry);
+	priv->wstats.discard.code = get_unaligned_le32(&log->wepundecryptable);
+	priv->wstats.discard.misc = get_unaligned_le32(&log->ackfailure);
+	lbs_deb_leave(LBS_DEB_CMD);
+
 	return 0;
 }
 
@@ -284,7 +298,9 @@ static inline int handle_cmd_response(struct lbs_private *priv,
 	case CMD_RET(CMD_802_11_BEACON_CTRL):
 		ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
 		break;
-
+	case CMD_RET(CMD_802_11_GET_LOG):
+		ret = lbs_ret_802_11_get_log(priv, resp);
+		break;
 	default:
 		lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
 			   get_unaligned_le16(&resp->command));
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index c6d5771..00423f7 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -736,6 +736,7 @@ struct cmd_ds_command {
 
 	/* command Body */
 	union {
+		struct cmd_ds_802_11_get_log log;
 		struct cmd_ds_802_11_ps_mode psmode;
 		struct cmd_ds_802_11_associate associate;
 		struct cmd_ds_802_11_authenticate auth;
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index e1700a1..8c7201f 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -789,7 +789,6 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
 	int stats_valid = 0;
 	u8 rssi;
 	u32 tx_retries;
-	struct cmd_ds_802_11_get_log log;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -805,12 +804,11 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
 	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
 	     priv->NF[TYPE_BEACON][TYPE_NOAVG]);
 
-	if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+	if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0)
 		priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
-	} else {
+	else
 		priv->wstats.qual.noise =
 		    CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-	}
 
 	lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
 	lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
@@ -831,13 +829,11 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
 	quality = rssi_qual;
 
 	/* Quality by TX errors */
-	priv->wstats.discard.retries = priv->stats.tx_errors;
+	/* Previously this line was here, but the value was overwritten
+	 * a few lines later.
+	 * priv->wstats.discard.retries = priv->stats.tx_errors; */
 
-	memset(&log, 0, sizeof(log));
-	log.hdr.size = cpu_to_le16(sizeof(log));
-	lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
-
-	tx_retries = get_unaligned_le32(&log.retry);
+	tx_retries = priv->wstats.discard.retries;
 
 	if (tx_retries > 75)
 		tx_qual = (90 - tx_retries) * POOR / 15;
@@ -847,16 +843,12 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
 		tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
 	else if (tx_retries > 50)
 		tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
-		    15 + GOOD;
+			15 + GOOD;
 	else
 		tx_qual = (50 - tx_retries) *
-		    (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+			(PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
 	quality = min(quality, tx_qual);
 
-	priv->wstats.discard.code = get_unaligned_le32(&log.wepundecryptable);
-	priv->wstats.discard.retries = tx_retries;
-	priv->wstats.discard.misc = get_unaligned_le32(&log.ackfailure);
-
 	/* Calculate quality */
 	priv->wstats.qual.qual = min_t(u8, quality, 100);
 	priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
@@ -865,6 +857,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
 	/* update stats asynchronously for future calls */
 	lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
 					0, 0, NULL);
+
+	lbs_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0,
+				     0, 0, NULL);
 out:
 	if (!stats_valid) {
 		priv->wstats.miss.beacon = 0;



More information about the libertas-dev mailing list