From patchwork Fri Nov 10 09:27:15 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wright Feng X-Patchwork-Id: 10052649 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 6DC2E6035D for ; Fri, 10 Nov 2017 09:21:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 654492B235 for ; Fri, 10 Nov 2017 09:21:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 599E32B241; Fri, 10 Nov 2017 09:21:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4B3532B235 for ; Fri, 10 Nov 2017 09:21:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752503AbdKJJVW (ORCPT ); Fri, 10 Nov 2017 04:21:22 -0500 Received: from mail-co1nam03on0129.outbound.protection.outlook.com ([104.47.40.129]:53568 "EHLO NAM03-CO1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751601AbdKJJVQ (ORCPT ); Fri, 10 Nov 2017 04:21:16 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cycorp.onmicrosoft.com; s=selector1-cypress-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=0hJ79FrZE3hAY0v7rFbJA0C4PvlvjtIw+23rTQFTT6c=; b=A+IQo6Z63uJFyCkXOEGluVL7pn/spOqPKdMuosnlIX1YZCXRBkB/3HkaKfWeVOLEaHfJE5cJhCjY6iV4GtkeN5HXNp515DIBQ22P8uo2yad8j+j0mOLOoexUkFdnIsCIFYY8gd7Wp7IYSfQmbaSpENtSOw5eN3L+jFQODf6epHk= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Wright.Feng@cypress.com; Received: from localhost (61.222.14.99) by DM5PR0601MB3590.namprd06.prod.outlook.com (2603:10b6:4:7c::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.197.13; Fri, 10 Nov 2017 09:21:13 +0000 From: Wright Feng To: arend.vanspriel@broadcom.com, franky.lin@broadcom.com, hante.meuleman@broadcom.com, kvalo@codeaurora.org, chi-hsien.lin@cypress.com Cc: wright.feng@cypress.com, linux-wireless@vger.kernel.org, brcm80211-dev-list.pdl@broadcom.com, Chung-Hsien Hsu Subject: [PATCH v7] brcmfmac: add CLM download support Date: Fri, 10 Nov 2017 17:27:15 +0800 Message-Id: <1510306035-12196-1-git-send-email-wright.feng@cypress.com> X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 X-Originating-IP: [61.222.14.99] X-ClientProxiedBy: KAXPR01CA0015.jpnprd01.prod.outlook.com (2603:1096:402:19::25) To DM5PR0601MB3590.namprd06.prod.outlook.com (2603:10b6:4:7c::12) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: b0c6f1a3-2573-40dd-16b4-08d5281c6402 X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001)(48565401081)(4534020)(4602075)(4627115)(201703031133081)(201702281549075)(2017052603199); SRVR:DM5PR0601MB3590; X-Microsoft-Exchange-Diagnostics: 1; DM5PR0601MB3590; 3:NTYrNTfPkf+AcmhR7wEQ2V76LaYHfxKHx0GCWlHJh3DFkwooYbjoM7umkhXfFjQQvOGQcc1pDcUHNrOIQBWSbFFZfOAojnkiaD1C4e3dX8qUN56rq/7f+w12Q+Eo9nTiivGRfvg/lgYsKkcpexBDRv++P9VRNK+bMW+kZBt/vicwv43F2Y4zNElRZStEB9ocCPA5wHQbNZFE2cqV6IbKoJRzJqrhpkN8OHNBTCYLMxkBH99CZDG6+xFTh/0A2lCn; 25:fBGbTLtXl/Fuz8ze67Ccnpw+VxZTQ6Iki9RkK03e2ce8lCdfVz2vfp+zmYW66zREKXpIAaEavGz6NbiXzk2Abf/fTBqJzhFtUtLUOaiqt6OlpnXnYe9mBCoM0ZCeMGd+9phXU4GOAc871ZzCzMqnovt3VNd50pkzGdYkgE04Hh8GW9kyUDMAlI0TxNRyZg5FEfCCkxGpUqeIzNZlnYW2OlilLkvPi6LZ0Met/Pc9vkq35TR913zXBEI2UJXt9NCxlmpsCl/YOXPPLgfy2BMU0dmlWltNu7YE6/x5lLeNvqUjuLSwxEarlu6DiIZSCzK3I6XoMTaSCXEdz1P4sZWpYw==; 31:s2L5jFiKsULqGqTpGBAV+4ZNef1InocjPP8MsRCJ2ibvkNyMfP8q8zU1KxJco3WBtukN+O6mLJmFsNckZyJjcXClPfpXv3gtT28NRT5xfVR43SxtdRwEuf3hyJ4gjS09hPR72/Yu+Ct05oHcMy6AZLsv+9LXr5Q7ObpnsHUzWrAtS88RNdYUit35yqjWhPqyK3X1PPVS0TlhrhmunMmHPs8dSpKmNiL6grdOOP2JyBk= X-MS-TrafficTypeDiagnostic: DM5PR0601MB3590: X-Microsoft-Exchange-Diagnostics: 1; DM5PR0601MB3590; 20:2urksutTaa5OWxc6kKHlQckyH23sDSZWhiraLF8RRGP94aa94zVe/0MngvexT+AOm8YF1mh6Mpiw1QZ823ivHcqKVcvyASQQCJanqaouyIXQieC+A3E1adbA17B1JYNegg3rqnaBs7fb0TVbT3RGeyMkvranyeyJFUqp5mdiaiaFvQYNqmU0P3ezaEm0oBJ1UKya4lA1VL4jyXOU/3BZ3b4NWdaA3eX1LHL1wMCSRaWez0hGMV57T/iiUlh1Fa6S4EZ8GzV4/xK79m75Les8Uk6VmPwDUQKrVJIsAUpGxzxvrZ6JznG/CGxShZFZ2SYfwlIjT8LVDdL+4cv1XkHRz0vIWtcP+jVgK2Y7Of0z7HR3whyos+7JK9wu01S0xVfE6yWf2pkARjc+BXda8HxBQK9FtMm5TSPNy8jM5LP2nG/Md4Ihsm8UMuJhWW8bRE4hzRKOaFcYf04yEZcSw+kA+n+mLZOLTh55f3XYPxCHhf1op4uP3cQj3xcjJ+2kAxsL; 4:f2aHGKVImLFjoiUXYeKP47s7BBj5bFUir46/22vYPOuLjWtSnM0guD7ZkyuPU0X6cG8T8ZMY0Ws8uelKZeUJevEC86tdMTgGrhVCLlwnT8G5TUWqSjMQBUDmQIZOPqQfNwEHLmWF28IQTAblJfmIxdtjfj+iMfHP3F/M0rGEbuGy1bBzbDAIONIVCjMMff85Qd742M/kkUmFxePwnK0prJeqNGI2ztU8mAfHLoJH3wG5gxrZ9gw4I/UyXgQ9D909s2YXmTDQ09rqz03+ALc6ntgLcgnN2a51kvYWEeajwqF/2RjRLNldoJ0K/FHClpz7g99cQzXiViUAypcmY0oKBw== X-Exchange-Antispam-Report-Test: UriScan:(258095267146985)(788757137089); X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(8121501046)(5005006)(100000703101)(100105400095)(3231021)(10201501046)(3002001)(93006095)(93001095)(6055026)(6041248)(20161123560025)(20161123564025)(20161123562025)(20161123555025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123558100)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095); SRVR:DM5PR0601MB3590; BCL:0; PCL:0; RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095); SRVR:DM5PR0601MB3590; X-Forefront-PRVS: 0487C0DB7E X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(6069001)(6009001)(376002)(346002)(39860400002)(199003)(189002)(86362001)(53936002)(316002)(36756003)(105586002)(68736007)(47776003)(189998001)(66066001)(16586007)(8676002)(50226002)(106356001)(6496005)(2906002)(5660300001)(6636002)(107886003)(6486002)(50986999)(25786009)(101416001)(97736004)(72206003)(4326008)(575784001)(305945005)(478600001)(76506005)(7736002)(48376002)(50466002)(81156014)(81166006)(5003940100001)(33646002)(6116002)(16526018)(8936002)(3846002); DIR:OUT; SFP:1102; SCL:1; SRVR:DM5PR0601MB3590; H:localhost; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: cypress.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; DM5PR0601MB3590; 23:N9sTWam+/1nBprogkuAqKiBvmNjqhSKceUkObhO?= =?us-ascii?Q?9F44e63UfW5VdhzNRLhN5+Yum6jlP2y5BhZAtoBAhWa+i8b2sR5Mv7WJarVQ?= =?us-ascii?Q?/u/XqRoQ4pPUWfsODQFOhWY5zC+Sq+E+r4x60k65yr9zVf68aCD06KEP3gcj?= =?us-ascii?Q?qtVdqRT7jf34kaFopnQ9DT2uMArwbp1qi3Ecz6Bfs/42ymPgZ285z3eJMnFo?= =?us-ascii?Q?QHgV9XY+JNqSvGa6VctrB/3Nio/iQ/NSKlasgCwl28D+qpYyWAixs0tVldBS?= =?us-ascii?Q?LdgUaKR6+xP+61yNsmowhPEinPLahvBzeSMVVULiGQYK8Qd09g7JVRIqBRvj?= =?us-ascii?Q?CzSwY0BpOamPxFT8NkMd5qmu2lotdCQ459+zFqEjjMMSnInz4UaFZyDR2HNU?= =?us-ascii?Q?cnVfg22CM+zQcwd0VfndtnKRr9Xg67BaEVLRSD9Y9d/gJQ7bu8MCAB2XomCk?= =?us-ascii?Q?v4sc6POfZkh63XPOuvAC5JAiGo/DfxcGylLQxQxiSZbI/9v4kU4swhVlXZCz?= =?us-ascii?Q?MbZ9SMrl7eskQs6XnLOz/Oy68Qp0RayeKJ94ay8tUVZ0wPjrxJkeMwZorniv?= =?us-ascii?Q?y53obWS9IQkHyfmtp43YOmud/3WWwy0zwPK5dw0amu90kOBgpum+jjTVkHLY?= =?us-ascii?Q?x5/Gb3QpZ+xL8kHh0YogyD2j62ynQKPTEsb+zYrDg7yA4yCbDH7ZFo1DBJMf?= =?us-ascii?Q?Y5Y07fTDnTB2mSBthggpPs6Fo16iNyBfkcXIj1InQe2F2d5uU+Gv+kSnwOjK?= =?us-ascii?Q?Sq6BJ3uicru0NJC5gHbIEKJOwajBpFF/q3p7c4JXM/7+IOiqUFXnB4CQ9VXo?= =?us-ascii?Q?+KJ/BzktbNTAdKPLSKYfH14D5MilFgljd9mJzY+q9tYrBnSa828FuCdXyXeH?= =?us-ascii?Q?/usQQRnIjWaDm0xbBFXUVu5sBNKo0UdHr3MvjHVx1p+HhNERqHFYKz87dYyy?= =?us-ascii?Q?Qq+fIV0NvZM9o56jBB2bddYs/aNsgCrtwLycYzk0hC8GyhsNvIssGBv1JoCl?= =?us-ascii?Q?FidRyl00VD0q2ssYks1fDZrhh1dtdu7vc7vXc97D2YEnX0zLCeikJAe5+HKO?= =?us-ascii?Q?dUWAOWD4V1a8+bLIlUS37tSdOJ1l3Ky+2ibvuULWBnOoCdH+4Ndeh6yJQCxD?= =?us-ascii?Q?oAQOVJ3FEfbI=3D?= X-Microsoft-Exchange-Diagnostics: 1; DM5PR0601MB3590; 6:cvFClpF5oGOwO6ty7MCKCW40JEnW+QUBF7GsyLbKX4AsCg1YnK4AX/MDNOgi9dPeeJyQY+ID1iHQVUvc5TbLZ0h+N1OQbHeBJiJwS+6Ii8iaeCP6eJqIwxxDI+FHqi5tpPjTiRkwdGBPT/uDjtFg6jT4CPrzghRarmcOv9JViJCYhACC7PKKgutcVZ5I2yTnk1rF7SfpTpK7K5Z6cEfqx7F/DROVqzwUbmST2nWZNb/XtW7Y5FR1fnzS/e8dahp7G+xm2AEKyWA33KccjpAHMkH5aYVMgfj45F1XDqnwArTur/U1jFg07jdOWOplTA0EngWYC50H3WZlBoHgAGyEA8ntHCjESdmXWdUp9EGH43s=; 5:fQrPBRHONHN+ve+NpK+eMOvx5nSrOBLRfcAoT00ICn7cT/05U8RF5DMCPegNZyGZC3pVSR/QflSICfL+Ly9Gf/StjLoHUqWNODtdEF46FMBRdBMHTPZcpIAGDKtOyrJyUaOBuaZkTKIuhBlRtGpG5IB0RvNc2Tp539qLbfv2E7Q=; 24:rpdy2f7UOUBNJWJxj4pZ2EuA8Hr5PVyOIzHVxm0rVPSHrzpuzuRDeBAJs1lV8Kvu6epA/OZI9xiWvEIBxbnV0Fpl9nGUHPGXD+6VPWZ5CVk=; 7:tHpnMhFFEoRxoH/pwfjSbo5YgWd9dTVkjd4XNSBXcHBDXHNqPUNhsRGvRuiK3agDwDoezJLUnr/zbFggAv6fmGBhg7W0VVGHAA5Tjy5STG+3FNQheZE9Iln2RIjyU2gtD+cxu3lgAp3gVPltpGJjv/SsYTuGey+AGL2FRhil9ZJ5Y+RxITb6G6AOsT3wAMDwezcpr465TFwWaD3BXUJLVLjNt+H52UWQW8CZS6/ryGmrwgnlXpMMTdk+PonSakt9 SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: cypress.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Nov 2017 09:21:13.8284 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: b0c6f1a3-2573-40dd-16b4-08d5281c6402 X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 011addfc-2c09-450d-8938-e0bbc2dd2376 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR0601MB3590 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Chung-Hsien Hsu The firmware for brcmfmac devices includes information regarding regulatory constraints. For certain devices this information is kept separately in a binary form that needs to be downloaded to the device. This patch adds support to download this so-called CLM blob file. It uses the same naming scheme as the other firmware files with extension of .clm_blob. The CLM blob file is optional. If the file does not exist, the download process will be bypassed. It will not affect the driver loading. Reviewed-by: Arend van Spriel Signed-off-by: Chung-Hsien Hsu --- v2: Revise commit message to describe in more detail v3: Add error handling in brcmf_c_get_clm_name function v4: Correct the length of dload_buf in brcmf_c_download function v5: Remove unnecessary cast and alignment v6: Add debug log for the case of no CLM file present v7: Rebase and remove unnecessary magic number --- .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 10 ++ .../wireless/broadcom/brcm80211/brcmfmac/common.c | 157 +++++++++++++++++++++ .../wireless/broadcom/brcm80211/brcmfmac/core.c | 2 + .../wireless/broadcom/brcm80211/brcmfmac/core.h | 2 + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 31 ++++ .../wireless/broadcom/brcm80211/brcmfmac/pcie.c | 19 +++ .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 19 +++ .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 18 +++ 8 files changed, 258 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index 163ddc4..0b76a61 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -71,6 +71,7 @@ struct brcmf_bus_dcmd { * @wowl_config: specify if dongle is configured for wowl when going to suspend * @get_ramsize: obtain size of device memory. * @get_memdump: obtain device memory dump in provided buffer. + * @get_fwname: obtain firmware name. * * This structure provides an abstract interface towards the * bus specific driver. For control messages to common driver @@ -87,6 +88,8 @@ struct brcmf_bus_ops { void (*wowl_config)(struct device *dev, bool enabled); size_t (*get_ramsize)(struct device *dev); int (*get_memdump)(struct device *dev, void *data, size_t len); + int (*get_fwname)(struct device *dev, uint chip, uint chiprev, + unsigned char *fw_name); }; @@ -224,6 +227,13 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len) return bus->ops->get_memdump(bus->dev, data, len); } +static inline +int brcmf_bus_get_fwname(struct brcmf_bus *bus, uint chip, uint chiprev, + unsigned char *fw_name) +{ + return bus->ops->get_fwname(bus->dev, chip, chiprev, fw_name); +} + /* * interface functions from common layer */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 7a2b495..6a59d06 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include "core.h" @@ -28,6 +29,7 @@ #include "tracepoint.h" #include "common.h" #include "of.h" +#include "firmware.h" MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); @@ -104,12 +106,140 @@ void brcmf_c_set_joinpref_default(struct brcmf_if *ifp) brcmf_err("Set join_pref error (%d)\n", err); } +static int brcmf_c_download(struct brcmf_if *ifp, u16 flag, + struct brcmf_dload_data_le *dload_buf, + u32 len) +{ + s32 err; + + flag |= (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT); + dload_buf->flag = cpu_to_le16(flag); + dload_buf->dload_type = cpu_to_le16(DL_TYPE_CLM); + dload_buf->len = cpu_to_le32(len); + dload_buf->crc = cpu_to_le32(0); + len = sizeof(*dload_buf) + len - 1; + + err = brcmf_fil_iovar_data_set(ifp, "clmload", dload_buf, len); + + return err; +} + +static int brcmf_c_get_clm_name(struct brcmf_if *ifp, u8 *clm_name) +{ + struct brcmf_bus *bus = ifp->drvr->bus_if; + struct brcmf_rev_info *ri = &ifp->drvr->revinfo; + u8 fw_name[BRCMF_FW_NAME_LEN]; + u8 *ptr; + size_t len; + s32 err; + + memset(fw_name, 0, BRCMF_FW_NAME_LEN); + err = brcmf_bus_get_fwname(bus, ri->chipnum, ri->chiprev, fw_name); + if (err) { + brcmf_err("get firmware name failed (%d)\n", err); + goto done; + } + + /* generate CLM blob file name */ + ptr = strrchr(fw_name, '.'); + if (!ptr) { + err = -ENOENT; + goto done; + } + + len = ptr - fw_name + 1; + if (len + strlen(".clm_blob") > BRCMF_FW_NAME_LEN) { + err = -E2BIG; + } else { + strlcpy(clm_name, fw_name, len); + strlcat(clm_name, ".clm_blob", BRCMF_FW_NAME_LEN); + } +done: + return err; +} + +static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) +{ + struct device *dev = ifp->drvr->bus_if->dev; + struct brcmf_dload_data_le *chunk_buf; + const struct firmware *clm = NULL; + u8 clm_name[BRCMF_FW_NAME_LEN]; + u32 chunk_len; + u32 datalen; + u32 cumulative_len; + u16 dl_flag = DL_BEGIN; + u32 status; + s32 err; + + brcmf_dbg(TRACE, "Enter\n"); + + memset(clm_name, 0, BRCMF_FW_NAME_LEN); + err = brcmf_c_get_clm_name(ifp, clm_name); + if (err) { + brcmf_err("get CLM blob file name failed (%d)\n", err); + return err; + } + + err = request_firmware(&clm, clm_name, dev); + if (err) { + if (err == -ENOENT) { + brcmf_dbg(INFO, "continue with CLM data currently present in firmware\n"); + return 0; + } + brcmf_err("request CLM blob file failed (%d)\n", err); + return err; + } + + chunk_buf = kzalloc(sizeof(*chunk_buf) + MAX_CHUNK_LEN - 1, GFP_KERNEL); + if (!chunk_buf) { + err = -ENOMEM; + goto done; + } + + datalen = clm->size; + cumulative_len = 0; + do { + if (datalen > MAX_CHUNK_LEN) { + chunk_len = MAX_CHUNK_LEN; + } else { + chunk_len = datalen; + dl_flag |= DL_END; + } + memcpy(chunk_buf->data, clm->data + cumulative_len, chunk_len); + + err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len); + + dl_flag &= ~DL_BEGIN; + + cumulative_len += chunk_len; + datalen -= chunk_len; + } while ((datalen > 0) && (err == 0)); + + if (err) { + brcmf_err("clmload (%zu byte file) failed (%d); ", + clm->size, err); + /* Retrieve clmload_status and print */ + err = brcmf_fil_iovar_int_get(ifp, "clmload_status", &status); + if (err) + brcmf_err("get clmload_status failed (%d)\n", err); + else + brcmf_dbg(INFO, "clmload_status=%d\n", status); + err = -EIO; + } + + kfree(chunk_buf); +done: + release_firmware(clm); + return err; +} + int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) { s8 eventmask[BRCMF_EVENTING_MASK_LEN]; u8 buf[BRCMF_DCMD_SMLEN]; struct brcmf_rev_info_le revinfo; struct brcmf_rev_info *ri; + char *clmver; char *ptr; s32 err; @@ -148,6 +278,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) } ri->result = err; + /* Do any CLM downloading */ + err = brcmf_c_process_clm_blob(ifp); + if (err < 0) { + brcmf_err("download CLM blob file failed, %d\n", err); + goto done; + } + /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); strcpy(buf, "ver"); @@ -167,6 +304,26 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) ptr = strrchr(buf, ' ') + 1; strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver)); + /* Query for 'clmver' to get CLM version info from firmware */ + memset(buf, 0, sizeof(buf)); + err = brcmf_fil_iovar_data_get(ifp, "clmver", buf, sizeof(buf)); + if (err) { + brcmf_dbg(TRACE, "retrieving clmver failed, %d\n", err); + } else { + clmver = (char *)buf; + /* store CLM version for adding it to revinfo debugfs file */ + memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver)); + + /* Replace all newline/linefeed characters with space + * character + */ + ptr = clmver; + while ((ptr = strnchr(ptr, '\n', sizeof(buf))) != NULL) + *ptr = ' '; + + brcmf_dbg(INFO, "CLM version = %s\n", clmver); + } + /* set mpc */ err = brcmf_fil_iovar_int_set(ifp, "mpc", 1); if (err) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 5cc3a07..e6b87a7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -950,6 +950,8 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data) seq_printf(s, "anarev: %u\n", ri->anarev); seq_printf(s, "nvramrev: %08x\n", ri->nvramrev); + seq_printf(s, "clmver: %s\n", bus_if->drvr->clmver); + return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index a4dd313..ae39128 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -141,6 +141,8 @@ struct brcmf_pub { struct notifier_block inetaddr_notifier; struct notifier_block inet6addr_notifier; struct brcmf_mp_device *settings; + + u8 clmver[BRCMF_DCMD_SMLEN]; }; /* forward declarations */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index e0d22fe..4b29070 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -155,6 +155,21 @@ #define BRCMF_MFP_CAPABLE 1 #define BRCMF_MFP_REQUIRED 2 +/* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each + * ioctl. It is relatively small because firmware has small maximum size input + * playload restriction for ioctls. + */ +#define MAX_CHUNK_LEN 1400 + +#define DLOAD_HANDLER_VER 1 /* Downloader version */ +#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ +#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ + +#define DL_BEGIN 0x0002 +#define DL_END 0x0004 + +#define DL_TYPE_CLM 2 + /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { BRCMF_JOIN_PREF_RSSI = 1, @@ -827,6 +842,22 @@ struct brcmf_pno_macaddr_le { }; /** + * struct brcmf_dload_data_le - data passing to firmware for downloading + * @flag: flags related to download data. + * @dload_type: type of download data. + * @len: length in bytes of download data. + * @crc: crc of download data. + * @data: download data. + */ +struct brcmf_dload_data_le { + __le16 flag; + __le16 dload_type; + __le32 len; + __le32 crc; + u8 data[1]; +}; + +/** * struct brcmf_pno_bssid_le - bssid configuration for PNO scan. * * @bssid: BSS network identifier. diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index e6e9b00..3c87157 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1350,6 +1350,24 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len) return 0; } +static int brcmf_pcie_get_fwname(struct device *dev, u32 chip, u32 chiprev, + u8 *fw_name) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie; + struct brcmf_pciedev_info *devinfo = buspub->devinfo; + int ret = 0; + + if (devinfo->fw_name[0] != '\0') + strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN); + else + ret = brcmf_fw_map_chip_to_name(chip, chiprev, + brcmf_pcie_fwnames, + ARRAY_SIZE(brcmf_pcie_fwnames), + fw_name, NULL); + + return ret; +} static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { .txdata = brcmf_pcie_tx, @@ -1359,6 +1377,7 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len) .wowl_config = brcmf_pcie_wowl_config, .get_ramsize = brcmf_pcie_get_ramsize, .get_memdump = brcmf_pcie_get_memdump, + .get_fwname = brcmf_pcie_get_fwname, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 613caca..83bed54 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -3979,6 +3979,24 @@ static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val) } } +static int brcmf_sdio_get_fwname(struct device *dev, u32 chip, u32 chiprev, + u8 *fw_name) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + int ret = 0; + + if (sdiodev->fw_name[0] != '\0') + strlcpy(fw_name, sdiodev->fw_name, BRCMF_FW_NAME_LEN); + else + ret = brcmf_fw_map_chip_to_name(chip, chiprev, + brcmf_sdio_fwnames, + ARRAY_SIZE(brcmf_sdio_fwnames), + fw_name, NULL); + + return ret; +} + static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { .stop = brcmf_sdio_bus_stop, .preinit = brcmf_sdio_bus_preinit, @@ -3989,6 +4007,7 @@ static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val) .wowl_config = brcmf_sdio_wowl_config, .get_ramsize = brcmf_sdio_bus_get_ramsize, .get_memdump = brcmf_sdio_bus_get_memdump, + .get_fwname = brcmf_sdio_get_fwname, }; static void brcmf_sdio_firmware_callback(struct device *dev, int err, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 11ffaa0..b27170c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1128,12 +1128,30 @@ static void brcmf_usb_wowl_config(struct device *dev, bool enabled) device_set_wakeup_enable(devinfo->dev, false); } +static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev, + u8 *fw_name) +{ + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); + int ret = 0; + + if (devinfo->fw_name[0] != '\0') + strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN); + else + ret = brcmf_fw_map_chip_to_name(chip, chiprev, + brcmf_usb_fwnames, + ARRAY_SIZE(brcmf_usb_fwnames), + fw_name, NULL); + + return ret; +} + static const struct brcmf_bus_ops brcmf_usb_bus_ops = { .txdata = brcmf_usb_tx, .stop = brcmf_usb_down, .txctl = brcmf_usb_tx_ctlpkt, .rxctl = brcmf_usb_rx_ctlpkt, .wowl_config = brcmf_usb_wowl_config, + .get_fwname = brcmf_usb_get_fwname, }; static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)