From patchwork Fri Sep 17 15:13:49 2021 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: 12502565 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,MSGID_FROM_MTA_HEADER,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 551AEC433F5 for ; Fri, 17 Sep 2021 15:17:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3B41861164 for ; Fri, 17 Sep 2021 15:17:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344726AbhIQPSz (ORCPT ); Fri, 17 Sep 2021 11:18:55 -0400 Received: from mail-bn7nam10on2088.outbound.protection.outlook.com ([40.107.92.88]:46465 "EHLO NAM10-BN7-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1343992AbhIQPRJ (ORCPT ); Fri, 17 Sep 2021 11:17:09 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=X0i1hQv/R33kUYiiaKLETrmLtENoKmmDcXDiyXrvTDAicCfspRlP2oHLQlOJ7g36WLoO+YgMlkd2aQxuzgOZ5gzbxQHUVav7zRaW2jgMZYF9G9GH28yw+WiDzV/SrI6U5oIitXEPkvpY3xD2pqgZSpTXYNbSnvHNwZgV0YeeuDHmvsqdgc6BmYX3SzWmeK2qRJRIqHXd4fxOnFCRc/D4XXAHUxoUDgRokLSxO3TqPgZAwOSw4Hg7HgkO8Bek1hHYOPdJcOT3TK4TM+gza5JIei0ZCMLmuGrgmMZGBgmmefD9ncBQC6iOfgD7JU+dwM9dl1QiyFNmX9BFLI4F/mNF4Q== 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; bh=JoF8rd7pOcuK4trIqHcnLJlpHT7+vJdshQrnJJlm26k=; b=DvHN4Eq8ozQc8KQZudAhDFjqZ+D+769xWX3PIgItW7oFuYtWAs1kVHKQ3yiXnY61k+gIsfCGXjJ2kef9COCiwpLRdwZye9wCpLxYlAawgQjdSnb00BNvknfE370nKSWi4RQgwi4/itiG8HqnyHuyUtHm2Bpq2w9SBUB/odQARNcugSSckJB1agUCz4kYhkrzsOSLgveoDk+DlotuuG2ArCZPE6L6fXFL0/n7dEIK+rFAzRdpWUQkU8rnk0uBeQupAdIFs+SwrfoPnsFb41J6k7jAMlLqLD+Ay3oTdN5isPb2EtKsAsGzA6BPjBcDBhPR2Ic+jRplMgtaUt7EdeMVwQ== 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=JoF8rd7pOcuK4trIqHcnLJlpHT7+vJdshQrnJJlm26k=; b=e3EuEiPPHEFtwG6XWcflTIyxHrbBN1UB+ZisY8Btz/i2vnGZYN/ipsUwTpyRmo7/wYcMJdN5H9WX6NMZ+pJdTS/Rr7Wk9DlV7fprtN69ZBUE6QDkDYNqkcBYh9IIplqxcUXpN1O/lBd1vePwcJ4dsLG1zlC4nIrCyG9Hpse/x9E= Authentication-Results: vger.kernel.org; dkim=none (message not signed) header.d=none;vger.kernel.org; dmarc=none action=none header.from=silabs.com; Received: from SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) by SA0PR11MB4574.namprd11.prod.outlook.com (2603:10b6:806:71::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4523.14; Fri, 17 Sep 2021 15:14:51 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::7050:a0a:415:2ccd]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::7050:a0a:415:2ccd%7]) with mapi id 15.20.4500.017; Fri, 17 Sep 2021 15:14:51 +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 v6 13/24] wfx: add hif_tx*.c/hif_tx*.h Date: Fri, 17 Sep 2021 17:13:49 +0200 Message-Id: <20210917151401.2274772-14-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210917151401.2274772-1-Jerome.Pouiller@silabs.com> References: <20210917151401.2274772-1-Jerome.Pouiller@silabs.com> X-ClientProxiedBy: SA9PR03CA0029.namprd03.prod.outlook.com (2603:10b6:806:20::34) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 Received: from pc-42.silabs.com (2a01:e34:ecb5:66a0:9876:e1d7:65be:d294) by SA9PR03CA0029.namprd03.prod.outlook.com (2603:10b6:806:20::34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4523.14 via Frontend Transport; Fri, 17 Sep 2021 15:14:49 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 587073c9-bb9e-42a2-6b94-08d979ede596 X-MS-TrafficTypeDiagnostic: SA0PR11MB4574: X-MS-Exchange-Transport-Forked: True 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: gFfpeCoXpxuuw/GEXF31WTdJpfXPhaONppOfzAyf2o920N2kx8UfnqZAsezhaf4uqQIyZHi2hU9MDdMFxk5OWsWoX/wOPmSI6x9dbdmsCW25Aac2q0P2D0+siTt8iYreYKmxrAhmYcvwi9P0V+zu++Zr8TAZIiXR/XBAVVuHR4QDDUtTxSTS1nLPbi4zj2fmGQ7sDaRV6/XDzCNk5UV1jU4l4dxy/SmdRc6fLyWpIIH7ncLou7/4HIfHiB//vALPL68gKlEz9JFy1qdfXq8hSYhC6WuA3drzEAn6oxMwAN4PuT2vN7qTu9Cn9xYdT/vkRnk6+cPQ17uxtbzpK3r6sHemmjszHCS4w4rtpwR7SpInmq2zvw0M0SjwmTMudaGAnHk7ma+zGzLFZML1devnkF+wDlmdn5M7hLIRaUkdJP6D/GQjI61JPi7L9UpflBYALCwmjbwWL0XO5bc89+ujTbWM1YEo4CYxA1o2cszVRe9Shk3RVmfWoC+f+aB5rTSozgK5HM5hH3lUlKUp/Xk3ZzJjVeujsNZOuxKXvvLTfiR5jFvw1IJCxiqaouP7Q+g9RGYD6K1p2bTzNPRO1CR7eo/Lllx1UlHhR1KtHI0Og/ulWBEJ2NFfFhgOofjh8cUmU8fockwLg/nW+Vqjk78/xQ== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SN6PR11MB2718.namprd11.prod.outlook.com;PTR:;CAT:NONE;SFS:(136003)(346002)(376002)(39850400004)(396003)(366004)(52116002)(38100700002)(8936002)(7696005)(478600001)(6486002)(186003)(7416002)(86362001)(5660300002)(54906003)(66556008)(66476007)(4326008)(1076003)(66946007)(2616005)(107886003)(6916009)(316002)(30864003)(36756003)(8676002)(66574015)(2906002)(83380400001);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?q?iUwjBoqqcjYh6t3yQ7xZ2hRgUclj?= =?utf-8?q?7mtZ6nn5J0p8TTV98CO4g/8ZI4Dp4rB0ryHT06NDOLcrOhqS+3bO9IjhdcKPqblwY?= =?utf-8?q?ndM5ktkBwDR6pwhLC9OAZBfWZfG2I5uQw2fIE8v+YhBOppR/KOIxxOH2O26dDUAb+?= =?utf-8?q?j7IEsj8ePCUFnvD2o6W4uKOQm5Cu6t4AFWtx9iIkxmvr5AiX1kwoFOQVlnQLYfDb4?= =?utf-8?q?IlNNWBJO9tvoJYpof+xsXYWQZ0KfUFC7/18UJgYwJ39raB/rbweYV+7U0oC8KCqAI?= =?utf-8?q?XtRPZbNK4bImBf+B8JiB6e3yh53JY6Se0ATUWwsfcAlJufgw/wh+402PwZVZoO+Ze?= =?utf-8?q?F4MsORa/vY1Dpf/82DatdM7Nv2iBDOOBo/MvnTEsa+DpP7j1e6xf3IRyW+1NyzzI3?= =?utf-8?q?5m5QE/vcirqHpC8ICuyW9MUG14BhbKW+MRqEIBfzq5zvac7vM2axMujkpzAfXGnNt?= =?utf-8?q?cWiKgeK+LBtTZflDZTZ1E4/Xxz0pu+Y4FHpsTfBAMa03cLHB5ay/OhXxz47F9BRs9?= =?utf-8?q?qSnIy0NUp5+OFs7S0xgI+rVXd/B8dxBgVGZr5w2tWgspZp9pEXRCR7Z4PnwbYOGEJ?= =?utf-8?q?0b4SKbHFU/uszkurD3gVnlbHFXjIjqVF8EkwvXf0iagz3azrV2CZj4BlwQLbUCSD6?= =?utf-8?q?cofBb+4fwKUepDVQbGKZ3OyxL4OuNPOa0CM0IfbTamdKtrJRF4lAjEKKeJcHjMcgb?= =?utf-8?q?Y7wzcRoziZMitCy1fIGeYj3+E7o+KABQQsOcb/C4KfaHAruBFbcAeGvLm7tYDZjAq?= =?utf-8?q?oiLyZq6/vT0afcONF5p1aRZl4dvzlzKD78cRj1gQBcA5UoqY27PfHEApH4usePLiJ?= =?utf-8?q?UssrE5RYKckNvNeaK3VXrCxf80BYmb8RkVh/NDh20cox8tpEK4252i4US3rkSJN/X?= =?utf-8?q?ylM9GbArKdw5HoX1CdI/MjF+y0yVKz7L2PWYpz5dDzmH9xNs6gj5H1P0KOwvks5rO?= =?utf-8?q?UNDYEl5zehBiT3muNTPSPzdJA9M/Y54vRpWxRN1Mkpl2dBkj4rNGcxewcStUy29HY?= =?utf-8?q?sThemBS8hJ2Q0BfEAodCiPNylf4tn0Kx466PX6umSd0V+iquPb19/h5C1NogvUSRP?= =?utf-8?q?Pel+BnM+Ugp2Z2L7CEaCtvgGSVw3TumgKUS4kCV/0IKwg3vUr+UCCbEYquH3k4b5/?= =?utf-8?q?JFNvSYHiyNbMAT1lQ8181R53APOrnhk52jRz79Hn2SV8zKweKrhaciN2vHu7wjgC/?= =?utf-8?q?Iwh1mWeUT+vRs1Fm3O/9+DIMcaGEZZvVxuMmfbYMg7/CKL/JVX8BtWnA/kc9/hT+s?= =?utf-8?q?VnL6MNMeuoH3MRVdon1YmK74QpiGxYK3iz3sRbc0W2oAZQ+UoslhXrtjJG2SLe/BU?= =?utf-8?q?6zr55swMq9RiXDU?= X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 587073c9-bb9e-42a2-6b94-08d979ede596 X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Sep 2021 15:14:51.8264 (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: C8B013DUuSnNlzzuaaTb+JXJRrc8HV3LHwV9/qkGvpOjCD8SXZurhac0QZqvXyhJW10/PC1rdkM5f0eWs+p5+w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA0PR11MB4574 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Jérôme Pouiller Signed-off-by: Jérôme Pouiller --- drivers/net/wireless/silabs/wfx/hif_tx.c | 514 +++++++++++++++++++ drivers/net/wireless/silabs/wfx/hif_tx.h | 60 +++ drivers/net/wireless/silabs/wfx/hif_tx_mib.c | 324 ++++++++++++ drivers/net/wireless/silabs/wfx/hif_tx_mib.h | 49 ++ 4 files changed, 947 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..d39366c171ba --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx.c @@ -0,0 +1,514 @@ +// 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 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 hif_msg **hif) +{ + *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL); + if (*hif) + return (*hif)->body; + else + return NULL; +} + +int wfx_cmd_send(struct wfx_dev *wdev, struct 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 = 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", + 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", + 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 hif_shutdown(struct wfx_dev *wdev) +{ + int ret; + struct 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 + control_reg_write(wdev, 0); + kfree(hif); + return ret; +} + +int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len) +{ + int ret; + size_t buf_len = sizeof(struct hif_req_configuration) + len; + struct hif_msg *hif; + struct 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 hif_reset(struct wfx_vif *wvif, bool reset_stat) +{ + int ret; + struct hif_msg *hif; + struct 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 hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *val, size_t val_len) +{ + int ret; + struct hif_msg *hif; + int buf_len = sizeof(struct hif_cnf_read_mib) + val_len; + struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif); + struct 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", + 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 hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *val, size_t val_len) +{ + int ret; + struct hif_msg *hif; + int buf_len = sizeof(struct hif_req_write_mib) + val_len; + struct 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 hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req, + int chan_start_idx, int chan_num) +{ + int ret, i; + struct hif_msg *hif; + size_t buf_len = + sizeof(struct hif_req_start_scan_alt) + chan_num * sizeof(u8); + struct 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 hif_stop_scan(struct wfx_vif *wvif) +{ + int ret; + struct 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 hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + struct ieee80211_channel *channel, const u8 *ssid, int ssidlen) +{ + int ret; + struct hif_msg *hif; + struct 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 hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count) +{ + int ret; + struct hif_msg *hif; + struct 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 hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg) +{ + int ret; + struct hif_msg *hif; + /* FIXME: only send necessary bits */ + struct 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 hif_remove_key(struct wfx_dev *wdev, int idx) +{ + int ret; + struct hif_msg *hif; + struct 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 hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, + const struct ieee80211_tx_queue_params *arg) +{ + int ret; + struct hif_msg *hif; + struct 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 hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout) +{ + int ret; + struct hif_msg *hif; + struct 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 hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + const struct ieee80211_channel *channel) +{ + int ret; + struct hif_msg *hif; + struct 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 hif_beacon_transmit(struct wfx_vif *wvif, bool enable) +{ + int ret; + struct hif_msg *hif; + struct 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 hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp) +{ + int ret; + struct hif_msg *hif; + struct 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 hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len) +{ + int ret; + struct hif_msg *hif; + int buf_len = sizeof(struct hif_req_update_ie) + ies_len; + struct 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..e57eabdcfa77 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx.h @@ -0,0 +1,60 @@ +/* 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 + +struct ieee80211_channel; +struct ieee80211_bss_conf; +struct ieee80211_tx_queue_params; +struct cfg80211_scan_request; +struct hif_req_add_key; +struct wfx_dev; +struct wfx_vif; + +struct wfx_hif_cmd { + struct mutex lock; + struct completion ready; + struct completion done; + struct 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 hif_msg *request, + void *reply, size_t reply_len, bool async); + +int hif_shutdown(struct wfx_dev *wdev); +int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len); +int hif_reset(struct wfx_vif *wvif, bool reset_stat); +int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *buf, size_t buf_size); +int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *buf, size_t buf_size); +int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211, + int chan_start, int chan_num); +int hif_stop_scan(struct wfx_vif *wvif); +int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + struct ieee80211_channel *channel, const u8 *ssid, int ssidlen); +int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout); +int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count); +int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg); +int hif_remove_key(struct wfx_dev *wdev, int idx); +int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, + const struct ieee80211_tx_queue_params *arg); +int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + const struct ieee80211_channel *channel); +int hif_beacon_transmit(struct wfx_vif *wvif, bool enable); +int hif_map_link(struct wfx_vif *wvif, + bool unmap, u8 *mac_addr, int sta_id, bool mfp); +int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len); + +#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..97e961e6bcf6 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx_mib.c @@ -0,0 +1,324 @@ +// 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 hif_set_output_power(struct wfx_vif *wvif, int val) +{ + struct hif_mib_current_tx_power_level arg = { + .power_level = cpu_to_le32(val * 10), + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_CURRENT_TX_POWER_LEVEL, + &arg, sizeof(arg)); +} + +int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, + unsigned int dtim_interval, + unsigned int listen_interval) +{ + struct 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 hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_WAKEUP_PERIOD, + &arg, sizeof(arg)); +} + +int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, + int rssi_thold, int rssi_hyst) +{ + struct 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 hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_RCPI_RSSI_THRESHOLD, &arg, sizeof(arg)); +} + +int hif_get_counters_table(struct wfx_dev *wdev, int vif_id, + struct 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 hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE, + arg, sizeof(struct hif_mib_count_table)); + } else { + return hif_read_mib(wdev, vif_id, + HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, arg, + sizeof(struct hif_mib_extended_count_table)); + } +} + +int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac) +{ + struct hif_mib_mac_address arg = { }; + + if (mac) + ether_addr_copy(arg.mac_addr, mac); + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS, + &arg, sizeof(arg)); +} + +int hif_set_rx_filter(struct wfx_vif *wvif, + bool filter_bssid, bool filter_prbreq) +{ + struct hif_mib_rx_filter arg = { }; + + if (filter_bssid) + arg.bssid_filter = 1; + if (!filter_prbreq) + arg.fwd_probe_req = 1; + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, + &arg, sizeof(arg)); +} + +int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, + const struct hif_ie_table_entry *tbl) +{ + int ret; + struct 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 = hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_FILTER_TABLE, arg, buf_len); + kfree(arg); + return ret; +} + +int hif_beacon_filter_control(struct wfx_vif *wvif, + int enable, int beacon_count) +{ + struct hif_mib_bcn_filter_enable arg = { + .enable = cpu_to_le32(enable), + .bcn_count = cpu_to_le32(beacon_count), + }; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_FILTER_ENABLE, + &arg, sizeof(arg)); +} + +int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode) +{ + struct hif_mib_gl_operational_power_mode arg = { + .power_mode = mode, + .wup_ind_activation = 1, + }; + + return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE, + &arg, sizeof(arg)); +} + +int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, + u8 frame_type, int init_rate) +{ + struct hif_mib_template_frame *arg; + + WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big"); + skb_push(skb, 4); + arg = (struct 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 hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME, + arg, sizeof(*arg) + skb->len); +} + +int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required) +{ + struct 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 hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_PROTECTED_MGMT_POLICY, + &arg, sizeof(arg)); +} + +int hif_set_block_ack_policy(struct wfx_vif *wvif, + u8 tx_tid_policy, u8 rx_tid_policy) +{ + struct hif_mib_block_ack_policy arg = { + .block_ack_tx_tid_policy = tx_tid_policy, + .block_ack_rx_tid_policy = rx_tid_policy, + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY, + &arg, sizeof(arg)); +} + +int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density, + bool greenfield, bool short_preamble) +{ + struct 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 hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_ASSOCIATION_MODE, &arg, sizeof(arg)); +} + +int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, + int policy_index, u8 *rates) +{ + struct 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 = hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size); + kfree(arg); + return ret; +} + +int hif_keep_alive_period(struct wfx_vif *wvif, int period) +{ + struct hif_mib_keep_alive_period arg = { + .keep_alive_period = cpu_to_le16(period), + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD, + &arg, sizeof(arg)); +}; + +int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr) +{ + struct 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 hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE, + &arg, sizeof(arg)); +} + +int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable) +{ + struct hif_mib_gl_set_multi_msg arg = { + .enable_multi_tx_conf = enable, + }; + + return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, + &arg, sizeof(arg)); +} + +int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val) +{ + struct 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 hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_UAPSD_INFORMATION, + &arg, sizeof(arg)); +} + +int hif_erp_use_protection(struct wfx_vif *wvif, bool enable) +{ + struct hif_mib_non_erp_protection arg = { + .use_cts_to_self = enable, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg)); +} + +int hif_slot_time(struct wfx_vif *wvif, int val) +{ + struct hif_mib_slot_time arg = { + .slot_time = cpu_to_le32(val), + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, + &arg, sizeof(arg)); +} + +int hif_wep_default_key_id(struct wfx_vif *wvif, int val) +{ + struct hif_mib_wep_default_key_id arg = { + .wep_default_key_id = val, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, + &arg, sizeof(arg)); +} + +int hif_rts_threshold(struct wfx_vif *wvif, int val) +{ + struct hif_mib_dot11_rts_threshold arg = { + .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF), + }; + + return 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..2a3b84868ee4 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx_mib.h @@ -0,0 +1,49 @@ +/* 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 + +struct wfx_vif; +struct sk_buff; + +int hif_set_output_power(struct wfx_vif *wvif, int val); +int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, + unsigned int dtim_interval, + unsigned int listen_interval); +int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, + int rssi_thold, int rssi_hyst); +int hif_get_counters_table(struct wfx_dev *wdev, int vif_id, + struct hif_mib_extended_count_table *arg); +int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac); +int hif_set_rx_filter(struct wfx_vif *wvif, + bool filter_bssid, bool fwd_probe_req); +int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, + const struct hif_ie_table_entry *tbl); +int hif_beacon_filter_control(struct wfx_vif *wvif, + int enable, int beacon_count); +int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode); +int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, + u8 frame_type, int init_rate); +int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required); +int hif_set_block_ack_policy(struct wfx_vif *wvif, + u8 tx_tid_policy, u8 rx_tid_policy); +int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density, + bool greenfield, bool short_preamble); +int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, + int policy_index, u8 *rates); +int hif_keep_alive_period(struct wfx_vif *wvif, int period); +int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr); +int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable); +int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val); +int hif_erp_use_protection(struct wfx_vif *wvif, bool enable); +int hif_slot_time(struct wfx_vif *wvif, int val); +int hif_wep_default_key_id(struct wfx_vif *wvif, int val); +int hif_rts_threshold(struct wfx_vif *wvif, int val); + +#endif