[RFC PATCH] libertas: turn radio off when down

Dan Williams dcbw at redhat.com
Tue Nov 20 23:18:07 EST 2007


Backport of a patch to olpc-2.6 I'm going to post to linux-wireless.
When both interfaces are down (~IFF_UP), turn off the radio to save
power.  When either interface is opened (via iwconfig up or otherwise)
turn the radio back on unless the radio was explicitly disabled by the
user via 'iwconfig txpower off' which also is the previous behavior
without this patch.

This should allow NetworkManager to be told to go to sleep, at which
point it will mark all devices down, and with this patch should turn off
the radio and save power.

It also cleans up some of the mess that was *_open, the intent for which
(unless I'm reading that code wrong) was just to check whether the
interface was up or not, since that's what open/close do.

Comments?

Signed-off-by: Dan Williams <dcbw at redhat.com>

diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index caf0b1c..5a15b56 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -479,6 +479,8 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
 	return 0;
 }
 
+#define TURN_ON_RF  0x01
+
 static int wlan_cmd_802_11_radio_control(wlan_private * priv,
 					 struct cmd_ds_command *cmd,
 					 int cmd_action)
@@ -510,7 +512,7 @@ static int wlan_cmd_802_11_radio_control(wlan_private * priv,
 		break;
 	}
 
-	if (adapter->radioon)
+	if (adapter->radio_on)
 		pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
 	else
 		pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
@@ -1112,7 +1114,7 @@ int libertas_set_radio_control(wlan_private * priv)
 				    CMD_OPTION_WAITFORRSP, 0, NULL);
 
 	lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
-	       priv->adapter->radioon, priv->adapter->preamble);
+	       priv->adapter->radio_on, priv->adapter->preamble);
 
 	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return ret;
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index d391391..433d481 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -991,7 +991,7 @@ int libertas_process_event(wlan_private * priv)
 		}
 		lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
 		adapter->mesh_connect_status = LIBERTAS_CONNECTED;
-		if (priv->mesh_open == 1) {
+		if (priv->mesh_dev->flags & IFF_UP) {
 			netif_wake_queue(priv->mesh_dev);
 			netif_carrier_on(priv->mesh_dev);
 		}
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 404ca50..62c3e75 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -100,9 +100,6 @@ struct wlan_mesh_stats {
 
 /** Private structure for the MV device */
 struct _wlan_private {
-	int open;
-	int mesh_open;
-	int infra_open;
 	int mesh_autostart_enabled;
 	__le16 boot2_version;
 
@@ -339,7 +336,8 @@ struct _wlan_adapter {
 	u16 nextSNRNF;
 	u16 numSNRNF;
 
-	u8 radioon;
+	u8 user_radio_on;
+	u8 radio_on;
 	u32 preamble;
 
 	/** data rate stuff */
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 00d5675..eb516be 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -183,10 +183,6 @@
 #define CMD_TYPE_SHORT_PREAMBLE             0x0002
 #define CMD_TYPE_LONG_PREAMBLE              0x0003
 
-#define TURN_ON_RF                              0x01
-#define RADIO_ON                                0x01
-#define RADIO_OFF                               0x00
-
 #define SET_AUTO_PREAMBLE                       0x05
 #define SET_SHORT_PREAMBLE                      0x03
 #define SET_LONG_PREAMBLE                       0x01
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 2b104d2..f07d5b4 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -11,7 +11,9 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/kthread.h>
+#if CONFIG_OLPC
 #include <asm/olpc.h>
+#endif
 
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
@@ -406,8 +408,6 @@ static int libertas_dev_open(struct net_device *dev)
 
 	lbs_deb_enter(LBS_DEB_NET);
 
-	priv->open = 1;
-
 	if (adapter->connect_status == LIBERTAS_CONNECTED) {
 		netif_carrier_on(priv->dev);
 	} 
@@ -433,20 +433,33 @@ static int libertas_dev_open(struct net_device *dev)
  */
 static int libertas_mesh_open(struct net_device *dev)
 {
-	wlan_private *priv = (wlan_private *) dev->priv ;
+	wlan_private *priv = (wlan_private *) dev->priv;
+	int ret = -1;
+
+	lbs_deb_enter(LBS_DEB_NET);
 
 	if (pre_open_check(dev) == -1)
-		return -1;
-	priv->mesh_open = 1 ;
+		goto out;
+
+	/* Turn the radio on unless it was turned off by the user */
+	if (priv->adapter->user_radio_on)
+		libertas_set_radio_on (priv, 1);
+
 	netif_wake_queue(priv->mesh_dev);
 
-        priv->adapter->mesh_connect_status = LIBERTAS_CONNECTED;
+	priv->adapter->mesh_connect_status = LIBERTAS_CONNECTED;
 
 	netif_carrier_on(priv->mesh_dev);
 	netif_wake_queue(priv->mesh_dev);
-	if (priv->infra_open == 0)
-		return libertas_dev_open(priv->dev) ;
-	return 0;
+
+	if (!(priv->dev->flags & IFF_UP))
+		ret = libertas_dev_open(priv->dev);
+	else
+		ret = 0;
+
+out:
+	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+	return ret;
 }
 
 /**
@@ -457,15 +470,28 @@ static int libertas_mesh_open(struct net_device *dev)
  */
 static int libertas_open(struct net_device *dev)
 {
-	wlan_private *priv = (wlan_private *) dev->priv ;
+	wlan_private *priv = (wlan_private *) dev->priv;
+	int ret = -1;
+
+	lbs_deb_enter(LBS_DEB_NET);
+
+	if (pre_open_check(dev) == -1)
+		goto out;
+
+	/* Turn the radio on unless it was turned off by the user */
+	if (priv->adapter->user_radio_on)
+		libertas_set_radio_on (priv, 1);
 
-	if(pre_open_check(dev) == -1)
-		return -1;
-	priv->infra_open = 1 ;
 	netif_wake_queue(priv->dev);
-	if (priv->open == 0)
-		return libertas_dev_open(priv->dev) ;
-	return 0;
+
+	if (!(priv->mesh_dev->flags & IFF_UP))
+		ret = libertas_dev_open(priv->dev);
+	else
+		ret = 0;
+
+out:
+	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+	return ret;
 }
 
 static int libertas_dev_close(struct net_device *dev)
@@ -475,7 +501,6 @@ static int libertas_dev_close(struct net_device *dev)
 	lbs_deb_enter(LBS_DEB_NET);
 
 	netif_carrier_off(priv->dev);
-	priv->open = 0;
 
 	lbs_deb_leave(LBS_DEB_NET);
 	return 0;
@@ -491,12 +516,15 @@ static int libertas_mesh_close(struct net_device *dev)
 {
 	wlan_private *priv = (wlan_private *) (dev->priv);
 
-	priv->mesh_open = 0;
 	netif_stop_queue(priv->mesh_dev);
-	if (priv->infra_open == 0)
+	if (!(priv->dev->flags & IFF_UP)) {
+		/* Turn the radio off if neither interface is up */
+		libertas_set_radio_on (priv, 0);
+
 		return libertas_dev_close(dev);
-	else
-		return 0;
+	}
+
+	return 0;
 }
 
 /**
@@ -510,11 +538,14 @@ static int libertas_close(struct net_device *dev)
 	wlan_private *priv = (wlan_private *) dev->priv;
 
 	netif_stop_queue(dev);
-	priv->infra_open = 0;
-	if (priv->mesh_open == 0)
+	if (!(priv->mesh_dev->flags & IFF_UP)) {
+		/* Turn the radio off if neither interface is up */
+		libertas_set_radio_on (priv, 0);
+
 		return libertas_dev_close(dev);
-	else
-		return 0;
+	}
+
+	return 0;
 }
 
 
@@ -1148,7 +1179,8 @@ static void wlan_init_adapter(wlan_private * priv)
 	adapter->currentpacketfilter =
 	    CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
 
-	adapter->radioon = RADIO_ON;
+	adapter->radio_on = 1;
+	adapter->user_radio_on = adapter->radio_on;
 
 	adapter->auto_rate = 1;
 	adapter->cur_rate = 0;
@@ -1234,8 +1266,6 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
 
 	priv->dev = dev;
 	priv->card = card;
-	priv->mesh_open = 0;
-	priv->infra_open = 0;
 
 	SET_MODULE_OWNER(dev);
 
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 11f9389..61b31fa 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -111,16 +111,18 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
  *  @option 			Radio Option
  *  @return 	   		0 --success, otherwise fail
  */
-static int wlan_radio_ioctl(wlan_private * priv, u8 option)
+int libertas_set_radio_on(wlan_private * priv, u8 on)
 {
 	int ret = 0;
 	wlan_adapter *adapter = priv->adapter;
 
+	on = on ? 0x01 : 0x00;
+
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (adapter->radioon != option) {
-		lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
-		adapter->radioon = option;
+	if (adapter->radio_on != on) {
+		lbs_deb_wext("turning radio %s\n", on ? "on" : "off");
+		adapter->radio_on = on;
 
 		ret = libertas_prepare_and_send_command(priv,
 					    CMD_802_11_RADIO_CONTROL,
@@ -451,7 +453,7 @@ static int wlan_get_txpow(struct net_device *dev,
 	lbs_deb_wext("tx power level %d dbm\n", adapter->txpowerlevel);
 	vwrq->value = adapter->txpowerlevel;
 	vwrq->fixed = 1;
-	if (adapter->radioon) {
+	if (adapter->radio_on) {
 		vwrq->disabled = 0;
 		vwrq->flags = IW_TXPOW_DBM;
 	} else {
@@ -1885,19 +1887,20 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
 	int ret = 0;
 	wlan_private *priv = dev->priv;
 	wlan_adapter *adapter = priv->adapter;
-
 	u16 dbm;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	if (vwrq->disabled) {
-		wlan_radio_ioctl(priv, RADIO_OFF);
+		adapter->user_radio_on = 0;
+		libertas_set_radio_on(priv, 0);
 		return 0;
 	}
 
 	adapter->preamble = CMD_TYPE_AUTO_PREAMBLE;
+	adapter->user_radio_on = 1;
 
-	wlan_radio_ioctl(priv, RADIO_ON);
+	libertas_set_radio_on(priv, 1);
 
 	/* Userspace check in iwrange if it should use dBm or mW,
 	 * therefore this should never happen... Jean II */
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
index e93853b..d01c54a 100644
--- a/drivers/net/wireless/libertas/wext.h
+++ b/drivers/net/wireless/libertas/wext.h
@@ -67,5 +67,6 @@ struct wlan_ioctl_regrdwr {
 extern struct iw_handler_def libertas_handler_def;
 extern struct iw_handler_def mesh_handler_def;
 int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+int libertas_set_radio_on(wlan_private * priv, u8 on);
 
 #endif				/* _WLAN_WEXT_H_ */




More information about the Devel mailing list