Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+41 −23
Original line number Original line Diff line number Diff line
@@ -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);
}
}