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: 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>
This commit is contained in:
committed by
John W. Linville
parent
30c52bcf5c
commit
803599d404
@ -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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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 = {
|
|||||||
.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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user