From patchwork Sat Aug 4 04:01:30 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ming Lei X-Patchwork-Id: 1272941 Return-Path: X-Original-To: patchwork-linux-wireless@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id F083C3FD57 for ; Sat, 4 Aug 2012 04:03:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754213Ab2HDEDe (ORCPT ); Sat, 4 Aug 2012 00:03:34 -0400 Received: from mail-pb0-f46.google.com ([209.85.160.46]:45263 "EHLO mail-pb0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751000Ab2HDEDa (ORCPT ); Sat, 4 Aug 2012 00:03:30 -0400 Received: by mail-pb0-f46.google.com with SMTP id rp8so2344343pbb.19 for ; Fri, 03 Aug 2012 21:03:29 -0700 (PDT) Received: by 10.68.236.129 with SMTP id uu1mr2250593pbc.77.1344053009704; Fri, 03 Aug 2012 21:03:29 -0700 (PDT) Received: from localhost ([183.37.208.115]) by mx.google.com with ESMTPS id gj10sm4199504pbc.18.2012.08.03.21.03.24 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 03 Aug 2012 21:03:28 -0700 (PDT) From: Ming Lei To: Linus Torvalds , Greg Kroah-Hartman Cc: "Rafael J. Wysocki" , Borislav Petkov , linux-kernel@vger.kernel.org, Ming Lei , linux-wireless@vger.kernel.org, "Luis R. Rodriguez" , Jouni Malinen , Vasanthakumar Thiagarajan , Senthil Balasubramanian , "John W. Linville" Subject: [RFC PATCH v1 15/15] wireless: ath9k-htc: only load firmware in need Date: Sat, 4 Aug 2012 12:01:30 +0800 Message-Id: <1344052890-31935-16-git-send-email-ming.lei@canonical.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1344052890-31935-1-git-send-email-ming.lei@canonical.com> References: <1344052890-31935-1-git-send-email-ming.lei@canonical.com> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org 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: linux-wireless@vger.kernel.org Cc: "Luis R. Rodriguez" Cc: Jouni Malinen Cc: Vasanthakumar Thiagarajan Cc: Senthil Balasubramanian Cc: "John W. Linville" Signed-off-by: Ming Lei --- drivers/net/wireless/ath/ath9k/hif_usb.c | 34 ++++++++++++++++++++---------- drivers/net/wireless/ath/ath9k/hif_usb.h | 4 +++- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index aa327ad..d35a19c 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -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; @@ -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; } @@ -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 */ @@ -1111,6 +1111,8 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) if (ret) goto err_dev_init; + release_firmware(fw); + ret = ath9k_htc_hw_init(hif_dev->htc_handle, &hif_dev->interface->dev, hif_dev->usb_device_id->idProduct, @@ -1121,6 +1123,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) goto err_htc_hw_init; } + hif_dev->flags |= HIF_USB_READY; complete(&hif_dev->fw_done); return; @@ -1129,8 +1132,8 @@ err_htc_hw_init: 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); } @@ -1277,11 +1280,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); @@ -1317,13 +1319,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 { diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 487ff65..51496e7 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -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;