* [PATCH 2/2] orinoco: cache downloadable firmware image in memory for use during resume
2008-10-11 14:16 [PATCH 1/2] orinoco: reload firmware on resume Andrey Borzenkov
@ 2008-10-11 14:21 ` Andrey Borzenkov
2008-10-11 17:59 ` Dave
0 siblings, 1 reply; 4+ messages in thread
From: Andrey Borzenkov @ 2008-10-11 14:21 UTC (permalink / raw)
To: orinoco-devel; +Cc: linux-wireless
[-- Attachment #1: Type: text/plain, Size: 4170 bytes --]
orinoco: cache downloadable firmware image in memory for use during resume
If card is using downloadable firmware (like Agere 9.x), firmware has
to be reloaded during resume. It is not possible to use request_firmware
for that, because tasks are still frozen, so request_firmware will
just timeout and fail. So cache firmware image in memory for later
reuse in ->resume method.
Signed-off-by: Andrey Borzenkov <arvidjaar@mail.ru>
---
Unfortunately this is the only way to do it given current infrastructure.
I think that extra memory cost (~60kb) does not warrant anything more
sophisticated - even if this is possible. Also users not using dowloadable
firmware won't be penalized at all.
drivers/net/wireless/orinoco.c | 42 ++++++++++++++++++++++++++++++----------
drivers/net/wireless/orinoco.h | 4 ++++
2 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 76c480b..204b2a6 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -487,15 +487,25 @@ orinoco_dl_firmware(struct orinoco_private *priv,
if (err)
goto free;
- 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;
+ if (!priv->cached_fw_data) {
+ 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_size = fw_entry->size;
+ priv->cached_fw_data = kmemdup(fw_entry->data, fw_entry->size,
+ GFP_KERNEL);
+ release_firmware(fw_entry);
+ if (!priv->cached_fw_data) {
+ err = -ENOMEM;
+ goto abort;
+ }
}
- hdr = (const struct orinoco_fw_header *) fw_entry->data;
+ hdr = (const struct orinoco_fw_header *) priv->cached_fw_data;
/* Enable aux port to allow programming */
err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
@@ -504,10 +514,10 @@ orinoco_dl_firmware(struct orinoco_private *priv,
goto abort;
/* Program data */
- first_block = (fw_entry->data +
+ first_block = (priv->cached_fw_data +
le16_to_cpu(hdr->headersize) +
le32_to_cpu(hdr->block_offset));
- end = fw_entry->data + fw_entry->size;
+ end = priv->cached_fw_data + priv->cached_fw_size;
err = hermes_program(hw, first_block, end);
printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
@@ -515,7 +525,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
goto abort;
/* Update production data */
- first_block = (fw_entry->data +
+ first_block = (priv->cached_fw_data +
le16_to_cpu(hdr->headersize) +
le32_to_cpu(hdr->pdr_offset));
@@ -535,7 +545,13 @@ orinoco_dl_firmware(struct orinoco_private *priv,
dev->name, hermes_present(hw));
abort:
- release_firmware(fw_entry);
+
+ /* If downloading failed, destroy cached copy */
+ if (err) {
+ priv->cached_fw_size = 0;
+ kfree(priv->cached_fw_data);
+ priv->cached_fw_data = NULL;
+ }
free:
kfree(pda);
@@ -3534,6 +3550,9 @@ struct net_device
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
+ priv->cached_fw_size = 0;
+ priv->cached_fw_data = NULL;
+
return dev;
}
@@ -3545,6 +3564,7 @@ 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);
+ kfree(priv->cached_fw_data);
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 981570b..403fff8 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -164,6 +164,10 @@ struct orinoco_private {
unsigned int wpa_enabled:1;
unsigned int tkip_cm_active:1;
unsigned int key_mgmt:3;
+
+ /* Cached firmware to use in ->resume */
+ u8 *cached_fw_data;
+ size_t cached_fw_size;
};
#ifdef ORINOCO_DEBUG
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] orinoco: cache downloadable firmware image in memory for use during resume
2008-10-11 14:21 ` [PATCH 2/2] orinoco: cache downloadable firmware image in memory for use during resume Andrey Borzenkov
@ 2008-10-11 17:59 ` Dave
2008-10-12 17:42 ` Andrey Borzenkov
0 siblings, 1 reply; 4+ messages in thread
From: Dave @ 2008-10-11 17:59 UTC (permalink / raw)
To: Andrey Borzenkov; +Cc: orinoco-devel, linux-wireless
Andrey Borzenkov wrote:
> orinoco: cache downloadable firmware image in memory for use during resume
>
> If card is using downloadable firmware (like Agere 9.x), firmware has
> to be reloaded during resume. It is not possible to use request_firmware
> for that, because tasks are still frozen, so request_firmware will
> just timeout and fail. So cache firmware image in memory for later
> reuse in ->resume method.
>
> Signed-off-by: Andrey Borzenkov <arvidjaar@mail.ru>
>
> ---
>
> Unfortunately this is the only way to do it given current infrastructure.
> I think that extra memory cost (~60kb) does not warrant anything more
> sophisticated - even if this is possible. Also users not using dowloadable
> firmware won't be penalized at all.
Spectrum_cs has had firmware download for a while. It achieves the firmware reload on resume by doing schedule_work(&priv->reset_work).
Would the same work for orinoco_cs?
If not, is there a way to avoid the caching when you've got the firmware built into the kernel image?
Regards,
Dave.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] orinoco: cache downloadable firmware image in memory for use during resume
2008-10-11 17:59 ` Dave
@ 2008-10-12 17:42 ` Andrey Borzenkov
0 siblings, 0 replies; 4+ messages in thread
From: Andrey Borzenkov @ 2008-10-12 17:42 UTC (permalink / raw)
To: Dave; +Cc: orinoco-devel, linux-wireless
[-- Attachment #1.1: Type: text/plain, Size: 1424 bytes --]
On Saturday 11 October 2008, Dave wrote:
> Andrey Borzenkov wrote:
> > orinoco: cache downloadable firmware image in memory for use during resume
> >
> > If card is using downloadable firmware (like Agere 9.x), firmware has
> > to be reloaded during resume. It is not possible to use request_firmware
> > for that, because tasks are still frozen, so request_firmware will
> > just timeout and fail. So cache firmware image in memory for later
> > reuse in ->resume method.
> >
> > Signed-off-by: Andrey Borzenkov <arvidjaar@mail.ru>
> >
> > ---
> >
> > Unfortunately this is the only way to do it given current infrastructure.
> > I think that extra memory cost (~60kb) does not warrant anything more
> > sophisticated - even if this is possible. Also users not using dowloadable
> > firmware won't be penalized at all.
>
> Spectrum_cs has had firmware download for a while. It achieves the firmware reload on resume by doing schedule_work(&priv->reset_work).
>
> Would the same work for orinoco_cs?
>
I think it could result in hard to trace race condition, because you really
have no way to synchronize it with unfreezing of udev.
> If not, is there a way to avoid the caching when you've got the firmware built into the kernel image?
>
Actually, yes. Patch attached. It needs some touching when (if) we start
supporting AP mode; right now only one kind of image is ever loaded.
[-- Attachment #1.2: 02-orinoco-cache-firmware-image-in-memory --]
[-- Type: text/x-diff, Size: 3035 bytes --]
Subject: [PATCH] orinoco: cache downloadable firmware image in memory for use during resume
From: Andrey Borzenkov <arvidjaar@mail.ru>
If card is using downloadable firmware (like Agere 9.x), firmware has
to be reloaded during resume. It is not possible to use request_firmware
for that, because tasks are still frozen, so request_firmware will
just timeout and fail. So cache firmware image in memory for later
reuse in ->resume method.
Signed-off-by: Andrey Borzenkov <arvidjaar@mail.ru>
---
drivers/net/wireless/orinoco.c | 28 +++++++++++++++++++++-------
drivers/net/wireless/orinoco.h | 5 +++++
2 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 722619c..8a15230 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -487,12 +487,17 @@ orinoco_dl_firmware(struct orinoco_private *priv,
if (err)
goto free;
- 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;
+ if (priv->cached_fw)
+ fw_entry = priv->cached_fw;
+ else {
+ 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;
}
hdr = (const struct orinoco_fw_header *) fw_entry->data;
@@ -535,7 +540,11 @@ orinoco_dl_firmware(struct orinoco_private *priv,
dev->name, hermes_present(hw));
abort:
- release_firmware(fw_entry);
+ /* In case of error, assume firmware was bogus and release it */
+ if (err) {
+ priv->cached_fw = NULL;
+ release_firmware(fw_entry);
+ }
free:
kfree(pda);
@@ -3534,6 +3543,8 @@ struct net_device
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
+ priv->cached_fw = NULL;
+
return dev;
}
@@ -3545,6 +3556,9 @@ 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;
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 981570b..8c29538 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -66,6 +66,8 @@ struct orinoco_rx_data {
struct list_head list;
};
+struct firmware;
+
struct orinoco_private {
void *card; /* Pointer to card dependent structure */
struct device *dev;
@@ -164,6 +166,9 @@ struct orinoco_private {
unsigned int wpa_enabled:1;
unsigned int tkip_cm_active:1;
unsigned int key_mgmt:3;
+
+ /* Cached in memory firmware to use in ->resume */
+ const struct firmware *cached_fw;
};
#ifdef ORINOCO_DEBUG
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] orinoco: cache downloadable firmware image in memory for use during resume
@ 2008-10-26 8:29 Andrey Borzenkov
0 siblings, 0 replies; 4+ messages in thread
From: Andrey Borzenkov @ 2008-10-26 8:29 UTC (permalink / raw)
To: linux-wireless; +Cc: orinoco-devel
[-- Attachment #1: Type: text/plain, Size: 3459 bytes --]
From: Andrey Borzenkov <arvidjaar@mail.ru>
Date: Sun, 19 Oct 2008 12:06:11 +0400
Subject: [PATCH 2/2] orinoco: cache downloadable firmware image in memory for use during resume
If card is using downloadable firmware (like Agere 9.x), firmware has
to be reloaded during resume. It is not possible to use request_firmware
for that, because tasks are still frozen, so request_firmware will
just timeout and fail. So cache firmware image in memory for later
reuse in ->resume method.
Signed-off-by: Andrey Borzenkov <arvidjaar@mail.ru>
---
This version transparently works both with external and built-in firmware.
In case of built in extra overhead is one "struct firmware".
spectrum_cs has used delayed work to reset card after resume. After
reading multiple discussions on lkml I got impression, that this is
unreliable - there is no way to sycnronize delayed task with unfreezing
of user space.
drivers/net/wireless/orinoco.c | 28 +++++++++++++++++++++-------
drivers/net/wireless/orinoco.h | 5 +++++
2 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 860803e..653306f 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -487,12 +487,17 @@ orinoco_dl_firmware(struct orinoco_private *priv,
if (err)
goto free;
- 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;
+ if (priv->cached_fw)
+ fw_entry = priv->cached_fw;
+ else {
+ 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;
}
hdr = (const struct orinoco_fw_header *) fw_entry->data;
@@ -535,7 +540,11 @@ orinoco_dl_firmware(struct orinoco_private *priv,
dev->name, hermes_present(hw));
abort:
- release_firmware(fw_entry);
+ /* In case of error, assume firmware was bogus and release it */
+ if (err) {
+ priv->cached_fw = NULL;
+ release_firmware(fw_entry);
+ }
free:
kfree(pda);
@@ -3534,6 +3543,8 @@ struct net_device
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
+ priv->cached_fw = NULL;
+
return dev;
}
@@ -3545,6 +3556,9 @@ 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;
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 981570b..8c29538 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -66,6 +66,8 @@ struct orinoco_rx_data {
struct list_head list;
};
+struct firmware;
+
struct orinoco_private {
void *card; /* Pointer to card dependent structure */
struct device *dev;
@@ -164,6 +166,9 @@ struct orinoco_private {
unsigned int wpa_enabled:1;
unsigned int tkip_cm_active:1;
unsigned int key_mgmt:3;
+
+ /* Cached in memory firmware to use in ->resume */
+ const struct firmware *cached_fw;
};
#ifdef ORINOCO_DEBUG
--
1.6.0.2
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2008-10-26 8:29 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-10-26 8:29 [PATCH 2/2] orinoco: cache downloadable firmware image in memory for use during resume Andrey Borzenkov
-- strict thread matches above, loose matches on Subject: below --
2008-10-11 14:16 [PATCH 1/2] orinoco: reload firmware on resume Andrey Borzenkov
2008-10-11 14:21 ` [PATCH 2/2] orinoco: cache downloadable firmware image in memory for use during resume Andrey Borzenkov
2008-10-11 17:59 ` Dave
2008-10-12 17:42 ` Andrey Borzenkov
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.