From: David Kilroy <kilroyd@googlemail.com>
To: linux-wireless@vger.kernel.org, orinoco-devel@lists.sourceforge.net
Cc: arvidjaar@mail.ru, linux-pm@lists.linux-foundation.org,
David Kilroy <kilroyd@googlemail.com>
Subject: [RFC PATCH 1/2] orinoco: Use PM notifier to cache firmware for use during resume
Date: Fri, 31 Oct 2008 01:15:42 +0000 [thread overview]
Message-ID: <1225415743-28209-2-git-send-email-kilroyd@googlemail.com> (raw)
In-Reply-To: <1225415743-28209-1-git-send-email-kilroyd@googlemail.com>
When preparing for either suspend or hibernation, load the necessary
firmware from userspace.
Upon error or resume, release the firmware.
Works for both Agere and Symbol firmware.
Signed-off by: David Kilroy <kilroyd@gmail.com>
---
drivers/net/wireless/orinoco.c | 140 +++++++++++++++++++++++++++++++---------
drivers/net/wireless/orinoco.h | 8 ++-
2 files changed, 115 insertions(+), 33 deletions(-)
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 653306f..190fcec 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -84,6 +84,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/firmware.h>
+#include <linux/suspend.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
@@ -431,9 +432,9 @@ struct fw_info {
};
const static struct fw_info orinoco_fw[] = {
- { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
- { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
- { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 }
+ { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
+ { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
+ { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
};
/* Structure used to access fields in FW
@@ -487,18 +488,17 @@ orinoco_dl_firmware(struct orinoco_private *priv,
if (err)
goto free;
- if (priv->cached_fw)
- fw_entry = priv->cached_fw;
- else {
+ if (!priv->cached_sta_fw) {
err = request_firmware(&fw_entry, firmware, priv->dev);
+
if (err) {
printk(KERN_ERR "%s: Cannot find firmware %s\n",
dev->name, firmware);
err = -ENOENT;
goto free;
}
- priv->cached_fw = fw_entry;
- }
+ } else
+ fw_entry = priv->cached_sta_fw;
hdr = (const struct orinoco_fw_header *) fw_entry->data;
@@ -540,11 +540,10 @@ orinoco_dl_firmware(struct orinoco_private *priv,
dev->name, hermes_present(hw));
abort:
- /* In case of error, assume firmware was bogus and release it */
- if (err) {
- priv->cached_fw = NULL;
+ /* If we requested the firmware, release it. Otherwise leave
+ * it to the PM notifier */
+ if (!priv->cached_sta_fw)
release_firmware(fw_entry);
- }
free:
kfree(pda);
@@ -621,7 +620,7 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
ret = hermes_init(hw);
/* hermes_reset() should return 0 with the secondary firmware */
- if (secondary && ret != 0)
+ if (secondary && (ret != 0))
return -ENODEV;
/* And this should work with any firmware */
@@ -648,34 +647,41 @@ symbol_dl_firmware(struct orinoco_private *priv,
int ret;
const struct firmware *fw_entry;
- if (request_firmware(&fw_entry, fw->pri_fw,
- priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->pri_fw);
- return -ENOENT;
- }
+ if (!priv->cached_pri_fw) {
+ if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
+ printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+ dev->name, fw->pri_fw);
+ return -ENOENT;
+ }
+ } else
+ fw_entry = priv->cached_pri_fw;
/* Load primary firmware */
ret = symbol_dl_image(priv, fw, fw_entry->data,
fw_entry->data + fw_entry->size, 0);
- release_firmware(fw_entry);
+
+ if (!priv->cached_pri_fw)
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR "%s: Primary firmware download failed\n",
dev->name);
return ret;
}
- if (request_firmware(&fw_entry, fw->sta_fw,
- priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->sta_fw);
- return -ENOENT;
- }
+ if (!priv->cached_sta_fw) {
+ if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
+ printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+ dev->name, fw->sta_fw);
+ return -ENOENT;
+ }
+ } else
+ fw_entry = priv->cached_sta_fw;
/* Load secondary firmware */
ret = symbol_dl_image(priv, fw, fw_entry->data,
fw_entry->data + fw_entry->size, 1);
- release_firmware(fw_entry);
+ if (!priv->cached_sta_fw)
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR "%s: Secondary firmware download failed\n",
dev->name);
@@ -3064,6 +3070,68 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id)
}
/********************************************************************/
+/* Power management */
+/********************************************************************/
+
+static int orinoco_pm_notifier(struct notifier_block *notifier,
+ unsigned long pm_event,
+ void *unused)
+{
+ struct orinoco_private *priv = container_of(notifier,
+ struct orinoco_private,
+ pm_notifier);
+
+ /* All we need to do is cache the firmware before suspend, and
+ * release it when we come out */
+
+ switch (pm_event) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ {
+ const struct firmware *fw_entry = NULL;
+ const char *pri_fw;
+ const char *sta_fw;
+
+ pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
+ sta_fw = orinoco_fw[priv->firmware_type].sta_fw;
+
+ if (pri_fw) {
+ if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
+ priv->cached_pri_fw = fw_entry;
+ }
+
+ if (sta_fw) {
+ if (request_firmware(&fw_entry, sta_fw, priv->dev) == 0)
+ priv->cached_sta_fw = fw_entry;
+ }
+
+ break;
+ }
+ case PM_POST_RESTORE:
+ /* Restore from hibernation failed. We need to clean
+ * up in exactly the same way, so fall through. */
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ if (priv->cached_pri_fw)
+ release_firmware(priv->cached_pri_fw);
+
+ if (priv->cached_sta_fw)
+ release_firmware(priv->cached_sta_fw);
+
+ priv->cached_pri_fw = NULL;
+ priv->cached_sta_fw = NULL;
+
+ break;
+
+ case PM_RESTORE_PREPARE:
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+/********************************************************************/
/* Initialization */
/********************************************************************/
@@ -3543,7 +3611,12 @@ struct net_device
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
- priv->cached_fw = NULL;
+ priv->cached_pri_fw = NULL;
+ priv->cached_sta_fw = NULL;
+
+ /* Register PM notifiers */
+ priv->pm_notifier.notifier_call = orinoco_pm_notifier;
+ register_pm_notifier(&priv->pm_notifier);
return dev;
}
@@ -3556,9 +3629,14 @@ void free_orinocodev(struct net_device *dev)
* when we call tasklet_kill it will run one final time,
* emptying the list */
tasklet_kill(&priv->rx_tasklet);
- if (priv->cached_fw)
- release_firmware(priv->cached_fw);
- priv->cached_fw = NULL;
+ unregister_pm_notifier(&priv->pm_notifier);
+
+ if (priv->cached_pri_fw)
+ release_firmware(priv->cached_pri_fw);
+ if (priv->cached_sta_fw)
+ release_firmware(priv->cached_sta_fw);
+ priv->cached_pri_fw = NULL;
+ priv->cached_sta_fw = NULL;
priv->wpa_ie_len = 0;
kfree(priv->wpa_ie);
orinoco_mic_free(priv);
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index 8c29538..5a9685a 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -10,6 +10,7 @@
#define DRIVER_VERSION "0.15"
#include <linux/interrupt.h>
+#include <linux/suspend.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
@@ -167,8 +168,11 @@ struct orinoco_private {
unsigned int tkip_cm_active:1;
unsigned int key_mgmt:3;
- /* Cached in memory firmware to use in ->resume */
- const struct firmware *cached_fw;
+ /* Cached in memory firmware to use during ->resume. */
+ const struct firmware *cached_pri_fw;
+ const struct firmware *cached_sta_fw;
+
+ struct notifier_block pm_notifier;
};
#ifdef ORINOCO_DEBUG
--
1.5.6.4
next prev parent reply other threads:[~2008-10-31 1:15 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-10-31 1:15 [RFC PATCH 0/2] orinoco: Don't keep cached firmware around permanently David Kilroy
2008-10-31 1:15 ` David Kilroy [this message]
2008-10-31 1:15 ` [RFC PATCH 2/2] orinoco: Resume spectrum_cs in the same way as orinoco_cs David Kilroy
2008-10-31 1:15 ` David Kilroy
2008-10-31 17:36 ` [RFC PATCH 1/2] orinoco: Use PM notifier to cache firmware for use during resume Andrey Borzenkov
2008-10-31 17:36 ` Andrey Borzenkov
2008-10-31 21:27 ` [linux-pm] " Rafael J. Wysocki
2008-10-31 21:27 ` Rafael J. Wysocki
2008-10-31 1:15 ` David Kilroy
2008-11-02 10:35 ` [RFC PATCH 0/2] orinoco: Don't keep cached firmware around permanently Andrey Borzenkov
2008-11-02 10:35 ` Andrey Borzenkov
2008-11-02 12:29 ` Dave
2008-11-02 12:29 ` Dave
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1225415743-28209-2-git-send-email-kilroyd@googlemail.com \
--to=kilroyd@googlemail.com \
--cc=arvidjaar@mail.ru \
--cc=linux-pm@lists.linux-foundation.org \
--cc=linux-wireless@vger.kernel.org \
--cc=orinoco-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.