diff mbox

[1/2] libertas: add ability to power off card on suspend

Message ID 1312280832-27675-1-git-send-email-anarsoul@gmail.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Vasily Khoruzhick Aug. 2, 2011, 10:27 a.m. UTC
Could be usefull if it's not possible to keep power on the card
when host goes into suspend.

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
 drivers/net/wireless/libertas/dev.h  |    3 ++-
 drivers/net/wireless/libertas/main.c |   22 +++++++++++++++-------
 2 files changed, 17 insertions(+), 8 deletions(-)

Comments

Daniel Drake Aug. 2, 2011, 10:54 a.m. UTC | #1
On 2 August 2011 11:27, Vasily Khoruzhick <anarsoul@gmail.com> wrote:
> Could be usefull if it's not possible to keep power on the card
> when host goes into suspend.

If it's not possible to keep power during suspend, then I don't see
why you need to explicitly turn it off on the way down.

If power can be maintained, this is going to confuse userspace. If the
network interface is up while you go into suspend, this code would
kick in and power down the device. Then, during resume, it would power
it up again. During this whole time, the network interface has
remained UP, so userspace isn't aware that anything has happened. But,
since the hardware has been powered off and on again, it has lost all
state (association, encryption keys, etc).

The way we handle this in libertas_sdio is that if we don't want the
card powered during suspend, we ask the MMC layer to remove the
device. This causes the remove function to be run, and the interface
disappears. During resume, it gets probed again from scratch, which
then prompts userspace into deciding which network to connect to,
reprogramming keys, etc.

Daniel
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vasily Khoruzhick Aug. 2, 2011, 8:09 p.m. UTC | #2
On Tuesday 02 August 2011 13:54:07 Daniel Drake wrote:
> On 2 August 2011 11:27, Vasily Khoruzhick <anarsoul@gmail.com> wrote:
> > Could be usefull if it's not possible to keep power on the card
> > when host goes into suspend.
> 
> If it's not possible to keep power during suspend, then I don't see
> why you need to explicitly turn it off on the way down.

Because no one puts interface down before suspend?
I just re-tested - if interface is up - kernel does not put it down before 
suspend, so I got a lot of timeouts and errors on dmesg after resume.

Regards
Vasily
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Daniel Drake Aug. 2, 2011, 8:32 p.m. UTC | #3
On 2 August 2011 21:09, Vasily Khoruzhick <anarsoul@gmail.com> wrote:
> Because no one puts interface down before suspend?
> I just re-tested - if interface is up - kernel does not put it down before
> suspend, so I got a lot of timeouts and errors on dmesg after resume.

I can't see how this would have been influenced by my work.

Your resume handler should already be fixing up the hardware state so
that it can be operated (regardless of any power saving that might
come into effect), or otherwise your suspend handler should cause the
device to be removed so that it can be reprobed completely during
resume.

Daniel
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vasily Khoruzhick Aug. 2, 2011, 9:12 p.m. UTC | #4
On Tuesday 02 August 2011 23:32:27 Daniel Drake wrote:
> On 2 August 2011 21:09, Vasily Khoruzhick <anarsoul@gmail.com> wrote:
> > Because no one puts interface down before suspend?
> > I just re-tested - if interface is up - kernel does not put it down
> > before suspend, so I got a lot of timeouts and errors on dmesg after
> > resume.
> 
> I can't see how this would have been influenced by my work.

Now generic libertas driver controls power, not if_spi. So it should be able 
to turn off card before going suspend. Messing with power in if_* and generic 
part does not look like a good idea to me.

> Your resume handler should already be fixing up the hardware state so
> that it can be operated (regardless of any power saving that might
> come into effect), or otherwise your suspend handler should cause the
> device to be removed so that it can be reprobed completely during
> resume.

My resume handler calls lbs_suspend to detach device, and it expects that 
lbs_suspend will disable card power.
 
> Daniel

Regards
Vasily
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Daniel Drake Aug. 2, 2011, 10:32 p.m. UTC | #5
On 2 August 2011 22:12, Vasily Khoruzhick <anarsoul@gmail.com> wrote:
> Now generic libertas driver controls power, not if_spi. So it should be able
> to turn off card before going suspend. Messing with power in if_* and generic
> part does not look like a good idea to me.

But there's no way your approach will bring good results. Userspace
won't see any interface state change, but the entire hardware and
firmware will be fully reset. Things will get very confused.

A lot of the stuff done in stop_iface is not relevant for the suspend
case. e.g. If commands were queued before suspend, they should execute
after resume. stop_iface is designed to run when the userspace-visible
interfaces are brought down - by running it while they are still up,
you will confuse things.

You are battling with a general suspend/resume problem which should be
handled by suspend/resume handlers alone. libertas already has plenty
of experience in this area which you can build upon.

Daniel
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index f526633..563a8b0 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -86,9 +86,10 @@  struct lbs_private {
 	/* Hardware access */
 	void *card;
 	bool iface_running;
+	bool suspend_iface_status;
 	u8 fw_ready;
 	u8 surpriseremoved;
-	u8 setup_fw_on_resume;
+	u8 disable_on_suspend;
 	int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
 	void (*reset_card) (struct lbs_private *priv);
 	int (*power_save) (struct lbs_private *priv);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 208e4d9..5522202 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -644,7 +644,7 @@  done:
 
 int lbs_suspend(struct lbs_private *priv)
 {
-	int ret;
+	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_FW);
 
@@ -658,7 +658,13 @@  int lbs_suspend(struct lbs_private *priv)
 		priv->deep_sleep_required = 1;
 	}
 
-	ret = lbs_set_host_sleep(priv, 1);
+	if (priv->disable_on_suspend) {
+		/* Disable card */
+		priv->suspend_iface_status = priv->iface_running;
+		if (priv->iface_running)
+			lbs_stop_iface(priv);
+	} else
+		ret = lbs_set_host_sleep(priv, 1);
 
 	netif_device_detach(priv->dev);
 	if (priv->mesh_dev)
@@ -671,11 +677,16 @@  EXPORT_SYMBOL_GPL(lbs_suspend);
 
 int lbs_resume(struct lbs_private *priv)
 {
-	int ret;
+	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_FW);
 
-	ret = lbs_set_host_sleep(priv, 0);
+	if (priv->disable_on_suspend) {
+		/* Enable card */
+		if (priv->suspend_iface_status)
+			lbs_start_iface(priv);
+	} else
+		ret = lbs_set_host_sleep(priv, 0);
 
 	netif_device_attach(priv->dev);
 	if (priv->mesh_dev)
@@ -689,9 +700,6 @@  int lbs_resume(struct lbs_private *priv)
 				   "deep sleep activation failed: %d\n", ret);
 	}
 
-	if (priv->setup_fw_on_resume)
-		ret = lbs_setup_firmware(priv);
-
 	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
 	return ret;
 }