Skip to content

Commit

Permalink
wireless: ath9k-htc: only load firmware in need
Browse files Browse the repository at this point in the history
It is not necessary to hold the firmware memory during the whole
driver lifetime, and obviously it does waste memory. Suppose there
are 4 ath9k-htc usb dongles working, kernel has to consume about
4*50KBytes RAM to cache firmware for all dongles. After applying the
patch, kernel only caches one single firmware image in RAM for
all ath9k-htc devices just during system suspend/resume cycle.

When system is ready for loading firmware, ath9k-htc can request
the loading from usersapce. During system resume, ath9k-htc still
can load the firmware which was cached in kernel memory before
system suspend.

Cc: ath9k-devel@lists.ath9k.org
Cc: "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
Cc: Jouni Malinen <jouni@qca.qualcomm.com>
Cc: Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
Cc: Senthil Balasubramanian <senthilb@qca.qualcomm.com>
Cc: "John W. Linville" <linville@tuxdriver.com>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Ming Lei authored and John W. Linville committed Sep 7, 2012
1 parent ee91592 commit 32e31de
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 12 deletions.
33 changes: 22 additions & 11 deletions drivers/net/wireless/ath/ath9k/hif_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -973,8 +973,8 @@ static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
{
int transfer, err;
const void *data = hif_dev->firmware->data;
size_t len = hif_dev->firmware->size;
const void *data = hif_dev->fw_data;
size_t len = hif_dev->fw_size;
u32 addr = AR9271_FIRMWARE;
u8 *buf = kzalloc(4096, GFP_KERNEL);
u32 firm_offset;
Expand Down Expand Up @@ -1017,7 +1017,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
return -EIO;

dev_info(&hif_dev->udev->dev, "ath9k_htc: Transferred FW: %s, size: %ld\n",
hif_dev->fw_name, (unsigned long) hif_dev->firmware->size);
hif_dev->fw_name, (unsigned long) hif_dev->fw_size);

return 0;
}
Expand Down Expand Up @@ -1099,11 +1099,11 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)

hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb,
&hif_dev->udev->dev);
if (hif_dev->htc_handle == NULL) {
goto err_fw;
}
if (hif_dev->htc_handle == NULL)
goto err_dev_alloc;

hif_dev->firmware = fw;
hif_dev->fw_data = fw->data;
hif_dev->fw_size = fw->size;

/* Proceed with initialization */

Expand All @@ -1121,6 +1121,8 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
goto err_htc_hw_init;
}

release_firmware(fw);
hif_dev->flags |= HIF_USB_READY;
complete(&hif_dev->fw_done);

return;
Expand All @@ -1129,8 +1131,8 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
ath9k_hif_usb_dev_deinit(hif_dev);
err_dev_init:
ath9k_htc_hw_free(hif_dev->htc_handle);
err_dev_alloc:
release_firmware(fw);
hif_dev->firmware = NULL;
err_fw:
ath9k_hif_usb_firmware_fail(hif_dev);
}
Expand Down Expand Up @@ -1277,11 +1279,10 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)

wait_for_completion(&hif_dev->fw_done);

if (hif_dev->firmware) {
if (hif_dev->flags & HIF_USB_READY) {
ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
ath9k_htc_hw_free(hif_dev->htc_handle);
ath9k_hif_usb_dev_deinit(hif_dev);
release_firmware(hif_dev->firmware);
}

usb_set_intfdata(interface, NULL);
Expand Down Expand Up @@ -1317,13 +1318,23 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface)
struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
struct htc_target *htc_handle = hif_dev->htc_handle;
int ret;
const struct firmware *fw;

ret = ath9k_hif_usb_alloc_urbs(hif_dev);
if (ret)
return ret;

if (hif_dev->firmware) {
if (hif_dev->flags & HIF_USB_READY) {
/* request cached firmware during suspend/resume cycle */
ret = request_firmware(&fw, hif_dev->fw_name,
&hif_dev->udev->dev);
if (ret)
goto fail_resume;

hif_dev->fw_data = fw->data;
hif_dev->fw_size = fw->size;
ret = ath9k_hif_usb_download_fw(hif_dev);
release_firmware(fw);
if (ret)
goto fail_resume;
} else {
Expand Down
4 changes: 3 additions & 1 deletion drivers/net/wireless/ath/ath9k/hif_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,14 @@ struct cmd_buf {
};

#define HIF_USB_START BIT(0)
#define HIF_USB_READY BIT(1)

struct hif_device_usb {
struct usb_device *udev;
struct usb_interface *interface;
const struct usb_device_id *usb_device_id;
const struct firmware *firmware;
const void *fw_data;
size_t fw_size;
struct completion fw_done;
struct htc_target *htc_handle;
struct hif_usb_tx tx;
Expand Down

0 comments on commit 32e31de

Please sign in to comment.