brcmfmac: store usb fw images in local linked list.
authorHante Meuleman <meuleman@broadcom.com>
Wed, 19 Sep 2012 20:21:10 +0000 (22:21 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 24 Sep 2012 19:02:05 +0000 (15:02 -0400)
For suspend/resume it is necessary to store firmware in memory.
In order to support multiple usb dongles at the same time a linked
list of firmwares was created.

Reviewed-by: Arend Van Spriel <arend@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/brcm80211/brcmfmac/usb.c

index 03f59cd0572aeca0e0477728e6821f0040266cd0..edb431182d1093932c68bc7b31f831d0c9481085 100644 (file)
@@ -81,10 +81,12 @@ enum usbdev_suspend_state {
 };
 
 struct brcmf_usb_image {
-       void *data;
-       u32 len;
+       struct list_head list;
+       s8 *fwname;
+       u8 *image;
+       int image_len;
 };
-static struct brcmf_usb_image g_image = { NULL, 0 };
+static struct list_head fw_image_list;
 
 struct intr_transfer_buf {
        u32 notification;
@@ -1152,10 +1154,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
 {
        brcmf_dbg(TRACE, "devinfo %p\n", devinfo);
 
-       /* store the image globally */
-       g_image.data = devinfo->image;
-       g_image.len = devinfo->image_len;
-
        /* free the URBS */
        brcmf_usb_free_q(&devinfo->rx_freeq, false);
        brcmf_usb_free_q(&devinfo->tx_freeq, false);
@@ -1207,17 +1205,9 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
 {
        s8 *fwname;
        const struct firmware *fw;
+       struct brcmf_usb_image *fw_image;
        int err;
 
-       devinfo->image = g_image.data;
-       devinfo->image_len = g_image.len;
-
-       /*
-        * if we have an image we can leave here.
-        */
-       if (devinfo->image)
-               return 0;
-
        switch (devinfo->bus_pub.devid) {
        case 43143:
                fwname = BRCMF_USB_43143_FW_NAME;
@@ -1235,6 +1225,14 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
                break;
        }
 
+       list_for_each_entry(fw_image, &fw_image_list, list) {
+               if (fw_image->fwname == fwname) {
+                       devinfo->image = fw_image->image;
+                       devinfo->image_len = fw_image->image_len;
+                       return 0;
+               }
+       }
+       /* fw image not yet loaded. Load it now and add to list */
        err = request_firmware(&fw, fwname, devinfo->dev);
        if (!fw) {
                brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname);
@@ -1245,14 +1243,24 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
                return -EINVAL;
        }
 
-       devinfo->image = vmalloc(fw->size); /* plus nvram */
-       if (!devinfo->image)
+       fw_image = kzalloc(sizeof(*fw_image), GFP_ATOMIC);
+       if (!fw_image)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&fw_image->list);
+       list_add_tail(&fw_image->list, &fw_image_list);
+       fw_image->fwname = fwname;
+       fw_image->image = vmalloc(fw->size);
+       if (!fw_image->image)
                return -ENOMEM;
 
-       memcpy(devinfo->image, fw->data, fw->size);
-       devinfo->image_len = fw->size;
+       memcpy(fw_image->image, fw->data, fw->size);
+       fw_image->image_len = fw->size;
 
        release_firmware(fw);
+
+       devinfo->image = fw_image->image;
+       devinfo->image_len = fw_image->image_len;
+
        return 0;
 }
 
@@ -1594,15 +1602,25 @@ static struct usb_driver brcmf_usbdrvr = {
        .disable_hub_initiated_lpm = 1,
 };
 
+static void brcmf_release_fw(struct list_head *q)
+{
+       struct brcmf_usb_image *fw_image, *next;
+
+       list_for_each_entry_safe(fw_image, next, q, list) {
+               vfree(fw_image->image);
+               list_del_init(&fw_image->list);
+       }
+}
+
+
 void brcmf_usb_exit(void)
 {
        usb_deregister(&brcmf_usbdrvr);
-       vfree(g_image.data);
-       g_image.data = NULL;
-       g_image.len = 0;
+       brcmf_release_fw(&fw_image_list);
 }
 
 void brcmf_usb_init(void)
 {
+       INIT_LIST_HEAD(&fw_image_list);
        usb_register(&brcmf_usbdrvr);
 }