From patchwork Wed Nov 4 15:51:45 2020 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: 318393 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 BE8CFC388F9 for ; Wed, 4 Nov 2020 15:52:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 67B0420781 for ; Wed, 4 Nov 2020 15:52:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="UJxetc53" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730785AbgKDPwi (ORCPT ); Wed, 4 Nov 2020 10:52:38 -0500 Received: from mail-eopbgr750080.outbound.protection.outlook.com ([40.107.75.80]:6126 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730871AbgKDPwf (ORCPT ); Wed, 4 Nov 2020 10:52:35 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=bUPnn/Sb+BKkya436/dEQknP2hszssHZ5+IMoSgKWsQkZdtjMJgq93GQVzui+IyG6zDir6y2gllB5Ffa1EKV0UqeWR4qyHWt1teNrNgagjy08OgG75x8ibfQHbA7hwHNUfBpYdR4JjdTCpTbCHchomZEOZD+6NJvs6nWCcOi9ID2KVvjQaGsoTLsOa6qYqW3QWoRd3VrRkZqxqkbTI1PPGd6lzZZrglxwpxFkT+L2dnAi+izy5eVVBqMcFK7dSHMJCBc4iht1NjMjRsgZuaUY29djFFCxuSwEu3wmhLmFQdIYARhVCmmohWKK5x7cazEMpth+Mwfqn+a4wYnURu9gA== 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-SenderADCheck; bh=YekLf7amXYKq9twfWKvoXTRecyL+hvQncbuTAVKuyHg=; b=CV5z5i7qS00KalbbdDr6BcF3JXMdj6TlvxWBNcPR4czyecyMDmE0NUUL5Pxg34eEfbWAxYdOtlTbje5s8T0teRmnsMz36wRH9FwP88834fLtZEaGHPRSFskrtZ/HGxBM1uotTwzBPwvtAu+HNTHWQmMUGaIkFc8iSxNMgssFzTGCSccPf1rNEIXZtELy4Rrok1C2CkE3DNVXHh4faLzPuzGAdlTcBbEFrK8fRJOEQ7flXZykKsBn4/G37/S4ED13yEmqvZaXoWAfn/NnoiMbrqK1wgk6RPST6uiFp0Ac3CyzdDZ7MhnFfEC9u1RE2xC5Mn5stBI+QkNBqYFS/9GQMw== 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=YekLf7amXYKq9twfWKvoXTRecyL+hvQncbuTAVKuyHg=; b=UJxetc53+vxdJTO2mnlWQFfdwmQiImM/NzIwWNilXHpCwcCBEBMh1QT/YlFH9J3BYoHOu6csn9FrFeSHskERO3ckHzYWmJFYZw7AmJmwxhbGMqjwiKvngReU6jggmoxjZxEMjRketHrFKCQd0GgOR6YND38z8eFd15wCtc3hUq8= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:52:26 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:52:26 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 02/24] dt-bindings: introduce silabs,wfx.yaml Date: Wed, 4 Nov 2020 16:51:45 +0100 Message-Id: <20201104155207.128076-3-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:52:24 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 89e1f47b-a8f3-4942-e701-08d880d9a06c X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:8882; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: UT27EFOp4QjKziqbHJecGGwQwemfpCvH+r9UZS6qp8z8DEnArUicsRZFksm74peIurrdX6CfkHstG3U4Iigsry4Nc8MGC1ZGx+7J04UFqAlf1g0lmZYn30dIDwOA/hq3FXYos7oNlHeJ9FeuQG7C6Bl4bZzgsBvty8OUeoIFj4lqcgcqJSssiwBLKxPCU2l91UT+Uq2yIt1gpToZj7+R7+/frumUxW3qVBZJUsrOQFb75gOdpTqvwmPz9qzXNrZXsFLo0c/cFP43aDnR/ad8UnKh+M5Eai6ugiswZ8bA9SGa6f4A0MWR47yB1YKCerZv20Rom2WDDzKph3Qmawz9icz45RqQ3bWmu1Z8fB4kNh6zVtMNpUZ7+5SSAZS55o0N55o43SIfKKTV+FPw/lZPog== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(966005)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66476007)(66556008)(66946007)(316002)(7696005)(6666004)(26005)(54906003)(107886003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: 3KGAH1cqGm1oJJ+S+ZoThEr8QJN4o/UAxZIa7GXx1pRRmC/2tS4AOnYXPMyQz42ftIUwJkEv0sGgdi2q4ljsJuEtY88MSFqgf4JzmOMg1FT9MwXPjYuXfdQd2E8N6cXXrxTTfHGIhrY5o8YLFeB3LfLZhgWkrjy7JTiCDdgk7vy/4eRsci5s3DZAzN/iPg9UoyU/YtD6eRyV8C/l/jfrzki/Dnw/ebTjcIJG0nRGc2/csph5UFq9bXCPoi900S68sNZScreuAIvZgJBLdoT8rJLzJfORRjN2tuksDJO7/aw8oIESoJLw50GO7HtKmjmA6hGF47GEWrdTZvLUp9s0C2ZTku6gNqtP72lMHhimXQpk+5z3ScIvIstIozGvgJJesk5ds5CkqRYmDykwnelpRZtQCDIUrwus6B0JgEGqtYzGbhX8ExTRaLmQ/bXislhEfbcZ7JSFjVJ2FWtVVTNgnqTddrc4uXtidKyW/WVgF80vhhz4gpc2K3ISpMD+94l9jPQNXPJsCAlAVyME1s8GhxPxD8i4NfWWPjQMOWjIFzdMU9is5zBHOKQVbxelZkyB85s1u7n3mbR5rvFm/pt7eeDMokigwS2dpQTmtey0VKAYVSFUyXf71bMzUll67c0+5KAcT1nsR95QqvSqy/2vNg== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 89e1f47b-a8f3-4942-e701-08d880d9a06c X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:52:26.2934 (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: 1Mb09NbqQpHybMDi0QWdVFj3dAJUDEh0GZFU6x373AoehaFvMbYsDnHNDgKW+iru02V3QH7htcqtL5+wOuTe0A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Jérôme Pouiller Signed-off-by: Jérôme Pouiller --- .../bindings/net/wireless/silabs,wfx.yaml | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml diff --git a/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml b/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml new file mode 100644 index 000000000000..c9fc5ff95b58 --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2020, Silicon Laboratories, Inc. +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/net/wireless/silabs,wfx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Silicon Labs WFxxx devicetree bindings + +maintainers: + - Jérôme Pouiller + +description: > + Support for the Wifi chip WFxxx from Silicon Labs. Currently, the only device + from the WFxxx series is the WF200 described here: + https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf + + The WF200 can be connected via SPI or via SDIO. + + For SDIO: + + Declaring the WFxxx chip in device tree is mandatory (usually, the VID/PID is + sufficient for the SDIO devices). + + It is recommended to declare a mmc-pwrseq on SDIO host above WFx. Without + it, you may encounter issues during reboot. The mmc-pwrseq should be + compatible with mmc-pwrseq-simple. Please consult + Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt for more + information. + + For SPI: + + In add of the properties below, please consult + Documentation/devicetree/bindings/spi/spi-controller.yaml for optional SPI + related properties. + +properties: + compatible: + const: silabs,wf200 + + reg: + description: + When used on SDIO bus, must be set to 1. When used on SPI bus, it is + the chip select address of the device as defined in the SPI devices + bindings. + maxItems: 1 + + spi-max-frequency: true + + interrupts: + description: The interrupt line. Triggers IRQ_TYPE_LEVEL_HIGH and + IRQ_TYPE_EDGE_RISING are both supported by the chip and the driver. When + SPI is used, this property is required. When SDIO is used, the "in-band" + interrupt provided by the SDIO bus is used unless an interrupt is defined + in the Device Tree. + maxItems: 1 + + reset-gpios: + description: (SPI only) Phandle of gpio that will be used to reset chip + during probe. Without this property, you may encounter issues with warm + boot. (For legacy purpose, the gpio in inverted when compatible == + "silabs,wfx-spi") + + For SDIO, the reset gpio should declared using a mmc-pwrseq. + maxItems: 1 + + wakeup-gpios: + description: Phandle of gpio that will be used to wake-up chip. Without this + property, driver will disable most of power saving features. + maxItems: 1 + + silabs,antenna-config-file: + $ref: /schemas/types.yaml#/definitions/string + description: Use an alternative file for antenna configuration (aka + "Platform Data Set" in Silabs jargon). Default is 'wf200.pds'. + + local-mac-address: true + + mac-address: true + +required: + - compatible + - reg + +examples: + - | + #include + #include + + spi0 { + #address-cells = <1>; + #size-cells = <0>; + + wifi@0 { + compatible = "silabs,wf200"; + pinctrl-names = "default"; + pinctrl-0 = <&wfx_irq &wfx_gpios>; + reg = <0>; + interrupts-extended = <&gpio 16 IRQ_TYPE_EDGE_RISING>; + wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; + spi-max-frequency = <42000000>; + }; + }; + + - | + #include + #include + + wfx_pwrseq: wfx_pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&wfx_reset>; + reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; + }; + + mmc0 { + mmc-pwrseq = <&wfx_pwrseq>; + #address-cells = <1>; + #size-cells = <0>; + + wifi@1 { + compatible = "silabs,wf200"; + pinctrl-names = "default"; + pinctrl-0 = <&wfx_wakeup>; + reg = <1>; + wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; + }; + }; +... From patchwork Wed Nov 4 15:51:46 2020 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: 318382 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 757C4C2D0A3 for ; Wed, 4 Nov 2020 15:56:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 21896205ED for ; Wed, 4 Nov 2020 15:56:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="k4z9JRFM" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730779AbgKDPwo (ORCPT ); Wed, 4 Nov 2020 10:52:44 -0500 Received: from mail-eopbgr750080.outbound.protection.outlook.com ([40.107.75.80]:6126 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730682AbgKDPwi (ORCPT ); Wed, 4 Nov 2020 10:52:38 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=AKHLw2c6AkRh9Yj0+z8RXcZAmeQJvAdpXSGRpdE2NrCqTf2Zhd2jQeUv25tjP5pV9O+kb4A98mo9MiTcc7HYeGUQpXC3emVcquU7Etar4SVVJCz/V6IJj8LjeuAwbjhVizTBJUuIt+FY2QHHoUlYlpkWnc2FlsMl2jjT/ZSfzr7jkGdkDygY8Z5CncgRQhIv/O0vvD16nMqYqAl5vftpssZDE/qHD1Hco6vdAxjKj3gRuGbaV4qJLreuyFzBoucZGLTr4I3Z0lfn2dWFdRYPcn7dgYBfeRpDlK2iomjphY4PHE6N4DFcMwI5FfDQ2uUNF0AvkGeEePKpNypEbnHZhQ== 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-SenderADCheck; bh=58XMnNgaUS8bBLHPu9hEGfkhu7DZAV5XWPx13jJWCV0=; b=N+1aCmf+YP0MyapvRToWqHyHwKyMnliXHI6ngtUEWt9X53+27Pid5ImdgA49Zf7FPMr8SgRRX7rf3BBJ2Dfjy69NItm+T4he2m4j1ltlGJQM+oevVC7EuD8uzX6r8J48lkbdKdPs2PXyMhKMKmOo/Xt/wo6TFlIKvvO9r3ygz2MKNLEVaGD0wb1LwBTM0QJ1nGM4oN7dkerXerkMRcbw7H8XeHxtLsluSsBtwty0hABDn58GF6Yad9jiQICxytWkgHuT2/bVWRg5jYV/eOQXNBLQUDuBNJzB4JLMrNE/IxMuy6FXibJu2YmuTAx8L/aJhDszo3Ve0XbDK0/tHlTAyw== 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=58XMnNgaUS8bBLHPu9hEGfkhu7DZAV5XWPx13jJWCV0=; b=k4z9JRFMMMrznNt6Ae+uNNts6kLwKuP+pIJb5wJAtNYOBP2znCyvMguCqbraP0gZTLevIRPfcwQtWmOWTAuUUs2alAATS+CCIJBHGpHn/Ael0BcYTIEEKe4EzJdc4h3NKCVRKcQffjQRZ9gYSSIdcrz3B87pctbjVxDyQ3fGock= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:52:28 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:52:28 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 03/24] wfx: add Makefile/Kconfig Date: Wed, 4 Nov 2020 16:51:46 +0100 Message-Id: <20201104155207.128076-4-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:52:26 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 4b96683e-9dad-41fd-77a3-08d880d9a1c6 X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:7219; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 29Z6nyaouE0IUsSi69Jbole6ftmQcoHFISOHac+0zj/q42cPevH64blfElB4HzWPMZlSSUcu5yxOWRVqti4C/cY2D1+kiQ9mrb9H2maH2jAvoAJArNbnbVZrj1vGIegLKSE513bfjGMRAj60AGCFwKwtwDNJeRcciXpluNpQ7nQ7S17983w0DaJoQ16Kikwy6mez8Y9Pig195fDRBAORS/U6Xl+Hnj8oQxS/iTPHonCIUNyjZl53XrK4ckXXDZwHCikP3RS3YWx4vUwtYN+GUmpLaRTRLvqQtxd2Z25NNuJ1QFfN3lZbLTAr+5LeFNDx 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(6666004)(26005)(54906003)(107886003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: RSgRNvTUS0ndq/MivqdjErm7zrZocnxzL6iMY21cwnWyvCtfvAGWwRdDSOdRifuQAnZFGHKK5uCiX/qHLPKdmXJuOtE0bTvL2mJAQRRKzahek8yyZn1YX/40YOGB5zFGlqMoJE2X26plHeL61QlCaGhpnf6emV6Y7jMa4xOJqLbLjm+9B2Bk71Ngb9PJlkSNHfuHWkY0I2bzOYo3tKbPnJOuPMN92C4MBcn+24QOYmyyEctqpNN3fHJiD/4lmQOmcwZrtoA4PdmiIvNaqHk5nPnfwDzqh3snVM1CWjiwEq/CPcTcmJtrrLXHiBHYto4Bxi9uAS/6KWAgsNcYp1UT9wEA1uF/bhDner/RdxSocw2yIE4v7/BPbURb7GfQxjFjSAsISZ16nkqmcWHqGCQ9qBwnsDKm5FgN9qM8XjkDE2vbOznEsgVOiXav/hv1SCFNHb2k+Ifpt/Ns42kZeUR8jIpf63duYo7i68bMI9CsVsoKC3nxW4ggBZ4hplxCJiQHPRBqzLOUkxHjx+EKaCbZl+KWruUeNJ8N7/7fUNnlyZfEteXvflQ0Au+xaOJLOQQUfsFOTd9hXyfA+jLEU1/FGfOSjoVmFXzMH+6Yvct/5NiIZd6qHUsZZ5KXYEu7PdW+CH67sw3cgPoJKEbXtc3jmg== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 4b96683e-9dad-41fd-77a3-08d880d9a1c6 X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:52:28.5411 (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: Dgx6bin2OEI7w6p4y846ZL47M28aQ9Dwim8htynT1lZy9rG2jcsQNeCcZEKfe4+77KxMxvguyYKpspioTwbCWw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/Kconfig | 8 ++++++++ drivers/net/wireless/silabs/wfx/Makefile | 25 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/Kconfig create mode 100644 drivers/net/wireless/silabs/wfx/Makefile diff --git a/drivers/net/wireless/silabs/wfx/Kconfig b/drivers/net/wireless/silabs/wfx/Kconfig new file mode 100644 index 000000000000..83ee4d0ca8c6 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/Kconfig @@ -0,0 +1,8 @@ +config WFX + tristate "Silicon Labs wireless chips WF200 and further" + depends on MAC80211 + depends on MMC || !MMC # do not allow WFX=y if MMC=m + depends on (SPI || MMC) + help + This is a driver for Silicons Labs WFxxx series (WF200 and further) + chipsets. This chip can be found on SPI or SDIO buses. diff --git a/drivers/net/wireless/silabs/wfx/Makefile b/drivers/net/wireless/silabs/wfx/Makefile new file mode 100644 index 000000000000..0e0cc982ceab --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/Makefile @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Necessary for CREATE_TRACE_POINTS +CFLAGS_debug.o = -I$(src) + +wfx-y := \ + bh.o \ + hwio.o \ + fwio.o \ + hif_tx_mib.o \ + hif_tx.o \ + hif_rx.o \ + queue.o \ + data_tx.o \ + data_rx.o \ + scan.o \ + sta.o \ + key.o \ + main.o \ + sta.o \ + debug.o +wfx-$(CONFIG_SPI) += bus_spi.o +wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o + +obj-$(CONFIG_WFX) += wfx.o From patchwork Wed Nov 4 15:51:47 2020 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: 318383 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 BB285C2D0A3 for ; Wed, 4 Nov 2020 15:56:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5D27E204EF for ; Wed, 4 Nov 2020 15:56:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="k5xTDQqQ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730945AbgKDPwp (ORCPT ); Wed, 4 Nov 2020 10:52:45 -0500 Received: from mail-eopbgr750080.outbound.protection.outlook.com ([40.107.75.80]:6126 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730902AbgKDPwn (ORCPT ); Wed, 4 Nov 2020 10:52:43 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=dz5xtnQY7duxWoJQ3f0MemnwJi0TF6D9BsfUE7tkuSji52AKzSQyyNlOD8QTEhKL/I1XkiLrXB79I9RsKr8vU+EQiulTmh4or62Q49/eNOCtZps2atSI16EpcfDpRFrLlDTM8A9REG4MyRnPN/YbybBTfuRrwOXxH0777z88ZC+RbvlOu2suiUxlxeC06D0zZDvRIuMGsdKIPxjwHrPGvoia3Gsvx8pbVTLNFvulsSrY2KLFYww7ofGbH2uPUr9gIh54AKrCi4+4i5FSAnAKsO2u5ICnlwIXHLUmZMWX+nHaKQDItzDi1YgGu2mVk7Mi44fSAK5rCBZt1y8p+7x2EQ== 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-SenderADCheck; bh=RqZzTE5IDNzLeiEeh0gtmEhR+vjHmPP5GDL6eBo8e3g=; b=dKojzDNmS0h61w+Sx7dL0+bbNr2lgYe/Jer942106yocaeubV5qf915GYUgT3aaxSOHiuSXx2Ak1lGvSSBKEqYXmBMBe+Pw5lqa5ACt5kgPqsIgRDZYyj4DZ2U+IqsuORbN3IgDh8ZVgbGEXYq6gC7LQDRGRgRr62EhrXc51oQ3q8Jd5hTKQfxWRcLnQavcI/UnG8CONBVlET1C2SPfzh9tIe9++jwZ8hj8lIsfsYpJ+h6N0GGqxADYg7LtkD81wUIb6J9iJMtIQORuUQ1NPr4pw3v0ho2bYmfrabgncfyHqjW5wOFwsdh6dAFGFWAyob3aMJK8rieZfWT1bzmkiSw== 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=RqZzTE5IDNzLeiEeh0gtmEhR+vjHmPP5GDL6eBo8e3g=; b=k5xTDQqQKRzTqf09CUZOo3tWiXzFWmVv6HrsphD7lX++WnWD3mFvwzdZuNC4NN1t0PDt+0DnyqxgeypD2Wx7+hCMgm4OEXAAS1qtwkfheGAfD6KC5viMdS0/+3BLMsvlpX4hYHPV5OD+v9vaJyYNYMlIIqrvD+pldHGOUoy/Scc= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:52:30 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:52:30 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 04/24] wfx: add wfx.h Date: Wed, 4 Nov 2020 16:51:47 +0100 Message-Id: <20201104155207.128076-5-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:52:28 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 7ccbe006-9698-4641-046a-08d880d9a319 X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:773; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 0EqOFdNV57tC2chAktkH9xgxrYlhl8KA45kkMdwIDrttojIp8rLKcFCcL54+caEDoYFWOXUm3mCVcQXpSnPL+x5GVN9cQyQ6xRSzuDKz2Li3ilA3xM2lcrWPMXVam7MbXidaSYw3ILc0Mxr0TBGmRxnlqJ1Y7OrAu7YZ5T1LYTRxFvSBvyDGuhhc0BBRb+DnNirflXq7UtKd7nRuIP2lY5k/jVJC8zHIqUw4Xm6CFrkHGoS9+1q4Gu/C12w08LqD8Mi5fNVYkgt+x+2KQcyjt6sINxttYXQjqgGoT/hbW+26o7kPr3M4mwn8di6s8kzz1i0gxG1v5RXq3PHzinsTAw== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(6666004)(83380400001)(26005)(54906003)(107886003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: niaEZNHaAlb2+hWr39boGlhA8GhTpmKp1eZwKeASDWhIKduNexhAM7oc8udrNcw8NQp75obtbT2prpDsNprYimWW/BXUnhTm+ZtZ4mXcZ50D5zUiO6IDa+V19wG+KRo2Avrs7ArNFJwoyIj2FjN8+HjH2WfJ0mw/jWcA8PvNLJLGoowCoDVYccbK2icsSjbNH88VuAzrn4DM3NSrBWqH9U6yUi+W2gtfrus3pUUm9/w5Zq4k3tLC2EJekEOjU3Gwh7ufT3gEDX7x+R5NSWZx9Bs/Qw5p+qetU7sCg71Q4dOnA8EJU33yQL4YTEWtDv2aJVFLbcziBaZ+xrW6pUUffxupuW6J6NGjsMy25HR9IL1A2LV7zI2HZ7Q5u/OR9/pT5tAbBLWkNnmZFIQC3WYDoKk+6DGSW8lS5xX2Y+wPFm1/FxWYQU7kB1HmzO6k0RiA0noQzBUuBlm+yS7R05p4DZF273qor3O+vn71fBUHTlHwiLjYHNeaILMpX8P33MSwGlLia32d04t68zTGBHmboIZHZkSYy2iW2TDMVnjgd1uT5t7mtsKUIrPC/96q6HJ6PKrszPD8uFYCQyW1kIq22l2rIEa/LzSqD24WK376wAirwRfFzKe3SgHp8AlxvD6DMvQM9vdljpZzjxOTRZ+8OQ== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 7ccbe006-9698-4641-046a-08d880d9a319 X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:52:30.7628 (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: JHwR/jmY+tDIlLU2x8pUVvtwEW8B6v2EgDq20KNvgfiUSfRva5Cb6i/yBdJY9hDjItlMOJLoeuba/q0RsbVOyw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/wfx.h | 166 ++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/wfx.h diff --git a/drivers/net/wireless/silabs/wfx/wfx.h b/drivers/net/wireless/silabs/wfx/wfx.h new file mode 100644 index 000000000000..94898680ccde --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/wfx.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Common private data for Silicon Labs WFx chips. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (c) 2006, Michael Wu + * Copyright 2004-2006 Jean-Baptiste Note , et al. + */ +#ifndef WFX_H +#define WFX_H + +#include +#include +#include +#include +#include + +#include "bh.h" +#include "data_tx.h" +#include "main.h" +#include "queue.h" +#include "hif_tx.h" + +#define USEC_PER_TXOP 32 // see struct ieee80211_tx_queue_params +#define USEC_PER_TU 1024 + +struct hwbus_ops; + +struct wfx_dev { + struct wfx_platform_data pdata; + struct device *dev; + struct ieee80211_hw *hw; + struct ieee80211_vif *vif[2]; + struct mac_address addresses[2]; + const struct hwbus_ops *hwbus_ops; + void *hwbus_priv; + + u8 keyset; + struct completion firmware_ready; + struct hif_ind_startup hw_caps; + struct wfx_hif hif; + struct delayed_work cooling_timeout_work; + bool poll_irq; + bool chip_frozen; + struct mutex conf_mutex; + + struct wfx_hif_cmd hif_cmd; + struct sk_buff_head tx_pending; + wait_queue_head_t tx_dequeue; + atomic_t tx_lock; + + atomic_t packet_id; + u32 key_map; + + struct hif_rx_stats rx_stats; + struct mutex rx_stats_lock; + struct hif_tx_power_loop_info tx_power_loop_info; + struct mutex tx_power_loop_info_lock; + int force_ps_timeout; +}; + +struct wfx_vif { + struct wfx_dev *wdev; + struct ieee80211_vif *vif; + struct ieee80211_channel *channel; + int id; + + u32 link_id_map; + + bool after_dtim_tx_allowed; + bool join_in_progress; + + struct delayed_work beacon_loss_work; + + struct wfx_queue tx_queue[4]; + struct tx_policy_cache tx_policy_cache; + struct work_struct tx_policy_upload_work; + + struct work_struct update_tim_work; + + unsigned long uapsd_mask; + + /* avoid some operations in parallel with scan */ + struct mutex scan_lock; + struct work_struct scan_work; + struct completion scan_complete; + bool scan_abort; + struct ieee80211_scan_request *scan_req; + + struct completion set_pm_mode_complete; +}; + +static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id) +{ + if (vif_id >= ARRAY_SIZE(wdev->vif)) { + dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id); + return NULL; + } + vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif)); + if (!wdev->vif[vif_id]) { + dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n", + vif_id); + return NULL; + } + return (struct wfx_vif *) wdev->vif[vif_id]->drv_priv; +} + +static inline struct wfx_vif *wvif_iterate(struct wfx_dev *wdev, + struct wfx_vif *cur) +{ + int i; + int mark = 0; + struct wfx_vif *tmp; + + if (!cur) + mark = 1; + for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { + tmp = wdev_to_wvif(wdev, i); + if (mark && tmp) + return tmp; + if (tmp == cur) + mark = 1; + } + return NULL; +} + +static inline int wvif_count(struct wfx_dev *wdev) +{ + int i; + int ret = 0; + struct wfx_vif *wvif; + + for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { + wvif = wdev_to_wvif(wdev, i); + if (wvif) + ret++; + } + return ret; +} + +static inline void memreverse(u8 *src, u8 length) +{ + u8 *lo = src; + u8 *hi = src + length - 1; + u8 swap; + + while (lo < hi) { + swap = *lo; + *lo++ = *hi; + *hi-- = swap; + } +} + +static inline int memzcmp(void *src, unsigned int size) +{ + u8 *buf = src; + + if (!size) + return 0; + if (*buf) + return 1; + return memcmp(buf, buf + 1, size - 1); +} + +#endif /* WFX_H */ From patchwork Wed Nov 4 15:51:49 2020 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: 318384 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 4E580C2D0A3 for ; Wed, 4 Nov 2020 15:56:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EF67C22280 for ; Wed, 4 Nov 2020 15:56:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="S9QWxj1X" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731006AbgKDPwx (ORCPT ); Wed, 4 Nov 2020 10:52:53 -0500 Received: from mail-dm6nam11on2049.outbound.protection.outlook.com ([40.107.223.49]:54240 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730968AbgKDPwu (ORCPT ); Wed, 4 Nov 2020 10:52:50 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=JfWtwCOj2zowsK7OAdtjdinK+3UYpuphK1yRgzZbjvDTBkwbioM8ksItootBOIjtCG46i6cDAH6rulJ5mYVBDwYKnZtKy4rW3qYnPo6MSSE2aJRXyXczo7FYYEUxuQfxD4xZl1cPQeyVCO9U5WA6GWQ4/IBqGPdfUZSfDZHotsNCJAwIocK28pyNUp0Z/rLG6CqB+YEZHp2N3OZdsEhEMc9L2Bh0t+wlAdRKsEEtgGmlDUy4bkTFk5b2UbNrCcS1C27k01u1VhhAbFMlxLGosjiMCruimXdvOutTd2TEZaboneRkyYjfgZgZujFnztQR5fqtZ/65/ZhmUhxutwrBCA== 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-SenderADCheck; bh=sj+FvaSzNUL70rljsFsFSy63ayCemnk7bCXXALwJfCM=; b=A08+8mPSB7gt6qLgBzL41XN4HiY26PE3e1sIdDR3goyajd5o9ZebNfo+HXzdOeUlxwXdtkkn7tzUfwLBtyc5hku26UIgFeI1tse8TRmH0N0z4efNHkIP+LBfmgWDc7447ddTuuj6dyeByX7Ui543W1e/KVuloLezQbXFXXh0fK0OX7mWz9LmcQ/6fOp1CmtiodEolaHr3E291YIRVs+whg8SeEDfRq8vy0biiRj3aT2oVrMbIUFLefk2GhPPYL0vJmJ0IXIpkWD0JMABWB0jWgkodlZyOVwvQ0sMkAhnEqIMN75TAIvBA8TtFEvibtkmAAmSWg1+5LFJnS6aOn7mow== 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=sj+FvaSzNUL70rljsFsFSy63ayCemnk7bCXXALwJfCM=; b=S9QWxj1XaV4kZsTR3MT8jyaTRhx5FHsHIEUZYPQmHPCTDT8VOeguncloqakcYnqSQWB5gIU4GVrAD/g5FP4mKlxyl5XXMI7qLoDLiGE4N0jNotB6Xv4UVqhnzlC+sKn7Gel7LUikCR3FycrQtG6pr+h6rxloiwyfg+GIpFms2q4= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:52:35 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:52:35 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 06/24] wfx: add bus.h Date: Wed, 4 Nov 2020 16:51:49 +0100 Message-Id: <20201104155207.128076-7-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:52:33 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 21f4aa8b-acf7-4b94-28e2-08d880d9a5dc X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:421; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: guQPnc13TVkt1jEH8uZDxPqh0uQCjDoLRnd98SFgUAyLOhZICYvveyBKrPpsELsoafaTSvD2Ot1Rq6pbhBZ8UyKWKB3ArgW27/CM2EqAq8/maiUatpS4O17Y+Jowlh37BCDLnQriyvPX2DG4TmR8IQU18D12pmNeJEcSLLxpduBiB8ADt1nWXmwSqZVIV0bWINsfgwEI9yS4fULw8ZWiUwxRuHoj0bbW3JfRK/24DT3+n0U4u7+bLemNv0CNj+gCAgV5vJrXtsIbMvuSePBoCjaJsGD3xMZ2nxr9009GTJMwACZZsbW57JqS5dTEt9R8 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(6666004)(83380400001)(26005)(54906003)(107886003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: NzWtIhBtHBMXCr0DfxFFvVTI0jhdmyICA+vacrOKByjlxxu1zY/KGXCg4HI4wxxqpd/qEEDcCW9g0nNWzECySTUnGvWDFk+9jjvQzqKQkibFrcJbgQViOgn8imp/FBCSbO+LYd65calIytdvzM1Yorm3Hv29Jzua6dvQaQPrSBdW3uE4+k4zGU+/FQLMNFLyMuvSb4v5DMGEg7l0JLttn3O94FMTlPaVnLU99YHFybFs5g9x1EIy1zRAoiQiscYc0+jnALuVxhnEYqFR8Ud5zKlhIqKz94G9Pf3gBdpH+uRh+3EekQed/ZfGHh0Qvj8I3MKjf8xmmq57rlOOeLpu819p41ONYpWB/ZgJRnlsiegDH+y/YGfr96DlLX7X/OWzFqW59s23tXT/yZmDdnDRyiTe03/1fgw3N7bJUMysBs5Q9KY1wXCvbOPHcig3CEZfxAK9nWXPKGYR1ZpO91QbtqK55FQQxecLuNzknHoMcJzPlxDPv9F9qtpAZ/tDm4snuZD7lEDzlCCnFQl9OdilTdcjgmVw62z0ydLLzjmTgPyY9E3zJqtnvmb+pXZ0KVhxCdnsgpafX7QUfcqL+DBkKKJPHwIBYP0fz0iJFuSrNda956ob++0Ln+OnXCZAttz9N40MRPxLePtNQmQofvxJPg== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 21f4aa8b-acf7-4b94-28e2-08d880d9a5dc X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:52:35.4621 (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: eA55/wyzM/SiyRMkEHFf2y+h2t/AFJQ3iz7LVAy28+2Uu/a2rVfXPheo61i4CuJO+UW4CtMuMYgekUB5rhbwrA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/bus.h | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/bus.h diff --git a/drivers/net/wireless/silabs/wfx/bus.h b/drivers/net/wireless/silabs/wfx/bus.h new file mode 100644 index 000000000000..ca04b3da6204 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/bus.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Common bus abstraction layer. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_BUS_H +#define WFX_BUS_H + +#include +#include + +#define WFX_REG_CONFIG 0x0 +#define WFX_REG_CONTROL 0x1 +#define WFX_REG_IN_OUT_QUEUE 0x2 +#define WFX_REG_AHB_DPORT 0x3 +#define WFX_REG_BASE_ADDR 0x4 +#define WFX_REG_SRAM_DPORT 0x5 +#define WFX_REG_SET_GEN_R_W 0x6 +#define WFX_REG_FRAME_OUT 0x7 + +struct hwbus_ops { + int (*copy_from_io)(void *bus_priv, unsigned int addr, + void *dst, size_t count); + int (*copy_to_io)(void *bus_priv, unsigned int addr, + const void *src, size_t count); + int (*irq_subscribe)(void *bus_priv); + int (*irq_unsubscribe)(void *bus_priv); + void (*lock)(void *bus_priv); + void (*unlock)(void *bus_priv); + size_t (*align_size)(void *bus_priv, size_t size); +}; + +extern struct sdio_driver wfx_sdio_driver; +extern struct spi_driver wfx_spi_driver; + +#endif From patchwork Wed Nov 4 15:51:52 2020 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: 318385 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 BAAADC5517A for ; Wed, 4 Nov 2020 15:56:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 564222236F for ; Wed, 4 Nov 2020 15:56:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="JwEMTiTD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731072AbgKDPxC (ORCPT ); Wed, 4 Nov 2020 10:53:02 -0500 Received: from mail-dm6nam11on2049.outbound.protection.outlook.com ([40.107.223.49]:54240 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1731031AbgKDPxB (ORCPT ); Wed, 4 Nov 2020 10:53:01 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=aaf19moLErh5asryNBae6ve5iviAqrVyfb9VL3AA/P/pC0MRSUpzC1O6ADFNKNyCdzx4It8Bjd/WwKXE9XNDSiMBFkxlzXs1a5GWLtKZ1LtZK1sSLDAJ4Jw24MxMc5tGtnkEKejZ5IIrP6865bUq0L0INUHAUHIxV17STn2ekE7beblkcYh/fPVzBWdyt+HC3MTISp+ssUBwLDFDv2HkGcW4iGd8JW8E67NOlxczoi6qndCIglwDABbsCriovaMnsjUnMU/wnIzOounkwsplJfIa3DnHD2Ko11U0719Ct8P46cWbse3sYOrVVDfofH2dm3t8ctV8c0ma6zZUS7o+0A== 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-SenderADCheck; bh=avmXx+dXA4M7vEFGc5mUuiRWmSiPmhrFJykm4WmwTBM=; b=kYenpFZqzsPOMJDLhkDHEjsjU6i1jpq0DEH1qcpLDo9ERp+8oC+pCBomNCd3grssP98LSbmsN20TbuNZYdxFArZGlcKyFQxEbQNvt33jeXVJyMjo+oHoP1gSr53Wwu+ZJNAI+iM6qDSQHNijY8IVJiC6cSV23MDjKc1hlOfJ5Ad3eVcstXu2Efa2Pa1iRlZzV5dnF02UtDj+/v2EwU0PNi5GZE4lFy6O30To/a7RDOeZuol0AZRY6365bnl9dII1SI5EnkXKarNgBoW8jFGx2bQ5HysKAI5+mT2wS6WdMVnv+TCdwVUA++xvXe1nhDcrQXtT3KQFR78f98vttP9gnw== 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=avmXx+dXA4M7vEFGc5mUuiRWmSiPmhrFJykm4WmwTBM=; b=JwEMTiTDeGI3Z3JtKcuQF269Ord0+5ZjlVoDmbKNFn15UOp/zKSezZQL8JXE+5XWVW8vCtM4ofgDwhg8z3OYBeWKl19ZQg9lpPSRQuqDMilpWcerfx+Zx3DQ0tvIVwHQIrVU/qfKRGjedOLTyxCdoaMeg9SOH0a+eGKI6o6j678= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:52:42 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:52:42 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 09/24] wfx: add hwio.c/hwio.h Date: Wed, 4 Nov 2020 16:51:52 +0100 Message-Id: <20201104155207.128076-10-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:52:40 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 3db5ea44-a324-4614-1f39-08d880d9a9f6 X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:483; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 9fRS/JW448mI2nRjilUajIp/lnFKHoB9GDg0tPLRQpPKHPm4Xrawt+61GzKP21Ygfz5zxvtxvJhNp+mscKo0sxtMvf4pGO+V7YT+vJtxGokc7Ki5Q+doycNZ5vXunZfF0EWDuq9H9nZU6vTHOPtPWt4rou8Zh+R4yRAFvno/bie1IbOKqUiTb8utY4i8vzQDXH05JSbFt/r3Q65m0Qk25MCO4/3WfGlAKncDVj//Dujkz+cXWFy5twkj76XVRVeX1gSwoxsqYAkVW8VA17Uteo7Fp0c96QVnOR6Tenzr6imuR1aVw8ORUggUoSdyJigGQ+aUfy9tm0OoNO6wBeb5yg== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(6666004)(83380400001)(26005)(54906003)(107886003)(30864003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: SYhG2QejhSGBKZZ9/vISgmWGeEMt1DQcV22A1n2g24dsq7GqNLHNnEtpcJ6OJ1IQJGQ2Uua0+h3ghhH1IrcUCZ4nAw+OpSy/PfMHXDzxc2XCKS04piKfKUV8kaqvbxa+ZpfDzkd1YMp42XxZ97Pl3jpUA/Y3NWulL5NTOJYc7IqLpZRo/nBHfZKo5JeCBUre3WXFYfaY10qXM3SPoOSxGfqEc2K57BUeEuV0z7HrLJhICzXhHED0x13tCS6sPgDqYUrLPFLfldwsyAfbVTl+O2YFeWwS2NiifU/L9YByBek97KzaW3zW2X1sbdST5Tz/ndnhT+/vBW2HdMC2OqAnjJXHjZlA+PAvgrkekl+t5PLMSJgRJn1EwfVO3brEr1p5xXJnJR9WhtDTOGMdyWgYT/Q5dqt3VHtll7TJdwUYCd/BUecHsedchy1uLxrKcPWwAtMIzYkQ6dd8bVD4pTkbmWuBAMKnTS5LuPIHV1LJxdXLUB7hBg/L3wlLHTxA+o7Nu9xAMwtNXzkHezyN7m323bPCoCs/d7k2NxFryckNQb7N1iMSTWWll/4uwvWFAAyex/CEmWfgIRrCju+nlcnmxb/gUT167Q22bkp8aWK63M4oJXGTa9FATHoz1fUArF/Yz+Ajo5Tgn0pxd53QaF2uDg== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3db5ea44-a324-4614-1f39-08d880d9a9f6 X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:52:42.2811 (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: aU6I/RYCIHy/e70AtFvUr3SI65/41zw9Fd+mvERC3kXiOvOYmVquMtetJwhWfp771a+PY6PJ6pfTQM/6GwZQpA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/hwio.c | 352 +++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/hwio.h | 75 ++++++ 2 files changed, 427 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/hwio.c create mode 100644 drivers/net/wireless/silabs/wfx/hwio.h diff --git a/drivers/net/wireless/silabs/wfx/hwio.c b/drivers/net/wireless/silabs/wfx/hwio.c new file mode 100644 index 000000000000..36fbc5b5d64c --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hwio.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Low-level I/O functions. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include +#include + +#include "hwio.h" +#include "wfx.h" +#include "bus.h" +#include "traces.h" + +/* + * Internal helpers. + * + * About CONFIG_VMAP_STACK: + * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack + * allocated data. Functions below that work with registers (aka functions + * ending with "32") automatically reallocate buffers with kmalloc. However, + * functions that work with arbitrary length buffers let's caller to handle + * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located + * buffer. + */ + +static int read32(struct wfx_dev *wdev, int reg, u32 *val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + *val = ~0; // Never return undefined value + if (!tmp) + return -ENOMEM; + ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, + sizeof(u32)); + if (ret >= 0) + *val = le32_to_cpu(*tmp); + kfree(tmp); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", + __func__, ret); + return ret; +} + +static int write32(struct wfx_dev *wdev, int reg, u32 val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + *tmp = cpu_to_le32(val); + ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, + sizeof(u32)); + kfree(tmp); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", + __func__, ret); + return ret; +} + +static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = read32(wdev, reg, val); + _trace_io_read32(reg, *val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int write32_locked(struct wfx_dev *wdev, int reg, u32 val) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = write32(wdev, reg, val); + _trace_io_write32(reg, val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val) +{ + int ret; + u32 val_r, val_w; + + WARN_ON(~mask & val); + val &= mask; + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = read32(wdev, reg, &val_r); + _trace_io_read32(reg, val_r); + if (ret < 0) + goto err; + val_w = (val_r & ~mask) | val; + if (val_w != val_r) { + ret = write32(wdev, reg, val_w); + _trace_io_write32(reg, val_w); + } +err: + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, + void *buf, size_t len) +{ + int ret; + int i; + u32 cfg; + u32 prefetch; + + WARN_ON(len >= 0x2000); + WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); + + if (reg == WFX_REG_AHB_DPORT) + prefetch = CFG_PREFETCH_AHB; + else if (reg == WFX_REG_SRAM_DPORT) + prefetch = CFG_PREFETCH_SRAM; + else + return -ENODEV; + + ret = write32(wdev, WFX_REG_BASE_ADDR, addr); + if (ret < 0) + goto err; + + ret = read32(wdev, WFX_REG_CONFIG, &cfg); + if (ret < 0) + goto err; + + ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch); + if (ret < 0) + goto err; + + for (i = 0; i < 20; i++) { + ret = read32(wdev, WFX_REG_CONFIG, &cfg); + if (ret < 0) + goto err; + if (!(cfg & prefetch)) + break; + usleep_range(200, 250); + } + if (i == 20) { + ret = -ETIMEDOUT; + goto err; + } + + ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len); + +err: + if (ret < 0) + memset(buf, 0xFF, len); // Never return undefined value + return ret; +} + +static int indirect_write(struct wfx_dev *wdev, int reg, u32 addr, + const void *buf, size_t len) +{ + int ret; + + WARN_ON(len >= 0x2000); + WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); + ret = write32(wdev, WFX_REG_BASE_ADDR, addr); + if (ret < 0) + return ret; + + return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len); +} + +static int indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr, + void *buf, size_t len) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_read(wdev, reg, addr, buf, len); + _trace_io_ind_read(reg, addr, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr, + const void *buf, size_t len) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_write(wdev, reg, addr, buf, len); + _trace_io_ind_write(reg, addr, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int indirect_read32_locked(struct wfx_dev *wdev, int reg, + u32 addr, u32 *val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32)); + *val = le32_to_cpu(*tmp); + _trace_io_ind_read32(reg, addr, *val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + kfree(tmp); + return ret; +} + +static int indirect_write32_locked(struct wfx_dev *wdev, int reg, + u32 addr, u32 val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + *tmp = cpu_to_le32(val); + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32)); + _trace_io_ind_write32(reg, addr, val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + kfree(tmp); + return ret; +} + +int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len) +{ + int ret; + + WARN((long)buf & 3, "%s: unaligned buffer", __func__); + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, + WFX_REG_IN_OUT_QUEUE, buf, len); + _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", + __func__, ret); + return ret; +} + +int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len) +{ + int ret; + + WARN((long)buf & 3, "%s: unaligned buffer", __func__); + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, + WFX_REG_IN_OUT_QUEUE, buf, len); + _trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", + __func__, ret); + return ret; +} + +int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) +{ + return indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); +} + +int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) +{ + return indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); +} + +int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) +{ + return indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); +} + +int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) +{ + return indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); +} + +int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) +{ + return indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); +} + +int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) +{ + return indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); +} + +int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) +{ + return indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); +} + +int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) +{ + return indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); +} + +int config_reg_read(struct wfx_dev *wdev, u32 *val) +{ + return read32_locked(wdev, WFX_REG_CONFIG, val); +} + +int config_reg_write(struct wfx_dev *wdev, u32 val) +{ + return write32_locked(wdev, WFX_REG_CONFIG, val); +} + +int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) +{ + return write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val); +} + +int control_reg_read(struct wfx_dev *wdev, u32 *val) +{ + return read32_locked(wdev, WFX_REG_CONTROL, val); +} + +int control_reg_write(struct wfx_dev *wdev, u32 val) +{ + return write32_locked(wdev, WFX_REG_CONTROL, val); +} + +int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) +{ + return write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val); +} + +int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val) +{ + int ret; + + *val = ~0; // Never return undefined value + ret = write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24); + if (ret) + return ret; + ret = read32_locked(wdev, WFX_REG_SET_GEN_R_W, val); + if (ret) + return ret; + *val &= IGPR_VALUE; + return ret; +} + +int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val) +{ + return write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val); +} diff --git a/drivers/net/wireless/silabs/wfx/hwio.h b/drivers/net/wireless/silabs/wfx/hwio.h new file mode 100644 index 000000000000..0b8e4f7157df --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hwio.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Low-level API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_HWIO_H +#define WFX_HWIO_H + +#include + +struct wfx_dev; + +int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t buf_len); +int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t buf_len); + +int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); +int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); + +int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); +int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); + +int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); +int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); + +int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); +int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); + +#define CFG_ERR_SPI_FRAME 0x00000001 // only with SPI +#define CFG_ERR_SDIO_BUF_MISMATCH 0x00000001 // only with SDIO +#define CFG_ERR_BUF_UNDERRUN 0x00000002 +#define CFG_ERR_DATA_IN_TOO_LARGE 0x00000004 +#define CFG_ERR_HOST_NO_OUT_QUEUE 0x00000008 +#define CFG_ERR_BUF_OVERRUN 0x00000010 +#define CFG_ERR_DATA_OUT_TOO_LARGE 0x00000020 +#define CFG_ERR_HOST_NO_IN_QUEUE 0x00000040 +#define CFG_ERR_HOST_CRC_MISS 0x00000080 // only with SDIO +#define CFG_SPI_IGNORE_CS 0x00000080 // only with SPI +#define CFG_BYTE_ORDER_MASK 0x00000300 // only writable with SPI +#define CFG_BYTE_ORDER_BADC 0x00000000 +#define CFG_BYTE_ORDER_DCBA 0x00000100 +#define CFG_BYTE_ORDER_ABCD 0x00000200 // SDIO always use this value +#define CFG_DIRECT_ACCESS_MODE 0x00000400 +#define CFG_PREFETCH_AHB 0x00000800 +#define CFG_DISABLE_CPU_CLK 0x00001000 +#define CFG_PREFETCH_SRAM 0x00002000 +#define CFG_CPU_RESET 0x00004000 +#define CFG_SDIO_DISABLE_IRQ 0x00008000 // only with SDIO +#define CFG_IRQ_ENABLE_DATA 0x00010000 +#define CFG_IRQ_ENABLE_WRDY 0x00020000 +#define CFG_CLK_RISE_EDGE 0x00040000 +#define CFG_SDIO_DISABLE_CRC_CHK 0x00080000 // only with SDIO +#define CFG_RESERVED 0x00F00000 +#define CFG_DEVICE_ID_MAJOR 0x07000000 +#define CFG_DEVICE_ID_RESERVED 0x78000000 +#define CFG_DEVICE_ID_TYPE 0x80000000 +int config_reg_read(struct wfx_dev *wdev, u32 *val); +int config_reg_write(struct wfx_dev *wdev, u32 val); +int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); + +#define CTRL_NEXT_LEN_MASK 0x00000FFF +#define CTRL_WLAN_WAKEUP 0x00001000 +#define CTRL_WLAN_READY 0x00002000 +int control_reg_read(struct wfx_dev *wdev, u32 *val); +int control_reg_write(struct wfx_dev *wdev, u32 val); +int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); + +#define IGPR_RW 0x80000000 +#define IGPR_INDEX 0x7F000000 +#define IGPR_VALUE 0x00FFFFFF +int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val); +int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val); + +#endif /* WFX_HWIO_H */ From patchwork Wed Nov 4 15:51:57 2020 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: 318386 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 F216AC56201 for ; Wed, 4 Nov 2020 15:55:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8A85A2236F for ; Wed, 4 Nov 2020 15:55:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="pannGhmE" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731017AbgKDPzg (ORCPT ); Wed, 4 Nov 2020 10:55:36 -0500 Received: from mail-dm6nam11on2049.outbound.protection.outlook.com ([40.107.223.49]:54240 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730625AbgKDPxY (ORCPT ); Wed, 4 Nov 2020 10:53:24 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=IDrQB11Hkg9NY5t1mQmXJTpclxzAivzfPIVHpXdBsUwqDBE8KtMA8nfHdsaczJZDo6iEpAHUhV49tHErcEAOvsUAjm//xj9bD89KePFH2cihvxMaPs6ELelHCsrOWWZ4SU3BfZWMB4SfSxveKXUtUVzsf5Kqy42gnXFenDvdE32V7T5JPTXxdEcH/eHKkwcGXHlM/2V4wCWtpxzoLi4INBM7/49H+F0CT0wuVjkl5ibq/o7MiDpxJ5axFo74Oai69rVCI2ywacyySQn/eMMm6Rf8p3IFiGhm/HrQ9qLDDnaM1+2pwRfJXRcj0c+YzTDgJAUn8+cD9Y9BTH8DtwxJnQ== 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-SenderADCheck; bh=WUnsoPoplvHUt9Xza9j1HavLwuWmOnSVnZZ+2HeiqCQ=; b=kqO+2KeGFx3kCuO1EkMl+9/4Hk2Juwygs2ucK9KwT6SsQOyJOkTrykz6jBwAUObiy3Tuk3ekx9zq0iUnq2Y+/BTCdXNsjZN0yasniPwCCq4/JMoSGmXoOKLKJguUzWxkDfu3Ggyu782izsKoxxbnDUfRd4TqF1LsVLcx1ppz4a5qFJINjV4el5diFVI4LesiuhEx3sXqzduVgV+rKK3VOUz4YZ36qj0NYqtRAi25gTztywmEeX5ba6NlZcvnp6kEXvqaxB52ksPDn02Qk+6Idek7BYlEQdPKRFKekzjQjp0GyN0O7gTXxXRhtMwI4BCCbfM+2HQHm1gV7kDBTdCqhw== 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=WUnsoPoplvHUt9Xza9j1HavLwuWmOnSVnZZ+2HeiqCQ=; b=pannGhmEpIbKU17rAkHqD6eDnZ0Luci6qb4bo906TxggxCn82r4Li71uHvbQS8gcYvkJjP2AacUBPH4oWZ9EVGzm1XWUIYm+IeSeCRRD7IcnYUarjBOL3ExvPjjxox/uwjaaTL+RaSo68jQ01t/ZziYaCVU4ii2z7n3nAnAdwN0= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:52:53 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:52:53 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 14/24] wfx: add key.c/key.h Date: Wed, 4 Nov 2020 16:51:57 +0100 Message-Id: <20201104155207.128076-15-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:52:51 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 01836fe3-0f84-406b-0f0a-08d880d9b0cc X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:376; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: F9jtMQkhAur1+BSY/dBgn+NpCFATHGYq8LqYzcuANYQqQE3Nkq3aCH8kGWPvR2h0hpJ+btnc1NmDJfn+OKjzaptEuNKLaM/Vv3Bsim8+G8aelq7Xg4Zv78H5cPt5El3yXY/llnRjpPdWgd1vYt/soXvShe/wCOYYU7RAxF3R7Yc6G+/btEi7hhD5B3wLEC2xO6nw6enf8OuMTbusivTtuKE6cuCEkqVOJUXEJ6Jbq2u5wNNbhn6XHBkGL31ET+OMYjkGt4ksZT464MnCheEdEk282xIOKKYAwQVP3UCusZPfBzKecUljiILJA3XoeG8j3FYIZy4aJELENNTl3JXncA== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(83380400001)(26005)(54906003)(107886003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: V7cvX3SG5seAYrg+HDJ4FYJYg4KTWblsYrHQlhSFYawesQbV5Xx7EWufbE89eFAuxlzB6sjyAyv/zdltRhYcmV2p71UFdVw0mqXDSBuFIc3kLySWM1OhZ7jIYaifT53UDyoCzWUQdczXMOwJbYQqNhdx1Eto72kECqgOkiI187PSTiS+1v58JnuTwYEwtS1jztykv+hUirLSeocoleWL+G50DnitvfEWud9x3gCk4DbP3clXYCwgXfX+5LyOm0fkZFKeZhHS9YjEEnClTtSkNCzLt7s7kpPwi4d3GaGb5tkQYq1x8TwDFb6VZtmiAwJj6hESzSAwkW7gKCmik0oGhnF47A2ujJfHpZXXZbMO5LaehQmbLEsBJgRpS7V/WiEsEyRlEOmdGCsXKUjGWDYPMwa6HfDMwfCxMMM2EJ3j3I5BkcnlV46tc4l4oaxvCE4FxjrAt/0lckRYUFzFdSEkK1DPpHWZlATKRsYfM3gc0oW+3w7KvH5JCRC0blmOsCh6J9lB8bGeWGKuiEugWIJYC8z+a0FtxYg/w9/3uYWBnomCp/tTrsu6umn40k+d7+JKPsptedbv/mNpNlY+3HdIJMRxGUgTpV7C4ZlSH4o+UO/o9X8isdGBHbFQ/9kcRjl7vSb6FSI31YeCLfJ8h/6fTg== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 01836fe3-0f84-406b-0f0a-08d880d9b0cc X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:52:53.7655 (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: mKJQtg80jeVdc5/lBGYgM94cmwDlHBPrKKG+kZ6XXfT1xonXcXqippQTpff8QvRw6ZmmLJvtBcRcoVjSV7l6kQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/key.c | 241 ++++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/key.h | 20 +++ 2 files changed, 261 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/key.c create mode 100644 drivers/net/wireless/silabs/wfx/key.h diff --git a/drivers/net/wireless/silabs/wfx/key.c b/drivers/net/wireless/silabs/wfx/key.c new file mode 100644 index 000000000000..2ab82bed4c1b --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/key.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Key management related functions. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "key.h" +#include "wfx.h" +#include "hif_tx_mib.h" + +static int wfx_alloc_key(struct wfx_dev *wdev) +{ + int idx; + + idx = ffs(~wdev->key_map) - 1; + if (idx < 0 || idx >= MAX_KEY_ENTRIES) + return -1; + + wdev->key_map |= BIT(idx); + return idx; +} + +static void wfx_free_key(struct wfx_dev *wdev, int idx) +{ + WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation"); + wdev->key_map &= ~BIT(idx); +} + +static u8 fill_wep_pair(struct hif_wep_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); + msg->key_length = key->keylen; + memcpy(msg->key_data, key->key, key->keylen); + ether_addr_copy(msg->peer_address, peer_addr); + return HIF_KEY_TYPE_WEP_PAIRWISE; +} + +static u8 fill_wep_group(struct hif_wep_group_key *msg, + struct ieee80211_key_conf *key) +{ + WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); + msg->key_id = key->keyidx; + msg->key_length = key->keylen; + memcpy(msg->key_data, key->key, key->keylen); + return HIF_KEY_TYPE_WEP_DEFAULT; +} + +static u8 fill_tkip_pair(struct hif_tkip_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + u8 *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->tkip_key_data) + + sizeof(msg->tx_mic_key) + + sizeof(msg->rx_mic_key), "inconsistent data"); + memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); + keybuf += sizeof(msg->tkip_key_data); + memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key)); + keybuf += sizeof(msg->tx_mic_key); + memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key)); + ether_addr_copy(msg->peer_address, peer_addr); + return HIF_KEY_TYPE_TKIP_PAIRWISE; +} + +static u8 fill_tkip_group(struct hif_tkip_group_key *msg, + struct ieee80211_key_conf *key, + struct ieee80211_key_seq *seq, + enum nl80211_iftype iftype) +{ + u8 *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->tkip_key_data) + + 2 * sizeof(msg->rx_mic_key), "inconsistent data"); + msg->key_id = key->keyidx; + memcpy(msg->rx_sequence_counter, + &seq->tkip.iv16, sizeof(seq->tkip.iv16)); + memcpy(msg->rx_sequence_counter + sizeof(u16), + &seq->tkip.iv32, sizeof(seq->tkip.iv32)); + memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); + keybuf += sizeof(msg->tkip_key_data); + if (iftype == NL80211_IFTYPE_AP) + // Use Tx MIC Key + memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key)); + else + // Use Rx MIC Key + memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key)); + return HIF_KEY_TYPE_TKIP_GROUP; +} + +static u8 fill_ccmp_pair(struct hif_aes_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); + ether_addr_copy(msg->peer_address, peer_addr); + memcpy(msg->aes_key_data, key->key, key->keylen); + return HIF_KEY_TYPE_AES_PAIRWISE; +} + +static u8 fill_ccmp_group(struct hif_aes_group_key *msg, + struct ieee80211_key_conf *key, + struct ieee80211_key_seq *seq) +{ + WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); + memcpy(msg->aes_key_data, key->key, key->keylen); + memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn)); + memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_AES_GROUP; +} + +static u8 fill_sms4_pair(struct hif_wapi_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + u8 *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->wapi_key_data) + + sizeof(msg->mic_key_data), "inconsistent data"); + ether_addr_copy(msg->peer_address, peer_addr); + memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); + keybuf += sizeof(msg->wapi_key_data); + memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_WAPI_PAIRWISE; +} + +static u8 fill_sms4_group(struct hif_wapi_group_key *msg, + struct ieee80211_key_conf *key) +{ + u8 *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->wapi_key_data) + + sizeof(msg->mic_key_data), "inconsistent data"); + memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); + keybuf += sizeof(msg->wapi_key_data); + memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_WAPI_GROUP; +} + +static u8 fill_aes_cmac_group(struct hif_igtk_group_key *msg, + struct ieee80211_key_conf *key, + struct ieee80211_key_seq *seq) +{ + WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data"); + memcpy(msg->igtk_key_data, key->key, key->keylen); + memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn)); + memreverse(msg->ipn, sizeof(seq->aes_cmac.pn)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_IGTK_GROUP; +} + +static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + int ret; + struct hif_req_add_key k = { }; + struct ieee80211_key_seq seq; + struct wfx_dev *wdev = wvif->wdev; + int idx = wfx_alloc_key(wvif->wdev); + bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE; + + WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data"); + ieee80211_get_key_rx_seq(key, 0, &seq); + if (idx < 0) + return -EINVAL; + k.int_id = wvif->id; + k.entry_index = idx; + if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || + key->cipher == WLAN_CIPHER_SUITE_WEP104) { + if (pairwise) + k.type = fill_wep_pair(&k.key.wep_pairwise_key, key, + sta->addr); + else + k.type = fill_wep_group(&k.key.wep_group_key, key); + } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { + if (pairwise) + k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key, + sta->addr); + else + k.type = fill_tkip_group(&k.key.tkip_group_key, key, + &seq, wvif->vif->type); + } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) { + if (pairwise) + k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key, + sta->addr); + else + k.type = fill_ccmp_group(&k.key.aes_group_key, key, + &seq); + } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) { + if (pairwise) + k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key, + sta->addr); + else + k.type = fill_sms4_group(&k.key.wapi_group_key, key); + } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, &seq); + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + } else { + dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher); + wfx_free_key(wdev, idx); + return -EOPNOTSUPP; + } + ret = hif_add_key(wdev, &k); + if (ret) { + wfx_free_key(wdev, idx); + return -EOPNOTSUPP; + } + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | + IEEE80211_KEY_FLAG_RESERVE_TAILROOM; + key->hw_key_idx = idx; + return 0; +} + +static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key) +{ + WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx"); + wfx_free_key(wvif->wdev, key->hw_key_idx); + return hif_remove_key(wvif->wdev, key->hw_key_idx); +} + +int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + int ret = -EOPNOTSUPP; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + mutex_lock(&wvif->wdev->conf_mutex); + if (cmd == SET_KEY) + ret = wfx_add_key(wvif, sta, key); + if (cmd == DISABLE_KEY) + ret = wfx_remove_key(wvif, key); + mutex_unlock(&wvif->wdev->conf_mutex); + return ret; +} + diff --git a/drivers/net/wireless/silabs/wfx/key.h b/drivers/net/wireless/silabs/wfx/key.h new file mode 100644 index 000000000000..70a44d0ca35e --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/key.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of mac80211 API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_KEY_H +#define WFX_KEY_H + +#include + +struct wfx_dev; +struct wfx_vif; + +int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); + +#endif /* WFX_STA_H */ From patchwork Wed Nov 4 15:51:59 2020 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: 318392 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 A9FB6C5517A for ; Wed, 4 Nov 2020 15:53:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 57EAC2236F for ; Wed, 4 Nov 2020 15:53:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="NU4G6brZ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731169AbgKDPxe (ORCPT ); Wed, 4 Nov 2020 10:53:34 -0500 Received: from mail-dm6nam11on2049.outbound.protection.outlook.com ([40.107.223.49]:54240 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1731157AbgKDPxc (ORCPT ); Wed, 4 Nov 2020 10:53:32 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=CKIyd5D8QMZfnKOnpqxDtkVCC6yn4Xig9U8j3eDd6gp29F4BWChBHXnuMutszE4r2U+xvMPXC7n/vie12Zmgn7Ez9CeZPohAX87HoKRQf3ZnRsDtga3wKmhypNqqej93Ct05ab0h4d8zDAQmDPCWj5IkaRbKl85ZnhLSD7dPAsbE8NuZnN6h9bcVHKavZoYfZzzeLKnxZ4IFD9kWp6Act17SgFHvfO9HkP6H3mV0RKuul+i2o/IArcCmk088WxysKIfXAqef5HF3SxD2gl3gJpeh5BKPvAPL6BU/glKxgOIeE98Ieek7+X/EyPju3jFVWeDxcfXWOUAYZqqSaHi7Gg== 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-SenderADCheck; bh=edc12fpY37LlQK8Q6v4oXf+Qq4aIaiABOQkqEIdKP7k=; b=EuNO1QrFviy6EBsQ4UPIyTBOBQMD4NGZd5WOUv+o65NN/6YgrBiutW4fD3jjy/WlH59fsV6hVP6RzrqwkvLa/yL7lSODZGQE/RvkC4FOw5Ryb1oji+sFijlNgWeVCX2uFPdyFrBEE0gygTD0oOecbzUc820367zIYXVm6u8vMhWrB8YNROViY8/wc2bfh2edSb6D+ytCdFcEC/cZY0icPPIBbkhykV/57p7CK8n3L3u7WceqQRDqS8z+FkfIOFF62Qsilq7/o4c6oVe+FIRxChoIm1Ov0T4fZDKrw3ybJjlUnHp6yDgnLm/G+YQuVz8c2DqCAHTv+j5gg/Ja4YlSow== 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=edc12fpY37LlQK8Q6v4oXf+Qq4aIaiABOQkqEIdKP7k=; b=NU4G6brZGlHW/YlXhBZ2ZpgJRdqwrPQBJ1C934dgMAhvrwI5ShA7vkTgjHPnwCIkCeQlQT41aMXSmiu13JivGJiByISi6v1TTmgTDYqNiLL7cDXwu80kqx4Bgg9vsh9FTPwn8QogNcs3k2MyCLjL8UiiyIER+GiZM3UEXM6u/78= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:52:58 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:52:58 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 16/24] wfx: add data_rx.c/data_rx.h Date: Wed, 4 Nov 2020 16:51:59 +0100 Message-Id: <20201104155207.128076-17-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:52:56 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: fe335203-f6d5-4569-7efb-08d880d9b376 X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:644; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: i2w8E+hxMjX2n3lheXGYRSi2rznFHJBPnQnf5paEmV0CSiNBkpawJ1oixXW7hhpQiOdNv+N2TOokF0zxJoZ9si6DwKLlYcd+m6hOUeBdjP6pSlnE3VrSZlxcSlbmCgLFtWX6aDfFuhx6I0Wnt8VOlx2RQi8WEu7vXAMkgXePALnso5WciSMDrHjdDOOOVwWJrtGtxoLBPoP45iYWQke/XkWk/WPuAWETfby2q/1ME/HMH51p8S4jECUQLUNAY8N/VP1MYhhIVDRlrb/M9vaA9lf920XXS8ScyBDc3tGCfZ1pbl6a0tR+TOPEiN0MfIV4CmroraeQluZv91u7TVBUjA== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66476007)(66556008)(66946007)(316002)(7696005)(83380400001)(26005)(54906003)(107886003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: Yep4i03Y0QE87M6SMtecMAlrJCF2Cdu8VjCGkshXO4X7rzD1mfNQwpZvC7LsSioX/f2AJRh1OGIUhJS8PM4obx5PgWIz/Et5gPGWI4XoC0Hzpm5wha3IwOGBXtokDTBUsPVn6sybkvGH3NK6vX5Pefi8Ljxbqq6az01cKQIOPoHiPbcu/aeBr8UsGl6SMFYcPeZrCo2ELc42KPTZtae5zJTShu2b5aOCdpeVgRWhjdyWMN4jd2k/QytcBEAFDREgjb0k8vxNG2OYJc/Io6zqPi3b1NpJu3BnBC9O6gYD9WtFpjBjTZ2fI5zszkB5Z/3ADYYO2jmwn3uG6QIoZFQTxNbfNDvjTvtstQnPg91P6d2/uDQjgFCOM61OnxkNBHPbiEcjoBOHajKnvrxgVtKvvbL/H5DSjub47SeNfZ02VoA/U0ZLE7hzPoeOpSok1COEPB5PhUWteLUN8OLf3uNVb+B/ITy5uYZqqPH+0Z+/77Tm/nPPk2Y3yyxQEaP7gl7TWb5gguvhSzwumLGNwpEXK2+hyJbCnVaUt3/sGAXjKFDhzM6NqUupxtk24Zd0lZgkP12+kgdW/Xu1kGd7K0pakvxrkiQI4c8qLG5zWRiO2ReJioSlzp9mr0S2hRLz+x70qrkAO6rbXEPWwhxIJZ4eTQ== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: fe335203-f6d5-4569-7efb-08d880d9b376 X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:52:58.2469 (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: 6qBBtD3ghiYlR9t2MNq/Xk3PXc503UKx3rsuldHFHvsT8+5Mn4jARXOhu3sg8cl9D63r1XeyzBcDaqZLJv0Jmw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/data_rx.c | 93 +++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/data_rx.h | 18 +++++ 2 files changed, 111 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/data_rx.c create mode 100644 drivers/net/wireless/silabs/wfx/data_rx.h diff --git a/drivers/net/wireless/silabs/wfx/data_rx.c b/drivers/net/wireless/silabs/wfx/data_rx.c new file mode 100644 index 000000000000..385f2d42a0e2 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/data_rx.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Datapath implementation. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "data_rx.h" +#include "wfx.h" +#include "bh.h" +#include "sta.h" + +static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt) +{ + int params, tid; + + if (wfx_api_older_than(wvif->wdev, 3, 6)) + return; + + switch (mgmt->u.action.u.addba_req.action_code) { + case WLAN_ACTION_ADDBA_REQ: + params = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + ieee80211_start_rx_ba_session_offl(wvif->vif, mgmt->sa, tid); + break; + case WLAN_ACTION_DELBA: + params = le16_to_cpu(mgmt->u.action.u.delba.params); + tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; + ieee80211_stop_rx_ba_session_offl(wvif->vif, mgmt->sa, tid); + break; + } +} + +void wfx_rx_cb(struct wfx_vif *wvif, + const struct hif_ind_rx *arg, struct sk_buff *skb) +{ + struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + + memset(hdr, 0, sizeof(*hdr)); + + if (arg->status == HIF_STATUS_RX_FAIL_MIC) + hdr->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_IV_STRIPPED; + else if (arg->status) + goto drop; + + if (skb->len < sizeof(struct ieee80211_pspoll)) { + dev_warn(wvif->wdev->dev, "malformed SDU received\n"); + goto drop; + } + + hdr->band = NL80211_BAND_2GHZ; + hdr->freq = ieee80211_channel_to_frequency(arg->channel_number, + hdr->band); + + if (arg->rxed_rate >= 14) { + hdr->encoding = RX_ENC_HT; + hdr->rate_idx = arg->rxed_rate - 14; + } else if (arg->rxed_rate >= 4) { + hdr->rate_idx = arg->rxed_rate - 2; + } else { + hdr->rate_idx = arg->rxed_rate; + } + + if (!arg->rcpi_rssi) { + hdr->flag |= RX_FLAG_NO_SIGNAL_VAL; + dev_info(wvif->wdev->dev, "received frame without RSSI data\n"); + } + hdr->signal = arg->rcpi_rssi / 2 - 110; + hdr->antenna = 0; + + if (arg->encryp) + hdr->flag |= RX_FLAG_DECRYPTED; + + // Block ack negotiation is offloaded by the firmware. However, + // re-ordering must be done by the mac80211. + if (ieee80211_is_action(frame->frame_control) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + skb->len > IEEE80211_MIN_ACTION_SIZE) { + wfx_rx_handle_ba(wvif, mgmt); + goto drop; + } + + ieee80211_rx_irqsafe(wvif->wdev->hw, skb); + return; + +drop: + dev_kfree_skb(skb); +} diff --git a/drivers/net/wireless/silabs/wfx/data_rx.h b/drivers/net/wireless/silabs/wfx/data_rx.h new file mode 100644 index 000000000000..4c0da37f2084 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/data_rx.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Datapath implementation. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_DATA_RX_H +#define WFX_DATA_RX_H + +struct wfx_vif; +struct sk_buff; +struct hif_ind_rx; + +void wfx_rx_cb(struct wfx_vif *wvif, + const struct hif_ind_rx *arg, struct sk_buff *skb); + +#endif /* WFX_DATA_RX_H */ From patchwork Wed Nov 4 15:52:01 2020 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: 318391 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 1A142C4742C for ; Wed, 4 Nov 2020 15:53:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AAF47223AB for ; Wed, 4 Nov 2020 15:53:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="jtrS07I6" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731203AbgKDPxx (ORCPT ); Wed, 4 Nov 2020 10:53:53 -0500 Received: from mail-dm6nam11on2049.outbound.protection.outlook.com ([40.107.223.49]:54240 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1731186AbgKDPxs (ORCPT ); Wed, 4 Nov 2020 10:53:48 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=aWhZ8AniZ8L6tmEJfny3nNnu6edQmOkdkyie4U8EJS0H6fWEXiu++dcUBVOhoItK5A7rF0rTDx2/+9B0e/SLZUhQxdc7mSDTCJ8Uc9Pvrc0yNcfCw/wgcCr+SCh4VWpSEZ6dJepK1sjOYjt04ybLCSjYBB8DeDp0kFIVyMf3dHZhvP7lOJ+VftTJJVHMCIN0vTzCIQzfpp5fuDyCfJ088E8JRhuGQO29OZFs227YV0mbZqFmKGJyRpu/UGuMaCkLr7ja1NH/j3ogXcmjtEEjeCfYatiOmkEVrYcLM/86zQDyhhf8AWbAIpoO8Y2/r25NCurFX47YkjSwiZrTL9cgkQ== 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-SenderADCheck; bh=eEPoAcLMuYJzkTkzf4tbDCzv6UuZwYhqeMcpodAeeHM=; b=JrrRMbufDzUJp3J2ZaE39ZBytBkJlJG3PxnzpIJ+OPT3TgsBgu6WDbtb4mhI8E0bioeljThd8tS5nkldXtcy3AKH6IQqdbgq9vc9nfUNqkEKx0v7wX6D97jJAL/RXhZuy2QZvM9WIKO8XzMK6EFwp8QMe195hmpacWay/IsQj0y8Rp/6G5ly7/aDqKnzNIbW3yD3MM85t3SsVWMKzsZtjFx5awE5N4B5LpBCfzB6e+m0bTaHVFcicZqQyK3IvrDHih8AyfV3KFqhCOjXliM4nd1lf4dpvFWr/aI+hAp9psLBFumeCRlZUvrOo8CKXzShNSGzGep/fE/0JvL9AAlP6w== 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=eEPoAcLMuYJzkTkzf4tbDCzv6UuZwYhqeMcpodAeeHM=; b=jtrS07I6GdINQ6em5wK/0bxZ7bMcmP/9UOxlSp1PIfT429TfcjMKJwEjZi2FNEKXOEKTAygVuPI75cBul6UdW18hTNNNiO7asnKKjSpUwatBJ/0DtKpE8jBj0fzZAVrlWFyJKCfaX/U6beAiUI1nIG6yaCakBAwgP0RChXDGoBU= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:53:02 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:53:02 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 18/24] wfx: add data_tx.c/data_tx.h Date: Wed, 4 Nov 2020 16:52:01 +0100 Message-Id: <20201104155207.128076-19-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:53:00 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 45a785c8-84b0-4422-6358-08d880d9b62a X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:5516; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: hFaq8hEaHgSdo8RMHqWGJQJJBVx7on2+7wzN6nSoQLiaocd5BNA2W0LDIk/psA77hFv1Ecrx4sWl/4pYRgz9BIX9GSa+/sbPJORW8piuAiSe9ofgb2fAMdghXz7tf/FR9eBTM/8trw6L2fZx02xRTGlabUQiitfwvIzDyMrC0RbLL8Ije0qq1rrs1ibKjkzhC4F8mEOKN5pdqsAGQ1cEq0KkFV+qnj38Fv0JcwhWMHjadJ7QvwR2OCsckAv4xBE6kvx+FL9MXAzkfCbJR4Iq5j0MkTsJ794ZXzdwyNIcVEOCloAIMOnlFRTeqCm0UEOaBoED5TzEDtw5em6puAj53g== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(83380400001)(26005)(54906003)(107886003)(30864003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: eWgBd7CqUPS8Z/dLBh5mASR3rbinIcuwO/6AnAmm29eluxE53PuAgjmqKw1UE3Hvic/CUouSP37gURHg7RR1ketOq7MQv6vaJADs62D1bhPXQFJopPYMUmrddRO5EBjze5zYEwgC+foHTZ9l7+sVTWUlU41ywCnNLXmOsyOeVtSRsLB7cZc/0LD6yb+gVDyvb85oKHsljkKU5UWjOi+VscZzNDSI1Se15lM+sTvwPxKfChqTB8XDQYpF2R3nX/Gz3ZOeGyQNVPJv3raTAm07KwiHpuFzJqmW5ERLMX82Yw4t46WL3ZEIbeC92Fohi1Ij3QHGeaMsuloJKteJZpfNSM2V8HmWkyOlOBmZviHUk+gUIwsq6/sYUwV66ggT38DCz7cV8y37VfVXRGs2m8qaXIXTqfq2IWXLzQhSC+wFL/f5rU/ak2W54u7JIdxSOABpwUaVD6LBNkAUvwmSZdEVdiCk+2i4XcQj87roNhjBvJb6tFUxRvrbW42JBFukYJZvgLHw0GmF3YjR0hnp9rV+Lxyvdg3JnyGaDfETKCQ4n7SNPqGer2isDjM0xHlxDmqa6EzN3UtFB0TkBSscjJg22dkAoW7EzZcW+jCRCu+jgfu8z4lrCtO4sUA/D+jjNpCdgh+QenF1DGccM1B0jajwlQ== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 45a785c8-84b0-4422-6358-08d880d9b62a X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:53:02.7693 (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: nyE8fEKdlG3g+xmGFzLurMT7k9amGzgwhmTaxwA+E4bmfg4BiXtQ0gXz5Goo1LaGH65EmsZ32QYEp2hACX03Ag== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/data_tx.c | 585 ++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/data_tx.h | 67 +++ 2 files changed, 652 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/data_tx.c create mode 100644 drivers/net/wireless/silabs/wfx/data_tx.h diff --git a/drivers/net/wireless/silabs/wfx/data_tx.c b/drivers/net/wireless/silabs/wfx/data_tx.c new file mode 100644 index 000000000000..2f49da7cd538 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/data_tx.c @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Datapath implementation. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "data_tx.h" +#include "wfx.h" +#include "bh.h" +#include "sta.h" +#include "queue.h" +#include "debug.h" +#include "traces.h" +#include "hif_tx_mib.h" + +static int wfx_get_hw_rate(struct wfx_dev *wdev, + const struct ieee80211_tx_rate *rate) +{ + struct ieee80211_supported_band *band; + + if (rate->idx < 0) + return -1; + if (rate->flags & IEEE80211_TX_RC_MCS) { + if (rate->idx > 7) { + WARN(1, "wrong rate->idx value: %d", rate->idx); + return -1; + } + return rate->idx + 14; + } + // WFx only support 2GHz, else band information should be retrieved + // from ieee80211_tx_info + band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; + if (rate->idx >= band->n_bitrates) { + WARN(1, "wrong rate->idx value: %d", rate->idx); + return -1; + } + return band->bitrates[rate->idx].hw_value; +} + +/* TX policy cache implementation */ + +static void wfx_tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy, + struct ieee80211_tx_rate *rates) +{ + struct wfx_dev *wdev = wvif->wdev; + int i, rateid; + u8 count; + + WARN(rates[0].idx < 0, "invalid rate policy"); + memset(policy, 0, sizeof(*policy)); + for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) { + if (rates[i].idx < 0) + break; + WARN_ON(rates[i].count > 15); + rateid = wfx_get_hw_rate(wdev, &rates[i]); + // Pack two values in each byte of policy->rates + count = rates[i].count; + if (rateid % 2) + count <<= 4; + policy->rates[rateid / 2] |= count; + } +} + +static bool tx_policy_is_equal(const struct tx_policy *a, + const struct tx_policy *b) +{ + return !memcmp(a->rates, b->rates, sizeof(a->rates)); +} + +static int wfx_tx_policy_find(struct tx_policy_cache *cache, + struct tx_policy *wanted) +{ + struct tx_policy *it; + + list_for_each_entry(it, &cache->used, link) + if (tx_policy_is_equal(wanted, it)) + return it - cache->cache; + list_for_each_entry(it, &cache->free, link) + if (tx_policy_is_equal(wanted, it)) + return it - cache->cache; + return -1; +} + +static void wfx_tx_policy_use(struct tx_policy_cache *cache, + struct tx_policy *entry) +{ + ++entry->usage_count; + list_move(&entry->link, &cache->used); +} + +static int wfx_tx_policy_release(struct tx_policy_cache *cache, + struct tx_policy *entry) +{ + int ret = --entry->usage_count; + + if (!ret) + list_move(&entry->link, &cache->free); + return ret; +} + +static int wfx_tx_policy_get(struct wfx_vif *wvif, + struct ieee80211_tx_rate *rates, bool *renew) +{ + int idx; + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + struct tx_policy wanted; + + wfx_tx_policy_build(wvif, &wanted, rates); + + spin_lock_bh(&cache->lock); + if (list_empty(&cache->free)) { + WARN(1, "unable to get a valid Tx policy"); + spin_unlock_bh(&cache->lock); + return HIF_TX_RETRY_POLICY_INVALID; + } + idx = wfx_tx_policy_find(cache, &wanted); + if (idx >= 0) { + *renew = false; + } else { + struct tx_policy *entry; + *renew = true; + /* If policy is not found create a new one + * using the oldest entry in "free" list + */ + entry = list_entry(cache->free.prev, struct tx_policy, link); + memcpy(entry->rates, wanted.rates, sizeof(entry->rates)); + entry->uploaded = false; + entry->usage_count = 0; + idx = entry - cache->cache; + } + wfx_tx_policy_use(cache, &cache->cache[idx]); + if (list_empty(&cache->free)) + ieee80211_stop_queues(wvif->wdev->hw); + spin_unlock_bh(&cache->lock); + return idx; +} + +static void wfx_tx_policy_put(struct wfx_vif *wvif, int idx) +{ + int usage, locked; + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + + if (idx == HIF_TX_RETRY_POLICY_INVALID) + return; + spin_lock_bh(&cache->lock); + locked = list_empty(&cache->free); + usage = wfx_tx_policy_release(cache, &cache->cache[idx]); + if (locked && !usage) + ieee80211_wake_queues(wvif->wdev->hw); + spin_unlock_bh(&cache->lock); +} + +static int wfx_tx_policy_upload(struct wfx_vif *wvif) +{ + struct tx_policy *policies = wvif->tx_policy_cache.cache; + u8 tmp_rates[12]; + int i, is_used; + + do { + spin_lock_bh(&wvif->tx_policy_cache.lock); + for (i = 0; i < ARRAY_SIZE(wvif->tx_policy_cache.cache); ++i) { + is_used = memzcmp(policies[i].rates, + sizeof(policies[i].rates)); + if (!policies[i].uploaded && is_used) + break; + } + if (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)) { + policies[i].uploaded = true; + memcpy(tmp_rates, policies[i].rates, sizeof(tmp_rates)); + spin_unlock_bh(&wvif->tx_policy_cache.lock); + hif_set_tx_rate_retry_policy(wvif, i, tmp_rates); + } else { + spin_unlock_bh(&wvif->tx_policy_cache.lock); + } + } while (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)); + return 0; +} + +void wfx_tx_policy_upload_work(struct work_struct *work) +{ + struct wfx_vif *wvif = + container_of(work, struct wfx_vif, tx_policy_upload_work); + + wfx_tx_policy_upload(wvif); + wfx_tx_unlock(wvif->wdev); +} + +void wfx_tx_policy_init(struct wfx_vif *wvif) +{ + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + int i; + + memset(cache, 0, sizeof(*cache)); + + spin_lock_init(&cache->lock); + INIT_LIST_HEAD(&cache->used); + INIT_LIST_HEAD(&cache->free); + + for (i = 0; i < ARRAY_SIZE(cache->cache); ++i) + list_add(&cache->cache[i].link, &cache->free); +} + +/* Tx implementation */ + +static bool ieee80211_is_action_back(struct ieee80211_hdr *hdr) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr; + + if (!ieee80211_is_action(mgmt->frame_control)) + return false; + if (mgmt->u.action.category != WLAN_CATEGORY_BACK) + return false; + return true; +} + +static u8 wfx_tx_get_link_id(struct wfx_vif *wvif, struct ieee80211_sta *sta, + struct ieee80211_hdr *hdr) +{ + struct wfx_sta_priv *sta_priv = + sta ? (struct wfx_sta_priv *)&sta->drv_priv : NULL; + const u8 *da = ieee80211_get_DA(hdr); + + if (sta_priv && sta_priv->link_id) + return sta_priv->link_id; + if (wvif->vif->type != NL80211_IFTYPE_AP) + return 0; + if (is_multicast_ether_addr(da)) + return 0; + return HIF_LINK_ID_NOT_ASSOCIATED; +} + +static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates) +{ + int i; + bool finished; + + // Firmware is not able to mix rates with different flags + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) + rates[i].flags |= IEEE80211_TX_RC_SHORT_GI; + if (!(rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) + rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; + if (!(rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)) + rates[i].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; + } + + // Sort rates and remove duplicates + do { + finished = true; + for (i = 0; i < IEEE80211_TX_MAX_RATES - 1; i++) { + if (rates[i + 1].idx == rates[i].idx && + rates[i].idx != -1) { + rates[i].count += rates[i + 1].count; + if (rates[i].count > 15) + rates[i].count = 15; + rates[i + 1].idx = -1; + rates[i + 1].count = 0; + + finished = false; + } + if (rates[i + 1].idx > rates[i].idx) { + swap(rates[i + 1], rates[i]); + finished = false; + } + } + } while (!finished); + // Ensure that MCS0 or 1Mbps is present at the end of the retry list + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (rates[i].idx == 0) + break; + if (rates[i].idx == -1) { + rates[i].idx = 0; + rates[i].count = 8; // == hw->max_rate_tries + rates[i].flags = rates[i - 1].flags & + IEEE80211_TX_RC_MCS; + break; + } + } + // All retries use long GI + for (i = 1; i < IEEE80211_TX_MAX_RATES; i++) + rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; +} + +static u8 wfx_tx_get_rate_id(struct wfx_vif *wvif, + struct ieee80211_tx_info *tx_info) +{ + bool tx_policy_renew = false; + u8 rate_id; + + rate_id = wfx_tx_policy_get(wvif, + tx_info->driver_rates, &tx_policy_renew); + if (rate_id == HIF_TX_RETRY_POLICY_INVALID) + dev_warn(wvif->wdev->dev, "unable to get a valid Tx policy"); + + if (tx_policy_renew) { + wfx_tx_lock(wvif->wdev); + if (!schedule_work(&wvif->tx_policy_upload_work)) + wfx_tx_unlock(wvif->wdev); + } + return rate_id; +} + +static int wfx_tx_get_frame_format(struct ieee80211_tx_info *tx_info) +{ + if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_MCS)) + return HIF_FRAME_FORMAT_NON_HT; + else if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) + return HIF_FRAME_FORMAT_MIXED_FORMAT_HT; + else + return HIF_FRAME_FORMAT_GF_HT_11N; +} + +static int wfx_tx_get_icv_len(struct ieee80211_key_conf *hw_key) +{ + int mic_space; + + if (!hw_key) + return 0; + if (hw_key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) + return 0; + mic_space = (hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) ? 8 : 0; + return hw_key->icv_len + mic_space; +} + +static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + struct hif_msg *hif_msg; + struct hif_req_tx *req; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + int queue_id = skb_get_queue_mapping(skb); + size_t offset = (size_t)skb->data & 3; + int wmsg_len = sizeof(struct hif_msg) + + sizeof(struct hif_req_tx) + offset; + + WARN(queue_id >= IEEE80211_NUM_ACS, "unsupported queue_id"); + wfx_tx_fixup_rates(tx_info->driver_rates); + + // From now tx_info->control is unusable + memset(tx_info->rate_driver_data, 0, sizeof(struct wfx_tx_priv)); + + // Fill hif_msg + WARN(skb_headroom(skb) < wmsg_len, "not enough space in skb"); + WARN(offset & 1, "attempt to transmit an unaligned frame"); + skb_put(skb, wfx_tx_get_icv_len(hw_key)); + skb_push(skb, wmsg_len); + memset(skb->data, 0, wmsg_len); + hif_msg = (struct hif_msg *)skb->data; + hif_msg->len = cpu_to_le16(skb->len); + hif_msg->id = HIF_REQ_ID_TX; + hif_msg->interface = wvif->id; + if (skb->len > wvif->wdev->hw_caps.size_inp_ch_buf) { + dev_warn(wvif->wdev->dev, + "requested frame size (%d) is larger than maximum supported (%d)\n", + skb->len, wvif->wdev->hw_caps.size_inp_ch_buf); + skb_pull(skb, wmsg_len); + return -EIO; + } + + // Fill tx request + req = (struct hif_req_tx *)hif_msg->body; + // packet_id just need to be unique on device. 32bits are more than + // necessary for that task, so we tae advantage of it to add some extra + // data for debug. + req->packet_id = atomic_add_return(1, &wvif->wdev->packet_id) & 0xFFFF; + req->packet_id |= IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)) << 16; + req->packet_id |= queue_id << 28; + + req->fc_offset = offset; + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) + req->after_dtim = 1; + req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr); + // Queue index are inverted between firmware and Linux + req->queue_id = 3 - queue_id; + req->retry_policy_index = wfx_tx_get_rate_id(wvif, tx_info); + req->frame_format = wfx_tx_get_frame_format(tx_info); + if (tx_info->driver_rates[0].flags & IEEE80211_TX_RC_SHORT_GI) + req->short_gi = 1; + + // Auxiliary operations + wfx_tx_queues_put(wvif, skb); + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) + schedule_work(&wvif->update_tim_work); + wfx_bh_request_tx(wvif->wdev); + return 0; +} + +void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif; + struct ieee80211_sta *sta = control ? control->sta : NULL; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + size_t driver_data_room = sizeof_field(struct ieee80211_tx_info, + rate_driver_data); + + compiletime_assert(sizeof(struct wfx_tx_priv) <= driver_data_room, + "struct tx_priv is too large"); + WARN(skb->next || skb->prev, "skb is already member of a list"); + // control.vif can be NULL for injected frames + if (tx_info->control.vif) + wvif = (struct wfx_vif *)tx_info->control.vif->drv_priv; + else + wvif = wvif_iterate(wdev, NULL); + if (WARN_ON(!wvif)) + goto drop; + // Because of TX_AMPDU_SETUP_IN_HW, mac80211 does not try to send any + // BlockAck session management frame. The check below exist just in case. + if (ieee80211_is_action_back(hdr)) { + dev_info(wdev->dev, "drop BA action\n"); + goto drop; + } + if (wfx_tx_inner(wvif, sta, skb)) + goto drop; + + return; + +drop: + ieee80211_tx_status_irqsafe(wdev->hw, skb); +} + +static void wfx_skb_dtor(struct wfx_vif *wvif, struct sk_buff *skb) +{ + struct hif_msg *hif = (struct hif_msg *)skb->data; + struct hif_req_tx *req = (struct hif_req_tx *)hif->body; + unsigned int offset = sizeof(struct hif_msg) + + sizeof(struct hif_req_tx) + + req->fc_offset; + + if (!wvif) { + pr_warn("vif associated with the skb does not exist anymore\n"); + return; + } + wfx_tx_policy_put(wvif, req->retry_policy_index); + skb_pull(skb, offset); + ieee80211_tx_status_irqsafe(wvif->wdev->hw, skb); +} + +static void wfx_tx_fill_rates(struct wfx_dev *wdev, + struct ieee80211_tx_info *tx_info, + const struct hif_cnf_tx *arg) +{ + struct ieee80211_tx_rate *rate; + int tx_count; + int i; + + tx_count = arg->ack_failures; + if (!arg->status || arg->ack_failures) + tx_count += 1; // Also report success + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + rate = &tx_info->status.rates[i]; + if (rate->idx < 0) + break; + if (tx_count < rate->count && + arg->status == HIF_STATUS_TX_FAIL_RETRIES && + arg->ack_failures) + dev_dbg(wdev->dev, "all retries were not consumed: %d != %d\n", + rate->count, tx_count); + if (tx_count <= rate->count && tx_count && + arg->txed_rate != wfx_get_hw_rate(wdev, rate)) + dev_dbg(wdev->dev, "inconsistent tx_info rates: %d != %d\n", + arg->txed_rate, wfx_get_hw_rate(wdev, rate)); + if (tx_count > rate->count) { + tx_count -= rate->count; + } else if (!tx_count) { + rate->count = 0; + rate->idx = -1; + } else { + rate->count = tx_count; + tx_count = 0; + } + } + if (tx_count) + dev_dbg(wdev->dev, "%d more retries than expected\n", tx_count); +} + +void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg) +{ + struct ieee80211_tx_info *tx_info; + struct wfx_vif *wvif; + struct sk_buff *skb; + + skb = wfx_pending_get(wdev, arg->packet_id); + if (!skb) { + dev_warn(wdev->dev, "received unknown packet_id (%#.8x) from chip\n", + arg->packet_id); + return; + } + tx_info = IEEE80211_SKB_CB(skb); + wvif = wdev_to_wvif(wdev, ((struct hif_msg *)skb->data)->interface); + WARN_ON(!wvif); + if (!wvif) + return; + + // Note that wfx_pending_get_pkt_us_delay() get data from tx_info + _trace_tx_stats(arg, skb, wfx_pending_get_pkt_us_delay(wdev, skb)); + wfx_tx_fill_rates(wdev, tx_info, arg); + // From now, you can touch to tx_info->status, but do not touch to + // tx_priv anymore + // FIXME: use ieee80211_tx_info_clear_status() + memset(tx_info->rate_driver_data, 0, sizeof(tx_info->rate_driver_data)); + memset(tx_info->pad, 0, sizeof(tx_info->pad)); + + if (!arg->status) { + tx_info->status.tx_time = + le32_to_cpu(arg->media_delay) - + le32_to_cpu(arg->tx_queue_delay); + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } else if (arg->status == HIF_STATUS_TX_FAIL_REQUEUE) { + WARN(!arg->requeue, "incoherent status and result_flags"); + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + wvif->after_dtim_tx_allowed = false; // DTIM period elapsed + schedule_work(&wvif->update_tim_work); + } + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + } + wfx_skb_dtor(wvif, skb); +} + +static void wfx_flush_vif(struct wfx_vif *wvif, u32 queues, + struct sk_buff_head *dropped) +{ + struct wfx_queue *queue; + int i; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (!(BIT(i) & queues)) + continue; + queue = &wvif->tx_queue[i]; + if (dropped) + wfx_tx_queue_drop(wvif, queue, dropped); + } + if (wvif->wdev->chip_frozen) + return; + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (!(BIT(i) & queues)) + continue; + queue = &wvif->tx_queue[i]; + if (wait_event_timeout(wvif->wdev->tx_dequeue, + wfx_tx_queue_empty(wvif, queue), + msecs_to_jiffies(1000)) <= 0) + dev_warn(wvif->wdev->dev, + "frames queued while flushing tx queues?"); + } +} + +void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct wfx_dev *wdev = hw->priv; + struct sk_buff_head dropped; + struct wfx_vif *wvif; + struct hif_msg *hif; + struct sk_buff *skb; + + skb_queue_head_init(&dropped); + if (vif) { + wvif = (struct wfx_vif *)vif->drv_priv; + wfx_flush_vif(wvif, queues, drop ? &dropped : NULL); + } else { + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_flush_vif(wvif, queues, drop ? &dropped : NULL); + } + wfx_tx_flush(wdev); + if (wdev->chip_frozen) + wfx_pending_drop(wdev, &dropped); + while ((skb = skb_dequeue(&dropped)) != NULL) { + hif = (struct hif_msg *)skb->data; + wvif = wdev_to_wvif(wdev, hif->interface); + ieee80211_tx_info_clear_status(IEEE80211_SKB_CB(skb)); + wfx_skb_dtor(wvif, skb); + } +} diff --git a/drivers/net/wireless/silabs/wfx/data_tx.h b/drivers/net/wireless/silabs/wfx/data_tx.h new file mode 100644 index 000000000000..46c9fff7a870 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/data_tx.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Datapath implementation. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_DATA_TX_H +#define WFX_DATA_TX_H + +#include +#include + +#include "hif_api_cmd.h" +#include "hif_api_mib.h" + +struct wfx_tx_priv; +struct wfx_dev; +struct wfx_vif; + +struct tx_policy { + struct list_head link; + int usage_count; + u8 rates[12]; + bool uploaded; +}; + +struct tx_policy_cache { + struct tx_policy cache[HIF_TX_RETRY_POLICY_MAX]; + // FIXME: use a trees and drop hash from tx_policy + struct list_head used; + struct list_head free; + spinlock_t lock; +}; + +struct wfx_tx_priv { + ktime_t xmit_timestamp; +}; + +void wfx_tx_policy_init(struct wfx_vif *wvif); +void wfx_tx_policy_upload_work(struct work_struct *work); + +void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb); +void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg); +void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); + +static inline struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info; + + if (!skb) + return NULL; + tx_info = IEEE80211_SKB_CB(skb); + return (struct wfx_tx_priv *)tx_info->rate_driver_data; +} + +static inline struct hif_req_tx *wfx_skb_txreq(struct sk_buff *skb) +{ + struct hif_msg *hif = (struct hif_msg *)skb->data; + struct hif_req_tx *req = (struct hif_req_tx *)hif->body; + + return req; +} + +#endif /* WFX_DATA_TX_H */ From patchwork Wed Nov 4 15:52:02 2020 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: 318390 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham 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 023ACC4742C for ; Wed, 4 Nov 2020 15:54:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9349822280 for ; Wed, 4 Nov 2020 15:54:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="FRASoUKZ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731213AbgKDPyE (ORCPT ); Wed, 4 Nov 2020 10:54:04 -0500 Received: from mail-dm6nam11on2049.outbound.protection.outlook.com ([40.107.223.49]:54240 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730534AbgKDPyA (ORCPT ); Wed, 4 Nov 2020 10:54:00 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=eke60EH6CdTU+ZVXhGk6CvBW9uxNNXi1KBsERpRB4U0Q8dgR0RqAa1Ixau3Z8X9J8jmC3uWy6wW/ie/DCs9TgvLVIDX26as5yTr+Q4BnD3CctKqZKa8lXYXVdwjJVSANAErHn2QouZgkUsFxB8Me5fNv2ojC2QU6vwW9V/J2yusrf3Qgd7DvbR50Q4l8ZMVqwDT8Rcr9AoGNjkDYIX5YvbGcsEj0ICW5dFfYfigp0fZ4MWKCXnFguiuBVFm6JDjQnlaAxY186yME852uSx9NoyPRy04iYuO4t4aUckzSY/4wGzd/NPy1qGGcWZihjyhG3d5nQ+HrJhB6dxW+tAqodw== 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-SenderADCheck; bh=7taBAYehje1XVW1nbj2j0kmpBXYOhX17C2ZVt+CjCmQ=; b=k9GdaWxelITmwpEEyU1dbTAs6RQZ0Qm/R+yqvKoHQAgNg20k39obqUnhdWikMbEgwFnqzHDAYznbM5cDJQrBoAfqbJMnPJiFuRalMeGqLvEPUfjKsyJcAHoYBz09eBpw502zyycxdeqSFGeytNndXiLuZAdHYt1Hj0Awix8smoNW4cxLo2iS+eHUoXQdm38m0/IxvGxQikg1DMpm7OBRJNkIqc5ieOXChpqUUcmOwiH4/sajm+5QthubC/aQlmfJjtfg1fZhjtnefs+bdxuw9JuStwq97pkBUTc0zzkV6aD8n5Wedx9VK5f0cLa8NNW3luD9oMKcEySqSRxRYWzWxA== 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=7taBAYehje1XVW1nbj2j0kmpBXYOhX17C2ZVt+CjCmQ=; b=FRASoUKZS24vxoml6hTip65qg15Ubr0no8KZjFV1ZnaX2vnCtSSonbqrV55peWTtBW1N7mKe5P3YeMWKbrrupjkzie6qqx1cb6qns1GE5lXhgNVizO9gS98R5+Lb6vDhGW1zomQK3oio4MPomen3ApHO6nTgwz5RS3mnz9QhCIo= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:53:05 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:53:05 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 19/24] wfx: add sta.c/sta.h Date: Wed, 4 Nov 2020 16:52:02 +0100 Message-Id: <20201104155207.128076-20-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:53:03 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: e3db2e82-c807-4ef2-2871-08d880d9b77e X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:1388; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: Ul64w6vpHzVjsvJfoOl3Uft6w/330r3UhIWZkHXQ94QkvEd1Qivp/0fsnaiWmtFYJTsEdlcAp3P/solCCRxb/7Onh+YzM7eRZAPH31BH+cRc/5mcrru8HM73/acHD0GFqnM09iqR/oPA7yAG0qJS1hzOJtKBlI65QCOJgk+gN8Ouj+BEyCathspZDFctdezc/Z/8H2l4H76odQjOCIoUkYOncp7pZ1BQS8Lc+SeiYgKS94bwJzIy1lyVm7gqcdhL7s5p/9A23B4HRD9Oi9B3kno9wfdbtU6v4J3iWCYk2U0W6kdoREEFNzlxU25Z0MX/6ALbWOHp6PKw9D1hWQglpQ== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(83380400001)(26005)(54906003)(107886003)(30864003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: fS7MigGll2goPeEFHBPHF9VmANqnCMCNXlG5WADFeAmwkhVDdbL/xjgpWfbir3B5Vb7YPoD0DI+WRuP+jfoj1bCRC/08bxmE0hYNN7vYaWSTXbAiOHVsm0iF9r5eh7uyENuRQe6dYmRcHIWAcaAtsMP4q27RFizJiz6dgpdYTInUTpYhuSJMLBYx3cucaTyEoZ7B2j7/gO+V7aPXc9I7FIcEiTeiK6Kofr2bQ2ThgnS3mwbge+laYGmAobi2AcYWhCgLeTTjOJZigIGCdYqRVjPm42XZaH3tbgXi+SZHVNX6KPk8u8lgOKF2uQH292BhdutV6GIKEOop+PsPg8L7t/k+nJOJFoEq5jkyfolFkqIljEFYzRHqEifvdixK/ZO4zL7BzXRJy5NGWF++OTJbUIWTBrV7oAw4n5bxc3yFlKQsnWh7+vGAjd2Mp/iAo6g1O/ctKxRummv2NXDvX/jAPxesWYJBCDIyqh3ulxZu5g+4wei0x1rp5u+waJrqzrjLbIZDo+tKeEArlydP4TPQ2PVR5XUEStofSdsrUcoQc8okr8EZaNnTIu2S5OFm7pT0YBcTJvs7FZ9Sp8rtxH13WSaaDtpmnHSpkkzbeD43OTwq1rNwUgkWda1+0mPmbBf0sz8WEe62c9aCEPSSD57HNg== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: e3db2e82-c807-4ef2-2871-08d880d9b77e X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:53:05.0150 (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: JJhtN3J0O0aQ2tfYepNYn2O3Edz9bW5m4sZ9X6dsCKZ3IpXcLFwT+iteZN4PyTl0ylH9Kw0mN+QmNeGKNUr01w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/sta.c | 807 ++++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/sta.h | 73 +++ 2 files changed, 880 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/sta.c create mode 100644 drivers/net/wireless/silabs/wfx/sta.h diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c new file mode 100644 index 000000000000..196779a1b89a --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -0,0 +1,807 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of mac80211 API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "sta.h" +#include "wfx.h" +#include "fwio.h" +#include "bh.h" +#include "key.h" +#include "scan.h" +#include "debug.h" +#include "hif_tx.h" +#include "hif_tx_mib.h" + +#define HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES 2 + +u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates) +{ + int i; + u32 ret = 0; + // WFx only support 2GHz + struct ieee80211_supported_band *sband = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; + + for (i = 0; i < sband->n_bitrates; i++) { + if (rates & BIT(i)) { + if (i >= sband->n_bitrates) + dev_warn(wdev->dev, "unsupported basic rate\n"); + else + ret |= BIT(sband->bitrates[i].hw_value); + } + } + return ret; +} + +void wfx_cooling_timeout_work(struct work_struct *work) +{ + struct wfx_dev *wdev = container_of(to_delayed_work(work), + struct wfx_dev, + cooling_timeout_work); + + wdev->chip_frozen = true; + wfx_tx_unlock(wdev); +} + +void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd) +{ + if (cmd == STA_NOTIFY_AWAKE) { + // Device recover normal temperature + if (cancel_delayed_work(&wdev->cooling_timeout_work)) + wfx_tx_unlock(wdev); + } else { + // Device is too hot + schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ); + wfx_tx_lock(wdev); + } +} + +static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon) +{ + static const struct hif_ie_table_entry filter_ies[] = { + { + .ie_id = WLAN_EID_VENDOR_SPECIFIC, + .has_changed = 1, + .no_longer = 1, + .has_appeared = 1, + .oui = { 0x50, 0x6F, 0x9A }, + }, { + .ie_id = WLAN_EID_HT_OPERATION, + .has_changed = 1, + .no_longer = 1, + .has_appeared = 1, + }, { + .ie_id = WLAN_EID_ERP_INFO, + .has_changed = 1, + .no_longer = 1, + .has_appeared = 1, + } + }; + + if (!filter_beacon) { + hif_beacon_filter_control(wvif, 0, 1); + } else { + hif_set_beacon_filter_table(wvif, 3, filter_ies); + hif_beacon_filter_control(wvif, HIF_BEACON_FILTER_ENABLE, 0); + } +} + +void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 unused) +{ + struct wfx_vif *wvif = NULL; + struct wfx_dev *wdev = hw->priv; + bool filter_bssid, filter_prbreq, filter_beacon; + + // Notes: + // - Probe responses (FIF_BCN_PRBRESP_PROMISC) are never filtered + // - PS-Poll (FIF_PSPOLL) are never filtered + // - RTS, CTS and Ack (FIF_CONTROL) are always filtered + // - Broken frames (FIF_FCSFAIL and FIF_PLCPFAIL) are always filtered + // - Firmware does (yet) allow to forward unicast traffic sent to + // other stations (aka. promiscuous mode) + *total_flags &= FIF_BCN_PRBRESP_PROMISC | FIF_ALLMULTI | FIF_OTHER_BSS | + FIF_PROBE_REQ | FIF_PSPOLL; + + mutex_lock(&wdev->conf_mutex); + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + mutex_lock(&wvif->scan_lock); + + // Note: FIF_BCN_PRBRESP_PROMISC covers probe response and + // beacons from other BSS + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + filter_beacon = false; + else + filter_beacon = true; + wfx_filter_beacon(wvif, filter_beacon); + + if (*total_flags & FIF_OTHER_BSS) + filter_bssid = false; + else + filter_bssid = true; + + // In AP mode, chip can reply to probe request itself + if (*total_flags & FIF_PROBE_REQ && + wvif->vif->type == NL80211_IFTYPE_AP) { + dev_dbg(wdev->dev, "do not forward probe request in AP mode\n"); + *total_flags &= ~FIF_PROBE_REQ; + } + + if (*total_flags & FIF_PROBE_REQ) + filter_prbreq = false; + else + filter_prbreq = true; + hif_set_rx_filter(wvif, filter_bssid, filter_prbreq); + + mutex_unlock(&wvif->scan_lock); + } + mutex_unlock(&wdev->conf_mutex); +} + +static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) +{ + struct ieee80211_channel *chan0 = NULL, *chan1 = NULL; + struct ieee80211_conf *conf = &wvif->wdev->hw->conf; + + WARN(!wvif->vif->bss_conf.assoc && enable_ps, + "enable_ps is reliable only if associated"); + if (wdev_to_wvif(wvif->wdev, 0)) + chan0 = wdev_to_wvif(wvif->wdev, 0)->vif->bss_conf.chandef.chan; + if (wdev_to_wvif(wvif->wdev, 1)) + chan1 = wdev_to_wvif(wvif->wdev, 1)->vif->bss_conf.chandef.chan; + if (chan0 && chan1 && chan0->hw_value != chan1->hw_value && + wvif->vif->type != NL80211_IFTYPE_AP) { + // It is necessary to enable powersave if channels + // are different. + if (enable_ps) + *enable_ps = true; + if (wvif->wdev->force_ps_timeout > -1) + return wvif->wdev->force_ps_timeout; + else if (wfx_api_older_than(wvif->wdev, 3, 2)) + return 0; + else + return 30; + } + if (enable_ps) + *enable_ps = wvif->vif->bss_conf.ps; + if (wvif->wdev->force_ps_timeout > -1) + return wvif->wdev->force_ps_timeout; + else if (wvif->vif->bss_conf.assoc && wvif->vif->bss_conf.ps) + return conf->dynamic_ps_timeout; + else + return -1; +} + +int wfx_update_pm(struct wfx_vif *wvif) +{ + int ps_timeout; + bool ps; + + if (!wvif->vif->bss_conf.assoc) + return 0; + ps_timeout = wfx_get_ps_timeout(wvif, &ps); + if (!ps) + ps_timeout = 0; + WARN_ON(ps_timeout < 0); + if (wvif->uapsd_mask) + ps_timeout = 0; + + if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete, + TU_TO_JIFFIES(512))) + dev_warn(wvif->wdev->dev, + "timeout while waiting of set_pm_mode_complete\n"); + return hif_set_pm(wvif, ps, ps_timeout); +} + +int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + int old_uapsd = wvif->uapsd_mask; + + WARN_ON(queue >= hw->queues); + + mutex_lock(&wdev->conf_mutex); + assign_bit(queue, &wvif->uapsd_mask, params->uapsd); + hif_set_edca_queue_params(wvif, queue, params); + if (wvif->vif->type == NL80211_IFTYPE_STATION && + old_uapsd != wvif->uapsd_mask) { + hif_set_uapsd_info(wvif, wvif->uapsd_mask); + wfx_update_pm(wvif); + } + mutex_unlock(&wdev->conf_mutex); + return 0; +} + +int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = NULL; + + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + hif_rts_threshold(wvif, value); + return 0; +} + +/* WSM callbacks */ + +void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) +{ + /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 + * RSSI = RCPI / 2 - 110 + */ + int rcpi_rssi; + int cqm_evt; + + rcpi_rssi = raw_rcpi_rssi / 2 - 110; + if (rcpi_rssi <= wvif->vif->bss_conf.cqm_rssi_thold) + cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + else + cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + ieee80211_cqm_rssi_notify(wvif->vif, cqm_evt, rcpi_rssi, GFP_KERNEL); +} + +static void wfx_beacon_loss_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(to_delayed_work(work), + struct wfx_vif, beacon_loss_work); + struct ieee80211_bss_conf *bss_conf = &wvif->vif->bss_conf; + + ieee80211_beacon_loss(wvif->vif); + schedule_delayed_work(to_delayed_work(work), + msecs_to_jiffies(bss_conf->beacon_int)); +} + +void wfx_set_default_unicast_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int idx) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + hif_wep_default_key_id(wvif, idx); +} + +void wfx_reset(struct wfx_vif *wvif) +{ + struct wfx_dev *wdev = wvif->wdev; + + wfx_tx_lock_flush(wdev); + hif_reset(wvif, false); + wfx_tx_policy_init(wvif); + if (wvif_count(wdev) <= 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + wfx_tx_unlock(wdev); + wvif->join_in_progress = false; + cancel_delayed_work_sync(&wvif->beacon_loss_work); + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_update_pm(wvif); +} + +int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; + + sta_priv->vif_id = wvif->id; + + if (vif->type == NL80211_IFTYPE_STATION) + hif_set_mfp(wvif, sta->mfp, sta->mfp); + + // In station mode, the firmware interprets new link-id as a TDLS peer. + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + return 0; + sta_priv->link_id = ffz(wvif->link_id_map); + wvif->link_id_map |= BIT(sta_priv->link_id); + WARN_ON(!sta_priv->link_id); + WARN_ON(sta_priv->link_id >= HIF_LINK_ID_MAX); + hif_map_link(wvif, false, sta->addr, sta_priv->link_id, sta->mfp); + + return 0; +} + +int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; + + // See note in wfx_sta_add() + if (!sta_priv->link_id) + return 0; + // FIXME add a mutex? + hif_map_link(wvif, true, sta->addr, sta_priv->link_id, false); + wvif->link_id_map &= ~BIT(sta_priv->link_id); + return 0; +} + +static int wfx_upload_ap_templates(struct wfx_vif *wvif) +{ + struct sk_buff *skb; + + skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); + if (!skb) + return -ENOMEM; + hif_set_template_frame(wvif, skb, HIF_TMPLT_BCN, + API_RATE_INDEX_B_1MBPS); + dev_kfree_skb(skb); + + skb = ieee80211_proberesp_get(wvif->wdev->hw, wvif->vif); + if (!skb) + return -ENOMEM; + hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBRES, + API_RATE_INDEX_B_1MBPS); + dev_kfree_skb(skb); + return 0; +} + +static void wfx_set_mfp_ap(struct wfx_vif *wvif) +{ + struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); + const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + const u16 *ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, + skb->data + ieoffset, + skb->len - ieoffset); + const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16); + const int pairwise_cipher_suite_size = 4 / sizeof(u16); + const int akm_suite_size = 4 / sizeof(u16); + + if (ptr) { + ptr += pairwise_cipher_suite_count_offset; + if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) + return; + ptr += 1 + pairwise_cipher_suite_size * *ptr; + if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) + return; + ptr += 1 + akm_suite_size * *ptr; + if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) + return; + hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6)); + } +} + +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct wfx_dev *wdev = wvif->wdev; + int ret; + + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_update_pm(wvif); + wvif = (struct wfx_vif *)vif->drv_priv; + wfx_upload_ap_templates(wvif); + ret = hif_start(wvif, &vif->bss_conf, wvif->channel); + if (ret > 0) + return -EIO; + wfx_set_mfp_ap(wvif); + return ret; +} + +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wfx_reset(wvif); +} + +static void wfx_join(struct wfx_vif *wvif) +{ + int ret; + struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf; + struct cfg80211_bss *bss = NULL; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + const u8 *ssidie = NULL; + int ssidlen = 0; + + wfx_tx_lock_flush(wvif->wdev); + + bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel, + conf->bssid, NULL, 0, + IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); + if (!bss && !conf->ibss_joined) { + wfx_tx_unlock(wvif->wdev); + return; + } + + rcu_read_lock(); // protect ssidie + if (bss) + ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); + if (ssidie) { + ssidlen = ssidie[1]; + if (ssidlen > IEEE80211_MAX_SSID_LEN) + ssidlen = IEEE80211_MAX_SSID_LEN; + memcpy(ssid, &ssidie[2], ssidlen); + } + rcu_read_unlock(); + + cfg80211_put_bss(wvif->wdev->hw->wiphy, bss); + + wvif->join_in_progress = true; + ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen); + if (ret) { + ieee80211_connection_loss(wvif->vif); + wfx_reset(wvif); + } else { + /* Due to beacon filtering it is possible that the + * AP's beacon is not known for the mac80211 stack. + * Disable filtering temporary to make sure the stack + * receives at least one + */ + wfx_filter_beacon(wvif, false); + } + wfx_tx_unlock(wvif->wdev); +} + +static void wfx_join_finalize(struct wfx_vif *wvif, + struct ieee80211_bss_conf *info) +{ + struct ieee80211_sta *sta = NULL; + int ampdu_density = 0; + bool greenfield = false; + + rcu_read_lock(); // protect sta + if (info->bssid && !info->ibss_joined) + sta = ieee80211_find_sta(wvif->vif, info->bssid); + if (sta && sta->ht_cap.ht_supported) + ampdu_density = sta->ht_cap.ampdu_density; + if (sta && sta->ht_cap.ht_supported && + !(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)) + greenfield = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); + rcu_read_unlock(); + + wvif->join_in_progress = false; + hif_set_association_mode(wvif, ampdu_density, greenfield, + info->use_short_preamble); + hif_keep_alive_period(wvif, 0); + // beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use + // the same value. + hif_set_bss_params(wvif, info->aid, 7); + hif_set_beacon_wakeup_period(wvif, 1, 1); + wfx_update_pm(wvif); +} + +int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wfx_upload_ap_templates(wvif); + wfx_join(wvif); + return 0; +} + +void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wfx_reset(wvif); +} + +static void wfx_enable_beacon(struct wfx_vif *wvif, bool enable) +{ + // Driver has Content After DTIM Beacon in queue. Driver is waiting for + // a signal from the firmware. Since we are going to stop to send + // beacons, this signal will never happens. See also + // wfx_suspend_resume_mc() + if (!enable && wfx_tx_queues_has_cab(wvif)) { + wvif->after_dtim_tx_allowed = true; + wfx_bh_request_tx(wvif->wdev); + } + hif_beacon_transmit(wvif, enable); +} + +void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + int i; + + mutex_lock(&wdev->conf_mutex); + + if (changed & BSS_CHANGED_BASIC_RATES || + changed & BSS_CHANGED_BEACON_INT || + changed & BSS_CHANGED_BSSID) { + if (vif->type == NL80211_IFTYPE_STATION) + wfx_join(wvif); + } + + if (changed & BSS_CHANGED_ASSOC) { + if (info->assoc || info->ibss_joined) + wfx_join_finalize(wvif, info); + else if (!info->assoc && vif->type == NL80211_IFTYPE_STATION) + wfx_reset(wvif); + else + dev_warn(wdev->dev, "%s: misunderstood change: ASSOC\n", + __func__); + } + + if (changed & BSS_CHANGED_BEACON_INFO) { + if (vif->type != NL80211_IFTYPE_STATION) + dev_warn(wdev->dev, "%s: misunderstood change: BEACON_INFO\n", + __func__); + hif_set_beacon_wakeup_period(wvif, info->dtim_period, + info->dtim_period); + // We temporary forwarded beacon for join process. It is now no + // more necessary. + wfx_filter_beacon(wvif, true); + } + + if (changed & BSS_CHANGED_ARP_FILTER) { + for (i = 0; i < HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES; i++) { + __be32 *arp_addr = &info->arp_addr_list[i]; + + if (info->arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES) + arp_addr = NULL; + if (i >= info->arp_addr_cnt) + arp_addr = NULL; + hif_set_arp_ipv4_filter(wvif, i, arp_addr); + } + } + + if (changed & BSS_CHANGED_AP_PROBE_RESP || + changed & BSS_CHANGED_BEACON) + wfx_upload_ap_templates(wvif); + + if (changed & BSS_CHANGED_BEACON_ENABLED) + wfx_enable_beacon(wvif, info->enable_beacon); + + if (changed & BSS_CHANGED_KEEP_ALIVE) + hif_keep_alive_period(wvif, info->max_idle_period * + USEC_PER_TU / USEC_PER_MSEC); + + if (changed & BSS_CHANGED_ERP_CTS_PROT) + hif_erp_use_protection(wvif, info->use_cts_prot); + + if (changed & BSS_CHANGED_ERP_SLOT) + hif_slot_time(wvif, info->use_short_slot ? 9 : 20); + + if (changed & BSS_CHANGED_CQM) + hif_set_rcpi_rssi_threshold(wvif, info->cqm_rssi_thold, + info->cqm_rssi_hyst); + + if (changed & BSS_CHANGED_TXPOWER) + hif_set_output_power(wvif, info->txpower); + + if (changed & BSS_CHANGED_PS) + wfx_update_pm(wvif); + + mutex_unlock(&wdev->conf_mutex); +} + +static int wfx_update_tim(struct wfx_vif *wvif) +{ + struct sk_buff *skb; + u16 tim_offset, tim_length; + u8 *tim_ptr; + + skb = ieee80211_beacon_get_tim(wvif->wdev->hw, wvif->vif, + &tim_offset, &tim_length); + if (!skb) + return -ENOENT; + tim_ptr = skb->data + tim_offset; + + if (tim_offset && tim_length >= 6) { + /* Ignore DTIM count from mac80211: + * firmware handles DTIM internally. + */ + tim_ptr[2] = 0; + + /* Set/reset aid0 bit */ + if (wfx_tx_queues_has_cab(wvif)) + tim_ptr[4] |= 1; + else + tim_ptr[4] &= ~1; + } + + hif_update_ie_beacon(wvif, tim_ptr, tim_length); + dev_kfree_skb(skb); + + return 0; +} + +static void wfx_update_tim_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, update_tim_work); + + wfx_update_tim(wvif); +} + +int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_sta_priv *sta_dev = (struct wfx_sta_priv *)&sta->drv_priv; + struct wfx_vif *wvif = wdev_to_wvif(wdev, sta_dev->vif_id); + + if (!wvif) { + dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); + return -EIO; + } + schedule_work(&wvif->update_tim_work); + return 0; +} + +void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd notify_cmd) +{ + if (notify_cmd != STA_NOTIFY_AWAKE) + return; + WARN(!wfx_tx_queues_has_cab(wvif), "incorrect sequence"); + WARN(wvif->after_dtim_tx_allowed, "incorrect sequence"); + wvif->after_dtim_tx_allowed = true; + wfx_bh_request_tx(wvif->wdev); +} + +int wfx_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + // Aggregation is implemented fully in firmware + switch (params->action) { + case IEEE80211_AMPDU_RX_START: + case IEEE80211_AMPDU_RX_STOP: + // Just acknowledge it to enable frame re-ordering + return 0; + default: + // Leave the firmware doing its business for tx aggregation + return -ENOTSUPP; + } +} + +int wfx_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ + return 0; +} + +void wfx_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ +} + +void wfx_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + u32 changed) +{ +} + +int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct ieee80211_channel *ch = conf->def.chan; + + WARN(wvif->channel, "channel overwrite"); + wvif->channel = ch; + + return 0; +} + +void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct ieee80211_channel *ch = conf->def.chan; + + WARN(wvif->channel != ch, "channel mismatch"); + wvif->channel = NULL; +} + +int wfx_config(struct ieee80211_hw *hw, u32 changed) +{ + return 0; +} + +int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + int i, ret = 0; + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; + + mutex_lock(&wdev->conf_mutex); + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + break; + default: + mutex_unlock(&wdev->conf_mutex); + return -EOPNOTSUPP; + } + + // FIXME: prefer use of container_of() to get vif + wvif->vif = vif; + wvif->wdev = wdev; + + wvif->link_id_map = 1; // link-id 0 is reserved for multicast + INIT_WORK(&wvif->update_tim_work, wfx_update_tim_work); + INIT_DELAYED_WORK(&wvif->beacon_loss_work, wfx_beacon_loss_work); + + init_completion(&wvif->set_pm_mode_complete); + complete(&wvif->set_pm_mode_complete); + INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work); + + mutex_init(&wvif->scan_lock); + init_completion(&wvif->scan_complete); + INIT_WORK(&wvif->scan_work, wfx_hw_scan_work); + + wfx_tx_queues_init(wvif); + wfx_tx_policy_init(wvif); + + for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { + if (!wdev->vif[i]) { + wdev->vif[i] = vif; + wvif->id = i; + break; + } + } + WARN(i == ARRAY_SIZE(wdev->vif), "try to instantiate more vif than supported"); + + hif_set_macaddr(wvif, vif->addr); + + mutex_unlock(&wdev->conf_mutex); + + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + // Combo mode does not support Block Acks. We can re-enable them + if (wvif_count(wdev) == 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + else + hif_set_block_ack_policy(wvif, 0x00, 0x00); + } + return ret; +} + +void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300)); + wfx_tx_queues_check_empty(wvif); + + mutex_lock(&wdev->conf_mutex); + WARN(wvif->link_id_map != 1, "corrupted state"); + + hif_reset(wvif, false); + hif_set_macaddr(wvif, NULL); + wfx_tx_policy_init(wvif); + + cancel_delayed_work_sync(&wvif->beacon_loss_work); + wdev->vif[wvif->id] = NULL; + wvif->vif = NULL; + + mutex_unlock(&wdev->conf_mutex); + + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + // Combo mode does not support Block Acks. We can re-enable them + if (wvif_count(wdev) == 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + else + hif_set_block_ack_policy(wvif, 0x00, 0x00); + } +} + +int wfx_start(struct ieee80211_hw *hw) +{ + return 0; +} + +void wfx_stop(struct ieee80211_hw *hw) +{ + struct wfx_dev *wdev = hw->priv; + + WARN_ON(!skb_queue_empty_lockless(&wdev->tx_pending)); +} diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h new file mode 100644 index 000000000000..d7b5df5ea4e6 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of mac80211 API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_STA_H +#define WFX_STA_H + +#include + +struct wfx_dev; +struct wfx_vif; + +struct wfx_sta_priv { + int link_id; + int vif_id; +}; + +// mac80211 interface +int wfx_start(struct ieee80211_hw *hw); +void wfx_stop(struct ieee80211_hw *hw); +int wfx_config(struct ieee80211_hw *hw, u32 changed); +int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +void wfx_set_default_unicast_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int idx); +void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 unused); + +int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params); +void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed); +int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, struct ieee80211_sta *sta); +int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); +int wfx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params); +int wfx_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf); +void wfx_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf); +void wfx_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, u32 changed); +int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf); +void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf); + +// WSM Callbacks +void wfx_cooling_timeout_work(struct work_struct *work); +void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd); +void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd cmd); +void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi); +int wfx_update_pm(struct wfx_vif *wvif); + +// Other Helpers +void wfx_reset(struct wfx_vif *wvif); +u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates); + +#endif /* WFX_STA_H */ From patchwork Wed Nov 4 15:52:03 2020 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: 318389 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 D0866C4741F for ; Wed, 4 Nov 2020 15:54:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 691FB2236F for ; Wed, 4 Nov 2020 15:54:50 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="QzlS57fj" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729263AbgKDPyK (ORCPT ); Wed, 4 Nov 2020 10:54:10 -0500 Received: from mail-dm6nam11on2049.outbound.protection.outlook.com ([40.107.223.49]:54240 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730793AbgKDPyF (ORCPT ); Wed, 4 Nov 2020 10:54:05 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=OGdXCnKgz8twCdEdrYN8h7MpVXKXRbZBGrIFb7VbqBYtRQ0S8y4FDQhXiHkpyUNQfq9fh65wBK7tL2FFVsUAsp7j95hQTuBXmJIxZ8MILTnOQDnO32AsaQK4MeMp02KD5baFqkJ3mZX+q/2p2KMMt6yaQsBvH3C6PfBinFqstchOYovA5enG3En8oeT8Pqj5+1waPUY/YIF4AwU11q1qRPmYEiFtFv+QSD/YXo7cj0qe8zt4NVn3Dkjk2gHMhv0IYaHyGYJT3opQXgOEr+AV7itG8Ry8zYWdvQEXcDG34OjIqq6KqwCGk2wGujvQvQz/EqD98L22+Q9MztE5LkqUIA== 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-SenderADCheck; bh=yVDm7W0akEUjkcRCCEJ1oAdvjNfySJu4A7QXWZ6KM9c=; b=LHDVJuT9HLTvs3xveQkZXbW/CGZR9ioH9ghMAld4rDtQIiMAJY+PfsVvvHcO+A1sxI6793afVmLTlE8LUQZEiGmbE2ozasQDhBFPapwpbbKE3wg/AqoWyOtLgSrHvgu0Elng5NT7cghvJ7MsqHaUvGR2dc+M8Fzthna4e8eyIix2aDGl6zDcV/vIQiSzH2YP75xUEQZ4eU5/Oc17W+0nFg/KBbr9WVXPg9G/fzua91Y0ak9lx9v3XxJsRa+lALzitRsdpX+lZGWVbhOLKpRorRMzLZ7HqMsBZE5BFjJqF9wRz/2wP9p1MLYIubYVRHYAv1uoWWV4VYcEc6Saarou7A== 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=yVDm7W0akEUjkcRCCEJ1oAdvjNfySJu4A7QXWZ6KM9c=; b=QzlS57fj1TPePuA0tghB61T6y7mKNYCBCzN2Wzn6YUPyvWpMU0baSCogiGxUvtHV9Uo+hpOueASwOQBzQ3YRbL3Aqoh201vocCeC0OoLC+v2Lbo5DgSvCkWxwDSG3gEqpj8aSEoyS5m9Ud+JYA/oDbXrYAj2WTssD2IcVTCg7YQ= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:53:07 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:53:07 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 20/24] wfx: add scan.c/scan.h Date: Wed, 4 Nov 2020 16:52:03 +0100 Message-Id: <20201104155207.128076-21-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:53:05 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 2111db74-c80c-41e2-0b95-08d880d9b8d6 X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:3044; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: zxjxpE1KLE65msAzpbjvohBUmztn8ZyN3J+GZsP5NprS/995PCh5nRgZCNtEuFAoudKb5yNUDx3IylkIiDs80RPdodcRnBy/2IWkPMP7qh8czaVDqsvP8wPP2ybU2kb+Cybw/3cZh4WknCHtKljpE6CUriWrH/6c5gR2T3tORUeg2R0sfq0SCYzyOQiMZ5cptqdygaHFQGbWEWs7xXbPjKGP3p+Qh4qzWY1xrEQ0PqVZu3kztGjO5fFsULKFw4EJhdG7w4ACa3gwkLi4zdF24r24srmLRXRhBSen9KScso67jbSFNcTRQRjkhxK7dAgAgEIr0KDhST3oVYf7EZ5Iiw== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(83380400001)(26005)(54906003)(107886003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: A/SYxuJT8i/ZLfL4Cj7oor+30Cl6KQnKrAu46lfk4M1DyL9iRYiOziRoVUS2HpxHyige0+Gv1rOhMLp/6FVFGe4+3IVAzvw1n4tgOkvPaa/IX+mZ0N7MPLagWKeyyHLa8bHserb8hcANDbD0J13NoWpAmw+VpkdemhJAAg7/IP8WTkE8TNFMm7koLhuWN/q5nIUsJgzAlbZ6H1zNQNqne4BRNMgdfs/s0/qEQGDMmLLM6bkulx3WpmYI85S2IMYQ7HCvH/bgA7oRWHG4Q2+UCHyWqB5iWD7CXxgOxUPzRv9r4k5XJXL7jijL1JN0+kn5DWtC9KMGuCxtHa3JrxVUFGrqTeXzNdk8wxna0lz+81o+SvIen3nrJo/Tj+MDqFl7l1j3MhII70mWnJwQVHeTmLWlW45EkpiAQupXQj3nPLsKR0H8lTewY24i6cb346vj4AqGdX6AlDgq1bq70o5a4tZo0XP8KrXI6b96poYUZOpswUetkfuw6XUyfOcODUgzo/MISSyNIV6KOUqBxZkVmlBWPzCOvGRXpBlw4e1XN/CRhOrSxU2vv5dCgUFkUXUFak/Vl0cXGiFTQ5tUcqpW3GhHKQeAJvtw58+vYg863SbWkHYGgilCb+X+5w1ILknjZwosTtT424b6Uj8WhWAihA== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 2111db74-c80c-41e2-0b95-08d880d9b8d6 X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:53:07.2477 (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: N13SJemkdjMltNFeGXGTpTa583C3lfNcfAG2ktzYXIEzvqStxkwS4ZYjb+oTTwPQLCpjptDZxZ0OsKExT3F4fw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/scan.c | 132 +++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/scan.h | 22 +++++ 2 files changed, 154 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/scan.c create mode 100644 drivers/net/wireless/silabs/wfx/scan.h diff --git a/drivers/net/wireless/silabs/wfx/scan.c b/drivers/net/wireless/silabs/wfx/scan.c new file mode 100644 index 000000000000..fb47c7cddf2f --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/scan.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Scan related functions. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include + +#include "scan.h" +#include "wfx.h" +#include "sta.h" +#include "hif_tx_mib.h" + +static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw, + bool aborted) +{ + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + + ieee80211_scan_completed(hw, &info); +} + +static int update_probe_tmpl(struct wfx_vif *wvif, + struct cfg80211_scan_request *req) +{ + struct sk_buff *skb; + + skb = ieee80211_probereq_get(wvif->wdev->hw, wvif->vif->addr, + NULL, 0, req->ie_len); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, req->ie, req->ie_len); + hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBREQ, 0); + dev_kfree_skb(skb); + return 0; +} + +static int send_scan_req(struct wfx_vif *wvif, + struct cfg80211_scan_request *req, int start_idx) +{ + int i, ret, timeout; + struct ieee80211_channel *ch_start, *ch_cur; + + for (i = start_idx; i < req->n_channels; i++) { + ch_start = req->channels[start_idx]; + ch_cur = req->channels[i]; + WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported"); + if (ch_cur->max_power != ch_start->max_power) + break; + if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR) + break; + } + wfx_tx_lock_flush(wvif->wdev); + wvif->scan_abort = false; + reinit_completion(&wvif->scan_complete); + ret = hif_scan(wvif, req, start_idx, i - start_idx, &timeout); + if (ret) { + wfx_tx_unlock(wvif->wdev); + return -EIO; + } + ret = wait_for_completion_timeout(&wvif->scan_complete, timeout); + if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower) + hif_set_output_power(wvif, wvif->vif->bss_conf.txpower); + wfx_tx_unlock(wvif->wdev); + if (!ret) { + dev_notice(wvif->wdev->dev, "scan timeout\n"); + hif_stop_scan(wvif); + return -ETIMEDOUT; + } + if (wvif->scan_abort) { + dev_notice(wvif->wdev->dev, "scan abort\n"); + return -ECONNABORTED; + } + return i - start_idx; +} + +/* + * It is not really necessary to run scan request asynchronously. However, + * there is a bug in "iw scan" when ieee80211_scan_completed() is called before + * wfx_hw_scan() return + */ +void wfx_hw_scan_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work); + struct ieee80211_scan_request *hw_req = wvif->scan_req; + int chan_cur, ret; + + mutex_lock(&wvif->wdev->conf_mutex); + mutex_lock(&wvif->scan_lock); + if (wvif->join_in_progress) { + dev_info(wvif->wdev->dev, "%s: abort in-progress REQ_JOIN", + __func__); + wfx_reset(wvif); + } + update_probe_tmpl(wvif, &hw_req->req); + chan_cur = 0; + do { + ret = send_scan_req(wvif, &hw_req->req, chan_cur); + if (ret > 0) + chan_cur += ret; + } while (ret > 0 && chan_cur < hw_req->req.n_channels); + mutex_unlock(&wvif->scan_lock); + mutex_unlock(&wvif->wdev->conf_mutex); + __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0); +} + +int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS); + wvif->scan_req = hw_req; + schedule_work(&wvif->scan_work); + return 0; +} + +void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wvif->scan_abort = true; + hif_stop_scan(wvif); +} + +void wfx_scan_complete(struct wfx_vif *wvif) +{ + complete(&wvif->scan_complete); +} diff --git a/drivers/net/wireless/silabs/wfx/scan.h b/drivers/net/wireless/silabs/wfx/scan.h new file mode 100644 index 000000000000..c7496a766478 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/scan.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Scan related functions. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_SCAN_H +#define WFX_SCAN_H + +#include + +struct wfx_dev; +struct wfx_vif; + +void wfx_hw_scan_work(struct work_struct *work); +int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *req); +void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_scan_complete(struct wfx_vif *wvif); + +#endif /* WFX_SCAN_H */ From patchwork Wed Nov 4 15:52:04 2020 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: 318388 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 6AC2CC4742C for ; Wed, 4 Nov 2020 15:55:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1333A2236F for ; Wed, 4 Nov 2020 15:55:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="TnOvi9U1" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730958AbgKDPzE (ORCPT ); Wed, 4 Nov 2020 10:55:04 -0500 Received: from mail-dm6nam11on2049.outbound.protection.outlook.com ([40.107.223.49]:54240 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1731226AbgKDPyJ (ORCPT ); Wed, 4 Nov 2020 10:54:09 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=GZtQ6XVHnY6BYbel55EMpkw8R8zvNBrWcqAnyfm49TV9OOekaLA5tcn0pmEvqzVDwP/n9XOGorbZgVXw/DMm6hAplJgIfJH5tNCHYlk30AClF7yLzbUc/me2zNpq6zl+rCujY/CyLU0yk1JWJ9G1DffhoFizpLG+AEJVb54eHWQO0MIegPMKV8muI9qMZbO+SNMXqPS0Pqv2eUYBmKORnY8UtXcTkZeOyWoV6Xdp02QrYkG+EzYFcSXAB6xiUHt9xm79CUSdtAjcKo6ynN2gbOEzoZOHLhiIiZAbVV1dJ7qlh0LbKxHALbV2vW1W72y1jWIPcMWEzf6OuLdjKOTRGw== 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-SenderADCheck; bh=pzx7GjJTdUPKiaaRd4bh260anBlAccYiK+Ov2BmVArQ=; b=gMkNFLZkjuYim2Q2OqWvYmtkyfz7FvWQflwDAULGcQdCx1WKvu/+jN8HOtvxUhLB9QHXWFPYDeWy2h3DcWqD1NiQ0mbSJl80hfrTgMStNWvSZIRjDMoRO7a/OL+H5dj1xanq5MXHhwGZ2U+KBS8ylqLaiCXvHTSHzmY49dDmq/OiDf4N4l9s2U8rDBUesNDsgqRBuTYVRacftJstFjBySGeCEQm1T3DftL34yc+pRvfhSRFNwgXQxmMH/9g4NX+SKsrmCkW5TVEYBVxn47FgNbivd8h7yA4BGZT512oJRYTppANmhXetHMUCzuy8DjNBZesKDKQbucaz/pQG7xN7NQ== 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=pzx7GjJTdUPKiaaRd4bh260anBlAccYiK+Ov2BmVArQ=; b=TnOvi9U1gLW0Yfi8eZ3QsJFJVODuMgxWODjFmgQnAnhtTp6oDV0PN9S/sSJRE2MRi8CJN9Vg9Ai/gMdPMwlGUPhGmZTtZbJAYesuEgTzJ5nB3QrymCF2kHooeV1nyEOP7LX4EmWbWnq8YcTx2XOsiN6BtFdIuzTuDC13rN4yZTo= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:53:09 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:53:09 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 21/24] wfx: add debug.c/debug.h Date: Wed, 4 Nov 2020 16:52:04 +0100 Message-Id: <20201104155207.128076-22-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:53:07 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: a990c66c-2dc9-4649-7a3b-08d880d9ba24 X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:989; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 4ttSELqhggrOuo2/nbKCBEJzc8hJeBBsUVgxQ4cKKjrvgthA1rGk4R8EfetaR2f19DXuyBT4G0fYxzqzxKzIHFNH4NL+fTYEc9Cm5Sbu3YZAZy5VQLChVX3948B4wQ3QdAB1Oy1CWHDUVUy83QC1wYIDJH/SPRJXhqDwrcmSaAiBF7zzah1e1oggyEjRipmCRy+Q2jApHE7rZnph7qAzanz4gTMQUxI1VBV+ntwF84zWtv0B/a8Kn/m7qfK2hh4LAnBhBsXUdSFqKsKtnjivkkiRWGzGjf6U7Vg6ZWkB06r5HXzKihJrKBPYhEkNM0x6UKq0iqVMR4T1Zrv/fLzKJQ== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(6666004)(83380400001)(26005)(54906003)(107886003)(30864003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: usfcgO9Cs0shBF5xYyO73TXzFe6rLMtW0RXhl67owijNg2986NSs2n2i/JVnNXWKwYsvKXDis8o1MSLDro/gGFOpa0UWT9H+LXBiifcNVbO82QVS6Eeh4AD8J+nxZ2aJmcDUR45a6n/9OEARRX6VCjk8mnBdKDGy28CFyokkVXeehAZsWTREdURuGeOhtzmqCJG8ape5Fljo6u8BPNYE4UYAefptTeIxLAPwXCmmxH8uGFSwuKLxNHXNKiEPGJVOELUY64D1oEuj30+x0H7pdWi2H+VZpWxXBdAn1cljxahO+8BNDoRoKMQPHUwUyorpa7eKAGVMEIpV96HPiIweQFbQVTFvO94T5g+Yp5YMT7kvBeOK7JTHUQ5mkDnHqblIxEDAAG3fMdGFZ65LkSL0tR+I16L2rh+1sXnAQTfFzCQNlIChsdRMxaetbamywcbD5VNs8IlAH2ZEKgQqoMnl3GvFJLJEf7LuHWDMEVYn7LjWWji4nz1K/yt5FbVmXnG+vLGnT8cyXKFpnmUMterya+cy2CTf2lhuk8Yh4LKxgwp40vJXzl2sfTvzKq8pA003z+ERPIoA2xSE/LDiXNVSmdZqa25ZIzoSloKZRE2MmfViZ4P0y9NrDD6qzs/Gx5qpy5nvlDf1m4MuNSlHuu5L/A== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: a990c66c-2dc9-4649-7a3b-08d880d9ba24 X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:53:09.4665 (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: a1mg/Z09Vki/hZaicwOtLF3vniYSsl+feDWo+kIkRMnYMeCpjtDVMgcitvMPA0vIrOJyyPaAFEA4HJFbEx4S6A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 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/debug.c | 359 ++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/debug.h | 19 ++ 2 files changed, 378 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/debug.c create mode 100644 drivers/net/wireless/silabs/wfx/debug.h diff --git a/drivers/net/wireless/silabs/wfx/debug.c b/drivers/net/wireless/silabs/wfx/debug.c new file mode 100644 index 000000000000..eedada78c25f --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/debug.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Debugfs interface. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include +#include + +#include "debug.h" +#include "wfx.h" +#include "sta.h" +#include "main.h" +#include "hif_tx.h" +#include "hif_tx_mib.h" + +#define CREATE_TRACE_POINTS +#include "traces.h" + +static const struct trace_print_flags hif_msg_print_map[] = { + hif_msg_list, +}; + +static const struct trace_print_flags hif_mib_print_map[] = { + hif_mib_list, +}; + +static const struct trace_print_flags wfx_reg_print_map[] = { + wfx_reg_list, +}; + +static const char *get_symbol(unsigned long val, + const struct trace_print_flags *symbol_array) +{ + int i; + + for (i = 0; symbol_array[i].mask != -1; i++) { + if (val == symbol_array[i].mask) + return symbol_array[i].name; + } + + return "unknown"; +} + +const char *get_hif_name(unsigned long id) +{ + return get_symbol(id, hif_msg_print_map); +} + +const char *get_mib_name(unsigned long id) +{ + return get_symbol(id, hif_mib_print_map); +} + +const char *get_reg_name(unsigned long id) +{ + return get_symbol(id, wfx_reg_print_map); +} + +static int wfx_counters_show(struct seq_file *seq, void *v) +{ + int ret, i; + struct wfx_dev *wdev = seq->private; + struct hif_mib_extended_count_table counters[3]; + + for (i = 0; i < ARRAY_SIZE(counters); i++) { + ret = hif_get_counters_table(wdev, i, counters + i); + if (ret < 0) + return ret; + if (ret > 0) + return -EIO; + } + + seq_printf(seq, "%-24s %12s %12s %12s\n", + "", "global", "iface 0", "iface 1"); + +#define PUT_COUNTER(name) \ + seq_printf(seq, "%-24s %12d %12d %12d\n", #name, \ + le32_to_cpu(counters[2].count_##name), \ + le32_to_cpu(counters[0].count_##name), \ + le32_to_cpu(counters[1].count_##name)) + + PUT_COUNTER(tx_packets); + PUT_COUNTER(tx_multicast_frames); + PUT_COUNTER(tx_frames_success); + PUT_COUNTER(tx_frame_failures); + PUT_COUNTER(tx_frames_retried); + PUT_COUNTER(tx_frames_multi_retried); + + PUT_COUNTER(rts_success); + PUT_COUNTER(rts_failures); + PUT_COUNTER(ack_failures); + + PUT_COUNTER(rx_packets); + PUT_COUNTER(rx_frames_success); + PUT_COUNTER(rx_packet_errors); + PUT_COUNTER(plcp_errors); + PUT_COUNTER(fcs_errors); + PUT_COUNTER(rx_decryption_failures); + PUT_COUNTER(rx_mic_failures); + PUT_COUNTER(rx_no_key_failures); + PUT_COUNTER(rx_frame_duplicates); + PUT_COUNTER(rx_multicast_frames); + PUT_COUNTER(rx_cmacicv_errors); + PUT_COUNTER(rx_cmac_replays); + PUT_COUNTER(rx_mgmt_ccmp_replays); + + PUT_COUNTER(rx_beacon); + PUT_COUNTER(miss_beacon); + +#undef PUT_COUNTER + + for (i = 0; i < ARRAY_SIZE(counters[0].reserved); i++) + seq_printf(seq, "reserved[%02d]%12s %12d %12d %12d\n", i, "", + le32_to_cpu(counters[2].reserved[i]), + le32_to_cpu(counters[0].reserved[i]), + le32_to_cpu(counters[1].reserved[i])); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(wfx_counters); + +static const char * const channel_names[] = { + [0] = "1M", + [1] = "2M", + [2] = "5.5M", + [3] = "11M", + /* Entries 4 and 5 does not exist */ + [6] = "6M", + [7] = "9M", + [8] = "12M", + [9] = "18M", + [10] = "24M", + [11] = "36M", + [12] = "48M", + [13] = "54M", + [14] = "MCS0", + [15] = "MCS1", + [16] = "MCS2", + [17] = "MCS3", + [18] = "MCS4", + [19] = "MCS5", + [20] = "MCS6", + [21] = "MCS7", +}; + +static int wfx_rx_stats_show(struct seq_file *seq, void *v) +{ + struct wfx_dev *wdev = seq->private; + struct hif_rx_stats *st = &wdev->rx_stats; + int i; + + mutex_lock(&wdev->rx_stats_lock); + seq_printf(seq, "Timestamp: %dus\n", st->date); + seq_printf(seq, "Low power clock: frequency %uHz, external %s\n", + le32_to_cpu(st->pwr_clk_freq), + st->is_ext_pwr_clk ? "yes" : "no"); + seq_printf(seq, + "Num. of frames: %d, PER (x10e4): %d, Throughput: %dKbps/s\n", + st->nb_rx_frame, st->per_total, st->throughput); + seq_puts(seq, " Num. of PER RSSI SNR CFO\n"); + seq_puts(seq, " frames (x10e4) (dBm) (dB) (kHz)\n"); + for (i = 0; i < ARRAY_SIZE(channel_names); i++) { + if (channel_names[i]) + seq_printf(seq, "%5s %8d %8d %8d %8d %8d\n", + channel_names[i], + le32_to_cpu(st->nb_rx_by_rate[i]), + le16_to_cpu(st->per[i]), + (s16)le16_to_cpu(st->rssi[i]) / 100, + (s16)le16_to_cpu(st->snr[i]) / 100, + (s16)le16_to_cpu(st->cfo[i])); + } + mutex_unlock(&wdev->rx_stats_lock); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats); + +static int wfx_tx_power_loop_show(struct seq_file *seq, void *v) +{ + struct wfx_dev *wdev = seq->private; + struct hif_tx_power_loop_info *st = &wdev->tx_power_loop_info; + int tmp; + + mutex_lock(&wdev->tx_power_loop_info_lock); + tmp = le16_to_cpu(st->tx_gain_dig); + seq_printf(seq, "Tx gain digital: %d\n", tmp); + tmp = le16_to_cpu(st->tx_gain_pa); + seq_printf(seq, "Tx gain PA: %d\n", tmp); + tmp = (s16)le16_to_cpu(st->target_pout); + seq_printf(seq, "Target Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); + tmp = (s16)le16_to_cpu(st->p_estimation); + seq_printf(seq, "FEM Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); + tmp = le16_to_cpu(st->vpdet); + seq_printf(seq, "Vpdet: %d mV\n", tmp); + seq_printf(seq, "Measure index: %d\n", st->measurement_index); + mutex_unlock(&wdev->tx_power_loop_info_lock); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(wfx_tx_power_loop); + +static ssize_t wfx_send_pds_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wfx_dev *wdev = file->private_data; + char *buf; + int ret; + + if (*ppos != 0) { + dev_dbg(wdev->dev, "PDS data must be written in one transaction"); + return -EBUSY; + } + buf = memdup_user(user_buf, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + *ppos = *ppos + count; + ret = wfx_send_pds(wdev, buf, count); + kfree(buf); + if (ret < 0) + return ret; + return count; +} + +static const struct file_operations wfx_send_pds_fops = { + .open = simple_open, + .write = wfx_send_pds_write, +}; + +struct dbgfs_hif_msg { + struct wfx_dev *wdev; + struct completion complete; + u8 reply[1024]; + int ret; +}; + +static ssize_t wfx_send_hif_msg_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dbgfs_hif_msg *context = file->private_data; + struct wfx_dev *wdev = context->wdev; + struct hif_msg *request; + + if (completion_done(&context->complete)) { + dev_dbg(wdev->dev, "read previous result before start a new one\n"); + return -EBUSY; + } + if (count < sizeof(struct hif_msg)) + return -EINVAL; + + // wfx_cmd_send() checks that reply buffer is wide enough, but does not + // return precise length read. User have to know how many bytes should + // be read. Filling reply buffer with a memory pattern may help user. + memset(context->reply, 0xFF, sizeof(context->reply)); + request = memdup_user(user_buf, count); + if (IS_ERR(request)) + return PTR_ERR(request); + if (le16_to_cpu(request->len) != count) { + kfree(request); + return -EINVAL; + } + context->ret = wfx_cmd_send(wdev, request, context->reply, + sizeof(context->reply), false); + + kfree(request); + complete(&context->complete); + return count; +} + +static ssize_t wfx_send_hif_msg_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dbgfs_hif_msg *context = file->private_data; + int ret; + + if (count > sizeof(context->reply)) + return -EINVAL; + ret = wait_for_completion_interruptible(&context->complete); + if (ret) + return ret; + if (context->ret < 0) + return context->ret; + // Be careful, write() is waiting for a full message while read() + // only returns a payload + if (copy_to_user(user_buf, context->reply, count)) + return -EFAULT; + + return count; +} + +static int wfx_send_hif_msg_open(struct inode *inode, struct file *file) +{ + struct dbgfs_hif_msg *context = kzalloc(sizeof(*context), GFP_KERNEL); + + if (!context) + return -ENOMEM; + context->wdev = inode->i_private; + init_completion(&context->complete); + file->private_data = context; + return 0; +} + +static int wfx_send_hif_msg_release(struct inode *inode, struct file *file) +{ + struct dbgfs_hif_msg *context = file->private_data; + + kfree(context); + return 0; +} + +static const struct file_operations wfx_send_hif_msg_fops = { + .open = wfx_send_hif_msg_open, + .release = wfx_send_hif_msg_release, + .write = wfx_send_hif_msg_write, + .read = wfx_send_hif_msg_read, +}; + +static int wfx_ps_timeout_set(void *data, u64 val) +{ + struct wfx_dev *wdev = (struct wfx_dev *)data; + struct wfx_vif *wvif; + + wdev->force_ps_timeout = val; + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_update_pm(wvif); + return 0; +} + +static int wfx_ps_timeout_get(void *data, u64 *val) +{ + struct wfx_dev *wdev = (struct wfx_dev *)data; + + *val = wdev->force_ps_timeout; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(wfx_ps_timeout_fops, wfx_ps_timeout_get, wfx_ps_timeout_set, "%lld\n"); + +int wfx_debug_init(struct wfx_dev *wdev) +{ + struct dentry *d; + + d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir); + debugfs_create_file("counters", 0444, d, wdev, &wfx_counters_fops); + debugfs_create_file("rx_stats", 0444, d, wdev, &wfx_rx_stats_fops); + debugfs_create_file("tx_power_loop", 0444, d, wdev, + &wfx_tx_power_loop_fops); + debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops); + debugfs_create_file("send_hif_msg", 0600, d, wdev, + &wfx_send_hif_msg_fops); + debugfs_create_file("ps_timeout", 0600, d, wdev, &wfx_ps_timeout_fops); + + return 0; +} diff --git a/drivers/net/wireless/silabs/wfx/debug.h b/drivers/net/wireless/silabs/wfx/debug.h new file mode 100644 index 000000000000..6f2f84d64c9e --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Debugfs interface. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2011, ST-Ericsson + */ +#ifndef WFX_DEBUG_H +#define WFX_DEBUG_H + +struct wfx_dev; + +int wfx_debug_init(struct wfx_dev *wdev); + +const char *get_hif_name(unsigned long id); +const char *get_mib_name(unsigned long id); +const char *get_reg_name(unsigned long id); + +#endif /* WFX_DEBUG_H */ From patchwork Wed Nov 4 15:52:06 2020 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: 318387 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=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, 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 A0F67C2D0A3 for ; Wed, 4 Nov 2020 15:55:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B797B22280 for ; Wed, 4 Nov 2020 15:55:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=silabs.onmicrosoft.com header.i=@silabs.onmicrosoft.com header.b="SBse8I6v" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731347AbgKDPzQ (ORCPT ); Wed, 4 Nov 2020 10:55:16 -0500 Received: from mail-eopbgr750041.outbound.protection.outlook.com ([40.107.75.41]:2617 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1731281AbgKDPzO (ORCPT ); Wed, 4 Nov 2020 10:55:14 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=BkEvhpvFlbPXzmr68rbZkseT+kYzktQWosuaxFylXkJXME8JAzjkltQSXJt09WS2PwXnriD5HyyscY6sXqURxKTrGrvjtQRjpYzAaSSnZjaP3xmdBHd2e7tUfqv13E+N3VATuOrZZXreSefyHwyEjelmexKJbFyJ5Zt4oVZ8SlMmf1v142Q3ZrWUIiyMDNAifvfiq3JSI1U8B3xDL88WK0ci5kcAhJqSicF/DpsjsrNjKB9+fh7kmimgrx9YAY+A1D8vaCqZ/MlfsQbmz60iR+dP77+PahRwBUaTAwS8hHFahKCCRSmnY3uMaOi2yAI2hvowTJWlwjrM4bu25L1CHA== 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-SenderADCheck; bh=M52oy+hTpHdC262YeWjsYtbAbnSmD+lRrYD/5wjLoFA=; b=Pq9FmO7hrEOLS6kqnJxwwme96qgHmt3jQG60FGqFGEqoQPfMm/BoLEDEljZCTWrBfaooGJ2UYaIHmzLUtkPJTpgrUMJIdZMPbwKB2H57MGFZmlC8g3hmKwRSREim/dF2nE7tgsFNZu1FNj/6fSkJstt6dx0rbjmX3JMyjHLF0xSQEzojC+JdkKTz95WyebgCVV//8BZ3R+SouWMlnUQN4z9PRGOrP4Hq2a+LE7qsMCzfSxpgXTRUIeBYF18d1SxV2KNcwen3ufhf56jj9ENOaB4J0z7+IuW4xVedg1k5l3THoRJqiQpzspKT4azb81BBn82sZK8MkoWqlu1BBCNoMQ== 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=M52oy+hTpHdC262YeWjsYtbAbnSmD+lRrYD/5wjLoFA=; b=SBse8I6vQlrCC3S/c8pbfiUx+SGvnkMm8chm3/g2pBrJSEhOVFLSHYUblfe3eW7c0vV+GrgjTgcKIkUb5UAi6Bmzl2mXrQzRqMoX24mUH/aV1EOQLbUNu9wK9vfY50XdyhPqvqOwUic5nuivIUPj2FoeeB9u5NJ/ktY5GwNs/1g= 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 SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.32; Wed, 4 Nov 2020 15:53:14 +0000 Received: from SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a]) by SN6PR11MB2718.namprd11.prod.outlook.com ([fe80::4f5:fbe5:44a7:cb8a%5]) with mapi id 15.20.3499.032; Wed, 4 Nov 2020 15:53:14 +0000 From: Jerome Pouiller To: linux-wireless@vger.kernel.org, netdev@vger.kernel.org Cc: devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Kalle Valo , "David S . Miller" , devicetree@vger.kernel.org, Rob Herring , linux-mmc@vger.kernel.org, =?utf-8?q?Pali_Roh=C3=A1r?= , Ulf Hansson , =?utf-8?b?SsOpcsO0bWUg?= =?utf-8?q?Pouiller?= Subject: [PATCH v3 23/24] wfx: remove from the staging area Date: Wed, 4 Nov 2020 16:52:06 +0100 Message-Id: <20201104155207.128076-24-Jerome.Pouiller@silabs.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> X-Originating-IP: [82.67.86.106] X-ClientProxiedBy: SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) To SN6PR11MB2718.namprd11.prod.outlook.com (2603:10b6:805:63::18) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from pc-42.silabs.com (82.67.86.106) by SN6PR01CA0032.prod.exchangelabs.com (2603:10b6:805:b6::45) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3499.19 via Frontend Transport; Wed, 4 Nov 2020 15:53:11 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 784537b3-ce54-47c5-1a1a-08d880d9bccb X-MS-TrafficTypeDiagnostic: SN6PR11MB2718: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:5236; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: r7OhjQLSxgM8VLRQ9vHYcpnc/ziH2N4xPw9wBc6hjnAOfJXRxg/s4TSPlb/yp7eE4UYmmXjPpZYEjHTTXu74T4D3T5zzhh09Bsd+f9ucCx4I9mqK8QtCewhvXzJ9IMabjaOotCZtIpYdfevJLDZ+6w1NHAApv4uEwD45LkGZ+gzFFQej0wue+RRdIaAKH8yqfSXOhXDJfZWhgvpelGbXiwqx+havdFIutdrC8GpoHtO5w+yPx/zFxBGjwcmbt7FO9bH3gAZsq+htRz1ZG7qiwV+jTMYFMV/BhdI7yB50hOd4cxVbje4zpqpxJ86hYLFNh2YKMyGX65EEnnsOocxNrU8bquSMjxg9g7Lv6A2PpHecwiFsSQLI99cMJ6HU4f3udeGlym18RdChl8S2X9cKc8C7Gsnd68khgBLmk3oC99qzr3lK6t5nbw+V9o9rduuzi+sgLtP8dXv3hDFfKYbEhA== 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:(366004)(346002)(376002)(39850400004)(136003)(396003)(8936002)(966005)(478600001)(186003)(16526019)(956004)(2616005)(6486002)(8676002)(66574015)(66476007)(66556008)(66946007)(316002)(7696005)(6666004)(83380400001)(26005)(54906003)(107886003)(30864003)(36756003)(52116002)(7416002)(4326008)(5660300002)(86362001)(1076003)(2906002)(21314003)(559001)(579004)(569008); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: WWr6UJ+XCrELwLTHSzKqT6TPh6U50u329H/iiIK9yU3rWXki05Ck1NtY5Zv9Nit0vn4Q6EdPar2t9ZuhJC7DDmJ/9rpiBtz4JIgXOn6GTNG90LtD+OgIDVE+FNmy1SyTRsCAzV1LPECbxjzYizvCIPOtD05ckC9ZlG+g8HEQCRRlAdEsVxRptqJd0Z3ISmmEoxS4WgrBhOFWTklHbd+RxMN00YUNsULMiBLkconOPwtVl2JzqJKowfvGBFte5YzrUEeyCHUNBsoWbnfbGOOxpf8vZZn8MUn+iIPsybR5Fj8fQ5yi/GUSaKmEAqjDpgiS9aY9BXN9U//B4wOf8D4ALQP6XCQ78a/yhsnpAIDv+wOOepFDMiibAi+UUmZ+DjzsPZUg7qPVZApEjH2F+c3k0gqCsE0ImZ8XeD9kcfJRMW5bvMB+nFYbK0NocNCYwxrhDq1jkEFsFUeYC+KT+bwstKNQ+q9v3OJpf/p0J1Qctt1SZULaiWSZKWgTUlg4Dd8+Ct42Wh1RNFIqb0yRC6KW7zw3+fe+4ADDFtdsoeaonFYVrxnCbBjDO9bg2I1fVxRBEa4q9WhBYzpVFdjNQDzPGorcD+WiJK4dX5EpaGtUxCe1PtqjgJAWIRpcCHlYbAnXsyQcaz9wWcsIx39dLHjZ2A== X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 784537b3-ce54-47c5-1a1a-08d880d9bccb X-MS-Exchange-CrossTenant-AuthSource: SN6PR11MB2718.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Nov 2020 15:53:14.2887 (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: +8ZT6hbEqzFeUGYxA+74nlSntRLt/4BqzL8SeckCxcQMlqRljlXBdIKhapafyojd+FSNu8Eddb82JLmiWbbyeA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR11MB2718 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Jérôme Pouiller Signed-off-by: Jérôme Pouiller --- .../bindings/net/wireless/silabs,wfx.yaml | 125 --- drivers/staging/wfx/Kconfig | 8 - drivers/staging/wfx/Makefile | 25 - drivers/staging/wfx/bh.c | 333 -------- drivers/staging/wfx/bh.h | 33 - drivers/staging/wfx/bus.h | 38 - drivers/staging/wfx/bus_sdio.c | 269 ------ drivers/staging/wfx/bus_spi.c | 271 ------ drivers/staging/wfx/data_rx.c | 93 -- drivers/staging/wfx/data_rx.h | 18 - drivers/staging/wfx/data_tx.c | 585 ------------- drivers/staging/wfx/data_tx.h | 67 -- drivers/staging/wfx/debug.c | 359 -------- drivers/staging/wfx/debug.h | 19 - drivers/staging/wfx/fwio.c | 405 --------- drivers/staging/wfx/fwio.h | 15 - drivers/staging/wfx/hif_api_cmd.h | 553 ------------ drivers/staging/wfx/hif_api_general.h | 267 ------ drivers/staging/wfx/hif_api_mib.h | 343 -------- drivers/staging/wfx/hif_rx.c | 415 --------- drivers/staging/wfx/hif_rx.h | 18 - drivers/staging/wfx/hif_tx.c | 523 ------------ drivers/staging/wfx/hif_tx.h | 60 -- drivers/staging/wfx/hif_tx_mib.c | 324 ------- drivers/staging/wfx/hif_tx_mib.h | 49 -- drivers/staging/wfx/hwio.c | 352 -------- drivers/staging/wfx/hwio.h | 75 -- drivers/staging/wfx/key.c | 241 ------ drivers/staging/wfx/key.h | 20 - drivers/staging/wfx/main.c | 490 ----------- drivers/staging/wfx/main.h | 44 - drivers/staging/wfx/queue.c | 304 ------- drivers/staging/wfx/queue.h | 45 - drivers/staging/wfx/scan.c | 132 --- drivers/staging/wfx/scan.h | 22 - drivers/staging/wfx/sta.c | 807 ------------------ drivers/staging/wfx/sta.h | 73 -- drivers/staging/wfx/traces.h | 501 ----------- drivers/staging/wfx/wfx.h | 166 ---- 39 files changed, 8487 deletions(-) delete mode 100644 drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml delete mode 100644 drivers/staging/wfx/Kconfig delete mode 100644 drivers/staging/wfx/Makefile delete mode 100644 drivers/staging/wfx/bh.c delete mode 100644 drivers/staging/wfx/bh.h delete mode 100644 drivers/staging/wfx/bus.h delete mode 100644 drivers/staging/wfx/bus_sdio.c delete mode 100644 drivers/staging/wfx/bus_spi.c delete mode 100644 drivers/staging/wfx/data_rx.c delete mode 100644 drivers/staging/wfx/data_rx.h delete mode 100644 drivers/staging/wfx/data_tx.c delete mode 100644 drivers/staging/wfx/data_tx.h delete mode 100644 drivers/staging/wfx/debug.c delete mode 100644 drivers/staging/wfx/debug.h delete mode 100644 drivers/staging/wfx/fwio.c delete mode 100644 drivers/staging/wfx/fwio.h delete mode 100644 drivers/staging/wfx/hif_api_cmd.h delete mode 100644 drivers/staging/wfx/hif_api_general.h delete mode 100644 drivers/staging/wfx/hif_api_mib.h delete mode 100644 drivers/staging/wfx/hif_rx.c delete mode 100644 drivers/staging/wfx/hif_rx.h delete mode 100644 drivers/staging/wfx/hif_tx.c delete mode 100644 drivers/staging/wfx/hif_tx.h delete mode 100644 drivers/staging/wfx/hif_tx_mib.c delete mode 100644 drivers/staging/wfx/hif_tx_mib.h delete mode 100644 drivers/staging/wfx/hwio.c delete mode 100644 drivers/staging/wfx/hwio.h delete mode 100644 drivers/staging/wfx/key.c delete mode 100644 drivers/staging/wfx/key.h delete mode 100644 drivers/staging/wfx/main.c delete mode 100644 drivers/staging/wfx/main.h delete mode 100644 drivers/staging/wfx/queue.c delete mode 100644 drivers/staging/wfx/queue.h delete mode 100644 drivers/staging/wfx/scan.c delete mode 100644 drivers/staging/wfx/scan.h delete mode 100644 drivers/staging/wfx/sta.c delete mode 100644 drivers/staging/wfx/sta.h delete mode 100644 drivers/staging/wfx/traces.h delete mode 100644 drivers/staging/wfx/wfx.h diff --git a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml deleted file mode 100644 index 43b5630c0407..000000000000 --- a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml +++ /dev/null @@ -1,125 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -# Copyright (c) 2020, Silicon Laboratories, Inc. -%YAML 1.2 ---- - -$id: http://devicetree.org/schemas/net/wireless/silabs,wfx.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Silicon Labs WFxxx devicetree bindings - -maintainers: - - Jérôme Pouiller - -description: - The WFxxx chip series can be connected via SPI or via SDIO. - - For SDIO':' - - The driver is able to detect a WFxxx chip on SDIO bus by matching its Vendor - ID and Product ID. However, driver will only provide limited features in - this case. Thus declaring WFxxx chip in device tree is recommended (and may - become mandatory in the future). - - In addition, it is recommended to declare a mmc-pwrseq on SDIO host above - WFx. Without it, you may encounter issues with warm boot. The mmc-pwrseq - should be compatible with mmc-pwrseq-simple. Please consult - Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt for more - information. - - For SPI':' - - In add of the properties below, please consult - Documentation/devicetree/bindings/spi/spi-controller.yaml for optional SPI - related properties. - - Note that in add of the properties below, the WFx driver also supports - `mac-address` and `local-mac-address` as described in - Documentation/devicetree/bindings/net/ethernet.txt - -properties: - compatible: - const: silabs,wf200 - reg: - description: - When used on SDIO bus, must be set to 1. When used on SPI bus, it is - the chip select address of the device as defined in the SPI devices - bindings. - maxItems: 1 - spi-max-frequency: - description: (SPI only) Maximum SPI clocking speed of device in Hz. - maxItems: 1 - interrupts: - description: The interrupt line. Triggers IRQ_TYPE_LEVEL_HIGH and - IRQ_TYPE_EDGE_RISING are both supported by the chip and the driver. When - SPI is used, this property is required. When SDIO is used, the "in-band" - interrupt provided by the SDIO bus is used unless an interrupt is defined - in the Device Tree. - maxItems: 1 - reset-gpios: - description: (SPI only) Phandle of gpio that will be used to reset chip - during probe. Without this property, you may encounter issues with warm - boot. (For legacy purpose, the gpio in inverted when compatible == - "silabs,wfx-spi") - - For SDIO, the reset gpio should declared using a mmc-pwrseq. - maxItems: 1 - wakeup-gpios: - description: Phandle of gpio that will be used to wake-up chip. Without this - property, driver will disable most of power saving features. - maxItems: 1 - config-file: - description: Use an alternative file as PDS. Default is `wf200.pds`. Only - necessary for development/debug purpose. - maxItems: 1 - -required: - - compatible - - reg - -examples: - - | - #include - #include - - spi0 { - #address-cells = <1>; - #size-cells = <0>; - - wfx@0 { - compatible = "silabs,wf200"; - pinctrl-names = "default"; - pinctrl-0 = <&wfx_irq &wfx_gpios>; - reg = <0>; - interrupts-extended = <&gpio 16 IRQ_TYPE_EDGE_RISING>; - wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; - spi-max-frequency = <42000000>; - }; - }; - - - | - #include - #include - - wfx_pwrseq: wfx_pwrseq { - compatible = "mmc-pwrseq-simple"; - pinctrl-names = "default"; - pinctrl-0 = <&wfx_reset>; - reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; - }; - - mmc0 { - mmc-pwrseq = <&wfx_pwrseq>; - #address-cells = <1>; - #size-cells = <0>; - - mmc@1 { - compatible = "silabs,wf200"; - pinctrl-names = "default"; - pinctrl-0 = <&wfx_wakeup>; - reg = <1>; - wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; - }; - }; -... diff --git a/drivers/staging/wfx/Kconfig b/drivers/staging/wfx/Kconfig deleted file mode 100644 index 83ee4d0ca8c6..000000000000 --- a/drivers/staging/wfx/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config WFX - tristate "Silicon Labs wireless chips WF200 and further" - depends on MAC80211 - depends on MMC || !MMC # do not allow WFX=y if MMC=m - depends on (SPI || MMC) - help - This is a driver for Silicons Labs WFxxx series (WF200 and further) - chipsets. This chip can be found on SPI or SDIO buses. diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile deleted file mode 100644 index 0e0cc982ceab..000000000000 --- a/drivers/staging/wfx/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Necessary for CREATE_TRACE_POINTS -CFLAGS_debug.o = -I$(src) - -wfx-y := \ - bh.o \ - hwio.o \ - fwio.o \ - hif_tx_mib.o \ - hif_tx.o \ - hif_rx.o \ - queue.o \ - data_tx.o \ - data_rx.o \ - scan.o \ - sta.o \ - key.o \ - main.o \ - sta.o \ - debug.o -wfx-$(CONFIG_SPI) += bus_spi.o -wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o - -obj-$(CONFIG_WFX) += wfx.o diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c deleted file mode 100644 index ed53d0b45592..000000000000 --- a/drivers/staging/wfx/bh.c +++ /dev/null @@ -1,333 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Interrupt bottom half (BH). - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "bh.h" -#include "wfx.h" -#include "hwio.h" -#include "traces.h" -#include "hif_rx.h" -#include "hif_api_cmd.h" - -static void device_wakeup(struct wfx_dev *wdev) -{ - int max_retry = 3; - - if (!wdev->pdata.gpio_wakeup) - return; - if (gpiod_get_value_cansleep(wdev->pdata.gpio_wakeup) > 0) - return; - - if (wfx_api_older_than(wdev, 1, 4)) { - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); - if (!completion_done(&wdev->hif.ctrl_ready)) - usleep_range(2000, 2500); - return; - } - for (;;) { - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); - // completion.h does not provide any function to wait - // completion without consume it (a kind of - // wait_for_completion_done_timeout()). So we have to emulate - // it. - if (wait_for_completion_timeout(&wdev->hif.ctrl_ready, - msecs_to_jiffies(2))) { - complete(&wdev->hif.ctrl_ready); - return; - } else if (max_retry-- > 0) { - // Older firmwares have a race in sleep/wake-up process. - // Redo the process is sufficient to unfreeze the - // chip. - dev_err(wdev->dev, "timeout while wake up chip\n"); - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0); - usleep_range(2000, 2500); - } else { - dev_err(wdev->dev, "max wake-up retries reached\n"); - return; - } - } -} - -static void device_release(struct wfx_dev *wdev) -{ - if (!wdev->pdata.gpio_wakeup) - return; - - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0); -} - -static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf) -{ - struct sk_buff *skb; - struct hif_msg *hif; - size_t alloc_len; - size_t computed_len; - int release_count; - int piggyback = 0; - - WARN(read_len > round_down(0xFFF, 2) * sizeof(u16), - "%s: request exceed WFx capability", __func__); - - // Add 2 to take into account piggyback size - alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2); - skb = dev_alloc_skb(alloc_len); - if (!skb) - return -ENOMEM; - - if (wfx_data_read(wdev, skb->data, alloc_len)) - goto err; - - piggyback = le16_to_cpup((__le16 *)(skb->data + alloc_len - 2)); - _trace_piggyback(piggyback, false); - - hif = (struct hif_msg *)skb->data; - WARN(hif->encrypted & 0x3, "encryption is unsupported"); - if (WARN(read_len < sizeof(struct hif_msg), "corrupted read")) - goto err; - computed_len = le16_to_cpu(hif->len); - computed_len = round_up(computed_len, 2); - if (computed_len != read_len) { - dev_err(wdev->dev, "inconsistent message length: %zu != %zu\n", - computed_len, read_len); - print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, 16, 1, - hif, read_len, true); - goto err; - } - - if (!(hif->id & HIF_ID_IS_INDICATION)) { - (*is_cnf)++; - if (hif->id == HIF_CNF_ID_MULTI_TRANSMIT) - release_count = ((struct hif_cnf_multi_transmit *)hif->body)->num_tx_confs; - else - release_count = 1; - WARN(wdev->hif.tx_buffers_used < release_count, "corrupted buffer counter"); - wdev->hif.tx_buffers_used -= release_count; - } - _trace_hif_recv(hif, wdev->hif.tx_buffers_used); - - if (hif->id != HIF_IND_ID_EXCEPTION && hif->id != HIF_IND_ID_ERROR) { - if (hif->seqnum != wdev->hif.rx_seqnum) - dev_warn(wdev->dev, "wrong message sequence: %d != %d\n", - hif->seqnum, wdev->hif.rx_seqnum); - wdev->hif.rx_seqnum = (hif->seqnum + 1) % (HIF_COUNTER_MAX + 1); - } - - skb_put(skb, le16_to_cpu(hif->len)); - // wfx_handle_rx takes care on SKB livetime - wfx_handle_rx(wdev, skb); - if (!wdev->hif.tx_buffers_used) - wake_up(&wdev->hif.tx_buffers_empty); - - return piggyback; - -err: - if (skb) - dev_kfree_skb(skb); - return -EIO; -} - -static int bh_work_rx(struct wfx_dev *wdev, int max_msg, int *num_cnf) -{ - size_t len; - int i; - int ctrl_reg, piggyback; - - piggyback = 0; - for (i = 0; i < max_msg; i++) { - if (piggyback & CTRL_NEXT_LEN_MASK) - ctrl_reg = piggyback; - else if (try_wait_for_completion(&wdev->hif.ctrl_ready)) - ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, 0); - else - ctrl_reg = 0; - if (!(ctrl_reg & CTRL_NEXT_LEN_MASK)) - return i; - // ctrl_reg units are 16bits words - len = (ctrl_reg & CTRL_NEXT_LEN_MASK) * 2; - piggyback = rx_helper(wdev, len, num_cnf); - if (piggyback < 0) - return i; - if (!(piggyback & CTRL_WLAN_READY)) - dev_err(wdev->dev, "unexpected piggyback value: ready bit not set: %04x\n", - piggyback); - } - if (piggyback & CTRL_NEXT_LEN_MASK) { - ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, piggyback); - complete(&wdev->hif.ctrl_ready); - if (ctrl_reg) - dev_err(wdev->dev, "unexpected IRQ happened: %04x/%04x\n", - ctrl_reg, piggyback); - } - return i; -} - -static void tx_helper(struct wfx_dev *wdev, struct hif_msg *hif) -{ - int ret; - void *data; - bool is_encrypted = false; - size_t len = le16_to_cpu(hif->len); - - WARN(len < sizeof(*hif), "try to send corrupted data"); - - hif->seqnum = wdev->hif.tx_seqnum; - wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1); - - data = hif; - WARN(len > wdev->hw_caps.size_inp_ch_buf, - "%s: request exceed WFx capability: %zu > %d\n", __func__, - len, wdev->hw_caps.size_inp_ch_buf); - len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, len); - ret = wfx_data_write(wdev, data, len); - if (ret) - goto end; - - wdev->hif.tx_buffers_used++; - _trace_hif_send(hif, wdev->hif.tx_buffers_used); -end: - if (is_encrypted) - kfree(data); -} - -static int bh_work_tx(struct wfx_dev *wdev, int max_msg) -{ - struct hif_msg *hif; - int i; - - for (i = 0; i < max_msg; i++) { - hif = NULL; - if (wdev->hif.tx_buffers_used < wdev->hw_caps.num_inp_ch_bufs) { - if (try_wait_for_completion(&wdev->hif_cmd.ready)) { - WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); - hif = wdev->hif_cmd.buf_send; - } else { - hif = wfx_tx_queues_get(wdev); - } - } - if (!hif) - return i; - tx_helper(wdev, hif); - } - return i; -} - -/* In SDIO mode, it is necessary to make an access to a register to acknowledge - * last received message. It could be possible to restrict this acknowledge to - * SDIO mode and only if last operation was rx. - */ -static void ack_sdio_data(struct wfx_dev *wdev) -{ - u32 cfg_reg; - - config_reg_read(wdev, &cfg_reg); - if (cfg_reg & 0xFF) { - dev_warn(wdev->dev, "chip reports errors: %02x\n", - cfg_reg & 0xFF); - config_reg_write_bits(wdev, 0xFF, 0x00); - } -} - -static void bh_work(struct work_struct *work) -{ - struct wfx_dev *wdev = container_of(work, struct wfx_dev, hif.bh); - int stats_req = 0, stats_cnf = 0, stats_ind = 0; - bool release_chip = false, last_op_is_rx = false; - int num_tx, num_rx; - - device_wakeup(wdev); - do { - num_tx = bh_work_tx(wdev, 32); - stats_req += num_tx; - if (num_tx) - last_op_is_rx = false; - num_rx = bh_work_rx(wdev, 32, &stats_cnf); - stats_ind += num_rx; - if (num_rx) - last_op_is_rx = true; - } while (num_rx || num_tx); - stats_ind -= stats_cnf; - - if (last_op_is_rx) - ack_sdio_data(wdev); - if (!wdev->hif.tx_buffers_used && !work_pending(work)) { - device_release(wdev); - release_chip = true; - } - _trace_bh_stats(stats_ind, stats_req, stats_cnf, - wdev->hif.tx_buffers_used, release_chip); -} - -/* - * An IRQ from chip did occur - */ -void wfx_bh_request_rx(struct wfx_dev *wdev) -{ - u32 cur, prev; - - control_reg_read(wdev, &cur); - prev = atomic_xchg(&wdev->hif.ctrl_reg, cur); - complete(&wdev->hif.ctrl_ready); - queue_work(system_highpri_wq, &wdev->hif.bh); - - if (!(cur & CTRL_NEXT_LEN_MASK)) - dev_err(wdev->dev, "unexpected control register value: length field is 0: %04x\n", - cur); - if (prev != 0) - dev_err(wdev->dev, "received IRQ but previous data was not (yet) read: %04x/%04x\n", - prev, cur); -} - -/* - * Driver want to send data - */ -void wfx_bh_request_tx(struct wfx_dev *wdev) -{ - queue_work(system_highpri_wq, &wdev->hif.bh); -} - -/* - * If IRQ is not available, this function allow to manually poll the control - * register and simulate an IRQ ahen an event happened. - * - * Note that the device has a bug: If an IRQ raise while host read control - * register, the IRQ is lost. So, use this function carefully (only duing - * device initialisation). - */ -void wfx_bh_poll_irq(struct wfx_dev *wdev) -{ - ktime_t now, start; - u32 reg; - - WARN(!wdev->poll_irq, "unexpected IRQ polling can mask IRQ"); - start = ktime_get(); - for (;;) { - control_reg_read(wdev, ®); - now = ktime_get(); - if (reg & 0xFFF) - break; - if (ktime_after(now, ktime_add_ms(start, 1000))) { - dev_err(wdev->dev, "time out while polling control register\n"); - return; - } - udelay(200); - } - wfx_bh_request_rx(wdev); -} - -void wfx_bh_register(struct wfx_dev *wdev) -{ - INIT_WORK(&wdev->hif.bh, bh_work); - init_completion(&wdev->hif.ctrl_ready); - init_waitqueue_head(&wdev->hif.tx_buffers_empty); -} - -void wfx_bh_unregister(struct wfx_dev *wdev) -{ - flush_work(&wdev->hif.bh); -} diff --git a/drivers/staging/wfx/bh.h b/drivers/staging/wfx/bh.h deleted file mode 100644 index 78c49329e22a..000000000000 --- a/drivers/staging/wfx/bh.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Interrupt bottom half. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_BH_H -#define WFX_BH_H - -#include -#include -#include - -struct wfx_dev; - -struct wfx_hif { - struct work_struct bh; - struct completion ctrl_ready; - wait_queue_head_t tx_buffers_empty; - atomic_t ctrl_reg; - int rx_seqnum; - int tx_seqnum; - int tx_buffers_used; -}; - -void wfx_bh_register(struct wfx_dev *wdev); -void wfx_bh_unregister(struct wfx_dev *wdev); -void wfx_bh_request_rx(struct wfx_dev *wdev); -void wfx_bh_request_tx(struct wfx_dev *wdev); -void wfx_bh_poll_irq(struct wfx_dev *wdev); - -#endif /* WFX_BH_H */ diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h deleted file mode 100644 index ca04b3da6204..000000000000 --- a/drivers/staging/wfx/bus.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Common bus abstraction layer. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_BUS_H -#define WFX_BUS_H - -#include -#include - -#define WFX_REG_CONFIG 0x0 -#define WFX_REG_CONTROL 0x1 -#define WFX_REG_IN_OUT_QUEUE 0x2 -#define WFX_REG_AHB_DPORT 0x3 -#define WFX_REG_BASE_ADDR 0x4 -#define WFX_REG_SRAM_DPORT 0x5 -#define WFX_REG_SET_GEN_R_W 0x6 -#define WFX_REG_FRAME_OUT 0x7 - -struct hwbus_ops { - int (*copy_from_io)(void *bus_priv, unsigned int addr, - void *dst, size_t count); - int (*copy_to_io)(void *bus_priv, unsigned int addr, - const void *src, size_t count); - int (*irq_subscribe)(void *bus_priv); - int (*irq_unsubscribe)(void *bus_priv); - void (*lock)(void *bus_priv); - void (*unlock)(void *bus_priv); - size_t (*align_size)(void *bus_priv, size_t size); -}; - -extern struct sdio_driver wfx_sdio_driver; -extern struct spi_driver wfx_spi_driver; - -#endif diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c deleted file mode 100644 index e06d7e1ebe9c..000000000000 --- a/drivers/staging/wfx/bus_sdio.c +++ /dev/null @@ -1,269 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * SDIO interface. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include -#include -#include -#include -#include - -#include "bus.h" -#include "wfx.h" -#include "hwio.h" -#include "main.h" -#include "bh.h" - -static const struct wfx_platform_data wfx_sdio_pdata = { - .file_fw = "wfm_wf200", - .file_pds = "wf200.pds", -}; - -struct wfx_sdio_priv { - struct sdio_func *func; - struct wfx_dev *core; - u8 buf_id_tx; - u8 buf_id_rx; - int of_irq; -}; - -static int wfx_sdio_copy_from_io(void *priv, unsigned int reg_id, - void *dst, size_t count) -{ - struct wfx_sdio_priv *bus = priv; - unsigned int sdio_addr = reg_id << 2; - int ret; - - WARN(reg_id > 7, "chip only has 7 registers"); - WARN(((uintptr_t)dst) & 3, "unaligned buffer size"); - WARN(count & 3, "unaligned buffer address"); - - /* Use queue mode buffers */ - if (reg_id == WFX_REG_IN_OUT_QUEUE) - sdio_addr |= (bus->buf_id_rx + 1) << 7; - ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count); - if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) - bus->buf_id_rx = (bus->buf_id_rx + 1) % 4; - - return ret; -} - -static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id, - const void *src, size_t count) -{ - struct wfx_sdio_priv *bus = priv; - unsigned int sdio_addr = reg_id << 2; - int ret; - - WARN(reg_id > 7, "chip only has 7 registers"); - WARN(((uintptr_t)src) & 3, "unaligned buffer size"); - WARN(count & 3, "unaligned buffer address"); - - /* Use queue mode buffers */ - if (reg_id == WFX_REG_IN_OUT_QUEUE) - sdio_addr |= bus->buf_id_tx << 7; - // FIXME: discards 'const' qualifier for src - ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *)src, count); - if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) - bus->buf_id_tx = (bus->buf_id_tx + 1) % 32; - - return ret; -} - -static void wfx_sdio_lock(void *priv) -{ - struct wfx_sdio_priv *bus = priv; - - sdio_claim_host(bus->func); -} - -static void wfx_sdio_unlock(void *priv) -{ - struct wfx_sdio_priv *bus = priv; - - sdio_release_host(bus->func); -} - -static void wfx_sdio_irq_handler(struct sdio_func *func) -{ - struct wfx_sdio_priv *bus = sdio_get_drvdata(func); - - wfx_bh_request_rx(bus->core); -} - -static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv) -{ - struct wfx_sdio_priv *bus = priv; - - sdio_claim_host(bus->func); - wfx_bh_request_rx(bus->core); - sdio_release_host(bus->func); - return IRQ_HANDLED; -} - -static int wfx_sdio_irq_subscribe(void *priv) -{ - struct wfx_sdio_priv *bus = priv; - u32 flags; - int ret; - u8 cccr; - - if (!bus->of_irq) { - sdio_claim_host(bus->func); - ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler); - sdio_release_host(bus->func); - return ret; - } - - sdio_claim_host(bus->func); - cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL); - cccr |= BIT(0); - cccr |= BIT(bus->func->num); - sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL); - sdio_release_host(bus->func); - flags = irq_get_trigger_type(bus->of_irq); - if (!flags) - flags = IRQF_TRIGGER_HIGH; - flags |= IRQF_ONESHOT; - return devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL, - wfx_sdio_irq_handler_ext, flags, - "wfx", bus); -} - -static int wfx_sdio_irq_unsubscribe(void *priv) -{ - struct wfx_sdio_priv *bus = priv; - int ret; - - if (bus->of_irq) - devm_free_irq(&bus->func->dev, bus->of_irq, bus); - sdio_claim_host(bus->func); - ret = sdio_release_irq(bus->func); - sdio_release_host(bus->func); - return ret; -} - -static size_t wfx_sdio_align_size(void *priv, size_t size) -{ - struct wfx_sdio_priv *bus = priv; - - return sdio_align_size(bus->func, size); -} - -static const struct hwbus_ops wfx_sdio_hwbus_ops = { - .copy_from_io = wfx_sdio_copy_from_io, - .copy_to_io = wfx_sdio_copy_to_io, - .irq_subscribe = wfx_sdio_irq_subscribe, - .irq_unsubscribe = wfx_sdio_irq_unsubscribe, - .lock = wfx_sdio_lock, - .unlock = wfx_sdio_unlock, - .align_size = wfx_sdio_align_size, -}; - -static const struct of_device_id wfx_sdio_of_match[] = { - { .compatible = "silabs,wfx-sdio" }, - { .compatible = "silabs,wf200" }, - { }, -}; -MODULE_DEVICE_TABLE(of, wfx_sdio_of_match); - -static int wfx_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - struct device_node *np = func->dev.of_node; - struct wfx_sdio_priv *bus; - int ret; - - if (func->num != 1) { - dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n", - func->num); - return -ENODEV; - } - - bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL); - if (!bus) - return -ENOMEM; - - if (np) { - if (!of_match_node(wfx_sdio_of_match, np)) { - dev_warn(&func->dev, "no compatible device found in DT\n"); - return -ENODEV; - } - bus->of_irq = irq_of_parse_and_map(np, 0); - } else { - dev_warn(&func->dev, - "device is not declared in DT, features will be limited\n"); - // FIXME: ignore VID/PID and only rely on device tree - // return -ENODEV; - } - - bus->func = func; - sdio_set_drvdata(func, bus); - func->card->quirks |= MMC_QUIRK_LENIENT_FN0 | - MMC_QUIRK_BLKSZ_FOR_BYTE_MODE | - MMC_QUIRK_BROKEN_BYTE_MODE_512; - - sdio_claim_host(func); - ret = sdio_enable_func(func); - // Block of 64 bytes is more efficient than 512B for frame sizes < 4k - sdio_set_block_size(func, 64); - sdio_release_host(func); - if (ret) - goto err0; - - bus->core = wfx_init_common(&func->dev, &wfx_sdio_pdata, - &wfx_sdio_hwbus_ops, bus); - if (!bus->core) { - ret = -EIO; - goto err1; - } - - ret = wfx_probe(bus->core); - if (ret) - goto err1; - - return 0; - -err1: - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); -err0: - return ret; -} - -static void wfx_sdio_remove(struct sdio_func *func) -{ - struct wfx_sdio_priv *bus = sdio_get_drvdata(func); - - wfx_release(bus->core); - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); -} - -#define SDIO_VENDOR_ID_SILABS 0x0000 -#define SDIO_DEVICE_ID_SILABS_WF200 0x1000 -static const struct sdio_device_id wfx_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_SILABS, SDIO_DEVICE_ID_SILABS_WF200) }, - // FIXME: ignore VID/PID and only rely on device tree - // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) }, - { }, -}; -MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids); - -struct sdio_driver wfx_sdio_driver = { - .name = "wfx-sdio", - .id_table = wfx_sdio_ids, - .probe = wfx_sdio_probe, - .remove = wfx_sdio_remove, - .drv = { - .owner = THIS_MODULE, - .of_match_table = wfx_sdio_of_match, - } -}; diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c deleted file mode 100644 index a99125d1a30d..000000000000 --- a/drivers/staging/wfx/bus_spi.c +++ /dev/null @@ -1,271 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * SPI interface. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2011, Sagrad Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include -#include -#include -#include -#include - -#include "bus.h" -#include "wfx.h" -#include "hwio.h" -#include "main.h" -#include "bh.h" - -#define SET_WRITE 0x7FFF /* usage: and operation */ -#define SET_READ 0x8000 /* usage: or operation */ - -#define WFX_RESET_INVERTED 1 - -static const struct wfx_platform_data wfx_spi_pdata = { - .file_fw = "wfm_wf200", - .file_pds = "wf200.pds", - .use_rising_clk = true, -}; - -struct wfx_spi_priv { - struct spi_device *func; - struct wfx_dev *core; - struct gpio_desc *gpio_reset; - bool need_swab; -}; - -/* - * WFx chip read data 16bits at time and place them directly into (little - * endian) CPU register. So, chip expect byte order like "B1 B0 B3 B2" (while - * LE is "B0 B1 B2 B3" and BE is "B3 B2 B1 B0") - * - * A little endian host with bits_per_word == 16 should do the right job - * natively. The code below to support big endian host and commonly used SPI - * 8bits. - */ -static int wfx_spi_copy_from_io(void *priv, unsigned int addr, - void *dst, size_t count) -{ - struct wfx_spi_priv *bus = priv; - u16 regaddr = (addr << 12) | (count / 2) | SET_READ; - struct spi_message m; - struct spi_transfer t_addr = { - .tx_buf = ®addr, - .len = sizeof(regaddr), - }; - struct spi_transfer t_msg = { - .rx_buf = dst, - .len = count, - }; - u16 *dst16 = dst; - int ret, i; - - WARN(count % 2, "buffer size must be a multiple of 2"); - - cpu_to_le16s(®addr); - if (bus->need_swab) - swab16s(®addr); - - spi_message_init(&m); - spi_message_add_tail(&t_addr, &m); - spi_message_add_tail(&t_msg, &m); - ret = spi_sync(bus->func, &m); - - if (bus->need_swab && addr == WFX_REG_CONFIG) - for (i = 0; i < count / 2; i++) - swab16s(&dst16[i]); - return ret; -} - -static int wfx_spi_copy_to_io(void *priv, unsigned int addr, - const void *src, size_t count) -{ - struct wfx_spi_priv *bus = priv; - u16 regaddr = (addr << 12) | (count / 2); - // FIXME: use a bounce buffer - u16 *src16 = (void *)src; - int ret, i; - struct spi_message m; - struct spi_transfer t_addr = { - .tx_buf = ®addr, - .len = sizeof(regaddr), - }; - struct spi_transfer t_msg = { - .tx_buf = src, - .len = count, - }; - - WARN(count % 2, "buffer size must be a multiple of 2"); - WARN(regaddr & SET_READ, "bad addr or size overflow"); - - cpu_to_le16s(®addr); - - // Register address and CONFIG content always use 16bit big endian - // ("BADC" order) - if (bus->need_swab) - swab16s(®addr); - if (bus->need_swab && addr == WFX_REG_CONFIG) - for (i = 0; i < count / 2; i++) - swab16s(&src16[i]); - - spi_message_init(&m); - spi_message_add_tail(&t_addr, &m); - spi_message_add_tail(&t_msg, &m); - ret = spi_sync(bus->func, &m); - - if (bus->need_swab && addr == WFX_REG_CONFIG) - for (i = 0; i < count / 2; i++) - swab16s(&src16[i]); - return ret; -} - -static void wfx_spi_lock(void *priv) -{ -} - -static void wfx_spi_unlock(void *priv) -{ -} - -static irqreturn_t wfx_spi_irq_handler(int irq, void *priv) -{ - struct wfx_spi_priv *bus = priv; - - wfx_bh_request_rx(bus->core); - return IRQ_HANDLED; -} - -static int wfx_spi_irq_subscribe(void *priv) -{ - struct wfx_spi_priv *bus = priv; - u32 flags; - - flags = irq_get_trigger_type(bus->func->irq); - if (!flags) - flags = IRQF_TRIGGER_HIGH; - flags |= IRQF_ONESHOT; - return devm_request_threaded_irq(&bus->func->dev, bus->func->irq, NULL, - wfx_spi_irq_handler, IRQF_ONESHOT, - "wfx", bus); -} - -static int wfx_spi_irq_unsubscribe(void *priv) -{ - struct wfx_spi_priv *bus = priv; - - devm_free_irq(&bus->func->dev, bus->func->irq, bus); - return 0; -} - -static size_t wfx_spi_align_size(void *priv, size_t size) -{ - // Most of SPI controllers avoid DMA if buffer size is not 32bit aligned - return ALIGN(size, 4); -} - -static const struct hwbus_ops wfx_spi_hwbus_ops = { - .copy_from_io = wfx_spi_copy_from_io, - .copy_to_io = wfx_spi_copy_to_io, - .irq_subscribe = wfx_spi_irq_subscribe, - .irq_unsubscribe = wfx_spi_irq_unsubscribe, - .lock = wfx_spi_lock, - .unlock = wfx_spi_unlock, - .align_size = wfx_spi_align_size, -}; - -static int wfx_spi_probe(struct spi_device *func) -{ - struct wfx_spi_priv *bus; - int ret; - - if (!func->bits_per_word) - func->bits_per_word = 16; - ret = spi_setup(func); - if (ret) - return ret; - // Trace below is also displayed by spi_setup() if compiled with DEBUG - dev_dbg(&func->dev, "SPI params: CS=%d, mode=%d bits/word=%d speed=%d\n", - func->chip_select, func->mode, func->bits_per_word, - func->max_speed_hz); - if (func->bits_per_word != 16 && func->bits_per_word != 8) - dev_warn(&func->dev, "unusual bits/word value: %d\n", - func->bits_per_word); - if (func->max_speed_hz > 50000000) - dev_warn(&func->dev, "%dHz is a very high speed\n", - func->max_speed_hz); - - bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL); - if (!bus) - return -ENOMEM; - bus->func = func; - if (func->bits_per_word == 8 || IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) - bus->need_swab = true; - spi_set_drvdata(func, bus); - - bus->gpio_reset = devm_gpiod_get_optional(&func->dev, "reset", - GPIOD_OUT_LOW); - if (IS_ERR(bus->gpio_reset)) - return PTR_ERR(bus->gpio_reset); - if (!bus->gpio_reset) { - dev_warn(&func->dev, - "gpio reset is not defined, trying to load firmware anyway\n"); - } else { - gpiod_set_consumer_name(bus->gpio_reset, "wfx reset"); - if (spi_get_device_id(func)->driver_data & WFX_RESET_INVERTED) - gpiod_toggle_active_low(bus->gpio_reset); - gpiod_set_value_cansleep(bus->gpio_reset, 1); - usleep_range(100, 150); - gpiod_set_value_cansleep(bus->gpio_reset, 0); - usleep_range(2000, 2500); - } - - bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata, - &wfx_spi_hwbus_ops, bus); - if (!bus->core) - return -EIO; - - return wfx_probe(bus->core); -} - -static int wfx_spi_remove(struct spi_device *func) -{ - struct wfx_spi_priv *bus = spi_get_drvdata(func); - - wfx_release(bus->core); - return 0; -} - -/* - * For dynamic driver binding, kernel does not use OF to match driver. It only - * use modalias and modalias is a copy of 'compatible' DT node with vendor - * stripped. - */ -static const struct spi_device_id wfx_spi_id[] = { - { "wfx-spi", WFX_RESET_INVERTED }, - { "wf200", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(spi, wfx_spi_id); - -#ifdef CONFIG_OF -static const struct of_device_id wfx_spi_of_match[] = { - { .compatible = "silabs,wfx-spi", .data = (void *)WFX_RESET_INVERTED }, - { .compatible = "silabs,wf200" }, - { }, -}; -MODULE_DEVICE_TABLE(of, wfx_spi_of_match); -#endif - -struct spi_driver wfx_spi_driver = { - .driver = { - .name = "wfx-spi", - .of_match_table = of_match_ptr(wfx_spi_of_match), - }, - .id_table = wfx_spi_id, - .probe = wfx_spi_probe, - .remove = wfx_spi_remove, -}; diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c deleted file mode 100644 index 385f2d42a0e2..000000000000 --- a/drivers/staging/wfx/data_rx.c +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Datapath implementation. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "data_rx.h" -#include "wfx.h" -#include "bh.h" -#include "sta.h" - -static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt) -{ - int params, tid; - - if (wfx_api_older_than(wvif->wdev, 3, 6)) - return; - - switch (mgmt->u.action.u.addba_req.action_code) { - case WLAN_ACTION_ADDBA_REQ: - params = le16_to_cpu(mgmt->u.action.u.addba_req.capab); - tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; - ieee80211_start_rx_ba_session_offl(wvif->vif, mgmt->sa, tid); - break; - case WLAN_ACTION_DELBA: - params = le16_to_cpu(mgmt->u.action.u.delba.params); - tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; - ieee80211_stop_rx_ba_session_offl(wvif->vif, mgmt->sa, tid); - break; - } -} - -void wfx_rx_cb(struct wfx_vif *wvif, - const struct hif_ind_rx *arg, struct sk_buff *skb) -{ - struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); - struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - - memset(hdr, 0, sizeof(*hdr)); - - if (arg->status == HIF_STATUS_RX_FAIL_MIC) - hdr->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_IV_STRIPPED; - else if (arg->status) - goto drop; - - if (skb->len < sizeof(struct ieee80211_pspoll)) { - dev_warn(wvif->wdev->dev, "malformed SDU received\n"); - goto drop; - } - - hdr->band = NL80211_BAND_2GHZ; - hdr->freq = ieee80211_channel_to_frequency(arg->channel_number, - hdr->band); - - if (arg->rxed_rate >= 14) { - hdr->encoding = RX_ENC_HT; - hdr->rate_idx = arg->rxed_rate - 14; - } else if (arg->rxed_rate >= 4) { - hdr->rate_idx = arg->rxed_rate - 2; - } else { - hdr->rate_idx = arg->rxed_rate; - } - - if (!arg->rcpi_rssi) { - hdr->flag |= RX_FLAG_NO_SIGNAL_VAL; - dev_info(wvif->wdev->dev, "received frame without RSSI data\n"); - } - hdr->signal = arg->rcpi_rssi / 2 - 110; - hdr->antenna = 0; - - if (arg->encryp) - hdr->flag |= RX_FLAG_DECRYPTED; - - // Block ack negotiation is offloaded by the firmware. However, - // re-ordering must be done by the mac80211. - if (ieee80211_is_action(frame->frame_control) && - mgmt->u.action.category == WLAN_CATEGORY_BACK && - skb->len > IEEE80211_MIN_ACTION_SIZE) { - wfx_rx_handle_ba(wvif, mgmt); - goto drop; - } - - ieee80211_rx_irqsafe(wvif->wdev->hw, skb); - return; - -drop: - dev_kfree_skb(skb); -} diff --git a/drivers/staging/wfx/data_rx.h b/drivers/staging/wfx/data_rx.h deleted file mode 100644 index 4c0da37f2084..000000000000 --- a/drivers/staging/wfx/data_rx.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Datapath implementation. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_DATA_RX_H -#define WFX_DATA_RX_H - -struct wfx_vif; -struct sk_buff; -struct hif_ind_rx; - -void wfx_rx_cb(struct wfx_vif *wvif, - const struct hif_ind_rx *arg, struct sk_buff *skb); - -#endif /* WFX_DATA_RX_H */ diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c deleted file mode 100644 index 36b36ef39d05..000000000000 --- a/drivers/staging/wfx/data_tx.c +++ /dev/null @@ -1,585 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Datapath implementation. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "data_tx.h" -#include "wfx.h" -#include "bh.h" -#include "sta.h" -#include "queue.h" -#include "debug.h" -#include "traces.h" -#include "hif_tx_mib.h" - -static int wfx_get_hw_rate(struct wfx_dev *wdev, - const struct ieee80211_tx_rate *rate) -{ - struct ieee80211_supported_band *band; - - if (rate->idx < 0) - return -1; - if (rate->flags & IEEE80211_TX_RC_MCS) { - if (rate->idx > 7) { - WARN(1, "wrong rate->idx value: %d", rate->idx); - return -1; - } - return rate->idx + 14; - } - // WFx only support 2GHz, else band information should be retrieved - // from ieee80211_tx_info - band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; - if (rate->idx >= band->n_bitrates) { - WARN(1, "wrong rate->idx value: %d", rate->idx); - return -1; - } - return band->bitrates[rate->idx].hw_value; -} - -/* TX policy cache implementation */ - -static void wfx_tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy, - struct ieee80211_tx_rate *rates) -{ - struct wfx_dev *wdev = wvif->wdev; - int i, rateid; - u8 count; - - WARN(rates[0].idx < 0, "invalid rate policy"); - memset(policy, 0, sizeof(*policy)); - for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) { - if (rates[i].idx < 0) - break; - WARN_ON(rates[i].count > 15); - rateid = wfx_get_hw_rate(wdev, &rates[i]); - // Pack two values in each byte of policy->rates - count = rates[i].count; - if (rateid % 2) - count <<= 4; - policy->rates[rateid / 2] |= count; - } -} - -static bool tx_policy_is_equal(const struct tx_policy *a, - const struct tx_policy *b) -{ - return !memcmp(a->rates, b->rates, sizeof(a->rates)); -} - -static int wfx_tx_policy_find(struct tx_policy_cache *cache, - struct tx_policy *wanted) -{ - struct tx_policy *it; - - list_for_each_entry(it, &cache->used, link) - if (tx_policy_is_equal(wanted, it)) - return it - cache->cache; - list_for_each_entry(it, &cache->free, link) - if (tx_policy_is_equal(wanted, it)) - return it - cache->cache; - return -1; -} - -static void wfx_tx_policy_use(struct tx_policy_cache *cache, - struct tx_policy *entry) -{ - ++entry->usage_count; - list_move(&entry->link, &cache->used); -} - -static int wfx_tx_policy_release(struct tx_policy_cache *cache, - struct tx_policy *entry) -{ - int ret = --entry->usage_count; - - if (!ret) - list_move(&entry->link, &cache->free); - return ret; -} - -static int wfx_tx_policy_get(struct wfx_vif *wvif, - struct ieee80211_tx_rate *rates, bool *renew) -{ - int idx; - struct tx_policy_cache *cache = &wvif->tx_policy_cache; - struct tx_policy wanted; - - wfx_tx_policy_build(wvif, &wanted, rates); - - spin_lock_bh(&cache->lock); - if (list_empty(&cache->free)) { - WARN(1, "unable to get a valid Tx policy"); - spin_unlock_bh(&cache->lock); - return HIF_TX_RETRY_POLICY_INVALID; - } - idx = wfx_tx_policy_find(cache, &wanted); - if (idx >= 0) { - *renew = false; - } else { - struct tx_policy *entry; - *renew = true; - /* If policy is not found create a new one - * using the oldest entry in "free" list - */ - entry = list_entry(cache->free.prev, struct tx_policy, link); - memcpy(entry->rates, wanted.rates, sizeof(entry->rates)); - entry->uploaded = false; - entry->usage_count = 0; - idx = entry - cache->cache; - } - wfx_tx_policy_use(cache, &cache->cache[idx]); - if (list_empty(&cache->free)) - ieee80211_stop_queues(wvif->wdev->hw); - spin_unlock_bh(&cache->lock); - return idx; -} - -static void wfx_tx_policy_put(struct wfx_vif *wvif, int idx) -{ - int usage, locked; - struct tx_policy_cache *cache = &wvif->tx_policy_cache; - - if (idx == HIF_TX_RETRY_POLICY_INVALID) - return; - spin_lock_bh(&cache->lock); - locked = list_empty(&cache->free); - usage = wfx_tx_policy_release(cache, &cache->cache[idx]); - if (locked && !usage) - ieee80211_wake_queues(wvif->wdev->hw); - spin_unlock_bh(&cache->lock); -} - -static int wfx_tx_policy_upload(struct wfx_vif *wvif) -{ - struct tx_policy *policies = wvif->tx_policy_cache.cache; - u8 tmp_rates[12]; - int i, is_used; - - do { - spin_lock_bh(&wvif->tx_policy_cache.lock); - for (i = 0; i < ARRAY_SIZE(wvif->tx_policy_cache.cache); ++i) { - is_used = memzcmp(policies[i].rates, - sizeof(policies[i].rates)); - if (!policies[i].uploaded && is_used) - break; - } - if (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)) { - policies[i].uploaded = true; - memcpy(tmp_rates, policies[i].rates, sizeof(tmp_rates)); - spin_unlock_bh(&wvif->tx_policy_cache.lock); - hif_set_tx_rate_retry_policy(wvif, i, tmp_rates); - } else { - spin_unlock_bh(&wvif->tx_policy_cache.lock); - } - } while (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)); - return 0; -} - -void wfx_tx_policy_upload_work(struct work_struct *work) -{ - struct wfx_vif *wvif = - container_of(work, struct wfx_vif, tx_policy_upload_work); - - wfx_tx_policy_upload(wvif); - wfx_tx_unlock(wvif->wdev); -} - -void wfx_tx_policy_init(struct wfx_vif *wvif) -{ - struct tx_policy_cache *cache = &wvif->tx_policy_cache; - int i; - - memset(cache, 0, sizeof(*cache)); - - spin_lock_init(&cache->lock); - INIT_LIST_HEAD(&cache->used); - INIT_LIST_HEAD(&cache->free); - - for (i = 0; i < ARRAY_SIZE(cache->cache); ++i) - list_add(&cache->cache[i].link, &cache->free); -} - -/* Tx implementation */ - -static bool ieee80211_is_action_back(struct ieee80211_hdr *hdr) -{ - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr; - - if (!ieee80211_is_action(mgmt->frame_control)) - return false; - if (mgmt->u.action.category != WLAN_CATEGORY_BACK) - return false; - return true; -} - -static u8 wfx_tx_get_link_id(struct wfx_vif *wvif, struct ieee80211_sta *sta, - struct ieee80211_hdr *hdr) -{ - struct wfx_sta_priv *sta_priv = - sta ? (struct wfx_sta_priv *)&sta->drv_priv : NULL; - const u8 *da = ieee80211_get_DA(hdr); - - if (sta_priv && sta_priv->link_id) - return sta_priv->link_id; - if (wvif->vif->type != NL80211_IFTYPE_AP) - return 0; - if (is_multicast_ether_addr(da)) - return 0; - return HIF_LINK_ID_NOT_ASSOCIATED; -} - -static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates) -{ - int i; - bool finished; - - // Firmware is not able to mix rates with different flags - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) - rates[i].flags |= IEEE80211_TX_RC_SHORT_GI; - if (!(rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) - rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; - if (!(rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)) - rates[i].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; - } - - // Sort rates and remove duplicates - do { - finished = true; - for (i = 0; i < IEEE80211_TX_MAX_RATES - 1; i++) { - if (rates[i + 1].idx == rates[i].idx && - rates[i].idx != -1) { - rates[i].count += rates[i + 1].count; - if (rates[i].count > 15) - rates[i].count = 15; - rates[i + 1].idx = -1; - rates[i + 1].count = 0; - - finished = false; - } - if (rates[i + 1].idx > rates[i].idx) { - swap(rates[i + 1], rates[i]); - finished = false; - } - } - } while (!finished); - // Ensure that MCS0 or 1Mbps is present at the end of the retry list - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - if (rates[i].idx == 0) - break; - if (rates[i].idx == -1) { - rates[i].idx = 0; - rates[i].count = 8; // == hw->max_rate_tries - rates[i].flags = rates[i - 1].flags & - IEEE80211_TX_RC_MCS; - break; - } - } - // All retries use long GI - for (i = 1; i < IEEE80211_TX_MAX_RATES; i++) - rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; -} - -static u8 wfx_tx_get_rate_id(struct wfx_vif *wvif, - struct ieee80211_tx_info *tx_info) -{ - bool tx_policy_renew = false; - u8 rate_id; - - rate_id = wfx_tx_policy_get(wvif, - tx_info->driver_rates, &tx_policy_renew); - if (rate_id == HIF_TX_RETRY_POLICY_INVALID) - dev_warn(wvif->wdev->dev, "unable to get a valid Tx policy"); - - if (tx_policy_renew) { - wfx_tx_lock(wvif->wdev); - if (!schedule_work(&wvif->tx_policy_upload_work)) - wfx_tx_unlock(wvif->wdev); - } - return rate_id; -} - -static int wfx_tx_get_frame_format(struct ieee80211_tx_info *tx_info) -{ - if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_MCS)) - return HIF_FRAME_FORMAT_NON_HT; - else if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) - return HIF_FRAME_FORMAT_MIXED_FORMAT_HT; - else - return HIF_FRAME_FORMAT_GF_HT_11N; -} - -static int wfx_tx_get_icv_len(struct ieee80211_key_conf *hw_key) -{ - int mic_space; - - if (!hw_key) - return 0; - if (hw_key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) - return 0; - mic_space = (hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) ? 8 : 0; - return hw_key->icv_len + mic_space; -} - -static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, - struct sk_buff *skb) -{ - struct hif_msg *hif_msg; - struct hif_req_tx *req; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - int queue_id = skb_get_queue_mapping(skb); - size_t offset = (size_t)skb->data & 3; - int wmsg_len = sizeof(struct hif_msg) + - sizeof(struct hif_req_tx) + offset; - - WARN(queue_id >= IEEE80211_NUM_ACS, "unsupported queue_id"); - wfx_tx_fixup_rates(tx_info->driver_rates); - - // From now tx_info->control is unusable - memset(tx_info->rate_driver_data, 0, sizeof(struct wfx_tx_priv)); - - // Fill hif_msg - WARN(skb_headroom(skb) < wmsg_len, "not enough space in skb"); - WARN(offset & 1, "attempt to transmit an unaligned frame"); - skb_put(skb, wfx_tx_get_icv_len(hw_key)); - skb_push(skb, wmsg_len); - memset(skb->data, 0, wmsg_len); - hif_msg = (struct hif_msg *)skb->data; - hif_msg->len = cpu_to_le16(skb->len); - hif_msg->id = HIF_REQ_ID_TX; - hif_msg->interface = wvif->id; - if (skb->len > wvif->wdev->hw_caps.size_inp_ch_buf) { - dev_warn(wvif->wdev->dev, - "requested frame size (%d) is larger than maximum supported (%d)\n", - skb->len, wvif->wdev->hw_caps.size_inp_ch_buf); - skb_pull(skb, wmsg_len); - return -EIO; - } - - // Fill tx request - req = (struct hif_req_tx *)hif_msg->body; - // packet_id just need to be unique on device. 32bits are more than - // necessary for that task, so we tae advantage of it to add some extra - // data for debug. - req->packet_id = atomic_add_return(1, &wvif->wdev->packet_id) & 0xFFFF; - req->packet_id |= IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)) << 16; - req->packet_id |= queue_id << 28; - - req->fc_offset = offset; - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - req->after_dtim = 1; - req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr); - // Queue index are inverted between firmware and Linux - req->queue_id = 3 - queue_id; - req->retry_policy_index = wfx_tx_get_rate_id(wvif, tx_info); - req->frame_format = wfx_tx_get_frame_format(tx_info); - if (tx_info->driver_rates[0].flags & IEEE80211_TX_RC_SHORT_GI) - req->short_gi = 1; - - // Auxiliary operations - wfx_tx_queues_put(wvif, skb); - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - schedule_work(&wvif->update_tim_work); - wfx_bh_request_tx(wvif->wdev); - return 0; -} - -void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif; - struct ieee80211_sta *sta = control ? control->sta : NULL; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - size_t driver_data_room = sizeof_field(struct ieee80211_tx_info, - rate_driver_data); - - compiletime_assert(sizeof(struct wfx_tx_priv) <= driver_data_room, - "struct tx_priv is too large"); - WARN(skb->next || skb->prev, "skb is already member of a list"); - // control.vif can be NULL for injected frames - if (tx_info->control.vif) - wvif = (struct wfx_vif *)tx_info->control.vif->drv_priv; - else - wvif = wvif_iterate(wdev, NULL); - if (WARN_ON(!wvif)) - goto drop; - // Because of TX_AMPDU_SETUP_IN_HW, mac80211 does not try to send any - // BlockAck session management frame. The check below exist just in case. - if (ieee80211_is_action_back(hdr)) { - dev_info(wdev->dev, "drop BA action\n"); - goto drop; - } - if (wfx_tx_inner(wvif, sta, skb)) - goto drop; - - return; - -drop: - ieee80211_tx_status_irqsafe(wdev->hw, skb); -} - -static void wfx_skb_dtor(struct wfx_vif *wvif, struct sk_buff *skb) -{ - struct hif_msg *hif = (struct hif_msg *)skb->data; - struct hif_req_tx *req = (struct hif_req_tx *)hif->body; - unsigned int offset = sizeof(struct hif_msg) + - sizeof(struct hif_req_tx) + - req->fc_offset; - - if (!wvif) { - pr_warn("%s: vif associated with the skb does not exist anymore\n", __func__); - return; - } - wfx_tx_policy_put(wvif, req->retry_policy_index); - skb_pull(skb, offset); - ieee80211_tx_status_irqsafe(wvif->wdev->hw, skb); -} - -static void wfx_tx_fill_rates(struct wfx_dev *wdev, - struct ieee80211_tx_info *tx_info, - const struct hif_cnf_tx *arg) -{ - struct ieee80211_tx_rate *rate; - int tx_count; - int i; - - tx_count = arg->ack_failures; - if (!arg->status || arg->ack_failures) - tx_count += 1; // Also report success - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - rate = &tx_info->status.rates[i]; - if (rate->idx < 0) - break; - if (tx_count < rate->count && - arg->status == HIF_STATUS_TX_FAIL_RETRIES && - arg->ack_failures) - dev_dbg(wdev->dev, "all retries were not consumed: %d != %d\n", - rate->count, tx_count); - if (tx_count <= rate->count && tx_count && - arg->txed_rate != wfx_get_hw_rate(wdev, rate)) - dev_dbg(wdev->dev, "inconsistent tx_info rates: %d != %d\n", - arg->txed_rate, wfx_get_hw_rate(wdev, rate)); - if (tx_count > rate->count) { - tx_count -= rate->count; - } else if (!tx_count) { - rate->count = 0; - rate->idx = -1; - } else { - rate->count = tx_count; - tx_count = 0; - } - } - if (tx_count) - dev_dbg(wdev->dev, "%d more retries than expected\n", tx_count); -} - -void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg) -{ - struct ieee80211_tx_info *tx_info; - struct wfx_vif *wvif; - struct sk_buff *skb; - - skb = wfx_pending_get(wdev, arg->packet_id); - if (!skb) { - dev_warn(wdev->dev, "received unknown packet_id (%#.8x) from chip\n", - arg->packet_id); - return; - } - tx_info = IEEE80211_SKB_CB(skb); - wvif = wdev_to_wvif(wdev, ((struct hif_msg *)skb->data)->interface); - WARN_ON(!wvif); - if (!wvif) - return; - - // Note that wfx_pending_get_pkt_us_delay() get data from tx_info - _trace_tx_stats(arg, skb, wfx_pending_get_pkt_us_delay(wdev, skb)); - wfx_tx_fill_rates(wdev, tx_info, arg); - // From now, you can touch to tx_info->status, but do not touch to - // tx_priv anymore - // FIXME: use ieee80211_tx_info_clear_status() - memset(tx_info->rate_driver_data, 0, sizeof(tx_info->rate_driver_data)); - memset(tx_info->pad, 0, sizeof(tx_info->pad)); - - if (!arg->status) { - tx_info->status.tx_time = - le32_to_cpu(arg->media_delay) - - le32_to_cpu(arg->tx_queue_delay); - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; - else - tx_info->flags |= IEEE80211_TX_STAT_ACK; - } else if (arg->status == HIF_STATUS_TX_FAIL_REQUEUE) { - WARN(!arg->requeue, "incoherent status and result_flags"); - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { - wvif->after_dtim_tx_allowed = false; // DTIM period elapsed - schedule_work(&wvif->update_tim_work); - } - tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - } - wfx_skb_dtor(wvif, skb); -} - -static void wfx_flush_vif(struct wfx_vif *wvif, u32 queues, - struct sk_buff_head *dropped) -{ - struct wfx_queue *queue; - int i; - - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - if (!(BIT(i) & queues)) - continue; - queue = &wvif->tx_queue[i]; - if (dropped) - wfx_tx_queue_drop(wvif, queue, dropped); - } - if (wvif->wdev->chip_frozen) - return; - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - if (!(BIT(i) & queues)) - continue; - queue = &wvif->tx_queue[i]; - if (wait_event_timeout(wvif->wdev->tx_dequeue, - wfx_tx_queue_empty(wvif, queue), - msecs_to_jiffies(1000)) <= 0) - dev_warn(wvif->wdev->dev, - "frames queued while flushing tx queues?"); - } -} - -void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop) -{ - struct wfx_dev *wdev = hw->priv; - struct sk_buff_head dropped; - struct wfx_vif *wvif; - struct hif_msg *hif; - struct sk_buff *skb; - - skb_queue_head_init(&dropped); - if (vif) { - wvif = (struct wfx_vif *)vif->drv_priv; - wfx_flush_vif(wvif, queues, drop ? &dropped : NULL); - } else { - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - wfx_flush_vif(wvif, queues, drop ? &dropped : NULL); - } - wfx_tx_flush(wdev); - if (wdev->chip_frozen) - wfx_pending_drop(wdev, &dropped); - while ((skb = skb_dequeue(&dropped)) != NULL) { - hif = (struct hif_msg *)skb->data; - wvif = wdev_to_wvif(wdev, hif->interface); - ieee80211_tx_info_clear_status(IEEE80211_SKB_CB(skb)); - wfx_skb_dtor(wvif, skb); - } -} diff --git a/drivers/staging/wfx/data_tx.h b/drivers/staging/wfx/data_tx.h deleted file mode 100644 index 46c9fff7a870..000000000000 --- a/drivers/staging/wfx/data_tx.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Datapath implementation. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_DATA_TX_H -#define WFX_DATA_TX_H - -#include -#include - -#include "hif_api_cmd.h" -#include "hif_api_mib.h" - -struct wfx_tx_priv; -struct wfx_dev; -struct wfx_vif; - -struct tx_policy { - struct list_head link; - int usage_count; - u8 rates[12]; - bool uploaded; -}; - -struct tx_policy_cache { - struct tx_policy cache[HIF_TX_RETRY_POLICY_MAX]; - // FIXME: use a trees and drop hash from tx_policy - struct list_head used; - struct list_head free; - spinlock_t lock; -}; - -struct wfx_tx_priv { - ktime_t xmit_timestamp; -}; - -void wfx_tx_policy_init(struct wfx_vif *wvif); -void wfx_tx_policy_upload_work(struct work_struct *work); - -void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb); -void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg); -void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop); - -static inline struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb) -{ - struct ieee80211_tx_info *tx_info; - - if (!skb) - return NULL; - tx_info = IEEE80211_SKB_CB(skb); - return (struct wfx_tx_priv *)tx_info->rate_driver_data; -} - -static inline struct hif_req_tx *wfx_skb_txreq(struct sk_buff *skb) -{ - struct hif_msg *hif = (struct hif_msg *)skb->data; - struct hif_req_tx *req = (struct hif_req_tx *)hif->body; - - return req; -} - -#endif /* WFX_DATA_TX_H */ diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c deleted file mode 100644 index eedada78c25f..000000000000 --- a/drivers/staging/wfx/debug.c +++ /dev/null @@ -1,359 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Debugfs interface. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include - -#include "debug.h" -#include "wfx.h" -#include "sta.h" -#include "main.h" -#include "hif_tx.h" -#include "hif_tx_mib.h" - -#define CREATE_TRACE_POINTS -#include "traces.h" - -static const struct trace_print_flags hif_msg_print_map[] = { - hif_msg_list, -}; - -static const struct trace_print_flags hif_mib_print_map[] = { - hif_mib_list, -}; - -static const struct trace_print_flags wfx_reg_print_map[] = { - wfx_reg_list, -}; - -static const char *get_symbol(unsigned long val, - const struct trace_print_flags *symbol_array) -{ - int i; - - for (i = 0; symbol_array[i].mask != -1; i++) { - if (val == symbol_array[i].mask) - return symbol_array[i].name; - } - - return "unknown"; -} - -const char *get_hif_name(unsigned long id) -{ - return get_symbol(id, hif_msg_print_map); -} - -const char *get_mib_name(unsigned long id) -{ - return get_symbol(id, hif_mib_print_map); -} - -const char *get_reg_name(unsigned long id) -{ - return get_symbol(id, wfx_reg_print_map); -} - -static int wfx_counters_show(struct seq_file *seq, void *v) -{ - int ret, i; - struct wfx_dev *wdev = seq->private; - struct hif_mib_extended_count_table counters[3]; - - for (i = 0; i < ARRAY_SIZE(counters); i++) { - ret = hif_get_counters_table(wdev, i, counters + i); - if (ret < 0) - return ret; - if (ret > 0) - return -EIO; - } - - seq_printf(seq, "%-24s %12s %12s %12s\n", - "", "global", "iface 0", "iface 1"); - -#define PUT_COUNTER(name) \ - seq_printf(seq, "%-24s %12d %12d %12d\n", #name, \ - le32_to_cpu(counters[2].count_##name), \ - le32_to_cpu(counters[0].count_##name), \ - le32_to_cpu(counters[1].count_##name)) - - PUT_COUNTER(tx_packets); - PUT_COUNTER(tx_multicast_frames); - PUT_COUNTER(tx_frames_success); - PUT_COUNTER(tx_frame_failures); - PUT_COUNTER(tx_frames_retried); - PUT_COUNTER(tx_frames_multi_retried); - - PUT_COUNTER(rts_success); - PUT_COUNTER(rts_failures); - PUT_COUNTER(ack_failures); - - PUT_COUNTER(rx_packets); - PUT_COUNTER(rx_frames_success); - PUT_COUNTER(rx_packet_errors); - PUT_COUNTER(plcp_errors); - PUT_COUNTER(fcs_errors); - PUT_COUNTER(rx_decryption_failures); - PUT_COUNTER(rx_mic_failures); - PUT_COUNTER(rx_no_key_failures); - PUT_COUNTER(rx_frame_duplicates); - PUT_COUNTER(rx_multicast_frames); - PUT_COUNTER(rx_cmacicv_errors); - PUT_COUNTER(rx_cmac_replays); - PUT_COUNTER(rx_mgmt_ccmp_replays); - - PUT_COUNTER(rx_beacon); - PUT_COUNTER(miss_beacon); - -#undef PUT_COUNTER - - for (i = 0; i < ARRAY_SIZE(counters[0].reserved); i++) - seq_printf(seq, "reserved[%02d]%12s %12d %12d %12d\n", i, "", - le32_to_cpu(counters[2].reserved[i]), - le32_to_cpu(counters[0].reserved[i]), - le32_to_cpu(counters[1].reserved[i])); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(wfx_counters); - -static const char * const channel_names[] = { - [0] = "1M", - [1] = "2M", - [2] = "5.5M", - [3] = "11M", - /* Entries 4 and 5 does not exist */ - [6] = "6M", - [7] = "9M", - [8] = "12M", - [9] = "18M", - [10] = "24M", - [11] = "36M", - [12] = "48M", - [13] = "54M", - [14] = "MCS0", - [15] = "MCS1", - [16] = "MCS2", - [17] = "MCS3", - [18] = "MCS4", - [19] = "MCS5", - [20] = "MCS6", - [21] = "MCS7", -}; - -static int wfx_rx_stats_show(struct seq_file *seq, void *v) -{ - struct wfx_dev *wdev = seq->private; - struct hif_rx_stats *st = &wdev->rx_stats; - int i; - - mutex_lock(&wdev->rx_stats_lock); - seq_printf(seq, "Timestamp: %dus\n", st->date); - seq_printf(seq, "Low power clock: frequency %uHz, external %s\n", - le32_to_cpu(st->pwr_clk_freq), - st->is_ext_pwr_clk ? "yes" : "no"); - seq_printf(seq, - "Num. of frames: %d, PER (x10e4): %d, Throughput: %dKbps/s\n", - st->nb_rx_frame, st->per_total, st->throughput); - seq_puts(seq, " Num. of PER RSSI SNR CFO\n"); - seq_puts(seq, " frames (x10e4) (dBm) (dB) (kHz)\n"); - for (i = 0; i < ARRAY_SIZE(channel_names); i++) { - if (channel_names[i]) - seq_printf(seq, "%5s %8d %8d %8d %8d %8d\n", - channel_names[i], - le32_to_cpu(st->nb_rx_by_rate[i]), - le16_to_cpu(st->per[i]), - (s16)le16_to_cpu(st->rssi[i]) / 100, - (s16)le16_to_cpu(st->snr[i]) / 100, - (s16)le16_to_cpu(st->cfo[i])); - } - mutex_unlock(&wdev->rx_stats_lock); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats); - -static int wfx_tx_power_loop_show(struct seq_file *seq, void *v) -{ - struct wfx_dev *wdev = seq->private; - struct hif_tx_power_loop_info *st = &wdev->tx_power_loop_info; - int tmp; - - mutex_lock(&wdev->tx_power_loop_info_lock); - tmp = le16_to_cpu(st->tx_gain_dig); - seq_printf(seq, "Tx gain digital: %d\n", tmp); - tmp = le16_to_cpu(st->tx_gain_pa); - seq_printf(seq, "Tx gain PA: %d\n", tmp); - tmp = (s16)le16_to_cpu(st->target_pout); - seq_printf(seq, "Target Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); - tmp = (s16)le16_to_cpu(st->p_estimation); - seq_printf(seq, "FEM Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); - tmp = le16_to_cpu(st->vpdet); - seq_printf(seq, "Vpdet: %d mV\n", tmp); - seq_printf(seq, "Measure index: %d\n", st->measurement_index); - mutex_unlock(&wdev->tx_power_loop_info_lock); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(wfx_tx_power_loop); - -static ssize_t wfx_send_pds_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct wfx_dev *wdev = file->private_data; - char *buf; - int ret; - - if (*ppos != 0) { - dev_dbg(wdev->dev, "PDS data must be written in one transaction"); - return -EBUSY; - } - buf = memdup_user(user_buf, count); - if (IS_ERR(buf)) - return PTR_ERR(buf); - *ppos = *ppos + count; - ret = wfx_send_pds(wdev, buf, count); - kfree(buf); - if (ret < 0) - return ret; - return count; -} - -static const struct file_operations wfx_send_pds_fops = { - .open = simple_open, - .write = wfx_send_pds_write, -}; - -struct dbgfs_hif_msg { - struct wfx_dev *wdev; - struct completion complete; - u8 reply[1024]; - int ret; -}; - -static ssize_t wfx_send_hif_msg_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct dbgfs_hif_msg *context = file->private_data; - struct wfx_dev *wdev = context->wdev; - struct hif_msg *request; - - if (completion_done(&context->complete)) { - dev_dbg(wdev->dev, "read previous result before start a new one\n"); - return -EBUSY; - } - if (count < sizeof(struct hif_msg)) - return -EINVAL; - - // wfx_cmd_send() checks that reply buffer is wide enough, but does not - // return precise length read. User have to know how many bytes should - // be read. Filling reply buffer with a memory pattern may help user. - memset(context->reply, 0xFF, sizeof(context->reply)); - request = memdup_user(user_buf, count); - if (IS_ERR(request)) - return PTR_ERR(request); - if (le16_to_cpu(request->len) != count) { - kfree(request); - return -EINVAL; - } - context->ret = wfx_cmd_send(wdev, request, context->reply, - sizeof(context->reply), false); - - kfree(request); - complete(&context->complete); - return count; -} - -static ssize_t wfx_send_hif_msg_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct dbgfs_hif_msg *context = file->private_data; - int ret; - - if (count > sizeof(context->reply)) - return -EINVAL; - ret = wait_for_completion_interruptible(&context->complete); - if (ret) - return ret; - if (context->ret < 0) - return context->ret; - // Be careful, write() is waiting for a full message while read() - // only returns a payload - if (copy_to_user(user_buf, context->reply, count)) - return -EFAULT; - - return count; -} - -static int wfx_send_hif_msg_open(struct inode *inode, struct file *file) -{ - struct dbgfs_hif_msg *context = kzalloc(sizeof(*context), GFP_KERNEL); - - if (!context) - return -ENOMEM; - context->wdev = inode->i_private; - init_completion(&context->complete); - file->private_data = context; - return 0; -} - -static int wfx_send_hif_msg_release(struct inode *inode, struct file *file) -{ - struct dbgfs_hif_msg *context = file->private_data; - - kfree(context); - return 0; -} - -static const struct file_operations wfx_send_hif_msg_fops = { - .open = wfx_send_hif_msg_open, - .release = wfx_send_hif_msg_release, - .write = wfx_send_hif_msg_write, - .read = wfx_send_hif_msg_read, -}; - -static int wfx_ps_timeout_set(void *data, u64 val) -{ - struct wfx_dev *wdev = (struct wfx_dev *)data; - struct wfx_vif *wvif; - - wdev->force_ps_timeout = val; - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - wfx_update_pm(wvif); - return 0; -} - -static int wfx_ps_timeout_get(void *data, u64 *val) -{ - struct wfx_dev *wdev = (struct wfx_dev *)data; - - *val = wdev->force_ps_timeout; - return 0; -} - -DEFINE_DEBUGFS_ATTRIBUTE(wfx_ps_timeout_fops, wfx_ps_timeout_get, wfx_ps_timeout_set, "%lld\n"); - -int wfx_debug_init(struct wfx_dev *wdev) -{ - struct dentry *d; - - d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir); - debugfs_create_file("counters", 0444, d, wdev, &wfx_counters_fops); - debugfs_create_file("rx_stats", 0444, d, wdev, &wfx_rx_stats_fops); - debugfs_create_file("tx_power_loop", 0444, d, wdev, - &wfx_tx_power_loop_fops); - debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops); - debugfs_create_file("send_hif_msg", 0600, d, wdev, - &wfx_send_hif_msg_fops); - debugfs_create_file("ps_timeout", 0600, d, wdev, &wfx_ps_timeout_fops); - - return 0; -} diff --git a/drivers/staging/wfx/debug.h b/drivers/staging/wfx/debug.h deleted file mode 100644 index 6f2f84d64c9e..000000000000 --- a/drivers/staging/wfx/debug.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Debugfs interface. - * - * Copyright (c) 2017-2019, Silicon Laboratories, Inc. - * Copyright (c) 2011, ST-Ericsson - */ -#ifndef WFX_DEBUG_H -#define WFX_DEBUG_H - -struct wfx_dev; - -int wfx_debug_init(struct wfx_dev *wdev); - -const char *get_hif_name(unsigned long id); -const char *get_mib_name(unsigned long id); -const char *get_reg_name(unsigned long id); - -#endif /* WFX_DEBUG_H */ diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c deleted file mode 100644 index 1b8aec02d169..000000000000 --- a/drivers/staging/wfx/fwio.c +++ /dev/null @@ -1,405 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Firmware loading. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include -#include - -#include "fwio.h" -#include "wfx.h" -#include "hwio.h" - -// Addresses below are in SRAM area -#define WFX_DNLD_FIFO 0x09004000 -#define DNLD_BLOCK_SIZE 0x0400 -#define DNLD_FIFO_SIZE 0x8000 // (32 * DNLD_BLOCK_SIZE) -// Download Control Area (DCA) -#define WFX_DCA_IMAGE_SIZE 0x0900C000 -#define WFX_DCA_PUT 0x0900C004 -#define WFX_DCA_GET 0x0900C008 -#define WFX_DCA_HOST_STATUS 0x0900C00C -#define HOST_READY 0x87654321 -#define HOST_INFO_READ 0xA753BD99 -#define HOST_UPLOAD_PENDING 0xABCDDCBA -#define HOST_UPLOAD_COMPLETE 0xD4C64A99 -#define HOST_OK_TO_JUMP 0x174FC882 -#define WFX_DCA_NCP_STATUS 0x0900C010 -#define NCP_NOT_READY 0x12345678 -#define NCP_READY 0x87654321 -#define NCP_INFO_READY 0xBD53EF99 -#define NCP_DOWNLOAD_PENDING 0xABCDDCBA -#define NCP_DOWNLOAD_COMPLETE 0xCAFEFECA -#define NCP_AUTH_OK 0xD4C64A99 -#define NCP_AUTH_FAIL 0x174FC882 -#define NCP_PUB_KEY_RDY 0x7AB41D19 -#define WFX_DCA_FW_SIGNATURE 0x0900C014 -#define FW_SIGNATURE_SIZE 0x40 -#define WFX_DCA_FW_HASH 0x0900C054 -#define FW_HASH_SIZE 0x08 -#define WFX_DCA_FW_VERSION 0x0900C05C -#define FW_VERSION_SIZE 0x04 -#define WFX_DCA_RESERVED 0x0900C060 -#define DCA_RESERVED_SIZE 0x20 -#define WFX_STATUS_INFO 0x0900C080 -#define WFX_BOOTLOADER_LABEL 0x0900C084 -#define BOOTLOADER_LABEL_SIZE 0x3C -#define WFX_PTE_INFO 0x0900C0C0 -#define PTE_INFO_KEYSET_IDX 0x0D -#define PTE_INFO_SIZE 0x10 -#define WFX_ERR_INFO 0x0900C0D0 -#define ERR_INVALID_SEC_TYPE 0x05 -#define ERR_SIG_VERIF_FAILED 0x0F -#define ERR_AES_CTRL_KEY 0x10 -#define ERR_ECC_PUB_KEY 0x11 -#define ERR_MAC_KEY 0x18 - -#define DCA_TIMEOUT 50 // milliseconds -#define WAKEUP_TIMEOUT 200 // milliseconds - -static const char * const fwio_errors[] = { - [ERR_INVALID_SEC_TYPE] = "Invalid section type or wrong encryption", - [ERR_SIG_VERIF_FAILED] = "Signature verification failed", - [ERR_AES_CTRL_KEY] = "AES control key not initialized", - [ERR_ECC_PUB_KEY] = "ECC public key not initialized", - [ERR_MAC_KEY] = "MAC key not initialized", -}; - -/* - * request_firmware() allocate data using vmalloc(). It is not compatible with - * underlying hardware that use DMA. Function below detect this case and - * allocate a bounce buffer if necessary. - * - * Notice that, in doubt, you can enable CONFIG_DEBUG_SG to ask kernel to - * detect this problem at runtime (else, kernel silently fail). - * - * NOTE: it may also be possible to use 'pages' from struct firmware and avoid - * bounce buffer - */ -static int sram_write_dma_safe(struct wfx_dev *wdev, u32 addr, const u8 *buf, - size_t len) -{ - int ret; - const u8 *tmp; - - if (!virt_addr_valid(buf)) { - tmp = kmemdup(buf, len, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - } else { - tmp = buf; - } - ret = sram_buf_write(wdev, addr, tmp, len); - if (tmp != buf) - kfree(tmp); - return ret; -} - -static int get_firmware(struct wfx_dev *wdev, u32 keyset_chip, - const struct firmware **fw, int *file_offset) -{ - int keyset_file; - char filename[256]; - const char *data; - int ret; - - snprintf(filename, sizeof(filename), "%s_%02X.sec", - wdev->pdata.file_fw, keyset_chip); - ret = firmware_request_nowarn(fw, filename, wdev->dev); - if (ret) { - dev_info(wdev->dev, "can't load %s, falling back to %s.sec\n", - filename, wdev->pdata.file_fw); - snprintf(filename, sizeof(filename), "%s.sec", - wdev->pdata.file_fw); - ret = request_firmware(fw, filename, wdev->dev); - if (ret) { - dev_err(wdev->dev, "can't load %s\n", filename); - *fw = NULL; - return ret; - } - } - - data = (*fw)->data; - if (memcmp(data, "KEYSET", 6) != 0) { - // Legacy firmware format - *file_offset = 0; - keyset_file = 0x90; - } else { - *file_offset = 8; - keyset_file = (hex_to_bin(data[6]) * 16) | hex_to_bin(data[7]); - if (keyset_file < 0) { - dev_err(wdev->dev, "%s corrupted\n", filename); - release_firmware(*fw); - *fw = NULL; - return -EINVAL; - } - } - if (keyset_file != keyset_chip) { - dev_err(wdev->dev, "firmware keyset is incompatible with chip (file: 0x%02X, chip: 0x%02X)\n", - keyset_file, keyset_chip); - release_firmware(*fw); - *fw = NULL; - return -ENODEV; - } - wdev->keyset = keyset_file; - return 0; -} - -static int wait_ncp_status(struct wfx_dev *wdev, u32 status) -{ - ktime_t now, start; - u32 reg; - int ret; - - start = ktime_get(); - for (;;) { - ret = sram_reg_read(wdev, WFX_DCA_NCP_STATUS, ®); - if (ret < 0) - return -EIO; - now = ktime_get(); - if (reg == status) - break; - if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT))) - return -ETIMEDOUT; - } - if (ktime_compare(now, start)) - dev_dbg(wdev->dev, "chip answer after %lldus\n", - ktime_us_delta(now, start)); - else - dev_dbg(wdev->dev, "chip answer immediately\n"); - return 0; -} - -static int upload_firmware(struct wfx_dev *wdev, const u8 *data, size_t len) -{ - int ret; - u32 offs, bytes_done = 0; - ktime_t now, start; - - if (len % DNLD_BLOCK_SIZE) { - dev_err(wdev->dev, "firmware size is not aligned. Buffer overrun will occur\n"); - return -EIO; - } - offs = 0; - while (offs < len) { - start = ktime_get(); - for (;;) { - now = ktime_get(); - if (offs + DNLD_BLOCK_SIZE - bytes_done < DNLD_FIFO_SIZE) - break; - if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT))) - return -ETIMEDOUT; - ret = sram_reg_read(wdev, WFX_DCA_GET, &bytes_done); - if (ret < 0) - return ret; - } - if (ktime_compare(now, start)) - dev_dbg(wdev->dev, "answer after %lldus\n", - ktime_us_delta(now, start)); - - ret = sram_write_dma_safe(wdev, WFX_DNLD_FIFO + - (offs % DNLD_FIFO_SIZE), - data + offs, DNLD_BLOCK_SIZE); - if (ret < 0) - return ret; - - // WFx seems to not support writing 0 in this register during - // first loop - offs += DNLD_BLOCK_SIZE; - ret = sram_reg_write(wdev, WFX_DCA_PUT, offs); - if (ret < 0) - return ret; - } - return 0; -} - -static void print_boot_status(struct wfx_dev *wdev) -{ - u32 reg; - - sram_reg_read(wdev, WFX_STATUS_INFO, ®); - if (reg == 0x12345678) - return; - sram_reg_read(wdev, WFX_ERR_INFO, ®); - if (reg < ARRAY_SIZE(fwio_errors) && fwio_errors[reg]) - dev_info(wdev->dev, "secure boot: %s\n", fwio_errors[reg]); - else - dev_info(wdev->dev, "secure boot: Error %#02x\n", reg); -} - -static int load_firmware_secure(struct wfx_dev *wdev) -{ - const struct firmware *fw = NULL; - int header_size; - int fw_offset; - ktime_t start; - u8 *buf; - int ret; - - BUILD_BUG_ON(PTE_INFO_SIZE > BOOTLOADER_LABEL_SIZE); - buf = kmalloc(BOOTLOADER_LABEL_SIZE + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_READY); - ret = wait_ncp_status(wdev, NCP_INFO_READY); - if (ret) - goto error; - - sram_buf_read(wdev, WFX_BOOTLOADER_LABEL, buf, BOOTLOADER_LABEL_SIZE); - buf[BOOTLOADER_LABEL_SIZE] = 0; - dev_dbg(wdev->dev, "bootloader: \"%s\"\n", buf); - - sram_buf_read(wdev, WFX_PTE_INFO, buf, PTE_INFO_SIZE); - ret = get_firmware(wdev, buf[PTE_INFO_KEYSET_IDX], &fw, &fw_offset); - if (ret) - goto error; - header_size = fw_offset + FW_SIGNATURE_SIZE + FW_HASH_SIZE; - - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_INFO_READ); - ret = wait_ncp_status(wdev, NCP_READY); - if (ret) - goto error; - - sram_reg_write(wdev, WFX_DNLD_FIFO, 0xFFFFFFFF); // Fifo init - sram_write_dma_safe(wdev, WFX_DCA_FW_VERSION, "\x01\x00\x00\x00", - FW_VERSION_SIZE); - sram_write_dma_safe(wdev, WFX_DCA_FW_SIGNATURE, fw->data + fw_offset, - FW_SIGNATURE_SIZE); - sram_write_dma_safe(wdev, WFX_DCA_FW_HASH, - fw->data + fw_offset + FW_SIGNATURE_SIZE, - FW_HASH_SIZE); - sram_reg_write(wdev, WFX_DCA_IMAGE_SIZE, fw->size - header_size); - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_PENDING); - ret = wait_ncp_status(wdev, NCP_DOWNLOAD_PENDING); - if (ret) - goto error; - - start = ktime_get(); - ret = upload_firmware(wdev, fw->data + header_size, - fw->size - header_size); - if (ret) - goto error; - dev_dbg(wdev->dev, "firmware load after %lldus\n", - ktime_us_delta(ktime_get(), start)); - - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_COMPLETE); - ret = wait_ncp_status(wdev, NCP_AUTH_OK); - // Legacy ROM support - if (ret < 0) - ret = wait_ncp_status(wdev, NCP_PUB_KEY_RDY); - if (ret < 0) - goto error; - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_OK_TO_JUMP); - -error: - kfree(buf); - if (fw) - release_firmware(fw); - if (ret) - print_boot_status(wdev); - return ret; -} - -static int init_gpr(struct wfx_dev *wdev) -{ - int ret, i; - static const struct { - int index; - u32 value; - } gpr_init[] = { - { 0x07, 0x208775 }, - { 0x08, 0x2EC020 }, - { 0x09, 0x3C3C3C }, - { 0x0B, 0x322C44 }, - { 0x0C, 0xA06497 }, - }; - - for (i = 0; i < ARRAY_SIZE(gpr_init); i++) { - ret = igpr_reg_write(wdev, gpr_init[i].index, - gpr_init[i].value); - if (ret < 0) - return ret; - dev_dbg(wdev->dev, " index %02x: %08x\n", - gpr_init[i].index, gpr_init[i].value); - } - return 0; -} - -int wfx_init_device(struct wfx_dev *wdev) -{ - int ret; - int hw_revision, hw_type; - int wakeup_timeout = 50; // ms - ktime_t now, start; - u32 reg; - - reg = CFG_DIRECT_ACCESS_MODE | CFG_CPU_RESET | CFG_BYTE_ORDER_ABCD; - if (wdev->pdata.use_rising_clk) - reg |= CFG_CLK_RISE_EDGE; - ret = config_reg_write(wdev, reg); - if (ret < 0) { - dev_err(wdev->dev, "bus returned an error during first write access. Host configuration error?\n"); - return -EIO; - } - - ret = config_reg_read(wdev, ®); - if (ret < 0) { - dev_err(wdev->dev, "bus returned an error during first read access. Bus configuration error?\n"); - return -EIO; - } - if (reg == 0 || reg == ~0) { - dev_err(wdev->dev, "chip mute. Bus configuration error or chip wasn't reset?\n"); - return -EIO; - } - dev_dbg(wdev->dev, "initial config register value: %08x\n", reg); - - hw_revision = FIELD_GET(CFG_DEVICE_ID_MAJOR, reg); - if (hw_revision == 0) { - dev_err(wdev->dev, "bad hardware revision number: %d\n", - hw_revision); - return -ENODEV; - } - hw_type = FIELD_GET(CFG_DEVICE_ID_TYPE, reg); - if (hw_type == 1) { - dev_notice(wdev->dev, "development hardware detected\n"); - wakeup_timeout = 2000; - } - - ret = init_gpr(wdev); - if (ret < 0) - return ret; - - ret = control_reg_write(wdev, CTRL_WLAN_WAKEUP); - if (ret < 0) - return -EIO; - start = ktime_get(); - for (;;) { - ret = control_reg_read(wdev, ®); - now = ktime_get(); - if (reg & CTRL_WLAN_READY) - break; - if (ktime_after(now, ktime_add_ms(start, wakeup_timeout))) { - dev_err(wdev->dev, "chip didn't wake up. Chip wasn't reset?\n"); - return -ETIMEDOUT; - } - } - dev_dbg(wdev->dev, "chip wake up after %lldus\n", - ktime_us_delta(now, start)); - - ret = config_reg_write_bits(wdev, CFG_CPU_RESET, 0); - if (ret < 0) - return ret; - ret = load_firmware_secure(wdev); - if (ret < 0) - return ret; - return config_reg_write_bits(wdev, - CFG_DIRECT_ACCESS_MODE | - CFG_IRQ_ENABLE_DATA | - CFG_IRQ_ENABLE_WRDY, - CFG_IRQ_ENABLE_DATA); -} diff --git a/drivers/staging/wfx/fwio.h b/drivers/staging/wfx/fwio.h deleted file mode 100644 index 6028f92503fe..000000000000 --- a/drivers/staging/wfx/fwio.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Firmware loading. - * - * Copyright (c) 2017-2019, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_FWIO_H -#define WFX_FWIO_H - -struct wfx_dev; - -int wfx_init_device(struct wfx_dev *wdev); - -#endif /* WFX_FWIO_H */ diff --git a/drivers/staging/wfx/hif_api_cmd.h b/drivers/staging/wfx/hif_api_cmd.h deleted file mode 100644 index 11bc1a58edae..000000000000 --- a/drivers/staging/wfx/hif_api_cmd.h +++ /dev/null @@ -1,553 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * WFx hardware interface definitions - * - * Copyright (c) 2018-2020, Silicon Laboratories Inc. - */ - -#ifndef WFX_HIF_API_CMD_H -#define WFX_HIF_API_CMD_H - -#include - -#include "hif_api_general.h" - -enum hif_requests_ids { - HIF_REQ_ID_RESET = 0x0a, - HIF_REQ_ID_READ_MIB = 0x05, - HIF_REQ_ID_WRITE_MIB = 0x06, - HIF_REQ_ID_START_SCAN = 0x07, - HIF_REQ_ID_STOP_SCAN = 0x08, - HIF_REQ_ID_TX = 0x04, - HIF_REQ_ID_JOIN = 0x0b, - HIF_REQ_ID_SET_PM_MODE = 0x10, - HIF_REQ_ID_SET_BSS_PARAMS = 0x11, - HIF_REQ_ID_ADD_KEY = 0x0c, - HIF_REQ_ID_REMOVE_KEY = 0x0d, - HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13, - HIF_REQ_ID_START = 0x17, - HIF_REQ_ID_BEACON_TRANSMIT = 0x18, - HIF_REQ_ID_UPDATE_IE = 0x1b, - HIF_REQ_ID_MAP_LINK = 0x1c, -}; - -enum hif_confirmations_ids { - HIF_CNF_ID_RESET = 0x0a, - HIF_CNF_ID_READ_MIB = 0x05, - HIF_CNF_ID_WRITE_MIB = 0x06, - HIF_CNF_ID_START_SCAN = 0x07, - HIF_CNF_ID_STOP_SCAN = 0x08, - HIF_CNF_ID_TX = 0x04, - HIF_CNF_ID_MULTI_TRANSMIT = 0x1e, - HIF_CNF_ID_JOIN = 0x0b, - HIF_CNF_ID_SET_PM_MODE = 0x10, - HIF_CNF_ID_SET_BSS_PARAMS = 0x11, - HIF_CNF_ID_ADD_KEY = 0x0c, - HIF_CNF_ID_REMOVE_KEY = 0x0d, - HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13, - HIF_CNF_ID_START = 0x17, - HIF_CNF_ID_BEACON_TRANSMIT = 0x18, - HIF_CNF_ID_UPDATE_IE = 0x1b, - HIF_CNF_ID_MAP_LINK = 0x1c, -}; - -enum hif_indications_ids { - HIF_IND_ID_RX = 0x84, - HIF_IND_ID_SCAN_CMPL = 0x86, - HIF_IND_ID_JOIN_COMPLETE = 0x8f, - HIF_IND_ID_SET_PM_MODE_CMPL = 0x89, - HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c, - HIF_IND_ID_EVENT = 0x85 -}; - -struct hif_req_reset { - u8 reset_stat:1; - u8 reset_all_int:1; - u8 reserved1:6; - u8 reserved2[3]; -} __packed; - -struct hif_cnf_reset { - __le32 status; -} __packed; - -struct hif_req_read_mib { - __le16 mib_id; - __le16 reserved; -} __packed; - -struct hif_cnf_read_mib { - __le32 status; - __le16 mib_id; - __le16 length; - u8 mib_data[]; -} __packed; - -struct hif_req_write_mib { - __le16 mib_id; - __le16 length; - u8 mib_data[]; -} __packed; - -struct hif_cnf_write_mib { - __le32 status; -} __packed; - -struct hif_req_update_ie { - u8 beacon:1; - u8 probe_resp:1; - u8 probe_req:1; - u8 reserved1:5; - u8 reserved2; - __le16 num_ies; - struct element ie[]; -} __packed; - -struct hif_cnf_update_ie { - __le32 status; -} __packed; - -struct hif_ssid_def { - __le32 ssid_length; - u8 ssid[IEEE80211_MAX_SSID_LEN]; -} __packed; - -#define HIF_API_MAX_NB_SSIDS 2 -#define HIF_API_MAX_NB_CHANNELS 14 - -struct hif_req_start_scan_alt { - u8 band; - u8 maintain_current_bss:1; - u8 periodic:1; - u8 reserved1:6; - u8 disallow_ps:1; - u8 reserved2:1; - u8 short_preamble:1; - u8 reserved3:5; - u8 max_transmit_rate; - __le16 periodic_interval; - u8 reserved4; - s8 periodic_rssi_thr; - u8 num_of_probe_requests; - u8 probe_delay; - u8 num_of_ssids; - u8 num_of_channels; - __le32 min_channel_time; - __le32 max_channel_time; - __le32 tx_power_level; // signed value - struct hif_ssid_def ssid_def[HIF_API_MAX_NB_SSIDS]; - u8 channel_list[]; -} __packed; - -struct hif_cnf_start_scan { - __le32 status; -} __packed; - -struct hif_cnf_stop_scan { - __le32 status; -} __packed; - -enum hif_pm_mode_status { - HIF_PM_MODE_ACTIVE = 0x0, - HIF_PM_MODE_PS = 0x1, - HIF_PM_MODE_UNDETERMINED = 0x2 -}; - -struct hif_ind_scan_cmpl { - __le32 status; - u8 pm_mode; - u8 num_channels_completed; - __le16 reserved; -} __packed; - -enum hif_queue_id { - HIF_QUEUE_ID_BACKGROUND = 0x0, - HIF_QUEUE_ID_BESTEFFORT = 0x1, - HIF_QUEUE_ID_VIDEO = 0x2, - HIF_QUEUE_ID_VOICE = 0x3 -}; - -enum hif_frame_format { - HIF_FRAME_FORMAT_NON_HT = 0x0, - HIF_FRAME_FORMAT_MIXED_FORMAT_HT = 0x1, - HIF_FRAME_FORMAT_GF_HT_11N = 0x2 -}; - -struct hif_req_tx { - // packet_id is not interpreted by the device, so it is not necessary to - // declare it little endian - u32 packet_id; - u8 max_tx_rate; - u8 queue_id:2; - u8 peer_sta_id:4; - u8 reserved1:2; - u8 more:1; - u8 fc_offset:3; - u8 after_dtim:1; - u8 reserved2:3; - u8 start_exp:1; - u8 reserved3:3; - u8 retry_policy_index:4; - __le32 reserved4; - __le32 expire_time; - u8 frame_format:4; - u8 fec_coding:1; - u8 short_gi:1; - u8 reserved5:1; - u8 stbc:1; - u8 reserved6; - u8 aggregation:1; - u8 reserved7:7; - u8 reserved8; - u8 frame[]; -} __packed; - -enum hif_qos_ackplcy { - HIF_QOS_ACKPLCY_NORMAL = 0x0, - HIF_QOS_ACKPLCY_TXNOACK = 0x1, - HIF_QOS_ACKPLCY_NOEXPACK = 0x2, - HIF_QOS_ACKPLCY_BLCKACK = 0x3 -}; - -struct hif_cnf_tx { - __le32 status; - // packet_id is copied from struct hif_req_tx without been interpreted - // by the device, so it is not necessary to declare it little endian - u32 packet_id; - u8 txed_rate; - u8 ack_failures; - u8 aggr:1; - u8 requeue:1; - u8 ack_policy:2; - u8 txop_limit:1; - u8 reserved1:3; - u8 reserved2; - __le32 media_delay; - __le32 tx_queue_delay; -} __packed; - -struct hif_cnf_multi_transmit { - u8 num_tx_confs; - u8 reserved[3]; - struct hif_cnf_tx tx_conf_payload[]; -} __packed; - -enum hif_ri_flags_encrypt { - HIF_RI_FLAGS_UNENCRYPTED = 0x0, - HIF_RI_FLAGS_WEP_ENCRYPTED = 0x1, - HIF_RI_FLAGS_TKIP_ENCRYPTED = 0x2, - HIF_RI_FLAGS_AES_ENCRYPTED = 0x3, - HIF_RI_FLAGS_WAPI_ENCRYPTED = 0x4 -}; - -struct hif_ind_rx { - __le32 status; - u8 channel_number; - u8 reserved1; - u8 rxed_rate; - u8 rcpi_rssi; - u8 encryp:3; - u8 in_aggr:1; - u8 first_aggr:1; - u8 last_aggr:1; - u8 defrag:1; - u8 beacon:1; - u8 tim:1; - u8 bitmap:1; - u8 match_ssid:1; - u8 match_bssid:1; - u8 more:1; - u8 reserved2:1; - u8 ht:1; - u8 stbc:1; - u8 match_uc_addr:1; - u8 match_mc_addr:1; - u8 match_bc_addr:1; - u8 key_type:1; - u8 key_index:4; - u8 reserved3:1; - u8 peer_sta_id:4; - u8 reserved4:2; - u8 reserved5:1; - u8 frame[]; -} __packed; - -struct hif_req_edca_queue_params { - u8 queue_id; - u8 reserved1; - u8 aifsn; - u8 reserved2; - __le16 cw_min; - __le16 cw_max; - __le16 tx_op_limit; - __le16 allowed_medium_time; - __le32 reserved3; -} __packed; - -struct hif_cnf_edca_queue_params { - __le32 status; -} __packed; - -struct hif_req_join { - u8 infrastructure_bss_mode:1; - u8 reserved1:7; - u8 band; - u8 channel_number; - u8 reserved2; - u8 bssid[ETH_ALEN]; - __le16 atim_window; - u8 short_preamble:1; - u8 reserved3:7; - u8 probe_for_join; - u8 reserved4; - u8 reserved5:2; - u8 force_no_beacon:1; - u8 force_with_ind:1; - u8 reserved6:4; - __le32 ssid_length; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - __le32 beacon_interval; - __le32 basic_rate_set; -} __packed; - -struct hif_cnf_join { - __le32 status; -} __packed; - -struct hif_ind_join_complete { - __le32 status; -} __packed; - -struct hif_req_set_bss_params { - u8 lost_count_only:1; - u8 reserved:7; - u8 beacon_lost_count; - __le16 aid; - __le32 operational_rate_set; -} __packed; - -struct hif_cnf_set_bss_params { - __le32 status; -} __packed; - -struct hif_req_set_pm_mode { - u8 enter_psm:1; - u8 reserved:6; - u8 fast_psm:1; - u8 fast_psm_idle_period; - u8 ap_psm_change_period; - u8 min_auto_ps_poll_period; -} __packed; - -struct hif_cnf_set_pm_mode { - __le32 status; -} __packed; - -struct hif_ind_set_pm_mode_cmpl { - __le32 status; - u8 pm_mode; - u8 reserved[3]; -} __packed; - -struct hif_req_start { - u8 mode; - u8 band; - u8 channel_number; - u8 reserved1; - __le32 reserved2; - __le32 beacon_interval; - u8 dtim_period; - u8 short_preamble:1; - u8 reserved3:7; - u8 reserved4; - u8 ssid_length; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - __le32 basic_rate_set; -} __packed; - -struct hif_cnf_start { - __le32 status; -} __packed; - -struct hif_req_beacon_transmit { - u8 enable_beaconing; - u8 reserved[3]; -} __packed; - -struct hif_cnf_beacon_transmit { - __le32 status; -} __packed; - -#define HIF_LINK_ID_MAX 14 -#define HIF_LINK_ID_NOT_ASSOCIATED (HIF_LINK_ID_MAX + 1) - -struct hif_req_map_link { - u8 mac_addr[ETH_ALEN]; - u8 unmap:1; - u8 mfpc:1; - u8 reserved:6; - u8 peer_sta_id; -} __packed; - -struct hif_cnf_map_link { - __le32 status; -} __packed; - -struct hif_ind_suspend_resume_tx { - u8 resume:1; - u8 reserved1:2; - u8 bc_mc_only:1; - u8 reserved2:4; - u8 reserved3; - __le16 peer_sta_set; -} __packed; - - -#define MAX_KEY_ENTRIES 24 -#define HIF_API_WEP_KEY_DATA_SIZE 16 -#define HIF_API_TKIP_KEY_DATA_SIZE 16 -#define HIF_API_RX_MIC_KEY_SIZE 8 -#define HIF_API_TX_MIC_KEY_SIZE 8 -#define HIF_API_AES_KEY_DATA_SIZE 16 -#define HIF_API_WAPI_KEY_DATA_SIZE 16 -#define HIF_API_MIC_KEY_DATA_SIZE 16 -#define HIF_API_IGTK_KEY_DATA_SIZE 16 -#define HIF_API_RX_SEQUENCE_COUNTER_SIZE 8 -#define HIF_API_IPN_SIZE 8 - -enum hif_key_type { - HIF_KEY_TYPE_WEP_DEFAULT = 0x0, - HIF_KEY_TYPE_WEP_PAIRWISE = 0x1, - HIF_KEY_TYPE_TKIP_GROUP = 0x2, - HIF_KEY_TYPE_TKIP_PAIRWISE = 0x3, - HIF_KEY_TYPE_AES_GROUP = 0x4, - HIF_KEY_TYPE_AES_PAIRWISE = 0x5, - HIF_KEY_TYPE_WAPI_GROUP = 0x6, - HIF_KEY_TYPE_WAPI_PAIRWISE = 0x7, - HIF_KEY_TYPE_IGTK_GROUP = 0x8, - HIF_KEY_TYPE_NONE = 0x9 -}; - -struct hif_wep_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 reserved; - u8 key_length; - u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; -} __packed; - -struct hif_wep_group_key { - u8 key_id; - u8 key_length; - u8 reserved[2]; - u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; -} __packed; - -struct hif_tkip_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 reserved[2]; - u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; - u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; - u8 tx_mic_key[HIF_API_TX_MIC_KEY_SIZE]; -} __packed; - -struct hif_tkip_group_key { - u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; - u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; - u8 key_id; - u8 reserved[3]; - u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; -} __packed; - -struct hif_aes_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 reserved[2]; - u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; -} __packed; - -struct hif_aes_group_key { - u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; - u8 key_id; - u8 reserved[3]; - u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; -} __packed; - -struct hif_wapi_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 key_id; - u8 reserved; - u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; - u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; -} __packed; - -struct hif_wapi_group_key { - u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; - u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; - u8 key_id; - u8 reserved[3]; -} __packed; - -struct hif_igtk_group_key { - u8 igtk_key_data[HIF_API_IGTK_KEY_DATA_SIZE]; - u8 key_id; - u8 reserved[3]; - u8 ipn[HIF_API_IPN_SIZE]; -} __packed; - -struct hif_req_add_key { - u8 type; - u8 entry_index; - u8 int_id:2; - u8 reserved1:6; - u8 reserved2; - union { - struct hif_wep_pairwise_key wep_pairwise_key; - struct hif_wep_group_key wep_group_key; - struct hif_tkip_pairwise_key tkip_pairwise_key; - struct hif_tkip_group_key tkip_group_key; - struct hif_aes_pairwise_key aes_pairwise_key; - struct hif_aes_group_key aes_group_key; - struct hif_wapi_pairwise_key wapi_pairwise_key; - struct hif_wapi_group_key wapi_group_key; - struct hif_igtk_group_key igtk_group_key; - } key; -} __packed; - -struct hif_cnf_add_key { - __le32 status; -} __packed; - -struct hif_req_remove_key { - u8 entry_index; - u8 reserved[3]; -} __packed; - -struct hif_cnf_remove_key { - __le32 status; -} __packed; - -enum hif_event_ind { - HIF_EVENT_IND_BSSLOST = 0x1, - HIF_EVENT_IND_BSSREGAINED = 0x2, - HIF_EVENT_IND_RCPI_RSSI = 0x3, - HIF_EVENT_IND_PS_MODE_ERROR = 0x4, - HIF_EVENT_IND_INACTIVITY = 0x5 -}; - -enum hif_ps_mode_error { - HIF_PS_ERROR_NO_ERROR = 0, - HIF_PS_ERROR_AP_NOT_RESP_TO_POLL = 1, - HIF_PS_ERROR_AP_NOT_RESP_TO_UAPSD_TRIGGER = 2, - HIF_PS_ERROR_AP_SENT_UNICAST_IN_DOZE = 3, - HIF_PS_ERROR_AP_NO_DATA_AFTER_TIM = 4 -}; - -struct hif_ind_event { - __le32 event_id; - union { - u8 rcpi_rssi; - __le32 ps_mode_error; - __le32 peer_sta_set; - } event_data; -} __packed; - -#endif diff --git a/drivers/staging/wfx/hif_api_general.h b/drivers/staging/wfx/hif_api_general.h deleted file mode 100644 index 24188945718d..000000000000 --- a/drivers/staging/wfx/hif_api_general.h +++ /dev/null @@ -1,267 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * WFx hardware interface definitions - * - * Copyright (c) 2018-2020, Silicon Laboratories Inc. - */ - -#ifndef WFX_HIF_API_GENERAL_H -#define WFX_HIF_API_GENERAL_H - -#ifdef __KERNEL__ -#include -#include -#else -#include -#include -#define __packed __attribute__((__packed__)) -#endif - -#define HIF_ID_IS_INDICATION 0x80 -#define HIF_COUNTER_MAX 7 - -struct hif_msg { - __le16 len; - u8 id; - u8 reserved:1; - u8 interface:2; - u8 seqnum:3; - u8 encrypted:2; - u8 body[]; -} __packed; - -enum hif_general_requests_ids { - HIF_REQ_ID_CONFIGURATION = 0x09, - HIF_REQ_ID_CONTROL_GPIO = 0x26, - HIF_REQ_ID_SET_SL_MAC_KEY = 0x27, - HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS = 0x28, - HIF_REQ_ID_SL_CONFIGURE = 0x29, - HIF_REQ_ID_PREVENT_ROLLBACK = 0x2a, - HIF_REQ_ID_PTA_SETTINGS = 0x2b, - HIF_REQ_ID_PTA_PRIORITY = 0x2c, - HIF_REQ_ID_PTA_STATE = 0x2d, - HIF_REQ_ID_SHUT_DOWN = 0x32, -}; - -enum hif_general_confirmations_ids { - HIF_CNF_ID_CONFIGURATION = 0x09, - HIF_CNF_ID_CONTROL_GPIO = 0x26, - HIF_CNF_ID_SET_SL_MAC_KEY = 0x27, - HIF_CNF_ID_SL_EXCHANGE_PUB_KEYS = 0x28, - HIF_CNF_ID_SL_CONFIGURE = 0x29, - HIF_CNF_ID_PREVENT_ROLLBACK = 0x2a, - HIF_CNF_ID_PTA_SETTINGS = 0x2b, - HIF_CNF_ID_PTA_PRIORITY = 0x2c, - HIF_CNF_ID_PTA_STATE = 0x2d, - HIF_CNF_ID_SHUT_DOWN = 0x32, -}; - -enum hif_general_indications_ids { - HIF_IND_ID_EXCEPTION = 0xe0, - HIF_IND_ID_STARTUP = 0xe1, - HIF_IND_ID_WAKEUP = 0xe2, - HIF_IND_ID_GENERIC = 0xe3, - HIF_IND_ID_ERROR = 0xe4, - HIF_IND_ID_SL_EXCHANGE_PUB_KEYS = 0xe5 -}; - -#define HIF_STATUS_SUCCESS (cpu_to_le32(0x0000)) -#define HIF_STATUS_FAIL (cpu_to_le32(0x0001)) -#define HIF_STATUS_INVALID_PARAMETER (cpu_to_le32(0x0002)) -#define HIF_STATUS_WARNING (cpu_to_le32(0x0003)) -#define HIF_STATUS_UNKNOWN_REQUEST (cpu_to_le32(0x0004)) -#define HIF_STATUS_RX_FAIL_DECRYPT (cpu_to_le32(0x0010)) -#define HIF_STATUS_RX_FAIL_MIC (cpu_to_le32(0x0011)) -#define HIF_STATUS_RX_FAIL_NO_KEY (cpu_to_le32(0x0012)) -#define HIF_STATUS_TX_FAIL_RETRIES (cpu_to_le32(0x0013)) -#define HIF_STATUS_TX_FAIL_TIMEOUT (cpu_to_le32(0x0014)) -#define HIF_STATUS_TX_FAIL_REQUEUE (cpu_to_le32(0x0015)) -#define HIF_STATUS_REFUSED (cpu_to_le32(0x0016)) -#define HIF_STATUS_BUSY (cpu_to_le32(0x0017)) -#define HIF_STATUS_SLK_SET_KEY_SUCCESS (cpu_to_le32(0x005A)) -#define HIF_STATUS_SLK_SET_KEY_ALREADY_BURNED (cpu_to_le32(0x006B)) -#define HIF_STATUS_SLK_SET_KEY_DISALLOWED_MODE (cpu_to_le32(0x007C)) -#define HIF_STATUS_SLK_SET_KEY_UNKNOWN_MODE (cpu_to_le32(0x008D)) -#define HIF_STATUS_SLK_NEGO_SUCCESS (cpu_to_le32(0x009E)) -#define HIF_STATUS_SLK_NEGO_FAILED (cpu_to_le32(0x00AF)) -#define HIF_STATUS_ROLLBACK_SUCCESS (cpu_to_le32(0x1234)) -#define HIF_STATUS_ROLLBACK_FAIL (cpu_to_le32(0x1256)) - -enum hif_api_rate_index { - API_RATE_INDEX_B_1MBPS = 0, - API_RATE_INDEX_B_2MBPS = 1, - API_RATE_INDEX_B_5P5MBPS = 2, - API_RATE_INDEX_B_11MBPS = 3, - API_RATE_INDEX_PBCC_22MBPS = 4, - API_RATE_INDEX_PBCC_33MBPS = 5, - API_RATE_INDEX_G_6MBPS = 6, - API_RATE_INDEX_G_9MBPS = 7, - API_RATE_INDEX_G_12MBPS = 8, - API_RATE_INDEX_G_18MBPS = 9, - API_RATE_INDEX_G_24MBPS = 10, - API_RATE_INDEX_G_36MBPS = 11, - API_RATE_INDEX_G_48MBPS = 12, - API_RATE_INDEX_G_54MBPS = 13, - API_RATE_INDEX_N_6P5MBPS = 14, - API_RATE_INDEX_N_13MBPS = 15, - API_RATE_INDEX_N_19P5MBPS = 16, - API_RATE_INDEX_N_26MBPS = 17, - API_RATE_INDEX_N_39MBPS = 18, - API_RATE_INDEX_N_52MBPS = 19, - API_RATE_INDEX_N_58P5MBPS = 20, - API_RATE_INDEX_N_65MBPS = 21, - API_RATE_NUM_ENTRIES = 22 -}; - -enum hif_fw_type { - HIF_FW_TYPE_ETF = 0x0, - HIF_FW_TYPE_WFM = 0x1, - HIF_FW_TYPE_WSM = 0x2 -}; - -struct hif_ind_startup { - // As the others, this struct is interpreted as little endian by the - // device. However, this struct is also used by the driver. We prefer to - // declare it in native order and doing byte swap on reception. - __le32 status; - u16 hardware_id; - u8 opn[14]; - u8 uid[8]; - u16 num_inp_ch_bufs; - u16 size_inp_ch_buf; - u8 num_links_ap; - u8 num_interfaces; - u8 mac_addr[2][ETH_ALEN]; - u8 api_version_minor; - u8 api_version_major; - u8 link_mode:2; - u8 reserved1:6; - u8 reserved2; - u8 reserved3; - u8 reserved4; - u8 firmware_build; - u8 firmware_minor; - u8 firmware_major; - u8 firmware_type; - u8 disabled_channel_list[2]; - u8 region_sel_mode:4; - u8 reserved5:4; - u8 phy1_region:3; - u8 phy0_region:3; - u8 otp_phy_ver:2; - u32 supported_rate_mask; - u8 firmware_label[128]; -} __packed; - -struct hif_ind_wakeup { -} __packed; - -struct hif_req_configuration { - __le16 length; - u8 pds_data[]; -} __packed; - -struct hif_cnf_configuration { - __le32 status; -} __packed; - -enum hif_gpio_mode { - HIF_GPIO_MODE_D0 = 0x0, - HIF_GPIO_MODE_D1 = 0x1, - HIF_GPIO_MODE_OD0 = 0x2, - HIF_GPIO_MODE_OD1 = 0x3, - HIF_GPIO_MODE_TRISTATE = 0x4, - HIF_GPIO_MODE_TOGGLE = 0x5, - HIF_GPIO_MODE_READ = 0x6 -}; - -struct hif_req_control_gpio { - u8 gpio_label; - u8 gpio_mode; -} __packed; - -struct hif_cnf_control_gpio { - __le32 status; - __le32 value; -} __packed; - -enum hif_generic_indication_type { - HIF_GENERIC_INDICATION_TYPE_RAW = 0x0, - HIF_GENERIC_INDICATION_TYPE_STRING = 0x1, - HIF_GENERIC_INDICATION_TYPE_RX_STATS = 0x2, - HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO = 0x3, -}; - -struct hif_rx_stats { - __le32 nb_rx_frame; - __le32 nb_crc_frame; - __le32 per_total; - __le32 throughput; - __le32 nb_rx_by_rate[API_RATE_NUM_ENTRIES]; - __le16 per[API_RATE_NUM_ENTRIES]; - __le16 snr[API_RATE_NUM_ENTRIES]; // signed value - __le16 rssi[API_RATE_NUM_ENTRIES]; // signed value - __le16 cfo[API_RATE_NUM_ENTRIES]; // signed value - __le32 date; - __le32 pwr_clk_freq; - u8 is_ext_pwr_clk; - s8 current_temp; -} __packed; - -struct hif_tx_power_loop_info { - __le16 tx_gain_dig; - __le16 tx_gain_pa; - __le16 target_pout; // signed value - __le16 p_estimation; // signed value - __le16 vpdet; - u8 measurement_index; - u8 reserved; -} __packed; - -struct hif_ind_generic { - __le32 type; - union { - struct hif_rx_stats rx_stats; - struct hif_tx_power_loop_info tx_power_loop_info; - } data; -} __packed; - -enum hif_error { - HIF_ERROR_FIRMWARE_ROLLBACK = 0x00, - HIF_ERROR_FIRMWARE_DEBUG_ENABLED = 0x01, - HIF_ERROR_SLK_OUTDATED_SESSION_KEY = 0x02, - HIF_ERROR_SLK_SESSION_KEY = 0x03, - HIF_ERROR_OOR_VOLTAGE = 0x04, - HIF_ERROR_PDS_PAYLOAD = 0x05, - HIF_ERROR_OOR_TEMPERATURE = 0x06, - HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE = 0x07, - HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED = 0x08, - HIF_ERROR_SLK_OVERFLOW = 0x09, - HIF_ERROR_SLK_DECRYPTION = 0x0a, - HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE = 0x0b, - HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW = 0x0c, - HIF_ERROR_HIF_RX_DATA_TOO_LARGE = 0x0e, - HIF_ERROR_HIF_TX_QUEUE_FULL = 0x0d, - HIF_ERROR_HIF_BUS = 0x0f, - HIF_ERROR_PDS_TESTFEATURE = 0x10, - HIF_ERROR_SLK_UNCONFIGURED = 0x11, -}; - -struct hif_ind_error { - __le32 type; - u8 data[]; -} __packed; - -struct hif_ind_exception { - __le32 type; - u8 data[]; -} __packed; - -enum hif_secure_link_state { - SEC_LINK_UNAVAILABLE = 0x0, - SEC_LINK_RESERVED = 0x1, - SEC_LINK_EVAL = 0x2, - SEC_LINK_ENFORCED = 0x3 -}; - -#endif diff --git a/drivers/staging/wfx/hif_api_mib.h b/drivers/staging/wfx/hif_api_mib.h deleted file mode 100644 index ace924720ce6..000000000000 --- a/drivers/staging/wfx/hif_api_mib.h +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * WFx hardware interface definitions - * - * Copyright (c) 2018-2020, Silicon Laboratories Inc. - */ - -#ifndef WFX_HIF_API_MIB_H -#define WFX_HIF_API_MIB_H - -#include "hif_api_general.h" - -#define HIF_API_IPV4_ADDRESS_SIZE 4 -#define HIF_API_IPV6_ADDRESS_SIZE 16 - -enum hif_mib_ids { - HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE = 0x2000, - HIF_MIB_ID_GL_BLOCK_ACK_INFO = 0x2001, - HIF_MIB_ID_GL_SET_MULTI_MSG = 0x2002, - HIF_MIB_ID_CCA_CONFIG = 0x2003, - HIF_MIB_ID_ETHERTYPE_DATAFRAME_CONDITION = 0x2010, - HIF_MIB_ID_PORT_DATAFRAME_CONDITION = 0x2011, - HIF_MIB_ID_MAGIC_DATAFRAME_CONDITION = 0x2012, - HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION = 0x2013, - HIF_MIB_ID_IPV4_ADDR_DATAFRAME_CONDITION = 0x2014, - HIF_MIB_ID_IPV6_ADDR_DATAFRAME_CONDITION = 0x2015, - HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION = 0x2016, - HIF_MIB_ID_CONFIG_DATA_FILTER = 0x2017, - HIF_MIB_ID_SET_DATA_FILTERING = 0x2018, - HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE = 0x2019, - HIF_MIB_ID_NS_IP_ADDRESSES_TABLE = 0x201A, - HIF_MIB_ID_RX_FILTER = 0x201B, - HIF_MIB_ID_BEACON_FILTER_TABLE = 0x201C, - HIF_MIB_ID_BEACON_FILTER_ENABLE = 0x201D, - HIF_MIB_ID_GRP_SEQ_COUNTER = 0x2030, - HIF_MIB_ID_TSF_COUNTER = 0x2031, - HIF_MIB_ID_STATISTICS_TABLE = 0x2032, - HIF_MIB_ID_COUNTERS_TABLE = 0x2033, - HIF_MIB_ID_MAX_TX_POWER_LEVEL = 0x2034, - HIF_MIB_ID_EXTENDED_COUNTERS_TABLE = 0x2035, - HIF_MIB_ID_DOT11_MAC_ADDRESS = 0x2040, - HIF_MIB_ID_DOT11_MAX_TRANSMIT_MSDU_LIFETIME = 0x2041, - HIF_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME = 0x2042, - HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID = 0x2043, - HIF_MIB_ID_DOT11_RTS_THRESHOLD = 0x2044, - HIF_MIB_ID_SLOT_TIME = 0x2045, - HIF_MIB_ID_CURRENT_TX_POWER_LEVEL = 0x2046, - HIF_MIB_ID_NON_ERP_PROTECTION = 0x2047, - HIF_MIB_ID_TEMPLATE_FRAME = 0x2048, - HIF_MIB_ID_BEACON_WAKEUP_PERIOD = 0x2049, - HIF_MIB_ID_RCPI_RSSI_THRESHOLD = 0x204A, - HIF_MIB_ID_BLOCK_ACK_POLICY = 0x204B, - HIF_MIB_ID_OVERRIDE_INTERNAL_TX_RATE = 0x204C, - HIF_MIB_ID_SET_ASSOCIATION_MODE = 0x204D, - HIF_MIB_ID_SET_UAPSD_INFORMATION = 0x204E, - HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY = 0x204F, - HIF_MIB_ID_PROTECTED_MGMT_POLICY = 0x2050, - HIF_MIB_ID_SET_HT_PROTECTION = 0x2051, - HIF_MIB_ID_KEEP_ALIVE_PERIOD = 0x2052, - HIF_MIB_ID_ARP_KEEP_ALIVE_PERIOD = 0x2053, - HIF_MIB_ID_INACTIVITY_TIMER = 0x2054, - HIF_MIB_ID_INTERFACE_PROTECTION = 0x2055, - HIF_MIB_ID_BEACON_STATS = 0x2056, -}; - -enum hif_op_power_mode { - HIF_OP_POWER_MODE_ACTIVE = 0x0, - HIF_OP_POWER_MODE_DOZE = 0x1, - HIF_OP_POWER_MODE_QUIESCENT = 0x2 -}; - -struct hif_mib_gl_operational_power_mode { - u8 power_mode:4; - u8 reserved1:3; - u8 wup_ind_activation:1; - u8 reserved2[3]; -} __packed; - -struct hif_mib_gl_set_multi_msg { - u8 enable_multi_tx_conf:1; - u8 reserved1:7; - u8 reserved2[3]; -} __packed; - -enum hif_arp_ns_frame_treatment { - HIF_ARP_NS_FILTERING_DISABLE = 0x0, - HIF_ARP_NS_FILTERING_ENABLE = 0x1, - HIF_ARP_NS_REPLY_ENABLE = 0x2 -}; - -struct hif_mib_arp_ip_addr_table { - u8 condition_idx; - u8 arp_enable; - u8 reserved[2]; - u8 ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; -} __packed; - -struct hif_mib_rx_filter { - u8 reserved1:1; - u8 bssid_filter:1; - u8 reserved2:1; - u8 fwd_probe_req:1; - u8 keep_alive_filter:1; - u8 reserved3:3; - u8 reserved4[3]; -} __packed; - -struct hif_ie_table_entry { - u8 ie_id; - u8 has_changed:1; - u8 no_longer:1; - u8 has_appeared:1; - u8 reserved:1; - u8 num_match_data:4; - u8 oui[3]; - u8 match_data[3]; -} __packed; - -struct hif_mib_bcn_filter_table { - __le32 num_of_info_elmts; - struct hif_ie_table_entry ie_table[]; -} __packed; - -enum hif_beacon_filter { - HIF_BEACON_FILTER_DISABLE = 0x0, - HIF_BEACON_FILTER_ENABLE = 0x1, - HIF_BEACON_FILTER_AUTO_ERP = 0x2 -}; - -struct hif_mib_bcn_filter_enable { - __le32 enable; - __le32 bcn_count; -} __packed; - -struct hif_mib_extended_count_table { - __le32 count_plcp_errors; - __le32 count_fcs_errors; - __le32 count_tx_packets; - __le32 count_rx_packets; - __le32 count_rx_packet_errors; - __le32 count_rx_decryption_failures; - __le32 count_rx_mic_failures; - __le32 count_rx_no_key_failures; - __le32 count_tx_multicast_frames; - __le32 count_tx_frames_success; - __le32 count_tx_frame_failures; - __le32 count_tx_frames_retried; - __le32 count_tx_frames_multi_retried; - __le32 count_rx_frame_duplicates; - __le32 count_rts_success; - __le32 count_rts_failures; - __le32 count_ack_failures; - __le32 count_rx_multicast_frames; - __le32 count_rx_frames_success; - __le32 count_rx_cmacicv_errors; - __le32 count_rx_cmac_replays; - __le32 count_rx_mgmt_ccmp_replays; - __le32 count_rx_bipmic_errors; - __le32 count_rx_beacon; - __le32 count_miss_beacon; - __le32 reserved[15]; -} __packed; - -struct hif_mib_count_table { - __le32 count_plcp_errors; - __le32 count_fcs_errors; - __le32 count_tx_packets; - __le32 count_rx_packets; - __le32 count_rx_packet_errors; - __le32 count_rx_decryption_failures; - __le32 count_rx_mic_failures; - __le32 count_rx_no_key_failures; - __le32 count_tx_multicast_frames; - __le32 count_tx_frames_success; - __le32 count_tx_frame_failures; - __le32 count_tx_frames_retried; - __le32 count_tx_frames_multi_retried; - __le32 count_rx_frame_duplicates; - __le32 count_rts_success; - __le32 count_rts_failures; - __le32 count_ack_failures; - __le32 count_rx_multicast_frames; - __le32 count_rx_frames_success; - __le32 count_rx_cmacicv_errors; - __le32 count_rx_cmac_replays; - __le32 count_rx_mgmt_ccmp_replays; - __le32 count_rx_bipmic_errors; -} __packed; - -struct hif_mib_mac_address { - u8 mac_addr[ETH_ALEN]; - __le16 reserved; -} __packed; - -struct hif_mib_wep_default_key_id { - u8 wep_default_key_id; - u8 reserved[3]; -} __packed; - -struct hif_mib_dot11_rts_threshold { - __le32 threshold; -} __packed; - -struct hif_mib_slot_time { - __le32 slot_time; -} __packed; - -struct hif_mib_current_tx_power_level { - __le32 power_level; // signed value -} __packed; - -struct hif_mib_non_erp_protection { - u8 use_cts_to_self:1; - u8 reserved1:7; - u8 reserved2[3]; -} __packed; - -enum hif_tmplt { - HIF_TMPLT_PRBREQ = 0x0, - HIF_TMPLT_BCN = 0x1, - HIF_TMPLT_NULL = 0x2, - HIF_TMPLT_QOSNUL = 0x3, - HIF_TMPLT_PSPOLL = 0x4, - HIF_TMPLT_PRBRES = 0x5, - HIF_TMPLT_ARP = 0x6, - HIF_TMPLT_NA = 0x7 -}; - -#define HIF_API_MAX_TEMPLATE_FRAME_SIZE 700 - -struct hif_mib_template_frame { - u8 frame_type; - u8 init_rate:7; - u8 mode:1; - __le16 frame_length; - u8 frame[]; -} __packed; - -struct hif_mib_beacon_wake_up_period { - u8 wakeup_period_min; - u8 receive_dtim:1; - u8 reserved1:7; - u8 wakeup_period_max; - u8 reserved2; -} __packed; - -struct hif_mib_rcpi_rssi_threshold { - u8 detection:1; - u8 rcpi_rssi:1; - u8 upperthresh:1; - u8 lowerthresh:1; - u8 reserved:4; - u8 lower_threshold; - u8 upper_threshold; - u8 rolling_average_count; -} __packed; - -#define DEFAULT_BA_MAX_RX_BUFFER_SIZE 16 - -struct hif_mib_block_ack_policy { - u8 block_ack_tx_tid_policy; - u8 reserved1; - u8 block_ack_rx_tid_policy; - u8 block_ack_rx_max_buffer_size; -} __packed; - -enum hif_mpdu_start_spacing { - HIF_MPDU_START_SPACING_NO_RESTRIC = 0x0, - HIF_MPDU_START_SPACING_QUARTER = 0x1, - HIF_MPDU_START_SPACING_HALF = 0x2, - HIF_MPDU_START_SPACING_ONE = 0x3, - HIF_MPDU_START_SPACING_TWO = 0x4, - HIF_MPDU_START_SPACING_FOUR = 0x5, - HIF_MPDU_START_SPACING_EIGHT = 0x6, - HIF_MPDU_START_SPACING_SIXTEEN = 0x7 -}; - -struct hif_mib_set_association_mode { - u8 preambtype_use:1; - u8 mode:1; - u8 rateset:1; - u8 spacing:1; - u8 reserved1:4; - u8 short_preamble:1; - u8 reserved2:7; - u8 greenfield:1; - u8 reserved3:7; - u8 mpdu_start_spacing; - __le32 basic_rate_set; -} __packed; - -struct hif_mib_set_uapsd_information { - u8 trig_bckgrnd:1; - u8 trig_be:1; - u8 trig_video:1; - u8 trig_voice:1; - u8 reserved1:4; - u8 deliv_bckgrnd:1; - u8 deliv_be:1; - u8 deliv_video:1; - u8 deliv_voice:1; - u8 reserved2:4; - __le16 min_auto_trigger_interval; - __le16 max_auto_trigger_interval; - __le16 auto_trigger_step; -} __packed; - -struct hif_tx_rate_retry_policy { - u8 policy_index; - u8 short_retry_count; - u8 long_retry_count; - u8 first_rate_sel:2; - u8 terminate:1; - u8 count_init:1; - u8 reserved1:4; - u8 rate_recovery_count; - u8 reserved2[3]; - u8 rates[12]; -} __packed; - -#define HIF_TX_RETRY_POLICY_MAX 15 -#define HIF_TX_RETRY_POLICY_INVALID HIF_TX_RETRY_POLICY_MAX - -struct hif_mib_set_tx_rate_retry_policy { - u8 num_tx_rate_policies; - u8 reserved[3]; - struct hif_tx_rate_retry_policy tx_rate_retry_policy[]; -} __packed; - -struct hif_mib_protected_mgmt_policy { - u8 pmf_enable:1; - u8 unpmf_allowed:1; - u8 host_enc_auth_frames:1; - u8 reserved1:5; - u8 reserved2[3]; -} __packed; - -struct hif_mib_keep_alive_period { - __le16 keep_alive_period; - u8 reserved[2]; -} __packed; - -#endif diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c deleted file mode 100644 index 56a5f891447b..000000000000 --- a/drivers/staging/wfx/hif_rx.c +++ /dev/null @@ -1,415 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac - * (WSM) API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "hif_rx.h" -#include "wfx.h" -#include "scan.h" -#include "bh.h" -#include "sta.h" -#include "data_rx.h" -#include "hif_api_cmd.h" - -static int hif_generic_confirm(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - // All confirm messages start with status - int status = le32_to_cpup((__le32 *)buf); - int cmd = hif->id; - int len = le16_to_cpu(hif->len) - 4; // drop header - - WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); - - if (!wdev->hif_cmd.buf_send) { - dev_warn(wdev->dev, "unexpected confirmation: 0x%.2x\n", cmd); - return -EINVAL; - } - - if (cmd != wdev->hif_cmd.buf_send->id) { - dev_warn(wdev->dev, - "chip response mismatch request: 0x%.2x vs 0x%.2x\n", - cmd, wdev->hif_cmd.buf_send->id); - return -EINVAL; - } - - if (wdev->hif_cmd.buf_recv) { - if (wdev->hif_cmd.len_recv >= len && len > 0) - memcpy(wdev->hif_cmd.buf_recv, buf, len); - else - status = -EIO; - } - wdev->hif_cmd.ret = status; - - complete(&wdev->hif_cmd.done); - return status; -} - -static int hif_tx_confirm(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_cnf_tx *body = buf; - - wfx_tx_confirm_cb(wdev, body); - return 0; -} - -static int hif_multi_tx_confirm(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_cnf_multi_transmit *body = buf; - int i; - - WARN(body->num_tx_confs <= 0, "corrupted message"); - for (i = 0; i < body->num_tx_confs; i++) - wfx_tx_confirm_cb(wdev, &body->tx_conf_payload[i]); - return 0; -} - -static int hif_startup_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_ind_startup *body = buf; - - if (body->status || body->firmware_type > 4) { - dev_err(wdev->dev, "received invalid startup indication"); - return -EINVAL; - } - memcpy(&wdev->hw_caps, body, sizeof(struct hif_ind_startup)); - le16_to_cpus((__le16 *)&wdev->hw_caps.hardware_id); - le16_to_cpus((__le16 *)&wdev->hw_caps.num_inp_ch_bufs); - le16_to_cpus((__le16 *)&wdev->hw_caps.size_inp_ch_buf); - le32_to_cpus((__le32 *)&wdev->hw_caps.supported_rate_mask); - - complete(&wdev->firmware_ready); - return 0; -} - -static int hif_wakeup_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - if (!wdev->pdata.gpio_wakeup || - gpiod_get_value(wdev->pdata.gpio_wakeup) == 0) { - dev_warn(wdev->dev, "unexpected wake-up indication\n"); - return -EIO; - } - return 0; -} - -static int hif_receive_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf, struct sk_buff *skb) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - const struct hif_ind_rx *body = buf; - - if (!wvif) { - dev_warn(wdev->dev, "%s: ignore rx data for non-existent vif %d\n", - __func__, hif->interface); - return -EIO; - } - skb_pull(skb, sizeof(struct hif_msg) + sizeof(struct hif_ind_rx)); - wfx_rx_cb(wvif, body, skb); - - return 0; -} - -static int hif_event_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - const struct hif_ind_event *body = buf; - int type = le32_to_cpu(body->event_id); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - - switch (type) { - case HIF_EVENT_IND_RCPI_RSSI: - wfx_event_report_rssi(wvif, body->event_data.rcpi_rssi); - break; - case HIF_EVENT_IND_BSSLOST: - schedule_delayed_work(&wvif->beacon_loss_work, 0); - break; - case HIF_EVENT_IND_BSSREGAINED: - cancel_delayed_work(&wvif->beacon_loss_work); - dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n"); - break; - case HIF_EVENT_IND_PS_MODE_ERROR: - dev_warn(wdev->dev, "error while processing power save request: %d\n", - le32_to_cpu(body->event_data.ps_mode_error)); - break; - default: - dev_warn(wdev->dev, "unhandled event indication: %.2x\n", - type); - break; - } - return 0; -} - -static int hif_pm_mode_complete_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - complete(&wvif->set_pm_mode_complete); - - return 0; -} - -static int hif_scan_complete_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - - wfx_scan_complete(wvif); - - return 0; -} - -static int hif_join_complete_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - dev_warn(wdev->dev, "unattended JoinCompleteInd\n"); - - return 0; -} - -static int hif_suspend_resume_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf) -{ - const struct hif_ind_suspend_resume_tx *body = buf; - struct wfx_vif *wvif; - - if (body->bc_mc_only) { - wvif = wdev_to_wvif(wdev, hif->interface); - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - if (body->resume) - wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE); - else - wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP); - } else { - WARN(body->peer_sta_set, "misunderstood indication"); - WARN(hif->interface != 2, "misunderstood indication"); - if (body->resume) - wfx_suspend_hot_dev(wdev, STA_NOTIFY_AWAKE); - else - wfx_suspend_hot_dev(wdev, STA_NOTIFY_SLEEP); - } - - return 0; -} - -static int hif_generic_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_ind_generic *body = buf; - int type = le32_to_cpu(body->type); - - switch (type) { - case HIF_GENERIC_INDICATION_TYPE_RAW: - return 0; - case HIF_GENERIC_INDICATION_TYPE_STRING: - dev_info(wdev->dev, "firmware says: %s\n", (char *)&body->data); - return 0; - case HIF_GENERIC_INDICATION_TYPE_RX_STATS: - mutex_lock(&wdev->rx_stats_lock); - // Older firmware send a generic indication beside RxStats - if (!wfx_api_older_than(wdev, 1, 4)) - dev_info(wdev->dev, "Rx test ongoing. Temperature: %d degrees C\n", - body->data.rx_stats.current_temp); - memcpy(&wdev->rx_stats, &body->data.rx_stats, - sizeof(wdev->rx_stats)); - mutex_unlock(&wdev->rx_stats_lock); - return 0; - case HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO: - mutex_lock(&wdev->tx_power_loop_info_lock); - memcpy(&wdev->tx_power_loop_info, - &body->data.tx_power_loop_info, - sizeof(wdev->tx_power_loop_info)); - mutex_unlock(&wdev->tx_power_loop_info_lock); - return 0; - default: - dev_err(wdev->dev, "generic_indication: unknown indication type: %#.8x\n", - type); - return -EIO; - } -} - -static const struct { - int val; - const char *str; - bool has_param; -} hif_errors[] = { - { HIF_ERROR_FIRMWARE_ROLLBACK, - "rollback status" }, - { HIF_ERROR_FIRMWARE_DEBUG_ENABLED, - "debug feature enabled" }, - { HIF_ERROR_PDS_PAYLOAD, - "PDS version is not supported" }, - { HIF_ERROR_PDS_TESTFEATURE, - "PDS ask for an unknown test mode" }, - { HIF_ERROR_OOR_VOLTAGE, - "out-of-range power supply voltage", true }, - { HIF_ERROR_OOR_TEMPERATURE, - "out-of-range temperature", true }, - { HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE, - "secure link does not expect request during key exchange" }, - { HIF_ERROR_SLK_SESSION_KEY, - "secure link session key is invalid" }, - { HIF_ERROR_SLK_OVERFLOW, - "secure link overflow" }, - { HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE, - "secure link messages list does not match message encryption" }, - { HIF_ERROR_SLK_UNCONFIGURED, - "secure link not yet configured" }, - { HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW, - "bus clock is too slow (<1kHz)" }, - { HIF_ERROR_HIF_RX_DATA_TOO_LARGE, - "HIF message too large" }, - // Following errors only exists in old firmware versions: - { HIF_ERROR_HIF_TX_QUEUE_FULL, - "HIF messages queue is full" }, - { HIF_ERROR_HIF_BUS, - "HIF bus" }, - { HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED, - "secure link does not support multi-tx confirmations" }, - { HIF_ERROR_SLK_OUTDATED_SESSION_KEY, - "secure link session key is outdated" }, - { HIF_ERROR_SLK_DECRYPTION, - "secure link params (nonce or tag) mismatch" }, -}; - -static int hif_error_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_ind_error *body = buf; - int type = le32_to_cpu(body->type); - int param = (s8)body->data[0]; - int i; - - for (i = 0; i < ARRAY_SIZE(hif_errors); i++) - if (type == hif_errors[i].val) - break; - if (i < ARRAY_SIZE(hif_errors)) - if (hif_errors[i].has_param) - dev_err(wdev->dev, "asynchronous error: %s: %d\n", - hif_errors[i].str, param); - else - dev_err(wdev->dev, "asynchronous error: %s\n", - hif_errors[i].str); - else - dev_err(wdev->dev, "asynchronous error: unknown: %08x\n", type); - print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, - 16, 1, hif, le16_to_cpu(hif->len), false); - wdev->chip_frozen = true; - - return 0; -}; - -static int hif_exception_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_ind_exception *body = buf; - int type = le32_to_cpu(body->type); - - if (type == 4) - dev_err(wdev->dev, "firmware assert %d\n", - le32_to_cpup((__le32 *)body->data)); - else - dev_err(wdev->dev, "firmware exception\n"); - print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, - 16, 1, hif, le16_to_cpu(hif->len), false); - wdev->chip_frozen = true; - - return -1; -} - -static const struct { - int msg_id; - int (*handler)(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf); -} hif_handlers[] = { - /* Confirmations */ - { HIF_CNF_ID_TX, hif_tx_confirm }, - { HIF_CNF_ID_MULTI_TRANSMIT, hif_multi_tx_confirm }, - /* Indications */ - { HIF_IND_ID_STARTUP, hif_startup_indication }, - { HIF_IND_ID_WAKEUP, hif_wakeup_indication }, - { HIF_IND_ID_JOIN_COMPLETE, hif_join_complete_indication }, - { HIF_IND_ID_SET_PM_MODE_CMPL, hif_pm_mode_complete_indication }, - { HIF_IND_ID_SCAN_CMPL, hif_scan_complete_indication }, - { HIF_IND_ID_SUSPEND_RESUME_TX, hif_suspend_resume_indication }, - { HIF_IND_ID_EVENT, hif_event_indication }, - { HIF_IND_ID_GENERIC, hif_generic_indication }, - { HIF_IND_ID_ERROR, hif_error_indication }, - { HIF_IND_ID_EXCEPTION, hif_exception_indication }, - // FIXME: allocate skb_p from hif_receive_indication and make it generic - //{ HIF_IND_ID_RX, hif_receive_indication }, -}; - -void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb) -{ - int i; - const struct hif_msg *hif = (const struct hif_msg *)skb->data; - int hif_id = hif->id; - - if (hif_id == HIF_IND_ID_RX) { - // hif_receive_indication take care of skb lifetime - hif_receive_indication(wdev, hif, hif->body, skb); - return; - } - // Note: mutex_is_lock cause an implicit memory barrier that protect - // buf_send - if (mutex_is_locked(&wdev->hif_cmd.lock) - && wdev->hif_cmd.buf_send - && wdev->hif_cmd.buf_send->id == hif_id) { - hif_generic_confirm(wdev, hif, hif->body); - goto free; - } - for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) { - if (hif_handlers[i].msg_id == hif_id) { - if (hif_handlers[i].handler) - hif_handlers[i].handler(wdev, hif, hif->body); - goto free; - } - } - if (hif_id & 0x80) - dev_err(wdev->dev, "unsupported HIF indication: ID %02x\n", - hif_id); - else - dev_err(wdev->dev, "unexpected HIF confirmation: ID %02x\n", - hif_id); -free: - dev_kfree_skb(skb); -} diff --git a/drivers/staging/wfx/hif_rx.h b/drivers/staging/wfx/hif_rx.h deleted file mode 100644 index f07c10c8c6bd..000000000000 --- a/drivers/staging/wfx/hif_rx.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac - * (WSM) API. - * - * Copyright (c) 2017-2019, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (C) 2010, ST-Ericsson SA - */ -#ifndef WFX_HIF_RX_H -#define WFX_HIF_RX_H - -struct wfx_dev; -struct sk_buff; - -void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb); - -#endif diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c deleted file mode 100644 index 63b437261eb7..000000000000 --- a/drivers/staging/wfx/hif_tx.c +++ /dev/null @@ -1,523 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx - * Split Mac (WSM) 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 WSM 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, - "WSM 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, - "WSM 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 *timeout) -{ - 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); - int tmo_chan_fg, tmo_chan_bg, tmo; - - 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; - } - tmo_chan_bg = le32_to_cpu(body->max_channel_time) * USEC_PER_TU; - tmo_chan_fg = 512 * USEC_PER_TU + body->probe_delay; - tmo_chan_fg *= body->num_of_probe_requests; - tmo = chan_num * max(tmo_chan_bg, tmo_chan_fg) + 512 * USEC_PER_TU; - if (timeout) - *timeout = usecs_to_jiffies(tmo); - - 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(sizeof(body->ssid) < ssidlen); - WARN(!conf->ibss_joined && !ssidlen, "joining an unknown BSS"); - if (WARN_ON(!channel)) - return -EINVAL; - if (!hif) - return -ENOMEM; - body->infrastructure_bss_mode = !conf->ibss_joined; - body->short_preamble = conf->use_short_preamble; - if (channel->flags & IEEE80211_CHAN_NO_IR) - body->probe_for_join = 0; - else - body->probe_for_join = 1; - 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/staging/wfx/hif_tx.h b/drivers/staging/wfx/hif_tx.h deleted file mode 100644 index 3521c545ae6b..000000000000 --- a/drivers/staging/wfx/hif_tx.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx - * Split Mac (WSM) 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 *timeout); -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/staging/wfx/hif_tx_mib.c b/drivers/staging/wfx/hif_tx_mib.c deleted file mode 100644 index 1926cf1b62be..000000000000 --- a/drivers/staging/wfx/hif_tx_mib.c +++ /dev/null @@ -1,324 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) 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 msg = { }; - - if (mac) - ether_addr_copy(msg.mac_addr, mac); - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS, - &msg, sizeof(msg)); -} - -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/staging/wfx/hif_tx_mib.h b/drivers/staging/wfx/hif_tx_mib.h deleted file mode 100644 index 812b3ba0f00e..000000000000 --- a/drivers/staging/wfx/hif_tx_mib.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) 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 diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c deleted file mode 100644 index 36fbc5b5d64c..000000000000 --- a/drivers/staging/wfx/hwio.c +++ /dev/null @@ -1,352 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Low-level I/O functions. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include - -#include "hwio.h" -#include "wfx.h" -#include "bus.h" -#include "traces.h" - -/* - * Internal helpers. - * - * About CONFIG_VMAP_STACK: - * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack - * allocated data. Functions below that work with registers (aka functions - * ending with "32") automatically reallocate buffers with kmalloc. However, - * functions that work with arbitrary length buffers let's caller to handle - * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located - * buffer. - */ - -static int read32(struct wfx_dev *wdev, int reg, u32 *val) -{ - int ret; - __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); - - *val = ~0; // Never return undefined value - if (!tmp) - return -ENOMEM; - ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, - sizeof(u32)); - if (ret >= 0) - *val = le32_to_cpu(*tmp); - kfree(tmp); - if (ret) - dev_err(wdev->dev, "%s: bus communication error: %d\n", - __func__, ret); - return ret; -} - -static int write32(struct wfx_dev *wdev, int reg, u32 val) -{ - int ret; - __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); - - if (!tmp) - return -ENOMEM; - *tmp = cpu_to_le32(val); - ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, - sizeof(u32)); - kfree(tmp); - if (ret) - dev_err(wdev->dev, "%s: bus communication error: %d\n", - __func__, ret); - return ret; -} - -static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val) -{ - int ret; - - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = read32(wdev, reg, val); - _trace_io_read32(reg, *val); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int write32_locked(struct wfx_dev *wdev, int reg, u32 val) -{ - int ret; - - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = write32(wdev, reg, val); - _trace_io_write32(reg, val); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val) -{ - int ret; - u32 val_r, val_w; - - WARN_ON(~mask & val); - val &= mask; - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = read32(wdev, reg, &val_r); - _trace_io_read32(reg, val_r); - if (ret < 0) - goto err; - val_w = (val_r & ~mask) | val; - if (val_w != val_r) { - ret = write32(wdev, reg, val_w); - _trace_io_write32(reg, val_w); - } -err: - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, - void *buf, size_t len) -{ - int ret; - int i; - u32 cfg; - u32 prefetch; - - WARN_ON(len >= 0x2000); - WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); - - if (reg == WFX_REG_AHB_DPORT) - prefetch = CFG_PREFETCH_AHB; - else if (reg == WFX_REG_SRAM_DPORT) - prefetch = CFG_PREFETCH_SRAM; - else - return -ENODEV; - - ret = write32(wdev, WFX_REG_BASE_ADDR, addr); - if (ret < 0) - goto err; - - ret = read32(wdev, WFX_REG_CONFIG, &cfg); - if (ret < 0) - goto err; - - ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch); - if (ret < 0) - goto err; - - for (i = 0; i < 20; i++) { - ret = read32(wdev, WFX_REG_CONFIG, &cfg); - if (ret < 0) - goto err; - if (!(cfg & prefetch)) - break; - usleep_range(200, 250); - } - if (i == 20) { - ret = -ETIMEDOUT; - goto err; - } - - ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len); - -err: - if (ret < 0) - memset(buf, 0xFF, len); // Never return undefined value - return ret; -} - -static int indirect_write(struct wfx_dev *wdev, int reg, u32 addr, - const void *buf, size_t len) -{ - int ret; - - WARN_ON(len >= 0x2000); - WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); - ret = write32(wdev, WFX_REG_BASE_ADDR, addr); - if (ret < 0) - return ret; - - return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len); -} - -static int indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr, - void *buf, size_t len) -{ - int ret; - - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = indirect_read(wdev, reg, addr, buf, len); - _trace_io_ind_read(reg, addr, buf, len); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr, - const void *buf, size_t len) -{ - int ret; - - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = indirect_write(wdev, reg, addr, buf, len); - _trace_io_ind_write(reg, addr, buf, len); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int indirect_read32_locked(struct wfx_dev *wdev, int reg, - u32 addr, u32 *val) -{ - int ret; - __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); - - if (!tmp) - return -ENOMEM; - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32)); - *val = le32_to_cpu(*tmp); - _trace_io_ind_read32(reg, addr, *val); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - kfree(tmp); - return ret; -} - -static int indirect_write32_locked(struct wfx_dev *wdev, int reg, - u32 addr, u32 val) -{ - int ret; - __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); - - if (!tmp) - return -ENOMEM; - *tmp = cpu_to_le32(val); - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32)); - _trace_io_ind_write32(reg, addr, val); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - kfree(tmp); - return ret; -} - -int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len) -{ - int ret; - - WARN((long)buf & 3, "%s: unaligned buffer", __func__); - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, - WFX_REG_IN_OUT_QUEUE, buf, len); - _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - if (ret) - dev_err(wdev->dev, "%s: bus communication error: %d\n", - __func__, ret); - return ret; -} - -int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len) -{ - int ret; - - WARN((long)buf & 3, "%s: unaligned buffer", __func__); - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, - WFX_REG_IN_OUT_QUEUE, buf, len); - _trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - if (ret) - dev_err(wdev->dev, "%s: bus communication error: %d\n", - __func__, ret); - return ret; -} - -int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) -{ - return indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); -} - -int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) -{ - return indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); -} - -int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) -{ - return indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); -} - -int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) -{ - return indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); -} - -int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) -{ - return indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); -} - -int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) -{ - return indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); -} - -int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) -{ - return indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); -} - -int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) -{ - return indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); -} - -int config_reg_read(struct wfx_dev *wdev, u32 *val) -{ - return read32_locked(wdev, WFX_REG_CONFIG, val); -} - -int config_reg_write(struct wfx_dev *wdev, u32 val) -{ - return write32_locked(wdev, WFX_REG_CONFIG, val); -} - -int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) -{ - return write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val); -} - -int control_reg_read(struct wfx_dev *wdev, u32 *val) -{ - return read32_locked(wdev, WFX_REG_CONTROL, val); -} - -int control_reg_write(struct wfx_dev *wdev, u32 val) -{ - return write32_locked(wdev, WFX_REG_CONTROL, val); -} - -int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) -{ - return write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val); -} - -int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val) -{ - int ret; - - *val = ~0; // Never return undefined value - ret = write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24); - if (ret) - return ret; - ret = read32_locked(wdev, WFX_REG_SET_GEN_R_W, val); - if (ret) - return ret; - *val &= IGPR_VALUE; - return ret; -} - -int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val) -{ - return write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val); -} diff --git a/drivers/staging/wfx/hwio.h b/drivers/staging/wfx/hwio.h deleted file mode 100644 index 0b8e4f7157df..000000000000 --- a/drivers/staging/wfx/hwio.h +++ /dev/null @@ -1,75 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Low-level API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_HWIO_H -#define WFX_HWIO_H - -#include - -struct wfx_dev; - -int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t buf_len); -int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t buf_len); - -int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); -int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); - -int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); -int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); - -int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); -int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); - -int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); -int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); - -#define CFG_ERR_SPI_FRAME 0x00000001 // only with SPI -#define CFG_ERR_SDIO_BUF_MISMATCH 0x00000001 // only with SDIO -#define CFG_ERR_BUF_UNDERRUN 0x00000002 -#define CFG_ERR_DATA_IN_TOO_LARGE 0x00000004 -#define CFG_ERR_HOST_NO_OUT_QUEUE 0x00000008 -#define CFG_ERR_BUF_OVERRUN 0x00000010 -#define CFG_ERR_DATA_OUT_TOO_LARGE 0x00000020 -#define CFG_ERR_HOST_NO_IN_QUEUE 0x00000040 -#define CFG_ERR_HOST_CRC_MISS 0x00000080 // only with SDIO -#define CFG_SPI_IGNORE_CS 0x00000080 // only with SPI -#define CFG_BYTE_ORDER_MASK 0x00000300 // only writable with SPI -#define CFG_BYTE_ORDER_BADC 0x00000000 -#define CFG_BYTE_ORDER_DCBA 0x00000100 -#define CFG_BYTE_ORDER_ABCD 0x00000200 // SDIO always use this value -#define CFG_DIRECT_ACCESS_MODE 0x00000400 -#define CFG_PREFETCH_AHB 0x00000800 -#define CFG_DISABLE_CPU_CLK 0x00001000 -#define CFG_PREFETCH_SRAM 0x00002000 -#define CFG_CPU_RESET 0x00004000 -#define CFG_SDIO_DISABLE_IRQ 0x00008000 // only with SDIO -#define CFG_IRQ_ENABLE_DATA 0x00010000 -#define CFG_IRQ_ENABLE_WRDY 0x00020000 -#define CFG_CLK_RISE_EDGE 0x00040000 -#define CFG_SDIO_DISABLE_CRC_CHK 0x00080000 // only with SDIO -#define CFG_RESERVED 0x00F00000 -#define CFG_DEVICE_ID_MAJOR 0x07000000 -#define CFG_DEVICE_ID_RESERVED 0x78000000 -#define CFG_DEVICE_ID_TYPE 0x80000000 -int config_reg_read(struct wfx_dev *wdev, u32 *val); -int config_reg_write(struct wfx_dev *wdev, u32 val); -int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); - -#define CTRL_NEXT_LEN_MASK 0x00000FFF -#define CTRL_WLAN_WAKEUP 0x00001000 -#define CTRL_WLAN_READY 0x00002000 -int control_reg_read(struct wfx_dev *wdev, u32 *val); -int control_reg_write(struct wfx_dev *wdev, u32 val); -int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); - -#define IGPR_RW 0x80000000 -#define IGPR_INDEX 0x7F000000 -#define IGPR_VALUE 0x00FFFFFF -int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val); -int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val); - -#endif /* WFX_HWIO_H */ diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c deleted file mode 100644 index 2ab82bed4c1b..000000000000 --- a/drivers/staging/wfx/key.c +++ /dev/null @@ -1,241 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Key management related functions. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "key.h" -#include "wfx.h" -#include "hif_tx_mib.h" - -static int wfx_alloc_key(struct wfx_dev *wdev) -{ - int idx; - - idx = ffs(~wdev->key_map) - 1; - if (idx < 0 || idx >= MAX_KEY_ENTRIES) - return -1; - - wdev->key_map |= BIT(idx); - return idx; -} - -static void wfx_free_key(struct wfx_dev *wdev, int idx) -{ - WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation"); - wdev->key_map &= ~BIT(idx); -} - -static u8 fill_wep_pair(struct hif_wep_pairwise_key *msg, - struct ieee80211_key_conf *key, u8 *peer_addr) -{ - WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); - msg->key_length = key->keylen; - memcpy(msg->key_data, key->key, key->keylen); - ether_addr_copy(msg->peer_address, peer_addr); - return HIF_KEY_TYPE_WEP_PAIRWISE; -} - -static u8 fill_wep_group(struct hif_wep_group_key *msg, - struct ieee80211_key_conf *key) -{ - WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); - msg->key_id = key->keyidx; - msg->key_length = key->keylen; - memcpy(msg->key_data, key->key, key->keylen); - return HIF_KEY_TYPE_WEP_DEFAULT; -} - -static u8 fill_tkip_pair(struct hif_tkip_pairwise_key *msg, - struct ieee80211_key_conf *key, u8 *peer_addr) -{ - u8 *keybuf = key->key; - - WARN(key->keylen != sizeof(msg->tkip_key_data) - + sizeof(msg->tx_mic_key) - + sizeof(msg->rx_mic_key), "inconsistent data"); - memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); - keybuf += sizeof(msg->tkip_key_data); - memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key)); - keybuf += sizeof(msg->tx_mic_key); - memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key)); - ether_addr_copy(msg->peer_address, peer_addr); - return HIF_KEY_TYPE_TKIP_PAIRWISE; -} - -static u8 fill_tkip_group(struct hif_tkip_group_key *msg, - struct ieee80211_key_conf *key, - struct ieee80211_key_seq *seq, - enum nl80211_iftype iftype) -{ - u8 *keybuf = key->key; - - WARN(key->keylen != sizeof(msg->tkip_key_data) - + 2 * sizeof(msg->rx_mic_key), "inconsistent data"); - msg->key_id = key->keyidx; - memcpy(msg->rx_sequence_counter, - &seq->tkip.iv16, sizeof(seq->tkip.iv16)); - memcpy(msg->rx_sequence_counter + sizeof(u16), - &seq->tkip.iv32, sizeof(seq->tkip.iv32)); - memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); - keybuf += sizeof(msg->tkip_key_data); - if (iftype == NL80211_IFTYPE_AP) - // Use Tx MIC Key - memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key)); - else - // Use Rx MIC Key - memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key)); - return HIF_KEY_TYPE_TKIP_GROUP; -} - -static u8 fill_ccmp_pair(struct hif_aes_pairwise_key *msg, - struct ieee80211_key_conf *key, u8 *peer_addr) -{ - WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); - ether_addr_copy(msg->peer_address, peer_addr); - memcpy(msg->aes_key_data, key->key, key->keylen); - return HIF_KEY_TYPE_AES_PAIRWISE; -} - -static u8 fill_ccmp_group(struct hif_aes_group_key *msg, - struct ieee80211_key_conf *key, - struct ieee80211_key_seq *seq) -{ - WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); - memcpy(msg->aes_key_data, key->key, key->keylen); - memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn)); - memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn)); - msg->key_id = key->keyidx; - return HIF_KEY_TYPE_AES_GROUP; -} - -static u8 fill_sms4_pair(struct hif_wapi_pairwise_key *msg, - struct ieee80211_key_conf *key, u8 *peer_addr) -{ - u8 *keybuf = key->key; - - WARN(key->keylen != sizeof(msg->wapi_key_data) - + sizeof(msg->mic_key_data), "inconsistent data"); - ether_addr_copy(msg->peer_address, peer_addr); - memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); - keybuf += sizeof(msg->wapi_key_data); - memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); - msg->key_id = key->keyidx; - return HIF_KEY_TYPE_WAPI_PAIRWISE; -} - -static u8 fill_sms4_group(struct hif_wapi_group_key *msg, - struct ieee80211_key_conf *key) -{ - u8 *keybuf = key->key; - - WARN(key->keylen != sizeof(msg->wapi_key_data) - + sizeof(msg->mic_key_data), "inconsistent data"); - memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); - keybuf += sizeof(msg->wapi_key_data); - memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); - msg->key_id = key->keyidx; - return HIF_KEY_TYPE_WAPI_GROUP; -} - -static u8 fill_aes_cmac_group(struct hif_igtk_group_key *msg, - struct ieee80211_key_conf *key, - struct ieee80211_key_seq *seq) -{ - WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data"); - memcpy(msg->igtk_key_data, key->key, key->keylen); - memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn)); - memreverse(msg->ipn, sizeof(seq->aes_cmac.pn)); - msg->key_id = key->keyidx; - return HIF_KEY_TYPE_IGTK_GROUP; -} - -static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - int ret; - struct hif_req_add_key k = { }; - struct ieee80211_key_seq seq; - struct wfx_dev *wdev = wvif->wdev; - int idx = wfx_alloc_key(wvif->wdev); - bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE; - - WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data"); - ieee80211_get_key_rx_seq(key, 0, &seq); - if (idx < 0) - return -EINVAL; - k.int_id = wvif->id; - k.entry_index = idx; - if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || - key->cipher == WLAN_CIPHER_SUITE_WEP104) { - if (pairwise) - k.type = fill_wep_pair(&k.key.wep_pairwise_key, key, - sta->addr); - else - k.type = fill_wep_group(&k.key.wep_group_key, key); - } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - if (pairwise) - k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key, - sta->addr); - else - k.type = fill_tkip_group(&k.key.tkip_group_key, key, - &seq, wvif->vif->type); - } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) { - if (pairwise) - k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key, - sta->addr); - else - k.type = fill_ccmp_group(&k.key.aes_group_key, key, - &seq); - } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) { - if (pairwise) - k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key, - sta->addr); - else - k.type = fill_sms4_group(&k.key.wapi_group_key, key); - } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { - k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, &seq); - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; - } else { - dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher); - wfx_free_key(wdev, idx); - return -EOPNOTSUPP; - } - ret = hif_add_key(wdev, &k); - if (ret) { - wfx_free_key(wdev, idx); - return -EOPNOTSUPP; - } - key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | - IEEE80211_KEY_FLAG_RESERVE_TAILROOM; - key->hw_key_idx = idx; - return 0; -} - -static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key) -{ - WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx"); - wfx_free_key(wvif->wdev, key->hw_key_idx); - return hif_remove_key(wvif->wdev, key->hw_key_idx); -} - -int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - int ret = -EOPNOTSUPP; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - mutex_lock(&wvif->wdev->conf_mutex); - if (cmd == SET_KEY) - ret = wfx_add_key(wvif, sta, key); - if (cmd == DISABLE_KEY) - ret = wfx_remove_key(wvif, key); - mutex_unlock(&wvif->wdev->conf_mutex); - return ret; -} - diff --git a/drivers/staging/wfx/key.h b/drivers/staging/wfx/key.h deleted file mode 100644 index 70a44d0ca35e..000000000000 --- a/drivers/staging/wfx/key.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of mac80211 API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_KEY_H -#define WFX_KEY_H - -#include - -struct wfx_dev; -struct wfx_vif; - -int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); - -#endif /* WFX_STA_H */ diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c deleted file mode 100644 index e7bc1988124a..000000000000 --- a/drivers/staging/wfx/main.c +++ /dev/null @@ -1,490 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Device probe and register. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (c) 2008, Johannes Berg - * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). - * Copyright (c) 2007-2009, Christian Lamparter - * Copyright (c) 2006, Michael Wu - * Copyright (c) 2004-2006 Jean-Baptiste Note , et al. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "main.h" -#include "wfx.h" -#include "fwio.h" -#include "hwio.h" -#include "bus.h" -#include "bh.h" -#include "sta.h" -#include "key.h" -#include "scan.h" -#include "debug.h" -#include "data_tx.h" -#include "hif_tx_mib.h" -#include "hif_api_cmd.h" - -#define WFX_PDS_MAX_SIZE 1500 - -MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx"); -MODULE_AUTHOR("Jérôme Pouiller "); -MODULE_LICENSE("GPL"); - -#define RATETAB_ENT(_rate, _rateid, _flags) { \ - .bitrate = (_rate), \ - .hw_value = (_rateid), \ - .flags = (_flags), \ -} - -static struct ieee80211_rate wfx_rates[] = { - RATETAB_ENT(10, 0, 0), - RATETAB_ENT(20, 1, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(55, 2, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(110, 3, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(60, 6, 0), - RATETAB_ENT(90, 7, 0), - RATETAB_ENT(120, 8, 0), - RATETAB_ENT(180, 9, 0), - RATETAB_ENT(240, 10, 0), - RATETAB_ENT(360, 11, 0), - RATETAB_ENT(480, 12, 0), - RATETAB_ENT(540, 13, 0), -}; - -#define CHAN2G(_channel, _freq, _flags) { \ - .band = NL80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - -static struct ieee80211_channel wfx_2ghz_chantable[] = { - CHAN2G(1, 2412, 0), - CHAN2G(2, 2417, 0), - CHAN2G(3, 2422, 0), - CHAN2G(4, 2427, 0), - CHAN2G(5, 2432, 0), - CHAN2G(6, 2437, 0), - CHAN2G(7, 2442, 0), - CHAN2G(8, 2447, 0), - CHAN2G(9, 2452, 0), - CHAN2G(10, 2457, 0), - CHAN2G(11, 2462, 0), - CHAN2G(12, 2467, 0), - CHAN2G(13, 2472, 0), - CHAN2G(14, 2484, 0), -}; - -static const struct ieee80211_supported_band wfx_band_2ghz = { - .channels = wfx_2ghz_chantable, - .n_channels = ARRAY_SIZE(wfx_2ghz_chantable), - .bitrates = wfx_rates, - .n_bitrates = ARRAY_SIZE(wfx_rates), - .ht_cap = { - // Receive caps - .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_MAX_AMSDU | - (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), - .ht_supported = 1, - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, - .mcs = { - .rx_mask = { 0xFF }, // MCS0 to MCS7 - .rx_highest = cpu_to_le16(72), - .tx_params = IEEE80211_HT_MCS_TX_DEFINED, - }, - }, -}; - -static const struct ieee80211_iface_limit wdev_iface_limits[] = { - { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, - { .max = 1, .types = BIT(NL80211_IFTYPE_AP) }, -}; - -static const struct ieee80211_iface_combination wfx_iface_combinations[] = { - { - .num_different_channels = 2, - .max_interfaces = 2, - .limits = wdev_iface_limits, - .n_limits = ARRAY_SIZE(wdev_iface_limits), - } -}; - -static const struct ieee80211_ops wfx_ops = { - .start = wfx_start, - .stop = wfx_stop, - .add_interface = wfx_add_interface, - .remove_interface = wfx_remove_interface, - .config = wfx_config, - .tx = wfx_tx, - .join_ibss = wfx_join_ibss, - .leave_ibss = wfx_leave_ibss, - .conf_tx = wfx_conf_tx, - .hw_scan = wfx_hw_scan, - .cancel_hw_scan = wfx_cancel_hw_scan, - .start_ap = wfx_start_ap, - .stop_ap = wfx_stop_ap, - .sta_add = wfx_sta_add, - .sta_remove = wfx_sta_remove, - .set_tim = wfx_set_tim, - .set_key = wfx_set_key, - .set_rts_threshold = wfx_set_rts_threshold, - .set_default_unicast_key = wfx_set_default_unicast_key, - .bss_info_changed = wfx_bss_info_changed, - .configure_filter = wfx_configure_filter, - .ampdu_action = wfx_ampdu_action, - .flush = wfx_flush, - .add_chanctx = wfx_add_chanctx, - .remove_chanctx = wfx_remove_chanctx, - .change_chanctx = wfx_change_chanctx, - .assign_vif_chanctx = wfx_assign_vif_chanctx, - .unassign_vif_chanctx = wfx_unassign_vif_chanctx, -}; - -bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor) -{ - if (wdev->hw_caps.api_version_major < major) - return true; - if (wdev->hw_caps.api_version_major > major) - return false; - if (wdev->hw_caps.api_version_minor < minor) - return true; - return false; -} - -/* NOTE: wfx_send_pds() destroy buf */ -int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len) -{ - int ret; - int start, brace_level, i; - - start = 0; - brace_level = 0; - if (buf[0] != '{') { - dev_err(wdev->dev, "valid PDS start with '{'. Did you forget to compress it?\n"); - return -EINVAL; - } - for (i = 1; i < len - 1; i++) { - if (buf[i] == '{') - brace_level++; - if (buf[i] == '}') - brace_level--; - if (buf[i] == '}' && !brace_level) { - i++; - if (i - start + 1 > WFX_PDS_MAX_SIZE) - return -EFBIG; - buf[start] = '{'; - buf[i] = 0; - dev_dbg(wdev->dev, "send PDS '%s}'\n", buf + start); - buf[i] = '}'; - ret = hif_configuration(wdev, buf + start, - i - start + 1); - if (ret > 0) { - dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n", - start, i); - return -EINVAL; - } - if (ret == -ETIMEDOUT) { - dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n", - start, i); - return ret; - } - if (ret) { - dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n", - start, i); - return -EIO; - } - buf[i] = ','; - start = i; - } - } - return 0; -} - -static int wfx_send_pdata_pds(struct wfx_dev *wdev) -{ - int ret = 0; - const struct firmware *pds; - u8 *tmp_buf; - - ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev); - if (ret) { - dev_err(wdev->dev, "can't load PDS file %s\n", - wdev->pdata.file_pds); - goto err1; - } - tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL); - if (!tmp_buf) { - ret = -ENOMEM; - goto err2; - } - ret = wfx_send_pds(wdev, tmp_buf, pds->size); - kfree(tmp_buf); -err2: - release_firmware(pds); -err1: - return ret; -} - -static void wfx_free_common(void *data) -{ - struct wfx_dev *wdev = data; - - mutex_destroy(&wdev->tx_power_loop_info_lock); - mutex_destroy(&wdev->rx_stats_lock); - mutex_destroy(&wdev->conf_mutex); - ieee80211_free_hw(wdev->hw); -} - -struct wfx_dev *wfx_init_common(struct device *dev, - const struct wfx_platform_data *pdata, - const struct hwbus_ops *hwbus_ops, - void *hwbus_priv) -{ - struct ieee80211_hw *hw; - struct wfx_dev *wdev; - - hw = ieee80211_alloc_hw(sizeof(struct wfx_dev), &wfx_ops); - if (!hw) - return NULL; - - SET_IEEE80211_DEV(hw, dev); - - ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); - ieee80211_hw_set(hw, AMPDU_AGGREGATION); - ieee80211_hw_set(hw, CONNECTION_MONITOR); - ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); - ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); - ieee80211_hw_set(hw, SIGNAL_DBM); - ieee80211_hw_set(hw, SUPPORTS_PS); - ieee80211_hw_set(hw, MFP_CAPABLE); - - hw->vif_data_size = sizeof(struct wfx_vif); - hw->sta_data_size = sizeof(struct wfx_sta_priv); - hw->queues = 4; - hw->max_rates = 8; - hw->max_rate_tries = 8; - hw->extra_tx_headroom = sizeof(struct hif_msg) - + sizeof(struct hif_req_tx) - + 4 /* alignment */ + 8 /* TKIP IV */; - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP); - hw->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; - hw->wiphy->features |= NL80211_FEATURE_AP_SCAN; - hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - hw->wiphy->max_ap_assoc_sta = HIF_LINK_ID_MAX; - hw->wiphy->max_scan_ssids = 2; - hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; - hw->wiphy->n_iface_combinations = ARRAY_SIZE(wfx_iface_combinations); - hw->wiphy->iface_combinations = wfx_iface_combinations; - hw->wiphy->bands[NL80211_BAND_2GHZ] = devm_kmalloc(dev, sizeof(wfx_band_2ghz), GFP_KERNEL); - // FIXME: also copy wfx_rates and wfx_2ghz_chantable - memcpy(hw->wiphy->bands[NL80211_BAND_2GHZ], &wfx_band_2ghz, - sizeof(wfx_band_2ghz)); - - wdev = hw->priv; - wdev->hw = hw; - wdev->dev = dev; - wdev->hwbus_ops = hwbus_ops; - wdev->hwbus_priv = hwbus_priv; - memcpy(&wdev->pdata, pdata, sizeof(*pdata)); - of_property_read_string(dev->of_node, "config-file", - &wdev->pdata.file_pds); - wdev->pdata.gpio_wakeup = devm_gpiod_get_optional(dev, "wakeup", - GPIOD_OUT_LOW); - if (IS_ERR(wdev->pdata.gpio_wakeup)) - return NULL; - if (wdev->pdata.gpio_wakeup) - gpiod_set_consumer_name(wdev->pdata.gpio_wakeup, "wfx wakeup"); - - mutex_init(&wdev->conf_mutex); - mutex_init(&wdev->rx_stats_lock); - mutex_init(&wdev->tx_power_loop_info_lock); - init_completion(&wdev->firmware_ready); - INIT_DELAYED_WORK(&wdev->cooling_timeout_work, - wfx_cooling_timeout_work); - skb_queue_head_init(&wdev->tx_pending); - init_waitqueue_head(&wdev->tx_dequeue); - wfx_init_hif_cmd(&wdev->hif_cmd); - wdev->force_ps_timeout = -1; - - if (devm_add_action_or_reset(dev, wfx_free_common, wdev)) - return NULL; - - return wdev; -} - -int wfx_probe(struct wfx_dev *wdev) -{ - int i; - int err; - const void *macaddr; - struct gpio_desc *gpio_saved; - - // During first part of boot, gpio_wakeup cannot yet been used. So - // prevent bh() to touch it. - gpio_saved = wdev->pdata.gpio_wakeup; - wdev->pdata.gpio_wakeup = NULL; - wdev->poll_irq = true; - - wfx_bh_register(wdev); - - err = wfx_init_device(wdev); - if (err) - goto err0; - - wfx_bh_poll_irq(wdev); - err = wait_for_completion_timeout(&wdev->firmware_ready, 1 * HZ); - if (err <= 0) { - if (err == 0) { - dev_err(wdev->dev, "timeout while waiting for startup indication\n"); - err = -ETIMEDOUT; - } else if (err == -ERESTARTSYS) { - dev_info(wdev->dev, "probe interrupted by user\n"); - } - goto err0; - } - - // FIXME: fill wiphy::hw_version - dev_info(wdev->dev, "started firmware %d.%d.%d \"%s\" (API: %d.%d, keyset: %02X, caps: 0x%.8X)\n", - wdev->hw_caps.firmware_major, wdev->hw_caps.firmware_minor, - wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label, - wdev->hw_caps.api_version_major, wdev->hw_caps.api_version_minor, - wdev->keyset, wdev->hw_caps.link_mode); - snprintf(wdev->hw->wiphy->fw_version, - sizeof(wdev->hw->wiphy->fw_version), - "%d.%d.%d", - wdev->hw_caps.firmware_major, - wdev->hw_caps.firmware_minor, - wdev->hw_caps.firmware_build); - - if (wfx_api_older_than(wdev, 1, 0)) { - dev_err(wdev->dev, - "unsupported firmware API version (expect 1 while firmware returns %d)\n", - wdev->hw_caps.api_version_major); - err = -ENOTSUPP; - goto err0; - } - - if (wdev->hw_caps.link_mode == SEC_LINK_ENFORCED) { - dev_err(wdev->dev, - "chip require secure_link, but can't negotiate it\n"); - goto err0; - } - - if (wdev->hw_caps.region_sel_mode) { - wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[11].flags |= IEEE80211_CHAN_NO_IR; - wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[12].flags |= IEEE80211_CHAN_NO_IR; - wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[13].flags |= IEEE80211_CHAN_DISABLED; - } - - dev_dbg(wdev->dev, "sending configuration file %s\n", - wdev->pdata.file_pds); - err = wfx_send_pdata_pds(wdev); - if (err < 0) - goto err0; - - wdev->poll_irq = false; - err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv); - if (err) - goto err0; - - err = hif_use_multi_tx_conf(wdev, true); - if (err) - dev_err(wdev->dev, "misconfigured IRQ?\n"); - - wdev->pdata.gpio_wakeup = gpio_saved; - if (wdev->pdata.gpio_wakeup) { - dev_dbg(wdev->dev, - "enable 'quiescent' power mode with wakeup GPIO and PDS file %s\n", - wdev->pdata.file_pds); - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); - control_reg_write(wdev, 0); - hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT); - } else { - hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE); - } - - for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) { - eth_zero_addr(wdev->addresses[i].addr); - macaddr = of_get_mac_address(wdev->dev->of_node); - if (!IS_ERR_OR_NULL(macaddr)) { - ether_addr_copy(wdev->addresses[i].addr, macaddr); - wdev->addresses[i].addr[ETH_ALEN - 1] += i; - } else { - ether_addr_copy(wdev->addresses[i].addr, - wdev->hw_caps.mac_addr[i]); - } - if (!is_valid_ether_addr(wdev->addresses[i].addr)) { - dev_warn(wdev->dev, "using random MAC address\n"); - eth_random_addr(wdev->addresses[i].addr); - } - dev_info(wdev->dev, "MAC address %d: %pM\n", i, - wdev->addresses[i].addr); - } - wdev->hw->wiphy->n_addresses = ARRAY_SIZE(wdev->addresses); - wdev->hw->wiphy->addresses = wdev->addresses; - - err = ieee80211_register_hw(wdev->hw); - if (err) - goto err1; - - err = wfx_debug_init(wdev); - if (err) - goto err2; - - return 0; - -err2: - ieee80211_unregister_hw(wdev->hw); -err1: - wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); -err0: - wfx_bh_unregister(wdev); - return err; -} - -void wfx_release(struct wfx_dev *wdev) -{ - ieee80211_unregister_hw(wdev->hw); - hif_shutdown(wdev); - wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); - wfx_bh_unregister(wdev); -} - -static int __init wfx_core_init(void) -{ - int ret = 0; - - if (IS_ENABLED(CONFIG_SPI)) - ret = spi_register_driver(&wfx_spi_driver); - if (IS_ENABLED(CONFIG_MMC) && !ret) - ret = sdio_register_driver(&wfx_sdio_driver); - return ret; -} -module_init(wfx_core_init); - -static void __exit wfx_core_exit(void) -{ - if (IS_ENABLED(CONFIG_MMC)) - sdio_unregister_driver(&wfx_sdio_driver); - if (IS_ENABLED(CONFIG_SPI)) - spi_unregister_driver(&wfx_spi_driver); -} -module_exit(wfx_core_exit); diff --git a/drivers/staging/wfx/main.h b/drivers/staging/wfx/main.h deleted file mode 100644 index a0db322383a3..000000000000 --- a/drivers/staging/wfx/main.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Device probe and register. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (c) 2006, Michael Wu - * Copyright 2004-2006 Jean-Baptiste Note , et al. - */ -#ifndef WFX_MAIN_H -#define WFX_MAIN_H - -#include -#include - -#include "hif_api_general.h" - -struct wfx_dev; -struct hwbus_ops; - -struct wfx_platform_data { - /* Keyset and ".sec" extension will be appended to this string */ - const char *file_fw; - const char *file_pds; - struct gpio_desc *gpio_wakeup; - /* - * if true HIF D_out is sampled on the rising edge of the clock - * (intended to be used in 50Mhz SDIO) - */ - bool use_rising_clk; -}; - -struct wfx_dev *wfx_init_common(struct device *dev, - const struct wfx_platform_data *pdata, - const struct hwbus_ops *hwbus_ops, - void *hwbus_priv); - -int wfx_probe(struct wfx_dev *wdev); -void wfx_release(struct wfx_dev *wdev); - -bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor); -int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len); - -#endif diff --git a/drivers/staging/wfx/queue.c b/drivers/staging/wfx/queue.c deleted file mode 100644 index 31c37f69c295..000000000000 --- a/drivers/staging/wfx/queue.c +++ /dev/null @@ -1,304 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * O(1) TX queue with built-in allocator. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "queue.h" -#include "wfx.h" -#include "sta.h" -#include "data_tx.h" -#include "traces.h" - -void wfx_tx_lock(struct wfx_dev *wdev) -{ - atomic_inc(&wdev->tx_lock); -} - -void wfx_tx_unlock(struct wfx_dev *wdev) -{ - int tx_lock = atomic_dec_return(&wdev->tx_lock); - - WARN(tx_lock < 0, "inconsistent tx_lock value"); - if (!tx_lock) - wfx_bh_request_tx(wdev); -} - -void wfx_tx_flush(struct wfx_dev *wdev) -{ - int ret; - - // Do not wait for any reply if chip is frozen - if (wdev->chip_frozen) - return; - - wfx_tx_lock(wdev); - mutex_lock(&wdev->hif_cmd.lock); - ret = wait_event_timeout(wdev->hif.tx_buffers_empty, - !wdev->hif.tx_buffers_used, - msecs_to_jiffies(3000)); - if (!ret) { - dev_warn(wdev->dev, "cannot flush tx buffers (%d still busy)\n", - wdev->hif.tx_buffers_used); - wfx_pending_dump_old_frames(wdev, 3000); - // FIXME: drop pending frames here - wdev->chip_frozen = true; - } - mutex_unlock(&wdev->hif_cmd.lock); - wfx_tx_unlock(wdev); -} - -void wfx_tx_lock_flush(struct wfx_dev *wdev) -{ - wfx_tx_lock(wdev); - wfx_tx_flush(wdev); -} - -void wfx_tx_queues_init(struct wfx_vif *wvif) -{ - // The device is in charge to respect the details of the QoS parameters. - // The driver just ensure that it roughtly respect the priorities to - // avoid any shortage. - const int priorities[IEEE80211_NUM_ACS] = { 1, 2, 64, 128 }; - int i; - - for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - skb_queue_head_init(&wvif->tx_queue[i].normal); - skb_queue_head_init(&wvif->tx_queue[i].cab); - wvif->tx_queue[i].priority = priorities[i]; - } -} - -void wfx_tx_queues_check_empty(struct wfx_vif *wvif) -{ - int i; - - for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - WARN_ON(atomic_read(&wvif->tx_queue[i].pending_frames)); - WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].normal)); - WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].cab)); - } -} - -bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue) -{ - return skb_queue_empty(&queue->normal) && skb_queue_empty(&queue->cab); -} - -static void __wfx_tx_queue_drop(struct wfx_vif *wvif, - struct sk_buff_head *skb_queue, - struct sk_buff_head *dropped) -{ - struct sk_buff *skb, *tmp; - - spin_lock_bh(&skb_queue->lock); - skb_queue_walk_safe(skb_queue, skb, tmp) { - __skb_unlink(skb, skb_queue); - skb_queue_head(dropped, skb); - } - spin_unlock_bh(&skb_queue->lock); -} - -void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue, - struct sk_buff_head *dropped) -{ - __wfx_tx_queue_drop(wvif, &queue->cab, dropped); - __wfx_tx_queue_drop(wvif, &queue->normal, dropped); - wake_up(&wvif->wdev->tx_dequeue); -} - -void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb) -{ - struct wfx_queue *queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - skb_queue_tail(&queue->cab, skb); - else - skb_queue_tail(&queue->normal, skb); -} - -void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped) -{ - struct wfx_queue *queue; - struct wfx_vif *wvif; - struct hif_msg *hif; - struct sk_buff *skb; - - WARN(!wdev->chip_frozen, "%s should only be used to recover a frozen device", - __func__); - while ((skb = skb_dequeue(&wdev->tx_pending)) != NULL) { - hif = (struct hif_msg *)skb->data; - wvif = wdev_to_wvif(wdev, hif->interface); - if (wvif) { - queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; - WARN_ON(skb_get_queue_mapping(skb) > 3); - WARN_ON(!atomic_read(&queue->pending_frames)); - atomic_dec(&queue->pending_frames); - } - skb_queue_head(dropped, skb); - } -} - -struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id) -{ - struct wfx_queue *queue; - struct hif_req_tx *req; - struct wfx_vif *wvif; - struct hif_msg *hif; - struct sk_buff *skb; - - spin_lock_bh(&wdev->tx_pending.lock); - skb_queue_walk(&wdev->tx_pending, skb) { - hif = (struct hif_msg *)skb->data; - req = (struct hif_req_tx *)hif->body; - if (req->packet_id != packet_id) - continue; - spin_unlock_bh(&wdev->tx_pending.lock); - wvif = wdev_to_wvif(wdev, hif->interface); - if (wvif) { - queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; - WARN_ON(skb_get_queue_mapping(skb) > 3); - WARN_ON(!atomic_read(&queue->pending_frames)); - atomic_dec(&queue->pending_frames); - } - skb_unlink(skb, &wdev->tx_pending); - return skb; - } - spin_unlock_bh(&wdev->tx_pending.lock); - WARN(1, "cannot find packet in pending queue"); - return NULL; -} - -void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms) -{ - ktime_t now = ktime_get(); - struct wfx_tx_priv *tx_priv; - struct hif_req_tx *req; - struct sk_buff *skb; - bool first = true; - - spin_lock_bh(&wdev->tx_pending.lock); - skb_queue_walk(&wdev->tx_pending, skb) { - tx_priv = wfx_skb_tx_priv(skb); - req = wfx_skb_txreq(skb); - if (ktime_after(now, ktime_add_ms(tx_priv->xmit_timestamp, - limit_ms))) { - if (first) { - dev_info(wdev->dev, "frames stuck in firmware since %dms or more:\n", - limit_ms); - first = false; - } - dev_info(wdev->dev, " id %08x sent %lldms ago\n", - req->packet_id, - ktime_ms_delta(now, tx_priv->xmit_timestamp)); - } - } - spin_unlock_bh(&wdev->tx_pending.lock); -} - -unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, - struct sk_buff *skb) -{ - ktime_t now = ktime_get(); - struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); - - return ktime_us_delta(now, tx_priv->xmit_timestamp); -} - -bool wfx_tx_queues_has_cab(struct wfx_vif *wvif) -{ - int i; - - if (wvif->vif->type != NL80211_IFTYPE_AP) - return false; - for (i = 0; i < IEEE80211_NUM_ACS; ++i) - // Note: since only AP can have mcast frames in queue and only - // one vif can be AP, all queued frames has same interface id - if (!skb_queue_empty_lockless(&wvif->tx_queue[i].cab)) - return true; - return false; -} - -static int wfx_tx_queue_get_weight(struct wfx_queue *queue) -{ - return atomic_read(&queue->pending_frames) * queue->priority; -} - -static struct sk_buff *wfx_tx_queues_get_skb(struct wfx_dev *wdev) -{ - struct wfx_queue *queues[IEEE80211_NUM_ACS * ARRAY_SIZE(wdev->vif)]; - int i, j, num_queues = 0; - struct wfx_vif *wvif; - struct hif_msg *hif; - struct sk_buff *skb; - - // sort the queues - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - WARN_ON(num_queues >= ARRAY_SIZE(queues)); - queues[num_queues] = &wvif->tx_queue[i]; - for (j = num_queues; j > 0; j--) - if (wfx_tx_queue_get_weight(queues[j]) < - wfx_tx_queue_get_weight(queues[j - 1])) - swap(queues[j - 1], queues[j]); - num_queues++; - } - } - - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - if (!wvif->after_dtim_tx_allowed) - continue; - for (i = 0; i < num_queues; i++) { - skb = skb_dequeue(&queues[i]->cab); - if (!skb) - continue; - // Note: since only AP can have mcast frames in queue - // and only one vif can be AP, all queued frames has - // same interface id - hif = (struct hif_msg *)skb->data; - WARN_ON(hif->interface != wvif->id); - WARN_ON(queues[i] != - &wvif->tx_queue[skb_get_queue_mapping(skb)]); - atomic_inc(&queues[i]->pending_frames); - trace_queues_stats(wdev, queues[i]); - return skb; - } - // No more multicast to sent - wvif->after_dtim_tx_allowed = false; - schedule_work(&wvif->update_tim_work); - } - - for (i = 0; i < num_queues; i++) { - skb = skb_dequeue(&queues[i]->normal); - if (skb) { - atomic_inc(&queues[i]->pending_frames); - trace_queues_stats(wdev, queues[i]); - return skb; - } - } - return NULL; -} - -struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev) -{ - struct wfx_tx_priv *tx_priv; - struct sk_buff *skb; - - if (atomic_read(&wdev->tx_lock)) - return NULL; - skb = wfx_tx_queues_get_skb(wdev); - if (!skb) - return NULL; - skb_queue_tail(&wdev->tx_pending, skb); - wake_up(&wdev->tx_dequeue); - tx_priv = wfx_skb_tx_priv(skb); - tx_priv->xmit_timestamp = ktime_get(); - return (struct hif_msg *)skb->data; -} diff --git a/drivers/staging/wfx/queue.h b/drivers/staging/wfx/queue.h deleted file mode 100644 index 80ba19455ef3..000000000000 --- a/drivers/staging/wfx/queue.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * O(1) TX queue with built-in allocator. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_QUEUE_H -#define WFX_QUEUE_H - -#include -#include - -struct wfx_dev; -struct wfx_vif; - -struct wfx_queue { - struct sk_buff_head normal; - struct sk_buff_head cab; // Content After (DTIM) Beacon - atomic_t pending_frames; - int priority; -}; - -void wfx_tx_lock(struct wfx_dev *wdev); -void wfx_tx_unlock(struct wfx_dev *wdev); -void wfx_tx_flush(struct wfx_dev *wdev); -void wfx_tx_lock_flush(struct wfx_dev *wdev); - -void wfx_tx_queues_init(struct wfx_vif *wvif); -void wfx_tx_queues_check_empty(struct wfx_vif *wvif); -bool wfx_tx_queues_has_cab(struct wfx_vif *wvif); -void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb); -struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev); - -bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue); -void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue, - struct sk_buff_head *dropped); - -struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id); -void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped); -unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, - struct sk_buff *skb); -void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms); - -#endif /* WFX_QUEUE_H */ diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c deleted file mode 100644 index fb47c7cddf2f..000000000000 --- a/drivers/staging/wfx/scan.c +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Scan related functions. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include - -#include "scan.h" -#include "wfx.h" -#include "sta.h" -#include "hif_tx_mib.h" - -static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw, - bool aborted) -{ - struct cfg80211_scan_info info = { - .aborted = aborted, - }; - - ieee80211_scan_completed(hw, &info); -} - -static int update_probe_tmpl(struct wfx_vif *wvif, - struct cfg80211_scan_request *req) -{ - struct sk_buff *skb; - - skb = ieee80211_probereq_get(wvif->wdev->hw, wvif->vif->addr, - NULL, 0, req->ie_len); - if (!skb) - return -ENOMEM; - - skb_put_data(skb, req->ie, req->ie_len); - hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBREQ, 0); - dev_kfree_skb(skb); - return 0; -} - -static int send_scan_req(struct wfx_vif *wvif, - struct cfg80211_scan_request *req, int start_idx) -{ - int i, ret, timeout; - struct ieee80211_channel *ch_start, *ch_cur; - - for (i = start_idx; i < req->n_channels; i++) { - ch_start = req->channels[start_idx]; - ch_cur = req->channels[i]; - WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported"); - if (ch_cur->max_power != ch_start->max_power) - break; - if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR) - break; - } - wfx_tx_lock_flush(wvif->wdev); - wvif->scan_abort = false; - reinit_completion(&wvif->scan_complete); - ret = hif_scan(wvif, req, start_idx, i - start_idx, &timeout); - if (ret) { - wfx_tx_unlock(wvif->wdev); - return -EIO; - } - ret = wait_for_completion_timeout(&wvif->scan_complete, timeout); - if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower) - hif_set_output_power(wvif, wvif->vif->bss_conf.txpower); - wfx_tx_unlock(wvif->wdev); - if (!ret) { - dev_notice(wvif->wdev->dev, "scan timeout\n"); - hif_stop_scan(wvif); - return -ETIMEDOUT; - } - if (wvif->scan_abort) { - dev_notice(wvif->wdev->dev, "scan abort\n"); - return -ECONNABORTED; - } - return i - start_idx; -} - -/* - * It is not really necessary to run scan request asynchronously. However, - * there is a bug in "iw scan" when ieee80211_scan_completed() is called before - * wfx_hw_scan() return - */ -void wfx_hw_scan_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work); - struct ieee80211_scan_request *hw_req = wvif->scan_req; - int chan_cur, ret; - - mutex_lock(&wvif->wdev->conf_mutex); - mutex_lock(&wvif->scan_lock); - if (wvif->join_in_progress) { - dev_info(wvif->wdev->dev, "%s: abort in-progress REQ_JOIN", - __func__); - wfx_reset(wvif); - } - update_probe_tmpl(wvif, &hw_req->req); - chan_cur = 0; - do { - ret = send_scan_req(wvif, &hw_req->req, chan_cur); - if (ret > 0) - chan_cur += ret; - } while (ret > 0 && chan_cur < hw_req->req.n_channels); - mutex_unlock(&wvif->scan_lock); - mutex_unlock(&wvif->wdev->conf_mutex); - __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0); -} - -int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_scan_request *hw_req) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS); - wvif->scan_req = hw_req; - schedule_work(&wvif->scan_work); - return 0; -} - -void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wvif->scan_abort = true; - hif_stop_scan(wvif); -} - -void wfx_scan_complete(struct wfx_vif *wvif) -{ - complete(&wvif->scan_complete); -} diff --git a/drivers/staging/wfx/scan.h b/drivers/staging/wfx/scan.h deleted file mode 100644 index c7496a766478..000000000000 --- a/drivers/staging/wfx/scan.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Scan related functions. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_SCAN_H -#define WFX_SCAN_H - -#include - -struct wfx_dev; -struct wfx_vif; - -void wfx_hw_scan_work(struct work_struct *work); -int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_scan_request *req); -void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_scan_complete(struct wfx_vif *wvif); - -#endif /* WFX_SCAN_H */ diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c deleted file mode 100644 index 196779a1b89a..000000000000 --- a/drivers/staging/wfx/sta.c +++ /dev/null @@ -1,807 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Implementation of mac80211 API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "sta.h" -#include "wfx.h" -#include "fwio.h" -#include "bh.h" -#include "key.h" -#include "scan.h" -#include "debug.h" -#include "hif_tx.h" -#include "hif_tx_mib.h" - -#define HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES 2 - -u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates) -{ - int i; - u32 ret = 0; - // WFx only support 2GHz - struct ieee80211_supported_band *sband = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; - - for (i = 0; i < sband->n_bitrates; i++) { - if (rates & BIT(i)) { - if (i >= sband->n_bitrates) - dev_warn(wdev->dev, "unsupported basic rate\n"); - else - ret |= BIT(sband->bitrates[i].hw_value); - } - } - return ret; -} - -void wfx_cooling_timeout_work(struct work_struct *work) -{ - struct wfx_dev *wdev = container_of(to_delayed_work(work), - struct wfx_dev, - cooling_timeout_work); - - wdev->chip_frozen = true; - wfx_tx_unlock(wdev); -} - -void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd) -{ - if (cmd == STA_NOTIFY_AWAKE) { - // Device recover normal temperature - if (cancel_delayed_work(&wdev->cooling_timeout_work)) - wfx_tx_unlock(wdev); - } else { - // Device is too hot - schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ); - wfx_tx_lock(wdev); - } -} - -static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon) -{ - static const struct hif_ie_table_entry filter_ies[] = { - { - .ie_id = WLAN_EID_VENDOR_SPECIFIC, - .has_changed = 1, - .no_longer = 1, - .has_appeared = 1, - .oui = { 0x50, 0x6F, 0x9A }, - }, { - .ie_id = WLAN_EID_HT_OPERATION, - .has_changed = 1, - .no_longer = 1, - .has_appeared = 1, - }, { - .ie_id = WLAN_EID_ERP_INFO, - .has_changed = 1, - .no_longer = 1, - .has_appeared = 1, - } - }; - - if (!filter_beacon) { - hif_beacon_filter_control(wvif, 0, 1); - } else { - hif_set_beacon_filter_table(wvif, 3, filter_ies); - hif_beacon_filter_control(wvif, HIF_BEACON_FILTER_ENABLE, 0); - } -} - -void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, u64 unused) -{ - struct wfx_vif *wvif = NULL; - struct wfx_dev *wdev = hw->priv; - bool filter_bssid, filter_prbreq, filter_beacon; - - // Notes: - // - Probe responses (FIF_BCN_PRBRESP_PROMISC) are never filtered - // - PS-Poll (FIF_PSPOLL) are never filtered - // - RTS, CTS and Ack (FIF_CONTROL) are always filtered - // - Broken frames (FIF_FCSFAIL and FIF_PLCPFAIL) are always filtered - // - Firmware does (yet) allow to forward unicast traffic sent to - // other stations (aka. promiscuous mode) - *total_flags &= FIF_BCN_PRBRESP_PROMISC | FIF_ALLMULTI | FIF_OTHER_BSS | - FIF_PROBE_REQ | FIF_PSPOLL; - - mutex_lock(&wdev->conf_mutex); - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - mutex_lock(&wvif->scan_lock); - - // Note: FIF_BCN_PRBRESP_PROMISC covers probe response and - // beacons from other BSS - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - filter_beacon = false; - else - filter_beacon = true; - wfx_filter_beacon(wvif, filter_beacon); - - if (*total_flags & FIF_OTHER_BSS) - filter_bssid = false; - else - filter_bssid = true; - - // In AP mode, chip can reply to probe request itself - if (*total_flags & FIF_PROBE_REQ && - wvif->vif->type == NL80211_IFTYPE_AP) { - dev_dbg(wdev->dev, "do not forward probe request in AP mode\n"); - *total_flags &= ~FIF_PROBE_REQ; - } - - if (*total_flags & FIF_PROBE_REQ) - filter_prbreq = false; - else - filter_prbreq = true; - hif_set_rx_filter(wvif, filter_bssid, filter_prbreq); - - mutex_unlock(&wvif->scan_lock); - } - mutex_unlock(&wdev->conf_mutex); -} - -static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) -{ - struct ieee80211_channel *chan0 = NULL, *chan1 = NULL; - struct ieee80211_conf *conf = &wvif->wdev->hw->conf; - - WARN(!wvif->vif->bss_conf.assoc && enable_ps, - "enable_ps is reliable only if associated"); - if (wdev_to_wvif(wvif->wdev, 0)) - chan0 = wdev_to_wvif(wvif->wdev, 0)->vif->bss_conf.chandef.chan; - if (wdev_to_wvif(wvif->wdev, 1)) - chan1 = wdev_to_wvif(wvif->wdev, 1)->vif->bss_conf.chandef.chan; - if (chan0 && chan1 && chan0->hw_value != chan1->hw_value && - wvif->vif->type != NL80211_IFTYPE_AP) { - // It is necessary to enable powersave if channels - // are different. - if (enable_ps) - *enable_ps = true; - if (wvif->wdev->force_ps_timeout > -1) - return wvif->wdev->force_ps_timeout; - else if (wfx_api_older_than(wvif->wdev, 3, 2)) - return 0; - else - return 30; - } - if (enable_ps) - *enable_ps = wvif->vif->bss_conf.ps; - if (wvif->wdev->force_ps_timeout > -1) - return wvif->wdev->force_ps_timeout; - else if (wvif->vif->bss_conf.assoc && wvif->vif->bss_conf.ps) - return conf->dynamic_ps_timeout; - else - return -1; -} - -int wfx_update_pm(struct wfx_vif *wvif) -{ - int ps_timeout; - bool ps; - - if (!wvif->vif->bss_conf.assoc) - return 0; - ps_timeout = wfx_get_ps_timeout(wvif, &ps); - if (!ps) - ps_timeout = 0; - WARN_ON(ps_timeout < 0); - if (wvif->uapsd_mask) - ps_timeout = 0; - - if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete, - TU_TO_JIFFIES(512))) - dev_warn(wvif->wdev->dev, - "timeout while waiting of set_pm_mode_complete\n"); - return hif_set_pm(wvif, ps, ps_timeout); -} - -int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - int old_uapsd = wvif->uapsd_mask; - - WARN_ON(queue >= hw->queues); - - mutex_lock(&wdev->conf_mutex); - assign_bit(queue, &wvif->uapsd_mask, params->uapsd); - hif_set_edca_queue_params(wvif, queue, params); - if (wvif->vif->type == NL80211_IFTYPE_STATION && - old_uapsd != wvif->uapsd_mask) { - hif_set_uapsd_info(wvif, wvif->uapsd_mask); - wfx_update_pm(wvif); - } - mutex_unlock(&wdev->conf_mutex); - return 0; -} - -int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = NULL; - - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - hif_rts_threshold(wvif, value); - return 0; -} - -/* WSM callbacks */ - -void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) -{ - /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 - * RSSI = RCPI / 2 - 110 - */ - int rcpi_rssi; - int cqm_evt; - - rcpi_rssi = raw_rcpi_rssi / 2 - 110; - if (rcpi_rssi <= wvif->vif->bss_conf.cqm_rssi_thold) - cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; - else - cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; - ieee80211_cqm_rssi_notify(wvif->vif, cqm_evt, rcpi_rssi, GFP_KERNEL); -} - -static void wfx_beacon_loss_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(to_delayed_work(work), - struct wfx_vif, beacon_loss_work); - struct ieee80211_bss_conf *bss_conf = &wvif->vif->bss_conf; - - ieee80211_beacon_loss(wvif->vif); - schedule_delayed_work(to_delayed_work(work), - msecs_to_jiffies(bss_conf->beacon_int)); -} - -void wfx_set_default_unicast_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int idx) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - hif_wep_default_key_id(wvif, idx); -} - -void wfx_reset(struct wfx_vif *wvif) -{ - struct wfx_dev *wdev = wvif->wdev; - - wfx_tx_lock_flush(wdev); - hif_reset(wvif, false); - wfx_tx_policy_init(wvif); - if (wvif_count(wdev) <= 1) - hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - wfx_tx_unlock(wdev); - wvif->join_in_progress = false; - cancel_delayed_work_sync(&wvif->beacon_loss_work); - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - wfx_update_pm(wvif); -} - -int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; - - sta_priv->vif_id = wvif->id; - - if (vif->type == NL80211_IFTYPE_STATION) - hif_set_mfp(wvif, sta->mfp, sta->mfp); - - // In station mode, the firmware interprets new link-id as a TDLS peer. - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - return 0; - sta_priv->link_id = ffz(wvif->link_id_map); - wvif->link_id_map |= BIT(sta_priv->link_id); - WARN_ON(!sta_priv->link_id); - WARN_ON(sta_priv->link_id >= HIF_LINK_ID_MAX); - hif_map_link(wvif, false, sta->addr, sta_priv->link_id, sta->mfp); - - return 0; -} - -int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; - - // See note in wfx_sta_add() - if (!sta_priv->link_id) - return 0; - // FIXME add a mutex? - hif_map_link(wvif, true, sta->addr, sta_priv->link_id, false); - wvif->link_id_map &= ~BIT(sta_priv->link_id); - return 0; -} - -static int wfx_upload_ap_templates(struct wfx_vif *wvif) -{ - struct sk_buff *skb; - - skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); - if (!skb) - return -ENOMEM; - hif_set_template_frame(wvif, skb, HIF_TMPLT_BCN, - API_RATE_INDEX_B_1MBPS); - dev_kfree_skb(skb); - - skb = ieee80211_proberesp_get(wvif->wdev->hw, wvif->vif); - if (!skb) - return -ENOMEM; - hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBRES, - API_RATE_INDEX_B_1MBPS); - dev_kfree_skb(skb); - return 0; -} - -static void wfx_set_mfp_ap(struct wfx_vif *wvif) -{ - struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); - const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); - const u16 *ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, - skb->data + ieoffset, - skb->len - ieoffset); - const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16); - const int pairwise_cipher_suite_size = 4 / sizeof(u16); - const int akm_suite_size = 4 / sizeof(u16); - - if (ptr) { - ptr += pairwise_cipher_suite_count_offset; - if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) - return; - ptr += 1 + pairwise_cipher_suite_size * *ptr; - if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) - return; - ptr += 1 + akm_suite_size * *ptr; - if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) - return; - hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6)); - } -} - -int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct wfx_dev *wdev = wvif->wdev; - int ret; - - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - wfx_update_pm(wvif); - wvif = (struct wfx_vif *)vif->drv_priv; - wfx_upload_ap_templates(wvif); - ret = hif_start(wvif, &vif->bss_conf, wvif->channel); - if (ret > 0) - return -EIO; - wfx_set_mfp_ap(wvif); - return ret; -} - -void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wfx_reset(wvif); -} - -static void wfx_join(struct wfx_vif *wvif) -{ - int ret; - struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf; - struct cfg80211_bss *bss = NULL; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - const u8 *ssidie = NULL; - int ssidlen = 0; - - wfx_tx_lock_flush(wvif->wdev); - - bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel, - conf->bssid, NULL, 0, - IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - if (!bss && !conf->ibss_joined) { - wfx_tx_unlock(wvif->wdev); - return; - } - - rcu_read_lock(); // protect ssidie - if (bss) - ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); - if (ssidie) { - ssidlen = ssidie[1]; - if (ssidlen > IEEE80211_MAX_SSID_LEN) - ssidlen = IEEE80211_MAX_SSID_LEN; - memcpy(ssid, &ssidie[2], ssidlen); - } - rcu_read_unlock(); - - cfg80211_put_bss(wvif->wdev->hw->wiphy, bss); - - wvif->join_in_progress = true; - ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen); - if (ret) { - ieee80211_connection_loss(wvif->vif); - wfx_reset(wvif); - } else { - /* Due to beacon filtering it is possible that the - * AP's beacon is not known for the mac80211 stack. - * Disable filtering temporary to make sure the stack - * receives at least one - */ - wfx_filter_beacon(wvif, false); - } - wfx_tx_unlock(wvif->wdev); -} - -static void wfx_join_finalize(struct wfx_vif *wvif, - struct ieee80211_bss_conf *info) -{ - struct ieee80211_sta *sta = NULL; - int ampdu_density = 0; - bool greenfield = false; - - rcu_read_lock(); // protect sta - if (info->bssid && !info->ibss_joined) - sta = ieee80211_find_sta(wvif->vif, info->bssid); - if (sta && sta->ht_cap.ht_supported) - ampdu_density = sta->ht_cap.ampdu_density; - if (sta && sta->ht_cap.ht_supported && - !(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)) - greenfield = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); - rcu_read_unlock(); - - wvif->join_in_progress = false; - hif_set_association_mode(wvif, ampdu_density, greenfield, - info->use_short_preamble); - hif_keep_alive_period(wvif, 0); - // beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use - // the same value. - hif_set_bss_params(wvif, info->aid, 7); - hif_set_beacon_wakeup_period(wvif, 1, 1); - wfx_update_pm(wvif); -} - -int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wfx_upload_ap_templates(wvif); - wfx_join(wvif); - return 0; -} - -void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wfx_reset(wvif); -} - -static void wfx_enable_beacon(struct wfx_vif *wvif, bool enable) -{ - // Driver has Content After DTIM Beacon in queue. Driver is waiting for - // a signal from the firmware. Since we are going to stop to send - // beacons, this signal will never happens. See also - // wfx_suspend_resume_mc() - if (!enable && wfx_tx_queues_has_cab(wvif)) { - wvif->after_dtim_tx_allowed = true; - wfx_bh_request_tx(wvif->wdev); - } - hif_beacon_transmit(wvif, enable); -} - -void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - int i; - - mutex_lock(&wdev->conf_mutex); - - if (changed & BSS_CHANGED_BASIC_RATES || - changed & BSS_CHANGED_BEACON_INT || - changed & BSS_CHANGED_BSSID) { - if (vif->type == NL80211_IFTYPE_STATION) - wfx_join(wvif); - } - - if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc || info->ibss_joined) - wfx_join_finalize(wvif, info); - else if (!info->assoc && vif->type == NL80211_IFTYPE_STATION) - wfx_reset(wvif); - else - dev_warn(wdev->dev, "%s: misunderstood change: ASSOC\n", - __func__); - } - - if (changed & BSS_CHANGED_BEACON_INFO) { - if (vif->type != NL80211_IFTYPE_STATION) - dev_warn(wdev->dev, "%s: misunderstood change: BEACON_INFO\n", - __func__); - hif_set_beacon_wakeup_period(wvif, info->dtim_period, - info->dtim_period); - // We temporary forwarded beacon for join process. It is now no - // more necessary. - wfx_filter_beacon(wvif, true); - } - - if (changed & BSS_CHANGED_ARP_FILTER) { - for (i = 0; i < HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES; i++) { - __be32 *arp_addr = &info->arp_addr_list[i]; - - if (info->arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES) - arp_addr = NULL; - if (i >= info->arp_addr_cnt) - arp_addr = NULL; - hif_set_arp_ipv4_filter(wvif, i, arp_addr); - } - } - - if (changed & BSS_CHANGED_AP_PROBE_RESP || - changed & BSS_CHANGED_BEACON) - wfx_upload_ap_templates(wvif); - - if (changed & BSS_CHANGED_BEACON_ENABLED) - wfx_enable_beacon(wvif, info->enable_beacon); - - if (changed & BSS_CHANGED_KEEP_ALIVE) - hif_keep_alive_period(wvif, info->max_idle_period * - USEC_PER_TU / USEC_PER_MSEC); - - if (changed & BSS_CHANGED_ERP_CTS_PROT) - hif_erp_use_protection(wvif, info->use_cts_prot); - - if (changed & BSS_CHANGED_ERP_SLOT) - hif_slot_time(wvif, info->use_short_slot ? 9 : 20); - - if (changed & BSS_CHANGED_CQM) - hif_set_rcpi_rssi_threshold(wvif, info->cqm_rssi_thold, - info->cqm_rssi_hyst); - - if (changed & BSS_CHANGED_TXPOWER) - hif_set_output_power(wvif, info->txpower); - - if (changed & BSS_CHANGED_PS) - wfx_update_pm(wvif); - - mutex_unlock(&wdev->conf_mutex); -} - -static int wfx_update_tim(struct wfx_vif *wvif) -{ - struct sk_buff *skb; - u16 tim_offset, tim_length; - u8 *tim_ptr; - - skb = ieee80211_beacon_get_tim(wvif->wdev->hw, wvif->vif, - &tim_offset, &tim_length); - if (!skb) - return -ENOENT; - tim_ptr = skb->data + tim_offset; - - if (tim_offset && tim_length >= 6) { - /* Ignore DTIM count from mac80211: - * firmware handles DTIM internally. - */ - tim_ptr[2] = 0; - - /* Set/reset aid0 bit */ - if (wfx_tx_queues_has_cab(wvif)) - tim_ptr[4] |= 1; - else - tim_ptr[4] &= ~1; - } - - hif_update_ie_beacon(wvif, tim_ptr, tim_length); - dev_kfree_skb(skb); - - return 0; -} - -static void wfx_update_tim_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(work, struct wfx_vif, update_tim_work); - - wfx_update_tim(wvif); -} - -int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_sta_priv *sta_dev = (struct wfx_sta_priv *)&sta->drv_priv; - struct wfx_vif *wvif = wdev_to_wvif(wdev, sta_dev->vif_id); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - schedule_work(&wvif->update_tim_work); - return 0; -} - -void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd notify_cmd) -{ - if (notify_cmd != STA_NOTIFY_AWAKE) - return; - WARN(!wfx_tx_queues_has_cab(wvif), "incorrect sequence"); - WARN(wvif->after_dtim_tx_allowed, "incorrect sequence"); - wvif->after_dtim_tx_allowed = true; - wfx_bh_request_tx(wvif->wdev); -} - -int wfx_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params) -{ - // Aggregation is implemented fully in firmware - switch (params->action) { - case IEEE80211_AMPDU_RX_START: - case IEEE80211_AMPDU_RX_STOP: - // Just acknowledge it to enable frame re-ordering - return 0; - default: - // Leave the firmware doing its business for tx aggregation - return -ENOTSUPP; - } -} - -int wfx_add_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf) -{ - return 0; -} - -void wfx_remove_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf) -{ -} - -void wfx_change_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf, - u32 changed) -{ -} - -int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *conf) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct ieee80211_channel *ch = conf->def.chan; - - WARN(wvif->channel, "channel overwrite"); - wvif->channel = ch; - - return 0; -} - -void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *conf) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct ieee80211_channel *ch = conf->def.chan; - - WARN(wvif->channel != ch, "channel mismatch"); - wvif->channel = NULL; -} - -int wfx_config(struct ieee80211_hw *hw, u32 changed) -{ - return 0; -} - -int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - int i, ret = 0; - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | - IEEE80211_VIF_SUPPORTS_UAPSD | - IEEE80211_VIF_SUPPORTS_CQM_RSSI; - - mutex_lock(&wdev->conf_mutex); - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: - break; - default: - mutex_unlock(&wdev->conf_mutex); - return -EOPNOTSUPP; - } - - // FIXME: prefer use of container_of() to get vif - wvif->vif = vif; - wvif->wdev = wdev; - - wvif->link_id_map = 1; // link-id 0 is reserved for multicast - INIT_WORK(&wvif->update_tim_work, wfx_update_tim_work); - INIT_DELAYED_WORK(&wvif->beacon_loss_work, wfx_beacon_loss_work); - - init_completion(&wvif->set_pm_mode_complete); - complete(&wvif->set_pm_mode_complete); - INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work); - - mutex_init(&wvif->scan_lock); - init_completion(&wvif->scan_complete); - INIT_WORK(&wvif->scan_work, wfx_hw_scan_work); - - wfx_tx_queues_init(wvif); - wfx_tx_policy_init(wvif); - - for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { - if (!wdev->vif[i]) { - wdev->vif[i] = vif; - wvif->id = i; - break; - } - } - WARN(i == ARRAY_SIZE(wdev->vif), "try to instantiate more vif than supported"); - - hif_set_macaddr(wvif, vif->addr); - - mutex_unlock(&wdev->conf_mutex); - - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - // Combo mode does not support Block Acks. We can re-enable them - if (wvif_count(wdev) == 1) - hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - else - hif_set_block_ack_policy(wvif, 0x00, 0x00); - } - return ret; -} - -void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300)); - wfx_tx_queues_check_empty(wvif); - - mutex_lock(&wdev->conf_mutex); - WARN(wvif->link_id_map != 1, "corrupted state"); - - hif_reset(wvif, false); - hif_set_macaddr(wvif, NULL); - wfx_tx_policy_init(wvif); - - cancel_delayed_work_sync(&wvif->beacon_loss_work); - wdev->vif[wvif->id] = NULL; - wvif->vif = NULL; - - mutex_unlock(&wdev->conf_mutex); - - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - // Combo mode does not support Block Acks. We can re-enable them - if (wvif_count(wdev) == 1) - hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - else - hif_set_block_ack_policy(wvif, 0x00, 0x00); - } -} - -int wfx_start(struct ieee80211_hw *hw) -{ - return 0; -} - -void wfx_stop(struct ieee80211_hw *hw) -{ - struct wfx_dev *wdev = hw->priv; - - WARN_ON(!skb_queue_empty_lockless(&wdev->tx_pending)); -} diff --git a/drivers/staging/wfx/sta.h b/drivers/staging/wfx/sta.h deleted file mode 100644 index d7b5df5ea4e6..000000000000 --- a/drivers/staging/wfx/sta.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of mac80211 API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_STA_H -#define WFX_STA_H - -#include - -struct wfx_dev; -struct wfx_vif; - -struct wfx_sta_priv { - int link_id; - int vif_id; -}; - -// mac80211 interface -int wfx_start(struct ieee80211_hw *hw); -void wfx_stop(struct ieee80211_hw *hw); -int wfx_config(struct ieee80211_hw *hw, u32 changed); -int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value); -void wfx_set_default_unicast_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int idx); -void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, u64 unused); - -int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); -void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed); -int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, struct ieee80211_sta *sta); -int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); -int wfx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params); -int wfx_add_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf); -void wfx_remove_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf); -void wfx_change_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf, u32 changed); -int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *conf); -void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *conf); - -// WSM Callbacks -void wfx_cooling_timeout_work(struct work_struct *work); -void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd); -void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd cmd); -void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi); -int wfx_update_pm(struct wfx_vif *wvif); - -// Other Helpers -void wfx_reset(struct wfx_vif *wvif); -u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates); - -#endif /* WFX_STA_H */ diff --git a/drivers/staging/wfx/traces.h b/drivers/staging/wfx/traces.h deleted file mode 100644 index e34c7a538c65..000000000000 --- a/drivers/staging/wfx/traces.h +++ /dev/null @@ -1,501 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Tracepoints definitions. - * - * Copyright (c) 2018-2020, Silicon Laboratories, Inc. - */ - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM wfx - -#if !defined(_WFX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -#define _WFX_TRACE_H - -#include -#include - -#include "bus.h" -#include "hif_api_cmd.h" -#include "hif_api_mib.h" - -/* The hell below need some explanations. For each symbolic number, we need to - * define it with TRACE_DEFINE_ENUM() and in a list for __print_symbolic. - * - * 1. Define a new macro that call TRACE_DEFINE_ENUM(): - * - * #define xxx_name(sym) TRACE_DEFINE_ENUM(sym); - * - * 2. Define list of all symbols: - * - * #define list_names \ - * ... \ - * xxx_name(XXX) \ - * ... - * - * 3. Instantiate that list_names: - * - * list_names - * - * 4. Redefine xxx_name() as an entry of array for __print_symbolic() - * - * #undef xxx_name - * #define xxx_name(msg) { msg, #msg }, - * - * 5. list_name can now nearly be used with __print_symbolic() but, - * __print_symbolic() dislike last comma of list. So we define a new list - * with a dummy element: - * - * #define list_for_print_symbolic list_names { -1, NULL } - */ - -#define _hif_msg_list \ - hif_cnf_name(ADD_KEY) \ - hif_cnf_name(BEACON_TRANSMIT) \ - hif_cnf_name(EDCA_QUEUE_PARAMS) \ - hif_cnf_name(JOIN) \ - hif_cnf_name(MAP_LINK) \ - hif_cnf_name(READ_MIB) \ - hif_cnf_name(REMOVE_KEY) \ - hif_cnf_name(RESET) \ - hif_cnf_name(SET_BSS_PARAMS) \ - hif_cnf_name(SET_PM_MODE) \ - hif_cnf_name(START) \ - hif_cnf_name(START_SCAN) \ - hif_cnf_name(STOP_SCAN) \ - hif_cnf_name(TX) \ - hif_cnf_name(MULTI_TRANSMIT) \ - hif_cnf_name(UPDATE_IE) \ - hif_cnf_name(WRITE_MIB) \ - hif_cnf_name(CONFIGURATION) \ - hif_cnf_name(CONTROL_GPIO) \ - hif_cnf_name(PREVENT_ROLLBACK) \ - hif_cnf_name(SET_SL_MAC_KEY) \ - hif_cnf_name(SL_CONFIGURE) \ - hif_cnf_name(SL_EXCHANGE_PUB_KEYS) \ - hif_cnf_name(SHUT_DOWN) \ - hif_ind_name(EVENT) \ - hif_ind_name(JOIN_COMPLETE) \ - hif_ind_name(RX) \ - hif_ind_name(SCAN_CMPL) \ - hif_ind_name(SET_PM_MODE_CMPL) \ - hif_ind_name(SUSPEND_RESUME_TX) \ - hif_ind_name(SL_EXCHANGE_PUB_KEYS) \ - hif_ind_name(ERROR) \ - hif_ind_name(EXCEPTION) \ - hif_ind_name(GENERIC) \ - hif_ind_name(WAKEUP) \ - hif_ind_name(STARTUP) - -#define hif_msg_list_enum _hif_msg_list - -#undef hif_cnf_name -#undef hif_ind_name -#define hif_cnf_name(msg) TRACE_DEFINE_ENUM(HIF_CNF_ID_##msg); -#define hif_ind_name(msg) TRACE_DEFINE_ENUM(HIF_IND_ID_##msg); -hif_msg_list_enum -#undef hif_cnf_name -#undef hif_ind_name -#define hif_cnf_name(msg) { HIF_CNF_ID_##msg, #msg }, -#define hif_ind_name(msg) { HIF_IND_ID_##msg, #msg }, -#define hif_msg_list hif_msg_list_enum { -1, NULL } - -#define _hif_mib_list \ - hif_mib_name(ARP_IP_ADDRESSES_TABLE) \ - hif_mib_name(ARP_KEEP_ALIVE_PERIOD) \ - hif_mib_name(BEACON_FILTER_ENABLE) \ - hif_mib_name(BEACON_FILTER_TABLE) \ - hif_mib_name(BEACON_STATS) \ - hif_mib_name(BEACON_WAKEUP_PERIOD) \ - hif_mib_name(BLOCK_ACK_POLICY) \ - hif_mib_name(CCA_CONFIG) \ - hif_mib_name(CONFIG_DATA_FILTER) \ - hif_mib_name(COUNTERS_TABLE) \ - hif_mib_name(CURRENT_TX_POWER_LEVEL) \ - hif_mib_name(DOT11_MAC_ADDRESS) \ - hif_mib_name(DOT11_MAX_RECEIVE_LIFETIME) \ - hif_mib_name(DOT11_MAX_TRANSMIT_MSDU_LIFETIME) \ - hif_mib_name(DOT11_RTS_THRESHOLD) \ - hif_mib_name(DOT11_WEP_DEFAULT_KEY_ID) \ - hif_mib_name(ETHERTYPE_DATAFRAME_CONDITION) \ - hif_mib_name(EXTENDED_COUNTERS_TABLE) \ - hif_mib_name(GL_BLOCK_ACK_INFO) \ - hif_mib_name(GL_OPERATIONAL_POWER_MODE) \ - hif_mib_name(GL_SET_MULTI_MSG) \ - hif_mib_name(GRP_SEQ_COUNTER) \ - hif_mib_name(INACTIVITY_TIMER) \ - hif_mib_name(INTERFACE_PROTECTION) \ - hif_mib_name(IPV4_ADDR_DATAFRAME_CONDITION) \ - hif_mib_name(IPV6_ADDR_DATAFRAME_CONDITION) \ - hif_mib_name(KEEP_ALIVE_PERIOD) \ - hif_mib_name(MAC_ADDR_DATAFRAME_CONDITION) \ - hif_mib_name(MAGIC_DATAFRAME_CONDITION) \ - hif_mib_name(MAX_TX_POWER_LEVEL) \ - hif_mib_name(NON_ERP_PROTECTION) \ - hif_mib_name(NS_IP_ADDRESSES_TABLE) \ - hif_mib_name(OVERRIDE_INTERNAL_TX_RATE) \ - hif_mib_name(PORT_DATAFRAME_CONDITION) \ - hif_mib_name(PROTECTED_MGMT_POLICY) \ - hif_mib_name(RCPI_RSSI_THRESHOLD) \ - hif_mib_name(RX_FILTER) \ - hif_mib_name(SET_ASSOCIATION_MODE) \ - hif_mib_name(SET_DATA_FILTERING) \ - hif_mib_name(SET_HT_PROTECTION) \ - hif_mib_name(SET_TX_RATE_RETRY_POLICY) \ - hif_mib_name(SET_UAPSD_INFORMATION) \ - hif_mib_name(SLOT_TIME) \ - hif_mib_name(STATISTICS_TABLE) \ - hif_mib_name(TEMPLATE_FRAME) \ - hif_mib_name(TSF_COUNTER) \ - hif_mib_name(UC_MC_BC_DATAFRAME_CONDITION) - -#define hif_mib_list_enum _hif_mib_list - -#undef hif_mib_name -#define hif_mib_name(mib) TRACE_DEFINE_ENUM(HIF_MIB_ID_##mib); -hif_mib_list_enum -#undef hif_mib_name -#define hif_mib_name(mib) { HIF_MIB_ID_##mib, #mib }, -#define hif_mib_list hif_mib_list_enum { -1, NULL } - -DECLARE_EVENT_CLASS(hif_data, - TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv), - TP_ARGS(hif, tx_fill_level, is_recv), - TP_STRUCT__entry( - __field(int, tx_fill_level) - __field(int, msg_id) - __field(const char *, msg_type) - __field(int, msg_len) - __field(int, buf_len) - __field(int, if_id) - __field(int, mib) - __array(u8, buf, 128) - ), - TP_fast_assign( - int header_len; - - __entry->tx_fill_level = tx_fill_level; - __entry->msg_len = le16_to_cpu(hif->len); - __entry->msg_id = hif->id; - __entry->if_id = hif->interface; - if (is_recv) - __entry->msg_type = __entry->msg_id & 0x80 ? "IND" : "CNF"; - else - __entry->msg_type = "REQ"; - if (!is_recv && - (__entry->msg_id == HIF_REQ_ID_READ_MIB || - __entry->msg_id == HIF_REQ_ID_WRITE_MIB)) { - __entry->mib = le16_to_cpup((__le16 *)hif->body); - header_len = 4; - } else { - __entry->mib = -1; - header_len = 0; - } - __entry->buf_len = min_t(int, __entry->msg_len, - sizeof(__entry->buf)) - - sizeof(struct hif_msg) - header_len; - memcpy(__entry->buf, hif->body + header_len, __entry->buf_len); - ), - TP_printk("%d:%d:%s_%s%s%s: %s%s (%d bytes)", - __entry->tx_fill_level, - __entry->if_id, - __entry->msg_type, - __print_symbolic(__entry->msg_id, hif_msg_list), - __entry->mib != -1 ? "/" : "", - __entry->mib != -1 ? __print_symbolic(__entry->mib, hif_mib_list) : "", - __print_hex(__entry->buf, __entry->buf_len), - __entry->msg_len > sizeof(__entry->buf) ? " ..." : "", - __entry->msg_len - ) -); -DEFINE_EVENT(hif_data, hif_send, - TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv), - TP_ARGS(hif, tx_fill_level, is_recv)); -#define _trace_hif_send(hif, tx_fill_level)\ - trace_hif_send(hif, tx_fill_level, false) -DEFINE_EVENT(hif_data, hif_recv, - TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv), - TP_ARGS(hif, tx_fill_level, is_recv)); -#define _trace_hif_recv(hif, tx_fill_level)\ - trace_hif_recv(hif, tx_fill_level, true) - -#define wfx_reg_list_enum \ - wfx_reg_name(WFX_REG_CONFIG, "CONFIG") \ - wfx_reg_name(WFX_REG_CONTROL, "CONTROL") \ - wfx_reg_name(WFX_REG_IN_OUT_QUEUE, "QUEUE") \ - wfx_reg_name(WFX_REG_AHB_DPORT, "AHB") \ - wfx_reg_name(WFX_REG_BASE_ADDR, "BASE_ADDR") \ - wfx_reg_name(WFX_REG_SRAM_DPORT, "SRAM") \ - wfx_reg_name(WFX_REG_SET_GEN_R_W, "SET_GEN_R_W") \ - wfx_reg_name(WFX_REG_FRAME_OUT, "FRAME_OUT") - -#undef wfx_reg_name -#define wfx_reg_name(sym, name) TRACE_DEFINE_ENUM(sym); -wfx_reg_list_enum -#undef wfx_reg_name -#define wfx_reg_name(sym, name) { sym, name }, -#define wfx_reg_list wfx_reg_list_enum { -1, NULL } - -DECLARE_EVENT_CLASS(io_data, - TP_PROTO(int reg, int addr, const void *io_buf, size_t len), - TP_ARGS(reg, addr, io_buf, len), - TP_STRUCT__entry( - __field(int, reg) - __field(int, addr) - __field(int, msg_len) - __field(int, buf_len) - __array(u8, buf, 32) - __array(u8, addr_str, 10) - ), - TP_fast_assign( - __entry->reg = reg; - __entry->addr = addr; - __entry->msg_len = len; - __entry->buf_len = min_t(int, sizeof(__entry->buf), - __entry->msg_len); - memcpy(__entry->buf, io_buf, __entry->buf_len); - if (addr >= 0) - snprintf(__entry->addr_str, 10, "/%08x", addr); - else - __entry->addr_str[0] = 0; - ), - TP_printk("%s%s: %s%s (%d bytes)", - __print_symbolic(__entry->reg, wfx_reg_list), - __entry->addr_str, - __print_hex(__entry->buf, __entry->buf_len), - __entry->msg_len > sizeof(__entry->buf) ? " ..." : "", - __entry->msg_len - ) -); -DEFINE_EVENT(io_data, io_write, - TP_PROTO(int reg, int addr, const void *io_buf, size_t len), - TP_ARGS(reg, addr, io_buf, len)); -#define _trace_io_ind_write(reg, addr, io_buf, len)\ - trace_io_write(reg, addr, io_buf, len) -#define _trace_io_write(reg, io_buf, len) trace_io_write(reg, -1, io_buf, len) -DEFINE_EVENT(io_data, io_read, - TP_PROTO(int reg, int addr, const void *io_buf, size_t len), - TP_ARGS(reg, addr, io_buf, len)); -#define _trace_io_ind_read(reg, addr, io_buf, len)\ - trace_io_read(reg, addr, io_buf, len) -#define _trace_io_read(reg, io_buf, len) trace_io_read(reg, -1, io_buf, len) - -DECLARE_EVENT_CLASS(io_data32, - TP_PROTO(int reg, int addr, u32 val), - TP_ARGS(reg, addr, val), - TP_STRUCT__entry( - __field(int, reg) - __field(int, addr) - __field(int, val) - __array(u8, addr_str, 10) - ), - TP_fast_assign( - __entry->reg = reg; - __entry->addr = addr; - __entry->val = val; - if (addr >= 0) - snprintf(__entry->addr_str, 10, "/%08x", addr); - else - __entry->addr_str[0] = 0; - ), - TP_printk("%s%s: %08x", - __print_symbolic(__entry->reg, wfx_reg_list), - __entry->addr_str, - __entry->val - ) -); -DEFINE_EVENT(io_data32, io_write32, - TP_PROTO(int reg, int addr, u32 val), - TP_ARGS(reg, addr, val)); -#define _trace_io_ind_write32(reg, addr, val) trace_io_write32(reg, addr, val) -#define _trace_io_write32(reg, val) trace_io_write32(reg, -1, val) -DEFINE_EVENT(io_data32, io_read32, - TP_PROTO(int reg, int addr, u32 val), - TP_ARGS(reg, addr, val)); -#define _trace_io_ind_read32(reg, addr, val) trace_io_read32(reg, addr, val) -#define _trace_io_read32(reg, val) trace_io_read32(reg, -1, val) - -DECLARE_EVENT_CLASS(piggyback, - TP_PROTO(u32 val, bool ignored), - TP_ARGS(val, ignored), - TP_STRUCT__entry( - __field(int, val) - __field(bool, ignored) - ), - TP_fast_assign( - __entry->val = val; - __entry->ignored = ignored; - ), - TP_printk("CONTROL: %08x%s", - __entry->val, - __entry->ignored ? " (ignored)" : "" - ) -); -DEFINE_EVENT(piggyback, piggyback, - TP_PROTO(u32 val, bool ignored), - TP_ARGS(val, ignored)); -#define _trace_piggyback(val, ignored) trace_piggyback(val, ignored) - -TRACE_EVENT(bh_stats, - TP_PROTO(int ind, int req, int cnf, int busy, bool release), - TP_ARGS(ind, req, cnf, busy, release), - TP_STRUCT__entry( - __field(int, ind) - __field(int, req) - __field(int, cnf) - __field(int, busy) - __field(bool, release) - ), - TP_fast_assign( - __entry->ind = ind; - __entry->req = req; - __entry->cnf = cnf; - __entry->busy = busy; - __entry->release = release; - ), - TP_printk("IND/REQ/CNF:%3d/%3d/%3d, REQ in progress:%3d, WUP: %s", - __entry->ind, - __entry->req, - __entry->cnf, - __entry->busy, - __entry->release ? "release" : "keep" - ) -); -#define _trace_bh_stats(ind, req, cnf, busy, release)\ - trace_bh_stats(ind, req, cnf, busy, release) - -TRACE_EVENT(tx_stats, - TP_PROTO(const struct hif_cnf_tx *tx_cnf, const struct sk_buff *skb, - int delay), - TP_ARGS(tx_cnf, skb, delay), - TP_STRUCT__entry( - __field(int, pkt_id) - __field(int, delay_media) - __field(int, delay_queue) - __field(int, delay_fw) - __field(int, ack_failures) - __field(int, flags) - __array(int, rate, 4) - __array(int, tx_count, 4) - ), - TP_fast_assign( - // Keep sync with wfx_rates definition in main.c - static const int hw_rate[] = { 0, 1, 2, 3, 6, 7, 8, 9, - 10, 11, 12, 13 }; - const struct ieee80211_tx_info *tx_info = - (const struct ieee80211_tx_info *)skb->cb; - const struct ieee80211_tx_rate *rates = tx_info->driver_rates; - int i; - - __entry->pkt_id = tx_cnf->packet_id; - __entry->delay_media = le32_to_cpu(tx_cnf->media_delay); - __entry->delay_queue = le32_to_cpu(tx_cnf->tx_queue_delay); - __entry->delay_fw = delay; - __entry->ack_failures = tx_cnf->ack_failures; - if (!tx_cnf->status || __entry->ack_failures) - __entry->ack_failures += 1; - - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - if (rates[0].flags & IEEE80211_TX_RC_MCS) - __entry->rate[i] = rates[i].idx; - else - __entry->rate[i] = hw_rate[rates[i].idx]; - __entry->tx_count[i] = rates[i].count; - } - __entry->flags = 0; - if (rates[0].flags & IEEE80211_TX_RC_MCS) - __entry->flags |= 0x01; - if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) - __entry->flags |= 0x02; - if (rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD) - __entry->flags |= 0x04; - if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) - __entry->flags |= 0x08; - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - __entry->flags |= 0x10; - if (tx_cnf->status) - __entry->flags |= 0x20; - if (tx_cnf->status == HIF_STATUS_TX_FAIL_REQUEUE) - __entry->flags |= 0x40; - ), - TP_printk("packet ID: %08x, rate policy: %s %d|%d %d|%d %d|%d %d|%d -> %d attempt, Delays media/queue/total: %4dus/%4dus/%4dus", - __entry->pkt_id, - __print_flags(__entry->flags, NULL, - { 0x01, "M" }, { 0x02, "S" }, { 0x04, "G" }, - { 0x08, "R" }, { 0x10, "D" }, { 0x20, "F" }, - { 0x40, "Q" }), - __entry->rate[0], - __entry->tx_count[0], - __entry->rate[1], - __entry->tx_count[1], - __entry->rate[2], - __entry->tx_count[2], - __entry->rate[3], - __entry->tx_count[3], - __entry->ack_failures, - __entry->delay_media, - __entry->delay_queue, - __entry->delay_fw - ) -); -#define _trace_tx_stats(tx_cnf, skb, delay) trace_tx_stats(tx_cnf, skb, delay) - -TRACE_EVENT(queues_stats, - TP_PROTO(struct wfx_dev *wdev, const struct wfx_queue *elected_queue), - TP_ARGS(wdev, elected_queue), - TP_STRUCT__entry( - __field(int, vif_id) - __field(int, queue_id) - __array(int, hw, IEEE80211_NUM_ACS * 2) - __array(int, drv, IEEE80211_NUM_ACS * 2) - __array(int, cab, IEEE80211_NUM_ACS * 2) - ), - TP_fast_assign( - const struct wfx_queue *queue; - struct wfx_vif *wvif; - int i, j; - - for (j = 0; j < IEEE80211_NUM_ACS * 2; j++) { - __entry->hw[j] = -1; - __entry->drv[j] = -1; - __entry->cab[j] = -1; - } - __entry->vif_id = -1; - __entry->queue_id = -1; - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - j = wvif->id * IEEE80211_NUM_ACS + i; - WARN_ON(j >= IEEE80211_NUM_ACS * 2); - queue = &wvif->tx_queue[i]; - __entry->hw[j] = atomic_read(&queue->pending_frames); - __entry->drv[j] = skb_queue_len(&queue->normal); - __entry->cab[j] = skb_queue_len(&queue->cab); - if (queue == elected_queue) { - __entry->vif_id = wvif->id; - __entry->queue_id = i; - } - } - } - ), - TP_printk("got skb from %d/%d, pend. hw/norm/cab: [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ] [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ]", - __entry->vif_id, __entry->queue_id, - __entry->hw[0], __entry->drv[0], __entry->cab[0], - __entry->hw[1], __entry->drv[1], __entry->cab[1], - __entry->hw[2], __entry->drv[2], __entry->cab[2], - __entry->hw[3], __entry->drv[3], __entry->cab[3], - __entry->hw[4], __entry->drv[4], __entry->cab[4], - __entry->hw[5], __entry->drv[5], __entry->cab[5], - __entry->hw[6], __entry->drv[6], __entry->cab[6], - __entry->hw[7], __entry->drv[7], __entry->cab[7] - ) -); - -#endif - -/* This part must be outside protection */ -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE traces - -#include diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h deleted file mode 100644 index 94898680ccde..000000000000 --- a/drivers/staging/wfx/wfx.h +++ /dev/null @@ -1,166 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Common private data for Silicon Labs WFx chips. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (c) 2006, Michael Wu - * Copyright 2004-2006 Jean-Baptiste Note , et al. - */ -#ifndef WFX_H -#define WFX_H - -#include -#include -#include -#include -#include - -#include "bh.h" -#include "data_tx.h" -#include "main.h" -#include "queue.h" -#include "hif_tx.h" - -#define USEC_PER_TXOP 32 // see struct ieee80211_tx_queue_params -#define USEC_PER_TU 1024 - -struct hwbus_ops; - -struct wfx_dev { - struct wfx_platform_data pdata; - struct device *dev; - struct ieee80211_hw *hw; - struct ieee80211_vif *vif[2]; - struct mac_address addresses[2]; - const struct hwbus_ops *hwbus_ops; - void *hwbus_priv; - - u8 keyset; - struct completion firmware_ready; - struct hif_ind_startup hw_caps; - struct wfx_hif hif; - struct delayed_work cooling_timeout_work; - bool poll_irq; - bool chip_frozen; - struct mutex conf_mutex; - - struct wfx_hif_cmd hif_cmd; - struct sk_buff_head tx_pending; - wait_queue_head_t tx_dequeue; - atomic_t tx_lock; - - atomic_t packet_id; - u32 key_map; - - struct hif_rx_stats rx_stats; - struct mutex rx_stats_lock; - struct hif_tx_power_loop_info tx_power_loop_info; - struct mutex tx_power_loop_info_lock; - int force_ps_timeout; -}; - -struct wfx_vif { - struct wfx_dev *wdev; - struct ieee80211_vif *vif; - struct ieee80211_channel *channel; - int id; - - u32 link_id_map; - - bool after_dtim_tx_allowed; - bool join_in_progress; - - struct delayed_work beacon_loss_work; - - struct wfx_queue tx_queue[4]; - struct tx_policy_cache tx_policy_cache; - struct work_struct tx_policy_upload_work; - - struct work_struct update_tim_work; - - unsigned long uapsd_mask; - - /* avoid some operations in parallel with scan */ - struct mutex scan_lock; - struct work_struct scan_work; - struct completion scan_complete; - bool scan_abort; - struct ieee80211_scan_request *scan_req; - - struct completion set_pm_mode_complete; -}; - -static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id) -{ - if (vif_id >= ARRAY_SIZE(wdev->vif)) { - dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id); - return NULL; - } - vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif)); - if (!wdev->vif[vif_id]) { - dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n", - vif_id); - return NULL; - } - return (struct wfx_vif *) wdev->vif[vif_id]->drv_priv; -} - -static inline struct wfx_vif *wvif_iterate(struct wfx_dev *wdev, - struct wfx_vif *cur) -{ - int i; - int mark = 0; - struct wfx_vif *tmp; - - if (!cur) - mark = 1; - for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { - tmp = wdev_to_wvif(wdev, i); - if (mark && tmp) - return tmp; - if (tmp == cur) - mark = 1; - } - return NULL; -} - -static inline int wvif_count(struct wfx_dev *wdev) -{ - int i; - int ret = 0; - struct wfx_vif *wvif; - - for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { - wvif = wdev_to_wvif(wdev, i); - if (wvif) - ret++; - } - return ret; -} - -static inline void memreverse(u8 *src, u8 length) -{ - u8 *lo = src; - u8 *hi = src + length - 1; - u8 swap; - - while (lo < hi) { - swap = *lo; - *lo++ = *hi; - *hi-- = swap; - } -} - -static inline int memzcmp(void *src, unsigned int size) -{ - u8 *buf = src; - - if (!size) - return 0; - if (*buf) - return 1; - return memcmp(buf, buf + 1, size - 1); -} - -#endif /* WFX_H */