orinoco: cache downloadable firmware image in memory for use during resume
authorAndrey Borzenkov <arvidjaar@mail.ru>
Sun, 19 Oct 2008 08:06:11 +0000 (12:06 +0400)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 31 Oct 2008 23:02:34 +0000 (19:02 -0400)
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>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco.h

index 7bd1559..5a39166 100644 (file)
@@ -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);
@@ -3532,6 +3541,8 @@ struct net_device
        netif_carrier_off(dev);
        priv->last_linkstatus = 0xffff;
 
+       priv->cached_fw = NULL;
+
        return dev;
 }
 
@@ -3543,6 +3554,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);
index 981570b..8c29538 100644 (file)
@@ -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