From patchwork Tue Jan 11 17:14:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?SsOpcsO0bWUgUG91aWxsZXI=?= X-Patchwork-Id: 12710132 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5CD38C433F5 for ; Tue, 11 Jan 2022 17:16:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343948AbiAKRQ2 (ORCPT ); Tue, 11 Jan 2022 12:16:28 -0500 Received: from mail-bn7nam10on2045.outbound.protection.outlook.com ([40.107.92.45]:52705 "EHLO NAM10-BN7-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1343989AbiAKRPq (ORCPT ); Tue, 11 Jan 2022 12:15:46 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Jq9reMzrJrPJWi0NLvn8lPJqxzt7xr9jDkXsXnBK/Uq2VL8KHIYDIZgTSDVnWGKj1njy6i/d+QGVr2PfUZ+1U689c1XzFXcJqPKRp1x1/655cdTQORepq3WgTL+qtICQDzBMzt4Z2FuCx3ezR3D8aQfq2dlsO1U8Qg2kzqM4q1X1mVqlxNzZJgAxmdMgDKbChNPkVug1m5OJEky97Ii8kVzSpW9MWKk+tYC8cbvOxzvAM2wZuzz+lGvAJvJwX+I5FTdoT1stb69Za4hehZdNA4mlr5zyKpnY+FvP4Ab1KVTQ1dVmsOCGZH4S64zIv7jSkyVtxwwpYE9bZA9ZBDmLzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=X1cR2BtYV8qIgaXe/OsSh91spBngEHgNdC/46S3ZZms=; b=OOSwhb3yOqclMSI4cY5S61nMhxCG9OhQqK9FdUPNJmz3RjsVTkBT99vwSXKg2wnx3K+ks2n6d6I0SQzIOr0fkRT1rluVLkmd9/Ogu+IWCVVzv2z2x+H+XCXpcU4jefLF2U2oSPirPIZ5I52I2L+JRmaZwrWXgnsngDLevzLdAlOo16rAV/twjtFkUtIm4UMe7Qa9IosyZlofqZ0yDwX5v8DFaO+3uJJoRsBfHoFzsisiFtcrNRqHt7ezWSmzae2bbTeactKWTZmp6auQ7LQ3Cf1wNjdEpcqq9gOPWcD+AshWGacz8Y55dbv7wrArLzPWg5AHF8fhGp1Nwh4nSmyMWQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=silabs.com; dmarc=pass action=none header.from=silabs.com; dkim=pass header.d=silabs.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=silabs.onmicrosoft.com; s=selector2-silabs-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=X1cR2BtYV8qIgaXe/OsSh91spBngEHgNdC/46S3ZZms=; b=qKK3Q07TeVKJsciHlLEzxFl5O1FEqSuJKMUN6l7nWyCX5/P/rDkSqT862xb0/KoNgfUkBBernuOkg+A1+O8oPk3sVQRmkeJT7nv3SmnJyxMK+TyHrj0cuWQfgLCo6SdispB+sOQHrklMkOi+S1mHS5p72nCwQvz9YkDERodS274= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=silabs.com; Received: from PH0PR11MB5657.namprd11.prod.outlook.com (2603:10b6:510:ee::19) by PH0PR11MB5609.namprd11.prod.outlook.com (2603:10b6:510:e0::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4867.9; Tue, 11 Jan 2022 17:15:20 +0000 Received: from PH0PR11MB5657.namprd11.prod.outlook.com ([fe80::d031:da9e:71a:73e4]) by PH0PR11MB5657.namprd11.prod.outlook.com ([fe80::d031:da9e:71a:73e4%6]) with mapi id 15.20.4867.012; Tue, 11 Jan 2022 17:15:20 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org, Kalle Valo Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali?= =?utf-8?q?_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUgUG91aWxsZXI=?= Subject: [PATCH v9 13/24] wfx: add hif_tx*.c/hif_tx*.h Date: Tue, 11 Jan 2022 18:14:13 +0100 Message-Id: <20220111171424.862764-14-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220111171424.862764-1-Jerome.Pouiller@silabs.com> References: <20220111171424.862764-1-Jerome.Pouiller@silabs.com> X-ClientProxiedBy: SN1PR12CA0099.namprd12.prod.outlook.com (2603:10b6:802:21::34) To PH0PR11MB5657.namprd11.prod.outlook.com (2603:10b6:510:ee::19) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: f25653c3-31b7-4b8e-c869-08d9d525f1e5 X-MS-TrafficTypeDiagnostic: PH0PR11MB5609:EE_ X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:21; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: ULfO4AdT/+UVYshoac8ySCrunRNnD+fiUuO9nWqDxNNTwW9al6+ah2yjOJVnAiDwwAZwVaLWLH9x804Ouo8M3JWD91sL0y9f5VkAQFj9R58CQVCJ5FfzReRR2kHN6YoslrQKcYyH0P21J2p3TbdEMZoriwFg/f4ydhOasTg/AgcposeO/pHuF7wFeyNxdha90d3bMewk3ogfm69jqgPPGdkxj2Tz0f36tcx9tfKvr9z3DTlpywKGQIOrNnxERPml6QocCaRFdw3oi2O44dRTYqL1rYV1WrgdmALMh2Sa2xaQmY6tAaxOsXVOVoVQi2yHMGhLpgHLvy00Fv2coqsuLfXhvckxvARYbfdtZ3D5ZRUYydcYGWlNj0+wkMdcUHl305TFs6jYB2dOvkxBmqqzAkSdaifx2E8qOh1NmX7pMIGXD09YwM5QU3zKc7lDx2+FVSEMw4KqeNfPWltUOIC5XE1W4D0W2lyUONQWfK6gU1+X4+ZJ5MkNLjnxaILdwjR5r6x0fzyY99Gc2jgMhr+In8euDcCUSynIqpFqyO98gtUhhGJmFCUbt8xonUNUazNapeR+ckuLU9vrxfUeHpCWgdxzaCTgc9PQwtkeqpTKxMPYpzV26vT/ZPLBf8S9B+DPNIetCUEg1U1GGlxjbHr/Hw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:PH0PR11MB5657.namprd11.prod.outlook.com;PTR:;CAT:NONE;SFS:(366004)(5660300002)(8676002)(36756003)(38100700002)(186003)(7416002)(66476007)(54906003)(6486002)(6916009)(6512007)(4326008)(508600001)(107886003)(66946007)(6666004)(2616005)(1076003)(8936002)(66556008)(86362001)(2906002)(6506007)(52116002)(66574015)(316002)(83380400001)(30864003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?q?4GNBMbjPsvfJP6ObAYz64W8qTtDv?= =?utf-8?q?Ka3AJarfcrMUZQ8LqSglRYFA4HcZ/djqqYQ+JVA0/W3uGCU0D+8yEmIHAJ1mFXppC?= =?utf-8?q?kflNWIai4M95YsqiZB8Tqej/Dc5xB1PZD1GMPJMGx7iHPJpiDoKFDAHn2ZSfTdT7c?= =?utf-8?q?3NV6lZHUI+JrJdfgj2z7WPgZtCuaJu4gsJq8t/gawWhafLhMN487e2Q3ST3n1Eq9A?= =?utf-8?q?J6h44a567iQ96SKDP/ENYCUYxs3eyC3dwFQhY+OMPR2AI7rfJN1/nvsa+apIq+F7Z?= =?utf-8?q?uh5Xr8N0qszub0+hsCF8NGr+pl9EvhZIFX7RXTYrfHdcJHgFBbnFoy0ZvocxDYOhK?= =?utf-8?q?xcEnVyHxVmLXhbhtypS2+h5Pvhxveb87Orc7+X8kB9gZaV3SPDhY4PQCBAVNxzX34?= =?utf-8?q?/ipFvWLdWYx0fG3lKguRgLqAGpWTDvT3yEdl99u0PELmJzD3O9X+RKjcJw1SXqOKT?= =?utf-8?q?/TKyLaNWCQBrFmiWwymVR47cGzKwq3jzSE9VOplyqutZp2MI5faRUcuJ+Tkl4MEmG?= =?utf-8?q?FI57yOGljDU0WE4WHuMwhZxdJfd3x7fzeLNbEVhAzoYDzzgKIU5YLMDgHjNQsW/jz?= =?utf-8?q?aRp8c+rcXn705vw76gBHXoqKqnLDtuj0V3ZTN0e5sEXUqIpZrsxfuoOdKUhmk4wSx?= =?utf-8?q?EydxxNFFt5V+6JfXD8uWtCnB4wo4lxCVjS9vw/qH5u/7c0NQkmtrNKj0Uhd7ta39y?= =?utf-8?q?ifJ/LUlwEGQ1y3oRbz6Qv/Fm3xCTX74jMjmdqApUe8q0rcT98vM156riRhiwL3Zmw?= =?utf-8?q?fpr8YNs2+4Xarb8vLLY57oqwYW/8DfQbIP+sRwnZPA22GVBhchKnuP4a+yGmG10LH?= =?utf-8?q?X/WXEeG0qb9rJjvrGl+QH/mdRcZcFHTzudizxhcnF9Hu4ttidPnqBsLwA9l6hvhdC?= =?utf-8?q?wEJnqHjmyyROJS0zHOZ0t4uXajMabtBy09HhcfsaQLrx6sa3n08nJ8LV31tj04eaA?= =?utf-8?q?0Q1z4S+KTrmymUXFym4GuP09YZ2UGjMbFCnIsUbkGp96mDQv4LTVZczWhzIUkVlwN?= =?utf-8?q?BJjtVJV9iQ1SaDP1pARYvYlqIHCVlIlvpAUZuHYyFmyYh4ywV0V/X1aPxBQq2V9ed?= =?utf-8?q?piAVO23/hLK84dbYwTQ23reUVSqlrmQVaWSP906S8M9iwfLyGZRxa8pdzYl0Zqh+W?= =?utf-8?q?KzF8m0tZ2NlfW6epsvFaHj0zpEzC9VjvfJgJU0JOTx6vx363Bl3uqkyWY8EClY+N1?= =?utf-8?q?S4oGqrT0BOCg03LfzXHiVeWdYSjef9iiM8QWrhS0GSyNT2OxMHe4j9cgdzHSan6cV?= =?utf-8?q?JBUEE+44MPLt04sD81/RnUivl+5/EvRAxM0B63ynA9l+Yzp7KLxzytT1VF7i5fz/k?= =?utf-8?q?Z9XjDzfN8ahOKIL244GgQcSzbZFL7Xq6cO8Ra6B62HOa3NADpJDlhjljcavr9P/X2?= =?utf-8?q?lAKlJ1iawhj+Qtmy91FyH31xr3AwLkeXYUSCQIbZHN1m3X6U5/ds8zkOAaNOGFfZv?= =?utf-8?q?jDrgG3mUl36zAnr6OClnVKNLJO0nbQ1ogcrpT285XGrj8nu4Zqu1mGVizayVnb2kp?= =?utf-8?q?wGJUho56dVTk5KokRzvd9WMQWoQhTMh/ZKyI+LQ+sank2Uee724yxaHsZdo9Z1onf?= =?utf-8?q?+9W4DsKyR68495EIDQoLIIa8gE7yfNiRLzooSgHJX0UDEWhRyxUNvM=3D?= X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: f25653c3-31b7-4b8e-c869-08d9d525f1e5 X-MS-Exchange-CrossTenant-AuthSource: PH0PR11MB5657.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 Jan 2022 17:15:20.1947 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 54dbd822-5231-4b20-944d-6f4abcd541fb X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Sg47NqexAA6kHHsn5vJz1ZZ1CYqea7Bku9H0tT0iX3M1l1ZVFfmlVapeHvFgKcRbyk3UmxrBlj7acQ3YpF4WzQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR11MB5609 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Jérôme Pouiller Signed-off-by: Jérôme Pouiller --- drivers/net/wireless/silabs/wfx/hif_tx.c | 492 +++++++++++++++++++ drivers/net/wireless/silabs/wfx/hif_tx.h | 61 +++ drivers/net/wireless/silabs/wfx/hif_tx_mib.c | 308 ++++++++++++ drivers/net/wireless/silabs/wfx/hif_tx_mib.h | 48 ++ 4 files changed, 909 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx.c create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx.h create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx_mib.c create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx_mib.h diff --git a/drivers/net/wireless/silabs/wfx/hif_tx.c b/drivers/net/wireless/silabs/wfx/hif_tx.c new file mode 100644 index 000000000000..40b9808eb511 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx.c @@ -0,0 +1,492 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of the host-to-chip commands (aka request/confirmation) of the + * hardware API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include + +#include "hif_tx.h" +#include "wfx.h" +#include "bh.h" +#include "hwio.h" +#include "debug.h" +#include "sta.h" + +void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd) +{ + init_completion(&hif_cmd->ready); + init_completion(&hif_cmd->done); + mutex_init(&hif_cmd->lock); +} + +static void wfx_fill_header(struct wfx_hif_msg *hif, int if_id, unsigned int cmd, size_t size) +{ + if (if_id == -1) + if_id = 2; + + WARN(cmd > 0x3f, "invalid hardware command %#.2x", cmd); + WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size); + WARN(if_id > 0x3, "invalid interface ID %d", if_id); + + hif->len = cpu_to_le16(size + 4); + hif->id = cmd; + hif->interface = if_id; +} + +static void *wfx_alloc_hif(size_t body_len, struct wfx_hif_msg **hif) +{ + *hif = kzalloc(sizeof(*hif) + body_len, GFP_KERNEL); + if (*hif) + return (*hif)->body; + else + return NULL; +} + +int wfx_cmd_send(struct wfx_dev *wdev, struct wfx_hif_msg *request, + void *reply, size_t reply_len, bool no_reply) +{ + const char *mib_name = ""; + const char *mib_sep = ""; + int cmd = request->id; + int vif = request->interface; + int ret; + + /* Do not wait for any reply if chip is frozen */ + if (wdev->chip_frozen) + return -ETIMEDOUT; + + mutex_lock(&wdev->hif_cmd.lock); + WARN(wdev->hif_cmd.buf_send, "data locking error"); + + /* Note: call to complete() below has an implicit memory barrier that hopefully protect + * buf_send + */ + wdev->hif_cmd.buf_send = request; + wdev->hif_cmd.buf_recv = reply; + wdev->hif_cmd.len_recv = reply_len; + complete(&wdev->hif_cmd.ready); + + wfx_bh_request_tx(wdev); + + if (no_reply) { + /* Chip won't reply. Give enough time to the wq to send the buffer. */ + msleep(100); + wdev->hif_cmd.buf_send = NULL; + mutex_unlock(&wdev->hif_cmd.lock); + return 0; + } + + if (wdev->poll_irq) + wfx_bh_poll_irq(wdev); + + ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ); + if (!ret) { + dev_err(wdev->dev, "chip is abnormally long to answer\n"); + reinit_completion(&wdev->hif_cmd.ready); + ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ); + } + if (!ret) { + dev_err(wdev->dev, "chip did not answer\n"); + wfx_pending_dump_old_frames(wdev, 3000); + wdev->chip_frozen = true; + reinit_completion(&wdev->hif_cmd.done); + ret = -ETIMEDOUT; + } else { + ret = wdev->hif_cmd.ret; + } + + wdev->hif_cmd.buf_send = NULL; + mutex_unlock(&wdev->hif_cmd.lock); + + if (ret && + (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) { + mib_name = wfx_get_mib_name(((u16 *)request)[2]); + mib_sep = "/"; + } + if (ret < 0) + dev_err(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned error %d\n", + wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret); + if (ret > 0) + dev_warn(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned status %d\n", + wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret); + + return ret; +} + +/* This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any request anymore. + * Obviously, only call this function during device unregister. + */ +int wfx_hif_shutdown(struct wfx_dev *wdev) +{ + int ret; + struct wfx_hif_msg *hif; + + wfx_alloc_hif(0, &hif); + if (!hif) + return -ENOMEM; + wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0); + ret = wfx_cmd_send(wdev, hif, NULL, 0, true); + if (wdev->pdata.gpio_wakeup) + gpiod_set_value(wdev->pdata.gpio_wakeup, 0); + else + wfx_control_reg_write(wdev, 0); + kfree(hif); + return ret; +} + +int wfx_hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len) +{ + int ret; + size_t buf_len = sizeof(struct wfx_hif_req_configuration) + len; + struct wfx_hif_msg *hif; + struct wfx_hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif); + + if (!hif) + return -ENOMEM; + body->length = cpu_to_le16(len); + memcpy(body->pds_data, conf, len); + wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_reset(struct wfx_vif *wvif, bool reset_stat) +{ + int ret; + struct wfx_hif_msg *hif; + struct wfx_hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + body->reset_stat = reset_stat; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *val, size_t val_len) +{ + int ret; + struct wfx_hif_msg *hif; + int buf_len = sizeof(struct wfx_hif_cnf_read_mib) + val_len; + struct wfx_hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif); + struct wfx_hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL); + + if (!body || !reply) { + ret = -ENOMEM; + goto out; + } + body->mib_id = cpu_to_le16(mib_id); + wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, reply, buf_len, false); + + if (!ret && mib_id != le16_to_cpu(reply->mib_id)) { + dev_warn(wdev->dev, "%s: confirmation mismatch request\n", __func__); + ret = -EIO; + } + if (ret == -ENOMEM) + dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n", + wfx_get_mib_name(mib_id), val_len, le16_to_cpu(reply->length)); + if (!ret) + memcpy(val, &reply->mib_data, le16_to_cpu(reply->length)); + else + memset(val, 0xFF, val_len); +out: + kfree(hif); + kfree(reply); + return ret; +} + +int wfx_hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len) +{ + int ret; + struct wfx_hif_msg *hif; + int buf_len = sizeof(struct wfx_hif_req_write_mib) + val_len; + struct wfx_hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif); + + if (!hif) + return -ENOMEM; + body->mib_id = cpu_to_le16(mib_id); + body->length = cpu_to_le16(val_len); + memcpy(&body->mib_data, val, val_len); + wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req, + int chan_start_idx, int chan_num) +{ + int ret, i; + struct wfx_hif_msg *hif; + size_t buf_len = sizeof(struct wfx_hif_req_start_scan_alt) + chan_num * sizeof(u8); + struct wfx_hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif); + + WARN(chan_num > HIF_API_MAX_NB_CHANNELS, "invalid params"); + WARN(req->n_ssids > HIF_API_MAX_NB_SSIDS, "invalid params"); + + if (!hif) + return -ENOMEM; + for (i = 0; i < req->n_ssids; i++) { + memcpy(body->ssid_def[i].ssid, req->ssids[i].ssid, IEEE80211_MAX_SSID_LEN); + body->ssid_def[i].ssid_length = cpu_to_le32(req->ssids[i].ssid_len); + } + body->num_of_ssids = HIF_API_MAX_NB_SSIDS; + body->maintain_current_bss = 1; + body->disallow_ps = 1; + body->tx_power_level = cpu_to_le32(req->channels[chan_start_idx]->max_power); + body->num_of_channels = chan_num; + for (i = 0; i < chan_num; i++) + body->channel_list[i] = req->channels[i + chan_start_idx]->hw_value; + if (req->no_cck) + body->max_transmit_rate = API_RATE_INDEX_G_6MBPS; + else + body->max_transmit_rate = API_RATE_INDEX_B_1MBPS; + if (req->channels[chan_start_idx]->flags & IEEE80211_CHAN_NO_IR) { + body->min_channel_time = cpu_to_le32(50); + body->max_channel_time = cpu_to_le32(150); + } else { + body->min_channel_time = cpu_to_le32(10); + body->max_channel_time = cpu_to_le32(50); + body->num_of_probe_requests = 2; + body->probe_delay = 100; + } + + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_stop_scan(struct wfx_vif *wvif) +{ + int ret; + struct wfx_hif_msg *hif; + /* body associated to HIF_REQ_ID_STOP_SCAN is empty */ + wfx_alloc_hif(0, &hif); + + if (!hif) + return -ENOMEM; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + struct ieee80211_channel *channel, const u8 *ssid, int ssidlen) +{ + int ret; + struct wfx_hif_msg *hif; + struct wfx_hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif); + + WARN_ON(!conf->beacon_int); + WARN_ON(!conf->basic_rates); + WARN_ON(!channel); + WARN_ON(sizeof(body->ssid) < ssidlen); + WARN(!conf->ibss_joined && !ssidlen, "joining an unknown BSS"); + if (!hif) + return -ENOMEM; + body->infrastructure_bss_mode = !conf->ibss_joined; + body->short_preamble = conf->use_short_preamble; + body->probe_for_join = !(channel->flags & IEEE80211_CHAN_NO_IR); + body->channel_number = channel->hw_value; + body->beacon_interval = cpu_to_le32(conf->beacon_int); + body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); + memcpy(body->bssid, conf->bssid, sizeof(body->bssid)); + if (ssid) { + body->ssid_length = cpu_to_le32(ssidlen); + memcpy(body->ssid, ssid, ssidlen); + } + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count) +{ + int ret; + struct wfx_hif_msg *hif; + struct wfx_hif_req_set_bss_params *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + body->aid = cpu_to_le16(aid); + body->beacon_lost_count = beacon_lost_count; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_add_key(struct wfx_dev *wdev, const struct wfx_hif_req_add_key *arg) +{ + int ret; + struct wfx_hif_msg *hif; + /* FIXME: only send necessary bits */ + struct wfx_hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + /* FIXME: swap bytes as necessary in body */ + memcpy(body, arg, sizeof(*body)); + if (wfx_api_older_than(wdev, 1, 5)) + /* Legacy firmwares expect that add_key to be sent on right interface. */ + wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY, sizeof(*body)); + else + wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_remove_key(struct wfx_dev *wdev, int idx) +{ + int ret; + struct wfx_hif_msg *hif; + struct wfx_hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + body->entry_index = idx; + wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, + const struct ieee80211_tx_queue_params *arg) +{ + int ret; + struct wfx_hif_msg *hif; + struct wfx_hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!body) + return -ENOMEM; + + WARN_ON(arg->aifs > 255); + if (!hif) + return -ENOMEM; + body->aifsn = arg->aifs; + body->cw_min = cpu_to_le16(arg->cw_min); + body->cw_max = cpu_to_le16(arg->cw_max); + body->tx_op_limit = cpu_to_le16(arg->txop * USEC_PER_TXOP); + body->queue_id = 3 - queue; + /* API 2.0 has changed queue IDs values */ + if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BE) + body->queue_id = HIF_QUEUE_ID_BACKGROUND; + if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BK) + body->queue_id = HIF_QUEUE_ID_BESTEFFORT; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout) +{ + int ret; + struct wfx_hif_msg *hif; + struct wfx_hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!body) + return -ENOMEM; + + if (!hif) + return -ENOMEM; + if (ps) { + body->enter_psm = 1; + /* Firmware does not support more than 128ms */ + body->fast_psm_idle_period = min(dynamic_ps_timeout * 2, 255); + if (body->fast_psm_idle_period) + body->fast_psm = 1; + } + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + const struct ieee80211_channel *channel) +{ + int ret; + struct wfx_hif_msg *hif; + struct wfx_hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif); + + WARN_ON(!conf->beacon_int); + if (!hif) + return -ENOMEM; + body->dtim_period = conf->dtim_period; + body->short_preamble = conf->use_short_preamble; + body->channel_number = channel->hw_value; + body->beacon_interval = cpu_to_le32(conf->beacon_int); + body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); + body->ssid_length = conf->ssid_len; + memcpy(body->ssid, conf->ssid, conf->ssid_len); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_beacon_transmit(struct wfx_vif *wvif, bool enable) +{ + int ret; + struct wfx_hif_msg *hif; + struct wfx_hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + body->enable_beaconing = enable ? 1 : 0; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp) +{ + int ret; + struct wfx_hif_msg *hif; + struct wfx_hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + if (mac_addr) + ether_addr_copy(body->mac_addr, mac_addr); + body->mfpc = mfp ? 1 : 0; + body->unmap = unmap ? 1 : 0; + body->peer_sta_id = sta_id; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int wfx_hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len) +{ + int ret; + struct wfx_hif_msg *hif; + int buf_len = sizeof(struct wfx_hif_req_update_ie) + ies_len; + struct wfx_hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif); + + if (!hif) + return -ENOMEM; + body->beacon = 1; + body->num_ies = cpu_to_le16(1); + memcpy(body->ie, ies, ies_len); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} diff --git a/drivers/net/wireless/silabs/wfx/hif_tx.h b/drivers/net/wireless/silabs/wfx/hif_tx.h new file mode 100644 index 000000000000..71817a6571f0 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of the host-to-chip commands (aka request/confirmation) of the + * hardware API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ +#ifndef WFX_HIF_TX_H +#define WFX_HIF_TX_H + +#include +#include +#include + +struct ieee80211_channel; +struct ieee80211_bss_conf; +struct ieee80211_tx_queue_params; +struct cfg80211_scan_request; +struct wfx_hif_req_add_key; +struct wfx_dev; +struct wfx_vif; + +struct wfx_hif_cmd { + struct mutex lock; + struct completion ready; + struct completion done; + struct wfx_hif_msg *buf_send; + void *buf_recv; + size_t len_recv; + int ret; +}; + +void wfx_init_hif_cmd(struct wfx_hif_cmd *wfx_hif_cmd); +int wfx_cmd_send(struct wfx_dev *wdev, struct wfx_hif_msg *request, + void *reply, size_t reply_len, bool async); + +int wfx_hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *buf, size_t buf_size); +int wfx_hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *buf, size_t buf_size); +int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + const struct ieee80211_channel *channel); +int wfx_hif_reset(struct wfx_vif *wvif, bool reset_stat); +int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + struct ieee80211_channel *channel, const u8 *ssid, int ssidlen); +int wfx_hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp); +int wfx_hif_add_key(struct wfx_dev *wdev, const struct wfx_hif_req_add_key *arg); +int wfx_hif_remove_key(struct wfx_dev *wdev, int idx); +int wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout); +int wfx_hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count); +int wfx_hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, + const struct ieee80211_tx_queue_params *arg); +int wfx_hif_beacon_transmit(struct wfx_vif *wvif, bool enable); +int wfx_hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len); +int wfx_hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211, + int chan_start, int chan_num); +int wfx_hif_stop_scan(struct wfx_vif *wvif); +int wfx_hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len); +int wfx_hif_shutdown(struct wfx_dev *wdev); + +#endif diff --git a/drivers/net/wireless/silabs/wfx/hif_tx_mib.c b/drivers/net/wireless/silabs/wfx/hif_tx_mib.c new file mode 100644 index 000000000000..1c57dd2b697c --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx_mib.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of the host-to-chip MIBs of the hardware API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ + +#include + +#include "wfx.h" +#include "hif_tx.h" +#include "hif_tx_mib.h" +#include "hif_api_mib.h" + +int wfx_hif_set_output_power(struct wfx_vif *wvif, int val) +{ + struct wfx_hif_mib_current_tx_power_level arg = { + .power_level = cpu_to_le32(val * 10), + }; + + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_CURRENT_TX_POWER_LEVEL, + &arg, sizeof(arg)); +} + +int wfx_hif_set_beacon_wakeup_period(struct wfx_vif *wvif, + unsigned int dtim_interval, unsigned int listen_interval) +{ + struct wfx_hif_mib_beacon_wake_up_period arg = { + .wakeup_period_min = dtim_interval, + .receive_dtim = 0, + .wakeup_period_max = listen_interval, + }; + + if (dtim_interval > 0xFF || listen_interval > 0xFFFF) + return -EINVAL; + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_WAKEUP_PERIOD, + &arg, sizeof(arg)); +} + +int wfx_hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, int rssi_thold, int rssi_hyst) +{ + struct wfx_hif_mib_rcpi_rssi_threshold arg = { + .rolling_average_count = 8, + .detection = 1, + }; + + if (!rssi_thold && !rssi_hyst) { + arg.upperthresh = 1; + arg.lowerthresh = 1; + } else { + arg.upper_threshold = rssi_thold + rssi_hyst; + arg.upper_threshold = (arg.upper_threshold + 110) * 2; + arg.lower_threshold = rssi_thold; + arg.lower_threshold = (arg.lower_threshold + 110) * 2; + } + + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RCPI_RSSI_THRESHOLD, + &arg, sizeof(arg)); +} + +int wfx_hif_get_counters_table(struct wfx_dev *wdev, int vif_id, + struct wfx_hif_mib_extended_count_table *arg) +{ + if (wfx_api_older_than(wdev, 1, 3)) { + /* extended_count_table is wider than count_table */ + memset(arg, 0xFF, sizeof(*arg)); + return wfx_hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE, + arg, sizeof(struct wfx_hif_mib_count_table)); + } else { + return wfx_hif_read_mib(wdev, vif_id, HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, + arg, sizeof(struct wfx_hif_mib_extended_count_table)); + } +} + +int wfx_hif_set_macaddr(struct wfx_vif *wvif, u8 *mac) +{ + struct wfx_hif_mib_mac_address arg = { }; + + if (mac) + ether_addr_copy(arg.mac_addr, mac); + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS, + &arg, sizeof(arg)); +} + +int wfx_hif_set_rx_filter(struct wfx_vif *wvif, + bool filter_bssid, bool filter_prbreq) +{ + struct wfx_hif_mib_rx_filter arg = { }; + + if (filter_bssid) + arg.bssid_filter = 1; + if (!filter_prbreq) + arg.fwd_probe_req = 1; + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, &arg, sizeof(arg)); +} + +int wfx_hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, + const struct wfx_hif_ie_table_entry *tbl) +{ + int ret; + struct wfx_hif_mib_bcn_filter_table *arg; + int buf_len = struct_size(arg, ie_table, tbl_len); + + arg = kzalloc(buf_len, GFP_KERNEL); + if (!arg) + return -ENOMEM; + arg->num_of_info_elmts = cpu_to_le32(tbl_len); + memcpy(arg->ie_table, tbl, flex_array_size(arg, ie_table, tbl_len)); + ret = wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_FILTER_TABLE, + arg, buf_len); + kfree(arg); + return ret; +} + +int wfx_hif_beacon_filter_control(struct wfx_vif *wvif, int enable, int beacon_count) +{ + struct wfx_hif_mib_bcn_filter_enable arg = { + .enable = cpu_to_le32(enable), + .bcn_count = cpu_to_le32(beacon_count), + }; + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BEACON_FILTER_ENABLE, + &arg, sizeof(arg)); +} + +int wfx_hif_set_operational_mode(struct wfx_dev *wdev, enum wfx_hif_op_power_mode mode) +{ + struct wfx_hif_mib_gl_operational_power_mode arg = { + .power_mode = mode, + .wup_ind_activation = 1, + }; + + return wfx_hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE, + &arg, sizeof(arg)); +} + +int wfx_hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, + u8 frame_type, int init_rate) +{ + struct wfx_hif_mib_template_frame *arg; + + WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big"); + skb_push(skb, 4); + arg = (struct wfx_hif_mib_template_frame *)skb->data; + skb_pull(skb, 4); + arg->init_rate = init_rate; + arg->frame_type = frame_type; + arg->frame_length = cpu_to_le16(skb->len); + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME, + arg, sizeof(*arg) + skb->len); +} + +int wfx_hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required) +{ + struct wfx_hif_mib_protected_mgmt_policy arg = { }; + + WARN(required && !capable, "incoherent arguments"); + if (capable) { + arg.pmf_enable = 1; + arg.host_enc_auth_frames = 1; + } + if (!required) + arg.unpmf_allowed = 1; + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_PROTECTED_MGMT_POLICY, + &arg, sizeof(arg)); +} + +int wfx_hif_set_block_ack_policy(struct wfx_vif *wvif, u8 tx_tid_policy, u8 rx_tid_policy) +{ + struct wfx_hif_mib_block_ack_policy arg = { + .block_ack_tx_tid_policy = tx_tid_policy, + .block_ack_rx_tid_policy = rx_tid_policy, + }; + + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY, + &arg, sizeof(arg)); +} + +int wfx_hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density, + bool greenfield, bool short_preamble) +{ + struct wfx_hif_mib_set_association_mode arg = { + .preambtype_use = 1, + .mode = 1, + .spacing = 1, + .short_preamble = short_preamble, + .greenfield = greenfield, + .mpdu_start_spacing = ampdu_density, + }; + + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_ASSOCIATION_MODE, + &arg, sizeof(arg)); +} + +int wfx_hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, int policy_index, u8 *rates) +{ + struct wfx_hif_mib_set_tx_rate_retry_policy *arg; + size_t size = struct_size(arg, tx_rate_retry_policy, 1); + int ret; + + arg = kzalloc(size, GFP_KERNEL); + if (!arg) + return -ENOMEM; + arg->num_tx_rate_policies = 1; + arg->tx_rate_retry_policy[0].policy_index = policy_index; + arg->tx_rate_retry_policy[0].short_retry_count = 255; + arg->tx_rate_retry_policy[0].long_retry_count = 255; + arg->tx_rate_retry_policy[0].first_rate_sel = 1; + arg->tx_rate_retry_policy[0].terminate = 1; + arg->tx_rate_retry_policy[0].count_init = 1; + memcpy(&arg->tx_rate_retry_policy[0].rates, rates, + sizeof(arg->tx_rate_retry_policy[0].rates)); + ret = wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, + arg, size); + kfree(arg); + return ret; +} + +int wfx_hif_keep_alive_period(struct wfx_vif *wvif, int period) +{ + struct wfx_hif_mib_keep_alive_period arg = { + .keep_alive_period = cpu_to_le16(period), + }; + + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD, + &arg, sizeof(arg)); +}; + +int wfx_hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr) +{ + struct wfx_hif_mib_arp_ip_addr_table arg = { + .condition_idx = idx, + .arp_enable = HIF_ARP_NS_FILTERING_DISABLE, + }; + + if (addr) { + /* Caution: type of addr is __be32 */ + memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address)); + arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE; + } + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE, + &arg, sizeof(arg)); +} + +int wfx_hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable) +{ + struct wfx_hif_mib_gl_set_multi_msg arg = { + .enable_multi_tx_conf = enable, + }; + + return wfx_hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, &arg, sizeof(arg)); +} + +int wfx_hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val) +{ + struct wfx_hif_mib_set_uapsd_information arg = { }; + + if (val & BIT(IEEE80211_AC_VO)) + arg.trig_voice = 1; + if (val & BIT(IEEE80211_AC_VI)) + arg.trig_video = 1; + if (val & BIT(IEEE80211_AC_BE)) + arg.trig_be = 1; + if (val & BIT(IEEE80211_AC_BK)) + arg.trig_bckgrnd = 1; + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_UAPSD_INFORMATION, + &arg, sizeof(arg)); +} + +int wfx_hif_erp_use_protection(struct wfx_vif *wvif, bool enable) +{ + struct wfx_hif_mib_non_erp_protection arg = { + .use_cts_to_self = enable, + }; + + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_NON_ERP_PROTECTION, + &arg, sizeof(arg)); +} + +int wfx_hif_slot_time(struct wfx_vif *wvif, int val) +{ + struct wfx_hif_mib_slot_time arg = { + .slot_time = cpu_to_le32(val), + }; + + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, &arg, sizeof(arg)); +} + +int wfx_hif_wep_default_key_id(struct wfx_vif *wvif, int val) +{ + struct wfx_hif_mib_wep_default_key_id arg = { + .wep_default_key_id = val, + }; + + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, + &arg, sizeof(arg)); +} + +int wfx_hif_rts_threshold(struct wfx_vif *wvif, int val) +{ + struct wfx_hif_mib_dot11_rts_threshold arg = { + .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF), + }; + + return wfx_hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_RTS_THRESHOLD, + &arg, sizeof(arg)); +} diff --git a/drivers/net/wireless/silabs/wfx/hif_tx_mib.h b/drivers/net/wireless/silabs/wfx/hif_tx_mib.h new file mode 100644 index 000000000000..bcd4ef6a8497 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx_mib.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of the host-to-chip MIBs of the hardware API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ +#ifndef WFX_HIF_TX_MIB_H +#define WFX_HIF_TX_MIB_H + +#include + +struct sk_buff; +struct wfx_vif; +struct wfx_dev; +struct wfx_hif_ie_table_entry; +struct wfx_hif_mib_extended_count_table; + +int wfx_hif_set_output_power(struct wfx_vif *wvif, int val); +int wfx_hif_set_beacon_wakeup_period(struct wfx_vif *wvif, + unsigned int dtim_interval, unsigned int listen_interval); +int wfx_hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, int rssi_thold, int rssi_hyst); +int wfx_hif_get_counters_table(struct wfx_dev *wdev, int vif_id, + struct wfx_hif_mib_extended_count_table *arg); +int wfx_hif_set_macaddr(struct wfx_vif *wvif, u8 *mac); +int wfx_hif_set_rx_filter(struct wfx_vif *wvif, bool filter_bssid, bool fwd_probe_req); +int wfx_hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, + const struct wfx_hif_ie_table_entry *tbl); +int wfx_hif_beacon_filter_control(struct wfx_vif *wvif, int enable, int beacon_count); +int wfx_hif_set_operational_mode(struct wfx_dev *wdev, enum wfx_hif_op_power_mode mode); +int wfx_hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, + u8 frame_type, int init_rate); +int wfx_hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required); +int wfx_hif_set_block_ack_policy(struct wfx_vif *wvif, u8 tx_tid_policy, u8 rx_tid_policy); +int wfx_hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density, + bool greenfield, bool short_preamble); +int wfx_hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, int policy_index, u8 *rates); +int wfx_hif_keep_alive_period(struct wfx_vif *wvif, int period); +int wfx_hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr); +int wfx_hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable); +int wfx_hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val); +int wfx_hif_erp_use_protection(struct wfx_vif *wvif, bool enable); +int wfx_hif_slot_time(struct wfx_vif *wvif, int val); +int wfx_hif_wep_default_key_id(struct wfx_vif *wvif, int val); +int wfx_hif_rts_threshold(struct wfx_vif *wvif, int val); + +#endif