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: 7+ 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 17:36 ` [RFC PATCH 1/2] orinoco: Use PM notifier to cache firmware for use during resume Andrey Borzenkov
2008-10-31 21:27 ` [linux-pm] " Rafael J. Wysocki
2008-11-02 10:35 ` [RFC PATCH 0/2] orinoco: Don't keep cached firmware around permanently Andrey Borzenkov
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).