Commit 803599d4 authored by Hante Meuleman's avatar Hante Meuleman Committed by John W. Linville

brcmfmac: store usb fw images in local linked list.

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: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 30c52bcf
...@@ -81,10 +81,12 @@ enum usbdev_suspend_state { ...@@ -81,10 +81,12 @@ enum usbdev_suspend_state {
}; };
struct brcmf_usb_image { struct brcmf_usb_image {
void *data; struct list_head list;
u32 len; 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 { struct intr_transfer_buf {
u32 notification; u32 notification;
...@@ -1152,10 +1154,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo) ...@@ -1152,10 +1154,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
{ {
brcmf_dbg(TRACE, "devinfo %p\n", 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 */ /* free the URBS */
brcmf_usb_free_q(&devinfo->rx_freeq, false); brcmf_usb_free_q(&devinfo->rx_freeq, false);
brcmf_usb_free_q(&devinfo->tx_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) ...@@ -1207,17 +1205,9 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
{ {
s8 *fwname; s8 *fwname;
const struct firmware *fw; const struct firmware *fw;
struct brcmf_usb_image *fw_image;
int err; 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) { switch (devinfo->bus_pub.devid) {
case 43143: case 43143:
fwname = BRCMF_USB_43143_FW_NAME; fwname = BRCMF_USB_43143_FW_NAME;
...@@ -1235,6 +1225,14 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) ...@@ -1235,6 +1225,14 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
break; 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); err = request_firmware(&fw, fwname, devinfo->dev);
if (!fw) { if (!fw) {
brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname); 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) ...@@ -1245,14 +1243,24 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
return -EINVAL; return -EINVAL;
} }
devinfo->image = vmalloc(fw->size); /* plus nvram */ fw_image = kzalloc(sizeof(*fw_image), GFP_ATOMIC);
if (!devinfo->image) 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; return -ENOMEM;
memcpy(devinfo->image, fw->data, fw->size); memcpy(fw_image->image, fw->data, fw->size);
devinfo->image_len = fw->size; fw_image->image_len = fw->size;
release_firmware(fw); release_firmware(fw);
devinfo->image = fw_image->image;
devinfo->image_len = fw_image->image_len;
return 0; return 0;
} }
...@@ -1594,15 +1602,25 @@ static struct usb_driver brcmf_usbdrvr = { ...@@ -1594,15 +1602,25 @@ static struct usb_driver brcmf_usbdrvr = {
.disable_hub_initiated_lpm = 1, .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) void brcmf_usb_exit(void)
{ {
usb_deregister(&brcmf_usbdrvr); usb_deregister(&brcmf_usbdrvr);
vfree(g_image.data); brcmf_release_fw(&fw_image_list);
g_image.data = NULL;
g_image.len = 0;
} }
void brcmf_usb_init(void) void brcmf_usb_init(void)
{ {
INIT_LIST_HEAD(&fw_image_list);
usb_register(&brcmf_usbdrvr); usb_register(&brcmf_usbdrvr);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment