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@xxxxxxx> > > > > --- > > > > 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.
Subject: [PATCH] orinoco: cache downloadable firmware image in memory for use during resume From: Andrey Borzenkov <arvidjaar@xxxxxxx> 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@xxxxxxx> --- 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:
signature.asc
Description: This is a digitally signed message part.