[RFC PATCH] libertas: turn radio off when down

Dan Williams dcbw at redhat.com
Wed Nov 21 01:41:47 EST 2007


On Tue, 2007-11-20 at 21:45 -0800, Ashish Shukla wrote:
> Mesh forwarding is always on. Therefore, disabling radio when interface
> in not up will disable mesh forwarding as well. Have you thought of
> this?

Yes, though interactions with suspend/resume need to be investigated
here.

First, if NM is told to sleep and marks the device down (ohm would be
doing this normally via a lid button event or such), that means that
either somebody is on an airplane, or the laptop really, really should
get turned _all_ the way off without mesh forwarding.

If you would like to keep mesh forwarding on, the mesh device shouldn't
be brought down [1].  This leads into suspend/resume land.  Basically,
when the machine suspends, the mesh device should be kept IFF_UP and NM
shouldn't be told to sleep, since this will be happening very often on
OLPC.  I'm not sure if the networking core closes the device on suspend,
hopefully not; if it doesn't close the device, then nothing else should
be touching it and things will work correctly.

Last I knew there were cases where mesh forwarding was _not_ supposed to
be on due to the high power drain of the 8388 when the radio was
enabled, plus the airplane case.  As long as the networking core doesn't
close the devices on suspend, this patch shouldn't have side-effects on
mesh forwarding.

Dan

[1] when doing long suspends, when the resume occurs userspace will need
to redo the networking setup anyway, scanning and searching for the
school server or default mesh channel, because a long suspend most
likely means you changed location and increases the likelihood that the
networking situation around you changed as well.

> Thanks
> -Ashish
> 
> > -----Original Message-----
> > From: devel-bounces at lists.laptop.org
> [mailto:devel-bounces at lists.laptop.org] On Behalf Of Dan
> > Williams
> > Sent: Wednesday, November 21, 2007 9:48 AM
> > To: devel at laptop.org
> > Cc: Brajesh Dave; Andres Salomon
> > Subject: [RFC PATCH] libertas: turn radio off when down
> > 
> > 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_ */
> > 
> > _______________________________________________
> > Devel mailing list
> > Devel at lists.laptop.org
> > http://lists.laptop.org/listinfo/devel




More information about the Devel mailing list