From patchwork Fri Aug 9 09:44:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818284 Received: from AS8PR04CU009.outbound.protection.outlook.com (mail-westeuropeazon11011004.outbound.protection.outlook.com [52.101.70.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ACF54190686; Fri, 9 Aug 2024 09:45:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.70.4 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196760; cv=fail; b=FK3mip7XHB2/fSD32Hjf7EWws+DoMWqKTW1KfxanWrKhwuLW+bys5ogYPJlxuo9sCrT+LcigqtFhelW5Np5AGIOGeGVgc+WchaJuvEzPgMz8bJFYA7SpMFpad9XeBkZczns16nsfOoOYDDR/+m/kjDNWwWIPn2p/w5vvyri6vYg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196760; c=relaxed/simple; bh=9E2BYEfAdC67ORWe04zygWegf4t9949M8HjL+v3qQQs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=WjrDvrorSbbgz9jjJeIgIlNVja2EJxk05b+P6t3RNlfuFXby/Q3ntqEO709/tdmUuohi/X18J860Zt9QrEYEuzviBaoQGoeKCryiMCGgxd56r0amDQrE+nlo3rVfbDzH0eNcibodrtikwg1PRODWfaSqCgB9ZsvvzZnFd3AjrJ4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=h6ztb8Om; arc=fail smtp.client-ip=52.101.70.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="h6ztb8Om" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=bLJDIrISAl+IoN0D/n3ppgYZpWrpI/8VvychYJDzM0DazpWVFSf5xVtpbSAZeAiV7DDEwPfxbcvmckgkEoBmzBSlceBP8/K7+5TXRkF8Gu2v4tEG+T3H6gIr7bjgTmMXPLaOKABLcwSuJ0ZRsN86VjB883d1Lak3/YP4+iHTl06xB0XILpn9TOfAYjLuFRkbatYLnoDc4PFeh4qNn6TWKqOUxgI/7y9Spi+3vbubS/tpqUnu+hfhnZaBU840Iicp0BSd/YRYamL7JLzhmbr5oFYn6bp3b6HsL+sT0bmd6UIk+rzrWC2NbUdS3Ca/U7TlEOJvQ+YSmIBEyse92poevw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=s+uZVJH/d2Oae4ido2ZVWKaRgeVGcwCwV3uhdGhhGKA=; b=HqqwvmIIUtiBnmkvvWkWVNo8PnMKP53UTgY61A1bgV+JBqR8jVoenwl/1tiOlXtREijtvI/WRkonq35KwHGra/Zit42ySL0VfCSoKtwYqZ8SBQH66nMj2Ktv3CD2U7Ht5t0jKedzaR/KHas28MWV+jhOm1HbCcPfBcE2Lrn+ANAlNnjqlT0ubSE8nbfL69LgL6zSSsV9wR7G5V801ExBIk9U42tXme9Rtujk9TbVX9/Rs1Sn5OdR/9xa0m4enc+uqdY2b+cLHMRTqR/76Cuk/Hpcb62DQKB3/X503POvd7Q0xYRCTgVAibBmrZE/9Zx+Q5Tsz/8TornqAObtdeAKqw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=s+uZVJH/d2Oae4ido2ZVWKaRgeVGcwCwV3uhdGhhGKA=; b=h6ztb8Om0zbofPsBPStiDw9J5xgDoxvZiG6MwxrRq+wwMzRs93apDXwavda0OtXY/Nda6b2Er02u+xtszePQxrZBzFJyi19Q3RZqrfh4izhcM+4vI9HMZiNVnhncP59W58WKQ5+GB73MpZMX3iXLlTCOeGmdd7G7fdh0FBCY+98nq21cibKhxgMD4817b5bazn9DmbdJ1hk84tTfzYz4/NYrNYsn1UP+c+R61QrX5eCSVPY7zwl6uvaBrdR2Q/y6MXzvw3TZbIglNllDQF0PdretHxXTeIFLdWLpa2BijBpSzbyWCrNx0kZpUbfWBWBDX5OyM0VzcB1loE5vm05+GA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:45:53 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:45:53 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 01/43] wifi: nxpwifi: add 11ac.c Date: Fri, 9 Aug 2024 17:44:51 +0800 Message-Id: <20240809094533.1660-2-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: 01753177-e374-4cf0-2a00-08dcb8580f39 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: xWW0ShU3mmPEkM4NFSnLH/2Vmt432U8UagqUeaARQeWEq1hnmvfNDlTUDzykkK++RAsyDqtiKk34AjgZ5JeROOhirUBivxE62Zw97CKnGa80ZV1myz7H90e5gsTNXhQS/VEYvdT+WI0zTTIZC68bLpNgSlxKbYh0Khvcms+q10IkT+/ZiX30bBQxtyxDfqgeMQhS1QOsfAURlSQVqKgyFH2S8i2wfobsUpECR8CBQqxrqJD028UoC+KAkPazD9+XYccN7oE89H2gRFMDhv+rEEj88kEbh9g4Yxt2ZvgXS3siEJVLthTvgkdd3IaAuIaJQQoOGMUCX/s645A6RHzJrJKKeKsmrOUo8WmaB3LrkMbtQVRjRkSNKH2Fcc7iaAQ3tQoxxToA5aKgfO4y/WPzTBHMJzAp1900g0xW/EHKj4JlUI1+FHLWrwapmIqN/6vvhbSVuIRABoo/tDXjc0Qb/LwXVmZWD+7SSOEFsizzyHhIgOqwDIzU4K7Q5wl2u0ubwl6+q9E30H3N5dURu6mlQfiQxRwFon2v7q0mHY/L86PqqojD/KwHi17g2JONErIQonrElNBbd/ukT0JYYDfw5SLlXp2tX2TTydb4ZMp9s5xOlB2KnshkHTIL0ahb6kj40KZxMU2lkg9XZv8wFwrH8VIoA3NemaNV9o/sZ3WFmHinty4BIypFiQ/72wWFGtGky6Fg98zStniv4qg7YIfjp/97lQOtr7L3GME3EjS8hp/18Tq3yZgEmXzpoTnXz77hDj7yse9lrR4pICk0mb2nUo7w8xy8RuX/UZqLW+yg6VFpqcW/T83jhmHX8pxR6RfipH5YJCSR2BXuaYoKYna+3pjMloXPpgsnngXWi9lAxodX573eTFdQM0JPNGi8MqWpMMZnoWBlOlOElbCW+OVfV/xVOIzKWgd/WY199/UM9AZ49XUh9/2r1Pk8ep4GUnm/Pne4CRkOtWpFkKC5lYlTVMroqGhmdQ0ri7Lz37aQp2/k9Ua+evzExiigCFHwPLJSBW6BoNRkDP+s6ClFGigb+C5tJa+uG95qoJ7PuxDWhoWrgDnTVwEfDtQfXZcLiXz6IhPaPth0okLFz5Zz0Ifo3f/mkGVrKGGHrB6iJAJFc54i1r+g/D6CIItoV6SBXxmkFGDpiA9cV4eVXTSwnpDpdKmYgdFYwPar1inWlTGjjuzz1aI8wIXdfmr1qfv8zSSkQfU1yGcL7g8fIfuA4krqOvgO9XWWo8Uu5JXbfEKT6/dtjXjrkIYcDU7NEhHrgtJh6oHB6wv7He70tZ7zIVy7+ufQoKOyuR/CJVfZfPvxrvmaMYb0h57fyGTZL63L1PR76dVlhDvdNOKM8dOTaFRcMg== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: ETFzIwb3k12bpzWFaRV/zkP5864rXe2yjhSW1GfG07xlagEuBb5U3t7Rex5oIuvfmSGoV3iR+W2JqKgD8UvunRQlkSfvbwcL7szp68LjEzVQ7hmXBdATUZ9OdV5ezb0PNlbqoKHG4dcA67Ksv+cWFTwsQ40Iy+BBuvQrlROI35OhhjvqblX5U1OwLEUzz2rIUlUTVb2u8gsttQD0CMBjsUcbfGHbYgB3LKWaHQS+gVQjvlri7DZSrW6aV7HaqPlI/SfBU3403i7BRBecxFzrEHj85iZw8TBzTr7VwndEzMYOPX4N4046PZjTbDq0PTWqcqhd56uQJMfxJWhSY4KaP8cvJ3ge74Mo3T5ZlA831LKVVAa+aOMdmrFMQlAXq3tf+G4RD4dKru1c8sCRnibcVndTeT+2UMyQixVdEDBEdYTZDkOFtPeW1CQz0O/0129Aafmp+xhvsyLpQsz2iFh9nk4Jlbp8cvhvEOClmfSOvWlgcjacj/kuNsTHwSSbv7aN8gVZ/AH74JvGwgXm/CsWijgTZUsMkgbRp5LZVZWd0EdqM1CiLxUsNfbcJspD5vqRllB5L1s992MOOQoj6sRVIHAYD9wHiCFrCcFEwFASGTYUvxtOiKAa6u0spvsIH7lWCbmhJC030U6XpvYOStwcLYjcr6lmiPeEcgAzqHVldAEx4bvyH/DuGUqQTxgBkmlHBptdZdsQoFQzY1wqujRmuF0Atda/XxZsHOSLa+s08Y8zVzf8ctb10vteBZpafBd5Yg2vjZs2V9vFpZDMNLiCOKl81iK/UNPH05dPNwLd4Le9ikSH/rXjHc/M9CbsIv8nF4C9Mdtz2QFhR3GuTXLGly0MJ4WyPl3szYR5bXJIdGC4Ux9g9cACnJSwksnYOwwKeQy5NKlp8odPh6UIZAPPHfuZqgixgTH3BFVniOTHbhUUMuS69eX7bXO8fete41qTx2ACLlOZJjwZA8cCUjJoDT4am5LVg4SJIFvlO4aenWvoQ35Yy6WgtdthvwF9hLyVh08lRim17GjNzztfWQQSs8aLsSkHBfFbmegUZB4+W/7UXf08/No03lRaLW2Aw0bjR15SxtSs97jUBTk2uW/leFzSU0ptKzqiSklXCVsOGROtegisUss4kB7skfqs4W6vsYc1Hzo+Bl4aYnnH94RJX8BVHjTMTq8apr8ZCVo0px/14u8qy85DAHxVZq2GMueUWfEqNz/b0/n0AFVO7pHLB8euOPHyN2UHPNXBMGbQaqEuUwN9AZGibAzOA0ZtmEe2vguJEZqUVsGSD6Udut63yybSyv0ZSWqbPedP5Jq77x5YBLP6SnI72IzwYDLTRi85eTz1cDzS3x5o/iQMvQuMgInqGuyhgsjJbTfQ1qI2O90ow+dHIneiodwewPOfDFGYXTn8Zr8gazZ223qRxwRtvsSgQkTIM7Fhf6L/o4czV0LLMGj2kXRk9Ek+UGfWe44neQnSYefZwPgi0QWQ6yIJR8lsmLo/QFaVvAwNJuV9GaYqx/amxd6EAaelkjgB1cyz0kRBDHp4EwJlf981QO7bj5Ff4Y50HzcnwfiwFdF99BZiG6ep2zhZhJrVAQKYc7b/+dcT0kG7ZBu9eyWS5LrCf1HgcnWy3s00JfwuyKFT2mKwIgTvyiGavpJwTgO8Qlzh X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 01753177-e374-4cf0-2a00-08dcb8580f39 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:45:53.5275 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: lyzzIMIE6MWjg34lkuij/ovDu4OwUZGxKuRst94zXcCnPBvtufFE3rIGEmCusYnicQjV9+DB+nJ4E5jWvyI4JQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/11ac.c | 366 ++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/11ac.c diff --git a/drivers/net/wireless/nxp/nxpwifi/11ac.c b/drivers/net/wireless/nxp/nxpwifi/11ac.c new file mode 100644 index 000000000000..514af3b92dd4 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/11ac.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: 802.11ac + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "fw.h" +#include "main.h" +#include "11ac.h" + +/* Tables of the MCS map to the highest data rate (in Mbps) supported + * for long GI. + */ +static const u16 max_rate_lgi_80MHZ[8][3] = { + {0x124, 0x15F, 0x186}, /* NSS = 1 */ + {0x249, 0x2BE, 0x30C}, /* NSS = 2 */ + {0x36D, 0x41D, 0x492}, /* NSS = 3 */ + {0x492, 0x57C, 0x618}, /* NSS = 4 */ + {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */ + {0x6DB, 0x83A, 0x0}, /* NSS = 6 */ + {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */ + {0x924, 0xAF8, 0xC30} /* NSS = 8 */ +}; + +static const u16 max_rate_lgi_160MHZ[8][3] = { + {0x249, 0x2BE, 0x30C}, /* NSS = 1 */ + {0x492, 0x57C, 0x618}, /* NSS = 2 */ + {0x6DB, 0x83A, 0x0}, /* NSS = 3 */ + {0x924, 0xAF8, 0xC30}, /* NSS = 4 */ + {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */ + {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */ + {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */ + {0x1248, 0x15F0, 0x1860} /* NSS = 8 */ +}; + +/* This function converts the 2-bit MCS map to the highest long GI + * VHT data rate. + */ +static u16 +nxpwifi_convert_mcsmap_to_maxrate(struct nxpwifi_private *priv, + u8 bands, u16 mcs_map) +{ + u8 i, nss, mcs; + u16 max_rate = 0; + u32 usr_vht_cap_info = 0; + struct nxpwifi_adapter *adapter = priv->adapter; + + if (bands & BAND_AAC) + usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a; + else + usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg; + + /* find the max NSS supported */ + nss = 1; + for (i = 1; i <= 8; i++) { + mcs = GET_VHTNSSMCS(mcs_map, i); + if (mcs < IEEE80211_VHT_MCS_NOT_SUPPORTED) + nss = i; + } + mcs = GET_VHTNSSMCS(mcs_map, nss); + + /* if mcs is 3, nss must be 1 (NSS = 1). Default mcs to MCS 0~9 */ + if (mcs == IEEE80211_VHT_MCS_NOT_SUPPORTED) + mcs = IEEE80211_VHT_MCS_SUPPORT_0_9; + + if (GET_VHTCAP_CHWDSET(usr_vht_cap_info)) { + /* support 160 MHz */ + max_rate = max_rate_lgi_160MHZ[nss - 1][mcs]; + if (!max_rate) + /* MCS9 is not supported in NSS6 */ + max_rate = max_rate_lgi_160MHZ[nss - 1][mcs - 1]; + } else { + max_rate = max_rate_lgi_80MHZ[nss - 1][mcs]; + if (!max_rate) + /* MCS9 is not supported in NSS3 */ + max_rate = max_rate_lgi_80MHZ[nss - 1][mcs - 1]; + } + + return max_rate; +} + +static void +nxpwifi_fill_vht_cap_info(struct nxpwifi_private *priv, + struct ieee80211_vht_cap *vht_cap, u8 bands) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + + if (bands & BAND_A) + vht_cap->vht_cap_info = + cpu_to_le32(adapter->usr_dot_11ac_dev_cap_a); + else + vht_cap->vht_cap_info = + cpu_to_le32(adapter->usr_dot_11ac_dev_cap_bg); +} + +void nxpwifi_fill_vht_cap_tlv(struct nxpwifi_private *priv, + struct ieee80211_vht_cap *vht_cap, u8 bands) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + u16 mcs_map_user, mcs_map_resp, mcs_map_result; + u16 mcs_user, mcs_resp, nss, tmp; + + /* Fill VHT cap info */ + nxpwifi_fill_vht_cap_info(priv, vht_cap, bands); + + /* rx MCS Set: find the minimum of the user rx mcs and ap rx mcs */ + mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support); + mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map); + mcs_map_result = 0; + + for (nss = 1; nss <= 8; nss++) { + mcs_user = GET_VHTNSSMCS(mcs_map_user, nss); + mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss); + + if (mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED || + mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED) + SET_VHTNSSMCS(mcs_map_result, nss, + IEEE80211_VHT_MCS_NOT_SUPPORTED); + else + SET_VHTNSSMCS(mcs_map_result, nss, + min(mcs_user, mcs_resp)); + } + + vht_cap->supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result); + + tmp = nxpwifi_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result); + vht_cap->supp_mcs.rx_highest = cpu_to_le16(tmp); + + /* tx MCS Set: find the minimum of the user tx mcs and ap tx mcs */ + mcs_map_user = GET_DEVTXMCSMAP(adapter->usr_dot_11ac_mcs_support); + mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map); + mcs_map_result = 0; + + for (nss = 1; nss <= 8; nss++) { + mcs_user = GET_VHTNSSMCS(mcs_map_user, nss); + mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss); + if (mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED || + mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED) + SET_VHTNSSMCS(mcs_map_result, nss, + IEEE80211_VHT_MCS_NOT_SUPPORTED); + else + SET_VHTNSSMCS(mcs_map_result, nss, + min(mcs_user, mcs_resp)); + } + + vht_cap->supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result); + + tmp = nxpwifi_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result); + vht_cap->supp_mcs.tx_highest = cpu_to_le16(tmp); +} + +int nxpwifi_cmd_append_11ac_tlv(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc, + u8 **buffer) +{ + struct nxpwifi_ie_types_vhtcap *vht_cap; + struct nxpwifi_ie_types_oper_mode_ntf *oper_ntf; + struct ieee_types_oper_mode_ntf *ieee_oper_ntf; + struct nxpwifi_ie_types_vht_oper *vht_op; + struct nxpwifi_adapter *adapter = priv->adapter; + u8 supp_chwd_set; + u32 usr_vht_cap_info; + int ret_len = 0; + + if (bss_desc->bss_band & BAND_A) + usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a; + else + usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg; + + /* VHT Capabilities IE */ + if (bss_desc->bcn_vht_cap) { + vht_cap = (struct nxpwifi_ie_types_vhtcap *)*buffer; + memset(vht_cap, 0, sizeof(*vht_cap)); + vht_cap->header.type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY); + vht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_vht_cap)); + memcpy((u8 *)vht_cap + sizeof(struct nxpwifi_ie_types_header), + (u8 *)bss_desc->bcn_vht_cap, + le16_to_cpu(vht_cap->header.len)); + + nxpwifi_fill_vht_cap_tlv(priv, &vht_cap->vht_cap, + bss_desc->bss_band); + *buffer += sizeof(*vht_cap); + ret_len += sizeof(*vht_cap); + } + + /* VHT Operation IE */ + if (bss_desc->bcn_vht_oper) { + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + vht_op = (struct nxpwifi_ie_types_vht_oper *)*buffer; + memset(vht_op, 0, sizeof(*vht_op)); + vht_op->header.type = + cpu_to_le16(WLAN_EID_VHT_OPERATION); + vht_op->header.len = cpu_to_le16(sizeof(*vht_op) - + sizeof(struct nxpwifi_ie_types_header)); + memcpy((u8 *)vht_op + + sizeof(struct nxpwifi_ie_types_header), + (u8 *)bss_desc->bcn_vht_oper, + le16_to_cpu(vht_op->header.len)); + + /* negotiate the channel width and central freq + * and keep the central freq as the peer suggests + */ + supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info); + + switch (supp_chwd_set) { + case 0: + vht_op->chan_width = + min_t(u8, IEEE80211_VHT_CHANWIDTH_80MHZ, + bss_desc->bcn_vht_oper->chan_width); + break; + case 1: + vht_op->chan_width = + min_t(u8, IEEE80211_VHT_CHANWIDTH_160MHZ, + bss_desc->bcn_vht_oper->chan_width); + break; + case 2: + vht_op->chan_width = + min_t(u8, IEEE80211_VHT_CHANWIDTH_80P80MHZ, + bss_desc->bcn_vht_oper->chan_width); + break; + default: + vht_op->chan_width = + IEEE80211_VHT_CHANWIDTH_USE_HT; + break; + } + + *buffer += sizeof(*vht_op); + ret_len += sizeof(*vht_op); + } + } + + /* Operating Mode Notification IE */ + if (bss_desc->oper_mode) { + ieee_oper_ntf = bss_desc->oper_mode; + oper_ntf = (void *)*buffer; + memset(oper_ntf, 0, sizeof(*oper_ntf)); + oper_ntf->header.type = cpu_to_le16(WLAN_EID_OPMODE_NOTIF); + oper_ntf->header.len = cpu_to_le16(sizeof(u8)); + oper_ntf->oper_mode = ieee_oper_ntf->oper_mode; + *buffer += sizeof(*oper_ntf); + ret_len += sizeof(*oper_ntf); + } + + return ret_len; +} + +int nxpwifi_cmd_11ac_cfg(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, u16 cmd_action, + struct nxpwifi_11ac_vht_cfg *cfg) +{ + struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg; + + cmd->command = cpu_to_le16(HOST_CMD_11AC_CFG); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) + + S_DS_GEN); + vhtcfg->action = cpu_to_le16(cmd_action); + vhtcfg->band_config = cfg->band_config; + vhtcfg->misc_config = cfg->misc_config; + vhtcfg->cap_info = cpu_to_le32(cfg->cap_info); + vhtcfg->mcs_tx_set = cpu_to_le32(cfg->mcs_tx_set); + vhtcfg->mcs_rx_set = cpu_to_le32(cfg->mcs_rx_set); + + return 0; +} + +/* This function initializes the BlockACK setup information for given + * nxpwifi_private structure for 11ac enabled networks. + */ +void nxpwifi_set_11ac_ba_params(struct nxpwifi_private *priv) +{ + priv->add_ba_param.timeout = NXPWIFI_DEFAULT_BLOCK_ACK_TIMEOUT; + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) { + priv->add_ba_param.tx_win_size = + NXPWIFI_11AC_UAP_AMPDU_DEF_TXWINSIZE; + priv->add_ba_param.rx_win_size = + NXPWIFI_11AC_UAP_AMPDU_DEF_RXWINSIZE; + } else { + priv->add_ba_param.tx_win_size = + NXPWIFI_11AC_STA_AMPDU_DEF_TXWINSIZE; + priv->add_ba_param.rx_win_size = + NXPWIFI_11AC_STA_AMPDU_DEF_RXWINSIZE; + } +} + +bool nxpwifi_is_bss_in_11ac_mode(struct nxpwifi_private *priv) +{ + struct nxpwifi_bssdescriptor *bss_desc; + struct ieee80211_vht_operation *vht_oper; + + bss_desc = &priv->curr_bss_params.bss_descriptor; + vht_oper = bss_desc->bcn_vht_oper; + + if (!bss_desc->bcn_vht_cap || !vht_oper) + return false; + + if (vht_oper->chan_width == IEEE80211_VHT_CHANWIDTH_USE_HT) + return false; + + return true; +} + +u8 nxpwifi_get_center_freq_index(struct nxpwifi_private *priv, u8 band, + u32 pri_chan, u8 chan_bw) +{ + u8 center_freq_idx = 0; + + if (band & BAND_AAC) { + switch (pri_chan) { + case 36: + case 40: + case 44: + case 48: + if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ) + center_freq_idx = 42; + break; + case 52: + case 56: + case 60: + case 64: + if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ) + center_freq_idx = 58; + else if (chan_bw == IEEE80211_VHT_CHANWIDTH_160MHZ) + center_freq_idx = 50; + break; + case 100: + case 104: + case 108: + case 112: + if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ) + center_freq_idx = 106; + break; + case 116: + case 120: + case 124: + case 128: + if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ) + center_freq_idx = 122; + else if (chan_bw == IEEE80211_VHT_CHANWIDTH_160MHZ) + center_freq_idx = 114; + break; + case 132: + case 136: + case 140: + case 144: + if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ) + center_freq_idx = 138; + break; + case 149: + case 153: + case 157: + case 161: + if (chan_bw == IEEE80211_VHT_CHANWIDTH_80MHZ) + center_freq_idx = 155; + break; + default: + center_freq_idx = 42; + } + } + + return center_freq_idx; +} From patchwork Fri Aug 9 09:44:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818398 Received: from AS8PR04CU009.outbound.protection.outlook.com (mail-westeuropeazon11011004.outbound.protection.outlook.com [52.101.70.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C3D0191F9E; Fri, 9 Aug 2024 09:46:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.70.4 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196762; cv=fail; b=CIAmyfr4sIkmnJtjFkmx9fXPiJ+lCM90yZLrJ7GhE165NG5PGzfUuwsERycHXUc3VoG9ClaZBz2wI/oVWD1SgnlUcDZ1QeQ5LYBk6Kb6CMP1iXomcyvIYDeiD6LnDkHSP0VvXiWSg+ZmVDzdTPMOsb+Mdn32kXKPdAD+deBiA9o= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196762; c=relaxed/simple; bh=E0s9X8Wne6kBEfKe+YOuimdOpYWMPmKTD97YtRAWrPg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=H2SXg/6AqNqidxM01Wd5UtibPzs6CA5/FJrzJduqGrycsJwbplHNDgTL0RIKFCRwxEkdUJk9BAA4yTrAQSqy8tMqO9Aqmmxm02XZAM+LGY4Z6wzP38Lw+xR+gbyL94oApa0qMqu7qAX8v2P1bjhMbSlkEWpWIiRhFiEbLLc85zI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=di2PvT7g; arc=fail smtp.client-ip=52.101.70.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="di2PvT7g" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=fMwP/Hgqf2ea0+/8NlWZ7o/1FsnVdQr4eISldNDBG9tAhZEM7sMMuC9SXdsuk/3tsKu93WVwp9RCzR+6l85rr/XpLwXtSqo/jZ3OTo6nCXzG8S8Ro9fJhTVn83XKZ4xBsw9EScluV4FlOrRXj8PSJgL1f+jptySfLgY6BkwfNHiyh04KJzyBv5p9dD2qgN4BugKq9PcJlLP05zjxyGiRWKCQ34bd805iSpS8zp6Gcwc6C/4twYmsJkwUWwk8S7zttt+OI4NoqWU0WX2tC12ztXa1NoVQsVbuEN+hBCHHs9kMhc0dGfyXXexHLmhWRrHReLOGF6RI0CiLlRg4EOFSdA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=IkabV74wYLnFDDb0iIkfEcSeLsp3BNYusGNRq5Q+q4Y=; b=dmGx783JyIesGxnEcehaC7GY97vlxdHYbQ/ipH9gIz04+3jfEPmqCeQJYC98s3H1IPQGWRcRFoRbxiPKYJ0Moil1btudjjxK/ZotJEYeWRnZsa+QaY9nsLpf7Ks8O4PalyQkQUc0A+Xr21R2YXSSnMZsjOJjzNmLPe59UOsmpSzfSwUWHOt+8fxVLJJJkrKHPkFSU3MQDqJCXgjeE9Z6U6V05uip2qK8uWvYOovsE/GNxFoD/pA0mcQm0TkkL3nXLMvEwYlQaB/4dCs1AKvd2gEZvGpWgxbuew6cNagTm5tynowwQot9RKbv0g8mqO3ZWOmy7VZAYaIS80JbFqSTHg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=IkabV74wYLnFDDb0iIkfEcSeLsp3BNYusGNRq5Q+q4Y=; b=di2PvT7gZugnX5lyaTTXQgZHU99mkRgCkDNIlwSkGiSn+pBEy/y2YKOXfkmU0Bljs/P12hb9RK733abyUhhJItNpk802S5fwGPX76PhTA3bMUlE4dDKlU1BbXdmcgMR6ltYYYRH7tg4lWEU7ZQs7JZwQ6k522rJOjEzl8jH4+woSuZdH3zM8gR9AA4JtWlS1+m5WIO+XZ/aggiq47fmf+LLQbPIWLgO0QEvwLaDno/c10INI6RBxmEkrEpFlUiCbxG7SwYyTr4dX2rWG0hl0Olie9q9uO1mWySh/+ItJ1ORGYkRN2hqy3t5St9OQYKYFdr8+qnqx5oTOhRRmjVyTLw== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:45:57 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:45:56 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 02/43] wifi: nxpwifi: add 11ac.h Date: Fri, 9 Aug 2024 17:44:52 +0800 Message-Id: <20240809094533.1660-3-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: 4fbc0fae-b2c0-44dc-5941-08dcb8581142 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: cLac36fooA30zzQXK4YedOm1xPuqKnOSJmBYWBKF/gVcBi6hD5Sl3KsuEZiD3TSpvHQVz6XdnagCvJLkCtlZgb/NJWTkwLr+Lm1TMVJx0Rgo5Ub2ZXWFEULtO8xQRRV70CFpEbh9moTJOcPtj3KixrOtnVsqYP2aWbv5ypBURYif/NSa16F9uzoS/1f+ZmUVTB6g9I69XIbjpTVNvdxKAV8A0Z1IBEB7vizmw0usSi3NfEv0khL/IRvfaH9IsKR/Z0R4hP4lGyP+H+9p+Vzl+Cbn9j8zeRKl5JQN2RhD2UCQ3AQ7VnLPOZUexUMw86lEd+jIOXjW4oOwiiT5ZJNk1CUUEsM8svLH3CpFep7tzMctyGwZbf9j0TLTzpRunIKcaEVGisMYK5zU6zgHwS+g8wIaYImF2BTxuw/wXCf/aKyqSbtKj3RRE4qnNYDlT4d2WfhgqTQKnBKKhL0XWSLmtGX28tIxcUF3pjktCeQNroA3S9ZjKU4jKly9dWvymYCf4f8J8k4gFesT4Y32w3SE4xvRbdYIN9vLxaaie/hdsf9JsiaaQMqzkFjlXfPwrr8F8BqwecIVvjPj2F5uYqoAUWuv2Y6YnDcVH2MmHCwiw12RfreZkU0DfF/Y8TEho5Y/LIqWLPen5HArDdENHcMl11VUBvyW+N1uNzM7+5qWG1oVxdh+UpUUoMbP4z5xVILJ4so0Mbk/uUHCoNWQLDlDzDV23/9qzQ9ux0jSLsc2XwR+HS3fQE9EN3VIHFKEOZf6iqP5ponoD74t0A2rG5AkqqQXoP2tNw0L12PcJBilg6HjMN7FhjsD73YBLmlsn6h9OJ1XstZwhwSH5+qnyOqCRSsAi6b5GFcTn4tjZRo+OTVJMfZzEA6G6dR6gRQRZZwXU8sLest3qxiUu3/4Tdc4DnaTqWQZn2cUl1EfvTHBbAvt7NX60J1ay9PjlRbIE1wYuOi+isaUHRuJbjy6PzW4gJbwDE9WLaKF1NBs3ZRPGmUXMtWXFl6WZQ53IUo7mzEhx1Kksex3lJwm3ZfELYz0R/L8ImIBC1ScV3Ld1x7CtDGoC/RGHbZQMRwBR60/MdffPX6XpDJRivRXOli0G+xC0NUYnbIR1MSjPzW4hiYT5S0qpVVNFf4v7U/fhVs6x0F29rlg7t0UL6vKyNSkcIdkdNCtf0Q/R96YjnmGWZ3NEOeSx1XAW6TEwKyQv8AC7pmKb87UyUWURljQvc3XdiZZBtgB5/71EgqOdht6MzEKsbnCHfcPRqfa9749oAELyCEOk8HiHUPDM36DHmsJ9h61U99hno9p9F2qmJIbfCT1AsbUSQpnLC6HCmXcOY7ac+FwFfB4uge7EJ5kpnU+flZRNg== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: zTOWEVgDKdgfJkC8iY+s3HrsOQcwLT7GoozJTlQPt5aaWWsWa8xZACB5Sr2T8DAfe8N3RfveGCy3/mDLDRIngwGPtQKTQ4NN11S6n92QOFq9Dlzc2Re306UEIdLLIU+h3ayhrVrnv6MupZFOho2/u72YFSzufLQ0W1piO342RE9LCBFa2pLwVJxZb2M0lR7RZot/GVNl0G0xo7CPgvOSHjJo7n8BwpX5eCL6veXbeOugntUpQs6BjJkixBdPb6E2QdMpgv6firIafl88JMYO5LVjWrFrz3rCcN2spMkQTEm4q5B4rh4v450aEe3MvPwx2cPrl0gQUH/Yt0EnQHrmz5slgR81UhOXqKoqve8gHmlkG65vUHz4aMcdO8h5yBjyjeX8xjCaXjPVr5qhDpB4quYxKWtRfQmtD0koytgkBSC5oMjeign3v5oeEmgtBHzxaUDX9w0Gjyh76PpVl35quPcJbAi4TFDM+MYyb/amkM3bOxAz+Ts/W9jurzJrU5HAPeBruCMPLKS2zZc0jx0arauZ+OaFlUYo/BF2/efvze8t4ZJ5+B0NFyg4dJXLRb83P6cdYvo4N3J7sCORgCYPU/DPSZJrWuRL9MBIeZhYnbiB8I+Rs6rBmC9tXjsxoPl3CCHHKb6K2CWr46uQ4HqORVZUK1cuk2xfcTtiIrnB5OMZYj1uH6yVGoXVu9Gq4yjNtTlSWHjGGT+K25V4M1OBG/UeVdxPEQzk3qbTHtahNdiWGX4qSrj6JgpGoUaMO25BUQjzdjM/J5nhqlTQYGocCtzeQpw8op/YCp9FkzxzWhlEEk5nQeoyYGJvE5ci2d7f1sFgDhgCsqLHVbw1piRFw3eX1r2rqvsuZ1X8/L8IY33aCqY9Sw12uz5CC1XOmCHV9AosY1P1Rq1P5EdTYFF2/hGK5OpVDeEj9pPIBHu888OpF/fmUqh0GFDgkhyAVwWKk/sM6I/Xs0LAkx5HpgIZ0PoCKJUh4t8D9pGb44GsuzrV6aNz/xpYoe2ldMBDbtdfcNmeECLvewNJaq+A+Bcuh0cUM0oS3hQUSZmFDjUQk5KBdvZUpQj79oE8WfRFm+ePvqDdX8esDpFW7Td7PBTMms6BqjMNLxI08P8u+ZoEeyk9QWWkFmKJ6io2iBxQjvg+AEnvDpoSpjQ72woUfBbbYC/lKj1ashX+O5htnYZCxqCkXjD28Wi/p9pzLHTzp4GGaxkMFTob5YMJp8cDkS6sFGXmF8G7un+uL19kJcbegL0wGs1JUXaB/kuoen2yQRwFJYe0RFAN8G5+AVYF2ynVdMFSwxHc5rX2/iARxi1XqQpXTumQQkKxNIV0qUdwN1oXOAWHB5aoLTdWmFi22PECmYCeaVVgQPsuJ2MZBtzFhBdYeSFmWtReD7NM91p5GvpPrkNbQ8Ryzdhs6t+j0gTnDes9Z8aVMiYli25IxPZA2wK5RsJLfbF3fM0A+S8KpVwuTJiChqHc+KuciZGnVSzn8jwwg5WCUaHkDNsZE8Rs4NAzlBUax2Clf2l6j4t/zIROtqsk8m5hwXuAt2+lYOil/agXu/TzvKoH7jN3Eiof4xsS1EgEyCRrVgy5Uzxh+lstuTnGk9tnUZo6NdyuNKVoZjAcTPZUnz1wWui88QJPd8euGPJI/X7h9IDfLxET5ex8 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 4fbc0fae-b2c0-44dc-5941-08dcb8581142 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:45:56.9388 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Mvj+tq5MaNa7b53TiYutDH9z8FFvkSfktwI7cE28ACAgJ+wzvAJekrPKFIWGpS4pSf+e2IOUWiezx/Xg+LBUEA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/11ac.h | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/11ac.h diff --git a/drivers/net/wireless/nxp/nxpwifi/11ac.h b/drivers/net/wireless/nxp/nxpwifi/11ac.h new file mode 100644 index 000000000000..b060de17a18e --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/11ac.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: 802.11ac + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_11AC_H_ +#define _NXPWIFI_11AC_H_ + +#define VHT_CFG_2GHZ BIT(0) +#define VHT_CFG_5GHZ BIT(1) + +enum vht_cfg_misc_config { + VHT_CAP_TX_OPERATION = 1, + VHT_CAP_ASSOCIATION, + VHT_CAP_UAP_ONLY +}; + +#define DEFAULT_VHT_MCS_SET 0xfffe +#define DISABLE_VHT_MCS_SET 0xffff + +#define VHT_BW_80_160_80P80 BIT(2) + +int nxpwifi_cmd_append_11ac_tlv(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc, + u8 **buffer); +int nxpwifi_cmd_11ac_cfg(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, u16 cmd_action, + struct nxpwifi_11ac_vht_cfg *cfg); +void nxpwifi_fill_vht_cap_tlv(struct nxpwifi_private *priv, + struct ieee80211_vht_cap *vht_cap, u8 bands); +#endif /* _NXPWIFI_11AC_H_ */ From patchwork Fri Aug 9 09:44:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818283 Received: from AS8PR04CU009.outbound.protection.outlook.com (mail-westeuropeazon11011004.outbound.protection.outlook.com [52.101.70.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 224B21922EF; Fri, 9 Aug 2024 09:46:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.70.4 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196765; cv=fail; b=e0KMFkwTarcfUPzoGYNw+Ew2B+F1IsnvcGgaarADyPvxJNDkZVdP9MEmA/Viuw4TfEucMsrRfVcL2a+dWnM3QhvkymqaOGEoI24sebL0zlL+AgoCWUFPzXWSD1oxh7osBrMucvapeiMtgbcW6k5T+YbEhPs7IYqk6JijgtgYC+E= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196765; c=relaxed/simple; bh=GgaKPoPlrHgrzHO0t8ngKmKKqPQwHU5uQ5IIBRevfgk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=ipruKcBivv0LB/6tiVCtWsXNRYJlPdgoW7SICQRekisFD0IkTBP9Di0Ne2YWo7vArY8eznWh+m0CkBSDHfEGgBpWtbizRG0+VAkAsCVbDv1LgwSHOHIGBVxtrZll+LIbq9I1QuyD1unXmblye6ptfdw4qnS2A8oZeblDTrWcRcw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=D2MR9Bnm; arc=fail smtp.client-ip=52.101.70.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="D2MR9Bnm" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=PLhf+HRudi9owxFIoXEIGbMjlw5Jo/DKg7fzxvyQrz6kkV8ZyziYNtIvWhrwVO0m2DDDqprbFqqUslOFu8N0dxa6ySIlgseQPYX1ZsWH6sQDK/a66HjyDb+J1x5Mh4UN8KPzM5TqSuSuCTjtthQpbHYR2ndcU94x65OzR9vZLjFRHzXGZveKO4CQlg00SUVB/AcWJpt6SIe92y8ragKiXiGOwee15XJhE74ygaC6BBGzCEexDHXMSSn1MtLBiZ/FXqg1iuPbenD0QKCz28ymvIvZa2pHplqrWyR//yQGLuyka2KW7o2IORWy7aItJ+52uomi0TTLu9zSbMM1kCY2sQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=/5fmHESFm0OpZJJtiuZv0GbuylV9Y2S0aS5AQa1v2Zc=; b=fD2NQe7DlRURE6rN5Ej2Ld41C2ZQiOiQxQNFZ0gIYOOQa3J9PeVVhIALtR0FCEYqey748kWDEmIviL5Xh/K9XwSlkunXdK+EBaQcnMetAL68x5Pt3hK2e1WmsnM9ZMl3zFNP2092bi8ePk1kw6dUu5KVkMfYxt6vWoM6kwBSqtNCMwh5uHHvDVhmyfutA1kODj3UDgqKuTgq8RYOLFc9D+qMaZ+ArED0YaiVr4fJGenOIrMZylTYftbAHq9XEb4D9jO24wnQk6EqjVsFUzfHwMhJh5tM6jDwvt8GcXQ2lq1YVyyeftjWp28RzAsEoKUiq5Rz2cKAxGwfvIjXta0ylw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=/5fmHESFm0OpZJJtiuZv0GbuylV9Y2S0aS5AQa1v2Zc=; b=D2MR9BnmhJ9KPPjphKxMZJOsddwu03YANic7RjdCM1pPB9p8IvjPJeH44aYn9dl77WQ94rV/KY0XfDujXd5Qs/seCXvOeecfi8vd5lfaBFpMYSnMHs6Pg2r4sa1T1349bG4IQIbcrsIcRxndPxrfjjjMhZ1sxf+1/xH45v65sEW2mP8xWVCA3g5YDa80Yr3LhLRxdYVGv2hoeY2oR2rjIjyLHFd1xwK/G1xrXoAY0Sc/PiRJrh3FROikxbmuuWimfw1qn7NufAbOFFQgJdKhTsSxoWH6tNYecVeC1HKtK3s7KBhNAEMEmq0SBEAYQ7GS0q6nve1Hq9CuABXxlltSng== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:00 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:00 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 03/43] wifi: nxpwifi: add 11h.c Date: Fri, 9 Aug 2024 17:44:53 +0800 Message-Id: <20240809094533.1660-4-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: f35bf027-12ba-46b3-58fe-08dcb858134a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: +wekley2HDAIgj83k4bEJZqD+pAhzsCw2ceOOwmc5n0MhW99ivKAGRSgJlLrlMgA8KtZvqjrCdYlBkOsa5B2/y3XjNp8388c10UTwQWL7EcS67vPO2LBaKK3FIx0/+WoiZuEumaNyAugY3gKyCDJg0cCD42hfvNwBjT1rKzTmIa82ZFAz9P2FN9JiMYT9tfnE+mk22AGyiu1q3jVovGfdEhkIRp0pNe9GJD8lPmeAG25HaAGfPI1uaxW7zR9u8wbEzgvEwQcx2uoj/0euGWFJCnBGv+E0GD95lyFCxMVZMlkb3IjMIrDdDsweSivDCsmLx/NiSQFgAm3e/s1C4ZKkZxqZoTheswPihUGrPYTJPZ8M0NVBlqQWGEtY09WEZ2ZAYmmrY3z9IQp1ttda/usHZRZJBoJfJSfh415kNg8c04XxvIqaQWkqw4pcDtK+DC3IZsEagj+MMSarzllvYPspsBMQY1QB6PA4Yyzt3qdT5ammR2smHe0aCYmn8sQrgBep1v8kg2pP1BOodho5lwimNVRCztlhiobmcCRhi36EDcktaDguNd2j6mv/4yllzd9f8Bu78t2w/q25gW4vcSjDAD8eBGoTuLvwk8OZHCwcI+CetlDXiNwVGOe7XHedvSNKYsWoax6KAzzHT+ixO/C9sbjx9ZSkmtttYYiwMsgH395agqwYjwIa14aGJ4vsH/Ssv+Qzfy7Rdeo2wt+AAxJk/hZ3IWWoB64sD4OTyyUB4nvUcGi5x/VNwh/BALv7sp7oph7BBLUQ/lsS8qw3WpnV8NpseKRIM5N3LXkmtf1mDJy45Qwgx1Cvlxd6If2zKYLjJT4aFMxpRRW8br7dm5RALWd0/62/pBJ5aKxVzKpCsMFcZQP18kFBbseBqq1EalqHwEio5SG6e1noPqFJf/2MOasBLBLuiL9ScOvy6/si4lVVLYCAN/XbftENGtRSdjVlMbTJPJ9anJAFkTTq2NPCyvvMmibfS6/T3dWuTQS8C04i2slyTPONAAUkxkolO1oTb3PjGqIYSztn+ujLwc3oaGioDIzuoNYMVnzv0otuCm9btNZbU2rC4nMOZaLduzAupwMdZu87JOUk2J30Fdm+cctvTz1FU1VvrCDxBbsYSzJcElhzf5qkwz7MCrddpFixdkdb/uskRDE4k8RvaIXpIApFnBXYkHPU7uu0xHV77xbJJ7+NblaKbTMFVt8SA520NkZPWWurawMDiH1kvm4geJooRwKhJekBkfP9CZp/BPJu/tD038sPgXy/Egw6Xe1qOJ6Q5vZ4ppXahrejXo/Nj0JRwOtGW55leSlBVJ5dI/5RxgVWrNssh79ckrgLO8I9q5KlLEKUZRgZ1YpfinC1g== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: nEUayJID/jcznK//dQOtXx8a/D9Ah/wuks6HJLM+4gQKP+RiG0SeS9Gmh6TjR7sL0CStZ7OX8X2P0NrPQEttH+GnkZimq1NR9GBgAgWBdhMgj+pa+KMNCL8RJphp6XeBZG3TOxpq38Mcdi7s8iXYatBokJqW/wgQ22GfD+QHnwT0toiHWRMcl9WWthNUwA88u4slG39MkPKMSSwN5kVbhLVcN7ww3EsaSmZT2I8KqxNm41yVKddQRupnGb73UmkToOiakvZbqZeaCrDo5yuEVEfMtlhXV0woYZwDibaOZImU9YQPZkdwvii0pX1D4I+1ZXBIJsba0ysIPi204piJa7yd17q6eOg20jQe0BjvWHZFaQYcpQcwCaQrZvf6y9CSvEqwljGgzEgz/Pnu3Z6fXHL80u5HNRvVyTcFrddJgh8usS3BRVuBh8c+16RFcO/YXK77jhxxyP9n1RUFayAFZ/XrqwMbYeoXdAuNTS5CCQmBW7mIHLeVon5FoVbBLeegPBQqOqEPs1/jHTXDR9Mw2W/BiraqjV/dI1rC5MQ8FK7eTwFtcusZTe/VFAiOcgl3+R6pXYXkcmbsmXfLFsQgIcpBfCT5MvfHFk+k3hx0xf32KBmQYgrOorM9CtQgQv3CSCW8EE7U9SsLZW18IIBFCKy1gC4a+jbu+/RvXwre1Wm8DL2qKqFzw4D3K3DwcppzG0P127ku9li1xgqKkDdHZw8bBFn4OfXFnEpT+8eP4V3M905wFxnoowi3VNDR2YpgyRCeDihkDk94PAZlLAES6xBDGYaT9UAtiS6GFim5HG273c2AUyFTpNmutIv0U1sFnPICA81wVFjvUhsqCvXpKinAVTicwwN/2MkcCGS38HuiP1/y+IKrJw2jOAAQvpMezes5Zf1tnl0Pg5aYyCQNxA+sjPyjkeH5CheCK/I68Z50M93Nqko7MjQcAk8V39qJTDt/Z91LycNaRNpntcgbnTcJgaOFDYzAn4UyrG9ZIpTMdMuBB1RxlG7L72LzQSa3jzy+Jg9hFOOR7S7nxYwIRyMVfB85qbn0cTC6ONYh6h7yoc32yvCMzsPRhmkoeKkkjmlNzgzsLmL3c1qvPMRWuSQkq+gebVlPTo30hvz+Ib4pjggtDZ4cMHm90cnD0zY+OHegbxNBQoFfcILmIW+zMjTAp/wxpKHqVjE8Fz8yRLVU6fMERBUxeV5hwm4KDM4LZhejpFfxWk08euG/Z8MRELd51AbVou20oVs1ojeZkltGfLEzuGEx1R2nyViyDVEU1//8q3ybhG1sxR4QHcSBmspDOYTEMRPRMqLxYMTsJDkRV4eIZtUk9kv+EsHvllZfCfRGqTrA1w2BS5btIuT06kejIuvYUbDd31DnN5p5comOrouKvWGIGeSv17g7orAyP5AqNIYqarmHaN9BygI1ag3tU1zClnnGVFBsBeGkz1REDIAhYoA5hGrF8kLkQ5I0a3tft1p8m3vMDaEGJUoFKMIjVoklfkv9xAKVAW34ANqp0ilg6oegnx4zHwSwv875nKNdndmb4ElHUAfm89we49R5tN8ixTO02Md+WKM1QvDtCQuEY3xlleRXsuor1OKZD1QQQTu+VfhU2yWn3vhPBLtMbUvzuX7MwVC1mrfxvzXKpZGKocWyu9etsjmBDyC1 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: f35bf027-12ba-46b3-58fe-08dcb858134a X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:00.3841 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: EDyNeJI9S7luREuMhNo+w9jdyI8AROQLEaMUV6c706M/VhswzKKu1X4YvUNYEbFKFglSJ2GyAymkCvd6ZHCJhw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/11h.c | 433 +++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/11h.c diff --git a/drivers/net/wireless/nxp/nxpwifi/11h.c b/drivers/net/wireless/nxp/nxpwifi/11h.c new file mode 100644 index 000000000000..b8f41b304510 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/11h.c @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: 802.11h + * + * Copyright 2011-2024 NXP + */ + +#include "main.h" +#include "cmdevt.h" +#include "fw.h" +#include "cfg80211.h" + +void nxpwifi_init_11h_params(struct nxpwifi_private *priv) +{ + priv->state_11h.is_11h_enabled = true; + priv->state_11h.is_11h_active = false; +} + +inline int nxpwifi_is_11h_active(struct nxpwifi_private *priv) +{ + return priv->state_11h.is_11h_active; +} + +/* This function appends 11h info to a buffer while joining an + * infrastructure BSS + */ +static void +nxpwifi_11h_process_infra_join(struct nxpwifi_private *priv, u8 **buffer, + struct nxpwifi_bssdescriptor *bss_desc) +{ + struct nxpwifi_ie_types_header *ie_header; + struct nxpwifi_ie_types_pwr_capability *cap; + struct nxpwifi_ie_types_local_pwr_constraint *constraint; + struct ieee80211_supported_band *sband; + u8 radio_type; + int i; + + if (!buffer || !(*buffer)) + return; + + radio_type = nxpwifi_band_to_radio_type((u8)bss_desc->bss_band); + sband = priv->wdev.wiphy->bands[radio_type]; + + cap = (struct nxpwifi_ie_types_pwr_capability *)*buffer; + cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY); + cap->header.len = cpu_to_le16(2); + cap->min_pwr = 0; + cap->max_pwr = 0; + *buffer += sizeof(*cap); + + constraint = (struct nxpwifi_ie_types_local_pwr_constraint *)*buffer; + constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT); + constraint->header.len = cpu_to_le16(2); + constraint->chan = bss_desc->channel; + constraint->constraint = bss_desc->local_constraint; + *buffer += sizeof(*constraint); + + ie_header = (struct nxpwifi_ie_types_header *)*buffer; + ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); + ie_header->len = cpu_to_le16(2 * sband->n_channels + 2); + *buffer += sizeof(*ie_header); + *(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS; + *(*buffer)++ = 2 * sband->n_channels; + for (i = 0; i < sband->n_channels; i++) { + u32 center_freq; + + center_freq = sband->channels[i].center_freq; + *(*buffer)++ = ieee80211_frequency_to_channel(center_freq); + *(*buffer)++ = 1; /* one channel in the subband */ + } +} + +/* Enable or disable the 11h extensions in the firmware */ +int nxpwifi_11h_activate(struct nxpwifi_private *priv, bool flag) +{ + u32 enable = flag; + + /* enable master mode radar detection on AP interface */ + if ((GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) && enable) + enable |= NXPWIFI_MASTER_RADAR_DET_MASK; + + return nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB, + HOST_ACT_GEN_SET, DOT11H_I, &enable, true); +} + +/* This functions processes TLV buffer for a pending BSS Join command. + * + * Activate 11h functionality in the firmware if the spectrum management + * capability bit is found in the network we are joining. Also, necessary + * TLVs are set based on requested network's 11h capability. + */ +void nxpwifi_11h_process_join(struct nxpwifi_private *priv, u8 **buffer, + struct nxpwifi_bssdescriptor *bss_desc) +{ + if (bss_desc->sensed_11h) { + /* Activate 11h functions in firmware, turns on capability + * bit + */ + nxpwifi_11h_activate(priv, true); + priv->state_11h.is_11h_active = true; + bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT; + nxpwifi_11h_process_infra_join(priv, buffer, bss_desc); + } else { + /* Deactivate 11h functions in the firmware */ + nxpwifi_11h_activate(priv, false); + priv->state_11h.is_11h_active = false; + bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT; + } +} + +/* This is DFS CAC work function. + * This delayed work emits CAC finished event for cfg80211 if + * CAC was started earlier. + */ +void nxpwifi_dfs_cac_work(struct work_struct *work) +{ + struct cfg80211_chan_def chandef; + struct delayed_work *delayed_work = to_delayed_work(work); + struct nxpwifi_private *priv = container_of(delayed_work, + struct nxpwifi_private, + dfs_cac_work); + + chandef = priv->dfs_chandef; + if (priv->wdev.cac_started) { + nxpwifi_dbg(priv->adapter, MSG, + "CAC timer finished; No radar detected\n"); + cfg80211_cac_event(priv->netdev, &chandef, + NL80211_RADAR_CAC_FINISHED, + GFP_KERNEL); + } +} + +static u8 nxpwifi_get_channel_2_offset(int chan) +{ + u8 chan2_offset = SEC_CHAN_NONE; + + switch (chan) { + case 36: + case 44: + case 52: + case 60: + case 100: + case 108: + case 116: + case 124: + case 132: + case 140: + case 149: + case 157: + case 165: + case 173: + chan2_offset = SEC_CHAN_ABOVE; + break; + case 40: + case 48: + case 56: + case 64: + case 104: + case 112: + case 120: + case 128: + case 136: + case 144: + case 153: + case 161: + case 169: + case 177: + chan2_offset = SEC_CHAN_BELOW; + break; + } + + return chan2_offset; +} + +static void nxpwifi_convert_chan_to_band_cfg(u8 *band_cfg, + struct cfg80211_chan_def *chan_def) +{ + u8 chan_band = 0, chan_width = 0, chan2_offset = 0; + + switch (chan_def->chan->band) { + case NL80211_BAND_2GHZ: + chan_band = BAND_2GHZ; + break; + case NL80211_BAND_5GHZ: + chan_band = BAND_5GHZ; + break; + default: + break; + } + + switch (chan_def->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + chan_width = CHAN_BW_20MHZ; + break; + case NL80211_CHAN_WIDTH_40: + chan_width = CHAN_BW_40MHZ; + if (chan_def->center_freq1 > chan_def->chan->center_freq) + chan2_offset = SEC_CHAN_ABOVE; + else + chan2_offset = SEC_CHAN_BELOW; + break; + case NL80211_CHAN_WIDTH_80: + chan2_offset = + nxpwifi_get_channel_2_offset(chan_def->chan->hw_value); + chan_width = CHAN_BW_80MHZ; + break; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + default: + break; + } + + *band_cfg = ((chan2_offset << BAND_CFG_CHAN2_SHIFT_BIT) & + BAND_CFG_CHAN2_OFFSET_MASK) | + ((chan_width << BAND_CFG_CHAN_WIDTH_SHIFT_BIT) & + BAND_CFG_CHAN_WIDTH_MASK) | + ((chan_band << BAND_CFG_CHAN_BAND_SHIFT_BIT) & + BAND_CFG_CHAN_BAND_MASK); +} + +/* This function prepares channel report request command to FW for + * starting radar detection. + */ +int nxpwifi_cmd_issue_chan_report_request(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req; + struct nxpwifi_radar_params *radar_params = (void *)data_buf; + u16 size; + + cmd->command = cpu_to_le16(HOST_CMD_CHAN_REPORT_REQUEST); + size = S_DS_GEN; + + cr_req->chan_desc.start_freq = cpu_to_le16(NXPWIFI_A_BAND_START_FREQ); + nxpwifi_convert_chan_to_band_cfg(&cr_req->chan_desc.band_cfg, + radar_params->chandef); + cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value; + cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms); + size += sizeof(*cr_req); + + if (radar_params->cac_time_ms) { + struct nxpwifi_ie_types_chan_rpt_data *rpt; + + rpt = (struct nxpwifi_ie_types_chan_rpt_data *)((u8 *)cmd + size); + rpt->header.type = cpu_to_le16(TLV_TYPE_CHANRPT_11H_BASIC); + rpt->header.len = cpu_to_le16(sizeof(u8)); + rpt->meas_rpt_map = 1 << MEAS_RPT_MAP_RADAR_SHIFT_BIT; + size += sizeof(*rpt); + + nxpwifi_dbg(priv->adapter, MSG, + "11h: issuing DFS Radar check for channel=%d\n", + radar_params->chandef->chan->hw_value); + } else { + nxpwifi_dbg(priv->adapter, MSG, "cancelling CAC\n"); + } + + cmd->size = cpu_to_le16(size); + + return 0; +} + +int nxpwifi_stop_radar_detection(struct nxpwifi_private *priv, + struct cfg80211_chan_def *chandef) +{ + struct nxpwifi_radar_params radar_params; + + memset(&radar_params, 0, sizeof(struct nxpwifi_radar_params)); + radar_params.chandef = chandef; + radar_params.cac_time_ms = 0; + + return nxpwifi_send_cmd(priv, HOST_CMD_CHAN_REPORT_REQUEST, + HOST_ACT_GEN_SET, 0, &radar_params, true); +} + +/* This function is to abort ongoing CAC upon stopping AP operations + * or during unload. + */ +void nxpwifi_abort_cac(struct nxpwifi_private *priv) +{ + if (priv->wdev.cac_started) { + if (nxpwifi_stop_radar_detection(priv, &priv->dfs_chandef)) + nxpwifi_dbg(priv->adapter, ERROR, + "failed to stop CAC in FW\n"); + nxpwifi_dbg(priv->adapter, MSG, + "Aborting delayed work for CAC.\n"); + cancel_delayed_work_sync(&priv->dfs_cac_work); + cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); + } +} + +/* This function handles channel report event from FW during CAC period. + * If radar is detected during CAC, driver indicates the same to cfg80211 + * and also cancels ongoing delayed work. + */ +int nxpwifi_11h_handle_chanrpt_ready(struct nxpwifi_private *priv, + struct sk_buff *skb) +{ + struct host_cmd_ds_chan_rpt_event *rpt_event; + struct nxpwifi_ie_types_chan_rpt_data *rpt; + u16 event_len, tlv_len; + + rpt_event = (void *)(skb->data + sizeof(u32)); + event_len = skb->len - (sizeof(struct host_cmd_ds_chan_rpt_event) + + sizeof(u32)); + + if (le32_to_cpu(rpt_event->result) != HOST_RESULT_OK) { + nxpwifi_dbg(priv->adapter, ERROR, + "Error in channel report event\n"); + return -EINVAL; + } + + while (event_len >= sizeof(struct nxpwifi_ie_types_header)) { + rpt = (void *)&rpt_event->tlvbuf; + tlv_len = le16_to_cpu(rpt->header.len); + + switch (le16_to_cpu(rpt->header.type)) { + case TLV_TYPE_CHANRPT_11H_BASIC: + if (rpt->meas_rpt_map & MEAS_RPT_MAP_RADAR_MASK) { + nxpwifi_dbg(priv->adapter, MSG, + "RADAR Detected on channel %d!\n", + priv->dfs_chandef.chan->hw_value); + cancel_delayed_work_sync(&priv->dfs_cac_work); + cfg80211_cac_event(priv->netdev, + &priv->dfs_chandef, + NL80211_RADAR_CAC_ABORTED, + GFP_KERNEL); + cfg80211_radar_event(priv->adapter->wiphy, + &priv->dfs_chandef, + GFP_KERNEL); + } + break; + default: + break; + } + + event_len -= (tlv_len + sizeof(rpt->header)); + } + + return 0; +} + +/* Handler for radar detected event from FW.*/ +int nxpwifi_11h_handle_radar_detected(struct nxpwifi_private *priv, + struct sk_buff *skb) +{ + struct nxpwifi_radar_det_event *rdr_event; + + rdr_event = (void *)(skb->data + sizeof(u32)); + + nxpwifi_dbg(priv->adapter, MSG, + "radar detected; indicating kernel\n"); + if (priv->wdev.cac_started) { + if (nxpwifi_stop_radar_detection(priv, &priv->dfs_chandef)) + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to stop CAC in FW\n"); + cancel_delayed_work_sync(&priv->dfs_cac_work); + cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); + } + cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef, + GFP_KERNEL); + nxpwifi_dbg(priv->adapter, MSG, "regdomain: %d\n", + rdr_event->reg_domain); + nxpwifi_dbg(priv->adapter, MSG, "radar detection type: %d\n", + rdr_event->det_type); + + return 0; +} + +/* This is work function for channel switch handling. + * This function takes care of updating new channel definitin to + * bss config structure, restart AP and indicate channel switch success + * to cfg80211. + */ +void nxpwifi_dfs_chan_sw_work(struct work_struct *work) +{ + struct nxpwifi_uap_bss_param *bss_cfg; + struct delayed_work *delayed_work = to_delayed_work(work); + struct nxpwifi_private *priv = container_of(delayed_work, + struct nxpwifi_private, + dfs_chan_sw_work); + struct nxpwifi_adapter *adapter = priv->adapter; + + if (nxpwifi_del_mgmt_ies(priv)) + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to delete mgmt IEs!\n"); + + bss_cfg = &priv->bss_cfg; + if (!bss_cfg->beacon_period) { + nxpwifi_dbg(adapter, ERROR, + "channel switch: AP already stopped\n"); + return; + } + + if (nxpwifi_send_cmd(priv, HOST_CMD_UAP_BSS_STOP, + HOST_ACT_GEN_SET, 0, NULL, true)) { + nxpwifi_dbg(adapter, ERROR, + "channel switch: Failed to stop the BSS\n"); + return; + } + + if (nxpwifi_cfg80211_change_beacon_data(adapter->wiphy, + priv->netdev, + &priv->beacon_after)) { + nxpwifi_dbg(adapter, ERROR, + "channel switch: Failed to set beacon\n"); + return; + } + + nxpwifi_uap_set_channel(priv, bss_cfg, priv->dfs_chandef); + + if (nxpwifi_config_start_uap(priv, bss_cfg)) { + nxpwifi_dbg(adapter, ERROR, + "Failed to start AP after channel switch\n"); + return; + } + + nxpwifi_dbg(adapter, MSG, + "indicating channel switch completion to kernel\n"); + wiphy_lock(priv->wdev.wiphy); + cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0); + wiphy_unlock(priv->wdev.wiphy); + + if (priv->uap_stop_tx) { + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + nxpwifi_wake_up_net_dev_queue(priv->netdev, adapter); + priv->uap_stop_tx = false; + } +} From patchwork Fri Aug 9 09:44:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818397 Received: from AS8PR04CU009.outbound.protection.outlook.com (mail-westeuropeazon11011004.outbound.protection.outlook.com [52.101.70.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E6E9D192B74; Fri, 9 Aug 2024 09:46:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.70.4 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196768; cv=fail; b=QJJkNC71ieI0YOELEpfnqEcg6A1aytjosEwYBfLhx+s+uSQZrkcLEWcPDvA3fy/OwCCf5TQehMpZ1OhVv5BIbCSNqwNs4AilQAqiw1hgjtg1XRT6hCuwUounrbJnagPp7B67b1UFRdHxgbw2xjKntO5CPxGzVk014O38tRwuLek= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196768; c=relaxed/simple; bh=7P/LnuSYSLdNtiA2kaRD2ylmDoBGn0TwKl7rF6BuZGA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=nf7LwmI4cOxrwaq809KFnXq7sBj0AnnQAqgOa8G8kG0f5gNykrTwukrxewo7NakajkLvJX1+bUH09Xm6KPG3kwGrRxJeCapPQVNTcB8IEE0m/pFcpO9mbhXl27IC+ZhwE9BZ7CL5/S0u6QmjWaVNSbbjRWMcncZiVF2HwD5Bpdc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=NKJINOM1; arc=fail smtp.client-ip=52.101.70.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="NKJINOM1" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Yj5QNB9Z6n9nCZ2hTQb+NVeiymN/X7tTAJa5VCD82ypyMBSSNzlvnEoA1oVRfw94tlhtKnsJp60V/c3spsMYWHpGgvnBWwgsrcMZnll3iwAywbtUt5tBbXE6EPuNJH0bffWFqbfIgyJ6kIXSkqeqanAiWfEKpAt3ilp72ANEeP+jmvtfpFtfUSrTbKoNTzQOrU5dzLnvhpri4RDqUMstkYm+sXhYOq3WfvCUFhMoicl1lHUELW7M0Bd1X44CYYXaUAaZzUJ/zIKoggUybd4pqSCW85Om+ENZ0dqgkeVZ0Fj4qd33k+g1zOTHMvIqAwddx8649PQHrwuRXYolh5lsJw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=x8/p8snz+4NkzgjaCyakojmj4QeDZLgn/yHswc5j4zE=; b=nIYFPr3cCjlHxOF2iLdrnH1f01USJkXZLfv1YnmWbO9E3Okly7qvo7hkY+bm5gKYKr21SLPaGK9EYZAvLGq4wweb6I9knpPBSwBemM7gcKqm0BrjF1ma7LvjawcevWgqUNrcnbk4Ub1OAVboMTe5lOmER7zxBxy3pDwn87DOfdO887WCZwp9QhjLL6zI2NT9S6eOnKDuBbcRAH8GQlZv6ZG58rhBFtktx0Gqpe2aojxoMtLSBzg2jYcGXv8QulTx9y/GaStIooNVcbb+RlELGYePB+X2iv0QBDqAm58xjrF2CuE00ZY/bwbcaKuk52WxtwrUy/c3UdcJw8zlrX0v1g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=x8/p8snz+4NkzgjaCyakojmj4QeDZLgn/yHswc5j4zE=; b=NKJINOM1H9a3jzTkGTlsX8hKodUvFe1qte6kcbgcMZToAUfijWXP17RBqnbwHePevyWiRPKFyr8fvPyX6d1u/XYwKHt5v6o+f0WQqtQC3Ibv/w9gSNQLst+v4wraJG0Q2SWoQxOCr/4niexAs5HBVSO07pW1jjxrL3PpvrzMFqOVoGrR4aLaxiYj48gyloh7ZHo+4kbirTKdW/HQcemAFHOo3TIxs4niXoogHuG0KGe2SdkABQaqagrUbkfIcq2Zni2Trd7z7n/s4dLCrhEH1UdpbUgloC+YhNj+ehhSwXhRAqTlh2nhI4kOCFfsI69MaXh31pFIuvubP0XMrUNI/g== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:03 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:03 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 04/43] wifi: nxpwifi: add 11n_aggr.c Date: Fri, 9 Aug 2024 17:44:54 +0800 Message-Id: <20240809094533.1660-5-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: ce9899f8-fea8-4b6c-f4ed-08dcb858155e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: QnxDJsNTaR0E0KfCnx4NREDrx2G7lhQiJdM5WdC/5RpLm0GaUYVtekP9MROWw1NL7TfZxWhwSLCPVWB2oI6nwP1EBXRB6Ae22w/lraXqCLvzlwvd5jzHaj+GZ+5Ayj1VOO3kphEzpM+I2wiuEAf9DhpVFbuoh76vy2nLlzu1uhtqH2Tskcd4o7AD5/SN9MDTGhOsen0sqMm+mSf5xiSWlR14wtmsOqjuOaxyGyGnwiVujhOpnI7iBr3g8MwdKvtSzYL2C4cq9h4q1fDRuqLn9S5KD6KaNIw08bvkK2jkaigH6vrYuznchI4hFyh25vVbgM/itahUXPL/+gX4ROqRwc8NAhQvXPCSL+4qkEcHVEXXvtf4fUP2WfK0K3DgbS2m8Y4waMTAddfdjY/Ro/ojSIXjD9Bx/RImiTH/1wr4uLlEt7F7qUBOGv80BsNZ+61WlgEvvvIuvr7WyCpK8zZFmn9yISsaoCWxJtVux+ZeK52vpnUGsCrWKTChy4QYfXtv6fwRfj307F5fdg6Ff1EOA1B3aG8vLqJi2ZxAZJpFc0mns/2wH7955qEE0hYT4EiAIevf9gdj26sb/CRX4t0tc1xE0DohQCQuGxouZ5jUUN9f0L48UgZv4OPiPo/mpOVktcklMriVhD//f9s7pcwai9fiVevFKsz/bEq6ACu/QMo18YX6V/qaL5Ur6R56XB7PblcQgNCgYV2S78wrprdtNyhvQkj8q3UjVb9oP+8xEEcIydSYLJQu7kMeZl4pg8TdGkBC80vofVsY+8Is3E/JJc08Yc7kwiKepOvwdXGqcyvcVKcWFOE4FC+qh08K70R9iq6qoVyDrSIi2f5SmV0qKWx7/iRSA6KNidd4RxZr7oDs7I4YpAJLOmWC/Xmjl2+vMej0y9SKW3n7aWkCjDaUbHwGpLDN1aCp/qSUVa8M7LTQgChfDslr7GpLgC8Yz7kCox/DFY2NWU29fm5W0zw3RO/TQZh+kdd+luYrlyHIt+Edtekwcy2E+CL7cMbE4ST/1Fw+v6YeDGZTbsLwsIhTSVNmjQAc9a96kI/RjNPIM70oJvBn9Oj9dkBbIfNmsAy2zpRPpcSG/AKqWmUuNfpeFjlq3vPt/zY9hlu/Eo2hocSjDAmeXDGU6jmEzVCBV4C+5sMjZDb0mJbO449FSDjkJBHR1A5rxvq+HkLwiEpNHulXNdCa5/A/VKICMMdxz2LHQYXyiUzd77FE4qOTelTAwCT2tG3vyff4BLqlqtLOHkJuug9gGxPcpjggQkLNuWXCHER1yRlECY0fW7i8pg+NW/bRtW7bRj4+Gyd0n87OR517c1jBp4VVLSDRmfmbI002by9a8oYGd9KoLP/NpF3VzA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: Pme9FG2rqvXDKVH/Z/vN820uMXkFJm73VuzQOSUJlZ6RSxl+gtaSS2Zqxgi3KhMISKGxIfHv7b2SBq1lukPokOgbx6lTFW7zYjHqbYJXnEpsUMR7Q09379AwQXxWHeUGIpmW0Rml3jIswjo509zY7oBFGMuaMt76Jrt/sJQ1YGgTJuTFmpEzCCY74DZpADkOzohiDG9ciqiMYeq2u73stBXDH0NpeiFu2yBJj2RFpqM667Rmk5lG2OxGJUM+iIOu/tl4EuzqHK0pzmXPbTmoQBo5NXYqygVKDehrg+twJVojKfzii0LfN8UZoaDisBmQl4t4G2Ac0ul6dvaQi5YqHpGAfAEb8mncx+YBIw647gyO6++R/0K8GkXUDTSm10oSHiL/Ek7Mo/CgGS5fco1r/KfTQDP39DtO/csAWWzgRjNAPmgn6Ec+mvo4MhpfY5cyw4ZZWL5ZsknHDVcwjFp5KZstWCPrNt4/BRSnl7CcSA2FQ9cc4FCFdIFvE7/rro0eEr0R09czp4yJiq2ASD8WxUO6hyv+6wETwFKglw06ej0dKSV2pscemk7dzMVntXxVgCFprwdIwZnuIDQjh+7U+Kft9F7GfsTEXFmKYyRjMChOgiW7UpPcvQnRCtj+3GL0GTI7MMCN2qpydMy7DjiAlde2PwDWwPzIT31WdC4j63qsmZvqh/aGCCjDB7pNZsMCjTmXWvO6e3DuxtGolYz2HmLNwG3e7Dnt10Z9FKMsBtB2J2QHh66yD2aja9kiWZ5bI8gUHSUGBwsBFZlaSu8C37gWm5yo8qRMS7DG8WMxVqQMQE2ZfNrgMN/cBYikLa3z/bPwq4jKKzn1AzyZEU2rqmb1OW1pF5owxNbA2sUeccrRPQvfR5tkqPSU/RBP+3YeNc/vGpcr91afbuhsyjU6mKzF64tmMKnOb+2aDhUH3HDLlt385j/khuGmFQzAuCI1pkZIqD4ttMH/vLRnQsman14vZb3h81Fo70SUQvSoss/qbC8p07Z4VVjx1BnPL7mir5nNiIcjiYAz9FTuoPp71gtTDBPzy7fQ7E39Yx73O0DFczo+T9EcLcCdaTgu2w1vX9CXReQI7jsV6+35y4yjoDj2a9besaut/2RrxSE4ElIoaCXw2jYZBC7mIyR3+le2DCnC1kyKc/8ZONoWhXlSjukoXDnpMsrLi3AVUq8hFalyp/YDOzEZ7KFLnytaGBR7GUu9akcl3If9goSw16bdLPVXv1sEZOKJ6fExB2tgeaE3Iu1EyEBAZXL7zOaERLwaErI3EV+9uh5lc5vYPKPyQtefqCRcIwM+FT9Q2VDaOSmGhY3v1DwUJRsewHG6aGozQFICYI/1mrcfQYrdPXKtI9tUIY0XAZ9eq+vWxvOLUofOt6BDv9QS3OMZvuMnvjD8t5+5U7oJODC8HMAsJENX/M2FS5jAUw5CjRS6LVu/YaHypU2ucNcF7zGNfuwnSTOIrqPcPXJtfvpi+ZKStRhsQ7aiZC5dg/4Cfl5jmZm7F0LUvthl6AyCpPYsCKd9l2UoIGvLq/PKMaURV0gEUSAwKSJPOqDRZPmAbTr3mLbjyKZR2SIjFjHRDbEJmyOluDy5K2NUqOm4FjIGUff04bPHXJ2tHd+ahqM4hykm/VLgscLGcOCTwqGD7BDhAjAKyv+M X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: ce9899f8-fea8-4b6c-f4ed-08dcb858155e X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:03.6329 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: X6Y3Wy+bVr1pLwEVdHnfyaymPcaKKxqK/8cs6F51JmbBdGITD9GZy5XfwFlb4w4mjslI1kXo4nksfnea9n2OOQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/11n_aggr.c | 276 ++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/11n_aggr.c diff --git a/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c b/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c new file mode 100644 index 000000000000..85ea840e6e91 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: 802.11n Aggregation + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "11n_aggr.h" + +/* Creates an AMSDU subframe for aggregation into one AMSDU packet. + * + * The resultant AMSDU subframe format is - + * + * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ + * | DA | SA | Length | SNAP header | MSDU | + * | data[0..5] | data[6..11] | | | data[14..] | + * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ + * <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes--> + * + * This function also computes the amount of padding required to make the + * buffer length multiple of 4 bytes. + * + * Data => |DA|SA|SNAP-TYPE|........ .| + * MSDU => |DA|SA|Length|SNAP|...... ..| + */ +static int +nxpwifi_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, + struct sk_buff *skb_src, int *pad) + +{ + int dt_offset; + struct rfc_1042_hdr snap = { + 0xaa, /* LLC DSAP */ + 0xaa, /* LLC SSAP */ + 0x03, /* LLC CTRL */ + {0x00, 0x00, 0x00}, /* SNAP OUI */ + 0x0000 /* SNAP type */ + /* This field will be overwritten + * later with ethertype + */ + }; + struct tx_packet_hdr *tx_header; + + tx_header = skb_put(skb_aggr, sizeof(*tx_header)); + + /* Copy DA and SA */ + dt_offset = 2 * ETH_ALEN; + memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset); + + /* Copy SNAP header */ + snap.snap_type = ((struct ethhdr *)skb_src->data)->h_proto; + + dt_offset += sizeof(__be16); + + memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr)); + + skb_pull(skb_src, dt_offset); + + /* Update Length field */ + tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN); + + /* Add payload */ + skb_put_data(skb_aggr, skb_src->data, skb_src->len); + + /* Add padding for new MSDU to start from 4 byte boundary */ + *pad = (4 - ((unsigned long)skb_aggr->tail & 0x3)) % 4; + + return skb_aggr->len + *pad; +} + +/* Adds TxPD to AMSDU header. + * + * Each AMSDU packet will contain one TxPD at the beginning, + * followed by multiple AMSDU subframes. + */ +static void +nxpwifi_11n_form_amsdu_txpd(struct nxpwifi_private *priv, + struct sk_buff *skb) +{ + struct txpd *local_tx_pd; + + skb_push(skb, sizeof(*local_tx_pd)); + + local_tx_pd = (struct txpd *)skb->data; + memset(local_tx_pd, 0, sizeof(struct txpd)); + + /* Original priority has been overwritten */ + local_tx_pd->priority = (u8)skb->priority; + local_tx_pd->pkt_delay_2ms = + nxpwifi_wmm_compute_drv_pkt_delay(priv, skb); + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + /* Always zero as the data is followed by struct txpd */ + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); + local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - + sizeof(*local_tx_pd)); + + if (local_tx_pd->tx_control == 0) + /* TxCtrl set by user or default */ + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA && + priv->adapter->pps_uapsd_mode) { + if (nxpwifi_check_last_packet_indication(priv)) { + priv->adapter->tx_lock_flag = true; + local_tx_pd->flags = + NXPWIFI_TxPD_POWER_MGMT_LAST_PACKET; + } + } +} + +/* Create aggregated packet. + * + * This function creates an aggregated MSDU packet, by combining buffers + * from the RA list. Each individual buffer is encapsulated as an AMSDU + * subframe and all such subframes are concatenated together to form the + * AMSDU packet. + * + * A TxPD is also added to the front of the resultant AMSDU packets for + * transmission. The resultant packets format is - + * + * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+ + * | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame| + * | | 1 | 2 | .. | n | + * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+ + */ +int +nxpwifi_11n_aggregate_pkt(struct nxpwifi_private *priv, + struct nxpwifi_ra_list_tbl *pra_list, + int ptrindex) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct sk_buff *skb_aggr, *skb_src; + struct nxpwifi_txinfo *tx_info_aggr, *tx_info_src; + int pad = 0, aggr_num = 0, ret; + struct nxpwifi_tx_param tx_param; + struct txpd *ptx_pd = NULL; + int headroom = adapter->intf_hdr_len; + + skb_src = skb_peek(&pra_list->skb_head); + if (!skb_src) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); + return 0; + } + + tx_info_src = NXPWIFI_SKB_TXCB(skb_src); + skb_aggr = nxpwifi_alloc_dma_align_buf(adapter->tx_buf_size, + GFP_ATOMIC); + if (!skb_aggr) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); + return -ENOMEM; + } + + /* skb_aggr->data already 64 byte align, just reserve bus interface + * header and txpd. + */ + skb_reserve(skb_aggr, headroom + sizeof(struct txpd)); + tx_info_aggr = NXPWIFI_SKB_TXCB(skb_aggr); + + memset(tx_info_aggr, 0, sizeof(*tx_info_aggr)); + tx_info_aggr->bss_type = tx_info_src->bss_type; + tx_info_aggr->bss_num = tx_info_src->bss_num; + + tx_info_aggr->flags |= NXPWIFI_BUF_FLAG_AGGR_PKT; + skb_aggr->priority = skb_src->priority; + skb_aggr->tstamp = skb_src->tstamp; + + do { + /* Check if AMSDU can accommodate this MSDU */ + if ((skb_aggr->len + skb_src->len + LLC_SNAP_LEN) > + adapter->tx_buf_size) + break; + + skb_src = skb_dequeue(&pra_list->skb_head); + pra_list->total_pkt_count--; + atomic_dec(&priv->wmm.tx_pkts_queued); + aggr_num++; + spin_unlock_bh(&priv->wmm.ra_list_spinlock); + nxpwifi_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad); + + nxpwifi_write_data_complete(adapter, skb_src, 0, 0); + + spin_lock_bh(&priv->wmm.ra_list_spinlock); + + if (!nxpwifi_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); + return -ENOENT; + } + + if (skb_tailroom(skb_aggr) < pad) { + pad = 0; + break; + } + skb_put(skb_aggr, pad); + + skb_src = skb_peek(&pra_list->skb_head); + + } while (skb_src); + + spin_unlock_bh(&priv->wmm.ra_list_spinlock); + + /* Last AMSDU packet does not need padding */ + skb_trim(skb_aggr, skb_aggr->len - pad); + + /* Form AMSDU */ + nxpwifi_11n_form_amsdu_txpd(priv, skb_aggr); + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA) + ptx_pd = (struct txpd *)skb_aggr->data; + + skb_push(skb_aggr, headroom); + tx_info_aggr->aggr_num = aggr_num * 2; + if (adapter->data_sent || adapter->tx_lock_flag) { + atomic_add(aggr_num * 2, &adapter->tx_queued); + skb_queue_tail(&adapter->tx_data_q, skb_aggr); + return 0; + } + + if (skb_src) + tx_param.next_pkt_len = skb_src->len + sizeof(struct txpd); + else + tx_param.next_pkt_len = 0; + + ret = adapter->if_ops.host_to_card(adapter, NXPWIFI_TYPE_DATA, + skb_aggr, &tx_param); + + switch (ret) { + case -EBUSY: + spin_lock_bh(&priv->wmm.ra_list_spinlock); + if (!nxpwifi_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); + nxpwifi_write_data_complete(adapter, skb_aggr, 1, -1); + return -EINVAL; + } + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA && + adapter->pps_uapsd_mode && adapter->tx_lock_flag) { + priv->adapter->tx_lock_flag = false; + if (ptx_pd) + ptx_pd->flags = 0; + } + + skb_queue_tail(&pra_list->skb_head, skb_aggr); + + pra_list->total_pkt_count++; + + atomic_inc(&priv->wmm.tx_pkts_queued); + + tx_info_aggr->flags |= NXPWIFI_BUF_FLAG_REQUEUED_PKT; + spin_unlock_bh(&priv->wmm.ra_list_spinlock); + nxpwifi_dbg(adapter, ERROR, "data: -EBUSY is returned\n"); + break; + case -EINPROGRESS: + break; + case 0: + nxpwifi_write_data_complete(adapter, skb_aggr, 1, ret); + break; + default: + nxpwifi_dbg(adapter, ERROR, "%s: host_to_card failed: %#x\n", + __func__, ret); + adapter->dbg.num_tx_host_to_card_failure++; + nxpwifi_write_data_complete(adapter, skb_aggr, 1, ret); + break; + } + if (ret != -EBUSY) + nxpwifi_rotate_priolists(priv, pra_list, ptrindex); + + return 0; +} From patchwork Fri Aug 9 09:44:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818282 Received: from AM0PR83CU005.outbound.protection.outlook.com (mail-westeuropeazon11010012.outbound.protection.outlook.com [52.101.69.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6AE67193073; Fri, 9 Aug 2024 09:46:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.69.12 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196772; cv=fail; b=WL/dOZfzm2W9J9IdV7KKSDPi1bEXlRNdbpfe+p4b0+pZUXHVSq1Rn8Y7h0WmBfIoaF6Oy42dMVtX9gfelkDzay+Zo/VGq34thsXmNzdyfWZRdKl6xgKp+DrCL2poskALJi3mK8Zfb4EpLC8f3XYqdCzyGIt2U82uUobNqwQ4wgI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196772; c=relaxed/simple; bh=1PYHA52R/1nqpCMGwdQLlFvxUwx/4pnaicj2K/AnL0M=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=tG+0RQ5v60KEKtMBpwWszQktnXUFDGiyn2TZzYxlFunCU6GpL59JjegAdY8z5MuSr32OFxosHQzTo1nvlyIHCe55Yilq0nWzb2l5m0CFM7Dh7TjXKp4B4psHpLU8RAB12YUTDetwKMaX0MTlZM2CjCTYoAlqNLHoj3UHJf3HsTI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=c4NwyK7q; arc=fail smtp.client-ip=52.101.69.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="c4NwyK7q" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=XKLWnG0GLd+ctBpycvoh8cjI2gBbTFcy0uQlcEaR5Gt7qOn0QCve6WQ37i/tuiloE08r0ZKFE5e7vtKq4QHcuOrAu0l4NcKZIZSjivA0ujfSEv/g7kQEVgjnccVImnj0459qmSUTFj0kbwr7sSyUOCh8fEY3HUDpp5nz3wW2GfJxR/0qjAB87lvbBtyoW8jzfwHyKi/ryMUbK+S/bmgQRZ8qs1lai1R2Te4StkOruyUGoM/tEfgArKEozqsES5oXvHOWQ6HkNIUlQEcBoxgWGAfvlQHv2x4YPM1t8BB2KKXn/hu4BBxK8T0l9IEZ68BKnBjrnDXUn3Am/B2K0XIt1w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=v2JYIEZb85X9tKSGLC0rFm03ywjVIAcFU04p57FJP7Q=; b=LNW0onlzqyUW1qWcdA3rV6gW6ElZ7yGy1j9Jdo8SafG8VGuf+t4MkixUqePI0pvJ3nq9PytXwIDn+ixJJdijzNT3YLCvfRGXZRWHrOTocsSBtF+/hXFzwNzbcMbVoZRk32OsyV/Vg8kxe4zr288WhUnuXqY2W1Tq8hwq4AnlFLkMy5zUnUV/u7yNlyAYXNbqaAKwc6XBiU+escASFSfl4A5nzp7TCwphz1KLRRD1ip/dynem0qLfDbo50VnHe9MdWSoq2noQ/6JVDZ+ibhbnH212qKcjQ+DOp7A2PbZLbXt4OqfqbKJur1q0TudaZf1tEgnRZxuMgbu96bHKBeXJ0w== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=v2JYIEZb85X9tKSGLC0rFm03ywjVIAcFU04p57FJP7Q=; b=c4NwyK7q1FP6OUaJHzLgmMR1ah+DfDeXBm2/PE6/7QC+tqw1xjWHi/RAUyn8S69pjOKAKJ823cAtPewzwzD0axreYspALbEFsA7Fa3mU/stXcjjwqzzuTYDzgp3lpH06GrsDHrncRhh3X1yqak0cSGzxqVPpLCeRHvnV1ViDdseubjcFTBXXrVS/q+fvPJK15fMNfQ00tuMaOxgVCuEMm9d5Yd/4aKMfaTghFYqnDxgsrkST9MD0NBPA7X8TX435UKGSwehMIB8u3mGvLELjnuOXIBaTrlJWvgeXhzcUnq28XKiICQ2YxYBHVzMc4KIXFRuty6Q265G94lCeBLsvRg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:07 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:07 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 05/43] wifi: nxpwifi: add 11n_aggr.h Date: Fri, 9 Aug 2024 17:44:55 +0800 Message-Id: <20240809094533.1660-6-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: b5f62cda-65cf-4ba1-f207-08dcb858175a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: nhv+EPUR94wZbO76TK9UV/l266aCKVyD4+TBEPOBex79k9EkQ4ncFkie2U1PDDB8FuFD2+7/z2hDqaSRvDQ6/L/xZhpc5rO9Wu4xKMom7KgiGfOVoSuwngrDpcmraG4LkzXa4NYw9MyL0xeHMfFVhfsfx2yKcR6jOp6YA2PBTRSR0T+ef6Y1nPvOiwmMUcLz4pB9leWhuJEX4V1VElTGk5CjSBw6eJf/X0Jacp14fppQ0SPStXUldXm2nAFCPprNjFYfazE/YS+APhQClQXi+9U611U2SbY3wer6aVP9hM4dI5wOCTy1Dcjiz41D8snQIn7iQToccazBEV97/jNYxRHOQ/EYJxzZ+xHCswueZxGcFDN3JRsrOVZTky1A+vglsCHbLY7yWldb4HLajiLyNWWx25v69VjPleRvRikfjfAXhI5hKKZHA/z5FGlvha8hiiHAhudKjQt24uuEJoAd9llakXs73tLy45mbxs3eHBoo6Rbc9vYKZphgBsQbKucW5yiWqtMeLB0lZM54QUP5i3yg8dCyqsqb6D+PgADY1F/P8SxzedwPfiAdVouC6fF+UPuxgYvxDK8MuRtOZd/HsEw+/KEYX3gQyiGuFK7oO0S18GwwFmv7QFO+SckySuztcy+t9tEQVhqNrch5zUE67zTc07cPsoUK7nkUvBLCg/RB5dXITHW+Mu27tfduBM9nTbyKqDkNztcAIzdjpunxXupxLZb8suEwpOKJ+/dtGcTyo5xUnlbTESEAXHzd8ATa5YnaqLNh49/GvVODg53/8xxQzmwzuA7BLIjuR9H5dkDQ1V+3ST6sISDsnXFiKDGToSge4OT+hvKZKGF5ZsBZQ/FVrMT5jXr0ZqJPK4BlZpZCwXriD0TKCz6dpgUSeDFByhNyR5zmvtCd0RfM0p/o0U1i3KnkPSF6mB9Yb0F50TdkgPfZLsiRw4bDiNPTa7kcIrteuP2uTCWW+hp+tkt+W7Jc3Xhv+rJYasZZXDSboLlN+Z0USe6LSpNf7NM2eTZWIvPIQCylCOXOFQbUKPTun9oYQVhJu71GC9DkIXVjhyEUMbmvGZtg0QjuYfSWRSj432ucHtuIL+xOPwPics+hFVRfO5T6+qBPA3tK65xYJFxxV8riEBUZt9J4OC5J8WlIT7GWrgiYS9mIrrxH9aWeLgq0RyxqMP4uqTVEp6FZqH5K4eOQWKcV0jbYX+l0BEfSqjvVb2UMKCotxcXYH/uHEzpt914o8Xc6nCWbUbAJiclnNDfKR/5nPke9s/0pdIIbhKZ2peL+bH+2ay5eLbYrt03Rf5NblRpLYMY8kO4i/x6LqdXyeZzKlFm1u7f5oMDLrGjy8Pd6hoMGcoEWpxeUMA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: GmGMDYK5ZfaVUqgHspHnZBdDcuUwQTmrMcDo8aO4eIIp/4HyGSeHa+VIm+PjqhuygpQpVNbF3GRwFW0deuA7pzv2dIYeZNuYEm8rWFzxCoOoNOO+e78VUxuy6C9XSvDUzqgUg+ftuRMTtXVrOO4dCIHKdgbTweDbnild964nPmJ/sN7otxdX2wDFghFvD3brSc341JdTdujdpoGGtB4AS1TTkxV/lyIw8wPmCuUafk9pTLSyFjzDz8wDz5r0fJcrKe4qcTvk5pv8PrOBP/QmC02Q2dBsJmfturxwPmpwHy3zocaBOtwiFgUDWp1N91aQrkODtHTK3snDy5TbK5Zo0SaMUXfuDLnXfjr2s+tDlaKkAu3aT36FJGhH4xGLLivR3rLZFvovmB+F7gJTIurmU/p9Es7PZ1ntB8Yq7AtZrJJIsw+TVXEeJY1encLkZHwuXhcPXpjet9LPxcKtozar0gS3putHP6RMQoBW4FPTKn6ErykNYVE/9ulc+Bm12djmn62XHwJ2mLg6IFoS2u0W5j4w73whXQsIyi4tmuWvXMYwoQCSjzsTzs21yQuYmBw4FRZak/2qMfwJl3cMCuP5vxqrAJuY9X4HRDpSjJhX5QU+G031GCGuCvSq9arm3nVEQsyAkZ9RZytEPxQfZRc9+mrwO3q+yCSp+OWbBi1Tath/8vrATRiOj9dUKUJHNu5RzCVqzuKFZfAVbFWBW3fI+w5Fxct7uTT0zQcBfzsGmyVbglaYY1Fop4yK+A6NYwqmU4fTjXZiq1C14M+C2Mn8XFvrkdlHGSpNemneP8Sp2tVoYCNBrHrEzTHijL7IMK+xEGofrfIwmpoydmt2fkE+ymBF1obyei+wPw7r6vIqdwZW6DT+dm0oR83Et2F/GDAf2krw/eK1bSQUruoFI3VPnrnr3y8BOzrrRaqsEFEn1qlbh61n+L1eQazEwzXHEntEznUbPiBWU6O0TwrVsuhy9kSGU5wuwWH++s7Qqp40Z9ZCUCluxHf6jqDuTmxPeS7v0u0aJyD0yOPbATyq1LrGm8Y6tuas19Su7vP/Q58tnS44GM1C7w5eyOEbev8UlwSoBS8FabySwBM6Vn6XWg768Xcqmh2sa0c+c1Wj/5YXaRAH+r2NRWptL3a6fwIic1LFME4EYjuJghTYzZ7sGPhL2orclTOzkkagBe6/CduF68k3nYFEUap5hL4nqxAiCKjyU7rBtUKduWbMjAx8IQZxhKRCsjQdM6aRw1Thy//LGNQF5+N2nMfFNhWUHUkEDS2GrUBWK8nuDtqg5wtXE974plBHpBpTTUNfAjq10DFe/KIfDcQPOQIO+JmY5UqR40X6AAoWtJ/XX4Bgo/pzyd/FzCLuGEUk+P4BEfcoSrnjq6Mq6gd/ejCNEtD8wCBi+p1T+5lEw2M27lB0PC2wW1dyGuNjUZah/9cUv2oxEAwy/MXudmf52NQ09rSKLOgn9bo5C9nlUFW9sXSADVboiR1KDAa4Qp6SAqLZmE6rKIdU4iPGsDu8OZmZnBKObWVHsKzsaafKSWGykvrgv8aCfHME+tSYAo9Wh1Tjt5WQ5BXovzr1J+D5J1xQ+jXjJQ2p2LXtEypoX4t+D8EufkTrZMndK0R5kvlw4+wuAR10VQG/HDLWndCW5aucJeGFTjfiDGXM X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: b5f62cda-65cf-4ba1-f207-08dcb858175a X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:07.1558 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: ClL5zfgT1eaLwHURsHJhAcB60zt9q6ng/n8775Z9GPXpnpPINd6lL/6pNQ+dfzNqVc4k9rsC1ebiZd8SoadcZw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/11n_aggr.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/11n_aggr.h diff --git a/drivers/net/wireless/nxp/nxpwifi/11n_aggr.h b/drivers/net/wireless/nxp/nxpwifi/11n_aggr.h new file mode 100644 index 000000000000..be9f0f8f4e48 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/11n_aggr.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: 802.11n Aggregation + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_11N_AGGR_H_ +#define _NXPWIFI_11N_AGGR_H_ + +#define PKT_TYPE_AMSDU 0xE6 +#define MIN_NUM_AMSDU 2 + +int nxpwifi_11n_deaggregate_pkt(struct nxpwifi_private *priv, + struct sk_buff *skb); +int nxpwifi_11n_aggregate_pkt(struct nxpwifi_private *priv, + struct nxpwifi_ra_list_tbl *ptr, + int ptr_index) + __releases(&priv->wmm.ra_list_spinlock); + +#endif /* !_NXPWIFI_11N_AGGR_H_ */ From patchwork Fri Aug 9 09:44:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818396 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012047.outbound.protection.outlook.com [52.101.66.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6559A194135; Fri, 9 Aug 2024 09:46:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.47 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196779; cv=fail; b=Fo+js+MTQohEgOZFeDgsjRqWUXjW0BD9qAGwhD9JtTYGTHnX7u9VErOb8WYglpk9DYj+AEVxQlGowc3eEq/DblRKfsGi4vsD5vfCDnspTPqo5vJcXZM4H4rzXzto9QonZfE7yOVb9vqoEwrv5qA+UHJwICHRSbkf1jsA2+9e56Q= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196779; c=relaxed/simple; bh=IgQwABwWD/eu7KzBEmzkXs5MzlOaBsjw05X3ZG1JSps=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=NRyK0SriNRwXMvbUGZcBkUsEw96GKtkzmEaDiafkkI1/vuy1LjmWOyXuBtckN67IefJGH5x5RPh3RkkHnpvyj2LK8I8KAQUMt5LUuZy662LthDNWhwNf+gUYuh7rnh7VlnE6a55ytFjADpeBEIBjw0VGArDp68OvPZ7s5dVstoc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=K33wSdNE; arc=fail smtp.client-ip=52.101.66.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="K33wSdNE" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=eq5OAhCQaUuM8Em9vTtcRnqxgRnNVrzpJtGJTioKiT3zC2NfqWjLAZVikFgumQsiDWUnzerSm0q6HpPscTzmdGc+JvzJsEQIbYQu8wTt7TmPoewaTo/mifKEKC9nAH2rQxo9Xo9ww8kuToewWQcgkpgvLQia+6XbBYJsU1zdDxDF6V6tCB6MsCMKTb1H0E74k0y4g3QMEbEBFzyMNFYOmrF7SdTd278evNexWV1rUVpJYSbwdy0xDGnZDQqACxWmnD+lnTQTbV2MgCmImfR9Yy+w7cRXuKI25s7wVhmX2inoE6QLeudD+pzdHKNh84un1NYTba0l5+n/SYoEmwZ7DQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=XQfv//rczM5vqo7lFkvCTnYNPan1lIL3rpMVGRSMens=; b=oiTmptT/NGlZ3VJ2RF56Ro+8oR/NwuVMTm2gKCnrMK2ZLqYWxQ9Zdr657Hd/GaW/RRL9sU5f9nYB4DjqDT4sqU4BhQ/UsecsZQmUjCyjq1vH9gK6BroAbwLC6MH8dkA7C72wG6LWxB1m5I5bZdsfKHd6u19uebWPOVsqjMs4Qzuir3moqsby3VKZcd4b66TfM4msWfjyIQ7KznmwKyzrS8VEQqZpKFzYBFqrSghu9QKctHDDhkVCqdhfqYAeQEVm7oWnpOLS7k6y1Udv+M6y25LGVVNXb98bCo7ZgyL3thGXaE4XfFVkb7yc/lCRmP4JIlO9m7pWeCQiZqX3ZqxPWQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=XQfv//rczM5vqo7lFkvCTnYNPan1lIL3rpMVGRSMens=; b=K33wSdNE/vWIXWoc+71HN4Z9GCWOrj/49lI8wIF0Uub4RcbZIgO+r4+HGLHfZ46mXxu1gS2ZcvgHqtin9Ew9/h33+siIbgPQL6641zbUv4wtrVSIVJ6WLtHPpM3AaDuXxM2jG4fHB5Z1oQyYSc2+Fhg9JDjvzWaBGPE/A+QxaduNbZPLz9hHTCAp9IMedmjeaKchm32P5FaqoVevuQqHVKs36kvcnV06LCoFfSxVE0YcauXlpXbcA2yz0zKuJP6TOqJCdrlK9KHscGvnQBYUizxCqWTtu9bY0h41ufQPUl3hoRlknO3fSAQ+QSXZ3l0NXc+kHViO1FJ33fwRnYClCw== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:10 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:10 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 06/43] wifi: nxpwifi: add 11n.c Date: Fri, 9 Aug 2024 17:44:56 +0800 Message-Id: <20240809094533.1660-7-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: 93663ea9-5709-4315-2619-08dcb858197d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: fq7lwUeJt3FeWTQ7po2AnBeHrnhZUtM0cQOGrMdkye1Vc4vu4E5SR7EMGyLuFZM7K5oHNnmKn9yR1zqgHW2EJNEKN+w54Nix5neLxcpijgZAYoCleNtNP8PsNjYPItBc1OM0FoxG1YqNcksW6xFD+q/yKALdeFZKKtc219e66jZpYoeYGMDmn3MQx6MxPBP9gHifeSJZ7yEYG4hUYBGp99L9EvOQADTAJ/FSvl0qLRxgWp83rPbZYZUYRlUDqJvFSDaVJs7HQtRkyZu9X5kKPZgLBIvUNCTsGAlnbsBvTR0BrCeF54y6A7cDwcEQnk1VMLyZHx18M5jU4H7erKRPK519RGqd2m9UEEmWmU5xmWPQ9NtJsdKXxle4dmWSs7rbYI/xD52KPtsuWxMh0gOhLOxkRTn/eSxRNLRi0fBA5zg8FQ64LcpLyt4xImHdWhuySJlDitIm6Fz4uI5LdBnzu+Z5Jc0IUaw+s0ODSMYGRwihD4FWlbHx7/58bBsR9cfQ5upf+GVNsRsYJLWV1SCs50zFaQNXMKwGwXm3yAK7O8XGPzykPv9yHexJMZbFC9Eze33GjGvrtEjHdVL/Y3AB4CIEq69xjrSz7V56eJI46J9XLj17m7p0JYqJtOB9ZNHp2AhnJaeOGJJsfea56kFl0+XWWpXyGboR/Xb57yCOicxFpDYBkEYq2ZiO2/nZuBiJhy68AlSOhfxVitfayNuIe/54GEbwYJaUmho9LJK8Phm/2bcm4iDh/VxT0OBFK6xlO/d3HhmjCKDjBMCVzve237IujawuUSv6qEq2Bkysc+Ty9me72qhiF+yDIPINFjAykWkCn6//GzNTQRPhVE6KQWwZnLdo7qGX7Et2Fg0foQ3ebWZn+j7ulWJ7CPHtbA09kANeMpVe8pegVgAWlofe0qAw7kFgAc1R91lfG/uTk3vBT80pfQWhWR8Jqj4t6ln5+hUW1MLq6+OXT40GzErcy46KhIA6hNQn2+hnGwC3/hAFKPAdYOso8D1EplYJvPnz9cDCxZEic6VQYErhv3E7Eus7UA2u81q+gSnmOMumpc0As/SkjuxLbeH6wcz2GGbwsL2PYK7e5L/lDdOVW3FHY+IvRkg3LleN72wBZbDAZswceGnaTDRDWPlALF46KEj9dPaFO9Cg1aukZ22E2Hk0uZ3+NLuEOf/95WMfv6kQE0UVBx+6Ao3RWnQqDIKSLf+2zGrRt910UfzjAbhNh79b4SqI8S1jrBD7aE/hPM4JZl/kTQRp2SwCzKoA4k0Jylj6TbDUyS1nZVzk9NOKxOoOnGlubTMBBq1W+zi4ZPdllW+hxQYUjNQzrfpNa+01GWMhX2KT0K0nR6ZkbBWRRsOw1A== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: Ac6UBPLT5wn0EVc3WyXDGBLe7f35U1pgbQQlC91H3/+wBUNZMyvd/l+dF/FdgUmPbvKZOrs+PxbRWLh6iDkRzxhllTJhV3VDLDuwiv42jxCS6V8/VsK7TcXHaE1y4Ep7xl5NVrLLLzmkv4FrZvujyXPhzg6xL/EQNYFUcpn0aCqW9Yfbt8mUKUIkveFl8Y3a8bQcnfleFFOKIIM4DSIF4ityTBO+ib49zmK3tPMq/Pvls7yivTShDUCw+YTp1ewA6qKVOJfO7PsCbitZJ3eeDMqbesNTsfnbfJ3OiJVtNNDhz9I68zy/ZtdirTogjmb7ctXFKPNOpTF4xInkH9vlHTNLYBCiCLmrs5WJ2i26BpLrOkYv/Lbs/agHuD5tp4KXlU9A1QIE8Yk9DPLNAXp3LVz0BO95vH0ZhSPS1evumYoubgDC3Il0N6QXhbJEStKF8C0USOCbbVZs4skkoko6reTIjHXVRFA9CxmmWuRs4+wj8aZ0ywz3KCbydUzEg5JAUjQOk/3V98EdArbLSGCjtctvEcpkRrtcNGbzqEaMTk/Z9TUS6ZUSiWHwNtvmjtUY0gnIyc96pVvAwI5LHrIfLbTY4bx1b94NSNBSaFiLDqzNqnmoz5lqEkHCAxaUcaw5pOKhH7BfgvgTOE5Z4EsGmiWZb1oMaC+4A41Pk2wvH4DVR4TAQOIh6ywBD2WGleSLjHCXQOOqqcKuKvfrjLjB8YcAT3F07P8JKL5KUGTvxwzEEWjEs/fbSamfAT5uJ2NFXUGFOLR/BR+1N2DED2GHeE1tyxbHzLH7fRBASo5umxVWJI2bIKHulHKAI9Q9WCp1y5enOELC5aAnOSe5EytxZLCXe4Dp+uNBQNTFRk5SNHb9JtkP69Y8YzHDpGLo8koQODPAcVbTOcJpNuohTNpzCZhuq2eolAArsST3ULfBDNDPaGDtA41SRx7rVZ/BCdMeiX+lOAEI/SRKl6Q5o+fTkPrJgkO58AV7+kgTqMuSIDv2meBqBJh7XgA1v6AUPip9k2hg/vQRF9HOVx0VxH27M6NQ7vTcjQQ9gHUDDNV5s9T0vSY+3AagQFmzPAPx1h/DHkUEl7Osm+XpYyT4P2UA0PBaUbyDEEvB15jtCf7w3mF8YzNa02vxVicHoX+hG6nuDQ9Xr80Q8RjPcc85fYhJebuIBKTNzE+rjjza/PficojgdrWfDMozDPqfC5ufkWhLGCX1boyJXWjwKlZvXFxrCzM56Ck1soyJGEo/XjIceebdm2kWl/AQ5/Vdk6Utl0wR+UB0kei42KSZj8krtMOk/G7Ifhsr/uqtsJswWRIMf7OEM/YNI6ixoGJ41ZHpiZ7Wug6rkGUhix3+n0zZg5Z98GW2Rdb9K5WXQ81aXRgDHWUIC7wcTVO/OS7ibmuvfQVZZh1g664jnBjf3HIwyov/PBRSAiKHGKKPQrk8sYCuBMRYHrRe540B8dh/yaZ2qEBeDX/oepzsUh5SC3FTMER3tbgKUjHJsRMVZjUNOlWtU9rq2taifcGgXzTM9IEx+3eyy4abx4wlUJftn7eUPok1Nx7QBaFz6WJN3t1uscQx5v6piJW57XJH0qkEQlr5DgWGF738l9NMfh0gBuJ4k1FlXZk4plMzhFKCgaOJ3iuaQnVWbmLOslC4B05U89MmEUE8 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 93663ea9-5709-4315-2619-08dcb858197d X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:10.5886 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: C0UQKyQuUmWWJA+HONDBaaoew8ua82DSbaYOQiehdOquXkXds5E8iLRpHWnr9lz2jxJ5rUQlKKB5nM1pCxrxzA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/11n.c | 851 +++++++++++++++++++++++++ 1 file changed, 851 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/11n.c diff --git a/drivers/net/wireless/nxp/nxpwifi/11n.c b/drivers/net/wireless/nxp/nxpwifi/11n.c new file mode 100644 index 000000000000..b33d4ade184c --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/11n.c @@ -0,0 +1,851 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: 802.11n + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cmdevt.h" +#include "wmm.h" +#include "11n.h" + +/* Fills HT capability information field, AMPDU Parameters field, HT extended + * capability field, and supported MCS set fields. + * + * HT capability information field, AMPDU Parameters field, supported MCS set + * fields are retrieved from cfg80211 stack + * + * RD responder bit to set to clear in the extended capability header. + */ +int nxpwifi_fill_cap_info(struct nxpwifi_private *priv, u8 radio_type, + struct ieee80211_ht_cap *ht_cap) +{ + u16 ht_cap_info; + u16 bcn_ht_cap = le16_to_cpu(ht_cap->cap_info); + u16 ht_ext_cap = le16_to_cpu(ht_cap->extended_ht_cap_info); + struct ieee80211_supported_band *sband = + priv->wdev.wiphy->bands[radio_type]; + + if (WARN_ON_ONCE(!sband)) { + nxpwifi_dbg(priv->adapter, ERROR, "Invalid radio type!\n"); + return -EINVAL; + } + + ht_cap->ampdu_params_info = + (sband->ht_cap.ampdu_factor & + IEEE80211_HT_AMPDU_PARM_FACTOR) | + ((sband->ht_cap.ampdu_density << + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) & + IEEE80211_HT_AMPDU_PARM_DENSITY); + + memcpy((u8 *)&ht_cap->mcs, &sband->ht_cap.mcs, + sizeof(sband->ht_cap.mcs)); + + if (priv->bss_mode == NL80211_IFTYPE_STATION || + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && + priv->adapter->sec_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_NONE)) + /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ + SETHT_MCS32(ht_cap->mcs.rx_mask); + + /* Clear RD responder bit */ + ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER; + + ht_cap_info = sband->ht_cap.cap; + if (bcn_ht_cap) { + if (!(bcn_ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + if (!(bcn_ht_cap & IEEE80211_HT_CAP_SGI_40)) + ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40; + if (!(bcn_ht_cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) + ht_cap_info &= ~IEEE80211_HT_CAP_40MHZ_INTOLERANT; + } + ht_cap->cap_info = cpu_to_le16(ht_cap_info); + ht_cap->extended_ht_cap_info = cpu_to_le16(ht_ext_cap); + + if (ISSUPP_BEAMFORMING(priv->adapter->hw_dot_11n_dev_cap)) + ht_cap->tx_BF_cap_info = cpu_to_le32(NXPWIFI_DEF_11N_TX_BF_CAP); + + return 0; +} + +/* This function returns the pointer to an entry in BA Stream + * table which matches the requested BA status. + */ +static struct nxpwifi_tx_ba_stream_tbl * +nxpwifi_get_ba_status(struct nxpwifi_private *priv, + enum nxpwifi_ba_status ba_status) +{ + struct nxpwifi_tx_ba_stream_tbl *tx_ba_tsr_tbl; + + spin_lock_bh(&priv->tx_ba_stream_tbl_lock); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_tsr_tbl->ba_status == ba_status) { + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); + return tx_ba_tsr_tbl; + } + } + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); + return NULL; +} + +/* This function handles the command response of delete a block + * ack request. + * + * The function checks the response success status and takes action + * accordingly (send an add BA request in case of success, or recreate + * the deleted stream in case of failure, if the add BA was also + * initiated by us). + */ +int nxpwifi_ret_11n_delba(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp) +{ + int tid; + struct nxpwifi_tx_ba_stream_tbl *tx_ba_tbl; + struct host_cmd_ds_11n_delba *del_ba = &resp->params.del_ba; + u16 del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); + + tid = del_ba_param_set >> DELBA_TID_POS; + if (del_ba->del_result == BA_RESULT_SUCCESS) { + nxpwifi_del_ba_tbl(priv, tid, del_ba->peer_mac_addr, + TYPE_DELBA_SENT, + INITIATOR_BIT(del_ba_param_set)); + + tx_ba_tbl = nxpwifi_get_ba_status(priv, BA_SETUP_INPROGRESS); + if (tx_ba_tbl) + nxpwifi_send_addba(priv, tx_ba_tbl->tid, + tx_ba_tbl->ra); + } else { /* + * In case of failure, recreate the deleted stream in case + * we initiated the DELBA + */ + if (!INITIATOR_BIT(del_ba_param_set)) + return 0; + + nxpwifi_create_ba_tbl(priv, del_ba->peer_mac_addr, tid, + BA_SETUP_INPROGRESS); + + tx_ba_tbl = nxpwifi_get_ba_status(priv, BA_SETUP_INPROGRESS); + + if (tx_ba_tbl) + nxpwifi_del_ba_tbl(priv, tx_ba_tbl->tid, tx_ba_tbl->ra, + TYPE_DELBA_SENT, true); + } + + return 0; +} + +/* This function handles the command response of add a block + * ack request. + * + * Handling includes changing the header fields to CPU formats, checking + * the response success status and taking actions accordingly (delete the + * BA stream table in case of failure). + */ +int nxpwifi_ret_11n_addba_req(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp) +{ + int tid, tid_down; + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp; + struct nxpwifi_tx_ba_stream_tbl *tx_ba_tbl; + struct nxpwifi_ra_list_tbl *ra_list; + u16 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); + + add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) + & SSN_MASK); + + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + + tid_down = nxpwifi_wmm_downgrade_tid(priv, tid); + ra_list = nxpwifi_wmm_get_ralist_node(priv, tid_down, + add_ba_rsp->peer_mac_addr); + if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { + if (ra_list) { + ra_list->ba_status = BA_SETUP_NONE; + ra_list->amsdu_in_ampdu = false; + } + nxpwifi_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr, + TYPE_DELBA_SENT, true); + if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) + priv->aggr_prio_tbl[tid].ampdu_ap = + BA_STREAM_NOT_ALLOWED; + return 0; + } + + tx_ba_tbl = nxpwifi_get_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr); + if (tx_ba_tbl) { + nxpwifi_dbg(priv->adapter, EVENT, "info: BA stream complete\n"); + tx_ba_tbl->ba_status = BA_SETUP_COMPLETE; + if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) && + priv->add_ba_param.tx_amsdu && + priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) + tx_ba_tbl->amsdu = true; + else + tx_ba_tbl->amsdu = false; + if (ra_list) { + ra_list->amsdu_in_ampdu = tx_ba_tbl->amsdu; + ra_list->ba_status = BA_SETUP_COMPLETE; + } + } else { + nxpwifi_dbg(priv->adapter, ERROR, "BA stream not created\n"); + } + + return 0; +} + +/* This function prepares command of reconfigure Tx buffer. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Tx buffer size (for SET only) + * - Ensuring correct endian-ness + */ +int nxpwifi_cmd_recfg_tx_buf(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, int cmd_action, + u16 *buf_size) +{ + struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; + u16 action = (u16)cmd_action; + + cmd->command = cpu_to_le16(HOST_CMD_RECONFIGURE_TX_BUFF); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); + tx_buf->action = cpu_to_le16(action); + switch (action) { + case HOST_ACT_GEN_SET: + nxpwifi_dbg(priv->adapter, CMD, + "cmd: set tx_buf=%d\n", *buf_size); + tx_buf->buff_size = cpu_to_le16(*buf_size); + break; + case HOST_ACT_GEN_GET: + default: + tx_buf->buff_size = 0; + break; + } + return 0; +} + +/* This function prepares command of AMSDU aggregation control. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting AMSDU control parameters (for SET only) + * - Ensuring correct endian-ness + */ +int nxpwifi_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, + int cmd_action, + struct nxpwifi_ds_11n_amsdu_aggr_ctrl *aa_ctrl) +{ + struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = + &cmd->params.amsdu_aggr_ctrl; + u16 action = (u16)cmd_action; + + cmd->command = cpu_to_le16(HOST_CMD_AMSDU_AGGR_CTRL); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) + + S_DS_GEN); + amsdu_ctrl->action = cpu_to_le16(action); + switch (action) { + case HOST_ACT_GEN_SET: + amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); + amsdu_ctrl->curr_buf_size = 0; + break; + case HOST_ACT_GEN_GET: + default: + amsdu_ctrl->curr_buf_size = 0; + break; + } + return 0; +} + +/* This function prepares 11n configuration command. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting HT Tx capability and HT Tx information fields + * - Ensuring correct endian-ness + */ +int nxpwifi_cmd_11n_cfg(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, u16 cmd_action, + struct nxpwifi_ds_11n_tx_cfg *txcfg) +{ + struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; + + cmd->command = cpu_to_le16(HOST_CMD_11N_CFG); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); + htcfg->action = cpu_to_le16(cmd_action); + htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); + htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); + + if (priv->adapter->is_hw_11ac_capable) + htcfg->misc_config = cpu_to_le16(txcfg->misc_config); + + return 0; +} + +/* This function appends an 11n TLV to a buffer. + * + * Buffer allocation is responsibility of the calling + * function. No size validation is made here. + * + * The function fills up the following sections, if applicable - + * - HT capability IE + * - HT information IE (with channel list) + * - 20/40 BSS Coexistence IE + * - HT Extended Capabilities IE + */ +int +nxpwifi_cmd_append_11n_tlv(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc, + u8 **buffer) +{ + struct nxpwifi_ie_types_htcap *ht_cap; + struct nxpwifi_ie_types_chan_list_param_set *chan_list; + struct nxpwifi_ie_types_2040bssco *bss_co_2040; + struct nxpwifi_ie_types_extcap *ext_cap; + int ret_len = 0; + struct ieee80211_supported_band *sband; + struct element *hdr; + u8 radio_type; + + if (!buffer || !*buffer) + return ret_len; + + radio_type = nxpwifi_band_to_radio_type((u8)bss_desc->bss_band); + sband = priv->wdev.wiphy->bands[radio_type]; + + if (bss_desc->bcn_ht_cap) { + ht_cap = (struct nxpwifi_ie_types_htcap *)*buffer; + memset(ht_cap, 0, sizeof(struct nxpwifi_ie_types_htcap)); + ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + memcpy((u8 *)ht_cap + sizeof(struct nxpwifi_ie_types_header), + (u8 *)bss_desc->bcn_ht_cap, + le16_to_cpu(ht_cap->header.len)); + + nxpwifi_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); + /* Update HT40 capability from current channel information */ + if (bss_desc->bcn_ht_oper) { + u8 ht_param = bss_desc->bcn_ht_oper->ht_param; + u8 radio = + nxpwifi_band_to_radio_type(bss_desc->bss_band); + int freq = + ieee80211_channel_to_frequency(bss_desc->channel, + radio); + struct ieee80211_channel *chan = + ieee80211_get_channel(priv->adapter->wiphy, freq); + + switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) { + ht_cap->ht_cap.cap_info &= + cpu_to_le16 + (~IEEE80211_HT_CAP_SUP_WIDTH_20_40); + ht_cap->ht_cap.cap_info &= + cpu_to_le16(~IEEE80211_HT_CAP_SGI_40); + } + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) { + ht_cap->ht_cap.cap_info &= + cpu_to_le16 + (~IEEE80211_HT_CAP_SUP_WIDTH_20_40); + ht_cap->ht_cap.cap_info &= + cpu_to_le16(~IEEE80211_HT_CAP_SGI_40); + } + break; + } + } + + *buffer += sizeof(struct nxpwifi_ie_types_htcap); + ret_len += sizeof(struct nxpwifi_ie_types_htcap); + } + + if (bss_desc->bcn_ht_oper) { + chan_list = + (struct nxpwifi_ie_types_chan_list_param_set *)*buffer; + memset(chan_list, 0, struct_size(chan_list, chan_scan_param, 1)); + chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_list->header.len = + cpu_to_le16(sizeof(struct nxpwifi_chan_scan_param_set)); + chan_list->chan_scan_param[0].chan_number = + bss_desc->bcn_ht_oper->primary_chan; + chan_list->chan_scan_param[0].radio_type = + nxpwifi_band_to_radio_type((u8)bss_desc->bss_band); + + if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && + bss_desc->bcn_ht_oper->ht_param & + IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) + SET_SECONDARYCHAN + (chan_list->chan_scan_param[0].radio_type, + (bss_desc->bcn_ht_oper->ht_param & + IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); + + *buffer += struct_size(chan_list, chan_scan_param, 1); + ret_len += struct_size(chan_list, chan_scan_param, 1); + } + + if (bss_desc->bcn_bss_co_2040) { + bss_co_2040 = (struct nxpwifi_ie_types_2040bssco *)*buffer; + memset(bss_co_2040, 0, + sizeof(struct nxpwifi_ie_types_2040bssco)); + bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); + bss_co_2040->header.len = + cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); + + memcpy((u8 *)bss_co_2040 + + sizeof(struct nxpwifi_ie_types_header), + bss_desc->bcn_bss_co_2040 + + sizeof(struct element), + le16_to_cpu(bss_co_2040->header.len)); + + *buffer += sizeof(struct nxpwifi_ie_types_2040bssco); + ret_len += sizeof(struct nxpwifi_ie_types_2040bssco); + } + + if (bss_desc->bcn_ext_cap) { + hdr = (void *)bss_desc->bcn_ext_cap; + ext_cap = (struct nxpwifi_ie_types_extcap *)*buffer; + memset(ext_cap, 0, sizeof(struct nxpwifi_ie_types_extcap)); + ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); + ext_cap->header.len = cpu_to_le16(hdr->datalen); + + memcpy((u8 *)ext_cap->ext_capab, + bss_desc->bcn_ext_cap + sizeof(struct element), + le16_to_cpu(ext_cap->header.len)); + + if (hdr->datalen > 3 && + ext_cap->ext_capab[3] & WLAN_EXT_CAPA4_INTERWORKING_ENABLED) + priv->hs2_enabled = true; + else + priv->hs2_enabled = false; + + *buffer += sizeof(struct nxpwifi_ie_types_extcap) + hdr->datalen; + ret_len += sizeof(struct nxpwifi_ie_types_extcap) + hdr->datalen; + } + + return ret_len; +} + +/* This function checks if the given pointer is valid entry of + * Tx BA Stream table. + */ +static int +nxpwifi_is_tx_ba_stream_ptr_valid(struct nxpwifi_private *priv, + struct nxpwifi_tx_ba_stream_tbl *tx_tbl_ptr) +{ + struct nxpwifi_tx_ba_stream_tbl *tx_ba_tsr_tbl; + + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_tsr_tbl == tx_tbl_ptr) + return true; + } + + return false; +} + +/* This function deletes the given entry in Tx BA Stream table. + * + * The function also performs a validity check on the supplied + * pointer before trying to delete. + */ +void +nxpwifi_11n_delete_tx_ba_stream_tbl_entry(struct nxpwifi_private *priv, + struct nxpwifi_tx_ba_stream_tbl *tbl) +{ + if (!tbl && nxpwifi_is_tx_ba_stream_ptr_valid(priv, tbl)) + return; + + nxpwifi_dbg(priv->adapter, INFO, + "info: tx_ba_tsr_tbl %p\n", tbl); + + list_del(&tbl->list); + + kfree(tbl); +} + +/* This function deletes all the entries in Tx BA Stream table. + */ +void nxpwifi_11n_delete_all_tx_ba_stream_tbl(struct nxpwifi_private *priv) +{ + int i; + struct nxpwifi_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node; + + spin_lock_bh(&priv->tx_ba_stream_tbl_lock); + list_for_each_entry_safe(del_tbl_ptr, tmp_node, + &priv->tx_ba_stream_tbl_ptr, list) + nxpwifi_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr); + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); + + INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); + + for (i = 0; i < MAX_NUM_TID; ++i) + priv->aggr_prio_tbl[i].ampdu_ap = + priv->aggr_prio_tbl[i].ampdu_user; +} + +/* This function returns the pointer to an entry in BA Stream + * table which matches the given RA/TID pair. + */ +struct nxpwifi_tx_ba_stream_tbl * +nxpwifi_get_ba_tbl(struct nxpwifi_private *priv, int tid, u8 *ra) +{ + struct nxpwifi_tx_ba_stream_tbl *tx_ba_tsr_tbl; + + spin_lock_bh(&priv->tx_ba_stream_tbl_lock); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (ether_addr_equal_unaligned(tx_ba_tsr_tbl->ra, ra) && + tx_ba_tsr_tbl->tid == tid) { + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); + return tx_ba_tsr_tbl; + } + } + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); + return NULL; +} + +/* This function creates an entry in Tx BA stream table for the + * given RA/TID pair. + */ +void nxpwifi_create_ba_tbl(struct nxpwifi_private *priv, u8 *ra, int tid, + enum nxpwifi_ba_status ba_status) +{ + struct nxpwifi_tx_ba_stream_tbl *new_node; + struct nxpwifi_ra_list_tbl *ra_list; + int tid_down; + + if (!nxpwifi_get_ba_tbl(priv, tid, ra)) { + new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); + if (!new_node) + return; + + tid_down = nxpwifi_wmm_downgrade_tid(priv, tid); + ra_list = nxpwifi_wmm_get_ralist_node(priv, tid_down, ra); + if (ra_list) { + ra_list->ba_status = ba_status; + ra_list->amsdu_in_ampdu = false; + } + INIT_LIST_HEAD(&new_node->list); + + new_node->tid = tid; + new_node->ba_status = ba_status; + memcpy(new_node->ra, ra, ETH_ALEN); + + spin_lock_bh(&priv->tx_ba_stream_tbl_lock); + list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); + } +} + +/* This function sends an add BA request to the given TID/RA pair. + */ +int nxpwifi_send_addba(struct nxpwifi_private *priv, int tid, u8 *peer_mac) +{ + struct host_cmd_ds_11n_addba_req add_ba_req; + u32 tx_win_size = priv->add_ba_param.tx_win_size; + static u8 dialog_tok; + int ret; + u16 block_ack_param_set; + + nxpwifi_dbg(priv->adapter, CMD, "cmd: %s: tid %d\n", __func__, tid); + + memset(&add_ba_req, 0, sizeof(add_ba_req)); + + block_ack_param_set = (u16)((tid << BLOCKACKPARAM_TID_POS) | + tx_win_size << BLOCKACKPARAM_WINSIZE_POS | + IMMEDIATE_BLOCK_ACK); + + /* enable AMSDU inside AMPDU */ + if (priv->add_ba_param.tx_amsdu && + priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) + block_ack_param_set |= BLOCKACKPARAM_AMSDU_SUPP_MASK; + + add_ba_req.block_ack_param_set = cpu_to_le16(block_ack_param_set); + add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); + + ++dialog_tok; + + if (dialog_tok == 0) + dialog_tok = 1; + + add_ba_req.dialog_token = dialog_tok; + memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); + + /* We don't wait for the response of this command */ + ret = nxpwifi_send_cmd(priv, HOST_CMD_11N_ADDBA_REQ, + 0, 0, &add_ba_req, false); + + return ret; +} + +/* This function sends a delete BA request to the given TID/RA pair. + */ +int nxpwifi_send_delba(struct nxpwifi_private *priv, int tid, u8 *peer_mac, + int initiator) +{ + struct host_cmd_ds_11n_delba delba; + int ret; + u16 del_ba_param_set; + + memset(&delba, 0, sizeof(delba)); + + del_ba_param_set = tid << DELBA_TID_POS; + + if (initiator) + del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK; + else + del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK; + + delba.del_ba_param_set = cpu_to_le16(del_ba_param_set); + memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); + + /* We don't wait for the response of this command */ + ret = nxpwifi_send_cmd(priv, HOST_CMD_11N_DELBA, + HOST_ACT_GEN_SET, 0, &delba, false); + + return ret; +} + +/* This function sends delba to specific tid + */ +void nxpwifi_11n_delba(struct nxpwifi_private *priv, int tid) +{ + struct nxpwifi_rx_reorder_tbl *rx_reor_tbl_ptr; + + spin_lock_bh(&priv->rx_reorder_tbl_lock); + list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { + if (rx_reor_tbl_ptr->tid == tid) { + dev_dbg(priv->adapter->dev, + "Send delba to tid=%d, %pM\n", + tid, rx_reor_tbl_ptr->ta); + nxpwifi_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0); + goto exit; + } + } +exit: + spin_unlock_bh(&priv->rx_reorder_tbl_lock); +} + +/* This function handles the command response of a delete BA request. + */ +void nxpwifi_11n_delete_ba_stream(struct nxpwifi_private *priv, u8 *del_ba) +{ + struct host_cmd_ds_11n_delba *cmd_del_ba = + (struct host_cmd_ds_11n_delba *)del_ba; + u16 del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); + int tid; + + tid = del_ba_param_set >> DELBA_TID_POS; + + nxpwifi_del_ba_tbl(priv, tid, cmd_del_ba->peer_mac_addr, + TYPE_DELBA_RECEIVE, INITIATOR_BIT(del_ba_param_set)); +} + +/* This function retrieves the Rx reordering table. + */ +int nxpwifi_get_rx_reorder_tbl(struct nxpwifi_private *priv, + struct nxpwifi_ds_rx_reorder_tbl *buf) +{ + int i; + struct nxpwifi_ds_rx_reorder_tbl *rx_reo_tbl = buf; + struct nxpwifi_rx_reorder_tbl *rx_reorder_tbl_ptr; + int count = 0; + + spin_lock_bh(&priv->rx_reorder_tbl_lock); + list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, + list) { + rx_reo_tbl->tid = (u16)rx_reorder_tbl_ptr->tid; + memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); + rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; + rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; + for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { + if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) + rx_reo_tbl->buffer[i] = true; + else + rx_reo_tbl->buffer[i] = false; + } + rx_reo_tbl++; + count++; + + if (count >= NXPWIFI_MAX_RX_BASTREAM_SUPPORTED) + break; + } + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + + return count; +} + +/* This function retrieves the Tx BA stream table. + */ +int nxpwifi_get_tx_ba_stream_tbl(struct nxpwifi_private *priv, + struct nxpwifi_ds_tx_ba_stream_tbl *buf) +{ + struct nxpwifi_tx_ba_stream_tbl *tx_ba_tsr_tbl; + struct nxpwifi_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; + int count = 0; + + spin_lock_bh(&priv->tx_ba_stream_tbl_lock); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + rx_reo_tbl->tid = (u16)tx_ba_tsr_tbl->tid; + nxpwifi_dbg(priv->adapter, DATA, "data: %s tid=%d\n", + __func__, rx_reo_tbl->tid); + memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); + rx_reo_tbl->amsdu = tx_ba_tsr_tbl->amsdu; + rx_reo_tbl++; + count++; + if (count >= NXPWIFI_MAX_TX_BASTREAM_SUPPORTED) + break; + } + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); + + return count; +} + +/* This function retrieves the entry for specific tx BA stream table by RA and + * deletes it. + */ +void nxpwifi_del_tx_ba_stream_tbl_by_ra(struct nxpwifi_private *priv, u8 *ra) +{ + struct nxpwifi_tx_ba_stream_tbl *tbl, *tmp; + + if (!ra) + return; + + spin_lock_bh(&priv->tx_ba_stream_tbl_lock); + list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) + if (!memcmp(tbl->ra, ra, ETH_ALEN)) + nxpwifi_11n_delete_tx_ba_stream_tbl_entry(priv, tbl); + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); +} + +/* This function initializes the BlockACK setup information for given + * nxpwifi_private structure. + */ +void nxpwifi_set_ba_params(struct nxpwifi_private *priv) +{ + priv->add_ba_param.timeout = NXPWIFI_DEFAULT_BLOCK_ACK_TIMEOUT; + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) { + priv->add_ba_param.tx_win_size = + NXPWIFI_UAP_AMPDU_DEF_TXWINSIZE; + priv->add_ba_param.rx_win_size = + NXPWIFI_UAP_AMPDU_DEF_RXWINSIZE; + } else { + priv->add_ba_param.tx_win_size = + NXPWIFI_STA_AMPDU_DEF_TXWINSIZE; + priv->add_ba_param.rx_win_size = + NXPWIFI_STA_AMPDU_DEF_RXWINSIZE; + } + + priv->add_ba_param.tx_amsdu = true; + priv->add_ba_param.rx_amsdu = true; +} + +u8 nxpwifi_get_sec_chan_offset(int chan) +{ + u8 sec_offset; + + switch (chan) { + case 36: + case 44: + case 52: + case 60: + case 100: + case 108: + case 116: + case 124: + case 132: + case 140: + case 149: + case 157: + sec_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + break; + case 40: + case 48: + case 56: + case 64: + case 104: + case 112: + case 120: + case 128: + case 136: + case 144: + case 153: + case 161: + sec_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; + break; + case 165: + default: + sec_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; + break; + } + + return sec_offset; +} + +/* This function will send DELBA to entries in the priv's + * Tx BA stream table + */ +static void +nxpwifi_send_delba_txbastream_tbl(struct nxpwifi_private *priv, u8 tid) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_tx_ba_stream_tbl *tx_ba_stream_tbl_ptr; + + list_for_each_entry(tx_ba_stream_tbl_ptr, + &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_stream_tbl_ptr->ba_status == BA_SETUP_COMPLETE) { + if (tid == tx_ba_stream_tbl_ptr->tid) { + dev_dbg(adapter->dev, + "Tx:Send delba to tid=%d, %pM\n", tid, + tx_ba_stream_tbl_ptr->ra); + nxpwifi_send_delba(priv, + tx_ba_stream_tbl_ptr->tid, + tx_ba_stream_tbl_ptr->ra, 1); + return; + } + } + } +} + +/* This function updates all the tx_win_size + */ +void nxpwifi_update_ampdu_txwinsize(struct nxpwifi_adapter *adapter) +{ + u8 i, j; + u32 tx_win_size; + struct nxpwifi_private *priv; + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i]) + continue; + priv = adapter->priv[i]; + tx_win_size = priv->add_ba_param.tx_win_size; + + if (priv->bss_type == NXPWIFI_BSS_TYPE_STA) + priv->add_ba_param.tx_win_size = + NXPWIFI_STA_AMPDU_DEF_TXWINSIZE; + + if (priv->bss_type == NXPWIFI_BSS_TYPE_UAP) + priv->add_ba_param.tx_win_size = + NXPWIFI_UAP_AMPDU_DEF_TXWINSIZE; + + if (adapter->coex_win_size) { + if (adapter->coex_tx_win_size) + priv->add_ba_param.tx_win_size = + adapter->coex_tx_win_size; + } + + if (tx_win_size != priv->add_ba_param.tx_win_size) { + if (!priv->media_connected) + continue; + for (j = 0; j < MAX_NUM_TID; j++) + nxpwifi_send_delba_txbastream_tbl(priv, j); + } + } +} From patchwork Fri Aug 9 09:44:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818281 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012047.outbound.protection.outlook.com [52.101.66.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A0281922DC; Fri, 9 Aug 2024 09:46:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.47 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196781; cv=fail; b=CQfSnJC4qjwb5G/b8TvEvw+5vId4W7H6/kRxD+EV9vSK84hGTKW6Kcn2fh8BQsyjKIoVznGydDpVXDAMEuLlP1oB5MexjQ1NQBIhHFiFN6/i1678vAwxf195gSWXYziYrXfno7xwcPGIi+6leVcDF5jtz3lO20NAQvRyz/Qu50g= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196781; c=relaxed/simple; bh=HmCvO/h8f91FB38TkMqSXKC1ZLseN1Fu2LSi9ffWw30=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=q9ccwiQdtRroQujlX+6kXlTwNbWfrWlUWbAUpB94288na0AfIlsDZqNMWkleo/eqaC4jnX7AHOjreVJyaz4pG2EHtXK6LPeVt+fs140h3mQfSv2ycXRmetZPrqui/SjV6mdp1e/cF4bXnBp6kSPT02OeeoFN/IABIXH/tWfyZJc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=IERCpAIE; arc=fail smtp.client-ip=52.101.66.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="IERCpAIE" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=BKNyefCRETeGx9A1Ss/OTQT0B+L9MZuGuBMCyjzhjvF42jIioD9G7zIEoIbcLkzO90k/VJB6Ie43e7gDd22TqEwM+qALSuudNdyhPSNsZ5Ra1QgVCJsCRSeXyKBL2icQLfmKGZ8cexUeK9xkCF0DLvWq0R30EHzJsBe/sn04fesifD8K+MELpLD2FS4kdMRpvAGQmx7SotgzbJJpqrP0W75ciiU6ed3uAPokK/M+bxVMIX3OSeoq9UZ4pXU11HME/HIqynqkk61DcaJeIlInpn2uPWI4u50EUTBTpowTx6Iwu8Lp9tLjVjDzi5HvShshIBJI3W6EFDD6cSyJ6uUEWg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=pnoqNv9SsjBuB8ksFnZAg7FWy8hlM2Jgzz2zuFH81bM=; b=k422csFsSjuwiA5NX371907ybXT1BnNgJWvuvhJtYm09cVtKKGErdrC4yYWf7L/bCS6BMQKdbofpoRuX5FfhVHp0Hu/JINuXGcoNISlVw8/2LjxBxCYWYx2l75FP4ukhsNX1TifH53z+R/ObHd7tl0LlKvOdf/7MALvxv1J4Yehek2uaKQlZ0NGvJWhyaz7u/1WLdd4ZyEo6k2ubqMhtaWHU3HHdk2d13b4FgR6leJw6an1rL9leTNOlf+MBFpJVQxscUqAxQ9YJv51TOv3J/Q8nJXw7K1hOfrU1RI69u3hWwL1L5RrWBjL/rKhd+lOFY1+glkO9OkqmDIXY1/L3Sw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=pnoqNv9SsjBuB8ksFnZAg7FWy8hlM2Jgzz2zuFH81bM=; b=IERCpAIEIDqhS1FybAp8ageh1udhdGidN+vPmK6qnYS7EJP6NYiedYXovVlSQ+ljNS1ZEWn5So4tTRWypclW113rQO6/ViGHNBCcBASY1mo6u6VrWT51xfEq7oXB6DQUpG0PC/04SkwwfZW4XPBz8LOYQBEoErV0xf5o9GHSGy+uXYl2YMUyn7pL4I/fa+mT0JcHmGxoVSHKjG7kieti0BeAhYlovVaZo3r43HVg3n7GiceI12Kmd7bnE37l4vgHmGvJary9b4SU8Zcoc7HHTSurUr3QlpFySY4SHNnGbbhoILIRBfpul/hWg+fJ3ONrQ1iMhEVPlFmRluy4LCMY1w== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:14 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:14 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 07/43] wifi: nxpwifi: add 11n.h Date: Fri, 9 Aug 2024 17:44:57 +0800 Message-Id: <20240809094533.1660-8-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: 90bb5ae2-1267-46e4-bfd2-08dcb8581bac X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: lI1pzkn3f9HQs6DQwlhtSsZqMVwp8h9birE4g4mvi+whTYbEfXoqSH2ajCdN63KUg3W0ItlmprKDeyV010l9s6B3wV46SOBxWwj1ogLpafEYJ7lAC3mPApNyjjUyoUOuPnelPSFvDDo0bCskuWHrjkZICjOql5uWMNw+4NTMc5el2C+qmR8+G5nhiEAnYuW/Z8AvsqfVi3o/bQ2wnYZkCVOWELlgQ78Us0xBMioavC2apGqxL5f6lZpwNpxZeM5WcVseXLrxFtcWh7IXYiwIpyMnFnjNjYQ7ut/nS25IvmVh9sTC+Jg3qjOI9/6Zf+vTd3/WaAcrMuRbuFoguEqDDELdclmNQ3RHr7CInIP3gMXaINtWUgwOb25/LvVTy99S4k/it7vyooFf9czcYOdgcpOfcr/GngrpyYchcosAWk6WF9IWV08USW7h+KMcyUm/idFWfXNTQtNjRwum+GlNzKDQ2/n4BiZ6QbZ1Yv2+VYSWj9pwD5UcHaBcmOjEzDyOGEfE24qacoTX3f2JeWohYV9XBtWlyimwJge1S3ivfqWjzzPtOhxrzshKz/5NA+RMNsEmzVvhDC+FleTB/flodCr4QxdmK7z9hvRZp4iqY8VHDbGIcGxBPgURWp73k8Yi+EYW9igubWvkVNScOqDLDqT/pFY4bdt+tja/jQCDwf9V6mYr2uWi6jueOXmAOtW+sac4aR+5QkiB0SEfVdA5hVGbb501IZ9BjGVgEOsjnoDf435jA4cRCfVX/dkCqDBXJGbZ/jV2PS8Cg/7OvHJlhEAarFx7rfUPZgfmD8eYKI8AUNvG9LwRTPaZbiG7CThDk7ssjsuorMgsTopNYmxYwazJASTEf67HIwppHEapICDcM4SJedm8t96kKGtkHopftI7up9Cs5H/ZheaB3RtjZHUwZAUtyYhECiQbZvmYGSdWNeYhAGZRX274T1uCRcZFDb8GpFnu4ZfvewwxeBjw7Y+Xi9NRMmOVq8dpuqW/pQuhjwVWfRBqgjzgKGkaXGFefsrSxOLV9jbk0bSraiPrHb58bQsEHVrC0AQVUKabraGteHjjomU4iCBck3zpNbKn2Y7fZKBYpTWTJ2rYcDcmrh6jQN1Y4350QyhWvFVQiaSQzIcigp7Nuzv2XNZueY+yVBKqRDR9tp94CiXs8RwNNkqYce9UxDTbK+r8ACw/m4oxFkcukYqAzzKKBIJjK8UNYJzcJaHZJNIrObP0CRbif6cni0YH3PARo35V2BGFOqyJ2kf3K24PMcRDmW3JWDaw/kfJp/XttgqEBHNxsN+g4dTFenqWpIX/GWs6dbi265mF0TnHeckYbIh0IiTf7y+uyYyiS/1LSLjNUn+hDvAyxQ== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: YCMXDcHdJWqv+eXzs8u4b45wGnQmWIDafjWQ6fIi0eu7mLQciHWKqUzFojUWpJbj+HpyKidCuP3qlH7gS2uW3dY1VIY7qXiG2uvbDN3U+iHfUiQGXH11ardbkatUiIZaP6orWYvAB1ncpaC73BCdp6eT/sm9v7QCo6DNLWrKkphrE4KzBLOqTHrIcvH+Kb8Xn7m1SjfSTy6AtMlt+PuueEXRGuPa5TTzaTHeLLGqnEinxXRMrkkkj1sXXTZc0S3KfypQJq1uIqItb6iFE8OEMmYrhnZwJISu7JQo64V7dC9e7Aj0Swtz+okUibVn3Kj/etlTApmGPuc33o4+DlwZ/9LVTRkaPGJvK1W2XmRM6O3X3Wo0GUYjRxmMWagy1xS8lMXMg5LFcPvOcdHyYbdsOu+HFIpB6XhCrr4wgYuRva6iYiarEHxUtmlMuIhF7Vckhe8ZK+uK036MAtBbkh93Yc9VAxQcCFKdPrthjWnqt0bQ0/hX18Nkb9iWB4/D7FI7ZwAFDX4k+55MUkBWnkuwEIvwoMDrm774kC/NZkouefImMnQyg3vVsEZ0W9rxdkW8FMsvuLV8xcjSY6KWY8ugRo/QmHA6bQBIaWm08JB1iqqCRTtkxNyWLwAmLNrOJCm8T0I40djxszMq/7GWToABA4LkpbWOKWTV3A+nN4LSNKXNIWMrlXhAZPWufj//kkpXKpqwACxtx5SGcwga6Q2hFugkLZ/YylU7QA0L3Oiz+EJxda4T25LAeE6BTmEcjiIx+cfUIQ1OJqCifcsnBpCkO5s+3ioQPR8/bQgmgKM7YJJ7zNrSXlg11351x6I/K3dxv3E/z1fRLJC7TcPUN+Jji05E+dk7Zmn+z3DQDvgw3gIVhnP5WTPoLqoDOwhC/YjxhpS3BurqluAFAQ7SFuS+FeW3bBaK4f1jFqswtNe4rw7ALyGOm4f/DCvBJ1VcE9wAlof4HVf4z5eRwLi3n/qnZjV0lebZsahldNLzE0fz6uCkjDXQ2P4OqbqMbzW9+9TXdDdkJO7SA90BEsbfIwaTX0CXWCKyfCy2jl/bo3rTgp5x0L4NS854hwqOveGgl0NGK6CRpGHFoXXVYYVEe6lonFt/OnHXhU7xR94ksgJpGRWWfzakUOs70ntpiFbj3FCXxmw3ephOd3HyUvfilnto/7VSDFGj9YvGtOf9QTYaoB1kQEiWKXOfd8b+XxPvuW7jmwP7hIXFKmRayIUJ9DeBsNuCAapK2f/RfjimWflgxz+0C66X41LnmcCC6HiUgrRU88X8Qg73Da/AYKzf0dVurFE1H5/fz3KbmKlsI6pw56eDu5EU6wPOXjdvDk7850iCP1xrnUHOc3J0LjygCtzogoh3oCiHFNYoroBCW1AKSJJrzgh+i9yHjLyuwFEXpgGnZKynI3MO77jQ1tDdZ1rwYGTAl6OqSCHY082jDYNuPzrGUm9VYqCR9N5I3gDAfNJ5YB2L/fsm+jC846nhjtb4d8Ad7Stxlv/fim/Tg9+RhIA3moxJ7+nQxz/QsKmSc9w+fyxYD3SOofnAll745rSmHxiX8jFxhi3bTUi8DHf4sJgPU8sx0SuZTXx2qEaZ+ok+Jnu8KjuwJbuzpXoKz9IWa6rJE2e4lhLsdagqFhhUhDMY/6kZIpcb4a2pryIy5Iv/ X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 90bb5ae2-1267-46e4-bfd2-08dcb8581bac X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:14.2151 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 0ZzDcDq+//xsCa/xNSsj1N8XJmVdPBWbOkc0igpcQDVxqPFIZxJjHemv9A5qlE6v46jdatHLuILaSmyL0ltIqg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/11n.h | 163 +++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/11n.h diff --git a/drivers/net/wireless/nxp/nxpwifi/11n.h b/drivers/net/wireless/nxp/nxpwifi/11n.h new file mode 100644 index 000000000000..9d983aea3a39 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/11n.h @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: 802.11n + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_11N_H_ +#define _NXPWIFI_11N_H_ + +#include "11n_aggr.h" +#include "11n_rxreorder.h" +#include "wmm.h" + +int nxpwifi_ret_11n_delba(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp); +int nxpwifi_ret_11n_addba_req(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp); +int nxpwifi_cmd_11n_cfg(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, u16 cmd_action, + struct nxpwifi_ds_11n_tx_cfg *txcfg); +int nxpwifi_cmd_append_11n_tlv(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc, + u8 **buffer); +int nxpwifi_fill_cap_info(struct nxpwifi_private *priv, u8 radio_type, + struct ieee80211_ht_cap *ht_cap); +int nxpwifi_set_get_11n_htcap_cfg(struct nxpwifi_private *priv, + u16 action, int *htcap_cfg); +void nxpwifi_11n_delete_tx_ba_stream_tbl_entry(struct nxpwifi_private *priv, + struct nxpwifi_tx_ba_stream_tbl + *tx_tbl); +void nxpwifi_11n_delete_all_tx_ba_stream_tbl(struct nxpwifi_private *priv); +struct nxpwifi_tx_ba_stream_tbl *nxpwifi_get_ba_tbl(struct nxpwifi_private + *priv, int tid, u8 *ra); +void nxpwifi_create_ba_tbl(struct nxpwifi_private *priv, u8 *ra, int tid, + enum nxpwifi_ba_status ba_status); +int nxpwifi_send_addba(struct nxpwifi_private *priv, int tid, u8 *peer_mac); +int nxpwifi_send_delba(struct nxpwifi_private *priv, int tid, u8 *peer_mac, + int initiator); +void nxpwifi_11n_delete_ba_stream(struct nxpwifi_private *priv, u8 *del_ba); +int nxpwifi_get_rx_reorder_tbl(struct nxpwifi_private *priv, + struct nxpwifi_ds_rx_reorder_tbl *buf); +int nxpwifi_get_tx_ba_stream_tbl(struct nxpwifi_private *priv, + struct nxpwifi_ds_tx_ba_stream_tbl *buf); +int nxpwifi_cmd_recfg_tx_buf(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + int cmd_action, u16 *buf_size); +int nxpwifi_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, + int cmd_action, + struct nxpwifi_ds_11n_amsdu_aggr_ctrl *aa_ctrl); +void nxpwifi_del_tx_ba_stream_tbl_by_ra(struct nxpwifi_private *priv, u8 *ra); +u8 nxpwifi_get_sec_chan_offset(int chan); + +static inline u8 +nxpwifi_is_station_ampdu_allowed(struct nxpwifi_private *priv, + struct nxpwifi_ra_list_tbl *ptr, int tid) +{ + struct nxpwifi_sta_node *node = nxpwifi_get_sta_entry(priv, ptr->ra); + + if (unlikely(!node)) + return false; + + return (node->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED) ? true : false; +} + +/* This function checks whether AMPDU is allowed or not for a particular TID. */ +static inline u8 +nxpwifi_is_ampdu_allowed(struct nxpwifi_private *priv, + struct nxpwifi_ra_list_tbl *ptr, int tid) +{ + u8 ret; + + if (is_broadcast_ether_addr(ptr->ra)) + return false; + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) + ret = nxpwifi_is_station_ampdu_allowed(priv, ptr, tid); + else + ret = (priv->aggr_prio_tbl[tid].ampdu_ap != + BA_STREAM_NOT_ALLOWED) ? true : false; + + return ret; +} + +/* This function checks whether AMSDU is allowed or not for a particular TID. + */ +static inline u8 +nxpwifi_is_amsdu_allowed(struct nxpwifi_private *priv, int tid) +{ + return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) && + (priv->is_data_rate_auto || !(priv->bitmap_rates[2] & 0x03))) + ? true : false); +} + +/* This function checks whether a space is available for new BA stream or not. + */ +static inline u8 +nxpwifi_space_avail_for_new_ba_stream(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + u8 i; + size_t ba_stream_num = 0, ba_stream_max; + + ba_stream_max = NXPWIFI_MAX_TX_BASTREAM_SUPPORTED; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) + ba_stream_num += + list_count_nodes(&priv->tx_ba_stream_tbl_ptr); + } + + if (adapter->fw_api_ver == NXPWIFI_FW_V15) { + ba_stream_max = + GETSUPP_TXBASTREAMS(adapter->hw_dot_11n_dev_cap); + if (!ba_stream_max) + ba_stream_max = NXPWIFI_MAX_TX_BASTREAM_SUPPORTED; + } + + return ((ba_stream_num < ba_stream_max) ? true : false); +} + +/* This function finds the correct Tx BA stream to delete. + * + * Upon successfully locating, both the TID and the RA are returned. + */ +static inline u8 +nxpwifi_find_stream_to_delete(struct nxpwifi_private *priv, int ptr_tid, + int *ptid, u8 *ra) +{ + int tid; + u8 ret = false; + struct nxpwifi_tx_ba_stream_tbl *tx_tbl; + + tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user; + + spin_lock_bh(&priv->tx_ba_stream_tbl_lock); + list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) { + tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user; + *ptid = tx_tbl->tid; + memcpy(ra, tx_tbl->ra, ETH_ALEN); + ret = true; + } + } + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); + + return ret; +} + +/* This function checks whether associated station is 11n enabled + */ +static inline int nxpwifi_is_sta_11n_enabled(struct nxpwifi_private *priv, + struct nxpwifi_sta_node *node) +{ + if (!node || (priv->bss_role == NXPWIFI_BSS_ROLE_UAP && + !priv->ap_11n_enabled)) + return 0; + + return node->is_11n_enabled; +} + +#endif /* !_NXPWIFI_11N_H_ */ From patchwork Fri Aug 9 09:44:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818395 Received: from DUZPR83CU001.outbound.protection.outlook.com (mail-northeuropeazon11013064.outbound.protection.outlook.com [52.101.67.64]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5207C1946B0; Fri, 9 Aug 2024 09:46:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.67.64 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196786; cv=fail; b=RsnuwvPFXXeGGiNYBgeK0zikwEyyhouJ1P1swkNZSZMzk4mctOXUT6RPaKcUZ3sx7eFQnk1ISaE4iqYK2oYELi8bDIP4/pDhBCmVU/4xzM0KtuJH8e9/2Bncy7YLwakAnhX1udb+F386lLWGvaceSeDomGsb+MhKHWbebS8+gfw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196786; c=relaxed/simple; bh=0CNz/25GMEbYYcYQxFZMmI2LMbIHPk/SDKijvl7H7ZU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=YLaQTaimMKYgQ5xiMUG8zIgMhzSQN42wwJ56p3pYz9qDM8oAlPerklw13lg12R9XXgh+fiKlBBtKOPdEbMO6NHvUUSCTGowSuFg0CZDIJU3D8ZrtKdZOIU+sSbXdIv0gSNmpddTb1xBw1T1tG45gF2IcYsfnSuSPtzzXOZ1xySw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=V4HgpJie; arc=fail smtp.client-ip=52.101.67.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="V4HgpJie" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=j31oXp1EHB0NpFv3KFnWv3MuOgIGKK1Z2u6pUrJqqtoyJoJgZkwrGYvvT6/urM+MlA69BAYQVi1iBjo+nOJAwot88Gqy7/pUJvmjxEq2fjT2hFkShbja7paI4AxyEqkb1gy4Nc+tPgFLInNHWHj9FhqVmYwoRvN9biSj/xzNxZ9Cd+H7rtckPfzK8wUf8qvocQVO7Xjv4xXIu4zG2jXbfxdsUV82QaHSOXDIN5uY4iIhJAsGyJEznRkNI0mbQvM2+8IuYHstNDL7Ht6Qofu5kAwNvPRzHl9n8XJflt31cx2oWIpnI5yORYEEBRPTkt9zS5cCYZrcS7Cnepw2hfEbeA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=J2DXrpx9hmOlKQwsxF0BPP2XgillHI6sHEcm28UpmPo=; b=R9XeDCh1eFUrpAC8j0N4ThLdS25KYVNeKfnOCCAh9GEyO2Oezq2U5rp5UmTbh2lSHTBnM3u1fkdGi+sd7UwG2Ea5KNHARyo8yvRqVxyfmYuioSOxkPQqdhbs3rq1h3Ysc2ALbK3O0Tv+dB5bZ5u0tOzFCI0bZRXZs2T/f14eOosUHgohiyLuO2PtSk8QJG/B2MuosYLJsappwWJ7H6S4MhDyWmHPlrmWHKtPsNi0+k4WPZWEm/qRh8cGI2ERVX/Gkqc3Cza+fWIdtJxSdiI1ngameCDdsDXFzL5Nu5IWIlVpyXR4+zR5Lw6OeUKvDyUPfZcTNvMd3swmgJVt0iZn7A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=J2DXrpx9hmOlKQwsxF0BPP2XgillHI6sHEcm28UpmPo=; b=V4HgpJie310fFThknTLq6d/aD1nNh7zvimA3SvCikc6f7uLtql5HScpPyBBWDnkCBgMsI6qZnm82EBAfhzPwloDm/OizZRe/WS9zoqapaLNmsl7YImOBZjRSZz3+GaMOQB7xx9e22ky4F2jj7FcYatacs3J5Omfhm8ljBy2esnLkrXKKAPXb7V4ey70+eNErDYmNxkb3cqRR1tuXOulkdU+v+BzUEVfC4Jx88v0aXJPIQOtlQYIdQ0bIinLAnI8JcrlTZiR45w/VuYvxu9ivmV9Ys8nGjm72gzOPqDj3vJkKdL6rh70tyC+jORCuJXjz0DXORxwZzvSeYIHSBQfL+g== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:17 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:17 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 08/43] wifi: nxpwifi: add 11n_rxreorder.c Date: Fri, 9 Aug 2024 17:44:58 +0800 Message-Id: <20240809094533.1660-9-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: 38994b04-bec0-42ef-7893-08dcb8581dac X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: 88jhYau1FLkjX3Hdb7RPrBTumypvtzLVbxU3CtizH4+ewgmYCbMitOX3tJ+P3aW+Wt0nLjYFwKKHYvDvrFo+BmqHbyau3SxH44Pi80d7g6w1jJOw6zAOzocqXO3pcWaio5wIF2ijkX8RogFIv7QjzfwAdOv5bUKKNGvN/guxhp10oKhyGKsGPbJPMHlbSpR9xmGU40xsBNJ+ZBOGsfTnvkNlgE0t0dyqbjtHfClZXfl2lM3KINZVXZcJH4l53LuKfrdB7uIea09JbsACqozQ7s/XVQN7ohN8WaKAUWiss8fAIknhcdLH5EJemIJ3GpF0UxVXSSAFx2L6n+lQ1r+ZHtwUDeK62Qvx2Dd9y66m+vSjNibWTlgJo/MyGlivHqkVQ7cyTgm8Ylszq2avXi2qOTsjk12nn2UjBod7kxULOd+T5x5RPdCCmjdHty971yG4kVlemvmpevaotoPMhWO6O1WO5MzUBvyNDoiHttTNu0wA5LeTUkXXhQuAz3CSnmpACrq/aIt+6vH34Hs8uL8LUzFftdUiQMwZkzKHWBAMhbm1YQfC7CR4dmc43juzjXp3hPJPVS5Gn0rpY726NsMMra+s+52KeaKbq2Vnqhm/ogz3tH4odh+4mKPDZj33W0YlWvW+9OsxBi1SwoHyHyRv1wsiIx/Iy8RKnjCRU7emjDMDSloLIwMjaBj+KEQTD0SFLq1epopy4AWHg/tWII3jGVYzRllbVoxtX4VqOrTNlyYEyh5Vi8SkTAjlZwOmxVbblVmsYYCdYBdkhqDE0SvEfSzuCup9oKs2+2mhDi2Z1QbDMTz+nOezf3w06D1hxVEZsTNyGEb0guWOCQ834ZU6Pj6xKop4mkYNp3VvbJWOWWg9X94a/OT7Yte+0WSSeG6UXlki8lhMvWNtX1nbEGQRVR6c/ARXj6DdSpoWOdhJSvZWU3jAtNmHSDeVoaTSRX6jxmP5mdL60JbkSWhZFY60vG/C6X7iAaCVMl6uimR2TJ0drA2ICz1rfkJ3mVMJdqgv589KBHKSdcHNuHSUOHCwwCU0J6dhI9RjY9ojE2n4xh9MkV92PpzUHvb5/KREimDaG7ePTXY9VivOxIO4Fd2gPf8qz6u7pUwaq9jjx4I2BiwFMtHC7Bv4F5o8GsNNV83nwnAcI8dgPDxyhyODPeJeGSYJFK/6GM1KJJRp27bIIpmhIt1+qMTygZCgBFkJzJfLv3VhEH0OnzARJsxJRUj65G+o8/z30ySYy0bcpSvspW/1eH8AsUaMtj47AU3/RWVIqKIZJgCeI8/S3TLrIP8JqZghmGA9yVWBjuERcXbl02kj4QLKm5yo6K+e0IT1+TDAv7QMt90DIPuD6uafJTkS/g== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: wmWkmjwR+10DkQFXpyHZRSXEuzzsHEM6X1fSP0gGRa1NULAr1LovU7KqH6KPhshPYttVwSFvnnIMpVL7mSc32eE6J3gb5O1RPYTaOYb7b0MBhI8pQySOdpoJhaE3JgHfyjOcQUjlPXhjV2A15JmsK3YQUrziCpqKwTS/JMMIDRfUV2I2DawChQRJI4X0bWUyi9AoFOqryS8Kj44e/z32qnIbp2xAZJHCozts1TuBeLHkqsTpqrP9r5e995VBjSrex7oS3u4bV3IeWGbS6ZZtNeC1SQHIMF/FZGd/Vle2GyS/53NaWmDcyJJnsRlhuHPUC+iS2svWQ31Rz0o3xR6VQkdCBwX/fPvZbUug+2QdIxzm454qvuNsIQozSfJs9n1Y697Xx0XPaYMrf5q97HnouPHh+l1cjU4yZRPj172OdfAtauw1A9ivasrTQdKMqkypfTlSfL6qeKj5OQBLkfZQC+a3CXRK+YZoc0dOQvNjxGYzHaiLIS1QBG0kwNEMcPfGT/+UEkA/1CeHWfTqxD4ARDejmDQqBhFvP9gZLJiM5pjWLrXqkRQjW44nnKQ/R3gVgxWJduYtpXk1cAvFj+CUlhrfggkXo1UoKNliqgHAyheh3xaHH0b4DbIXgiDNxF9CF+oruSSq9ZOk0RAlgbyk5oHmHDuCOdjaz829CVlutFed7Achec/FB1jDilCRuphTluWs4UZABj2ynKf/hDd+3W84N08HVY3ZR/y+hWHnGbG7qWFfAXdqKy2xuYVFSG9uKaSltkz5r9Tgedu7FUzmjSiuVIxnKmJJ/BJOTyNtounA5VY7v4nxU75B9EFOU9bOl7QsoZHBusoDEl2oxczdGUC8d3RvMTKrj3GT8Qwd/c9jq1uPslXsypIdEfL1YfbJsNImKQAsueeY+GY6hcgVPgFmE7ZXB81AnULzPSc/jtHuYsEIsHbuf1s5gheJhtARWPjgKICemQE7xOZSbTtdB1xJsNBKts8IIqO3BW3J6pOiUnSs+ukx130MqP/JH+FrR8soY715SHvaCnklkV5OCmEeiLhpaA1IpuPJfvjGemUHuNYjwej93ZgVyVzbyYrPs7CHx+Lg/T3A/PQfjfRzubPl0m/oITnMdWs63AmJaHOvvL1SCgtw+ZAlLFYW6p+zRhIFJsTmkSfV3n1VQQUEw5eRB1bc/JCOt1rOtccVK4uLCykWypFx/ctpKFD+3MQzw5XyZJOhbjfxZrvV3i1w26JV+eyNHu+8b7YgrlIIWPLybmNp3+tB8X2ghUxqmQjiAUBDMPrZuuTZh1756qI4OtyQxFZuO09FJ0Qg7lakNMW0OdtmzaLZKuyR93+7XzkXoHt8xgIt4ouD7eJdi8KCoIvl8VyZtu+Tw36olB2W/6urM4KosmeyKng0Qq0doOZV890Vo97uKwjCbkPJEzIoRqaE9ks32cFOjHezr0CsEzup2HuMFh9VJ7R+y4mgqad/ozeX2sSd35SZMI6Xx6Lp9psRumNwtk8xrMvoQ5AL2KLFmRPIkgluuywi7yGLfPc6QQ+YxV/1Lu8Jwc5om5wy2drWYq2z/0zC+UhDu6Aipo+Mna9RY2CEPGyFEYEJb+uxmm7M3OyzxYtwcVxX3q9odkYTTSp1VSGd3Jfixp3mOfOBnrjv3KuX4/iLBHstDuKp X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 38994b04-bec0-42ef-7893-08dcb8581dac X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:17.7702 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: w1g/fVQb+GWBeLxoVNzQywbI3VXNNeZpxPNe9iiWHurM/EBcxY/wA5eoTPeXy5SgpdQPHQxGonoEyVaZDWbqCw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- .../net/wireless/nxp/nxpwifi/11n_rxreorder.c | 917 ++++++++++++++++++ 1 file changed, 917 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c diff --git a/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c b/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c new file mode 100644 index 000000000000..f0407269942c --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c @@ -0,0 +1,917 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: 802.11n RX Re-ordering + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cmdevt.h" +#include "wmm.h" +#include "11n.h" +#include "11n_rxreorder.h" + +/* This function will dispatch amsdu packet and forward it to kernel/upper + * layer. + */ +static int nxpwifi_11n_dispatch_amsdu_pkt(struct nxpwifi_private *priv, + struct sk_buff *skb) +{ + struct rxpd *local_rx_pd = (struct rxpd *)(skb->data); + int ret; + + if (le16_to_cpu(local_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) { + struct sk_buff_head list; + struct sk_buff *rx_skb; + + __skb_queue_head_init(&list); + + skb_pull(skb, le16_to_cpu(local_rx_pd->rx_pkt_offset)); + skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length)); + + ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, + priv->wdev.iftype, 0, NULL, NULL, false); + + while (!skb_queue_empty(&list)) { + rx_skb = __skb_dequeue(&list); + + if (priv->bss_role == NXPWIFI_BSS_ROLE_UAP) + ret = nxpwifi_uap_recv_packet(priv, rx_skb); + else + ret = nxpwifi_recv_packet(priv, rx_skb); + if (ret) + nxpwifi_dbg(priv->adapter, ERROR, + "Rx of A-MSDU failed"); + } + return 0; + } + + return -EINVAL; +} + +/* This function will process the rx packet and forward it to kernel/upper + * layer. + */ +static int nxpwifi_11n_dispatch_pkt(struct nxpwifi_private *priv, + struct sk_buff *payload) +{ + int ret; + + if (!payload) { + nxpwifi_dbg(priv->adapter, INFO, "info: fw drop data\n"); + return 0; + } + + ret = nxpwifi_11n_dispatch_amsdu_pkt(priv, payload); + if (!ret) + return 0; + + if (priv->bss_role == NXPWIFI_BSS_ROLE_UAP) + return nxpwifi_handle_uap_rx_forward(priv, payload); + + return nxpwifi_process_rx_packet(priv, payload); +} + +/* This function dispatches all packets in the Rx reorder table until the + * start window. + * + * There could be holes in the buffer, which are skipped by the function. + * Since the buffer is linear, the function uses rotation to simulate + * circular buffer. + */ +static void +nxpwifi_11n_dispatch_pkt_until_start_win(struct nxpwifi_private *priv, + struct nxpwifi_rx_reorder_tbl *tbl, + int start_win) +{ + struct sk_buff_head list; + struct sk_buff *skb; + int pkt_to_send, i; + + __skb_queue_head_init(&list); + spin_lock_bh(&priv->rx_reorder_tbl_lock); + + pkt_to_send = (start_win > tbl->start_win) ? + min((start_win - tbl->start_win), tbl->win_size) : + tbl->win_size; + + for (i = 0; i < pkt_to_send; ++i) { + if (tbl->rx_reorder_ptr[i]) { + skb = tbl->rx_reorder_ptr[i]; + __skb_queue_tail(&list, skb); + tbl->rx_reorder_ptr[i] = NULL; + } + } + + /* We don't have a circular buffer, hence use rotation to simulate + * circular buffer + */ + for (i = 0; i < tbl->win_size - pkt_to_send; ++i) { + tbl->rx_reorder_ptr[i] = tbl->rx_reorder_ptr[pkt_to_send + i]; + tbl->rx_reorder_ptr[pkt_to_send + i] = NULL; + } + + tbl->start_win = start_win; + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + + while ((skb = __skb_dequeue(&list))) + nxpwifi_11n_dispatch_pkt(priv, skb); +} + +/* This function dispatches all packets in the Rx reorder table until + * a hole is found. + * + * The start window is adjusted automatically when a hole is located. + * Since the buffer is linear, the function uses rotation to simulate + * circular buffer. + */ +static void +nxpwifi_11n_scan_and_dispatch(struct nxpwifi_private *priv, + struct nxpwifi_rx_reorder_tbl *tbl) +{ + struct sk_buff_head list; + struct sk_buff *skb; + int i, j, xchg; + + __skb_queue_head_init(&list); + spin_lock_bh(&priv->rx_reorder_tbl_lock); + + for (i = 0; i < tbl->win_size; ++i) { + if (!tbl->rx_reorder_ptr[i]) + break; + skb = tbl->rx_reorder_ptr[i]; + __skb_queue_tail(&list, skb); + tbl->rx_reorder_ptr[i] = NULL; + } + + /* We don't have a circular buffer, hence use rotation to simulate + * circular buffer + */ + if (i > 0) { + xchg = tbl->win_size - i; + for (j = 0; j < xchg; ++j) { + tbl->rx_reorder_ptr[j] = tbl->rx_reorder_ptr[i + j]; + tbl->rx_reorder_ptr[i + j] = NULL; + } + } + tbl->start_win = (tbl->start_win + i) & (MAX_TID_VALUE - 1); + + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + + while ((skb = __skb_dequeue(&list))) + nxpwifi_11n_dispatch_pkt(priv, skb); +} + +/* This function deletes the Rx reorder table and frees the memory. + * + * The function stops the associated timer and dispatches all the + * pending packets in the Rx reorder table before deletion. + */ +static void +nxpwifi_del_rx_reorder_entry(struct nxpwifi_private *priv, + struct nxpwifi_rx_reorder_tbl *tbl) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + int start_win; + + if (!tbl) + return; + + tasklet_disable(&adapter->rx_task); + + start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1); + nxpwifi_11n_dispatch_pkt_until_start_win(priv, tbl, start_win); + + del_timer_sync(&tbl->timer_context.timer); + tbl->timer_context.timer_is_set = false; + + spin_lock_bh(&priv->rx_reorder_tbl_lock); + list_del(&tbl->list); + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + + kfree(tbl->rx_reorder_ptr); + kfree(tbl); + + tasklet_enable(&adapter->rx_task); +} + +/* This function returns the pointer to an entry in Rx reordering + * table which matches the given TA/TID pair. + */ +struct nxpwifi_rx_reorder_tbl * +nxpwifi_11n_get_rx_reorder_tbl(struct nxpwifi_private *priv, int tid, u8 *ta) +{ + struct nxpwifi_rx_reorder_tbl *tbl; + + spin_lock_bh(&priv->rx_reorder_tbl_lock); + list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) { + if (!memcmp(tbl->ta, ta, ETH_ALEN) && tbl->tid == tid) { + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + return tbl; + } + } + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + + return NULL; +} + +/* This function retrieves the pointer to an entry in Rx reordering + * table which matches the given TA and deletes it. + */ +void nxpwifi_11n_del_rx_reorder_tbl_by_ta(struct nxpwifi_private *priv, u8 *ta) +{ + struct nxpwifi_rx_reorder_tbl *tbl, *tmp; + + if (!ta) + return; + + spin_lock_bh(&priv->rx_reorder_tbl_lock); + list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) { + if (!memcmp(tbl->ta, ta, ETH_ALEN)) { + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + nxpwifi_del_rx_reorder_entry(priv, tbl); + spin_lock_bh(&priv->rx_reorder_tbl_lock); + } + } + spin_unlock_bh(&priv->rx_reorder_tbl_lock); +} + +/* This function finds the last sequence number used in the packets + * buffered in Rx reordering table. + */ +static int +nxpwifi_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx) +{ + struct nxpwifi_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr; + struct nxpwifi_private *priv = ctx->priv; + int i; + + spin_lock_bh(&priv->rx_reorder_tbl_lock); + for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) { + if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) { + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + return i; + } + } + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + + return -EINVAL; +} + +/* This function flushes all the packets in Rx reordering table. + * + * The function checks if any packets are currently buffered in the + * table or not. In case there are packets available, it dispatches + * them and then dumps the Rx reordering table. + */ +static void +nxpwifi_flush_data(struct timer_list *t) +{ + struct reorder_tmr_cnxt *ctx = + from_timer(ctx, t, timer); + int start_win, seq_num; + + ctx->timer_is_set = false; + seq_num = nxpwifi_11n_find_last_seq_num(ctx); + + if (seq_num < 0) + return; + + nxpwifi_dbg(ctx->priv->adapter, INFO, "info: flush data %d\n", seq_num); + start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1); + nxpwifi_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr, + start_win); +} + +/* This function creates an entry in Rx reordering table for the + * given TA/TID. + * + * The function also initializes the entry with sequence number, window + * size as well as initializes the timer. + * + * If the received TA/TID pair is already present, all the packets are + * dispatched and the window size is moved until the SSN. + */ +static void +nxpwifi_11n_create_rx_reorder_tbl(struct nxpwifi_private *priv, u8 *ta, + int tid, int win_size, int seq_num) +{ + int i; + struct nxpwifi_rx_reorder_tbl *tbl, *new_node; + u16 last_seq = 0; + struct nxpwifi_sta_node *node; + + /* If we get a TID, ta pair which is already present dispatch all + * the packets and move the window size until the ssn + */ + tbl = nxpwifi_11n_get_rx_reorder_tbl(priv, tid, ta); + if (tbl) { + nxpwifi_11n_dispatch_pkt_until_start_win(priv, tbl, seq_num); + return; + } + /* if !tbl then create one */ + new_node = kzalloc(sizeof(*new_node), GFP_KERNEL); + if (!new_node) + return; + + INIT_LIST_HEAD(&new_node->list); + new_node->tid = tid; + memcpy(new_node->ta, ta, ETH_ALEN); + new_node->start_win = seq_num; + new_node->init_win = seq_num; + new_node->flags = 0; + + spin_lock_bh(&priv->sta_list_spinlock); + if (nxpwifi_queuing_ra_based(priv)) { + if (priv->bss_role == NXPWIFI_BSS_ROLE_UAP) { + node = nxpwifi_get_sta_entry(priv, ta); + if (node) + last_seq = node->rx_seq[tid]; + } + } else { + node = nxpwifi_get_sta_entry(priv, ta); + if (node) + last_seq = node->rx_seq[tid]; + else + last_seq = priv->rx_seq[tid]; + } + spin_unlock_bh(&priv->sta_list_spinlock); + + nxpwifi_dbg(priv->adapter, INFO, + "info: last_seq=%d start_win=%d\n", + last_seq, new_node->start_win); + + if (last_seq != NXPWIFI_DEF_11N_RX_SEQ_NUM && + last_seq >= new_node->start_win) { + new_node->start_win = last_seq + 1; + new_node->flags |= RXREOR_INIT_WINDOW_SHIFT; + } + + new_node->win_size = win_size; + + new_node->rx_reorder_ptr = kcalloc(win_size, sizeof(void *), + GFP_KERNEL); + if (!new_node->rx_reorder_ptr) { + kfree(new_node); + nxpwifi_dbg(priv->adapter, ERROR, + "%s: failed to alloc reorder_ptr\n", __func__); + return; + } + + new_node->timer_context.ptr = new_node; + new_node->timer_context.priv = priv; + new_node->timer_context.timer_is_set = false; + + timer_setup(&new_node->timer_context.timer, nxpwifi_flush_data, 0); + + for (i = 0; i < win_size; ++i) + new_node->rx_reorder_ptr[i] = NULL; + + spin_lock_bh(&priv->rx_reorder_tbl_lock); + list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr); + spin_unlock_bh(&priv->rx_reorder_tbl_lock); +} + +static void +nxpwifi_11n_rxreorder_timer_restart(struct nxpwifi_rx_reorder_tbl *tbl) +{ + u32 min_flush_time; + + if (tbl->win_size >= NXPWIFI_BA_WIN_SIZE_32) + min_flush_time = MIN_FLUSH_TIMER_15_MS; + else + min_flush_time = MIN_FLUSH_TIMER_MS; + + mod_timer(&tbl->timer_context.timer, + jiffies + msecs_to_jiffies(min_flush_time * tbl->win_size)); + + tbl->timer_context.timer_is_set = true; +} + +/* This function prepares command for adding a BA request. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting add BA request buffer + * - Ensuring correct endian-ness + */ +int nxpwifi_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_11n_addba_req *add_ba_req = &cmd->params.add_ba_req; + + cmd->command = cpu_to_le16(HOST_CMD_11N_ADDBA_REQ); + cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN); + memcpy(add_ba_req, data_buf, sizeof(*add_ba_req)); + + return 0; +} + +/* This function prepares command for adding a BA response. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting add BA response buffer + * - Ensuring correct endian-ness + */ +int nxpwifi_cmd_11n_addba_rsp_gen(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + struct host_cmd_ds_11n_addba_req + *cmd_addba_req) +{ + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &cmd->params.add_ba_rsp; + u32 rx_win_size = priv->add_ba_param.rx_win_size; + u8 tid; + int win_size; + u16 block_ack_param_set; + + cmd->command = cpu_to_le16(HOST_CMD_11N_ADDBA_RSP); + cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN); + + memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr, + ETH_ALEN); + add_ba_rsp->dialog_token = cmd_addba_req->dialog_token; + add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo; + add_ba_rsp->ssn = cmd_addba_req->ssn; + + block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set); + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT); + block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; + + /* If we don't support AMSDU inside AMPDU, reset the bit */ + if (!priv->add_ba_param.rx_amsdu || + priv->aggr_prio_tbl[tid].amsdu == BA_STREAM_NOT_ALLOWED) + block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; + block_ack_param_set |= rx_win_size << BLOCKACKPARAM_WINSIZE_POS; + add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set); + win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set) + & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) + >> BLOCKACKPARAM_WINSIZE_POS; + cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set); + + nxpwifi_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr, + tid, win_size, + le16_to_cpu(cmd_addba_req->ssn)); + return 0; +} + +/* This function prepares command for deleting a BA request. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting del BA request buffer + * - Ensuring correct endian-ness + */ +int nxpwifi_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_11n_delba *del_ba = &cmd->params.del_ba; + + cmd->command = cpu_to_le16(HOST_CMD_11N_DELBA); + cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN); + memcpy(del_ba, data_buf, sizeof(*del_ba)); + + return 0; +} + +/* This function identifies if Rx reordering is needed for a received packet. + * + * In case reordering is required, the function will do the reordering + * before sending it to kernel. + * + * The Rx reorder table is checked first with the received TID/TA pair. If + * not found, the received packet is dispatched immediately. But if found, + * the packet is reordered and all the packets in the updated Rx reordering + * table is dispatched until a hole is found. + * + * For sequence number less than the starting window, the packet is dropped. + */ +int nxpwifi_11n_rx_reorder_pkt(struct nxpwifi_private *priv, + u16 seq_num, u16 tid, + u8 *ta, u8 pkt_type, void *payload) +{ + struct nxpwifi_rx_reorder_tbl *tbl; + int prev_start_win, start_win, end_win, win_size; + u16 pkt_index; + bool init_window_shift = false; + int ret = 0; + + tbl = nxpwifi_11n_get_rx_reorder_tbl(priv, tid, ta); + if (!tbl) { + if (pkt_type != PKT_TYPE_BAR) + nxpwifi_11n_dispatch_pkt(priv, payload); + return ret; + } + + if (pkt_type == PKT_TYPE_AMSDU && !tbl->amsdu) { + nxpwifi_11n_dispatch_pkt(priv, payload); + return ret; + } + + start_win = tbl->start_win; + prev_start_win = start_win; + win_size = tbl->win_size; + end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); + if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) { + init_window_shift = true; + tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT; + } + + if (tbl->flags & RXREOR_FORCE_NO_DROP) { + nxpwifi_dbg(priv->adapter, INFO, + "RXREOR_FORCE_NO_DROP when HS is activated\n"); + tbl->flags &= ~RXREOR_FORCE_NO_DROP; + } else if (init_window_shift && seq_num < start_win && + seq_num >= tbl->init_win) { + nxpwifi_dbg(priv->adapter, INFO, + "Sender TID sequence number reset %d->%d for SSN %d\n", + start_win, seq_num, tbl->init_win); + start_win = seq_num; + tbl->start_win = start_win; + end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); + } else { + /* If seq_num is less then starting win then ignore and drop + * the packet + */ + if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) { + if (seq_num >= ((start_win + TWOPOW11) & + (MAX_TID_VALUE - 1)) && + seq_num < start_win) { + ret = -EINVAL; + goto done; + } + } else if ((seq_num < start_win) || + (seq_num >= (start_win + TWOPOW11))) { + ret = -EINVAL; + goto done; + } + } + + /* If this packet is a BAR we adjust seq_num as + * WinStart = seq_num + */ + if (pkt_type == PKT_TYPE_BAR) + seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1); + + if ((end_win < start_win && + seq_num < start_win && seq_num > end_win) || + (end_win > start_win && (seq_num > end_win || + seq_num < start_win))) { + end_win = seq_num; + if (((end_win - win_size) + 1) >= 0) + start_win = (end_win - win_size) + 1; + else + start_win = (MAX_TID_VALUE - (win_size - end_win)) + 1; + nxpwifi_11n_dispatch_pkt_until_start_win(priv, tbl, start_win); + } + + if (pkt_type != PKT_TYPE_BAR) { + if (seq_num >= start_win) + pkt_index = seq_num - start_win; + else + pkt_index = (seq_num + MAX_TID_VALUE) - start_win; + + if (tbl->rx_reorder_ptr[pkt_index]) { + ret = -EINVAL; + goto done; + } + + tbl->rx_reorder_ptr[pkt_index] = payload; + } + + /* Dispatch all packets sequentially from start_win until a + * hole is found and adjust the start_win appropriately + */ + nxpwifi_11n_scan_and_dispatch(priv, tbl); + +done: + if (!tbl->timer_context.timer_is_set || + prev_start_win != tbl->start_win) + nxpwifi_11n_rxreorder_timer_restart(tbl); + return ret; +} + +/* This function deletes an entry for a given TID/TA pair. + * + * The TID/TA are taken from del BA event body. + */ +void +nxpwifi_del_ba_tbl(struct nxpwifi_private *priv, int tid, u8 *peer_mac, + u8 type, int initiator) +{ + struct nxpwifi_rx_reorder_tbl *tbl; + struct nxpwifi_tx_ba_stream_tbl *ptx_tbl; + struct nxpwifi_ra_list_tbl *ra_list; + u8 cleanup_rx_reorder_tbl; + int tid_down; + + if (type == TYPE_DELBA_RECEIVE) + cleanup_rx_reorder_tbl = (initiator) ? true : false; + else + cleanup_rx_reorder_tbl = (initiator) ? false : true; + + nxpwifi_dbg(priv->adapter, EVENT, "event: DELBA: %pM tid=%d initiator=%d\n", + peer_mac, tid, initiator); + + if (cleanup_rx_reorder_tbl) { + tbl = nxpwifi_11n_get_rx_reorder_tbl(priv, tid, peer_mac); + if (!tbl) { + nxpwifi_dbg(priv->adapter, EVENT, + "event: TID, TA not found in table\n"); + return; + } + nxpwifi_del_rx_reorder_entry(priv, tbl); + } else { + ptx_tbl = nxpwifi_get_ba_tbl(priv, tid, peer_mac); + if (!ptx_tbl) { + nxpwifi_dbg(priv->adapter, EVENT, + "event: TID, RA not found in table\n"); + return; + } + + tid_down = nxpwifi_wmm_downgrade_tid(priv, tid); + ra_list = nxpwifi_wmm_get_ralist_node(priv, tid_down, peer_mac); + if (ra_list) { + ra_list->amsdu_in_ampdu = false; + ra_list->ba_status = BA_SETUP_NONE; + } + spin_lock_bh(&priv->tx_ba_stream_tbl_lock); + nxpwifi_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); + spin_unlock_bh(&priv->tx_ba_stream_tbl_lock); + } +} + +/* This function handles the command response of an add BA response. + * + * Handling includes changing the header fields into CPU format and + * creating the stream, provided the add BA is accepted. + */ +int nxpwifi_ret_11n_addba_resp(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp; + int tid, win_size; + struct nxpwifi_rx_reorder_tbl *tbl; + u16 block_ack_param_set; + + block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); + + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + /* Check if we had rejected the ADDBA, if yes then do not create + * the stream + */ + if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { + nxpwifi_dbg(priv->adapter, ERROR, "ADDBA RSP: failed %pM tid=%d)\n", + add_ba_rsp->peer_mac_addr, tid); + + tbl = nxpwifi_11n_get_rx_reorder_tbl(priv, tid, + add_ba_rsp->peer_mac_addr); + if (tbl) + nxpwifi_del_rx_reorder_entry(priv, tbl); + + return 0; + } + + win_size = (block_ack_param_set & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) + >> BLOCKACKPARAM_WINSIZE_POS; + + tbl = nxpwifi_11n_get_rx_reorder_tbl(priv, tid, + add_ba_rsp->peer_mac_addr); + if (tbl) { + if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) && + priv->add_ba_param.rx_amsdu && + priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) + tbl->amsdu = true; + else + tbl->amsdu = false; + } + + nxpwifi_dbg(priv->adapter, CMD, + "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n", + add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size); + + return 0; +} + +/* This function handles BA stream timeout event by preparing and sending + * a command to the firmware. + */ +void nxpwifi_11n_ba_stream_timeout(struct nxpwifi_private *priv, + struct host_cmd_ds_11n_batimeout *event) +{ + struct host_cmd_ds_11n_delba delba; + + memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba)); + memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN); + + delba.del_ba_param_set |= + cpu_to_le16((u16)event->tid << DELBA_TID_POS); + delba.del_ba_param_set |= + cpu_to_le16((u16)event->origninator << DELBA_INITIATOR_POS); + delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); + nxpwifi_send_cmd(priv, HOST_CMD_11N_DELBA, 0, 0, &delba, false); +} + +/* This function cleans up the Rx reorder table by deleting all the entries + * and re-initializing. + */ +void nxpwifi_11n_cleanup_reorder_tbl(struct nxpwifi_private *priv) +{ + struct nxpwifi_rx_reorder_tbl *del_tbl_ptr, *tmp_node; + + spin_lock_bh(&priv->rx_reorder_tbl_lock); + list_for_each_entry_safe(del_tbl_ptr, tmp_node, + &priv->rx_reorder_tbl_ptr, list) { + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + nxpwifi_del_rx_reorder_entry(priv, del_tbl_ptr); + spin_lock_bh(&priv->rx_reorder_tbl_lock); + } + INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + + nxpwifi_reset_11n_rx_seq_num(priv); +} + +/* This function updates all rx_reorder_tbl's flags. + */ +void nxpwifi_update_rxreor_flags(struct nxpwifi_adapter *adapter, u8 flags) +{ + struct nxpwifi_private *priv; + struct nxpwifi_rx_reorder_tbl *tbl; + int i; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (!priv) + continue; + + spin_lock_bh(&priv->rx_reorder_tbl_lock); + list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) + tbl->flags = flags; + spin_unlock_bh(&priv->rx_reorder_tbl_lock); + } +} + +/* This function update all the rx_win_size based on coex flag + */ +static void nxpwifi_update_ampdu_rxwinsize(struct nxpwifi_adapter *adapter, + bool coex_flag) +{ + u8 i; + u32 rx_win_size; + struct nxpwifi_private *priv; + + dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag); + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i]) + continue; + priv = adapter->priv[i]; + rx_win_size = priv->add_ba_param.rx_win_size; + if (coex_flag) { + if (priv->bss_type == NXPWIFI_BSS_TYPE_STA) + priv->add_ba_param.rx_win_size = + NXPWIFI_STA_COEX_AMPDU_DEF_RXWINSIZE; + if (priv->bss_type == NXPWIFI_BSS_TYPE_UAP) + priv->add_ba_param.rx_win_size = + NXPWIFI_UAP_COEX_AMPDU_DEF_RXWINSIZE; + } else { + if (priv->bss_type == NXPWIFI_BSS_TYPE_STA) + priv->add_ba_param.rx_win_size = + NXPWIFI_STA_AMPDU_DEF_RXWINSIZE; + if (priv->bss_type == NXPWIFI_BSS_TYPE_UAP) + priv->add_ba_param.rx_win_size = + NXPWIFI_UAP_AMPDU_DEF_RXWINSIZE; + } + + if (adapter->coex_win_size && adapter->coex_rx_win_size) + priv->add_ba_param.rx_win_size = + adapter->coex_rx_win_size; + + if (rx_win_size != priv->add_ba_param.rx_win_size) { + if (!priv->media_connected) + continue; + for (i = 0; i < MAX_NUM_TID; i++) + nxpwifi_11n_delba(priv, i); + } + } +} + +/* This function check coex for RX BA + */ +void nxpwifi_coex_ampdu_rxwinsize(struct nxpwifi_adapter *adapter) +{ + u8 i; + struct nxpwifi_private *priv; + u8 count = 0; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA) { + if (priv->media_connected) + count++; + } + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) { + if (priv->bss_started) + count++; + } + } + if (count >= NXPWIFI_BSS_COEX_COUNT) + break; + } + if (count >= NXPWIFI_BSS_COEX_COUNT) + nxpwifi_update_ampdu_rxwinsize(adapter, true); + else + nxpwifi_update_ampdu_rxwinsize(adapter, false); +} + +/* This function handles rxba_sync event + */ +void nxpwifi_11n_rxba_sync_event(struct nxpwifi_private *priv, + u8 *event_buf, u16 len) +{ + struct nxpwifi_ie_types_rxba_sync *tlv_rxba = (void *)event_buf; + u16 tlv_type, tlv_len; + struct nxpwifi_rx_reorder_tbl *rx_reor_tbl_ptr; + u8 i, j; + u16 seq_num, tlv_seq_num, tlv_bitmap_len; + int tlv_buf_left = len; + int ret; + u8 *tmp; + + nxpwifi_dbg_dump(priv->adapter, EVT_D, "RXBA_SYNC event:", + event_buf, len); + while (tlv_buf_left > sizeof(*tlv_rxba)) { + tlv_type = le16_to_cpu(tlv_rxba->header.type); + tlv_len = le16_to_cpu(tlv_rxba->header.len); + if (size_add(sizeof(tlv_rxba->header), tlv_len) > tlv_buf_left) { + nxpwifi_dbg(priv->adapter, WARN, + "TLV size (%zu) overflows event_buf buf_left=%d\n", + size_add(sizeof(tlv_rxba->header), tlv_len), + tlv_buf_left); + return; + } + + if (tlv_type != TLV_TYPE_RXBA_SYNC) { + nxpwifi_dbg(priv->adapter, ERROR, + "Wrong TLV id=0x%x\n", tlv_type); + return; + } + + tlv_seq_num = le16_to_cpu(tlv_rxba->seq_num); + tlv_bitmap_len = le16_to_cpu(tlv_rxba->bitmap_len); + if (size_add(sizeof(*tlv_rxba), tlv_bitmap_len) > tlv_buf_left) { + nxpwifi_dbg(priv->adapter, WARN, + "TLV size (%zu) overflows event_buf buf_left=%d\n", + size_add(sizeof(*tlv_rxba), tlv_bitmap_len), + tlv_buf_left); + return; + } + + nxpwifi_dbg(priv->adapter, INFO, + "%pM tid=%d seq_num=%d bitmap_len=%d\n", + tlv_rxba->mac, tlv_rxba->tid, tlv_seq_num, + tlv_bitmap_len); + + rx_reor_tbl_ptr = + nxpwifi_11n_get_rx_reorder_tbl(priv, tlv_rxba->tid, + tlv_rxba->mac); + if (!rx_reor_tbl_ptr) { + nxpwifi_dbg(priv->adapter, ERROR, + "Can not find rx_reorder_tbl!"); + return; + } + + for (i = 0; i < tlv_bitmap_len; i++) { + for (j = 0 ; j < 8; j++) { + if (tlv_rxba->bitmap[i] & (1 << j)) { + seq_num = (MAX_TID_VALUE - 1) & + (tlv_seq_num + i * 8 + j); + + nxpwifi_dbg(priv->adapter, ERROR, + "drop packet,seq=%d\n", + seq_num); + + ret = nxpwifi_11n_rx_reorder_pkt + (priv, seq_num, tlv_rxba->tid, + tlv_rxba->mac, 0, NULL); + + if (ret) + nxpwifi_dbg(priv->adapter, + ERROR, + "Fail to drop packet"); + } + } + } + + tlv_buf_left -= (sizeof(tlv_rxba->header) + tlv_len); + tmp = (u8 *)tlv_rxba + sizeof(tlv_rxba->header) + tlv_len; + tlv_rxba = (struct nxpwifi_ie_types_rxba_sync *)tmp; + } +} From patchwork Fri Aug 9 09:44:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818280 Received: from DUZPR83CU001.outbound.protection.outlook.com (mail-northeuropeazon11013064.outbound.protection.outlook.com [52.101.67.64]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A039F194A42; Fri, 9 Aug 2024 09:46:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.67.64 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196788; cv=fail; b=PYtgj0BwSunGoQrAr606c/YrvcLf6enAN1TLWIWvbaeWUmM05tOA1k79AGNwaFTNKO/9F2onrUyHaJaddE/u9L/yy1qOSfZfvstauypRDkSGDjC9/HVWnFtmtR0Knde4tVlnxO6N9YCJg+OUczCnukAzYRw56ELucpyBLToe820= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196788; c=relaxed/simple; bh=znWLtTkFM76wGBuVsUdfZMDp40n4XqPUorbBvxwHMzQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=i/qTn164bIOYqyzejsmszXJkAJEQdZGvvrQdtuDz7k+K+4IB1Akbr7KRT7igCcf0xGJGVixIurJS8V1pUV9nWySRCuVkXXBIhf0OuvZ/bNoCX0Ebup5SQQHyHknbjarpmtC5zy1v7wKwCTQiYbGurrtmLHZ0AzWK+zY5UhH+HLU= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=Sz2o6YZY; arc=fail smtp.client-ip=52.101.67.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="Sz2o6YZY" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=FbonYZ7ke312MdB/NtTbYwZ8+n5d35Y2EmOdWHxlfjdQpDTkUvil0IEd2dxvurLjY67bSj1F0htx2fPHGNqGACP+0GY8nR4BEN3xjS8tg3tfmsiIpTWimImBbRHMfgbm/kjjXOFmPxDhoOQwrtizLirRImwU+btd3HKmsWa1jXNrEeTvOje9Htf8mQGZPElC4+qN64Ix9jn2jS0H/cePLC9SkihY1iAbI3ZXk9/X20yUYToFu1cE8zzq92vMg12xltSIXQ2FoRg9P4hdWlvTFkMpykT2mqpSCwvO3yBuvQzpD2TQQB0LpX5GSTNO5fNCQi5uBC5jZfSEU4qGZcFgOQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=D3boSOwEh0i1qO6vUWvAJ9pNPb0xhMcSZHsWqmugtc8=; b=dMruA+ySyZLbajpAsoeTM9OgU+om5hyxWSkVNenb+jZ8daCSpFZ8yXPvBd0Xoio5bbWxgMYoQo6d7AXsmd1dq+iDkssd4zdem7/YIEtYRDoAeVNJDZKOcZwngeazcQC4w6nVnOmuAna0cQ22b6xwsv3kyNp9D+zKWXEvBlHx3yt+oKY1SQc6PomZtGvj4ovgdTK9Sgofeovg13mmi4sioUKket8I93EKu8rJU+BRpQhbAcc6SGXHb1ZYXSB+UZHFTMAFJCG9zw4Bp9IUnjmjHPI/6Yd49/SWbNgHh/w7ZGHgQWevg1hEyOqhenT+W51FDEPayhJtIvTphwGZkNBU2Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=D3boSOwEh0i1qO6vUWvAJ9pNPb0xhMcSZHsWqmugtc8=; b=Sz2o6YZYm/9g/K5ITQfyIEwLcHPo+LOs0EhdpbAfYNG0GJk5yiMybxy/wYd8Y9a5dw1meU5+33yfb869NjLEyjrWwrd0HEKebOIhvhxcJNuBlZS/1HYJmzZbu8CeHSpcYmSKb4L9MorNAPNEMshGtxMvkNMoWzPfA7PZfJfN0cnhCmvlFXJ7+sv9b2jqoc7KCLdBOjRJ5C55NK6oBx+kI0GETzrdeh2e8UOiVMn59P7/grY6DRZf0Yh8Ewk1T6teTLhwYDnorwYGZ3e7xu4f12SqGvDpWam+39gmV7B50LFRrWN3CLua1fWLncrYerFa3iD6TPvng4qLkUSt8nUGFw== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:21 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:21 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 09/43] wifi: nxpwifi: add 11n_rxreorder.h Date: Fri, 9 Aug 2024 17:44:59 +0800 Message-Id: <20240809094533.1660-10-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: db09b283-f7b6-451d-76e5-08dcb8581fc6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: VwTNdyct9c6w4Q/e6lhNSwtSnZCQjGsNkJlFmXbSkZw+5x1if4TgfhqxXvhZFeugWE/PxG5l05qKRhCklHO7+YgiA5v4c9jACSoLZnq7i3dc1AzN6irAUG37GzXXTMq1MYCcsVK/rFeZ4+zjrIZKo7RCKhDIM0bhZRD6FqKpr3k6oHawUc2xoHkILPdYsv0bvEFyxif8hOBbdH12lPEOqfILJtirUNaxa642qdkTcV6seB0K0a3tqBChqWinKwq23KMMGSrdI2ZV6b9/P2+J/fhxMP0eFSuPdNbop2+WiDvX1C1JEoFHFLKg4GsuGg3mm4Y1eDcd485pH8ASyQBKqjXmTv1YvOEWf21hIrmCvrR+9k2PUe++Mh9Xd+Kqn6AoYHN9EGRsrHMt26mTqM3+C7YycZdJIDe+9uoKrmAzAgZ/eUHkYSP42+GNFzRJXOoZZYDVlFE6KeHYpOdv6I8FFNAG1ZXWht1QP5mf6JCb+eNaJ7BEERZ390S7c3YLCyhEqNjVel2TvWjQz8dIGBJnKbiaFI9OxJmWIIqC2tqgy/tYBSoMdrGPGWhMhj8wkDhrzbZkjJ5UesLkhFZxSxZDinir0StcUZQjz+n0CZbY1frnxjzkL6qthPWP2AtbLOILBfH6+tbE3Z/hCgUPzkqo61/WUX5E59EhX6eDYfGXNN3KAW4C3n1MeeeyZCHmhpDV8wjESwAYmqoAQTjTWRXq5UPf96Z+krnrblWDnXYyXbbRsrX29E7F3OkQdJe2fJiAzoNh5Q+zntMd+IkA+Wq9GS0n8+zCPm9ZHByj6urrkYvzF/u3DNZqiKqLFF0ey4SsnDjx7YB3BBttgJ9ghF9jTsRrULoIWPNNTZdhaYSme5g+Hb4g9gWFroPJPRJHSyMXxj+WNUbVof7NdCCdAo+/ypfKZU3WsqXj5D5rKvdav4nhasIyIOdJMECDZWEzkSHiotT8MFYho2/9tz9fpb6XeLqLmMO9QKQOB39ScR4OwyluKPam1pbxM0VNrY05uiGi42xVj43TpefP8cFK8wG/ESWzbDq9mKRTnbbcHDLB7bCqndEUZbdNBBBMq5N+z6vxa+O76qKUXVBzwRqYd/ADyEh59/6kwlOdFcIqOcIGyZ5o6z4GVO/kwguFwbm3BanIZTnAMAVX9t5OYgDMArzUp2NNNeGK3fqJ+gHtODQ6Ee1CKAYJ4PlauXRitqr08393BA9umyodWPIOhLwvXF2jQBx4oNgcxBvjT/kQtlIzUuXEVA5DmOjrRXlh52m3LQkWuUQliSyOYTfW5LyVA7RyLTC7WEfaDXuT/QgoqIzV3NgL74kntG/v+G9ImiroXxJctJR8TMIC6BToKZtP9LDgWA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: YW7VxbQSYrl6bC1s5FWN0I8CwvfUI34ig/xPfmTosJcokBhg/3P7DguUVkI3uNw8Cio2QHD/4ZOcjfNH3Qm04zXcZWkr1awv8fXvhVCupd1b+M87oR50dXty+9//ZuqTCdpAnzJ7qpvR43oVv9Qq7bSntBk5HU939tFHzgkc1CYmx/EcWVdXewrR3AVyei9/LwMpbeCGDQcSOqX0MAcXFufq3af3MOYAWo2nvbfsFkAEfTidYG3xrTJ+mZvwEJsxK6aRezdrnlzFidSBd5Fp1i1qGAhPlC19w//eV4Qw0wQyW5/fE7FFN+VJRcA/jqJtuQAiDJUHWSTq4e6lY0RLmiMLWkkdX14RVdjOqWSn0DYOoyqr0tqhA94wQnJiT7twtYPdL5NJ/YLx9M5oKbtZIwOoCZNBsxHGPBxkdyS4XHyl+DbIii+k199LAiiDfkplqbsmzmtMdQRdXwxOQIy1XlTqrQL1DqFBa0EN5KEPj2if65K6zBMetsEHZGc60Bw6XEk6AZ8Gva35KU05p0ax4LduKcljWAVBSOiUD9Ga4li+WWVN1lxxY6+VQJFjkKcqI3S+GpesMn1zSg9tg0NVczZw8n0OXNiAm0lZQ3pXELTevEm07c8Z0wMLFNCGYL8GojUceHpQNr0cxy6A5YBQTLjo5tlRIWkePkWI0QJ9c2IZiiLVr7s1hdi+zy65++hIbJKWKP/n6BMJjYO0rzeCbQ0c3oEKh3wBEmkQzPDtZXd537BiCGZnopPtSEAqKihHOUh5YEKbOp6+SA4IwPoHwOMdxhbqjBTI6Kg+Brold/vta9qtd84gO9Vj7lHsN93w311oZ88ED+Gec56bQq8fZuIndJD6myys0vHECnLG9Uyz868FIJ8KJc4h5RbXLGYcs59HqBUC36iWlMeMToVxc+jbZW96ASrUvCepTzuhv47mfSbqpt9DzbAlUJYQEl1OpwERRpAAVYIr5f0KwUnBNH3aOZYRTi+FPCV0iGuZSiP620KfA7ZJpgvCGRH1GEuH3AQLi49YhG7a6fXnJhinbNc5r2LHWgx5Yrwn5eXIeJnM4QO7fGblFWM2zQ0uJOBfGZ5JsBKjl40R8MHjPoIYZDKhhAOKFAsjxigD7/MWTDszCf+EspmNrBmf2xLKACZVhBWADwHGVZWCACqzzJoSj69XQ2a1xDVDDHmdziE2BtChvz8K4vmZOjZzLEV9ADBfCwJPhPPmfJxFHeK5sYRd5yFuvbKg6CDX7H2D7L5ubxB/MScuTGszlbUslBnUJ59fkD9XE+LL+CrMLdeBeSYRmqSaK6apHi2blfQkf4sTN9tU1kvm3UEQ1O/uVXENKbly5HWqZZY9OV7+kyifJHw1AWk4HNszQWzC5n+evbOdx/Zp3GZw8CQJEZAgliIhkzRsZ5MSbL6UUS3vLdaBi+UTa502uOAdMJLXxRL+y+nwbtjYkTgTgny8EJ/Qb5PhTHFcgeNv6o3geK7XCzD296+wBDyJa27ow3ySmCzHObi6WsjNRdxIoX78Arfa/v7sC688qr+aYF9ZyyvK1UhYpeNIqLMgV5H0C4OC8lQ2uh1Q94Y86bU9VQcbZImf+q5AOrf+2vFUbJZpiIh50RlCNPd+xOgvl2i+FHPUOvaR8znpf0oIEW42hJn0TiLiQA8ZvyRx X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: db09b283-f7b6-451d-76e5-08dcb8581fc6 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:21.0877 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: qwuax0rLl98o3pkjBx/D2u+qPW7EQuQwk9O8SzjX+Dl9W8qqPT+jDoMbjxA8Nkm+lL7C0320zLajqH//GnI1NA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- .../net/wireless/nxp/nxpwifi/11n_rxreorder.h | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.h diff --git a/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.h b/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.h new file mode 100644 index 000000000000..9b5dd4899f0e --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: 802.11n RX Re-ordering + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_11N_RXREORDER_H_ +#define _NXPWIFI_11N_RXREORDER_H_ + +#define MIN_FLUSH_TIMER_MS 50 +#define MIN_FLUSH_TIMER_15_MS 15 +#define NXPWIFI_BA_WIN_SIZE_32 32 + +#define PKT_TYPE_BAR 0xE7 +#define MAX_TID_VALUE (2 << 11) +#define TWOPOW11 (2 << 10) + +#define BLOCKACKPARAM_TID_POS 2 +#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1 +#define BLOCKACKPARAM_WINSIZE_POS 6 +#define DELBA_TID_POS 12 +#define DELBA_INITIATOR_POS 11 +#define TYPE_DELBA_SENT 1 +#define TYPE_DELBA_RECEIVE 2 +#define IMMEDIATE_BLOCK_ACK 0x2 + +#define ADDBA_RSP_STATUS_ACCEPT 0 + +#define NXPWIFI_DEF_11N_RX_SEQ_NUM 0xffff +#define BA_SETUP_MAX_PACKET_THRESHOLD 16 +#define BA_SETUP_PACKET_OFFSET 16 + +enum nxpwifi_rxreor_flags { + RXREOR_FORCE_NO_DROP = 1 << 0, + RXREOR_INIT_WINDOW_SHIFT = 1 << 1, +}; + +static inline void nxpwifi_reset_11n_rx_seq_num(struct nxpwifi_private *priv) +{ + memset(priv->rx_seq, 0xff, sizeof(priv->rx_seq)); +} + +int nxpwifi_11n_rx_reorder_pkt(struct nxpwifi_private *, + u16 seqNum, + u16 tid, u8 *ta, + u8 pkttype, void *payload); +void nxpwifi_del_ba_tbl(struct nxpwifi_private *priv, int tid, + u8 *peer_mac, u8 type, int initiator); +void nxpwifi_11n_ba_stream_timeout(struct nxpwifi_private *priv, + struct host_cmd_ds_11n_batimeout *event); +int nxpwifi_ret_11n_addba_resp(struct nxpwifi_private *priv, + struct host_cmd_ds_command + *resp); +int nxpwifi_cmd_11n_delba(struct host_cmd_ds_command *cmd, + void *data_buf); +int nxpwifi_cmd_11n_addba_rsp_gen(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + struct host_cmd_ds_11n_addba_req + *cmd_addba_req); +int nxpwifi_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, + void *data_buf); +void nxpwifi_11n_cleanup_reorder_tbl(struct nxpwifi_private *priv); +struct nxpwifi_rx_reorder_tbl * +nxpwifi_11n_get_rxreorder_tbl(struct nxpwifi_private *priv, int tid, u8 *ta); +struct nxpwifi_rx_reorder_tbl * +nxpwifi_11n_get_rx_reorder_tbl(struct nxpwifi_private *priv, int tid, u8 *ta); +void nxpwifi_11n_del_rx_reorder_tbl_by_ta(struct nxpwifi_private *priv, u8 *ta); +void nxpwifi_update_rxreor_flags(struct nxpwifi_adapter *adapter, u8 flags); +void nxpwifi_11n_rxba_sync_event(struct nxpwifi_private *priv, + u8 *event_buf, u16 len); +#endif /* _NXPWIFI_11N_RXREORDER_H_ */ From patchwork Fri Aug 9 09:45:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818394 Received: from DUZPR83CU001.outbound.protection.outlook.com (mail-northeuropeazon11013064.outbound.protection.outlook.com [52.101.67.64]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B02CD194A67; Fri, 9 Aug 2024 09:46:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.67.64 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196794; cv=fail; b=AS/FI94gfWPw0PPhTprxAEy/tIqX9BHHwXJCwNlQu3rSTZBwpZeUOxNuFHsE/DgPzx/62Mvg4PPPMeCQZs3ST2DPFkOcRLk92HJpkNsrFrnB8/DN1i4CEtPxVINLcCLU9NuhrwJYqdAiwVY1gS5h2YKqGPmXREnoGN2tmti5Org= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196794; c=relaxed/simple; bh=w6YhEyz3Ft4ZQHVGcN+11qn34mpD6bt/upb0H/fPero=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=NXOkKUI8ExKZhnVeL1uQDceO/X4pEh2/KJeLsbyDMX4JDYth8tUxJaTKy0w+4cjaiuEH0qr8psUuY4N+FqunL9urQ/e76nuAep/xqKyxHOcUpqlyXuX8wy4W/P4sDZvq4s1wikkVsqd5eYZjFRIu5V3MDD9dN/uDQldv1lofaFw= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=Ev853usb; arc=fail smtp.client-ip=52.101.67.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="Ev853usb" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ET+Px1zt4/3aDoFK6HHS82lOvWg0Uwjl5h5Uh2dX/kA3xSJg+o9kePcU+T9FIoTE07V+lY2ViuesILVJmPhepoPDelYZb7rePXmAEnoam6P0VA0iv6rXLKgwHDf+C7hoe6RrwOG/9VET1slK0EFejy9nuEfnUYLHVri3XZZDLoXVYSQz3Pro/jozx0N86IM/c4ycv5RJKJsJV2Mcf2zk0S21ixe7OSVpZH3y5aWCVVOjtAcueBsm4blP0Doqdc+eQnXtz7JtagW9Qd8zl6MRUYJOFymQg+3MaLagUqwTmAkPclOB2uZRXge0TeELOoA+hoTc0U/G1Z1XwZyGL/EQVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=wivINtag3c2Zhzz4gjuDvJiZyVcnQCTZaQnMb/2D8xc=; b=OPpeBk1/HSXMCXeA0k0CjEaiqxgHwis+WbQb5G8ILF6vclYPjCNAjPH/Ft25jASZAMpBTe6j999JdzvYShOgy1RKDYBTQTGo98REL2v0Aq7T+4kLSgNtFgFFjsbrZJsl8VQNxx9XYd1uvHYekA0WC5rsbBTTUuuab2aAjsp+duUF9eSYuJQcezpfBgBO1lFmhuPVwPQLAKBAbwj4QUNfJvSBoan4uhqqUCzBKxdu5GzN4eugqet2CvHH8vAfyUFavDS4i+v1q9PGF6q9b5GOUcws2Elxvc7451PEPJeSyC4E2zNAIec9GuLMI7cb7B7VjXN+NuiwJXcsTXCXC1AE4A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=wivINtag3c2Zhzz4gjuDvJiZyVcnQCTZaQnMb/2D8xc=; b=Ev853usbY+yO0xSC3vvBlNT2PFPIcJG4bqDBJ1xNDjjaZYpWdROl26QHxtNpN8jQugX1yJtfcIbSz6KwrUCv2WyJg67m0hfvBrvbpVXoVFswWUg4oVyNEcLFFGcBIFw8YjgL9nTRSQvCrRt3lltUVnyyHQ7Ib7Ir9gKHD+Jzs6F8B2oXlp0q5/EpN9/aA3mBsFhgINQHGpKwFjHktxWtgqxH23jmPQeOC0h3ozTeI+fn8wkZMNpxJeue3yP+vxPREFdzU6128NvY2eacVEC4sINAE5YGnB1ZLpNYOccsKju3YwM12pmpxiseL55xucSuqs2Hi3OpjbLt8IGLwIKFsQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:24 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:24 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 10/43] wifi: nxpwifi: add cfg80211.c Date: Fri, 9 Aug 2024 17:45:00 +0800 Message-Id: <20240809094533.1660-11-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: 558c299d-c73c-4b76-93da-08dcb85821b4 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|376014|366016|1800799024|4022899009|52116014; X-Microsoft-Antispam-Message-Info: IqEwbDJ15kZuhp1CYPuskKypJmuOEbrsTJ31pm/HIbvYWZe04YyhQ23WrRMZUDfjiIu0ODubAkSh/JgZTuWlOHZkVeM1STQDiMBx7QdzKzytdxnSrSqHAEAJC13+2aEF/KpjNHnfqYiXLjDmTGX50pkVpvccO9g5GgYeyJp7mbob8NB5KTTrIDpj2qJNVyoK9m3WYSvuFrow668cxAJcWf1dnqiRasKVBlVWaUz6R3bVzcp3D9FT7iZzmnVGXx184GJLFOtHNTdcBBJ+25BZ56g5iCFdVceK1rZ6Zx+PpVkwqFgpphBN6YRFSasoYh6dLyGOdBRC1oGHY0KIZJwYxGNjprwej83dDzgq6WGUpOejjPEViWvpaa7obwI0HVQxo/EOlHflSxpf1zw4OW63QWR/nCoh0YhUxLOnMUvPDH76hiRRKftxio8qdkHS3eld3LW6QTSaAguHA9ejDQWtQkMPKKRs3U4a2pEwREc+BmHtzrN8rZleBecAATzaXOAjGqFFRKKtJFRBItd3LrDK9vMp1nZ3br7up/uJFQaAmo1epXqpv0dqCsydh4d9gjhM8O+BSNqiqmvAX/UEsRyMtbqXc6tJlr0mL9ZPtxLisVCMiEUYCp0DT2dNZMp7DzApZ78MF9/CvBzS414ans4JBFp3Om5ntFdVhqL+4AekIW5gblRmcnQizyLxq9+TBZJdoLg3cY/hQqaWcPEb6QtS8+3HVuGs/QkhB5e8GlPzz1GN7yhXC4TdPlWwqnqCcEjRL0eZBZEu3tZMogB3IpcrkjEjotPU6/qmuWEWWZyJ9uBjhmpAfveZ7h0ekUrBPsCunhaIfz2vyr2vtgti7uKBtpGy09PJwTQ4ftv6QIAnBfjtlUw1jbDLwHBOuSnA1YlhdQyi2xnTfEEHfr8VRbeSGGIcCaP3rv5BWmIYg0InOlf1E7H2x7pO5L0QW7lq6B8CeYhYyc2kmc0BhGkfaS08AZGBMxUcTkCWZucOJWVVJU465RUwAU7qDb8SnE7xQfx67VdBgF3+X9j//i9eptE6GVl0islz081z/Qc2rec3gnMC6reHXKsA1j9TOyF4habaUlJTtJyr60GDu0mOJWK0LzILhYkC6eCsqPH3yxXz1KOyHIaucwUTuBXnJJ1M0NyNffGkXHljtDt4y+VPDWcFkL5JAQRZX+qYpDmVvi921JW29yeg0Nd6PhMJz18V7STQQ3lSQfOU8NUF7iUR5vOjN+G2U2tjpDSopsuoC64JzMplsGuTVNp4ktumk8t85bgkeCVeszmygTB3vXHL5sntlyI09JkRoUirWDu1KROGdnr9sDzfNPzzdqiEGt1wxfM6QsGYLhN9ohKzHK7KZRrB9Q== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(4022899009)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: x6pZBvCn0O8Anakgc7axAL+QpFO29G/+PsJdpZdbi/TDeEpihATK31tRWf0iXUQZwnrPDW/xfo5lMOyR03+59V4KJXOY7DsIm94EFrWfxLO455KtSwIEh62x4XiYXusuGt1iKEWHBN+OlUszoNNkvPBBa0w3K9mJsXobm64Ib2Wiw/t7b+DeumPPDkpuR7OOubA0m/ElkCfr7cVBCyQvB0BO0qAeJvSt8Rcq6K3SHaRI72amUxG3kAedSW8xnQ/6rrrw83L0wVjIXamStlk7MYeISwoN7LC5rju8chxEETyc7ESlk49k6r3ZK2NN9W7ig66bAp8WEb6HJ6iKK0z/SDzvdIhc2+Vj6xjQEc030JzP1XCdcy5fmiuAn95cGFqx+fxfFnTsNf68CrFgOETFzZPEW0M5XsqccWVLr3s7db0snI7qW0gItGWlH3vM0EhX+dAQqKGlPlKDWK+KVszRjfRfDDwPLsbA9xLquELh09XOXjJhV6h5A/bWuZ4JHq57brpdl0b8tx/fBXKQExY+KA6GR3rTxVUyFYSa2oHVndwMb2GLeBTJURmk2pMtjRFvqC9JBpf1F9yQhT+GmyJRmOvE6GmtCFBB8JnwVGfHMqDZAQYKvHt6Ccip9nH0JJh+HyGGiLxe3CIM/JDG9wjKNF/H/QE/ShadFDw7wi/hkFuCvIiIQFcDg0GCjXKyahJG8xljtthmS3it2YverejH6psDybm3HAbHv4BVoGuGxCgf91YCLxPrpO1x8qvpisUi/Q0JF1cKA6BdobsZrJPFFXJYF963pg8/TjQFihivL3XRtuTC/jb9rv4CQcxUu6BeJ7pTRm32rCStRGBvxDDboCzw8YMYhAbi//Q8wpgDyXB/4kX6IcjS8LUeFWONcwS9WKVn1NlKNiwlrRyDaMiLUcYmfaWr1wYizi4lR+Ik1a5LS8Lhv42TIrjhYfpnTovUWIdf8fBQk5jolY0UsjOQo//8dfabMzv0Lg/33xYq1aj/YH7LBdL6d+wQwrFzBB56ClMl9C7GnAC+p/XTXuh4ppaUjNWw61A/QjFulN4iFYigAYstn9ok5iC5uuCT4BZgC4cf0dNTz/vMamr17tcU00kWx3YGmPT4RWUoxinvd5gmvYgNQBU9qJcWc2s3qKD2PPbtwnut3QFRGZyebpMpinFwIONSJY1036eOslaPKSKcjppVU6V1YYGPKJ2fGKThDrdX9qv0EBC3NPrIcy/qj3h2YwVa3ca2rLdFyBVuFf8WHAXjOYrDcxBlrGLvrhTfX1R6urT1hLr2muyEyqONSUKbRhoUxl6M8FVWbZF+ZQV/k5dO8zZpYnakMrRADWn+79OUGeaVXIyKaHWfhqK2Elc6Q+DGT5zlKy+tEVOrmEeCjHTxBdaVX4OfzyTwsjzWBaAxOnEG/m+9tKCloWktFr2FmuNUpib+PRnj7XTOmMsEXtOQSC9GA0Cw8UCVzxpWp9SC3C0DvaeskEaL7WerInCktOsfq5Y2B6xJNAkFien2Z6IOMLaw1L4d21a/x3NOxqxk5o8d9OWPiDDiJBv7hkL0p3V65LwZYtthw3IcvikzOEydLdnka2fyjAzsh9e5FRmp/dPeri5xedP/KOrb0HRuqoPYQ6k9kDc7eVO0PaRz0kp/AmJ3VzyJqxVFfLWB X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 558c299d-c73c-4b76-93da-08dcb85821b4 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:24.5055 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: h+udXknpFOcdq1+ta/jeS2jKKEdz/Wd4YjL5+L8Bw2WR2SL7aSLqkK61TPO/OA3Eq+xGKhY10fG0Tyb1j+Ov1A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/cfg80211.c | 3773 +++++++++++++++++++ 1 file changed, 3773 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/cfg80211.c diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c new file mode 100644 index 000000000000..f099d51eac9a --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c @@ -0,0 +1,3773 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: CFG80211 + * + * Copyright 2011-2024 NXP + */ + +#include "cfg80211.h" +#include "main.h" +#include "cmdevt.h" +#include "11n.h" +#include "wmm.h" + +static const struct ieee80211_iface_limit nxpwifi_ap_sta_limits[] = { + { + .max = NXPWIFI_MAX_BSS_NUM, + .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_combination +nxpwifi_iface_comb_ap_sta = { + .limits = nxpwifi_ap_sta_limits, + .num_different_channels = 1, + .n_limits = ARRAY_SIZE(nxpwifi_ap_sta_limits), + .max_interfaces = NXPWIFI_MAX_BSS_NUM, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40), +}; + +static const struct ieee80211_iface_combination +nxpwifi_iface_comb_ap_sta_vht = { + .limits = nxpwifi_ap_sta_limits, + .num_different_channels = 1, + .n_limits = ARRAY_SIZE(nxpwifi_ap_sta_limits), + .max_interfaces = NXPWIFI_MAX_BSS_NUM, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), +}; + +/* This function maps the nl802.11 channel type into driver channel type. + * + * The mapping is as follows - + * NL80211_CHAN_NO_HT -> IEEE80211_HT_PARAM_CHA_SEC_NONE + * NL80211_CHAN_HT20 -> IEEE80211_HT_PARAM_CHA_SEC_NONE + * NL80211_CHAN_HT40PLUS -> IEEE80211_HT_PARAM_CHA_SEC_ABOVE + * NL80211_CHAN_HT40MINUS -> IEEE80211_HT_PARAM_CHA_SEC_BELOW + * Others -> IEEE80211_HT_PARAM_CHA_SEC_NONE + */ +u8 nxpwifi_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type) +{ + switch (chan_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + return IEEE80211_HT_PARAM_CHA_SEC_NONE; + case NL80211_CHAN_HT40PLUS: + return IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + case NL80211_CHAN_HT40MINUS: + return IEEE80211_HT_PARAM_CHA_SEC_BELOW; + default: + return IEEE80211_HT_PARAM_CHA_SEC_NONE; + } +} + +/* This function maps IEEE HT secondary channel type to NL80211 channel type + */ +u8 nxpwifi_get_chan_type(struct nxpwifi_private *priv) +{ + struct nxpwifi_channel_band channel_band; + int ret; + + ret = nxpwifi_get_chan_info(priv, &channel_band); + + if (!ret) { + switch (channel_band.band_config.chan_width) { + case CHAN_BW_20MHZ: + if (IS_11N_ENABLED(priv)) + return NL80211_CHAN_HT20; + else + return NL80211_CHAN_NO_HT; + case CHAN_BW_40MHZ: + if (channel_band.band_config.chan2_offset == + SEC_CHAN_ABOVE) + return NL80211_CHAN_HT40PLUS; + else + return NL80211_CHAN_HT40MINUS; + default: + return NL80211_CHAN_HT20; + } + } + + return NL80211_CHAN_HT20; +} + +/* This function retrieves the private structure from kernel wiphy structure. + */ +static void *nxpwifi_cfg80211_get_adapter(struct wiphy *wiphy) +{ + return (void *)(*(unsigned long *)wiphy_priv(wiphy)); +} + +/* CFG802.11 operation handler to delete a network key. + */ +static int +nxpwifi_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, + int link_id, u8 key_index, bool pairwise, + const u8 *mac_addr) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(netdev); + static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const u8 *peer_mac = pairwise ? mac_addr : bc_mac; + int ret; + + ret = nxpwifi_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1); + if (ret) + nxpwifi_dbg(priv->adapter, ERROR, + "crypto keys deleted failed %d\n", ret); + else + nxpwifi_dbg(priv->adapter, INFO, "info: crypto keys deleted\n"); + + return ret; +} + +/* This function forms an skb for management frame. + */ +static void +nxpwifi_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) +{ + u8 addr[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + u16 pkt_len; + u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT; + + pkt_len = len + ETH_ALEN; + + skb_reserve(skb, NXPWIFI_MIN_DATA_HEADER_LEN + + NXPWIFI_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); + memcpy(skb_push(skb, sizeof(pkt_len)), &pkt_len, sizeof(pkt_len)); + + memcpy(skb_push(skb, sizeof(tx_control)), + &tx_control, sizeof(tx_control)); + + memcpy(skb_push(skb, sizeof(pkt_type)), &pkt_type, sizeof(pkt_type)); + + /* Add packet data and address4 */ + skb_put_data(skb, buf, sizeof(struct ieee80211_hdr_3addr)); + skb_put_data(skb, addr, ETH_ALEN); + skb_put_data(skb, buf + sizeof(struct ieee80211_hdr_3addr), + len - sizeof(struct ieee80211_hdr_3addr)); + + skb->priority = LOW_PRIO_TID; + __net_timestamp(skb); +} + +/* CFG802.11 operation handler to transmit a management frame. + */ +static int +nxpwifi_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +{ + const u8 *buf = params->buf; + size_t len = params->len; + struct sk_buff *skb; + u16 pkt_len; + const struct ieee80211_mgmt *mgmt; + struct nxpwifi_txinfo *tx_info; + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev); + + if (!buf || !len) { + nxpwifi_dbg(priv->adapter, ERROR, "invalid buffer and length\n"); + return -EINVAL; + } + + mgmt = (const struct ieee80211_mgmt *)buf; + if (GET_BSS_ROLE(priv) != NXPWIFI_BSS_ROLE_STA && + ieee80211_is_probe_resp(mgmt->frame_control)) { + /* Since we support offload probe resp, we need to skip probe + * resp in AP or GO mode + */ + nxpwifi_dbg(priv->adapter, INFO, + "info: skip to send probe resp in AP or GO mode\n"); + return 0; + } + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) { + if (ieee80211_is_auth(mgmt->frame_control)) + nxpwifi_dbg(priv->adapter, MSG, + "auth: send auth to %pM\n", mgmt->da); + if (ieee80211_is_deauth(mgmt->frame_control)) + nxpwifi_dbg(priv->adapter, MSG, + "auth: send deauth to %pM\n", mgmt->da); + if (ieee80211_is_disassoc(mgmt->frame_control)) + nxpwifi_dbg(priv->adapter, MSG, + "assoc: send disassoc to %pM\n", mgmt->da); + if (ieee80211_is_assoc_resp(mgmt->frame_control)) + nxpwifi_dbg(priv->adapter, MSG, + "assoc: send assoc resp to %pM\n", + mgmt->da); + if (ieee80211_is_reassoc_resp(mgmt->frame_control)) + nxpwifi_dbg(priv->adapter, MSG, + "assoc: send reassoc resp to %pM\n", + mgmt->da); + } + + pkt_len = len + ETH_ALEN; + skb = dev_alloc_skb(NXPWIFI_MIN_DATA_HEADER_LEN + + NXPWIFI_MGMT_FRAME_HEADER_SIZE + + pkt_len + sizeof(pkt_len)); + + if (!skb) { + nxpwifi_dbg(priv->adapter, ERROR, + "allocate skb failed for management frame\n"); + return -ENOMEM; + } + + tx_info = NXPWIFI_SKB_TXCB(skb); + memset(tx_info, 0, sizeof(*tx_info)); + tx_info->bss_num = priv->bss_num; + tx_info->bss_type = priv->bss_type; + tx_info->pkt_len = pkt_len; + + nxpwifi_form_mgmt_frame(skb, buf, len); + *cookie = nxpwifi_roc_cookie(priv->adapter); + + if (ieee80211_is_action(mgmt->frame_control)) + skb = nxpwifi_clone_skb_for_tx_status(priv, + skb, + NXPWIFI_BUF_FLAG_ACTION_TX_STATUS, cookie); + else + cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, + GFP_ATOMIC); + + nxpwifi_queue_tx_pkt(priv, skb); + + nxpwifi_dbg(priv->adapter, INFO, "info: management frame transmitted\n"); + return 0; +} + +/* CFG802.11 operation handler to register a mgmt frame. + */ +static void +nxpwifi_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct mgmt_frame_regs *upd) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev); + u32 mask = upd->interface_stypes; + + if (mask != priv->mgmt_frame_mask) { + priv->mgmt_frame_mask = mask; + if (priv->host_mlme_reg && + GET_BSS_ROLE(priv) != NXPWIFI_BSS_ROLE_UAP) + priv->mgmt_frame_mask |= HOST_MLME_MGMT_MASK; + nxpwifi_send_cmd(priv, HOST_CMD_MGMT_FRAME_REG, + HOST_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false); + nxpwifi_dbg(priv->adapter, INFO, "info: mgmt frame registered\n"); + } +} + +/* CFG802.11 operation handler to remain on channel. + */ +static int +nxpwifi_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev); + struct nxpwifi_adapter *adapter = priv->adapter; + int ret; + + if (!chan || !cookie) { + nxpwifi_dbg(adapter, ERROR, "Invalid parameter for ROC\n"); + return -EINVAL; + } + + if (priv->roc_cfg.cookie) { + nxpwifi_dbg(adapter, INFO, + "info: ongoing ROC, cookie = 0x%llx\n", + priv->roc_cfg.cookie); + return -EBUSY; + } + + ret = nxpwifi_remain_on_chan_cfg(priv, HOST_ACT_GEN_SET, chan, + duration); + + if (!ret) { + *cookie = nxpwifi_roc_cookie(adapter); + priv->roc_cfg.cookie = *cookie; + priv->roc_cfg.chan = *chan; + + cfg80211_ready_on_channel(wdev, *cookie, chan, + duration, GFP_ATOMIC); + + nxpwifi_dbg(adapter, INFO, + "info: ROC, cookie = 0x%llx\n", *cookie); + } + + return ret; +} + +/* CFG802.11 operation handler to cancel remain on channel. + */ +static int +nxpwifi_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev); + int ret; + + if (cookie != priv->roc_cfg.cookie) + return -ENOENT; + + ret = nxpwifi_remain_on_chan_cfg(priv, HOST_ACT_GEN_REMOVE, + &priv->roc_cfg.chan, 0); + + if (!ret) { + cfg80211_remain_on_channel_expired(wdev, cookie, + &priv->roc_cfg.chan, + GFP_ATOMIC); + + memset(&priv->roc_cfg, 0, sizeof(struct nxpwifi_roc_cfg)); + + nxpwifi_dbg(priv->adapter, INFO, + "info: cancel ROC, cookie = 0x%llx\n", cookie); + } + + return ret; +} + +/* CFG802.11 operation handler to set Tx power. + */ +static int +nxpwifi_cfg80211_set_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, + int mbm) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_private *priv; + struct nxpwifi_power_cfg power_cfg; + int dbm = MBM_TO_DBM(mbm); + + switch (type) { + case NL80211_TX_POWER_FIXED: + power_cfg.is_power_auto = 0; + power_cfg.is_power_fixed = 1; + power_cfg.power_level = dbm; + break; + case NL80211_TX_POWER_LIMITED: + power_cfg.is_power_auto = 0; + power_cfg.is_power_fixed = 0; + power_cfg.power_level = dbm; + break; + case NL80211_TX_POWER_AUTOMATIC: + power_cfg.is_power_auto = 1; + break; + } + + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + + return nxpwifi_set_tx_power(priv, &power_cfg); +} + +/* CFG802.11 operation handler to get Tx power. + */ +static int +nxpwifi_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_private *priv = nxpwifi_get_priv(adapter, + NXPWIFI_BSS_ROLE_ANY); + int ret = nxpwifi_send_cmd(priv, HOST_CMD_RF_TX_PWR, + HOST_ACT_GEN_GET, 0, NULL, true); + + if (ret < 0) + return ret; + + /* tx_power_level is set in HOST_CMD_RF_TX_PWR command handler */ + *dbm = priv->tx_power_level; + + return 0; +} + +/* CFG802.11 operation handler to set Power Save option. + * + * The timeout value, if provided, is currently ignored. + */ +static int +nxpwifi_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool enabled, int timeout) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + u32 ps_mode; + + if (timeout) + nxpwifi_dbg(priv->adapter, INFO, + "info: ignore timeout value for IEEE Power Save\n"); + + ps_mode = enabled; + + return nxpwifi_drv_set_power(priv, &ps_mode); +} + +/* CFG802.11 operation handler to set the default network key. + */ +static int +nxpwifi_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, + int link_id, u8 key_index, bool unicast, + bool multicast) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(netdev); + int ret = 0; + + /* Return if WEP key not configured */ + if (!priv->sec_info.wep_enabled) + return 0; + + if (priv->bss_type == NXPWIFI_BSS_TYPE_UAP) { + priv->wep_key_curr_index = key_index; + } else { + ret = nxpwifi_set_encode(priv, NULL, NULL, 0, key_index, + NULL, 0); + if (ret) + nxpwifi_dbg(priv->adapter, ERROR, + "failed to set default Tx key index\n"); + } + + return ret; +} + +/* CFG802.11 operation handler to add a network key. + */ +static int +nxpwifi_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, + int link_id, u8 key_index, bool pairwise, + const u8 *mac_addr, struct key_params *params) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(netdev); + struct nxpwifi_wep_key *wep_key; + static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const u8 *peer_mac = pairwise ? mac_addr : bc_mac; + int ret; + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP && + (params->cipher == WLAN_CIPHER_SUITE_WEP40 || + params->cipher == WLAN_CIPHER_SUITE_WEP104)) { + if (params->key && params->key_len) { + wep_key = &priv->wep_key[key_index]; + memset(wep_key, 0, sizeof(struct nxpwifi_wep_key)); + memcpy(wep_key->key_material, params->key, + params->key_len); + wep_key->key_index = key_index; + wep_key->key_length = params->key_len; + priv->sec_info.wep_enabled = 1; + } + return 0; + } + + ret = nxpwifi_set_encode(priv, params, params->key, params->key_len, + key_index, peer_mac, 0); + if (ret) + nxpwifi_dbg(priv->adapter, ERROR, + "failed to add crypto keys\n"); + + return ret; +} + +/* CFG802.11 operation handler to set default mgmt key. + */ +static int +nxpwifi_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *netdev, + int link_id, + u8 key_index) +{ + return 0; +} + +/* This function sends domain information to the firmware. + * + * The following information are passed to the firmware - + * - Country codes + * - Sub bands (first channel, number of channels, maximum Tx power) + */ +int nxpwifi_send_domain_info_cmd_fw(struct wiphy *wiphy) +{ + u8 no_of_triplet = 0; + struct ieee80211_country_ie_triplet *t; + u8 no_of_parsed_chan = 0; + u8 first_chan = 0, next_chan = 0, max_pwr = 0; + u8 i, flag = 0; + enum nl80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_private *priv; + struct nxpwifi_802_11d_domain_reg *domain_info = &adapter->domain_reg; + int ret; + + domain_info->dfs_region = adapter->dfs_region; + + /* Set country code */ + domain_info->country_code[0] = adapter->country_code[0]; + domain_info->country_code[1] = adapter->country_code[1]; + domain_info->country_code[2] = ' '; + + band = nxpwifi_band_to_radio_type(adapter->config_bands); + if (!wiphy->bands[band]) { + nxpwifi_dbg(adapter, ERROR, + "11D: setting domain info in FW\n"); + return -EINVAL; + } + + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels ; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (!flag) { + flag = 1; + first_chan = (u32)ch->hw_value; + next_chan = first_chan; + max_pwr = ch->max_power; + no_of_parsed_chan = 1; + continue; + } + + if (ch->hw_value == next_chan + 1 && + ch->max_power == max_pwr) { + next_chan++; + no_of_parsed_chan++; + } else { + t = &domain_info->triplet[no_of_triplet]; + t->chans.first_channel = first_chan; + t->chans.num_channels = no_of_parsed_chan; + t->chans.max_power = max_pwr; + no_of_triplet++; + first_chan = (u32)ch->hw_value; + next_chan = first_chan; + max_pwr = ch->max_power; + no_of_parsed_chan = 1; + } + } + + if (flag) { + t = &domain_info->triplet[no_of_triplet]; + t->chans.first_channel = first_chan; + t->chans.num_channels = no_of_parsed_chan; + t->chans.max_power = max_pwr; + no_of_triplet++; + } + + domain_info->no_of_triplet = no_of_triplet; + + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11D_DOMAIN_INFO, + HOST_ACT_GEN_SET, 0, NULL, false); + + if (ret) + nxpwifi_dbg(adapter, INFO, + "11D: failed to set domain info in FW\n"); + + return ret; +} + +static void nxpwifi_reg_apply_radar_flags(struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + unsigned int i; + + if (!wiphy->bands[NL80211_BAND_5GHZ]) + return; + sband = wiphy->bands[NL80211_BAND_5GHZ]; + + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + if ((!(chan->flags & IEEE80211_CHAN_DISABLED)) && + (chan->flags & IEEE80211_CHAN_RADAR)) + chan->flags |= IEEE80211_CHAN_NO_IR; + } +} + +/* CFG802.11 regulatory domain callback function. + * + * This function is called when the regulatory domain is changed due to the + * following reasons - + * - Set by driver + * - Set by system core + * - Set by user + * - Set bt Country IE + */ +static void nxpwifi_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_private *priv = nxpwifi_get_priv(adapter, + NXPWIFI_BSS_ROLE_ANY); + nxpwifi_dbg(adapter, INFO, + "info: cfg80211 regulatory domain callback for %c%c\n", + request->alpha2[0], request->alpha2[1]); + nxpwifi_reg_apply_radar_flags(wiphy); + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + break; + default: + nxpwifi_dbg(adapter, ERROR, + "unknown regdom initiator: %d\n", + request->initiator); + return; + } + + /* Don't send world or same regdom info to firmware */ + if (strncmp(request->alpha2, "00", 2) && + strncmp(request->alpha2, adapter->country_code, + sizeof(request->alpha2))) { + memcpy(adapter->country_code, request->alpha2, + sizeof(request->alpha2)); + adapter->dfs_region = request->dfs_region; + nxpwifi_send_domain_info_cmd_fw(wiphy); + nxpwifi_dnld_txpwr_table(priv); + } +} + +/* This function sets the fragmentation threshold. + * + * The fragmentation threshold value must lie between NXPWIFI_FRAG_MIN_VALUE + * and NXPWIFI_FRAG_MAX_VALUE. + */ +static int +nxpwifi_set_frag(struct nxpwifi_private *priv, u32 frag_thr) +{ + if (frag_thr < NXPWIFI_FRAG_MIN_VALUE || + frag_thr > NXPWIFI_FRAG_MAX_VALUE) + frag_thr = NXPWIFI_FRAG_MAX_VALUE; + + return nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB, + HOST_ACT_GEN_SET, FRAG_THRESH_I, + &frag_thr, true); +} + +/* This function sets the RTS threshold. + * + * The rts value must lie between NXPWIFI_RTS_MIN_VALUE + * and NXPWIFI_RTS_MAX_VALUE. + */ +static int +nxpwifi_set_rts(struct nxpwifi_private *priv, u32 rts_thr) +{ + if (rts_thr < NXPWIFI_RTS_MIN_VALUE || rts_thr > NXPWIFI_RTS_MAX_VALUE) + rts_thr = NXPWIFI_RTS_MAX_VALUE; + + return nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB, + HOST_ACT_GEN_SET, RTS_THRESH_I, + &rts_thr, true); +} + +/* CFG802.11 operation handler to set wiphy parameters. + * + * This function can be used to set the RTS threshold and the + * Fragmentation threshold of the driver. + */ +static int +nxpwifi_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_private *priv; + struct nxpwifi_uap_bss_param *bss_cfg; + int ret = 0; + + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + + switch (priv->bss_role) { + case NXPWIFI_BSS_ROLE_UAP: + if (priv->bss_started) + break; + + bss_cfg = kzalloc(sizeof(*bss_cfg), GFP_KERNEL); + if (!bss_cfg) { + ret = -ENOMEM; + break; + } + + nxpwifi_set_sys_config_invalid_data(bss_cfg); + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + bss_cfg->rts_threshold = wiphy->rts_threshold; + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + bss_cfg->frag_threshold = wiphy->frag_threshold; + if (changed & WIPHY_PARAM_RETRY_LONG) + bss_cfg->retry_limit = wiphy->retry_long; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_UAP_SYS_CONFIG, + HOST_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg, + false); + + kfree(bss_cfg); + if (ret) + nxpwifi_dbg(adapter, ERROR, + "Failed to set wiphy phy params\n"); + break; + + case NXPWIFI_BSS_ROLE_STA: + if (priv->media_connected) + break; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + ret = nxpwifi_set_rts(priv, + wiphy->rts_threshold); + if (ret) + break; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + ret = nxpwifi_set_frag(priv, + wiphy->frag_threshold); + break; + } + + return ret; +} + +static int nxpwifi_deinit_priv_params(struct nxpwifi_private *priv) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + unsigned long flags; + int ret; + + priv->host_mlme_reg = false; + priv->mgmt_frame_mask = 0; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_MGMT_FRAME_REG, + HOST_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "could not unregister mgmt frame rx\n"); + return ret; + } + + nxpwifi_deauthenticate(priv, NULL); + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + adapter->main_locked = true; + if (adapter->nxpwifi_processing) { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + flush_workqueue(adapter->workqueue); + } else { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + } + + tasklet_disable(&adapter->rx_task); + + nxpwifi_free_priv(priv); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; + + return ret; +} + +static int +nxpwifi_init_new_priv_params(struct nxpwifi_private *priv, + struct net_device *dev, + enum nl80211_iftype type) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + unsigned long flags; + + nxpwifi_init_priv(priv); + + priv->bss_mode = type; + priv->wdev.iftype = type; + + nxpwifi_init_priv_params(priv, priv->netdev); + priv->bss_started = 0; + + switch (type) { + case NL80211_IFTYPE_STATION: + priv->bss_role = NXPWIFI_BSS_ROLE_STA; + priv->bss_type = NXPWIFI_BSS_TYPE_STA; + break; + case NL80211_IFTYPE_AP: + priv->bss_role = NXPWIFI_BSS_ROLE_UAP; + priv->bss_type = NXPWIFI_BSS_TYPE_UAP; + break; + default: + nxpwifi_dbg(adapter, ERROR, + "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + adapter->main_locked = false; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + + tasklet_enable(&adapter->rx_task); + + nxpwifi_set_mac_address(priv, dev, false, NULL); + + return 0; +} + +static bool +is_vif_type_change_allowed(struct nxpwifi_adapter *adapter, + enum nl80211_iftype old_iftype, + enum nl80211_iftype new_iftype) +{ + switch (old_iftype) { + case NL80211_IFTYPE_STATION: + switch (new_iftype) { + case NL80211_IFTYPE_AP: + return adapter->curr_iface_comb.uap_intf != + adapter->iface_limit.uap_intf; + default: + return false; + } + + case NL80211_IFTYPE_AP: + switch (new_iftype) { + case NL80211_IFTYPE_STATION: + return adapter->curr_iface_comb.sta_intf != + adapter->iface_limit.sta_intf; + default: + return false; + } + + default: + break; + } + + return false; +} + +static void +update_vif_type_counter(struct nxpwifi_adapter *adapter, + enum nl80211_iftype iftype, + int change) +{ + switch (iftype) { + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_STATION: + adapter->curr_iface_comb.sta_intf += change; + break; + case NL80211_IFTYPE_AP: + adapter->curr_iface_comb.uap_intf += change; + break; + default: + nxpwifi_dbg(adapter, ERROR, + "%s: Unsupported iftype passed: %d\n", + __func__, iftype); + break; + } +} + +static int +nxpwifi_change_vif_to_sta(struct net_device *dev, + enum nl80211_iftype curr_iftype, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct nxpwifi_private *priv; + struct nxpwifi_adapter *adapter; + int ret; + + priv = nxpwifi_netdev_get_priv(dev); + + if (!priv) + return -EINVAL; + + adapter = priv->adapter; + + nxpwifi_dbg(adapter, INFO, + "%s: changing role to station\n", dev->name); + + ret = nxpwifi_deinit_priv_params(priv); + if (ret) + goto done; + ret = nxpwifi_init_new_priv_params(priv, dev, type); + if (ret) + goto done; + + update_vif_type_counter(adapter, curr_iftype, -1); + update_vif_type_counter(adapter, type, 1); + dev->ieee80211_ptr->iftype = type; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_SET_BSS_MODE, + HOST_ACT_GEN_SET, 0, NULL, true); + if (ret) + goto done; + + ret = nxpwifi_sta_init_cmd(priv, false, false); + +done: + return ret; +} + +static int +nxpwifi_change_vif_to_ap(struct net_device *dev, + enum nl80211_iftype curr_iftype, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct nxpwifi_private *priv; + struct nxpwifi_adapter *adapter; + int ret; + + priv = nxpwifi_netdev_get_priv(dev); + + if (!priv) + return -EINVAL; + + adapter = priv->adapter; + + nxpwifi_dbg(adapter, INFO, + "%s: changing role to AP\n", dev->name); + + ret = nxpwifi_deinit_priv_params(priv); + if (ret) + goto done; + + ret = nxpwifi_init_new_priv_params(priv, dev, type); + if (ret) + goto done; + + update_vif_type_counter(adapter, curr_iftype, -1); + update_vif_type_counter(adapter, type, 1); + dev->ieee80211_ptr->iftype = type; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_SET_BSS_MODE, + HOST_ACT_GEN_SET, 0, NULL, true); + if (ret) + goto done; + + ret = nxpwifi_sta_init_cmd(priv, false, false); + +done: + return ret; +} + +/* CFG802.11 operation handler to change interface type. + */ +static int +nxpwifi_cfg80211_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + enum nl80211_iftype curr_iftype = dev->ieee80211_ptr->iftype; + + if (priv->scan_request) { + nxpwifi_dbg(priv->adapter, ERROR, + "change virtual interface: scan in process\n"); + return -EBUSY; + } + + if (type == NL80211_IFTYPE_UNSPECIFIED) { + nxpwifi_dbg(priv->adapter, INFO, + "%s: no new type specified, keeping old type %d\n", + dev->name, curr_iftype); + return 0; + } + + if (curr_iftype == type) { + nxpwifi_dbg(priv->adapter, INFO, + "%s: interface already is of type %d\n", + dev->name, curr_iftype); + return 0; + } + + if (!is_vif_type_change_allowed(priv->adapter, curr_iftype, type)) { + nxpwifi_dbg(priv->adapter, ERROR, + "%s: change from type %d to %d is not allowed\n", + dev->name, curr_iftype, type); + return -EOPNOTSUPP; + } + + switch (curr_iftype) { + case NL80211_IFTYPE_STATION: + switch (type) { + case NL80211_IFTYPE_AP: + return nxpwifi_change_vif_to_ap(dev, curr_iftype, type, + params); + default: + goto errnotsupp; + } + + case NL80211_IFTYPE_AP: + switch (type) { + case NL80211_IFTYPE_STATION: + return nxpwifi_change_vif_to_sta(dev, curr_iftype, + type, params); + break; + default: + goto errnotsupp; + } + + default: + goto errnotsupp; + } + + return 0; + +errnotsupp: + nxpwifi_dbg(priv->adapter, ERROR, + "unsupported interface type transition: %d to %d\n", + curr_iftype, type); + return -EOPNOTSUPP; +} + +static void +nxpwifi_parse_htinfo(struct nxpwifi_private *priv, u8 rateinfo, u8 htinfo, + struct rate_info *rate) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + + if (adapter->is_hw_11ac_capable) { + /* bit[1-0]: 00=LG 01=HT 10=VHT */ + if (htinfo & BIT(0)) { + /* HT */ + rate->mcs = rateinfo; + rate->flags |= RATE_INFO_FLAGS_MCS; + } + if (htinfo & BIT(1)) { + /* VHT */ + rate->mcs = rateinfo & 0x0F; + rate->flags |= RATE_INFO_FLAGS_VHT_MCS; + } + + if (htinfo & (BIT(1) | BIT(0))) { + /* HT or VHT */ + switch (htinfo & (BIT(3) | BIT(2))) { + case 0: + rate->bw = RATE_INFO_BW_20; + break; + case (BIT(2)): + rate->bw = RATE_INFO_BW_40; + break; + case (BIT(3)): + rate->bw = RATE_INFO_BW_80; + break; + case (BIT(3) | BIT(2)): + rate->bw = RATE_INFO_BW_160; + break; + } + + if (htinfo & BIT(4)) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + + if ((rateinfo >> 4) == 1) + rate->nss = 2; + else + rate->nss = 1; + } + } else { + /* Bit 0 in htinfo indicates that current rate is 11n. Valid + * MCS index values for us are 0 to 15. + */ + if ((htinfo & BIT(0)) && rateinfo < 16) { + rate->mcs = rateinfo; + rate->flags |= RATE_INFO_FLAGS_MCS; + rate->bw = RATE_INFO_BW_20; + if (htinfo & BIT(1)) + rate->bw = RATE_INFO_BW_40; + if (htinfo & BIT(2)) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + } + } + + /* Decode legacy rates for non-HT. */ + if (!(htinfo & (BIT(0) | BIT(1)))) { + /* Bitrates in multiples of 100kb/s. */ + static const int legacy_rates[] = { + [0] = 10, + [1] = 20, + [2] = 55, + [3] = 110, + [4] = 60, /* NXPWIFI_RATE_INDEX_OFDM0 */ + [5] = 60, + [6] = 90, + [7] = 120, + [8] = 180, + [9] = 240, + [10] = 360, + [11] = 480, + [12] = 540, + }; + if (rateinfo < ARRAY_SIZE(legacy_rates)) + rate->legacy = legacy_rates[rateinfo]; + } +} + +/* This function dumps the station information on a buffer. + * + * The following information are shown - + * - Total bytes transmitted + * - Total bytes received + * - Total packets transmitted + * - Total packets received + * - Signal quality level + * - Transmission rate + */ +static int +nxpwifi_dump_station_info(struct nxpwifi_private *priv, + struct nxpwifi_sta_node *node, + struct station_info *sinfo) +{ + u32 rate; + int ret; + + sinfo->filled = BIT_ULL(NL80211_STA_INFO_RX_BYTES) | + BIT_ULL(NL80211_STA_INFO_TX_BYTES) | + BIT_ULL(NL80211_STA_INFO_RX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_TX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_TX_BITRATE) | + BIT_ULL(NL80211_STA_INFO_SIGNAL) | + BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) { + if (!node) + return -ENOENT; + + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) | + BIT_ULL(NL80211_STA_INFO_TX_FAILED); + sinfo->inactive_time = + jiffies_to_msecs(jiffies - node->stats.last_rx); + + sinfo->signal = node->stats.rssi; + sinfo->signal_avg = node->stats.rssi; + sinfo->rx_bytes = node->stats.rx_bytes; + sinfo->tx_bytes = node->stats.tx_bytes; + sinfo->rx_packets = node->stats.rx_packets; + sinfo->tx_packets = node->stats.tx_packets; + sinfo->tx_failed = node->stats.tx_failed; + + nxpwifi_parse_htinfo(priv, priv->tx_rate, + node->stats.last_tx_htinfo, + &sinfo->txrate); + sinfo->txrate.legacy = node->stats.last_tx_rate * 5; + + return 0; + } + + /* Get signal information from the firmware */ + ret = nxpwifi_send_cmd(priv, HOST_CMD_RSSI_INFO, + HOST_ACT_GEN_GET, 0, NULL, true); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "failed to get signal information\n"); + goto done; + } + + ret = nxpwifi_drv_get_data_rate(priv, &rate); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "getting data rate error\n"); + goto done; + } + + /* Get DTIM period information from firmware */ + nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB, + HOST_ACT_GEN_GET, DTIM_PERIOD_I, + &priv->dtim_period, true); + + nxpwifi_parse_htinfo(priv, priv->tx_rate, priv->tx_htinfo, + &sinfo->txrate); + + sinfo->signal_avg = priv->bcn_rssi_avg; + sinfo->rx_bytes = priv->stats.rx_bytes; + sinfo->tx_bytes = priv->stats.tx_bytes; + sinfo->rx_packets = priv->stats.rx_packets; + sinfo->tx_packets = priv->stats.tx_packets; + sinfo->signal = priv->bcn_rssi_avg; + /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */ + sinfo->txrate.legacy = rate * 5; + + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); + nxpwifi_parse_htinfo(priv, priv->rxpd_rate, priv->rxpd_htinfo, + &sinfo->rxrate); + + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BSS_PARAM); + sinfo->bss_param.flags = 0; + if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap & + WLAN_CAPABILITY_SHORT_PREAMBLE) + sinfo->bss_param.flags |= + BSS_PARAM_FLAGS_SHORT_PREAMBLE; + if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap & + WLAN_CAPABILITY_SHORT_SLOT_TIME) + sinfo->bss_param.flags |= + BSS_PARAM_FLAGS_SHORT_SLOT_TIME; + sinfo->bss_param.dtim_period = priv->dtim_period; + sinfo->bss_param.beacon_interval = + priv->curr_bss_params.bss_descriptor.beacon_period; + } + +done: + return ret; +} + +/* CFG802.11 operation handler to get station information. + * + * This function only works in connected mode, and dumps the + * requested station information, if available. + */ +static int +nxpwifi_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_info *sinfo) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + + if (!priv->media_connected) + return -ENOENT; + if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) + return -ENOENT; + + return nxpwifi_dump_station_info(priv, NULL, sinfo); +} + +/* CFG802.11 operation handler to dump station information. + */ +static int +nxpwifi_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_sta_node *node; + int i; + + if ((GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA) && + priv->media_connected && idx == 0) { + ether_addr_copy(mac, priv->cfg_bssid); + return nxpwifi_dump_station_info(priv, NULL, sinfo); + } else if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) { + nxpwifi_send_cmd(priv, HOST_CMD_APCMD_STA_LIST, + HOST_ACT_GEN_GET, 0, NULL, true); + + i = 0; + list_for_each_entry(node, &priv->sta_list, list) { + if (i++ != idx) + continue; + ether_addr_copy(mac, node->mac_addr); + return nxpwifi_dump_station_info(priv, node, sinfo); + } + } + + return -ENOENT; +} + +static int +nxpwifi_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev, + int idx, struct survey_info *survey) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_chan_stats *pchan_stats = priv->adapter->chan_stats; + enum nl80211_band band; + u8 chan_num; + + nxpwifi_dbg(priv->adapter, DUMP, "dump_survey idx=%d\n", idx); + + memset(survey, 0, sizeof(struct survey_info)); + + if ((GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA) && + priv->media_connected && idx == 0) { + u8 curr_bss_band = priv->curr_bss_params.band; + u32 chan = priv->curr_bss_params.bss_descriptor.channel; + + band = nxpwifi_band_to_radio_type(curr_bss_band); + survey->channel = ieee80211_get_channel + (wiphy, + ieee80211_channel_to_frequency(chan, band)); + + if (priv->bcn_nf_last) { + survey->filled = SURVEY_INFO_NOISE_DBM; + survey->noise = priv->bcn_nf_last; + } + return 0; + } + + if (idx >= priv->adapter->num_in_chan_stats) + return -ENOENT; + + if (!pchan_stats[idx].cca_scan_dur) + return 0; + + band = pchan_stats[idx].bandcfg; + chan_num = pchan_stats[idx].chan_num; + survey->channel = ieee80211_get_channel + (wiphy, + ieee80211_channel_to_frequency(chan_num, band)); + survey->filled = SURVEY_INFO_NOISE_DBM | + SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY; + survey->noise = pchan_stats[idx].noise; + survey->time = pchan_stats[idx].cca_scan_dur; + survey->time_busy = pchan_stats[idx].cca_busy_dur; + + return 0; +} + +/* Supported rates to be advertised to the cfg80211 */ +static struct ieee80211_rate nxpwifi_rates[] = { + {.bitrate = 10, .hw_value = 2, }, + {.bitrate = 20, .hw_value = 4, }, + {.bitrate = 55, .hw_value = 11, }, + {.bitrate = 110, .hw_value = 22, }, + {.bitrate = 60, .hw_value = 12, }, + {.bitrate = 90, .hw_value = 18, }, + {.bitrate = 120, .hw_value = 24, }, + {.bitrate = 180, .hw_value = 36, }, + {.bitrate = 240, .hw_value = 48, }, + {.bitrate = 360, .hw_value = 72, }, + {.bitrate = 480, .hw_value = 96, }, + {.bitrate = 540, .hw_value = 108, }, +}; + +/* Channel definitions to be advertised to cfg80211 */ +static struct ieee80211_channel nxpwifi_channels_2ghz[] = { + {.center_freq = 2412, .hw_value = 1, }, + {.center_freq = 2417, .hw_value = 2, }, + {.center_freq = 2422, .hw_value = 3, }, + {.center_freq = 2427, .hw_value = 4, }, + {.center_freq = 2432, .hw_value = 5, }, + {.center_freq = 2437, .hw_value = 6, }, + {.center_freq = 2442, .hw_value = 7, }, + {.center_freq = 2447, .hw_value = 8, }, + {.center_freq = 2452, .hw_value = 9, }, + {.center_freq = 2457, .hw_value = 10, }, + {.center_freq = 2462, .hw_value = 11, }, + {.center_freq = 2467, .hw_value = 12, }, + {.center_freq = 2472, .hw_value = 13, }, + {.center_freq = 2484, .hw_value = 14, }, +}; + +static struct ieee80211_supported_band nxpwifi_band_2ghz = { + .channels = nxpwifi_channels_2ghz, + .n_channels = ARRAY_SIZE(nxpwifi_channels_2ghz), + .bitrates = nxpwifi_rates, + .n_bitrates = ARRAY_SIZE(nxpwifi_rates), +}; + +static struct ieee80211_channel nxpwifi_channels_5ghz[] = { + {.center_freq = 5040, .hw_value = 8, }, + {.center_freq = 5060, .hw_value = 12, }, + {.center_freq = 5080, .hw_value = 16, }, + {.center_freq = 5170, .hw_value = 34, }, + {.center_freq = 5190, .hw_value = 38, }, + {.center_freq = 5210, .hw_value = 42, }, + {.center_freq = 5230, .hw_value = 46, }, + {.center_freq = 5180, .hw_value = 36, }, + {.center_freq = 5200, .hw_value = 40, }, + {.center_freq = 5220, .hw_value = 44, }, + {.center_freq = 5240, .hw_value = 48, }, + {.center_freq = 5260, .hw_value = 52, }, + {.center_freq = 5280, .hw_value = 56, }, + {.center_freq = 5300, .hw_value = 60, }, + {.center_freq = 5320, .hw_value = 64, }, + {.center_freq = 5500, .hw_value = 100, }, + {.center_freq = 5520, .hw_value = 104, }, + {.center_freq = 5540, .hw_value = 108, }, + {.center_freq = 5560, .hw_value = 112, }, + {.center_freq = 5580, .hw_value = 116, }, + {.center_freq = 5600, .hw_value = 120, }, + {.center_freq = 5620, .hw_value = 124, }, + {.center_freq = 5640, .hw_value = 128, }, + {.center_freq = 5660, .hw_value = 132, }, + {.center_freq = 5680, .hw_value = 136, }, + {.center_freq = 5700, .hw_value = 140, }, + {.center_freq = 5745, .hw_value = 149, }, + {.center_freq = 5765, .hw_value = 153, }, + {.center_freq = 5785, .hw_value = 157, }, + {.center_freq = 5805, .hw_value = 161, }, + {.center_freq = 5825, .hw_value = 165, }, +}; + +static struct ieee80211_supported_band nxpwifi_band_5ghz = { + .channels = nxpwifi_channels_5ghz, + .n_channels = ARRAY_SIZE(nxpwifi_channels_5ghz), + .bitrates = nxpwifi_rates + 4, + .n_bitrates = ARRAY_SIZE(nxpwifi_rates) - 4, +}; + +/* Supported crypto cipher suits to be advertised to cfg80211 */ +static const u32 nxpwifi_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_SMS4, + WLAN_CIPHER_SUITE_AES_CMAC, +}; + +/* Supported mgmt frame types to be advertised to cfg80211 */ +static const struct ieee80211_txrx_stypes +nxpwifi_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4), + }, +}; + +/* CFG802.11 operation handler for setting bit rates. + * + * Function configures data rates to firmware using bitrate mask + * provided by cfg80211. + */ +static int +nxpwifi_cfg80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, + unsigned int link_id, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + enum nl80211_band band; + struct nxpwifi_adapter *adapter = priv->adapter; + + if (!priv->media_connected) { + nxpwifi_dbg(adapter, ERROR, + "Can not set Tx data rate in disconnected state\n"); + return -EINVAL; + } + + band = nxpwifi_band_to_radio_type(priv->curr_bss_params.band); + + memset(bitmap_rates, 0, sizeof(bitmap_rates)); + + /* Fill HR/DSSS rates. */ + if (band == NL80211_BAND_2GHZ) + bitmap_rates[0] = mask->control[band].legacy & 0x000f; + + /* Fill OFDM rates */ + if (band == NL80211_BAND_2GHZ) + bitmap_rates[1] = (mask->control[band].legacy & 0x0ff0) >> 4; + else + bitmap_rates[1] = mask->control[band].legacy; + + /* Fill HT MCS rates */ + bitmap_rates[2] = mask->control[band].ht_mcs[0]; + if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) + bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8; + + /* Fill VHT MCS rates */ + if (adapter->fw_api_ver == NXPWIFI_FW_V15) { + bitmap_rates[10] = mask->control[band].vht_mcs[0]; + if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) + bitmap_rates[11] = mask->control[band].vht_mcs[1]; + } + + return nxpwifi_send_cmd(priv, HOST_CMD_TX_RATE_CFG, + HOST_ACT_GEN_SET, 0, bitmap_rates, true); +} + +/* CFG802.11 operation handler for connection quality monitoring. + * + * This function subscribes/unsubscribes HIGH_RSSI and LOW_RSSI + * events to FW. + */ +static int nxpwifi_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, + struct net_device *dev, + s32 rssi_thold, u32 rssi_hyst) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_ds_misc_subsc_evt subsc_evt; + int ret = 0; + + priv->cqm_rssi_thold = rssi_thold; + priv->cqm_rssi_hyst = rssi_hyst; + + memset(&subsc_evt, 0x00, sizeof(struct nxpwifi_ds_misc_subsc_evt)); + subsc_evt.events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH; + + /* Subscribe/unsubscribe low and high rssi events */ + if (rssi_thold && rssi_hyst) { + subsc_evt.action = HOST_ACT_BITWISE_SET; + subsc_evt.bcn_l_rssi_cfg.abs_value = abs(rssi_thold); + subsc_evt.bcn_h_rssi_cfg.abs_value = abs(rssi_thold); + subsc_evt.bcn_l_rssi_cfg.evt_freq = 1; + subsc_evt.bcn_h_rssi_cfg.evt_freq = 1; + ret = nxpwifi_send_cmd(priv, + HOST_CMD_802_11_SUBSCRIBE_EVENT, + 0, 0, &subsc_evt, true); + } else { + subsc_evt.action = HOST_ACT_BITWISE_CLR; + ret = nxpwifi_send_cmd(priv, + HOST_CMD_802_11_SUBSCRIBE_EVENT, + 0, 0, &subsc_evt, true); + } + + return ret; +} + +int nxpwifi_cfg80211_change_beacon_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *data) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_adapter *adapter = priv->adapter; + int ret; + + nxpwifi_cancel_scan(adapter); + + if (GET_BSS_ROLE(priv) != NXPWIFI_BSS_ROLE_UAP) { + nxpwifi_dbg(priv->adapter, ERROR, + "%s: bss_type mismatched\n", __func__); + return -EINVAL; + } + + ret = nxpwifi_set_mgmt_ies(priv, data); + if (ret) + nxpwifi_dbg(priv->adapter, ERROR, + "%s: setting mgmt ies failed\n", __func__); + + return ret; +} + +/* cfg80211 operation handler for change_beacon. + * Function retrieves and sets modified management IEs to FW. + */ +static int nxpwifi_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_update *params) +{ + int ret; + + ret = nxpwifi_cfg80211_change_beacon_data(wiphy, dev, ¶ms->beacon); + + return ret; +} + +/* cfg80211 operation handler for del_station. + * Function deauthenticates station which value is provided in mac parameter. + * If mac is NULL/broadcast, all stations in associated station list are + * deauthenticated. If bss is not started or there are no stations in + * associated stations list, no action is taken. + */ +static int +nxpwifi_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, + struct station_del_parameters *params) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_sta_node *sta_node; + u8 deauth_mac[ETH_ALEN]; + int ret = 0; + + if (!priv->bss_started && priv->wdev.cac_started) { + nxpwifi_dbg(priv->adapter, INFO, "%s: abort CAC!\n", __func__); + nxpwifi_abort_cac(priv); + } + + if (list_empty(&priv->sta_list) || !priv->bss_started) + return 0; + + if (!params->mac || is_broadcast_ether_addr(params->mac)) + return 0; + + nxpwifi_dbg(priv->adapter, INFO, "%s: mac address %pM\n", + __func__, params->mac); + + eth_zero_addr(deauth_mac); + + spin_lock_bh(&priv->sta_list_spinlock); + sta_node = nxpwifi_get_sta_entry(priv, params->mac); + if (sta_node) + ether_addr_copy(deauth_mac, params->mac); + spin_unlock_bh(&priv->sta_list_spinlock); + + if (is_valid_ether_addr(deauth_mac)) + ret = nxpwifi_send_cmd(priv, HOST_CMD_UAP_STA_DEAUTH, + HOST_ACT_GEN_SET, 0, + deauth_mac, true); + + return ret; +} + +static int +nxpwifi_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_private *priv = nxpwifi_get_priv(adapter, + NXPWIFI_BSS_ROLE_ANY); + struct nxpwifi_ds_ant_cfg ant_cfg; + + if (!tx_ant || !rx_ant) + return -EOPNOTSUPP; + + if (adapter->hw_dev_mcs_support != HT_STREAM_2X2) { + /* Not a MIMO chip. User should provide specific antenna number + * for Tx/Rx path or enable all antennas for diversity + */ + if (tx_ant != rx_ant) + return -EOPNOTSUPP; + + if ((tx_ant & (tx_ant - 1)) && + (tx_ant != BIT(adapter->number_of_antenna) - 1)) + return -EOPNOTSUPP; + + if ((tx_ant == BIT(adapter->number_of_antenna) - 1) && + priv->adapter->number_of_antenna > 1) { + tx_ant = RF_ANTENNA_AUTO; + rx_ant = RF_ANTENNA_AUTO; + } + } else { + struct ieee80211_sta_ht_cap *ht_info; + int rx_mcs_supp; + enum nl80211_band band; + + if ((tx_ant == 0x1 && rx_ant == 0x1)) { + adapter->user_dev_mcs_support = HT_STREAM_1X1; + if (adapter->is_hw_11ac_capable) + adapter->usr_dot_11ac_mcs_support = + NXPWIFI_11AC_MCS_MAP_1X1; + } else { + adapter->user_dev_mcs_support = HT_STREAM_2X2; + if (adapter->is_hw_11ac_capable) + adapter->usr_dot_11ac_mcs_support = + NXPWIFI_11AC_MCS_MAP_2X2; + } + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!adapter->wiphy->bands[band]) + continue; + + ht_info = &adapter->wiphy->bands[band]->ht_cap; + rx_mcs_supp = + GET_RXMCSSUPP(adapter->user_dev_mcs_support); + memset(&ht_info->mcs, 0, adapter->number_of_antenna); + memset(&ht_info->mcs, 0xff, rx_mcs_supp); + } + } + + ant_cfg.tx_ant = tx_ant; + ant_cfg.rx_ant = rx_ant; + + return nxpwifi_send_cmd(priv, HOST_CMD_RF_ANTENNA, + HOST_ACT_GEN_SET, 0, &ant_cfg, true); +} + +static int +nxpwifi_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_private *priv = nxpwifi_get_priv(adapter, + NXPWIFI_BSS_ROLE_ANY); + int ret; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_RF_ANTENNA, + HOST_ACT_GEN_GET, 0, NULL, true); + + if (!ret) { + *tx_ant = priv->tx_ant; + *rx_ant = priv->rx_ant; + } + + return ret; +} + +/* cfg80211 operation handler for stop ap. + * Function stops BSS running at uAP interface. + */ +static int nxpwifi_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + int ret; + + nxpwifi_abort_cac(priv); + + if (nxpwifi_del_mgmt_ies(priv)) + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to delete mgmt IEs!\n"); + + priv->ap_11n_enabled = 0; + memset(&priv->bss_cfg, 0, sizeof(priv->bss_cfg)); + + ret = nxpwifi_send_cmd(priv, HOST_CMD_UAP_BSS_STOP, + HOST_ACT_GEN_SET, 0, NULL, true); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to stop the BSS\n"); + goto done; + } + + ret = nxpwifi_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET, + HOST_ACT_GEN_SET, 0, NULL, true); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to reset BSS\n"); + goto done; + } + + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + nxpwifi_stop_net_dev_queue(priv->netdev, priv->adapter); + +done: + return ret; +} + +/* cfg80211 operation handler for start_ap. + * Function sets beacon period, DTIM period, SSID and security into + * AP config structure. + * AP is configured with these settings and BSS is started. + */ +static int nxpwifi_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params) +{ + struct nxpwifi_uap_bss_param *bss_cfg; + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_private *tmp_priv; + int i; + struct nxpwifi_current_bss_params *bss_params; + enum nl80211_band band; + int freq; + int ret; + + if (GET_BSS_ROLE(priv) != NXPWIFI_BSS_ROLE_UAP) + return -EINVAL; + + for (i = 0; i < NXPWIFI_MAX_BSS_NUM; i++) { + tmp_priv = adapter->priv[i]; + if (tmp_priv == priv) + continue; + if (GET_BSS_ROLE(tmp_priv) == NXPWIFI_BSS_ROLE_STA && + tmp_priv->media_connected) { + bss_params = &tmp_priv->curr_bss_params; + band = nxpwifi_band_to_radio_type(bss_params->band); + freq = ieee80211_channel_to_frequency + (bss_params->bss_descriptor.channel, band); + if (!ieee80211_channel_equal + (params->chandef.chan, + ieee80211_get_channel(wiphy, freq))) { + nxpwifi_dbg + (priv->adapter, MSG, + "AP and STA must operate on same channel\n"); + return -EOPNOTSUPP; + } + } + } + + bss_cfg = kzalloc(sizeof(*bss_cfg), GFP_KERNEL); + if (!bss_cfg) + return -ENOMEM; + + nxpwifi_set_sys_config_invalid_data(bss_cfg); + + memcpy(bss_cfg->mac_addr, priv->curr_addr, ETH_ALEN); + + if (params->beacon_interval) + bss_cfg->beacon_period = params->beacon_interval; + if (params->dtim_period) + bss_cfg->dtim_period = params->dtim_period; + + if (params->ssid && params->ssid_len) { + memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); + bss_cfg->ssid.ssid_len = params->ssid_len; + } + if (params->inactivity_timeout > 0) { + /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ + bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout; + bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout; + } + + switch (params->hidden_ssid) { + case NL80211_HIDDEN_SSID_NOT_IN_USE: + bss_cfg->bcast_ssid_ctl = 1; + break; + case NL80211_HIDDEN_SSID_ZERO_LEN: + bss_cfg->bcast_ssid_ctl = 0; + break; + case NL80211_HIDDEN_SSID_ZERO_CONTENTS: + bss_cfg->bcast_ssid_ctl = 2; + break; + default: + kfree(bss_cfg); + return -EINVAL; + } + + nxpwifi_uap_set_channel(priv, bss_cfg, params->chandef); + nxpwifi_set_uap_rates(bss_cfg, params); + + ret = nxpwifi_set_secure_params(priv, bss_cfg, params); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to parse security parameters!\n"); + goto done; + } + + nxpwifi_set_ht_params(priv, bss_cfg, params); + + if (priv->adapter->is_hw_11ac_capable) { + nxpwifi_set_vht_params(priv, bss_cfg, params); + nxpwifi_set_vht_width(priv, params->chandef.width, + priv->ap_11ac_enabled); + } + + if (priv->ap_11ac_enabled) + nxpwifi_set_11ac_ba_params(priv); + else + nxpwifi_set_ba_params(priv); + + nxpwifi_set_wmm_params(priv, bss_cfg, params); + + if (nxpwifi_is_11h_active(priv)) + nxpwifi_set_tpc_params(priv, bss_cfg, params); + + if (nxpwifi_is_11h_active(priv) && + !cfg80211_chandef_dfs_required(wiphy, ¶ms->chandef, + priv->bss_mode)) { + nxpwifi_dbg(priv->adapter, INFO, + "Disable 11h extensions in FW\n"); + ret = nxpwifi_11h_activate(priv, false); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to disable 11h extensions!!"); + goto done; + } + priv->state_11h.is_11h_active = false; + } + + nxpwifi_config_uap_11d(priv, ¶ms->beacon); + + ret = nxpwifi_config_start_uap(priv, bss_cfg); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to start AP\n"); + goto done; + } + + ret = nxpwifi_set_mgmt_ies(priv, ¶ms->beacon); + if (ret) + goto done; + + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + nxpwifi_wake_up_net_dev_queue(priv->netdev, priv->adapter); + + memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg)); + +done: + kfree(bss_cfg); + return ret; +} + +/* CFG802.11 operation handler for scan request. + * + * This function issues a scan request to the firmware based upon + * the user specified scan configuration. On successful completion, + * it also informs the results. + */ +static int +nxpwifi_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request) +{ + struct net_device *dev = request->wdev->netdev; + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + int i, offset, ret; + struct ieee80211_channel *chan; + struct element *ie; + struct nxpwifi_user_scan_cfg *user_scan_cfg; + u8 mac_addr[ETH_ALEN]; + + nxpwifi_dbg(priv->adapter, CMD, + "info: received scan request on %s\n", dev->name); + + /* Block scan request if scan operation or scan cleanup when interface + * is disabled is in process + */ + if (priv->scan_request || priv->scan_aborting) { + nxpwifi_dbg(priv->adapter, WARN, + "cmd: Scan already in process..\n"); + return -EBUSY; + } + + if (!priv->wdev.connected && priv->scan_block) + priv->scan_block = false; + + if (!nxpwifi_stop_bg_scan(priv)) + cfg80211_sched_scan_stopped_locked(priv->wdev.wiphy, 0); + + user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); + if (!user_scan_cfg) + return -ENOMEM; + + priv->scan_request = request; + + if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + get_random_mask_addr(mac_addr, request->mac_addr, + request->mac_addr_mask); + ether_addr_copy(request->mac_addr, mac_addr); + ether_addr_copy(user_scan_cfg->random_mac, mac_addr); + } + + user_scan_cfg->num_ssids = request->n_ssids; + user_scan_cfg->ssid_list = request->ssids; + + if (request->ie && request->ie_len) { + offset = 0; + for (i = 0; i < NXPWIFI_MAX_VSIE_NUM; i++) { + if (priv->vs_ie[i].mask != NXPWIFI_VSIE_MASK_CLEAR) + continue; + priv->vs_ie[i].mask = NXPWIFI_VSIE_MASK_SCAN; + ie = (struct element *)(request->ie + offset); + memcpy(&priv->vs_ie[i].ie, ie, + sizeof(*ie) + ie->datalen); + offset += sizeof(*ie) + ie->datalen; + + if (offset >= request->ie_len) + break; + } + } + + for (i = 0; i < min_t(u32, request->n_channels, + NXPWIFI_USER_SCAN_CHAN_MAX); i++) { + chan = request->channels[i]; + user_scan_cfg->chan_list[i].chan_number = chan->hw_value; + user_scan_cfg->chan_list[i].radio_type = chan->band; + + if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids) + user_scan_cfg->chan_list[i].scan_type = + NXPWIFI_SCAN_TYPE_PASSIVE; + else + user_scan_cfg->chan_list[i].scan_type = + NXPWIFI_SCAN_TYPE_ACTIVE; + + user_scan_cfg->chan_list[i].scan_time = 0; + } + + if (priv->adapter->scan_chan_gap_enabled && + nxpwifi_is_any_intf_active(priv)) + user_scan_cfg->scan_chan_gap = + priv->adapter->scan_chan_gap_time; + + ret = nxpwifi_scan_networks(priv, user_scan_cfg); + kfree(user_scan_cfg); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "scan failed: %d\n", ret); + priv->scan_aborting = false; + priv->scan_request = NULL; + return ret; + } + + if (request->ie && request->ie_len) { + for (i = 0; i < NXPWIFI_MAX_VSIE_NUM; i++) { + if (priv->vs_ie[i].mask == NXPWIFI_VSIE_MASK_SCAN) { + priv->vs_ie[i].mask = NXPWIFI_VSIE_MASK_CLEAR; + memset(&priv->vs_ie[i].ie, 0, + NXPWIFI_MAX_VSIE_LEN); + } + } + } + return 0; +} + +/* CFG802.11 operation handler for sched_scan_start. + * + * This function issues a bgscan config request to the firmware based upon + * the user specified sched_scan configuration. On successful completion, + * firmware will generate BGSCAN_REPORT event, driver should issue bgscan + * query command to get sched_scan results from firmware. + */ +static int +nxpwifi_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *request) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + int i, offset; + struct ieee80211_channel *chan; + struct nxpwifi_bg_scan_cfg *bgscan_cfg; + struct element *ie; + int ret; + + if (!request || (!request->n_ssids && !request->n_match_sets)) { + wiphy_err(wiphy, "%s : Invalid Sched_scan parameters", + __func__); + return -EINVAL; + } + + wiphy_info(wiphy, "sched_scan start : n_ssids=%d n_match_sets=%d ", + request->n_ssids, request->n_match_sets); + wiphy_info(wiphy, "n_channels=%d interval=%d ie_len=%d\n", + request->n_channels, request->scan_plans->interval, + (int)request->ie_len); + + bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL); + if (!bgscan_cfg) + return -ENOMEM; + + if (priv->scan_request || priv->scan_aborting) + bgscan_cfg->start_later = true; + + bgscan_cfg->num_ssids = request->n_match_sets; + bgscan_cfg->ssid_list = request->match_sets; + + if (request->ie && request->ie_len) { + offset = 0; + for (i = 0; i < NXPWIFI_MAX_VSIE_NUM; i++) { + if (priv->vs_ie[i].mask != NXPWIFI_VSIE_MASK_CLEAR) + continue; + priv->vs_ie[i].mask = NXPWIFI_VSIE_MASK_BGSCAN; + ie = (struct element *)(request->ie + offset); + memcpy(&priv->vs_ie[i].ie, ie, + sizeof(*ie) + ie->datalen); + offset += sizeof(*ie) + ie->datalen; + + if (offset >= request->ie_len) + break; + } + } + + for (i = 0; i < min_t(u32, request->n_channels, + NXPWIFI_BG_SCAN_CHAN_MAX); i++) { + chan = request->channels[i]; + bgscan_cfg->chan_list[i].chan_number = chan->hw_value; + bgscan_cfg->chan_list[i].radio_type = chan->band; + + if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids) + bgscan_cfg->chan_list[i].scan_type = + NXPWIFI_SCAN_TYPE_PASSIVE; + else + bgscan_cfg->chan_list[i].scan_type = + NXPWIFI_SCAN_TYPE_ACTIVE; + + bgscan_cfg->chan_list[i].scan_time = 0; + } + + bgscan_cfg->chan_per_scan = min_t(u32, request->n_channels, + NXPWIFI_BG_SCAN_CHAN_MAX); + + /* Use at least 15 second for per scan cycle */ + bgscan_cfg->scan_interval = (request->scan_plans->interval > + NXPWIFI_BGSCAN_INTERVAL) ? + request->scan_plans->interval : + NXPWIFI_BGSCAN_INTERVAL; + + bgscan_cfg->repeat_count = NXPWIFI_BGSCAN_REPEAT_COUNT; + bgscan_cfg->report_condition = NXPWIFI_BGSCAN_SSID_MATCH | + NXPWIFI_BGSCAN_WAIT_ALL_CHAN_DONE; + bgscan_cfg->bss_type = NXPWIFI_BSS_MODE_INFRA; + bgscan_cfg->action = NXPWIFI_BGSCAN_ACT_SET; + bgscan_cfg->enable = true; + if (request->min_rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) { + bgscan_cfg->report_condition |= NXPWIFI_BGSCAN_SSID_RSSI_MATCH; + bgscan_cfg->rssi_threshold = request->min_rssi_thold; + } + + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_BG_SCAN_CONFIG, + HOST_ACT_GEN_SET, 0, bgscan_cfg, true); + + if (!ret) + priv->sched_scanning = true; + + kfree(bgscan_cfg); + return ret; +} + +/* CFG802.11 operation handler for sched_scan_stop. + * + * This function issues a bgscan config command to disable + * previous bgscan configuration in the firmware + */ +static int nxpwifi_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev, u64 reqid) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + + wiphy_info(wiphy, "sched scan stop!"); + return nxpwifi_stop_bg_scan(priv); +} + +static void nxpwifi_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info, + struct nxpwifi_private *priv) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + + vht_info->vht_supported = true; + + vht_info->cap = adapter->hw_dot_11ac_dev_cap; + /* Update MCS support for VHT */ + vht_info->vht_mcs.rx_mcs_map = + cpu_to_le16(adapter->hw_dot_11ac_mcs_support & 0xFFFF); + vht_info->vht_mcs.rx_highest = 0; + vht_info->vht_mcs.tx_mcs_map = + cpu_to_le16(adapter->hw_dot_11ac_mcs_support >> 16); + vht_info->vht_mcs.tx_highest = 0; +} + +/* This function sets up the CFG802.11 specific HT capability fields + * with default values. + * + * The following default values are set - + * - HT Supported = True + * - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K + * - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE + * - HT Capabilities supported by firmware + * - MCS information, Rx mask = 0xff + * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01) + */ +static void +nxpwifi_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, + struct nxpwifi_private *priv) +{ + int rx_mcs_supp; + struct ieee80211_mcs_info mcs_set; + u8 *mcs = (u8 *)&mcs_set; + struct nxpwifi_adapter *adapter = priv->adapter; + + ht_info->ht_supported = true; + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; + + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + + /* Fill HT capability information */ + if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20; + + if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40; + + if (adapter->user_dev_mcs_support == HT_STREAM_2X2) + ht_info->cap |= 2 << IEEE80211_HT_CAP_RX_STBC_SHIFT; + else + ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; + + if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + else + ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC; + + if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + else + ht_info->cap &= ~IEEE80211_HT_CAP_GRN_FLD; + + if (ISENABLED_40MHZ_INTOLERANT(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT; + else + ht_info->cap &= ~IEEE80211_HT_CAP_40MHZ_INTOLERANT; + + if (ISSUPP_RXLDPC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + else + ht_info->cap &= ~IEEE80211_HT_CAP_LDPC_CODING; + + ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + ht_info->cap |= IEEE80211_HT_CAP_SM_PS; + + rx_mcs_supp = GET_RXMCSSUPP(adapter->user_dev_mcs_support); + /* Set MCS for 1x1/2x2 */ + memset(mcs, 0xff, rx_mcs_supp); + /* Clear all the other values */ + memset(&mcs[rx_mcs_supp], 0, + sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); + if (priv->bss_mode == NL80211_IFTYPE_STATION || + ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) + /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ + SETHT_MCS32(mcs_set.rx_mask); + + memcpy((u8 *)&ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info)); + + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +} + +/* create a new virtual interface with the given name and name assign type + */ +struct wireless_dev *nxpwifi_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_private *priv; + struct net_device *dev; + void *mdev_priv; + int ret; + + if (!adapter) + return ERR_PTR(-EFAULT); + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_STATION: + if (adapter->curr_iface_comb.sta_intf == + adapter->iface_limit.sta_intf) { + nxpwifi_dbg(adapter, ERROR, + "cannot create multiple sta ifaces\n"); + return ERR_PTR(-EINVAL); + } + + priv = nxpwifi_get_unused_priv_by_bss_type + (adapter, NXPWIFI_BSS_TYPE_STA); + if (!priv) { + nxpwifi_dbg(adapter, ERROR, + "could not get free private struct\n"); + return ERR_PTR(-EFAULT); + } + + priv->wdev.wiphy = wiphy; + priv->wdev.iftype = NL80211_IFTYPE_STATION; + + if (type == NL80211_IFTYPE_UNSPECIFIED) + priv->bss_mode = NL80211_IFTYPE_STATION; + else + priv->bss_mode = type; + + priv->bss_type = NXPWIFI_BSS_TYPE_STA; + priv->frame_type = NXPWIFI_DATA_FRAME_TYPE_ETH_II; + priv->bss_priority = 0; + priv->bss_role = NXPWIFI_BSS_ROLE_STA; + + break; + case NL80211_IFTYPE_AP: + if (adapter->curr_iface_comb.uap_intf == + adapter->iface_limit.uap_intf) { + nxpwifi_dbg(adapter, ERROR, + "cannot create multiple AP ifaces\n"); + return ERR_PTR(-EINVAL); + } + + priv = nxpwifi_get_unused_priv_by_bss_type + (adapter, NXPWIFI_BSS_TYPE_UAP); + if (!priv) { + nxpwifi_dbg(adapter, ERROR, + "could not get free private struct\n"); + return ERR_PTR(-EFAULT); + } + + priv->wdev.wiphy = wiphy; + priv->wdev.iftype = NL80211_IFTYPE_AP; + + priv->bss_type = NXPWIFI_BSS_TYPE_UAP; + priv->frame_type = NXPWIFI_DATA_FRAME_TYPE_ETH_II; + priv->bss_priority = 0; + priv->bss_role = NXPWIFI_BSS_ROLE_UAP; + priv->bss_started = 0; + priv->bss_mode = type; + + break; + default: + nxpwifi_dbg(adapter, ERROR, "type not supported\n"); + return ERR_PTR(-EINVAL); + } + + dev = alloc_netdev_mqs(sizeof(struct nxpwifi_private *), name, + name_assign_type, ether_setup, + IEEE80211_NUM_ACS, 1); + if (!dev) { + nxpwifi_dbg(adapter, ERROR, + "no memory available for netdevice\n"); + ret = -ENOMEM; + goto err_alloc_netdev; + } + + nxpwifi_init_priv_params(priv, dev); + + priv->netdev = dev; + + nxpwifi_set_mac_address(priv, dev, false, NULL); + + ret = nxpwifi_send_cmd(priv, HOST_CMD_SET_BSS_MODE, + HOST_ACT_GEN_SET, 0, NULL, true); + if (ret) + goto err_set_bss_mode; + + ret = nxpwifi_sta_init_cmd(priv, false, false); + if (ret) + goto err_sta_init; + + nxpwifi_setup_ht_caps(&wiphy->bands[NL80211_BAND_2GHZ]->ht_cap, priv); + if (adapter->is_hw_11ac_capable) + nxpwifi_setup_vht_caps + (&wiphy->bands[NL80211_BAND_2GHZ]->vht_cap, priv); + + if (adapter->config_bands & BAND_A) + nxpwifi_setup_ht_caps + (&wiphy->bands[NL80211_BAND_5GHZ]->ht_cap, priv); + + if ((adapter->config_bands & BAND_A) && adapter->is_hw_11ac_capable) + nxpwifi_setup_vht_caps + (&wiphy->bands[NL80211_BAND_5GHZ]->vht_cap, priv); + + dev_net_set(dev, wiphy_net(wiphy)); + dev->ieee80211_ptr = &priv->wdev; + dev->ieee80211_ptr->iftype = priv->bss_mode; + SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); + + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->watchdog_timeo = NXPWIFI_DEFAULT_WATCHDOG_TIMEOUT; + dev->needed_headroom = NXPWIFI_MIN_DATA_HEADER_LEN; + dev->ethtool_ops = &nxpwifi_ethtool_ops; + + mdev_priv = netdev_priv(dev); + *((unsigned long *)mdev_priv) = (unsigned long)priv; + + SET_NETDEV_DEV(dev, adapter->dev); + + INIT_DELAYED_WORK(&priv->dfs_cac_work, nxpwifi_dfs_cac_work); + + INIT_DELAYED_WORK(&priv->dfs_chan_sw_work, nxpwifi_dfs_chan_sw_work); + + /* Register network device */ + if (cfg80211_register_netdevice(dev)) { + nxpwifi_dbg(adapter, ERROR, "cannot register network device\n"); + ret = -EFAULT; + goto err_reg_netdev; + } + + nxpwifi_dbg(adapter, INFO, + "info: %s: NXP 802.11 Adapter\n", dev->name); + +#ifdef CONFIG_DEBUG_FS + nxpwifi_dev_debugfs_init(priv); +#endif + + update_vif_type_counter(adapter, type, 1); + + return &priv->wdev; + +err_reg_netdev: + free_netdev(dev); + priv->netdev = NULL; +err_sta_init: +err_set_bss_mode: +err_alloc_netdev: + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(nxpwifi_add_virtual_intf); + +/* del_virtual_intf: remove the virtual interface determined by dev + */ +int nxpwifi_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev); + struct nxpwifi_adapter *adapter = priv->adapter; + struct sk_buff *skb, *tmp; + +#ifdef CONFIG_DEBUG_FS + nxpwifi_dev_debugfs_remove(priv); +#endif + + if (priv->sched_scanning) + priv->sched_scanning = false; + + nxpwifi_stop_net_dev_queue(priv->netdev, adapter); + + skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) { + skb_unlink(skb, &priv->bypass_txq); + nxpwifi_write_data_complete(priv->adapter, skb, 0, -1); + } + + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + + if (wdev->netdev->reg_state == NETREG_REGISTERED) + cfg80211_unregister_netdevice(wdev->netdev); + + /* Clear the priv in adapter */ + priv->netdev = NULL; + + update_vif_type_counter(adapter, priv->bss_mode, -1); + + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) + kfree(priv->hist_data); + + return 0; +} +EXPORT_SYMBOL_GPL(nxpwifi_del_virtual_intf); + +static bool +nxpwifi_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, + u8 max_byte_seq) +{ + int j, k, valid_byte_cnt = 0; + bool dont_care_byte = false; + + for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) { + for (k = 0; k < 8; k++) { + if (pat->mask[j] & 1 << k) { + memcpy(byte_seq + valid_byte_cnt, + &pat->pattern[j * 8 + k], 1); + valid_byte_cnt++; + if (dont_care_byte) + return false; + } else { + if (valid_byte_cnt) + dont_care_byte = true; + } + + /* wildcard bytes record as the offset + * before the valid byte + */ + if (!valid_byte_cnt && !dont_care_byte) + pat->pkt_offset++; + + if (valid_byte_cnt > max_byte_seq) + return false; + } + } + + byte_seq[max_byte_seq] = valid_byte_cnt; + + return true; +} + +#ifdef CONFIG_PM +static void nxpwifi_set_auto_arp_mef_entry(struct nxpwifi_private *priv, + struct nxpwifi_mef_entry *mef_entry) +{ + int i, filt_num = 0, num_ipv4 = 0; + struct in_device *in_dev; + struct in_ifaddr *ifa; + __be32 ips[NXPWIFI_MAX_SUPPORTED_IPADDR]; + struct nxpwifi_adapter *adapter = priv->adapter; + + mef_entry->mode = MEF_MODE_HOST_SLEEP; + mef_entry->action = MEF_ACTION_AUTO_ARP; + + /* Enable ARP offload feature */ + memset(ips, 0, sizeof(ips)); + for (i = 0; i < NXPWIFI_MAX_BSS_NUM; i++) { + if (adapter->priv[i]->netdev) { + in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev); + if (!in_dev) + continue; + ifa = rtnl_dereference(in_dev->ifa_list); + if (!ifa || !ifa->ifa_local) + continue; + ips[i] = ifa->ifa_local; + num_ipv4++; + } + } + + for (i = 0; i < num_ipv4; i++) { + if (!ips[i]) + continue; + mef_entry->filter[filt_num].repeat = 1; + memcpy(mef_entry->filter[filt_num].byte_seq, + (u8 *)&ips[i], sizeof(ips[i])); + mef_entry->filter[filt_num].byte_seq[NXPWIFI_MEF_MAX_BYTESEQ] = + sizeof(ips[i]); + mef_entry->filter[filt_num].offset = 46; + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + if (filt_num) { + mef_entry->filter[filt_num].filt_action = + TYPE_OR; + } + filt_num++; + } + + mef_entry->filter[filt_num].repeat = 1; + mef_entry->filter[filt_num].byte_seq[0] = 0x08; + mef_entry->filter[filt_num].byte_seq[1] = 0x06; + mef_entry->filter[filt_num].byte_seq[NXPWIFI_MEF_MAX_BYTESEQ] = 2; + mef_entry->filter[filt_num].offset = 20; + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + mef_entry->filter[filt_num].filt_action = TYPE_AND; +} + +static int nxpwifi_set_wowlan_mef_entry(struct nxpwifi_private *priv, + struct nxpwifi_ds_mef_cfg *mef_cfg, + struct nxpwifi_mef_entry *mef_entry, + struct cfg80211_wowlan *wowlan) +{ + int i, filt_num = 0, ret = 0; + bool first_pat = true; + u8 byte_seq[NXPWIFI_MEF_MAX_BYTESEQ + 1]; + static const u8 ipv4_mc_mac[] = {0x33, 0x33}; + static const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; + + mef_entry->mode = MEF_MODE_HOST_SLEEP; + mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST; + + for (i = 0; i < wowlan->n_patterns; i++) { + memset(byte_seq, 0, sizeof(byte_seq)); + if (!nxpwifi_is_pattern_supported + (&wowlan->patterns[i], byte_seq, + NXPWIFI_MEF_MAX_BYTESEQ)) { + nxpwifi_dbg(priv->adapter, ERROR, + "Pattern not supported\n"); + return -EOPNOTSUPP; + } + + if (!wowlan->patterns[i].pkt_offset) { + if (is_unicast_ether_addr(byte_seq) && + byte_seq[NXPWIFI_MEF_MAX_BYTESEQ] == 1) { + mef_cfg->criteria |= NXPWIFI_CRITERIA_UNICAST; + continue; + } else if (is_broadcast_ether_addr(byte_seq)) { + mef_cfg->criteria |= NXPWIFI_CRITERIA_BROADCAST; + continue; + } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && + (byte_seq[NXPWIFI_MEF_MAX_BYTESEQ] == 2)) || + (!memcmp(byte_seq, ipv6_mc_mac, 3) && + (byte_seq[NXPWIFI_MEF_MAX_BYTESEQ] == 3))) { + mef_cfg->criteria |= NXPWIFI_CRITERIA_MULTICAST; + continue; + } + } + mef_entry->filter[filt_num].repeat = 1; + mef_entry->filter[filt_num].offset = + wowlan->patterns[i].pkt_offset; + memcpy(mef_entry->filter[filt_num].byte_seq, byte_seq, + sizeof(byte_seq)); + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + + if (first_pat) { + first_pat = false; + nxpwifi_dbg(priv->adapter, INFO, "Wake on patterns\n"); + } else { + mef_entry->filter[filt_num].filt_action = TYPE_AND; + } + + filt_num++; + } + + if (wowlan->magic_pkt) { + mef_cfg->criteria |= NXPWIFI_CRITERIA_UNICAST; + mef_entry->filter[filt_num].repeat = 16; + memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, + ETH_ALEN); + mef_entry->filter[filt_num].byte_seq[NXPWIFI_MEF_MAX_BYTESEQ] = + ETH_ALEN; + mef_entry->filter[filt_num].offset = 28; + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + if (filt_num) + mef_entry->filter[filt_num].filt_action = TYPE_OR; + + filt_num++; + mef_entry->filter[filt_num].repeat = 16; + memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, + ETH_ALEN); + mef_entry->filter[filt_num].byte_seq[NXPWIFI_MEF_MAX_BYTESEQ] = + ETH_ALEN; + mef_entry->filter[filt_num].offset = 56; + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + mef_entry->filter[filt_num].filt_action = TYPE_OR; + nxpwifi_dbg(priv->adapter, INFO, "Wake on magic packet\n"); + } + return ret; +} + +static int nxpwifi_set_mef_filter(struct nxpwifi_private *priv, + struct cfg80211_wowlan *wowlan) +{ + int ret = 0, num_entries = 1; + struct nxpwifi_ds_mef_cfg mef_cfg; + struct nxpwifi_mef_entry *mef_entry; + + if (wowlan->n_patterns || wowlan->magic_pkt) + num_entries++; + + mef_entry = kcalloc(num_entries, sizeof(*mef_entry), GFP_KERNEL); + if (!mef_entry) + return -ENOMEM; + + memset(&mef_cfg, 0, sizeof(mef_cfg)); + mef_cfg.criteria |= NXPWIFI_CRITERIA_BROADCAST | + NXPWIFI_CRITERIA_UNICAST; + mef_cfg.num_entries = num_entries; + mef_cfg.mef_entry = mef_entry; + + nxpwifi_set_auto_arp_mef_entry(priv, &mef_entry[0]); + + if (wowlan->n_patterns || wowlan->magic_pkt) { + ret = nxpwifi_set_wowlan_mef_entry(priv, &mef_cfg, + &mef_entry[1], wowlan); + if (ret) + goto done; + } + + if (!mef_cfg.criteria) + mef_cfg.criteria = NXPWIFI_CRITERIA_BROADCAST | + NXPWIFI_CRITERIA_UNICAST | + NXPWIFI_CRITERIA_MULTICAST; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_MEF_CFG, HOST_ACT_GEN_SET, 0, + &mef_cfg, true); + +done: + kfree(mef_entry); + return ret; +} + +static int nxpwifi_cfg80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wowlan) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_ds_hs_cfg hs_cfg; + int i, ret = 0, retry_num = 10; + struct nxpwifi_private *priv; + struct nxpwifi_private *sta_priv = + nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA); + + sta_priv->scan_aborting = true; + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + nxpwifi_abort_cac(priv); + } + + nxpwifi_cancel_all_pending_cmd(adapter); + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv && priv->netdev) + netif_device_detach(priv->netdev); + } + + for (i = 0; i < retry_num; i++) { + if (!nxpwifi_wmm_lists_empty(adapter) || + !nxpwifi_bypass_txlist_empty(adapter) || + !skb_queue_empty(&adapter->tx_data_q)) + usleep_range(10000, 15000); + else + break; + } + + if (!wowlan) { + nxpwifi_dbg(adapter, INFO, + "None of the WOWLAN triggers enabled\n"); + ret = 0; + goto done; + } + + if (!sta_priv->media_connected && !wowlan->nd_config) { + nxpwifi_dbg(adapter, ERROR, + "Can not configure WOWLAN in disconnected state\n"); + ret = 0; + goto done; + } + + ret = nxpwifi_set_mef_filter(sta_priv, wowlan); + if (ret) { + nxpwifi_dbg(adapter, ERROR, "Failed to set MEF filter\n"); + goto done; + } + + memset(&hs_cfg, 0, sizeof(hs_cfg)); + hs_cfg.conditions = le32_to_cpu(adapter->hs_cfg.conditions); + + if (wowlan->nd_config) { + nxpwifi_dbg(adapter, INFO, "Wake on net detect\n"); + hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT; + nxpwifi_cfg80211_sched_scan_start(wiphy, sta_priv->netdev, + wowlan->nd_config); + } + + if (wowlan->disconnect) { + hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT; + nxpwifi_dbg(sta_priv->adapter, INFO, "Wake on device disconnect\n"); + } + + hs_cfg.is_invoke_hostcmd = false; + hs_cfg.gpio = adapter->hs_cfg.gpio; + hs_cfg.gap = adapter->hs_cfg.gap; + ret = nxpwifi_set_hs_params(sta_priv, HOST_ACT_GEN_SET, + NXPWIFI_SYNC_CMD, &hs_cfg); + if (ret) + nxpwifi_dbg(adapter, ERROR, "Failed to set HS params\n"); + +done: + sta_priv->scan_aborting = false; + return ret; +} + +static int nxpwifi_cfg80211_resume(struct wiphy *wiphy) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + struct nxpwifi_private *priv; + struct nxpwifi_ds_wakeup_reason wakeup_reason; + struct cfg80211_wowlan_wakeup wakeup_report; + int i; + bool report_wakeup_reason = true; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv && priv->netdev) + netif_device_attach(priv->netdev); + } + + if (!wiphy->wowlan_config) + goto done; + + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA); + nxpwifi_get_wakeup_reason(priv, HOST_ACT_GEN_GET, NXPWIFI_SYNC_CMD, + &wakeup_reason); + memset(&wakeup_report, 0, sizeof(struct cfg80211_wowlan_wakeup)); + + wakeup_report.pattern_idx = -1; + + switch (wakeup_reason.hs_wakeup_reason) { + case NO_HSWAKEUP_REASON: + break; + case BCAST_DATA_MATCHED: + break; + case MCAST_DATA_MATCHED: + break; + case UCAST_DATA_MATCHED: + break; + case MASKTABLE_EVENT_MATCHED: + break; + case NON_MASKABLE_EVENT_MATCHED: + if (wiphy->wowlan_config->disconnect) + wakeup_report.disconnect = true; + if (wiphy->wowlan_config->nd_config) + wakeup_report.net_detect = adapter->nd_info; + break; + case NON_MASKABLE_CONDITION_MATCHED: + break; + case MAGIC_PATTERN_MATCHED: + if (wiphy->wowlan_config->magic_pkt) + wakeup_report.magic_pkt = true; + if (wiphy->wowlan_config->n_patterns) + wakeup_report.pattern_idx = 1; + break; + case GTK_REKEY_FAILURE: + if (wiphy->wowlan_config->gtk_rekey_failure) + wakeup_report.gtk_rekey_failure = true; + break; + default: + report_wakeup_reason = false; + break; + } + + if (report_wakeup_reason) + cfg80211_report_wowlan_wakeup(&priv->wdev, &wakeup_report, + GFP_KERNEL); + +done: + if (adapter->nd_info) { + for (i = 0 ; i < adapter->nd_info->n_matches ; i++) + kfree(adapter->nd_info->matches[i]); + kfree(adapter->nd_info); + adapter->nd_info = NULL; + } + + return 0; +} + +static void nxpwifi_cfg80211_set_wakeup(struct wiphy *wiphy, + bool enabled) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + + device_set_wakeup_enable(adapter->dev, enabled); +} +#endif + +static int nxpwifi_get_coalesce_pkt_type(u8 *byte_seq) +{ + static const u8 ipv4_mc_mac[] = {0x33, 0x33}; + static const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; + static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff}; + + if ((byte_seq[0] & 0x01) && + byte_seq[NXPWIFI_COALESCE_MAX_BYTESEQ] == 1) + return PACKET_TYPE_UNICAST; + else if (!memcmp(byte_seq, bc_mac, 4)) + return PACKET_TYPE_BROADCAST; + else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && + byte_seq[NXPWIFI_COALESCE_MAX_BYTESEQ] == 2) || + (!memcmp(byte_seq, ipv6_mc_mac, 3) && + byte_seq[NXPWIFI_COALESCE_MAX_BYTESEQ] == 3)) + return PACKET_TYPE_MULTICAST; + + return 0; +} + +static int +nxpwifi_fill_coalesce_rule_info(struct nxpwifi_private *priv, + struct cfg80211_coalesce_rules *crule, + struct nxpwifi_coalesce_rule *mrule) +{ + u8 byte_seq[NXPWIFI_COALESCE_MAX_BYTESEQ + 1]; + struct filt_field_param *param; + int i; + + mrule->max_coalescing_delay = crule->delay; + + param = mrule->params; + + for (i = 0; i < crule->n_patterns; i++) { + memset(byte_seq, 0, sizeof(byte_seq)); + if (!nxpwifi_is_pattern_supported(&crule->patterns[i], + byte_seq, + NXPWIFI_COALESCE_MAX_BYTESEQ)) { + nxpwifi_dbg(priv->adapter, ERROR, + "Pattern not supported\n"); + return -EOPNOTSUPP; + } + + if (!crule->patterns[i].pkt_offset) { + u8 pkt_type; + + pkt_type = nxpwifi_get_coalesce_pkt_type(byte_seq); + if (pkt_type && mrule->pkt_type) { + nxpwifi_dbg(priv->adapter, ERROR, + "Multiple packet types not allowed\n"); + return -EOPNOTSUPP; + } else if (pkt_type) { + mrule->pkt_type = pkt_type; + continue; + } + } + + if (crule->condition == NL80211_COALESCE_CONDITION_MATCH) + param->operation = RECV_FILTER_MATCH_TYPE_EQ; + else + param->operation = RECV_FILTER_MATCH_TYPE_NE; + + param->operand_len = byte_seq[NXPWIFI_COALESCE_MAX_BYTESEQ]; + memcpy(param->operand_byte_stream, byte_seq, + param->operand_len); + param->offset = crule->patterns[i].pkt_offset; + param++; + + mrule->num_of_fields++; + } + + if (!mrule->pkt_type) { + nxpwifi_dbg(priv->adapter, ERROR, + "Packet type can not be determined\n"); + return -EOPNOTSUPP; + } + + return 0; +} + +static int nxpwifi_cfg80211_set_coalesce(struct wiphy *wiphy, + struct cfg80211_coalesce *coalesce) +{ + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); + int i, ret; + struct nxpwifi_ds_coalesce_cfg coalesce_cfg; + struct nxpwifi_private *priv = + nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA); + + memset(&coalesce_cfg, 0, sizeof(coalesce_cfg)); + if (!coalesce) { + nxpwifi_dbg(adapter, WARN, + "Disable coalesce and reset all previous rules\n"); + return nxpwifi_send_cmd(priv, HOST_CMD_COALESCE_CFG, + HOST_ACT_GEN_SET, 0, + &coalesce_cfg, true); + } + + coalesce_cfg.num_of_rules = coalesce->n_rules; + for (i = 0; i < coalesce->n_rules; i++) { + ret = nxpwifi_fill_coalesce_rule_info(priv, &coalesce->rules[i], + &coalesce_cfg.rule[i]); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "Recheck the patterns provided for rule %d\n", + i + 1); + return ret; + } + } + + return nxpwifi_send_cmd(priv, HOST_CMD_COALESCE_CFG, + HOST_ACT_GEN_SET, 0, &coalesce_cfg, true); +} + +static int +nxpwifi_cfg80211_uap_add_station(struct nxpwifi_private *priv, const u8 *mac, + struct station_parameters *params) +{ + struct nxpwifi_sta_info add_sta; + int ret; + + memcpy(add_sta.peer_mac, mac, ETH_ALEN); + add_sta.params = params; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_ADD_NEW_STATION, + HOST_ACT_ADD_STA, 0, (void *)&add_sta, true); + + if (!ret) { + struct station_info *sinfo = NULL; + + sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); + + if (sinfo) { + cfg80211_new_sta(priv->netdev, mac, sinfo, GFP_KERNEL); + kfree(sinfo); + } + } + + return ret; +} + +static int +nxpwifi_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_parameters *params) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + int ret = -EOPNOTSUPP; + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) + ret = nxpwifi_cfg80211_uap_add_station(priv, mac, params); + + return ret; +} + +static int +nxpwifi_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_csa_settings *params) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + int chsw_msec; + int ret; + + if (priv->adapter->scan_processing) { + nxpwifi_dbg(priv->adapter, ERROR, + "radar detection: scan in process...\n"); + return -EBUSY; + } + + if (priv->wdev.cac_started) + return -EBUSY; + + if (cfg80211_chandef_identical(¶ms->chandef, + &priv->dfs_chandef)) + return -EINVAL; + + if (params->block_tx) { + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + nxpwifi_stop_net_dev_queue(priv->netdev, priv->adapter); + priv->uap_stop_tx = true; + } + + ret = nxpwifi_del_mgmt_ies(priv); + if (ret) + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to delete mgmt IEs!\n"); + + ret = nxpwifi_set_mgmt_ies(priv, ¶ms->beacon_csa); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "%s: setting mgmt ies failed\n", __func__); + goto done; + } + + memcpy(&priv->dfs_chandef, ¶ms->chandef, sizeof(priv->dfs_chandef)); + memcpy(&priv->beacon_after, ¶ms->beacon_after, + sizeof(priv->beacon_after)); + + chsw_msec = max(params->count * priv->bss_cfg.beacon_period, 100); + nxpwifi_queue_delayed_work(priv->adapter, &priv->dfs_chan_sw_work, + msecs_to_jiffies(chsw_msec)); + +done: + return ret; +} + +static int nxpwifi_cfg80211_get_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + unsigned int link_id, + struct cfg80211_chan_def *chandef) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev); + struct nxpwifi_bssdescriptor *curr_bss; + struct ieee80211_channel *chan; + enum nl80211_channel_type chan_type; + enum nl80211_band band; + int freq; + int ret = -ENODATA; + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP && + cfg80211_chandef_valid(&priv->bss_chandef)) { + *chandef = priv->bss_chandef; + ret = 0; + } else if (priv->media_connected) { + curr_bss = &priv->curr_bss_params.bss_descriptor; + band = nxpwifi_band_to_radio_type(priv->curr_bss_params.band); + freq = ieee80211_channel_to_frequency(curr_bss->channel, band); + chan = ieee80211_get_channel(wiphy, freq); + + if (priv->ht_param_present) { + chan_type = nxpwifi_get_chan_type(priv); + cfg80211_chandef_create(chandef, chan, chan_type); + } else { + cfg80211_chandef_create(chandef, chan, + NL80211_CHAN_NO_HT); + } + ret = 0; + } + + return ret; +} + +#ifdef CONFIG_NL80211_TESTMODE + +enum nxpwifi_tm_attr { + __NXPWIFI_TM_ATTR_INVALID = 0, + NXPWIFI_TM_ATTR_CMD = 1, + NXPWIFI_TM_ATTR_DATA = 2, + + /* keep last */ + __NXPWIFI_TM_ATTR_AFTER_LAST, + NXPWIFI_TM_ATTR_MAX = __NXPWIFI_TM_ATTR_AFTER_LAST - 1, +}; + +static const struct nla_policy nxpwifi_tm_policy[NXPWIFI_TM_ATTR_MAX + 1] = { + [NXPWIFI_TM_ATTR_CMD] = { .type = NLA_U32 }, + [NXPWIFI_TM_ATTR_DATA] = { .type = NLA_BINARY, + .len = NXPWIFI_SIZE_OF_CMD_BUFFER }, +}; + +enum nxpwifi_tm_command { + NXPWIFI_TM_CMD_HOSTCMD = 0, +}; + +static int nxpwifi_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, + void *data, int len) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev); + struct nxpwifi_ds_misc_cmd *hostcmd; + struct nlattr *tb[NXPWIFI_TM_ATTR_MAX + 1]; + struct sk_buff *skb; + int err; + + if (!priv) + return -EINVAL; + + err = nla_parse_deprecated(tb, NXPWIFI_TM_ATTR_MAX, data, len, + nxpwifi_tm_policy, NULL); + if (err) + return err; + + if (!tb[NXPWIFI_TM_ATTR_CMD]) + return -EINVAL; + + switch (nla_get_u32(tb[NXPWIFI_TM_ATTR_CMD])) { + case NXPWIFI_TM_CMD_HOSTCMD: + if (!tb[NXPWIFI_TM_ATTR_DATA]) + return -EINVAL; + + hostcmd = kzalloc(sizeof(*hostcmd), GFP_KERNEL); + if (!hostcmd) + return -ENOMEM; + + hostcmd->len = nla_len(tb[NXPWIFI_TM_ATTR_DATA]); + memcpy(hostcmd->cmd, nla_data(tb[NXPWIFI_TM_ATTR_DATA]), + hostcmd->len); + + if (nxpwifi_send_cmd(priv, 0, 0, 0, hostcmd, true)) { + dev_err(priv->adapter->dev, "Failed to process hostcmd\n"); + kfree(hostcmd); + return -EFAULT; + } + + /* process hostcmd response*/ + skb = cfg80211_testmode_alloc_reply_skb(wiphy, hostcmd->len); + if (!skb) { + kfree(hostcmd); + return -ENOMEM; + } + err = nla_put(skb, NXPWIFI_TM_ATTR_DATA, + hostcmd->len, hostcmd->cmd); + if (err) { + kfree(hostcmd); + kfree_skb(skb); + return -EMSGSIZE; + } + + err = cfg80211_testmode_reply(skb); + kfree(hostcmd); + return err; + default: + return -EOPNOTSUPP; + } +} +#endif + +static int +nxpwifi_cfg80211_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + u32 cac_time_ms) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_radar_params radar_params; + int ret; + + if (priv->adapter->scan_processing) { + nxpwifi_dbg(priv->adapter, ERROR, + "radar detection: scan already in process...\n"); + return -EBUSY; + } + + if (!nxpwifi_is_11h_active(priv)) { + nxpwifi_dbg(priv->adapter, INFO, + "Enable 11h extensions in FW\n"); + if (nxpwifi_11h_activate(priv, true)) { + nxpwifi_dbg(priv->adapter, ERROR, + "Failed to activate 11h extensions!!"); + return -EPERM; + } + priv->state_11h.is_11h_active = true; + } + + memset(&radar_params, 0, sizeof(struct nxpwifi_radar_params)); + radar_params.chandef = chandef; + radar_params.cac_time_ms = cac_time_ms; + + memcpy(&priv->dfs_chandef, chandef, sizeof(priv->dfs_chandef)); + + ret = nxpwifi_send_cmd(priv, HOST_CMD_CHAN_REPORT_REQUEST, + HOST_ACT_GEN_SET, 0, &radar_params, true); + if (!ret) + nxpwifi_queue_delayed_work(priv->adapter, + &priv->dfs_cac_work, + msecs_to_jiffies(cac_time_ms)); + + return ret; +} + +static int +nxpwifi_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, + struct station_parameters *params) +{ + return 0; +} + +static int +nxpwifi_cfg80211_authenticate(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_auth_request *req) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_private *tmp_priv; + int i; + struct sk_buff *skb; + u16 pkt_len, auth_alg; + int ret; + struct nxpwifi_ieee80211_mgmt *mgmt; + struct nxpwifi_txinfo *tx_info; + u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT; + u8 trans = 1, status_code = 0; + u8 *varptr; + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) { + nxpwifi_dbg(adapter, ERROR, "Interface role is AP\n"); + return -EINVAL; + } + + if (priv->wdev.iftype != NL80211_IFTYPE_STATION) { + nxpwifi_dbg(adapter, ERROR, + "Interface type is not correct (type %d)\n", + priv->wdev.iftype); + return -EINVAL; + } + + for (i = 0; i < NXPWIFI_MAX_BSS_NUM; i++) { + tmp_priv = adapter->priv[i]; + if (tmp_priv == priv) + continue; + if (GET_BSS_ROLE(tmp_priv) == NXPWIFI_BSS_ROLE_UAP && + netif_carrier_ok(tmp_priv->netdev) && + cfg80211_chandef_valid(&tmp_priv->bss_chandef)) { + if (!ieee80211_channel_equal + (req->bss->channel, tmp_priv->bss_chandef.chan)) { + nxpwifi_dbg(adapter, MSG, + "STA/AP must on the same channel\n"); + return -EOPNOTSUPP; + } + } + } + + if (priv->auth_alg != WLAN_AUTH_SAE && + (priv->auth_flag & HOST_MLME_AUTH_PENDING)) { + nxpwifi_dbg(adapter, ERROR, "Pending auth on going\n"); + return -EBUSY; + } + + if (!priv->host_mlme_reg) { + priv->host_mlme_reg = true; + priv->mgmt_frame_mask |= HOST_MLME_MGMT_MASK; + nxpwifi_send_cmd(priv, HOST_CMD_MGMT_FRAME_REG, + HOST_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false); + } + + switch (req->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + auth_alg = WLAN_AUTH_OPEN; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + auth_alg = WLAN_AUTH_SHARED_KEY; + break; + case NL80211_AUTHTYPE_FT: + auth_alg = WLAN_AUTH_FT; + break; + case NL80211_AUTHTYPE_NETWORK_EAP: + auth_alg = WLAN_AUTH_LEAP; + break; + case NL80211_AUTHTYPE_SAE: + auth_alg = WLAN_AUTH_SAE; + break; + default: + nxpwifi_dbg(adapter, ERROR, + "unsupported auth type=%d\n", req->auth_type); + return -EOPNOTSUPP; + } + + if (!priv->auth_flag) { + ret = nxpwifi_remain_on_chan_cfg(priv, HOST_ACT_GEN_SET, + req->bss->channel, + AUTH_TX_DEFAULT_WAIT_TIME); + + if (!ret) { + priv->roc_cfg.cookie = + nxpwifi_roc_cookie(adapter); + priv->roc_cfg.chan = *req->bss->channel; + } else { + return -EPERM; + } + } + + priv->sec_info.authentication_mode = auth_alg; + + nxpwifi_cancel_scan(adapter); + + pkt_len = (u16)req->ie_len + req->auth_data_len + + NXPWIFI_MGMT_HEADER_LEN + NXPWIFI_AUTH_BODY_LEN; + if (req->auth_data_len >= 4) + pkt_len -= 4; + + skb = dev_alloc_skb(NXPWIFI_MIN_DATA_HEADER_LEN + + NXPWIFI_MGMT_FRAME_HEADER_SIZE + + pkt_len + sizeof(pkt_len)); + if (!skb) { + nxpwifi_dbg(adapter, ERROR, + "allocate skb failed for management frame\n"); + return -ENOMEM; + } + + tx_info = NXPWIFI_SKB_TXCB(skb); + memset(tx_info, 0, sizeof(*tx_info)); + tx_info->bss_num = priv->bss_num; + tx_info->bss_type = priv->bss_type; + tx_info->pkt_len = pkt_len; + + skb_reserve(skb, NXPWIFI_MIN_DATA_HEADER_LEN + + NXPWIFI_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); + memcpy(skb_push(skb, sizeof(pkt_len)), &pkt_len, sizeof(pkt_len)); + memcpy(skb_push(skb, sizeof(tx_control)), + &tx_control, sizeof(tx_control)); + memcpy(skb_push(skb, sizeof(pkt_type)), &pkt_type, sizeof(pkt_type)); + + mgmt = (struct nxpwifi_ieee80211_mgmt *)skb_put(skb, pkt_len); + memset(mgmt, 0, pkt_len); + mgmt->frame_control = + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); + memcpy(mgmt->da, req->bss->bssid, ETH_ALEN); + memcpy(mgmt->sa, priv->curr_addr, ETH_ALEN); + memcpy(mgmt->bssid, req->bss->bssid, ETH_ALEN); + eth_broadcast_addr(mgmt->addr4); + + if (req->auth_data_len >= 4) { + if (req->auth_type == NL80211_AUTHTYPE_SAE) { + __le16 *pos = (__le16 *)req->auth_data; + + trans = le16_to_cpu(pos[0]); + status_code = le16_to_cpu(pos[1]); + } + memcpy((u8 *)(&mgmt->auth.variable), req->auth_data + 4, + req->auth_data_len - 4); + varptr = (u8 *)&mgmt->auth.variable + + (req->auth_data_len - 4); + } + + mgmt->auth.auth_alg = cpu_to_le16(auth_alg); + mgmt->auth.auth_transaction = cpu_to_le16(trans); + mgmt->auth.status_code = cpu_to_le16(status_code); + + if (req->ie && req->ie_len) { + if (!varptr) + varptr = (u8 *)&mgmt->auth.variable; + memcpy((u8 *)varptr, req->ie, req->ie_len); + } + + priv->auth_flag = HOST_MLME_AUTH_PENDING; + priv->auth_alg = auth_alg; + + skb->priority = WMM_HIGHEST_PRIORITY; + __net_timestamp(skb); + + nxpwifi_dbg(adapter, MSG, + "auth: send authentication to %pM\n", req->bss->bssid); + + nxpwifi_queue_tx_pkt(priv, skb); + + return 0; +} + +static int +nxpwifi_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_assoc_request *req) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_adapter *adapter = priv->adapter; + int ret; + struct cfg80211_ssid req_ssid; + const u8 *ssid_ie; + + if (GET_BSS_ROLE(priv) != NXPWIFI_BSS_ROLE_STA) { + nxpwifi_dbg(adapter, ERROR, + "%s: reject infra assoc request in non-STA role\n", + dev->name); + return -EINVAL; + } + + if (test_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags) || + test_bit(NXPWIFI_IS_CMD_TIMEDOUT, &adapter->work_flags)) { + nxpwifi_dbg(adapter, ERROR, + "%s: Ignore association.\t" + "Card removed or FW in bad state\n", + dev->name); + return -EPERM; + } + + if (priv->auth_alg == WLAN_AUTH_SAE) + priv->auth_flag = HOST_MLME_AUTH_DONE; + + if (priv->auth_flag && !(priv->auth_flag & HOST_MLME_AUTH_DONE)) + return -EBUSY; + + if (priv->roc_cfg.cookie) { + ret = nxpwifi_remain_on_chan_cfg(priv, HOST_ACT_GEN_REMOVE, + &priv->roc_cfg.chan, 0); + if (!ret) + memset(&priv->roc_cfg, 0, + sizeof(struct nxpwifi_roc_cfg)); + else + return ret; + } + + if (!nxpwifi_stop_bg_scan(priv)) + cfg80211_sched_scan_stopped_locked(priv->wdev.wiphy, 0); + + memset(&req_ssid, 0, sizeof(struct cfg80211_ssid)); + rcu_read_lock(); + ssid_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); + + if (!ssid_ie) + goto ssid_err; + + req_ssid.ssid_len = ssid_ie[1]; + if (req_ssid.ssid_len > IEEE80211_MAX_SSID_LEN) { + nxpwifi_dbg(adapter, ERROR, "invalid SSID - aborting\n"); + goto ssid_err; + } + + memcpy(req_ssid.ssid, ssid_ie + 2, req_ssid.ssid_len); + if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) { + nxpwifi_dbg(adapter, ERROR, "invalid SSID - aborting\n"); + goto ssid_err; + } + rcu_read_unlock(); + + /* As this is new association, clear locally stored + * keys and security related flags + */ + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + priv->wep_key_curr_index = 0; + priv->sec_info.encryption_mode = 0; + priv->sec_info.is_authtype_auto = 0; + ret = nxpwifi_set_encode(priv, NULL, NULL, 0, 0, NULL, 1); + + if (req->crypto.n_ciphers_pairwise) + priv->sec_info.encryption_mode = + req->crypto.ciphers_pairwise[0]; + + if (req->crypto.cipher_group) + priv->sec_info.encryption_mode = req->crypto.cipher_group; + + if (req->ie) + ret = nxpwifi_set_gen_ie(priv, req->ie, req->ie_len); + + memcpy(priv->cfg_bssid, req->bss->bssid, ETH_ALEN); + + nxpwifi_dbg(adapter, MSG, + "assoc: send association to %pM\n", req->bss->bssid); + + cfg80211_ref_bss(adapter->wiphy, req->bss); + + ret = nxpwifi_bss_start(priv, req->bss, &req_ssid); + + if (ret) { + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + eth_zero_addr(priv->cfg_bssid); + } else { + if (priv->assoc_rsp_size) { + priv->req_bss = req->bss; + adapter->assoc_resp_received = true; + nxpwifi_queue_work(adapter, + &adapter->host_mlme_work); + } + } + + cfg80211_put_bss(priv->adapter->wiphy, req->bss); + + return ret; + +ssid_err: + + rcu_read_unlock(); + return -EINVAL; +} + +static int +nxpwifi_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + int ret; + + if (!nxpwifi_stop_bg_scan(priv)) + cfg80211_sched_scan_stopped_locked(priv->wdev.wiphy, 0); + + ret = nxpwifi_deauthenticate(priv, NULL); + if (!ret) { + eth_zero_addr(priv->cfg_bssid); + priv->hs2_enabled = false; + } + + return ret; +} + +static int +nxpwifi_cfg80211_deauthenticate(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_deauth_request *req) +{ + return nxpwifi_cfg80211_disconnect(wiphy, dev, req->reason_code); +} + +static int +nxpwifi_cfg80211_disassociate(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_disassoc_request *req) +{ + return nxpwifi_cfg80211_disconnect(wiphy, dev, req->reason_code); +} + +static int +nxpwifi_cfg80211_probe_client(struct wiphy *wiphy, + struct net_device *dev, const u8 *peer, + u64 *cookie) +{ + /* hostapd looks for NL80211_CMD_PROBE_CLIENT support; otherwise, + * it requires monitor-mode support (which mwifiex doesn't support). + * Provide fake probe_client support to work around this. + */ + return -EOPNOTSUPP; +} + +/* station cfg80211 operations */ +static struct cfg80211_ops nxpwifi_cfg80211_ops = { + .add_virtual_intf = nxpwifi_add_virtual_intf, + .del_virtual_intf = nxpwifi_del_virtual_intf, + .change_virtual_intf = nxpwifi_cfg80211_change_virtual_intf, + .scan = nxpwifi_cfg80211_scan, + .auth = nxpwifi_cfg80211_authenticate, + .assoc = nxpwifi_cfg80211_associate, + .deauth = nxpwifi_cfg80211_deauthenticate, + .disassoc = nxpwifi_cfg80211_disassociate, + .probe_client = nxpwifi_cfg80211_probe_client, + .get_station = nxpwifi_cfg80211_get_station, + .dump_station = nxpwifi_cfg80211_dump_station, + .dump_survey = nxpwifi_cfg80211_dump_survey, + .set_wiphy_params = nxpwifi_cfg80211_set_wiphy_params, + .add_key = nxpwifi_cfg80211_add_key, + .del_key = nxpwifi_cfg80211_del_key, + .set_default_mgmt_key = nxpwifi_cfg80211_set_default_mgmt_key, + .mgmt_tx = nxpwifi_cfg80211_mgmt_tx, + .update_mgmt_frame_registrations = + nxpwifi_cfg80211_update_mgmt_frame_registrations, + .remain_on_channel = nxpwifi_cfg80211_remain_on_channel, + .cancel_remain_on_channel = nxpwifi_cfg80211_cancel_remain_on_channel, + .set_default_key = nxpwifi_cfg80211_set_default_key, + .set_power_mgmt = nxpwifi_cfg80211_set_power_mgmt, + .set_tx_power = nxpwifi_cfg80211_set_tx_power, + .get_tx_power = nxpwifi_cfg80211_get_tx_power, + .set_bitrate_mask = nxpwifi_cfg80211_set_bitrate_mask, + .start_ap = nxpwifi_cfg80211_start_ap, + .stop_ap = nxpwifi_cfg80211_stop_ap, + .change_beacon = nxpwifi_cfg80211_change_beacon, + .set_cqm_rssi_config = nxpwifi_cfg80211_set_cqm_rssi_config, + .set_antenna = nxpwifi_cfg80211_set_antenna, + .get_antenna = nxpwifi_cfg80211_get_antenna, + .del_station = nxpwifi_cfg80211_del_station, + .sched_scan_start = nxpwifi_cfg80211_sched_scan_start, + .sched_scan_stop = nxpwifi_cfg80211_sched_scan_stop, + .change_station = nxpwifi_cfg80211_change_station, +#ifdef CONFIG_PM + .suspend = nxpwifi_cfg80211_suspend, + .resume = nxpwifi_cfg80211_resume, + .set_wakeup = nxpwifi_cfg80211_set_wakeup, +#endif + .set_coalesce = nxpwifi_cfg80211_set_coalesce, + .add_station = nxpwifi_cfg80211_add_station, + CFG80211_TESTMODE_CMD(nxpwifi_tm_cmd) + .get_channel = nxpwifi_cfg80211_get_channel, + .start_radar_detection = nxpwifi_cfg80211_start_radar_detection, + .channel_switch = nxpwifi_cfg80211_channel_switch, +}; + +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support nxpwifi_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_NET_DETECT | WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE, + .n_patterns = NXPWIFI_MEF_MAX_FILTERS, + .pattern_min_len = 1, + .pattern_max_len = NXPWIFI_MAX_PATTERN_LEN, + .max_pkt_offset = NXPWIFI_MAX_OFFSET_LEN, + .max_nd_match_sets = NXPWIFI_MAX_ND_MATCH_SETS, +}; + +static const struct wiphy_wowlan_support nxpwifi_wowlan_support_no_gtk = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_NET_DETECT, + .n_patterns = NXPWIFI_MEF_MAX_FILTERS, + .pattern_min_len = 1, + .pattern_max_len = NXPWIFI_MAX_PATTERN_LEN, + .max_pkt_offset = NXPWIFI_MAX_OFFSET_LEN, + .max_nd_match_sets = NXPWIFI_MAX_ND_MATCH_SETS, +}; +#endif + +static const struct wiphy_coalesce_support nxpwifi_coalesce_support = { + .n_rules = NXPWIFI_COALESCE_MAX_RULES, + .max_delay = NXPWIFI_MAX_COALESCING_DELAY, + .n_patterns = NXPWIFI_COALESCE_MAX_FILTERS, + .pattern_min_len = 1, + .pattern_max_len = NXPWIFI_MAX_PATTERN_LEN, + .max_pkt_offset = NXPWIFI_MAX_OFFSET_LEN, +}; + +int nxpwifi_init_channel_scan_gap(struct nxpwifi_adapter *adapter) +{ + u32 n_channels_bg, n_channels_a = 0; + + n_channels_bg = nxpwifi_band_2ghz.n_channels; + + if (adapter->config_bands & BAND_A) + n_channels_a = nxpwifi_band_5ghz.n_channels; + + /* allocate twice the number total channels, since the driver issues an + * additional active scan request for hidden SSIDs on passive channels. + */ + adapter->num_in_chan_stats = 2 * (n_channels_bg + n_channels_a); + adapter->chan_stats = vmalloc(array_size(sizeof(*adapter->chan_stats), + adapter->num_in_chan_stats)); + + if (!adapter->chan_stats) + return -ENOMEM; + + return 0; +} + +/* This function registers the device with CFG802.11 subsystem. + * + * The function creates the wireless device/wiphy, populates it with + * default parameters and handler function pointers, and finally + * registers the device. + */ + +int nxpwifi_register_cfg80211(struct nxpwifi_adapter *adapter) +{ + int ret; + void *wdev_priv; + struct wiphy *wiphy; + struct nxpwifi_private *priv = adapter->priv[NXPWIFI_BSS_TYPE_STA]; + u8 *country_code; + u32 thr, retry; + + /* create a new wiphy for use with cfg80211 */ + wiphy = wiphy_new(&nxpwifi_cfg80211_ops, + sizeof(struct nxpwifi_adapter *)); + if (!wiphy) { + nxpwifi_dbg(adapter, ERROR, + "%s: creating new wiphy\n", __func__); + return -ENOMEM; + } + + wiphy->max_scan_ssids = NXPWIFI_MAX_SSID_LIST_LENGTH; + wiphy->max_scan_ie_len = NXPWIFI_MAX_VSIE_LEN; + + wiphy->mgmt_stypes = nxpwifi_mgmt_stypes; + wiphy->max_remain_on_channel_duration = 5000; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP); + + wiphy->bands[NL80211_BAND_2GHZ] = &nxpwifi_band_2ghz; + if (adapter->config_bands & BAND_A) + wiphy->bands[NL80211_BAND_5GHZ] = &nxpwifi_band_5ghz; + else + wiphy->bands[NL80211_BAND_5GHZ] = NULL; + + if (adapter->is_hw_11ac_capable) + wiphy->iface_combinations = &nxpwifi_iface_comb_ap_sta_vht; + else + wiphy->iface_combinations = &nxpwifi_iface_comb_ap_sta; + wiphy->n_iface_combinations = 1; + + wiphy->max_ap_assoc_sta = adapter->max_sta_conn; + + /* Initialize cipher suits */ + wiphy->cipher_suites = nxpwifi_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(nxpwifi_cipher_suites); + + if (adapter->regd) { + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS | + REGULATORY_COUNTRY_IE_IGNORE; + wiphy_apply_custom_regulatory(wiphy, adapter->regd); + } + + ether_addr_copy(wiphy->perm_addr, adapter->perm_addr); + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | + WIPHY_FLAG_AP_UAPSD | + WIPHY_FLAG_REPORTS_OBSS | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_HAS_CHANNEL_SWITCH | + WIPHY_FLAG_NETNS_OK | + WIPHY_FLAG_PS_ON_BY_DEFAULT; + wiphy->max_num_csa_counters = NXPWIFI_MAX_CSA_COUNTERS; + +#ifdef CONFIG_PM + if (ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info)) + wiphy->wowlan = &nxpwifi_wowlan_support; + else + wiphy->wowlan = &nxpwifi_wowlan_support_no_gtk; +#endif + + wiphy->coalesce = &nxpwifi_coalesce_support; + + wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; + + wiphy->max_sched_scan_reqs = 1; + wiphy->max_sched_scan_ssids = NXPWIFI_MAX_SSID_LIST_LENGTH; + wiphy->max_sched_scan_ie_len = NXPWIFI_MAX_VSIE_LEN; + wiphy->max_match_sets = NXPWIFI_MAX_SSID_LIST_LENGTH; + + wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; + wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; + + wiphy->features |= NL80211_FEATURE_SAE | + NL80211_FEATURE_INACTIVITY_TIMER | + NL80211_FEATURE_LOW_PRIORITY_SCAN | + NL80211_FEATURE_NEED_OBSS_SCAN; + + if (ISSUPP_RANDOM_MAC(adapter->fw_cap_info)) + wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_ND_RANDOM_MAC_ADDR; + + if (adapter->fw_api_ver == NXPWIFI_FW_V15) + wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; + + /* Reserve space for nxpwifi specific private data for BSS */ + wiphy->bss_priv_size = sizeof(struct nxpwifi_bss_priv); + + wiphy->reg_notifier = nxpwifi_reg_notifier; + + /* Set struct nxpwifi_adapter pointer in wiphy_priv */ + wdev_priv = wiphy_priv(wiphy); + *(unsigned long *)wdev_priv = (unsigned long)adapter; + + set_wiphy_dev(wiphy, priv->adapter->dev); + + ret = wiphy_register(wiphy); + if (ret < 0) { + nxpwifi_dbg(adapter, ERROR, + "%s: wiphy_register failed: %d\n", __func__, ret); + wiphy_free(wiphy); + return ret; + } + + if (!adapter->regd) { + if (adapter->region_code == 0x00) { + nxpwifi_dbg(adapter, WARN, + "Ignore world regulatory domain\n"); + } else { + wiphy->regulatory_flags |= + REGULATORY_DISABLE_BEACON_HINTS | + REGULATORY_COUNTRY_IE_IGNORE; + country_code = + nxpwifi_11d_code_2_region(adapter->region_code); + if (country_code && + regulatory_hint(wiphy, country_code)) + nxpwifi_dbg(priv->adapter, ERROR, + "regulatory_hint() failed\n"); + } + } + + nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB, + HOST_ACT_GEN_GET, FRAG_THRESH_I, &thr, true); + wiphy->frag_threshold = thr; + nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB, + HOST_ACT_GEN_GET, RTS_THRESH_I, &thr, true); + wiphy->rts_threshold = thr; + nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB, + HOST_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry, true); + wiphy->retry_short = (u8)retry; + nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB, + HOST_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry, true); + wiphy->retry_long = (u8)retry; + + adapter->wiphy = wiphy; + return ret; +} From patchwork Fri Aug 9 09:45:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818279 Received: from DUZPR83CU001.outbound.protection.outlook.com (mail-northeuropeazon11013064.outbound.protection.outlook.com [52.101.67.64]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 45020194C69; Fri, 9 Aug 2024 09:46:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.67.64 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196796; cv=fail; b=XZldeSxVIwTy0ETVvwt3RAEmCwlUn1HWZAXSgrA29WKBE6yx+BjP8osINYg/CrrsQeNx1Rk22/gre1zo4ASvMph7HRijl/q6BcCa1KUoshYJFP8Zob4gP+lTQuyKqY1hZK6avLWg/bkEi1sOd/2hLR8fkOIqPmO+oxNaO0mUefY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196796; c=relaxed/simple; bh=QWKbkaSaNbaVtbJQGMeEXDCm8ELfLEM6Au7R9BuXTdo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=DJi5yAjQIrUWAmMEgOVGqKzHy626iwNgNnB72UTEYTbi1+WwTO8owkAxXd1Z57YyTVDCdXW5TnNQFlA3JyfcbOtPM2M78L2RxGBjRb80NZNbh/+8jgI9ESj8iBJt2Ng/7PFzzm53dI/4hR+1Ufamihv4SxQo9Bockc3g8Wzl3HA= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=gvJrmTit; arc=fail smtp.client-ip=52.101.67.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="gvJrmTit" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=p0Zu7GewcLK0qn8KdcGQg1FTts0e4c4Mi2hr48E6ZrXntgkncgjYTRaRBzxKkPrIwrvmOL/y07Wqxu1PZXr7swCApRCwPsFBx0RZuTEYcJcWdoUDUY6OyWTicOKVg5e8HuUUTyn1L2oTB6ooYBfXjj7ai2Wj/P/+d0ToTg7DY5nYC0uOi8hMqNNVWH+1IZtrQzZp7qzBntfy+QFF4N7rLErho+1tXwiszMqkPmD6COMSGoVTYrduzQ/+6/8utt6q2PbfMA06ILNr1Ach/FFMOyI7JZdrmQOsO0lv++au2mJJ0zWaJvkn6mAMvwH4MprfoLYPIH7KAH8wLTxxtLOFjw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=XBHjJCVxDsSzN5UzZKlN8f1WBHZH5bXsLg2QpNX+dRo=; b=CEz2O4EAlOehXj2xdTzNiBTSiUWxnVtVLkMCNcllJZejfsBan2NZWpyAmTxIvSmp8gox8WddrRLZJHKkqwYsM2+BiF13Cb/Rux0h4Z8BIqbRh679PuvfzwJ+omA+BXeCI7Z/c0gn1uOe5H2doVuy4r3qtp4HC6MyzF5yRlc+vQBdE7sb8jCtlzqYFjdhP4TXmaVUHofvGgkxfrAsShmwqLCAI24xla8SIewekLc0tgiVJvnYzItRcEIpodBCr/yuz7eM5ZnWKZutCn58Vlhwv1tb92nFgVAkMDMkTYSaW/wPjdDVpJCa5kr9AMTV5BhN/6kgncDt7V3W9+GxWmk5pQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=XBHjJCVxDsSzN5UzZKlN8f1WBHZH5bXsLg2QpNX+dRo=; b=gvJrmTitx31z4YrF/UbFytPixVJFaak2Krg1L5c+s1rS9+pDxm0VGBnZfQheoUcROB7nSEz/X9TLu3qowoz8bVmqASPfGqPYB6eVoayx/M9dmvtAqY7otjedhoVH5Ic4DPd32lt90k7dAyRK4bz+Cre2QHVbnUQOBx0uxh+bHKI9uSm/MK7T43+yGxfKmhR3sNVY852/iHY36ljcm3PK2m+NS5MR0v277hAQYx7q/YGirihLjQ4s7IrkbcyqtXrbHxOAPAQgGbObrIaF7XNPbvfwmK5s4PTcvPtq6BkapZJGPHs4Fzuc2PQ8wLvuG2T3RaF5hXiP4HdSNXEIllpeEA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:28 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:28 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 11/43] wifi: nxpwifi: add cfg80211.h Date: Fri, 9 Aug 2024 17:45:01 +0800 Message-Id: <20240809094533.1660-12-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: dfc2d294-ed02-4b39-9448-08dcb85823d6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: XJcsIJO2tqCFBc1VFaE4Q/aT6C15VES6pZXyK9yXYdVD9su9UvqlBSnaOGmLtrhtwOpvX4nNf/2fpj4q9QCZFlThg8ZBhOgYHmQFOIPr/fOYjK9neuY8Mm7clWw7VKp/uyBmaUX0TFPLhsS1umc3jvrG5lAf/rfCq6XcVPhyZVna2BXErvDmiocXmqCWaeXRg8TGxZze/Tta79/A2Wx28qCzxdKHp29P97xLHfCm2UVI/YPjFb6t1mP4idxKKoYck2k2fuu5cKQeQUw9pbM4shm3y2Mgxz/VZb+2dng1LbbJWDubEQ4W1O5wP5n70PKq6/Qr7e2gSJ/0/h2MI98RRa17mrpyJqIlu7TuZ5U8dKVvQJ9Z8ms2mUTwbvzcSoxVWzBokxb9L3xHznZyXS9wLoutz1ewQi0aI6BYAvYvoQRvrqkXdYUbgx+6ERsaUgb03fqpwIXtRN/Jq2w+y6IAEJyMaRqMFAxoYz4Wd5gIOAM8ZBeUzEcV4Old/xzB+wJqUu56f6HJ0BmlPvCLz/Uv430K+eUqeV81ETfF5tGaHcjKtINMcOiREmfALF8gE3CYuY/p8Uuz1psWV1xNXNqN6t0sSv3SzCjMqEkO+NmY4PcdbT8OTIMMQfYczt+emsrG5ekzUSJqjTyF/yfFdjx2xbOI+I0PDDNIAKgnFHcXI0s6HDA9awLQ63ulJAKsutgGXNflMDUEQqi+kew6VyZVpJC4AfCAjtVhKbzI/U2U+jeWagRE3hzuaOk4FWZPojblG1VlZVdzZGFrbQlMcOeA1OF97rZHsmnA72eOC/s2JsyXbzfawXTrH3q7rgvpfuYysx5XfamT7mVqF/7OC5Imh6tY+eCT3OtAaLXDO2bQbw38V+e92Xl6LjxbWs/gg4sXS7rPv/QbDBtzcDVnokzG4iEtz2xEw0vvEyPBLifMueKxfCJEZLH/xBUWePBNJ6s5z451Kj9u65UiraGD5JwpbEvIFdU9neofIvRVG8JcBqo34BEHLLssFxFWiImGMFQJYU7w09YqMai3J313XYwjpIp3I2niLgg05yhHM2+qhnfAvM9eBGye0VpCpqsOpUXkNicHdh+HAfSFDAJXYs7uRrefysG17+1n5cDgHuoxgJv7q4iG1ETIryfexdnIWMtY6E3gIBn1YPkK6VeViB9LLzj0fz4rOtsKcGaG/E9sa1OboLGiPwxNww34fkwbJMEJ/hM+9I0xwMaXM+ygiSBXeeQOzCVQYO5nU8wgriIQl/kFo0ZvjIPz9UvgamQFf0La19ur/f/AGwpPD0FQPloS83Opt95ttm8m+/nQL4yKg/0XL1alQ4fT0hFjagDLwM5HYI846lfCjgyS64Sb7UcVEg== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: Clk2AgKDDJHpuYMiAeUJEiJ2REPBql8N7uMKWg3gpi15LcVu9ADyJIRTduwJWfeOmtoN7rHqk9S305VvAChLIPJSgp5BxiRze8mqwHIYh9DV//u3ZtL1jtuj79cSyQMYgJgEX1UwzDQlGX9cyn0tgRrb2V4Xrrj3/LW1C53V7AutrZ25PtQ4Zq0Ni/Y+GjsvzY2thabOSRF0gD8Z5ejeUC2vRE9hxtcXOeFRbtzwN47gB6Yhe6ML9o1hzp3BXketu24Rkb0wkLrHuONYnjzhcMaZSGtaDFbcebgwzsD4nf8SZu1+RSMIo7ypMHSRq5rRvbdjLtGIfzC9UJOvr5wcvQT0nXRp7bUvpfBRX5MGGVYQKiLUlo4t8kuhMjJGUeGpPSThHkF0ScwZO1mt6ygQ6OsB1sNd1TgiK9+CM6v3Aso/a4IaAFdxBFgyioo8u5wXizCFBTDrgmSqbk6WmrG2kYnlkiFxByiJ1bRa5/v01yBRB6Poa8immEdharFkKua/NnF9e2xbnxH7nkKAS3g/u0CPxPoeimNLyV5IAy6ObzFh2aJOKbM1hT9F248GaE4xgxeRZnhd16ug5P8CrJUugUPoBULpE60tpY4XRvngKX0adaq58Wsl4rqXRQmai5vjZv6QWkqOAYNV1epglrOJUUI0Ppi4BTEknxqMpK1RX+ENlarOy4t4qlW/ewss+D2Sg8iEShRtSYxpbVEPiqTOYRGi5y2jvA3nQBfHqyDHmGyYbeJwFM5PmXEyL5M7sC4murVOEIu9JJDHkRMaZo+VR7cp/MI+I2iQ44t2B1rAkMxcTUgNNLsy2slz/rqIucMrE6FgNM0daRyGneVZ60kthYwRBrdYXl2ihHwHQb3GEKBUDmjRRpOnmJoWfOJ39bQztzMQORoiCmspN4r7abxJXjJIrMxUO6iUtiC9Ur1KFciO/eNtMOdcdh/r0nDq6XNnaFe3sex5RImLaxDt4xGi0vSKYGtKXJebEm5DaUH5yvrCiF1Dpu+sZZ+uWqmsnvILYbA2okPpwf6HQicgJhlVSXMaTDFPO5H4X8gtOJVUipy6pC5sXVmDUxbNhAVBSe+T7wnw1heVEsNMUY5nV1coIn/PgKUnL80kHSTAXj9EbT0uiB9Z5Dh7NwjgtI+6HCA6qOPPA0JJFEeIlTa5Ev70g3fOkXn9O2C+zu2xhOulvvbmQKlBu0blhFqm8HjAuWJe7kc2qdKCr7qF3vIXQnJeTlgLjScWslklSy7lfvyRk31VJZCh3YkwXYlWIZLNNbaju6yM1cSvz7E0Ac7Di5+g9VXOM5enjoaTNZzqow2XgF1m0WMHdOG5IkI0UNEvvtnpIMgVzczMAcwXuK6BUcZs3IcpHZDCKD5/ki+n0GwaIJfTShyN5JA3M7IoAvSAm2eAQLGI1pSEVxFjXACDJ2B6HoMzUIb+Rkt+t7+cJAvUPFqX1ErInjOIRrbbLG38vgmO1/0KuY0QEX69dUTeCIUykkzw/Uedk1iKKjdRxRab8W21AUox/32F4miWVTC8LfoE8CAKPZGlWO2+7TqSk9Rhgp66LHe3cm7/yZnki3OfTjZ7u9uEr0KIKtYvnml0El94N6NyaJCjH2A9Q8NQgGFlk/2c9zjQ6GvfApoTyBHvj17TDEDm2ixQ7fGI2rltiuJH X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: dfc2d294-ed02-4b39-9448-08dcb85823d6 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:28.1575 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: cOi3Y8rvhfS7Sftrbqnck3M54iVtuuKb0aYipPr9Q4qq7LW9u0LhESZUu4lvEwsjCj6mDi4T/9UAQw8P5hIc6g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/cfg80211.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/cfg80211.h diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.h b/drivers/net/wireless/nxp/nxpwifi/cfg80211.h new file mode 100644 index 000000000000..086ec9ca4cc9 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: CFG80211 + * + * Copyright 2011-2024 NXP + */ + +#ifndef __NXPWIFI_CFG80211__ +#define __NXPWIFI_CFG80211__ + +#include "main.h" + +int nxpwifi_register_cfg80211(struct nxpwifi_adapter *adapter); + +int nxpwifi_cfg80211_change_beacon_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *data); + +#endif From patchwork Fri Aug 9 09:45:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818393 Received: from AM0PR83CU005.outbound.protection.outlook.com (mail-westeuropeazon11010009.outbound.protection.outlook.com [52.101.69.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4385B194C7A; Fri, 9 Aug 2024 09:46:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.69.9 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196801; cv=fail; b=RE9oPTeUA7wtzM45czdOSOVyc2IRmefpDgoEHEMVuoRi03bZ2cfvvhb++6/gpT8BPNDRsV95fMhtgV6alCQNPTjAcT72azn+g57vmAdFoh//FyqtSRlt8+Wr93u9dXZmbJo0uqOYY2H32e9+ChPv/WE9x5ufUD5Vr4Qdy0d0V14= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196801; c=relaxed/simple; bh=k+6zGxyVG1oHfEMaZJ1tZmZPn1aVqjrQTSlzPkuQNeM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=Ftt+p+ZtxISYKhTboYLBDbJTKxFitGrq5nI8WJIIaX44NjKi1i7R+C6dsi95hrnC0SxpjNPp2n+XIyyIn4FaVE3oNGXYk/sJsuoUeNqM4sfcxDIag5wsdN76jVSkIj8m5NkpemVeFFmJCjBGbp71wJLMQb8U1/SdTKxkKGdAXB0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=iyzyz+dZ; arc=fail smtp.client-ip=52.101.69.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="iyzyz+dZ" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=eublVJg7prreQ0DHPvggGDRUFkzR4U/9tvxkuucjuYCM+rv9qBIFyKutceNkOePDq3y0xSIEupB27M3aGCXMbP3iK52imrTeMBnoaNYwFSf13G4kSL+vgrrCUVIpTQZN9ArlYKlJVDRbceY3YXJLIHeYguNatT/IvbIekMmF8yJNQ0RPugLvO/PYDnJQ6kB3XxlFkI0LKHIkEB0ClGuxEymunX+CWtJWaJp3LSiFtAZEKT4BNtZufDObE20jrs3neOZxTzCxeymbQBsc3VX6e8Hcnlgqk4DI3wzbb7giSucYtNqu13Z5ERkx09h/Me/VelDu/67sCVD2WVRIy1bVMQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=WHAERgpawj6urAJBLMjMifC6Z4ESZURpTzU16XE03EY=; b=Uc7Ig7NqcsCQdtGxsVxZlqCWv+C2v5Dpo3+Gm2u/j/s7NYj4eNGjSfe2noY6z1t6UUoaPRXERk1mmomSL9iGi56mngCa6w38blTertD/qbctmhRh6vHqeJs8nxnND036X6VKflZ0pwb6PHFdjsXkcdjso8s5xse2isChUBQtLQt0pX4/lY08flqNBdOruSrJLbz+KQqejXe4IKtwhaiCPuBmD9lcOZikSN6SJYRcJcPXFcbbBQiQtRpbaThXmtN/XfhniguYMTZ/DPb8btmWEMQjArgfvqcTD8pmaQny2p3Crxh+Sj69rRHH980nD+wT3Digbx4LRuViGfAEKLbsTQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=WHAERgpawj6urAJBLMjMifC6Z4ESZURpTzU16XE03EY=; b=iyzyz+dZF2wMQj2E21fNfC8f5UBBYNpmfPg9l+TLxOm1j5Lif2Z9HFZcVpXSW3mTbybk4+XSbrXYApCr8Go3oOQ8aG4Q3S8H8+mwOf3pe9/PJbKkMrXRVE845FFDR2s78y57dRNnGOMPD3jhKmoneh+j9pvcSIsvSwGHzrncoNVlNpLpuTkUUE0/6ChHhLm8WYDfmdR4PRN3xXIYxyCZ6kpWcIZKLPP3N5ZdBdGgsrW0zCWcIL8FMaDINJKgps1UKhIQk8hpIP2Q199lx7j83v5BztfYD+ynR1Ku02oSErglByKgczULSZMu8x90z4rafgytUQLwlFlHlFP7WqPMSQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:31 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:31 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 12/43] wifi: nxpwifi: add cfg.h Date: Fri, 9 Aug 2024 17:45:02 +0800 Message-Id: <20240809094533.1660-13-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: 1cdf206a-d532-4063-9e58-08dcb85825cf X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: 8ZO6+0q4Lm1uIvU42kOdHNBN/7wOYmd93rwOdVG4Qm+mFvUexS64y3OB3Ghk8fQ+phm2Onyh+zGsw0WrFuTKQxXMQV75/vbKZ6g52fPDBTuodlpRhzwPm7iiH4u0RNbkxojKVShrrrVuC/4YauZfZtPbQES/F6Q5dVYJN3uFQanG9kwQ80EwkIWe7HcevegpgZZKcZSpIBUYrZbsr+/e4E053JMCnUKotDnLgxJ9acE9VT7P53AHn+OVNoSnnnTZHBLWRcEzgS1aTmk1TQ2C7y/0CVC52imV5lVkCXhb/6NilnPt9sxkMG15F/t8s26hDpSuHwgHwASUR2K6UYWNRxtkrlhrHWDNtMBoVqzjaAzYjSy2z1Wg0zKwVBuWEBIHAQqkqGaftd+N+ywJvJHmZKmUIKsoDhaQIbI6bgoA1bLE42d7kuRZxv4M6PPI7myUlXCwG9GamYbcfuK/uCD1Bpte55+hUcPMcFSaPQu3EjcLFgZIl9ro8BOS9MF1ozoqE8xena2dLQFVP1aQoXNzCPhhIxcccl3s2fk45XVwVVVeaz0fj2t9LwAWNabS6mkb2VC9jaQGc7WoA0k7Rg9k7dzF4QNn+aC6cXDo1ZKGiB2TYENUTIlTUjqVNc/Zf1Wmk579rAKfTThqUoKTFN81X9xEO1ovBPLeqtwVtonnRqtGCgJidw7QFBPwG3+yMFcalUF0b0ek03aANiCk6FipWJ5ZqDoPHa+jWh79CbFEFfeJLylrdwSXnstO9kG8kJgdhcU3jlIBYUnl0tt447fQQ/2s/UAHsVx9I+EzMElsoTApMTNdwnWyxrXtA/xeznKTUf7FfNb1yd/+x7Yl06/UoUQPibpERJrFgfjZKrpa6xFifX3650hgKXHPuV9QmBWHsyMP9MhOH5o+nV79KTDRSvRZ23wl9DnLgO3pitOwvP9jrj80xv01/oUZUHreHU966UuaA2tNAJ65fQl2onJHanBYDyWrvNLbblP8PQO+mW+wCO+4BJ0AygJJitZGLgBZ7+HPcaEEviKLFnRtfblUgiJgeeteM11rj+3z/iGGPN2nN+PEsD0dGZyCQ0N10e+7u+s10IdiiZEyavMIxRWk/l4iME2uBGtsFs/d07bcJd1HoidJartTZGr2zZbl9y/YK1ra/rMX5vvyWncsDeD9mxHBzjbNoWIx22WjUiMGPEpDL3Mx21++BOpJXwIyTKyTJ371PX1zaOACHYzw1lEtJpw9xOP+eRBvG56/fB2R33aDGSRiQIvXODIsOVIiZQbb6p13Jd2xbmB4lfcTXL2+suk+9SJFS8vxRiUwIVnmf/UTsb3eBG+7jPQJx/erHSN2TnzCFgqyZHWxCy6CC0e7Rw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 8ma8NFNfBcwNFKnpkqiJz2uz9sX3N6HuvJnwplnFR8dIZi3QZhlscJb1GKsdIBmozcz2GcxtHk5g6bTmTsTetY1MkOY3UJDjaNoD/YOqBztghqIP3jI2E9is95cWiqsRWwjP0MTciGkGGyrrTTQ+V0j1gcJyrCk6uqXSzWQog9+aUvxQlaTntimPM34lgNzbUWUKuTg9zBwWylO6na0gU2RrY9LpDSxwF5RzS9bf88kAQB0PNyAS/bEgTqHVYNX99mbZVkNOByPEa+l+ZoXYS9d50eFe4YPA1o0BIKpVlL8peoucUyL8BR2W5t0Ne/tXHUmo1GA5l9wtrCuX8bucFRHjFnshlAO72QygYLI5gzebyPNkQCsuoKPhzrxbq+913vFlmT2c5cCRbohPbaq+IFDmeYUPXOksDIgjUC5FYd0SjmkTYuo0hbw8Or+vsVeO6LYAvDg6S74+BsN9t9FLPb9Qn8kVyn7NvTxr2JpMntw+73cQdFAQg4SSg9t5SSRLzcUyXHryKrnrBFRlTMb1ttyT7u6xw8bo5xMSuKgrrleZykSIPhwCe07mml43kTesAQaG+xOaeyoCN2Db0MqaRYj1/1ngxPz82/RMpcg/XtrjZsC4hRvMJWZxqazq9aKyrj/MmPqCRsLaX+CrCn0MD0TLOcvbmIbZtU4H9XEwib2awlbrTn+JVXaWpHWkZA8UoDf5gsJS0hqp2PbG8EDIWByM2lHTll+Ar5NwVyb1k0lg6tEsJgSMDeqtvK9FYKBNQ8CcvPNVClEgvGf7Eoq19ABnNCMqyMb8vzn7CbUu4ymOGnTpv6cNkIx1y8uVmrWyrnieq7Pj8bFYfzAJn8+9K+zz5r9uN73Cpg5obn8Ygotp/bC9szDFz3sz9kvGfyqqfUZJmewb4xKX7xI4MO7lHUD07I2bMgefL129OB564KyO9D5ilbHeIQuL7yzNghSyXKC1NVfzFLXmeBDHxn7iKG/B0wZfSBqV9p8PqipPkFYiwdQoKPLh7mRAR/TLZN4QCmelRGkRTZTMTFlbO5MT78bSCoUElIJOQMRQoq/oIYvtSPS22uiIGJNDn3nwLlTLzk1Ojj/sztjRA2uOK9eCdm5pqIrFC0pWPNSz9Mkt/OcKiZHaX+mqLcucEJ/C99Fuf6TCyurLaWdJAuWOYrJ1Ttv1a3UfU3abcNz0/ri/5ono+05iJadkbV5itGv0HPlNuHoAfl1UJnl9EpR1amsUW7DTu3+glgCgoz4m/fqPCcNIVGvvwO5D47E4mB8j7d8PVJ9mH/+eg+7LX+ECUc7ok8tcLl6MwokFwV6NfOkekSFyObFgZOckK0W5SxMGXUryNLfjoD+YIXLdUMYA/dtPADO/gRids+vTObVe5uw2Fm032YcXgKKIUI2T6JTwBugBlQPS9U4piC4XbrRPHYf6j4nT04jOzKkVLe1Z9nDSMrcVMteko7/DpZuFyyaYJhF+6KI2R2GbYYTOADCzAhKOdzMS4879gF+WQlRBelMHSkdeN7vTZhipbsNkbmJZodu8y2OrSdpPDPyc0TLk+OHLdfHETNzGZn0+kQk/bPgojFPx9NeLfqvgp3yVq2Q8ylRxprceKaGOJRHS1Vx/HMF5TalTJj8QTSO1hf+ITqjS39FXGeuWBhd1yGQDZeVWN24p X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1cdf206a-d532-4063-9e58-08dcb85825cf X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:31.2098 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: uKQjyv0BZe1pgyE1wyURf5g9+R+CFquKWik/xJboKd00EnJx1rB+tEgcyxfggvvifIMCAGIfb50I6Gxi+FK1Yw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/cfg.h | 445 +++++++++++++++++++++++++ 1 file changed, 445 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/cfg.h diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg.h b/drivers/net/wireless/nxp/nxpwifi/cfg.h new file mode 100644 index 000000000000..b55dfb872b76 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/cfg.h @@ -0,0 +1,445 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: ioctl data structures & APIs + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_IOCTL_H_ +#define _NXPWIFI_IOCTL_H_ + +#include + +enum { + NXPWIFI_SCAN_TYPE_UNCHANGED = 0, + NXPWIFI_SCAN_TYPE_ACTIVE, + NXPWIFI_SCAN_TYPE_PASSIVE +}; + +#define NXPWIFI_PROMISC_MODE 1 +#define NXPWIFI_MULTICAST_MODE 2 +#define NXPWIFI_ALL_MULTI_MODE 4 +#define NXPWIFI_MAX_MULTICAST_LIST_SIZE 32 + +struct nxpwifi_multicast_list { + u32 mode; + u32 num_multicast_addr; + u8 mac_list[NXPWIFI_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; +}; + +struct nxpwifi_chan_freq { + u32 channel; + u32 freq; +}; + +struct nxpwifi_ssid_bssid { + struct cfg80211_ssid ssid; + u8 bssid[ETH_ALEN]; +}; + +enum { + BAND_B = 1, + BAND_G = 2, + BAND_A = 4, + BAND_GN = 8, + BAND_AN = 16, + BAND_AAC = 32, +}; + +#define NXPWIFI_WPA_PASSHPHRASE_LEN 64 +struct wpa_param { + u8 pairwise_cipher_wpa; + u8 pairwise_cipher_wpa2; + u8 group_cipher; + u32 length; + u8 passphrase[NXPWIFI_WPA_PASSHPHRASE_LEN]; +}; + +struct wep_key { + u8 key_index; + u8 is_default; + u16 length; + u8 key[WLAN_KEY_LEN_WEP104]; +}; + +#define KEY_MGMT_ON_HOST 0x03 +#define NXPWIFI_AUTH_MODE_AUTO 0xFF +#define BAND_CONFIG_BG 0x00 +#define BAND_CONFIG_A 0x01 +#define NXPWIFI_SEC_CHAN_BELOW 0x30 +#define NXPWIFI_SEC_CHAN_ABOVE 0x10 +#define NXPWIFI_SUPPORTED_RATES 14 +#define NXPWIFI_SUPPORTED_RATES_EXT 32 +#define NXPWIFI_PRIO_BK 2 +#define NXPWIFI_PRIO_VI 5 +#define NXPWIFI_SUPPORTED_CHANNELS 2 +#define NXPWIFI_OPERATING_CLASSES 16 + +struct nxpwifi_uap_bss_param { + u8 mac_addr[ETH_ALEN]; + u8 channel; + u8 band_cfg; + u16 rts_threshold; + u16 frag_threshold; + u8 retry_limit; + struct nxpwifi_802_11_ssid ssid; + u8 bcast_ssid_ctl; + u8 radio_ctl; + u8 dtim_period; + u16 beacon_period; + u16 auth_mode; + u16 protocol; + u16 key_mgmt; + u16 key_mgmt_operation; + struct wpa_param wpa_cfg; + struct wep_key wep_cfg[NUM_WEP_KEYS]; + struct ieee80211_ht_cap ht_cap; + struct ieee80211_vht_cap vht_cap; + u8 rates[NXPWIFI_SUPPORTED_RATES]; + u32 sta_ao_timer; + u32 ps_sta_ao_timer; + u8 qos_info; + u8 power_constraint; + struct nxpwifi_types_wmm_info wmm_info; +}; + +struct nxpwifi_ds_get_stats { + u32 mcast_tx_frame; + u32 failed; + u32 retry; + u32 multi_retry; + u32 frame_dup; + u32 rts_success; + u32 rts_failure; + u32 ack_failure; + u32 rx_frag; + u32 mcast_rx_frame; + u32 fcs_error; + u32 tx_frame; + u32 wep_icv_error[4]; + u32 bcn_rcv_cnt; + u32 bcn_miss_cnt; +}; + +#define NXPWIFI_MAX_VER_STR_LEN 128 + +struct nxpwifi_ver_ext { + u32 version_str_sel; + char version_str[NXPWIFI_MAX_VER_STR_LEN]; +}; + +struct nxpwifi_bss_info { + u32 bss_mode; + struct cfg80211_ssid ssid; + u32 bss_chan; + u8 country_code[3]; + u32 media_connected; + u32 max_power_level; + u32 min_power_level; + signed int bcn_nf_last; + u32 wep_status; + u32 is_hs_configured; + u32 is_deep_sleep; + u8 bssid[ETH_ALEN]; +}; + +struct nxpwifi_sta_info { + u8 peer_mac[ETH_ALEN]; + struct station_parameters *params; +}; + +#define MAX_NUM_TID 8 + +#define MAX_RX_WINSIZE 64 + +struct nxpwifi_ds_rx_reorder_tbl { + u16 tid; + u8 ta[ETH_ALEN]; + u32 start_win; + u32 win_size; + u32 buffer[MAX_RX_WINSIZE]; +}; + +struct nxpwifi_ds_tx_ba_stream_tbl { + u16 tid; + u8 ra[ETH_ALEN]; + u8 amsdu; +}; + +#define DBG_CMD_NUM 5 +#define NXPWIFI_DBG_SDIO_MP_NUM 10 + +struct nxpwifi_debug_info { + unsigned int debug_mask; + u32 int_counter; + u32 packets_out[MAX_NUM_TID]; + u32 tx_buf_size; + u32 curr_tx_buf_size; + u32 tx_tbl_num; + struct nxpwifi_ds_tx_ba_stream_tbl + tx_tbl[NXPWIFI_MAX_TX_BASTREAM_SUPPORTED]; + u32 rx_tbl_num; + struct nxpwifi_ds_rx_reorder_tbl rx_tbl + [NXPWIFI_MAX_RX_BASTREAM_SUPPORTED]; + u16 ps_mode; + u32 ps_state; + u8 is_deep_sleep; + u8 pm_wakeup_card_req; + u32 pm_wakeup_fw_try; + u8 is_hs_configured; + u8 hs_activated; + u32 num_cmd_host_to_card_failure; + u32 num_cmd_sleep_cfm_host_to_card_failure; + u32 num_tx_host_to_card_failure; + u32 num_event_deauth; + u32 num_event_disassoc; + u32 num_event_link_lost; + u32 num_cmd_deauth; + u32 num_cmd_assoc_success; + u32 num_cmd_assoc_failure; + u32 num_tx_timeout; + u8 is_cmd_timedout; + u16 timeout_cmd_id; + u16 timeout_cmd_act; + u16 last_cmd_id[DBG_CMD_NUM]; + u16 last_cmd_act[DBG_CMD_NUM]; + u16 last_cmd_index; + u16 last_cmd_resp_id[DBG_CMD_NUM]; + u16 last_cmd_resp_index; + u16 last_event[DBG_CMD_NUM]; + u16 last_event_index; + u8 data_sent; + u8 cmd_sent; + u8 cmd_resp_received; + u8 event_received; + u32 last_mp_wr_bitmap[NXPWIFI_DBG_SDIO_MP_NUM]; + u32 last_mp_wr_ports[NXPWIFI_DBG_SDIO_MP_NUM]; + u32 last_mp_wr_len[NXPWIFI_DBG_SDIO_MP_NUM]; + u32 last_mp_curr_wr_port[NXPWIFI_DBG_SDIO_MP_NUM]; + u8 last_sdio_mp_index; +}; + +#define NXPWIFI_KEY_INDEX_UNICAST 0x40000000 +#define PN_LEN 16 + +struct nxpwifi_ds_encrypt_key { + u32 key_disable; + u32 key_index; + u32 key_len; + u8 key_material[WLAN_MAX_KEY_LEN]; + u8 mac_addr[ETH_ALEN]; + u8 pn[PN_LEN]; /* packet number */ + u8 pn_len; + u8 is_igtk_key; + u8 is_current_wep_key; + u8 is_rx_seq_valid; + u8 is_igtk_def_key; +}; + +struct nxpwifi_power_cfg { + u32 is_power_auto; + u32 is_power_fixed; + u32 power_level; +}; + +struct nxpwifi_ds_hs_cfg { + u32 is_invoke_hostcmd; + /* Bit0: non-unicast data + * Bit1: unicast data + * Bit2: mac events + * Bit3: magic packet + */ + u32 conditions; + u32 gpio; + u32 gap; +}; + +struct nxpwifi_ds_wakeup_reason { + u16 hs_wakeup_reason; +}; + +#define DEEP_SLEEP_ON 1 +#define DEEP_SLEEP_OFF 0 +#define DEEP_SLEEP_IDLE_TIME 100 +#define PS_MODE_AUTO 1 + +struct nxpwifi_ds_auto_ds { + u16 auto_ds; + u16 idle_time; +}; + +struct nxpwifi_ds_pm_cfg { + union { + u32 ps_mode; + struct nxpwifi_ds_hs_cfg hs_cfg; + struct nxpwifi_ds_auto_ds auto_deep_sleep; + u32 sleep_period; + } param; +}; + +struct nxpwifi_11ac_vht_cfg { + u8 band_config; + u8 misc_config; + u32 cap_info; + u32 mcs_tx_set; + u32 mcs_rx_set; +}; + +struct nxpwifi_ds_11n_tx_cfg { + u16 tx_htcap; + u16 tx_htinfo; + u16 misc_config; /* Needed for 802.11AC cards only */ +}; + +struct nxpwifi_ds_11n_amsdu_aggr_ctrl { + u16 enable; + u16 curr_buf_size; +}; + +struct nxpwifi_ds_ant_cfg { + u32 tx_ant; + u32 rx_ant; +}; + +#define NXPWIFI_NUM_OF_CMD_BUFFER 50 +#define NXPWIFI_SIZE_OF_CMD_BUFFER 2048 + +enum { + NXPWIFI_IE_TYPE_GEN_IE = 0, + NXPWIFI_IE_TYPE_ARP_FILTER, +}; + +enum { + NXPWIFI_REG_MAC = 1, + NXPWIFI_REG_BBP, + NXPWIFI_REG_RF, + NXPWIFI_REG_PMIC, + NXPWIFI_REG_CAU, +}; + +struct nxpwifi_ds_reg_rw { + u32 type; + u32 offset; + u32 value; +}; + +#define MAX_EEPROM_DATA 256 + +struct nxpwifi_ds_read_eeprom { + u16 offset; + u16 byte_count; + u8 value[MAX_EEPROM_DATA]; +}; + +struct nxpwifi_ds_mem_rw { + u32 addr; + u32 value; +}; + +#define IEEE_MAX_IE_SIZE 256 + +#define NXPWIFI_IE_HDR_SIZE (sizeof(struct nxpwifi_ie) - IEEE_MAX_IE_SIZE) + +struct nxpwifi_ds_misc_gen_ie { + u32 type; + u32 len; + u8 ie_data[IEEE_MAX_IE_SIZE]; +}; + +struct nxpwifi_ds_misc_cmd { + u32 len; + u8 cmd[NXPWIFI_SIZE_OF_CMD_BUFFER]; +}; + +#define BITMASK_BCN_RSSI_LOW BIT(0) +#define BITMASK_BCN_RSSI_HIGH BIT(4) + +enum subsc_evt_rssi_state { + EVENT_HANDLED, + RSSI_LOW_RECVD, + RSSI_HIGH_RECVD +}; + +struct subsc_evt_cfg { + u8 abs_value; + u8 evt_freq; +}; + +struct nxpwifi_ds_misc_subsc_evt { + u16 action; + u16 events; + struct subsc_evt_cfg bcn_l_rssi_cfg; + struct subsc_evt_cfg bcn_h_rssi_cfg; +}; + +#define NXPWIFI_MEF_MAX_BYTESEQ 6 /* non-adjustable */ +#define NXPWIFI_MEF_MAX_FILTERS 10 + +struct nxpwifi_mef_filter { + u16 repeat; + u16 offset; + s8 byte_seq[NXPWIFI_MEF_MAX_BYTESEQ + 1]; + u8 filt_type; + u8 filt_action; +}; + +struct nxpwifi_mef_entry { + u8 mode; + u8 action; + struct nxpwifi_mef_filter filter[NXPWIFI_MEF_MAX_FILTERS]; +}; + +struct nxpwifi_ds_mef_cfg { + u32 criteria; + u16 num_entries; + struct nxpwifi_mef_entry *mef_entry; +}; + +#define NXPWIFI_MAX_VSIE_LEN (256) +#define NXPWIFI_MAX_VSIE_NUM (8) +#define NXPWIFI_VSIE_MASK_CLEAR 0x00 +#define NXPWIFI_VSIE_MASK_SCAN 0x01 +#define NXPWIFI_VSIE_MASK_ASSOC 0x02 +#define NXPWIFI_VSIE_MASK_BGSCAN 0x08 + +enum { + NXPWIFI_FUNC_INIT = 1, + NXPWIFI_FUNC_SHUTDOWN, +}; + +enum COALESCE_OPERATION { + RECV_FILTER_MATCH_TYPE_EQ = 0x80, + RECV_FILTER_MATCH_TYPE_NE, +}; + +enum COALESCE_PACKET_TYPE { + PACKET_TYPE_UNICAST = 1, + PACKET_TYPE_MULTICAST = 2, + PACKET_TYPE_BROADCAST = 3 +}; + +#define NXPWIFI_COALESCE_MAX_RULES 8 +#define NXPWIFI_COALESCE_MAX_BYTESEQ 4 /* non-adjustable */ +#define NXPWIFI_COALESCE_MAX_FILTERS 4 +#define NXPWIFI_MAX_COALESCING_DELAY 100 /* in msecs */ + +struct filt_field_param { + u8 operation; + u8 operand_len; + u16 offset; + u8 operand_byte_stream[NXPWIFI_COALESCE_MAX_BYTESEQ]; +}; + +struct nxpwifi_coalesce_rule { + u16 max_coalescing_delay; + u8 num_of_fields; + u8 pkt_type; + struct filt_field_param params[NXPWIFI_COALESCE_MAX_FILTERS]; +}; + +struct nxpwifi_ds_coalesce_cfg { + u16 num_of_rules; + struct nxpwifi_coalesce_rule rule[NXPWIFI_COALESCE_MAX_RULES]; +}; + +#endif /* !_NXPWIFI_IOCTL_H_ */ From patchwork Fri Aug 9 09:45:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818278 Received: from AM0PR83CU005.outbound.protection.outlook.com (mail-westeuropeazon11010009.outbound.protection.outlook.com [52.101.69.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B79531957E2; Fri, 9 Aug 2024 09:46:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.69.9 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196804; cv=fail; b=GO6Q+YWuLAwnZVLjbKAgbgXNebpUtueSA3dR+h5N8MU27ndc1pXnpDsrLVTLb4m47VN/ytH5fGDfCiiM4Mt0evgpZ9ugRbKvZ5zVLNtR0KR5Oov0hxUuQ7Ujpz56jhZOcN4QXs534ftZPfblgyKrpKQE8mIWUhm6mvSLjQ7hokA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196804; c=relaxed/simple; bh=00hCiK7/BwzQH7lN+WBpRr1iRn+cvYeOJz/CFU9NVnU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=nUQKS8EvTnbkKJbQd8XQdh58MDO7E7i9hf2SjA17dKJQ4F0JAOoydVz5hUwVz3UZJBLHfQSGxbt2c6iYEOXVg96rvLb0RvV+8aqw9I95XLq4DkhpDNBteaDdUp4xFeqBHxauUTE25CwGvkC8LPnUW2W6Ts0VaKmO/Oi5EGZC+cs= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=hFroGAFq; arc=fail smtp.client-ip=52.101.69.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="hFroGAFq" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=UWN6S+Ny5Cav10kbqqrEjbe0uabZu7HueraaPvl7x+UxpUja3z4oiGD1HQzNOfW3rOpK7cWx7jjEn+HJFUhItrAbb7T9iVPZg5n0QlQs39HHgrPEf9MtWz5wNAf1gsKSVFPNN/enAkqylziMZ5PNIbJeOcH1+Bq3JVk/QK6d1frEaALwucmsdQ3MK5TqvER788QHBeAfh7jEzlwAPf+uUTSRDw02aHiYBVIgzS8p+N+ucpMJ6RoiFi4F/Zc7tcga2p5BBWx591OnGnHgOR+2PhHeT0micSjFD9ymS5HBl2Bn34Z1OuiKaIClaSDGD+yGQD3qwMIEoxOsTaeM7IbqNA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=eoBZLoCW4gBLbF736lnajcCz9D8aqYRFhv/UaE1f27c=; b=lWmblhIp52SRI6p/tfFouZKlW2oO7HG+iykakcF2pQbOVkVDyVs0jY8GLLUcEHpWiGUZwZW6ycH5veNJmasQKR7SXo5OdDyP8XN9bLZF8NgJN6QxL+iqxC49y8CGyDqVTmzmIPgsNFJqH91/U6ew1L7+dS+Y54F/WKreSghjPUiCF1zaNQMuk5ui1jtmYD8zdyeJRt1kUh++z4cm05Ym+e0N2T8IWtz2RKRwFP5pydjPDThWnRvIjkNVUbMY+969iqiUlauuixOR+DIq0A/k13JCZxtjDHFA0JKGIWaUL80J4EsdtZZZX+iItQXeYNTlC4ii+ne70VbUow+eaMBZaw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=eoBZLoCW4gBLbF736lnajcCz9D8aqYRFhv/UaE1f27c=; b=hFroGAFqCox6JmPpkPZ0iiWye3jwHOW0YwSifvK60/HQIuOb3u1NL8FSq/2awpsFqxfh5CZN8n/5y8w7Re+Zkvv8yIpFtlSaERjuHmjDaNVyd5WgPXWkMAByaylOryb+LLaQOj5ZYnZGRn8wKE3gsfm20OB7f+ruwlaNMCbQfm73PYNpxbvG+wIQvIzVuo9QT+Qb7NVZLcoeKYWQ/AtMO7DDXhSO36XTxxzMM3oxuE8mFR+4P/0AQrHVQ11fvnOAeSsbC3f2cJ5MGmZ6pk64R1zrfYGVAVHYO17VXa0FCTTtWuJpsEv1wfX0yLcVY9poKAXDQI4ragoQjxFh34dMBQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by PAXPR04MB9229.eurprd04.prod.outlook.com (2603:10a6:102:2bd::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.26; Fri, 9 Aug 2024 09:46:34 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:34 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 13/43] wifi: nxpwifi: add cfp.c Date: Fri, 9 Aug 2024 17:45:03 +0800 Message-Id: <20240809094533.1660-14-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|PAXPR04MB9229:EE_ X-MS-Office365-Filtering-Correlation-Id: f2b5dde3-d03f-4329-baeb-08dcb858279f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|52116014; X-Microsoft-Antispam-Message-Info: Y9rTmQ5HFrh1/8G/A/sVhvYgI/LC38Qpur0fEfTP4nFBmP7tgzTKZh4ST0ScvSF8HK8x4m5g5XX/c4YnYrMHn18AWD5nfs8aMLac65PwTE7HZvUowIIfMFDSZ25DO9o5nEE/uiiSgJZ6wEbKaUlVDiW+lBL8wujU5kaUnrWGia3YBsgwuaqR5+wAo7eiQWUpbhXHYBul95C5wTnwibXVfKsDktyTFFRQX07JqUFFucp6f2nqiAYsX0O6L8n6juOBZ9CeY3aaCJtyiaqQ3TRB6cGHbRgG8Cs3xeiqwQKLUWINwl7TErCNvPcMoqQJ0YNeRrJ6et+Lt7nj47Dra83YNaSYiCt9bbE7fvURSEw38a2bJFF5wUZLBUVe9ViC+zIq5OAjwN6lh0iphXaBS/0PWO82SCeDFy2iUQd83auzTEkMveeKD8Ku1zEd4gXr+DwJmougJHo0cnhYbwDRRYs1xVEl9OWmQqw7b8Sp88Da1fqqIrV5ny+964EEcxBJHHyZj2FVMaa9vakrdYLk+61b2MkfxvwvQm7UtiqBMDFKwkiPw6in0n5oS6WCmrYY1fpIn7bC1j9iJH5HzLdwDMDn7XBs9pvIg+3FRAbRE2OqBB48YeYm1yJudQaGgDtlmeE/GyGPhkf5k1NxW7CDdruwlKkhyrVvM056MYnU6KcL70gZOD03iKUvTD+g0P1CMiLmR4Z4P6A7/tawY+yIQ7vSLC63qQfbjiovJ66WmffDvgdtnNDiZSkCCLFAFm4UMJKIKJqr8AgDVcEVcc66JDu1OAbDeQbP02wgpgSljGJSCdjGkGW7EtOuoSFVzbcuwsKQWl4/x8G9myCOOb6Vu/x1rDyQOG+N+JlrO4Ob7PSEjw29xFKcsrW2oqDtQ7bTh/ZOryFzmO0uBsN+36XZZs5KmCADnLp71cQIBf4/GwaFgJ9x3LOJnLPJqWL88gEBpw1UVtrNJ/IdqosiJ3+/LkbmRLFKhORFZ6N58lpLFUZd+ZXX5hbuGej7csSB5JGW7f/L3ZxDV1BEfPvudycJzO4wuUeMFjgZmcCGDpNTM7IS17eLNEb4/4qZ4n1zCN7J5bblGiwfPl5kl2NEIla8glA7yGqAP+N2gAsM3sEf1HGGCzULNeOHBM2XNEpc07UTgS2U0Amsr1Fvce2thTt9TApnZ+J7oZUfQKgkwb3MvqRGsXtjSK/DCn43y5m3jtX91H9tUIFkgWfUyKjZyzGS79tb2WW4alWIXST9Q9q6fZWbt3nBEwHHCO4J8deYt6k/bTIF4vPt/tmZgYDlHOmH0+mU4WQe4/cSwpyAUP4+492YL52rQlQPNy8xbo07ykG51gHLcHawqIaLcgf+UOUx2RJVkQ== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 2gxsdBAjUhU5Z30XW2Gy89QmtpaQuzmLy14+dLwrsIpP7QzprbtvxXUGVZ5NRtQ6sO7fDTtXtDMRGtqhNS6hwdc9t30s+agjdjgKurJzkpNE0TDE6K1HfRkrCT1yPJKL4YjxDFK5vzNgi7eGO8HiR0Pp56tDbL5BV63HQJjrDk6fy2lc4vhSZ+Px+7JWVGURLDLPKgHrzn6SILoI2T3Asm7ZhJRnEvPwLT0YmQkPYhojjqQgFk0FpEsjoN4m37D816oPggzh+nI169rPvaxbK/BvK3YaJ/DvJJp9V7nibHxHceBL8ixrd7bOh/uEoA2nlSaqwctspnPObhXopFsyGOPHsUtQI6PPxPvlv3uBHOrwZlCrWUOA36+gGT8pncFH+4FGo8O+XPh36lLOqHocVrf8D220jikr4ggVwK0ztys48AMiNIBCW5DmXywwlNQpjNG1VGfQS5Ahi1qWMRdp3GMDiFfyiY4hSqEGHTzRSpOh4u+PqlO196+4gdzfo1/vuj8WGsqQTWkx0HVHj5f+HlZMEvS6RZfub9CzPvz4SsFl7mLnN7I49cdQnRytMEiBYrbI0Ei57Ux6LKnyk7v4dzQmR+5f69h4Vho0XCTbcUReGuEtw2tpuRYJVYwUR1+1PSpVhfJCA5ceCqveb+HZDlxpoBJoYdakj4diZzcZPq6lP//WI74xWDjviC5wy7QKuHLp+qC8+u7hkG6SAc0xFcTlCeD+frWAFNi5u50RE+l/wKkAedetkLbASprYYxng1+IbagfLihu7FOoe7Q8wWSEcCb2fvH/phznPTY8exytn+gsKL+4d4ddtPtyyaMuMWWOtLnk8urtVdM5MedbGTq0QE76w8iF8i7vrDT7Yzo99FXeZSsnkqCyXm7DeoIePyH1am1RuUDxe8J/oD5Z1D08ikoZtrMj4WXpiHcGTY+6Oj7qCQQWbVJZdoUfWKaYrE7L++hPppSuz1xbNOKx0FqAZG6DAGVSV407HVR2wQcleemmNRmt4ebTlXE6Xu47/YR9Wv4V+kD1gINBuRrbgpwvGFie6ypKU+Anl4FVveEvW3r2sxYkiofLg053NAUO+0uaSZOhpR7T60zh+nSROiN23yxfcRaWgyoJhYnOJznLHRLK+lVZT4FWChIExNuQUqHdXsZBjJatxdOwS63yGPaq5ZXpm1FLNQdPxIKkIqfMK+b4pFcvV8h83VZEOn22BE0zzpS78WOdKcNiiMqCC/+wig//DFYYCs1ph5lHhKaIHQZMjJ4OfRNWrskG4Emfi8aYHtjwBet6Zd1BrT76Y5V6/AFkvCSwhnMY6pqiuVsA7z5hIUgKXiJFc2h5kbmcm0KZAWYdKnWZk2vsg0tEq7ln/1etYEwjGP9B2/h9uGCNy9jTt+5d2tSdxIISyCwe+qtIguZuSGEYzqY8+8y8i+KU59tYPMYNFT0ordVcx2Vj/drxQZ25N/slXoeoWaHWd9e9qYSwuZ9WLf8tDnCt2kAp5gpfprL3smb6z8s/CAzjhd2ZiPfnkWWCedrcFyNNwmgS4g2ehoo0dFZ1uhh1Z1YMoWh5/vwi6jzdIK8pm+X7tB5FFhiB44kvs7N1ChvC4TkWtgEP265Lkm3bFBeL8iceMv9jtje5kQ2FKWX95fwF991IZW1+gYPNgWQGUDJs3 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: f2b5dde3-d03f-4329-baeb-08dcb858279f X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:34.4546 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 6JdXg4B7bJO2rR72Z4HP9qP2o9L8J9aLIQs/m+XiiDEYHOvnOBV1NgpwdTwchewjfoecuspaCOK8liXHVDEHrg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR04MB9229 --- drivers/net/wireless/nxp/nxpwifi/cfp.c | 484 +++++++++++++++++++++++++ 1 file changed, 484 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/cfp.c diff --git a/drivers/net/wireless/nxp/nxpwifi/cfp.c b/drivers/net/wireless/nxp/nxpwifi/cfp.c new file mode 100644 index 000000000000..249aa31c2d4c --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/cfp.c @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: Channel, Frequency and Power + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cfg80211.h" + +/* 100mW */ +#define NXPWIFI_TX_PWR_DEFAULT 20 +/* 100mW */ +#define NXPWIFI_TX_PWR_US_DEFAULT 20 +/* 50mW */ +#define NXPWIFI_TX_PWR_JP_DEFAULT 16 +/* 100mW */ +#define NXPWIFI_TX_PWR_FR_100MW 20 +/* 10mW */ +#define NXPWIFI_TX_PWR_FR_10MW 10 +/* 100mW */ +#define NXPWIFI_TX_PWR_EMEA_DEFAULT 20 + +static u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; +static u16 nxpwifi_data_rates[NXPWIFI_SUPPORTED_RATES_EXT] = { 0x02, 0x04, + 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, + 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90, + 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, + 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51, + 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 }; + +static u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; + +static u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, + 0x30, 0x48, 0x60, 0x6c, 0 }; + +static u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, + 0x12, 0x16, 0x18, 0x24, 0x30, 0x48, + 0x60, 0x6c, 0 }; + +u16 region_code_index[NXPWIFI_MAX_REGION_CODE] = { 0x00, 0x10, 0x20, 0x30, + 0x31, 0x32, 0x40, 0x41, 0x50 }; + +static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; + +/* For every mcs_rate line, the first 8 bytes are for stream 1x1, + * and all 16 bytes are for stream 2x2. + */ +static const u16 mcs_rate[4][16] = { + /* LGI 40M */ + { 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e, + 0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c }, + + /* SGI 40M */ + { 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c, + 0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 }, + + /* LGI 20M */ + { 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82, + 0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 }, + + /* SGI 20M */ + { 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90, + 0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 } +}; + +/* AC rates */ +static const u16 ac_mcs_rate_nss1[8][10] = { + /* LG 160M */ + { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D, + 0x492, 0x57C, 0x618 }, + + /* SG 160M */ + { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492, + 0x514, 0x618, 0x6C6 }, + + /* LG 80M */ + { 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F, + 0x249, 0x2BE, 0x30C }, + + /* SG 80M */ + { 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249, + 0x28A, 0x30C, 0x363 }, + + /* LG 40M */ + { 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3, + 0x10E, 0x144, 0x168 }, + + /* SG 40M */ + { 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E, + 0x12C, 0x168, 0x190 }, + + /* LG 20M */ + { 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 }, + + /* SG 20M */ + { 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 }, +}; + +/* NSS2 note: the value in the table is 2 multiplier of the actual rate */ +static const u16 ac_mcs_rate_nss2[8][10] = { + /* LG 160M */ + { 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A, + 0x924, 0xAF8, 0xC30 }, + + /* SG 160M */ + { 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924, + 0xA28, 0xC30, 0xD8B }, + + /* LG 80M */ + { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D, + 0x492, 0x57C, 0x618 }, + + /* SG 80M */ + { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492, + 0x514, 0x618, 0x6C6 }, + + /* LG 40M */ + { 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6, + 0x21C, 0x288, 0x2D0 }, + + /* SG 40M */ + { 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C, + 0x258, 0x2D0, 0x320 }, + + /* LG 20M */ + { 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104, + 0x138, 0x00 }, + + /* SG 20M */ + { 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121, + 0x15B, 0x00 }, +}; + +struct region_code_mapping { + u8 code; + u8 region[IEEE80211_COUNTRY_STRING_LEN]; +}; + +static struct region_code_mapping region_code_mapping_t[] = { + { 0x10, "US " }, /* US FCC */ + { 0x20, "CA " }, /* IC Canada */ + { 0x30, "FR " }, /* France */ + { 0x31, "ES " }, /* Spain */ + { 0x32, "FR " }, /* France */ + { 0x40, "JP " }, /* Japan */ + { 0x41, "JP " }, /* Japan */ + { 0x50, "CN " }, /* China */ +}; + +/* This function converts integer code to region string */ +u8 *nxpwifi_11d_code_2_region(u8 code) +{ + u8 i; + + /* Look for code in mapping table */ + for (i = 0; i < ARRAY_SIZE(region_code_mapping_t); i++) + if (region_code_mapping_t[i].code == code) + return region_code_mapping_t[i].region; + + return NULL; +} + +/* This function maps an index in supported rates table into + * the corresponding data rate. + */ +u32 nxpwifi_index_to_acs_data_rate(struct nxpwifi_private *priv, + u8 index, u8 ht_info) +{ + u32 rate = 0; + u8 mcs_index = 0; + u8 bw = 0; + u8 gi = 0; + + if ((ht_info & 0x3) == NXPWIFI_RATE_FORMAT_VHT) { + mcs_index = min(index & 0xF, 9); + + /* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */ + bw = (ht_info & 0xC) >> 2; + + /* LGI: gi =0, SGI: gi = 1 */ + gi = (ht_info & 0x10) >> 4; + + if ((index >> 4) == 1) /* NSS = 2 */ + rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index]; + else /* NSS = 1 */ + rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index]; + } else if ((ht_info & 0x3) == NXPWIFI_RATE_FORMAT_HT) { + /* 20M: bw=0, 40M: bw=1 */ + bw = (ht_info & 0xC) >> 2; + + /* LGI: gi =0, SGI: gi = 1 */ + gi = (ht_info & 0x10) >> 4; + + if (index == NXPWIFI_RATE_BITMAP_MCS0) { + if (gi == 1) + rate = 0x0D; /* MCS 32 SGI rate */ + else + rate = 0x0C; /* MCS 32 LGI rate */ + } else if (index < 16) { + if (bw == 1 || bw == 0) + rate = mcs_rate[2 * (1 - bw) + gi][index]; + else + rate = nxpwifi_data_rates[0]; + } else { + rate = nxpwifi_data_rates[0]; + } + } else { + /* 11n non-HT rates */ + if (index >= NXPWIFI_SUPPORTED_RATES_EXT) + index = 0; + rate = nxpwifi_data_rates[index]; + } + + return rate; +} + +/* This function maps an index in supported rates table into + * the corresponding data rate. + */ +u32 nxpwifi_index_to_data_rate(struct nxpwifi_private *priv, + u8 index, u8 ht_info) +{ + u32 mcs_num_supp = + (priv->adapter->user_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8; + u32 rate; + + if (priv->adapter->is_hw_11ac_capable) + return nxpwifi_index_to_acs_data_rate(priv, index, ht_info); + + if (ht_info & BIT(0)) { + if (index == NXPWIFI_RATE_BITMAP_MCS0) { + if (ht_info & BIT(2)) + rate = 0x0D; /* MCS 32 SGI rate */ + else + rate = 0x0C; /* MCS 32 LGI rate */ + } else if (index < mcs_num_supp) { + if (ht_info & BIT(1)) { + if (ht_info & BIT(2)) + /* SGI, 40M */ + rate = mcs_rate[1][index]; + else + /* LGI, 40M */ + rate = mcs_rate[0][index]; + } else { + if (ht_info & BIT(2)) + /* SGI, 20M */ + rate = mcs_rate[3][index]; + else + /* LGI, 20M */ + rate = mcs_rate[2][index]; + } + } else { + rate = nxpwifi_data_rates[0]; + } + } else { + if (index >= NXPWIFI_SUPPORTED_RATES_EXT) + index = 0; + rate = nxpwifi_data_rates[index]; + } + return rate; +} + +/* This function returns the current active data rates. + * + * The result may vary depending upon connection status. + */ +u32 nxpwifi_get_active_data_rates(struct nxpwifi_private *priv, u8 *rates) +{ + if (!priv->media_connected) + return nxpwifi_get_supported_rates(priv, rates); + else + return nxpwifi_copy_rates(rates, 0, + priv->curr_bss_params.data_rates, + priv->curr_bss_params.num_of_rates); +} + +/* This function locates the Channel-Frequency-Power triplet based upon + * band and channel/frequency parameters. + */ +struct nxpwifi_chan_freq_power * +nxpwifi_get_cfp(struct nxpwifi_private *priv, u8 band, u16 channel, u32 freq) +{ + struct nxpwifi_chan_freq_power *cfp = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch = NULL; + int i; + + if (!channel && !freq) + return cfp; + + if (nxpwifi_band_to_radio_type(band) == HOST_SCAN_RADIO_TYPE_BG) + sband = priv->wdev.wiphy->bands[NL80211_BAND_2GHZ]; + else + sband = priv->wdev.wiphy->bands[NL80211_BAND_5GHZ]; + + if (!sband) { + nxpwifi_dbg(priv->adapter, ERROR, + "%s: cannot find cfp by band %d\n", + __func__, band); + return cfp; + } + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (freq) { + if (ch->center_freq == freq) + break; + } else { + /* find by valid channel*/ + if (ch->hw_value == channel || + channel == FIRST_VALID_CHANNEL) + break; + } + } + if (i == sband->n_channels) { + nxpwifi_dbg(priv->adapter, WARN, + "%s: cannot find cfp by band %d\t" + "& channel=%d freq=%d\n", + __func__, band, channel, freq); + } else { + if (!ch) + return cfp; + + priv->cfp.channel = ch->hw_value; + priv->cfp.freq = ch->center_freq; + priv->cfp.max_tx_power = ch->max_power; + cfp = &priv->cfp; + } + + return cfp; +} + +/* This function checks if the data rate is set to auto. + */ +u8 +nxpwifi_is_rate_auto(struct nxpwifi_private *priv) +{ + u32 i; + int rate_num = 0; + + for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++) + if (priv->bitmap_rates[i]) + rate_num++; + + if (rate_num > 1) + return true; + else + return false; +} + +/* This function gets the supported data rates from bitmask inside + * cfg80211_scan_request. + */ +u32 nxpwifi_get_rates_from_cfg80211(struct nxpwifi_private *priv, + u8 *rates, u8 radio_type) +{ + struct wiphy *wiphy = priv->adapter->wiphy; + struct cfg80211_scan_request *request = priv->scan_request; + u32 num_rates, rate_mask; + struct ieee80211_supported_band *sband; + int i; + + if (radio_type) { + sband = wiphy->bands[NL80211_BAND_5GHZ]; + if (WARN_ON_ONCE(!sband)) + return 0; + rate_mask = request->rates[NL80211_BAND_5GHZ]; + } else { + sband = wiphy->bands[NL80211_BAND_2GHZ]; + if (WARN_ON_ONCE(!sband)) + return 0; + rate_mask = request->rates[NL80211_BAND_2GHZ]; + } + + num_rates = 0; + for (i = 0; i < sband->n_bitrates; i++) { + if ((BIT(i) & rate_mask) == 0) + continue; /* skip rate */ + rates[num_rates++] = (u8)(sband->bitrates[i].bitrate / 5); + } + + return num_rates; +} + +/* This function gets the supported data rates. The function works in + * both Ad-Hoc and infra mode by printing the band and returning the + * data rates. + */ +u32 nxpwifi_get_supported_rates(struct nxpwifi_private *priv, u8 *rates) +{ + u32 k = 0; + struct nxpwifi_adapter *adapter = priv->adapter; + + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + switch (adapter->config_bands) { + case BAND_B: + nxpwifi_dbg(adapter, INFO, "info: infra band=%d\t" + "supported_rates_b\n", + adapter->config_bands); + k = nxpwifi_copy_rates(rates, k, supported_rates_b, + sizeof(supported_rates_b)); + break; + case BAND_G: + case BAND_G | BAND_GN: + nxpwifi_dbg(adapter, INFO, "info: infra band=%d\t" + "supported_rates_g\n", + adapter->config_bands); + k = nxpwifi_copy_rates(rates, k, supported_rates_g, + sizeof(supported_rates_g)); + break; + case BAND_B | BAND_G: + case BAND_A | BAND_B | BAND_G: + case BAND_A | BAND_B: + case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN: + case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC: + case BAND_B | BAND_G | BAND_GN: + nxpwifi_dbg(adapter, INFO, "info: infra band=%d\t" + "supported_rates_bg\n", + adapter->config_bands); + k = nxpwifi_copy_rates(rates, k, supported_rates_bg, + sizeof(supported_rates_bg)); + break; + case BAND_A: + case BAND_A | BAND_G: + nxpwifi_dbg(adapter, INFO, "info: infra band=%d\t" + "supported_rates_a\n", + adapter->config_bands); + k = nxpwifi_copy_rates(rates, k, supported_rates_a, + sizeof(supported_rates_a)); + break; + case BAND_AN: + case BAND_A | BAND_AN: + case BAND_A | BAND_AN | BAND_AAC: + case BAND_A | BAND_G | BAND_AN | BAND_GN: + case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC: + nxpwifi_dbg(adapter, INFO, "info: infra band=%d\t" + "supported_rates_a\n", + adapter->config_bands); + k = nxpwifi_copy_rates(rates, k, supported_rates_a, + sizeof(supported_rates_a)); + break; + case BAND_GN: + nxpwifi_dbg(adapter, INFO, "info: infra band=%d\t" + "supported_rates_n\n", + adapter->config_bands); + k = nxpwifi_copy_rates(rates, k, supported_rates_n, + sizeof(supported_rates_n)); + break; + } + } + + return k; +} + +u8 nxpwifi_adjust_data_rate(struct nxpwifi_private *priv, + u8 rx_rate, u8 rate_info) +{ + u8 rate_index = 0; + + /* HT40 */ + if ((rate_info & BIT(0)) && (rate_info & BIT(1))) + rate_index = NXPWIFI_RATE_INDEX_MCS0 + + NXPWIFI_BW20_MCS_NUM + rx_rate; + else if (rate_info & BIT(0)) /* HT20 */ + rate_index = NXPWIFI_RATE_INDEX_MCS0 + rx_rate; + else + rate_index = (rx_rate > NXPWIFI_RATE_INDEX_OFDM0) ? + rx_rate - 1 : rx_rate; + + if (rate_index >= NXPWIFI_MAX_AC_RX_RATES) + rate_index = NXPWIFI_MAX_AC_RX_RATES - 1; + + return rate_index; +} From patchwork Fri Aug 9 09:45:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818392 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C2DB11953AB; Fri, 9 Aug 2024 09:46:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196807; cv=fail; b=JxI1zv8FE2aqmvN5EoYhKVy/5O37O+53iRB/d0FKjNuXEroo9Hzd3WH3/SeNxjgfamnhY1uwOXPyoYaRX4a/RRQ6LDnYM9YdXmOn/GE+Vd8jvJXmHH2+PGPgYQNSvZFrIIeYx2OHQlCEocB1fzm3r149OF3kaJTKMnT55wRchA4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196807; c=relaxed/simple; bh=LXDdCRj9OEnPIIam9+U10SRlYIvuO8JO2dHajdTFSSQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=Svy8KB+DieljPIwf353ghr3TX0CX0Hi2cJV5hnPYzyAy07WFVscrFKcJ66ogIn/L//xmFevuYwLLrWjagsXuq+0o0wC07eN6X32mxHPVg1J3MG9lWPMWF0Jgt9dy4g7beHDn2G0xcrFF1MEKhN0/WArX+Mjl+JPi/uGKMkZtveI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=c4VyDLoW; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="c4VyDLoW" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ue4cb+4YBDNjILB2upWwfCJHhy8+wYRwWl4usiMWgyXqG0Xj63mPmq7qfizlaMPv8xlPEUm8uN4caxz9Fhpo+zacEyC6+vuWL5ehY5kzh/OMJ2Lf0w9qzT4BPrctKORXm+ImbAnGl9kOebkrMuKvtO8jyNE33En98Y7M1qu8hr4xv5Rp/IfeIU+Sqqap+On3rlMlk8fuAdiJpSguMiCKKZmGYAECXguEDNS4ZNzhnEd6+g8pgNkAcNtkXlmenKD/uaLY24sYOPeaZrK+URZbAIeRqpxJT/m59xpzz0JdYZUCAoc0QDTvVe+ofaK6tu7DQNDjDPn1Wn524qhEMCNfIQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=lGz3rcEW7ipnH4iSmWgfTBqyk9kLlySd+an4cp9rWxI=; b=g3VMRXoll87QrZQGcT4QwzlC0YHp9ckBBtDqqOqcaEbF0RxbS+Qv2Xi0tNVz7m6Hd0w4tSB68n+SXv4WTNkvcjhTcKPmqwVw3ECXlNwgVXn51VsFsRN9Afikb83tL17B162r+A9gvm9bw+UMzmj2teSGhJyrq4bJY3CEXfklPkqBg/vZOmc+wr/LoLmoI9bjT2gtPEQwaJladUeupD5G+mz7uOBRNWbEV5C9fwJa0UuEvqHsXNcbXgB8BuAC3tV6K5r1q/Vw5nShOZqp7MRV18p0OMpF7ZNG4Y5nBLCFXAiMWhoZYqe/zcKOHgqcSgU+he3QbZO/l/yOm+tFMnKIHA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=lGz3rcEW7ipnH4iSmWgfTBqyk9kLlySd+an4cp9rWxI=; b=c4VyDLoWRyHtgvmuCrXlquOLVmDqUT7syig76UpWd9iysVkZdilNXCi2ajSt+JcUdRVtMfAmNmIPT56nE8JmV0cp6YvSo02ba7CUcVYhk9b/ImdtAELg7vjTx1WRkXPiHF0PfJKKa8iI+fQj6HsInCv/FL8uQUgnXKUPUUrenEP1XXE8NChb95lq1npvR5/D9IqKKAoBX2yJs+ZtH+HcIw6dsJoa7sYx6OtS3j65F2WYfhpxuU8FZ8FC40VmYHjb4RofwNsy76eVgGsRb35AOkVDHCVUKOrU4ipiEgSZVMd2o7q2p2quYKsj6qentgqGaajWKjqqyXqB8itFa3CIHg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:46:38 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:37 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 14/43] wifi: nxpwifi: add cmdevt.c Date: Fri, 9 Aug 2024 17:45:04 +0800 Message-Id: <20240809094533.1660-15-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: bca3ad69-4960-4ca4-0343-08dcb8582992 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: iZfnl3SXX0WyR5wuSMfXJspodzLiaCNprOX/wEOMu4ZtMZdTvd4TpHo++ePi1+HwwssDSBR1OSuLE9O82TNPqP4b/fIWmtaJtrDEaqNXw9b16+srIszwAVdk7xCt83gmimeyhVqUNNGo1yBUbMgkVhgbU+dqpstbqGqHRHZgwt/tQc2u09DBIN6tTqPrNsaHN0EfddwNvUIzYds1DxIElKetpiIHOypdFYzGOl6QX4JKcwZXW38Ij/gbXrE+w83HlmZ2Z5FiyVeXSIK1DstZXNllE4nrJ8WjdFDbSs1WF7z9B3CIG/l85b6u2ETWuyIYif97tFXjuLikvtjZVp9ThbQO7BDs6ZjaFbokr90C1wXcKb8t7NcwKwUeaLstrFSbOhqA8PpYLjT5EScGkmj8fTEDYIa/jLVuAv5NH5MS6Nsak25y111JPPcR+cj5uo3KggoWyU/bxzG80tv76XQ4YdKbk8FNxgWetdESqKSjAXxqhC92QgdgKPS+y/ViWmFB99zLLetVsWKXKet9AIzx86zOjPIip2odqzhwvx+1I+CWTA8MZs5fYn2O16j4m2SlheSkB6BETKcct0RKbukWg9uHFoofjZkUDkcgnwqrHbmjwx2jcBxy482u1PKl9Vhg4x3HRjpTVOpq18l59mGJNhweF0Ts++QzB5OEGWJWLQhpt+rwL37XCIb016U8IgqcBhqTAF4yjtavUx44ipjdyYs/JLZhZ97mCt/rRNLRv+ilaFf1lFRxmTxMSQTv7MaJypXnptZkbVWzlBu7J2ps85cj5xI1z9ghXDeKY103KG0PZH9IlRX04UMMVOq2An0yg8DC0vzfgwvuQeuenxjAN9aEmIWbvQZTGVokk4K3ElttENM7Idh5GeRXBHwlbE5nEKRMGT+ffwtiuq1JTeT1lbeV0RG3ORLoQggbnwGUaH1BO8+iu3zTz+d6pmm8iD7tEtrejqi8Um8P/0e9rg6lwJpg2KPw6ZLCf6drUmDCuVo2lN+p0+UDfAwmzJFBl8WouRrSwXQaRiKH0gPYLI5XTEXlaCmpUaqhqEBqnbXX8ZztJuIhTkCjMVQwgoK4vs4ECypm7bldsWTVnOGkADNTWSMtuzWZeqx0BtnTPxFwyDeWXjpsj8/dMCvnD5evZMBAWlYo4yk1yOixblc1t3vzooNnk8KDvxvBa+YEFoyhKnYZIUurs4t4urkqIX3XibmDKfUaFPCgS/geQT7/35vaIgHg2LY2ck8QJ8KjE91EtELfiWG4Cj68zVpRxFQVEUAebMMsuLkjU7YURx1NjPTOh9bKKzPGo5n0f2K0RporaB6V9oF1mlisAoz8pkcpni2LrwjiJqB6PKwQXObz2AL+8A== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: FCIV5MhGCo9IrAnoXF075Th0YNkwPZA6bRdsF4IaYimUD6AMq5E3xWa483YN9d9P8DXFDNJDiizqwE9PNKbpRyY+TAtv6eQCaV6C6GqEYp7445bDTUqc33IQz9bOzI+EeOtKoYsbuj/1LctsOgKRSXZHQbA2hvPshr1V48jzvaP8TOjKtH/spWsIkoQLg1fucR2SXjI/Yxp9ZidzV6YOK6OO5N5hi0PeX2a9NmzG/g9yypO3++leKT0bq7Kg2ezbJsup8CCHgOb7AjIp8sUvmal4gARizLNIgzdiyT8i3v5W9pAye1r/rVZBMq+X1LzIOJJ7upWjXJv5KcnyaVix/7GLOWPdLgAOnG/SkzsxItYXEbKy5qyqtYlpKoftNMdlBZsRBkF2lpk3tmJFpWwq8nyk9qv0zyzMMFJWdrlRtFyfQxPL9uW8OcVsrZUrrOVkAibQMqV96yaX+cE3wSJnAdGK+3HRNqnItpB6yYjoqifSXoQo3a5kwprD9wXR7ebiCxtUa1uhNokCadRLTFBbFW2KWEoh8jCN/EsKnRWfDCpwiHt9cncqHJURqI3e++VqEt135IGDXVdOykvAjadOLh7jB0CE8KnBdsRd7kyZOlnRPY3LzpLo64OF4bBeqUZtp1qF6NME+BwVBaE+6l5o3kOgZJfta+bJ4h9QerOHBRomlb56TBiqDT5iZuMiGcETgf6d1riQ70u+dzi+Q0rsFtzMLzlwQBLmac/I74+27vQYtiBtSqsjBXDodfGw0mLjIevBEPf9rcrooloIIusAAs+gZ4Nv5kjrABJPqT+plstqwnHVP2xeNUHL/osc2wnCbY4+D1w38vHjcVr9l7nkSA3juUUKt7+JQR3DfdChC9x+8PsCG+pB1SylFHw4iru0wQyNNEFbKAoTEq/i5weJyIcJ3n0ESaofOPbkGiZXpPT14W1Npgu50j9C4B+COcj4qA/uAYB5oCuKFYAhgyRGvYDIzniDEFTrUlc/8zcx8gYawK1fAt8lMYbYzI7mH5HdsvjMiEooDvl18ueai2nXyNObfSV8xLja9ppElG0rSKYXg7nnRm8TMCxm81wBgYbGcAU5WrAxshcP/8g+ei4L4o+j+OMkzm1LgubOYAnp+7+hO6fNuCazIobB5rBAENJjjIsliuBmqFqqQpdUjlySCzKtOPD8ub2ORDg807pvgFlKV24jO5mS+LIZvw8B+xr2m7jqspQDsvcOvOPm+4SMhL7eNO+8mfj08i0+W9kR/BpBKmuzct8k+urNKLzB4lVxZbOm4HJhaCZ3z8WRQ15THiyY/qjWhrMpB9I4zlZ+aiXH45sFo44OBVNDziD8RSxu/drduPOACfJzevK7DtOXTKhmqg8b4XaNQNiWT7fgHeORZQvoNOjkl2DA1KRCmM4h4UeCderF+m1ubb5EtEx+Fwu51SwEZ55MBiUcNIPni6/utgC+D8r91GDOv8kvlCYW8i2uPuH4T7L646/4ta64eDrJ60UMweHf9VKgp6RXairXgn1A+vmuKRPA7rM5LrGl7vVcJOk0hE+2vr5W4+ZdSOXQhYTsoVeZsWPivfbrn7quFUrgRFJgut+zzVNbwsGCEr5OhfqEdOmPUp6m2d8d9GoBBVcokMgeXUtpqdA7w488fQCxgmPLsuH0SGKMnEXJ X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: bca3ad69-4960-4ca4-0343-08dcb8582992 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:37.7355 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: q1qMnrcN24QAmzN18ykDaPRWwV6CLk0XS3l8DSuIY81G8qSanqnG2XM9Lj9eRFL6Vi/fracsUHBsi0vAjzVo8g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/cmdevt.c | 1285 +++++++++++++++++++++ 1 file changed, 1285 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/cmdevt.c diff --git a/drivers/net/wireless/nxp/nxpwifi/cmdevt.c b/drivers/net/wireless/nxp/nxpwifi/cmdevt.c new file mode 100644 index 000000000000..8bd1cdb39e91 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/cmdevt.c @@ -0,0 +1,1285 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: commands and events + * + * Copyright 2011-2024 NXP + */ + +#include +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cmdevt.h" +#include "wmm.h" +#include "11n.h" + +static void nxpwifi_cancel_pending_ioctl(struct nxpwifi_adapter *adapter); + +/* This function initializes a command node. + * + * The actual allocation of the node is not done by this function. It only + * initiates a node by filling it with default parameters. Similarly, + * allocation of the different buffers used (IOCTL buffer, data buffer) are + * not done by this function either. + */ +static void +nxpwifi_init_cmd_node(struct nxpwifi_private *priv, + struct cmd_ctrl_node *cmd_node, + u32 cmd_no, void *data_buf, bool sync) +{ + cmd_node->priv = priv; + cmd_node->cmd_no = cmd_no; + + if (sync) { + cmd_node->wait_q_enabled = true; + cmd_node->cmd_wait_q_woken = false; + cmd_node->condition = &cmd_node->cmd_wait_q_woken; + } + cmd_node->data_buf = data_buf; + cmd_node->cmd_skb = cmd_node->skb; + cmd_node->cmd_resp = NULL; +} + +/* This function returns a command node from the free queue depending upon + * availability. + */ +static struct cmd_ctrl_node * +nxpwifi_get_cmd_node(struct nxpwifi_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node; + + spin_lock_bh(&adapter->cmd_free_q_lock); + if (list_empty(&adapter->cmd_free_q)) { + nxpwifi_dbg(adapter, ERROR, + "GET_CMD_NODE: cmd node not available\n"); + spin_unlock_bh(&adapter->cmd_free_q_lock); + return NULL; + } + cmd_node = list_first_entry(&adapter->cmd_free_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_bh(&adapter->cmd_free_q_lock); + + return cmd_node; +} + +/* This function cleans up a command node. + * + * The function resets the fields including the buffer pointers. + * This function does not try to free the buffers. They must be + * freed before calling this function. + * + * This function will however call the receive completion callback + * in case a response buffer is still available before resetting + * the pointer. + */ +static void +nxpwifi_clean_cmd_node(struct nxpwifi_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + cmd_node->cmd_no = 0; + cmd_node->cmd_flag = 0; + cmd_node->data_buf = NULL; + cmd_node->wait_q_enabled = false; + + if (cmd_node->cmd_skb) + skb_trim(cmd_node->cmd_skb, 0); + + if (cmd_node->resp_skb) { + adapter->if_ops.cmdrsp_complete(adapter, cmd_node->resp_skb); + cmd_node->resp_skb = NULL; + } +} + +/* This function returns a command to the command free queue. + * + * The function also calls the completion callback if required, before + * cleaning the command node and re-inserting it into the free queue. + */ +static void +nxpwifi_insert_cmd_to_free_q(struct nxpwifi_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + if (!cmd_node) + return; + + if (cmd_node->wait_q_enabled) + nxpwifi_complete_cmd(adapter, cmd_node); + /* Clean the node */ + nxpwifi_clean_cmd_node(adapter, cmd_node); + + /* Insert node into cmd_free_q */ + spin_lock_bh(&adapter->cmd_free_q_lock); + list_add_tail(&cmd_node->list, &adapter->cmd_free_q); + spin_unlock_bh(&adapter->cmd_free_q_lock); +} + +/* This function reuses a command node. */ +void nxpwifi_recycle_cmd_node(struct nxpwifi_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + struct host_cmd_ds_command *host_cmd = (void *)cmd_node->cmd_skb->data; + + nxpwifi_insert_cmd_to_free_q(adapter, cmd_node); + + atomic_dec(&adapter->cmd_pending); + nxpwifi_dbg(adapter, CMD, + "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n", + le16_to_cpu(host_cmd->command), + atomic_read(&adapter->cmd_pending)); +} + +/* This function sends a host command to the firmware. + * + * The function copies the host command into the driver command + * buffer, which will be transferred to the firmware later by the + * main thread. + */ +static int nxpwifi_cmd_host_cmd(struct nxpwifi_private *priv, + struct cmd_ctrl_node *cmd_node) +{ + struct host_cmd_ds_command *cmd; + struct nxpwifi_ds_misc_cmd *pcmd_ptr; + + cmd = (struct host_cmd_ds_command *)cmd_node->skb->data; + pcmd_ptr = (struct nxpwifi_ds_misc_cmd *)cmd_node->data_buf; + + /* Copy the HOST command to command buffer */ + memcpy(cmd, pcmd_ptr->cmd, pcmd_ptr->len); + nxpwifi_dbg(priv->adapter, CMD, + "cmd: host cmd size = %d\n", pcmd_ptr->len); + return 0; +} + +/* This function downloads a command to the firmware. + * + * The function performs sanity tests, sets the command sequence + * number and size, converts the header fields to CPU format before + * sending. Afterwards, it logs the command ID and action for debugging + * and sets up the command timeout timer. + */ +static int nxpwifi_dnld_cmd_to_fw(struct nxpwifi_private *priv, + struct cmd_ctrl_node *cmd_node) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + int ret; + struct host_cmd_ds_command *host_cmd; + u16 cmd_code; + u16 cmd_size; + + if (!adapter || !cmd_node) + return -EINVAL; + + host_cmd = (struct host_cmd_ds_command *)(cmd_node->cmd_skb->data); + + /* Sanity test */ + if (host_cmd->size == 0) { + nxpwifi_dbg(adapter, ERROR, + "DNLD_CMD: host_cmd is null\t" + "or cmd size is 0, not sending\n"); + if (cmd_node->wait_q_enabled) + adapter->cmd_wait_q.status = -1; + nxpwifi_recycle_cmd_node(adapter, cmd_node); + return -EINVAL; + } + + cmd_code = le16_to_cpu(host_cmd->command); + cmd_node->cmd_no = cmd_code; + cmd_size = le16_to_cpu(host_cmd->size); + + if (adapter->hw_status == NXPWIFI_HW_STATUS_RESET && + cmd_code != HOST_CMD_FUNC_SHUTDOWN && + cmd_code != HOST_CMD_FUNC_INIT) { + nxpwifi_dbg(adapter, ERROR, + "DNLD_CMD: FW in reset state, ignore cmd %#x\n", + cmd_code); + nxpwifi_recycle_cmd_node(adapter, cmd_node); + nxpwifi_queue_work(adapter, &adapter->main_work); + return -EPERM; + } + + /* Set command sequence number */ + adapter->seq_num++; + host_cmd->seq_num = cpu_to_le16(HOST_SET_SEQ_NO_BSS_INFO + (adapter->seq_num, + cmd_node->priv->bss_num, + cmd_node->priv->bss_type)); + + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->curr_cmd = cmd_node; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + + /* Adjust skb length */ + if (cmd_node->cmd_skb->len > cmd_size) + /* cmd_size is less than sizeof(struct host_cmd_ds_command). + * Trim off the unused portion. + */ + skb_trim(cmd_node->cmd_skb, cmd_size); + else if (cmd_node->cmd_skb->len < cmd_size) + /* cmd_size is larger than sizeof(struct host_cmd_ds_command) + * because we have appended custom IE TLV. Increase skb length + * accordingly. + */ + skb_put(cmd_node->cmd_skb, cmd_size - cmd_node->cmd_skb->len); + + nxpwifi_dbg(adapter, CMD, + "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n", + cmd_code, + get_unaligned_le16((u8 *)host_cmd + S_DS_GEN), + cmd_size, le16_to_cpu(host_cmd->seq_num)); + nxpwifi_dbg_dump(adapter, CMD_D, "cmd buffer:", host_cmd, cmd_size); + + skb_push(cmd_node->cmd_skb, adapter->intf_hdr_len); + ret = adapter->if_ops.host_to_card(adapter, NXPWIFI_TYPE_CMD, + cmd_node->cmd_skb, NULL); + skb_pull(cmd_node->cmd_skb, adapter->intf_hdr_len); + + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "DNLD_CMD: host to card failed\n"); + if (cmd_node->wait_q_enabled) + adapter->cmd_wait_q.status = -1; + nxpwifi_recycle_cmd_node(adapter, adapter->curr_cmd); + + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->curr_cmd = NULL; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + + adapter->dbg.num_cmd_host_to_card_failure++; + return ret; + } + + /* Save the last command id and action to debug log */ + adapter->dbg.last_cmd_index = + (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code; + adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] = + get_unaligned_le16((u8 *)host_cmd + S_DS_GEN); + + /* Setup the timer after transmit command, except that specific + * command might not have command response. + */ + if (cmd_code != HOST_CMD_FW_DUMP_EVENT) + mod_timer(&adapter->cmd_timer, + jiffies + msecs_to_jiffies(NXPWIFI_TIMER_10S)); + + /* Clear BSS_NO_BITS from HOST */ + cmd_code &= HOST_CMD_ID_MASK; + + return 0; +} + +/* This function downloads a sleep confirm command to the firmware. + * + * The function performs sanity tests, sets the command sequence + * number and size, converts the header fields to CPU format before + * sending. + * + * No responses are needed for sleep confirm command. + */ +static int nxpwifi_dnld_sleep_confirm_cmd(struct nxpwifi_adapter *adapter) +{ + int ret; + struct nxpwifi_private *priv; + struct nxpwifi_opt_sleep_confirm *sleep_cfm_buf = + (struct nxpwifi_opt_sleep_confirm *) + adapter->sleep_cfm->data; + + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + + adapter->seq_num++; + sleep_cfm_buf->seq_num = + cpu_to_le16(HOST_SET_SEQ_NO_BSS_INFO + (adapter->seq_num, priv->bss_num, + priv->bss_type)); + + nxpwifi_dbg(adapter, CMD, + "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n", + le16_to_cpu(sleep_cfm_buf->command), + le16_to_cpu(sleep_cfm_buf->action), + le16_to_cpu(sleep_cfm_buf->size), + le16_to_cpu(sleep_cfm_buf->seq_num)); + nxpwifi_dbg_dump(adapter, CMD_D, "SLEEP_CFM buffer: ", sleep_cfm_buf, + le16_to_cpu(sleep_cfm_buf->size)); + + skb_push(adapter->sleep_cfm, adapter->intf_hdr_len); + ret = adapter->if_ops.host_to_card(adapter, NXPWIFI_TYPE_CMD, + adapter->sleep_cfm, NULL); + skb_pull(adapter->sleep_cfm, adapter->intf_hdr_len); + + if (ret) { + nxpwifi_dbg(adapter, ERROR, "SLEEP_CFM: failed\n"); + adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++; + return ret; + } + + if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl)) + /* Response is not needed for sleep confirm command */ + adapter->ps_state = PS_STATE_SLEEP; + else + adapter->ps_state = PS_STATE_SLEEP_CFM; + + if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl) && + (test_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags) && + !adapter->sleep_period.period)) { + adapter->pm_wakeup_card_req = true; + nxpwifi_hs_activated_event(nxpwifi_get_priv + (adapter, NXPWIFI_BSS_ROLE_ANY), true); + } + + return ret; +} + +/* This function allocates the command buffers and links them to + * the command free queue. + * + * The driver uses a pre allocated number of command buffers, which + * are created at driver initializations and freed at driver cleanup. + * Every command needs to obtain a command buffer from this pool before + * it can be issued. The command free queue lists the command buffers + * currently free to use, while the command pending queue lists the + * command buffers already in use and awaiting handling. Command buffers + * are returned to the free queue after use. + */ +int nxpwifi_alloc_cmd_buffer(struct nxpwifi_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_array; + u32 i; + + /* Allocate and initialize struct cmd_ctrl_node */ + cmd_array = kcalloc(NXPWIFI_NUM_OF_CMD_BUFFER, + sizeof(struct cmd_ctrl_node), GFP_KERNEL); + if (!cmd_array) + return -ENOMEM; + + adapter->cmd_pool = cmd_array; + + /* Allocate and initialize command buffers */ + for (i = 0; i < NXPWIFI_NUM_OF_CMD_BUFFER; i++) { + cmd_array[i].skb = dev_alloc_skb(NXPWIFI_SIZE_OF_CMD_BUFFER); + if (!cmd_array[i].skb) + return -ENOMEM; + } + + for (i = 0; i < NXPWIFI_NUM_OF_CMD_BUFFER; i++) + nxpwifi_insert_cmd_to_free_q(adapter, &cmd_array[i]); + + return 0; +} + +/* This function frees the command buffers. + * + * The function calls the completion callback for all the command + * buffers that still have response buffers associated with them. + */ +void nxpwifi_free_cmd_buffer(struct nxpwifi_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_array; + u32 i; + + /* Need to check if cmd pool is allocated or not */ + if (!adapter->cmd_pool) { + nxpwifi_dbg(adapter, FATAL, + "info: FREE_CMD_BUF: cmd_pool is null\n"); + return; + } + + cmd_array = adapter->cmd_pool; + + /* Release shared memory buffers */ + for (i = 0; i < NXPWIFI_NUM_OF_CMD_BUFFER; i++) { + if (cmd_array[i].skb) { + nxpwifi_dbg(adapter, CMD, + "cmd: free cmd buffer %d\n", i); + dev_kfree_skb_any(cmd_array[i].skb); + } + if (!cmd_array[i].resp_skb) + continue; + + dev_kfree_skb_any(cmd_array[i].resp_skb); + } + /* Release struct cmd_ctrl_node */ + if (adapter->cmd_pool) { + nxpwifi_dbg(adapter, CMD, + "cmd: free cmd pool\n"); + kfree(adapter->cmd_pool); + adapter->cmd_pool = NULL; + } +} + +/* This function handles events generated by firmware. + * + * Event body of events received from firmware are not used (though they are + * saved), only the event ID is used. Some events are re-invoked by + * the driver, with a new event body. + * + * After processing, the function calls the completion callback + * for cleanup. + */ +int nxpwifi_process_event(struct nxpwifi_adapter *adapter) +{ + int ret, i; + struct nxpwifi_private *priv = + nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + struct sk_buff *skb = adapter->event_skb; + u32 eventcause; + struct nxpwifi_rxinfo *rx_info; + + if ((adapter->event_cause & EVENT_ID_MASK) == EVENT_RADAR_DETECTED) { + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv && nxpwifi_is_11h_active(priv)) { + adapter->event_cause |= + ((priv->bss_num & 0xff) << 16) | + ((priv->bss_type & 0xff) << 24); + break; + } + } + } + + eventcause = adapter->event_cause; + + /* Save the last event to debug log */ + adapter->dbg.last_event_index = + (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_event[adapter->dbg.last_event_index] = + (u16)eventcause; + + /* Get BSS number and corresponding priv */ + priv = nxpwifi_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause), + EVENT_GET_BSS_TYPE(eventcause)); + if (!priv) + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + + /* Clear BSS_NO_BITS from event */ + eventcause &= EVENT_ID_MASK; + adapter->event_cause = eventcause; + + if (skb) { + rx_info = NXPWIFI_SKB_RXCB(skb); + memset(rx_info, 0, sizeof(*rx_info)); + rx_info->bss_num = priv->bss_num; + rx_info->bss_type = priv->bss_type; + nxpwifi_dbg_dump(adapter, EVT_D, "Event Buf:", + skb->data, skb->len); + } + + nxpwifi_dbg(adapter, EVENT, "EVENT: cause: %#x\n", eventcause); + + if (priv->bss_role == NXPWIFI_BSS_ROLE_UAP) + ret = nxpwifi_process_uap_event(priv); + else + ret = nxpwifi_process_sta_event(priv); + + adapter->event_cause = 0; + adapter->event_skb = NULL; + adapter->if_ops.event_complete(adapter, skb); + + return ret; +} + +/* This function prepares a command and send it to the firmware. + * + * Preparation includes - + * - Sanity tests to make sure the card is still present or the FW + * is not reset + * - Getting a new command node from the command free queue + * - Initializing the command node for default parameters + * - Fill up the non-default parameters and buffer pointers + * - Add the command to pending queue + */ +int nxpwifi_send_cmd(struct nxpwifi_private *priv, u16 cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync) +{ + int ret; + struct nxpwifi_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node; + + if (!adapter) { + pr_err("PREP_CMD: adapter is NULL\n"); + return -EINVAL; + } + + if (test_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags)) { + nxpwifi_dbg(adapter, ERROR, + "PREP_CMD: device in suspended state\n"); + return -EPERM; + } + + if (test_bit(NXPWIFI_IS_HS_ENABLING, &adapter->work_flags) && + cmd_no != HOST_CMD_802_11_HS_CFG_ENH) { + nxpwifi_dbg(adapter, ERROR, + "PREP_CMD: host entering sleep state\n"); + return -EPERM; + } + + if (test_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags)) { + nxpwifi_dbg(adapter, ERROR, + "PREP_CMD: card is removed\n"); + return -EPERM; + } + + if (test_bit(NXPWIFI_IS_CMD_TIMEDOUT, &adapter->work_flags)) { + nxpwifi_dbg(adapter, ERROR, + "PREP_CMD: FW is in bad state\n"); + return -EPERM; + } + + if (adapter->hw_status == NXPWIFI_HW_STATUS_RESET) { + if (cmd_no != HOST_CMD_FUNC_INIT) { + nxpwifi_dbg(adapter, ERROR, + "PREP_CMD: FW in reset state\n"); + return -EPERM; + } + } + + if (priv->adapter->hs_activated_manually && + cmd_no != HOST_CMD_802_11_HS_CFG_ENH) { + nxpwifi_cancel_hs(priv, NXPWIFI_ASYNC_CMD); + priv->adapter->hs_activated_manually = false; + } + + /* Get a new command node */ + cmd_node = nxpwifi_get_cmd_node(adapter); + + if (!cmd_node) { + nxpwifi_dbg(adapter, ERROR, + "PREP_CMD: no free cmd node\n"); + return -ENOMEM; + } + + /* Initialize the command node */ + nxpwifi_init_cmd_node(priv, cmd_node, cmd_no, data_buf, sync); + + if (!cmd_node->cmd_skb) { + nxpwifi_dbg(adapter, ERROR, + "PREP_CMD: no free cmd buf\n"); + return -ENOMEM; + } + + skb_put_zero(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)); + + /* Prepare command */ + if (cmd_no) { + switch (cmd_no) { + case HOST_CMD_UAP_SYS_CONFIG: + case HOST_CMD_UAP_BSS_START: + case HOST_CMD_UAP_BSS_STOP: + case HOST_CMD_UAP_STA_DEAUTH: + case HOST_CMD_APCMD_SYS_RESET: + case HOST_CMD_APCMD_STA_LIST: + case HOST_CMD_CHAN_REPORT_REQUEST: + case HOST_CMD_ADD_NEW_STATION: + ret = nxpwifi_uap_prepare_cmd(priv, cmd_node, + cmd_action, cmd_oid); + break; + default: + ret = nxpwifi_sta_prepare_cmd(priv, cmd_node, + cmd_action, cmd_oid); + break; + } + } else { + ret = nxpwifi_cmd_host_cmd(priv, cmd_node); + cmd_node->cmd_flag |= CMD_F_HOSTCMD; + } + + /* Return error, since the command preparation failed */ + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "PREP_CMD: cmd %#x preparation failed\n", + cmd_no); + nxpwifi_insert_cmd_to_free_q(adapter, cmd_node); + return ret; + } + + /* Send command */ + if (cmd_no == HOST_CMD_802_11_SCAN || + cmd_no == HOST_CMD_802_11_SCAN_EXT) { + nxpwifi_queue_scan_cmd(priv, cmd_node); + } else { + nxpwifi_insert_cmd_to_pending_q(adapter, cmd_node); + nxpwifi_queue_work(adapter, &adapter->main_work); + if (cmd_node->wait_q_enabled) + ret = nxpwifi_wait_queue_complete(adapter, cmd_node); + } + + return ret; +} + +/* This function queues a command to the command pending queue. + * + * This in effect adds the command to the command list to be executed. + * Exit PS command is handled specially, by placing it always to the + * front of the command queue. + */ +void +nxpwifi_insert_cmd_to_pending_q(struct nxpwifi_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + struct host_cmd_ds_command *host_cmd = NULL; + u16 command; + bool add_tail = true; + + host_cmd = (struct host_cmd_ds_command *)(cmd_node->cmd_skb->data); + if (!host_cmd) { + nxpwifi_dbg(adapter, ERROR, "QUEUE_CMD: host_cmd is NULL\n"); + return; + } + + command = le16_to_cpu(host_cmd->command); + + /* Exit_PS command needs to be queued in the header always. */ + if (command == HOST_CMD_802_11_PS_MODE_ENH) { + struct host_cmd_ds_802_11_ps_mode_enh *pm = + &host_cmd->params.psmode_enh; + if ((le16_to_cpu(pm->action) == DIS_PS) || + (le16_to_cpu(pm->action) == DIS_AUTO_PS)) { + if (adapter->ps_state != PS_STATE_AWAKE) + add_tail = false; + } + } + + /* Same with exit host sleep cmd, luckily that can't happen at the same time as EXIT_PS */ + if (command == HOST_CMD_802_11_HS_CFG_ENH) { + struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = + &host_cmd->params.opt_hs_cfg; + + if (le16_to_cpu(hs_cfg->action) == HS_ACTIVATE) + add_tail = false; + } + + spin_lock_bh(&adapter->cmd_pending_q_lock); + if (add_tail) + list_add_tail(&cmd_node->list, &adapter->cmd_pending_q); + else + list_add(&cmd_node->list, &adapter->cmd_pending_q); + spin_unlock_bh(&adapter->cmd_pending_q_lock); + + atomic_inc(&adapter->cmd_pending); + nxpwifi_dbg(adapter, CMD, + "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n", + command, atomic_read(&adapter->cmd_pending)); +} + +/* This function executes the next command in command pending queue. + * + * This function will fail if a command is already in processing stage, + * otherwise it will dequeue the first command from the command pending + * queue and send to the firmware. + * + * If the device is currently in host sleep mode, any commands, except the + * host sleep configuration command will de-activate the host sleep. For PS + * mode, the function will put the firmware back to sleep if applicable. + */ +int nxpwifi_exec_next_cmd(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + struct cmd_ctrl_node *cmd_node; + int ret = 0; + struct host_cmd_ds_command *host_cmd; + + /* Check if already in processing */ + if (adapter->curr_cmd) { + nxpwifi_dbg(adapter, FATAL, + "EXEC_NEXT_CMD: cmd in processing\n"); + return -EBUSY; + } + + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + /* Check if any command is pending */ + spin_lock_bh(&adapter->cmd_pending_q_lock); + if (list_empty(&adapter->cmd_pending_q)) { + spin_unlock_bh(&adapter->cmd_pending_q_lock); + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + return 0; + } + cmd_node = list_first_entry(&adapter->cmd_pending_q, + struct cmd_ctrl_node, list); + + host_cmd = (struct host_cmd_ds_command *)(cmd_node->cmd_skb->data); + priv = cmd_node->priv; + + if (adapter->ps_state != PS_STATE_AWAKE) { + nxpwifi_dbg(adapter, ERROR, + "%s: cannot send cmd in sleep state,\t" + "this should not happen\n", __func__); + spin_unlock_bh(&adapter->cmd_pending_q_lock); + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + return ret; + } + + list_del(&cmd_node->list); + spin_unlock_bh(&adapter->cmd_pending_q_lock); + + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + ret = nxpwifi_dnld_cmd_to_fw(priv, cmd_node); + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + /* Any command sent to the firmware when host is in sleep + * mode should de-configure host sleep. We should skip the + * host sleep configuration command itself though + */ + if (priv && host_cmd->command != + cpu_to_le16(HOST_CMD_802_11_HS_CFG_ENH)) { + if (adapter->hs_activated) { + clear_bit(NXPWIFI_IS_HS_CONFIGURED, + &adapter->work_flags); + nxpwifi_hs_activated_event(priv, false); + } + } + + return ret; +} + +static void +nxpwifi_process_cmdresp_error(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ps_mode_enh *pm; + + nxpwifi_dbg(adapter, ERROR, + "CMD_RESP: cmd %#x error, result=%#x\n", + resp->command, resp->result); + + if (adapter->curr_cmd->wait_q_enabled) + adapter->cmd_wait_q.status = -1; + + switch (le16_to_cpu(resp->command)) { + case HOST_CMD_802_11_PS_MODE_ENH: + pm = &resp->params.psmode_enh; + nxpwifi_dbg(adapter, ERROR, + "PS_MODE_ENH cmd failed: result=0x%x action=0x%X\n", + resp->result, le16_to_cpu(pm->action)); + break; + case HOST_CMD_802_11_SCAN: + case HOST_CMD_802_11_SCAN_EXT: + nxpwifi_cancel_scan(adapter); + break; + + case HOST_CMD_MAC_CONTROL: + break; + + case HOST_CMD_SDIO_SP_RX_AGGR_CFG: + nxpwifi_dbg(adapter, MSG, + "SDIO RX single-port aggregation Not support\n"); + break; + + default: + break; + } + /* Handling errors here */ + nxpwifi_recycle_cmd_node(adapter, adapter->curr_cmd); + + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->curr_cmd = NULL; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); +} + +/* This function handles the command response. + * + * After processing, the function cleans the command node and puts + * it back to the command free queue. + */ +int nxpwifi_process_cmdresp(struct nxpwifi_adapter *adapter) +{ + struct host_cmd_ds_command *resp; + struct nxpwifi_private *priv = + nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + int ret = 0; + u16 orig_cmdresp_no; + u16 cmdresp_no; + u16 cmdresp_result; + + if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) { + resp = (struct host_cmd_ds_command *)adapter->upld_buf; + nxpwifi_dbg(adapter, ERROR, + "CMD_RESP: NULL curr_cmd, %#x\n", + le16_to_cpu(resp->command)); + return -EINVAL; + } + + resp = (struct host_cmd_ds_command *)adapter->curr_cmd->resp_skb->data; + orig_cmdresp_no = le16_to_cpu(resp->command); + cmdresp_no = (orig_cmdresp_no & HOST_CMD_ID_MASK); + + if (adapter->curr_cmd->cmd_no != cmdresp_no) { + nxpwifi_dbg(adapter, ERROR, + "cmdresp error: cmd=0x%x cmd_resp=0x%x\n", + adapter->curr_cmd->cmd_no, cmdresp_no); + return -EINVAL; + } + /* Now we got response from FW, cancel the command timer */ + del_timer_sync(&adapter->cmd_timer); + clear_bit(NXPWIFI_IS_CMD_TIMEDOUT, &adapter->work_flags); + + if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { + /* Copy original response back to response buffer */ + struct nxpwifi_ds_misc_cmd *hostcmd; + u16 size = le16_to_cpu(resp->size); + + nxpwifi_dbg(adapter, INFO, + "info: host cmd resp size = %d\n", size); + size = min_t(u16, size, NXPWIFI_SIZE_OF_CMD_BUFFER); + if (adapter->curr_cmd->data_buf) { + hostcmd = adapter->curr_cmd->data_buf; + hostcmd->len = size; + memcpy(hostcmd->cmd, resp, size); + } + } + + /* Get BSS number and corresponding priv */ + priv = nxpwifi_get_priv_by_id + (adapter, HOST_GET_BSS_NO(le16_to_cpu(resp->seq_num)), + HOST_GET_BSS_TYPE(le16_to_cpu(resp->seq_num))); + if (!priv) + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + /* Clear RET_BIT from HOST */ + resp->command = cpu_to_le16(orig_cmdresp_no & HOST_CMD_ID_MASK); + + cmdresp_no = le16_to_cpu(resp->command); + cmdresp_result = le16_to_cpu(resp->result); + + /* Save the last command response to debug log */ + adapter->dbg.last_cmd_resp_index = + (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] = + orig_cmdresp_no; + + nxpwifi_dbg(adapter, CMD, + "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n", + orig_cmdresp_no, cmdresp_result, + le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num)); + nxpwifi_dbg_dump(adapter, CMD_D, "CMD_RESP buffer:", resp, + le16_to_cpu(resp->size)); + + if (!(orig_cmdresp_no & HOST_RET_BIT)) { + nxpwifi_dbg(adapter, ERROR, "CMD_RESP: invalid cmd resp\n"); + if (adapter->curr_cmd->wait_q_enabled) + adapter->cmd_wait_q.status = -1; + + nxpwifi_recycle_cmd_node(adapter, adapter->curr_cmd); + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->curr_cmd = NULL; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + return -EINVAL; + } + + if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { + adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD; + if (cmdresp_result == HOST_RESULT_OK && + cmdresp_no == HOST_CMD_802_11_HS_CFG_ENH) + ret = nxpwifi_ret_802_11_hs_cfg(priv, resp); + } else { + if (resp->result != HOST_RESULT_OK) { + nxpwifi_process_cmdresp_error(priv, resp); + return -EFAULT; + } + if (adapter->curr_cmd->cmd_resp) { + void *data_buf = adapter->curr_cmd->data_buf; + + ret = adapter->curr_cmd->cmd_resp(priv, resp, + cmdresp_no, + data_buf); + } + } + + /* Check init command response */ + if (adapter->hw_status == NXPWIFI_HW_STATUS_INITIALIZING) { + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "%s: cmd %#x failed during\t" + "initialization\n", __func__, cmdresp_no); + nxpwifi_init_fw_complete(adapter); + return ret; + } else if (adapter->last_init_cmd == cmdresp_no) { + adapter->hw_status = NXPWIFI_HW_STATUS_INIT_DONE; + } + } + + if (adapter->curr_cmd) { + if (adapter->curr_cmd->wait_q_enabled) + adapter->cmd_wait_q.status = ret; + + nxpwifi_recycle_cmd_node(adapter, adapter->curr_cmd); + + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->curr_cmd = NULL; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + } + + return ret; +} + +void nxpwifi_process_assoc_resp(struct nxpwifi_adapter *adapter) +{ + struct cfg80211_rx_assoc_resp_data assoc_resp = { + .uapsd_queues = -1, + }; + struct nxpwifi_private *priv = + nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA); + + if (priv->assoc_rsp_size) { + assoc_resp.links[0].bss = priv->req_bss; + assoc_resp.buf = priv->assoc_rsp_buf; + assoc_resp.len = priv->assoc_rsp_size; + cfg80211_rx_assoc_resp(priv->netdev, + &assoc_resp); + priv->assoc_rsp_size = 0; + } +} + +/* This function handles the timeout of command sending. + * + * It will re-send the same command again. + */ +void +nxpwifi_cmd_timeout_func(struct timer_list *t) +{ + struct nxpwifi_adapter *adapter = from_timer(adapter, t, cmd_timer); + struct cmd_ctrl_node *cmd_node; + + set_bit(NXPWIFI_IS_CMD_TIMEDOUT, &adapter->work_flags); + if (!adapter->curr_cmd) { + nxpwifi_dbg(adapter, ERROR, + "cmd: empty curr_cmd\n"); + return; + } + cmd_node = adapter->curr_cmd; + if (cmd_node) { + adapter->dbg.timeout_cmd_id = + adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; + adapter->dbg.timeout_cmd_act = + adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index]; + nxpwifi_dbg(adapter, MSG, + "%s: Timeout cmd id = %#x, act = %#x\n", __func__, + adapter->dbg.timeout_cmd_id, + adapter->dbg.timeout_cmd_act); + + nxpwifi_dbg(adapter, MSG, + "num_data_h2c_failure = %d\n", + adapter->dbg.num_tx_host_to_card_failure); + nxpwifi_dbg(adapter, MSG, + "num_cmd_h2c_failure = %d\n", + adapter->dbg.num_cmd_host_to_card_failure); + + nxpwifi_dbg(adapter, MSG, + "is_cmd_timedout = %d\n", + test_bit(NXPWIFI_IS_CMD_TIMEDOUT, + &adapter->work_flags)); + nxpwifi_dbg(adapter, MSG, + "num_tx_timeout = %d\n", + adapter->dbg.num_tx_timeout); + + nxpwifi_dbg(adapter, MSG, + "last_cmd_index = %d\n", + adapter->dbg.last_cmd_index); + nxpwifi_dbg(adapter, MSG, + "last_cmd_id: %*ph\n", + (int)sizeof(adapter->dbg.last_cmd_id), + adapter->dbg.last_cmd_id); + nxpwifi_dbg(adapter, MSG, + "last_cmd_act: %*ph\n", + (int)sizeof(adapter->dbg.last_cmd_act), + adapter->dbg.last_cmd_act); + + nxpwifi_dbg(adapter, MSG, + "last_cmd_resp_index = %d\n", + adapter->dbg.last_cmd_resp_index); + nxpwifi_dbg(adapter, MSG, + "last_cmd_resp_id: %*ph\n", + (int)sizeof(adapter->dbg.last_cmd_resp_id), + adapter->dbg.last_cmd_resp_id); + + nxpwifi_dbg(adapter, MSG, + "last_event_index = %d\n", + adapter->dbg.last_event_index); + nxpwifi_dbg(adapter, MSG, + "last_event: %*ph\n", + (int)sizeof(adapter->dbg.last_event), + adapter->dbg.last_event); + + nxpwifi_dbg(adapter, MSG, + "data_sent=%d cmd_sent=%d\n", + adapter->data_sent, adapter->cmd_sent); + + nxpwifi_dbg(adapter, MSG, + "ps_mode=%d ps_state=%d\n", + adapter->ps_mode, adapter->ps_state); + + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -ETIMEDOUT; + nxpwifi_cancel_pending_ioctl(adapter); + } + } + if (adapter->hw_status == NXPWIFI_HW_STATUS_INITIALIZING) { + nxpwifi_init_fw_complete(adapter); + return; + } + + if (adapter->if_ops.device_dump) + adapter->if_ops.device_dump(adapter); + + if (adapter->if_ops.card_reset) + adapter->if_ops.card_reset(adapter); +} + +void +nxpwifi_cancel_pending_scan_cmd(struct nxpwifi_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; + + /* Cancel all pending scan command */ + spin_lock_bh(&adapter->scan_pending_q_lock); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + cmd_node->wait_q_enabled = false; + nxpwifi_insert_cmd_to_free_q(adapter, cmd_node); + } + spin_unlock_bh(&adapter->scan_pending_q_lock); +} + +/* This function cancels all the pending commands. + * + * The current command, all commands in command pending queue and all scan + * commands in scan pending queue are cancelled. All the completion callbacks + * are called with failure status to ensure cleanup. + */ +void +nxpwifi_cancel_all_pending_cmd(struct nxpwifi_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; + + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + /* Cancel current cmd */ + if (adapter->curr_cmd && adapter->curr_cmd->wait_q_enabled) { + adapter->cmd_wait_q.status = -1; + nxpwifi_complete_cmd(adapter, adapter->curr_cmd); + adapter->curr_cmd->wait_q_enabled = false; + /* no recycle probably wait for response */ + } + /* Cancel all pending command */ + spin_lock_bh(&adapter->cmd_pending_q_lock); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->cmd_pending_q, list) { + list_del(&cmd_node->list); + + if (cmd_node->wait_q_enabled) + adapter->cmd_wait_q.status = -1; + nxpwifi_recycle_cmd_node(adapter, cmd_node); + } + spin_unlock_bh(&adapter->cmd_pending_q_lock); + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + + nxpwifi_cancel_scan(adapter); +} + +/* This function cancels all pending commands that matches with + * the given IOCTL request. + * + * Both the current command buffer and the pending command queue are + * searched for matching IOCTL request. The completion callback of + * the matched command is called with failure status to ensure cleanup. + * In case of scan commands, all pending commands in scan pending queue + * are cancelled. + */ +static void +nxpwifi_cancel_pending_ioctl(struct nxpwifi_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node = NULL; + + if (adapter->curr_cmd && + adapter->curr_cmd->wait_q_enabled) { + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + cmd_node = adapter->curr_cmd; + /* setting curr_cmd to NULL is quite dangerous, because + * nxpwifi_process_cmdresp checks curr_cmd to be != NULL + * at the beginning then relies on it and dereferences + * it at will + * this probably works since nxpwifi_cmd_timeout_func + * is the only caller of this function and responses + * at that point + */ + adapter->curr_cmd = NULL; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + + nxpwifi_recycle_cmd_node(adapter, cmd_node); + } + + nxpwifi_cancel_scan(adapter); +} + +/* This function sends the sleep confirm command to firmware, if + * possible. + * + * The sleep confirm command cannot be issued if command response, + * data response or event response is awaiting handling, or if we + * are in the middle of sending a command, or expecting a command + * response. + */ +void +nxpwifi_check_ps_cond(struct nxpwifi_adapter *adapter) +{ + if (!adapter->cmd_sent && !atomic_read(&adapter->tx_hw_pending) && + !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter)) + nxpwifi_dnld_sleep_confirm_cmd(adapter); + else + nxpwifi_dbg(adapter, CMD, + "cmd: Delay Sleep Confirm (%s%s%s%s)\n", + (adapter->cmd_sent) ? "D" : "", + atomic_read(&adapter->tx_hw_pending) ? "T" : "", + (adapter->curr_cmd) ? "C" : "", + (IS_CARD_RX_RCVD(adapter)) ? "R" : ""); +} + +/* This function sends a Host Sleep activated event to applications. + * + * This event is generated by the driver, with a blank event body. + */ +void +nxpwifi_hs_activated_event(struct nxpwifi_private *priv, u8 activated) +{ + if (activated) { + if (test_bit(NXPWIFI_IS_HS_CONFIGURED, + &priv->adapter->work_flags)) { + priv->adapter->hs_activated = true; + nxpwifi_update_rxreor_flags(priv->adapter, + RXREOR_FORCE_NO_DROP); + nxpwifi_dbg(priv->adapter, EVENT, + "event: hs_activated\n"); + priv->adapter->hs_activate_wait_q_woken = true; + wake_up_interruptible(&priv->adapter->hs_activate_wait_q); + } else { + nxpwifi_dbg(priv->adapter, EVENT, + "event: HS not configured\n"); + } + } else { + nxpwifi_dbg(priv->adapter, EVENT, + "event: hs_deactivated\n"); + priv->adapter->hs_activated = false; + } +} + +/* This function handles the command response of a Host Sleep configuration + * command. + * + * Handling includes changing the header fields into CPU format + * and setting the current host sleep activation status in driver. + * + * In case host sleep status change, the function generates an event to + * notify the applications. + */ +int nxpwifi_ret_802_11_hs_cfg(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg = + &resp->params.opt_hs_cfg; + u32 conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions); + + if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) { + nxpwifi_hs_activated_event(priv, true); + goto done; + } else { + nxpwifi_dbg(adapter, CMD, + "cmd: CMD_RESP: HS_CFG cmd reply\t" + " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n", + resp->result, conditions, + phs_cfg->params.hs_config.gpio, + phs_cfg->params.hs_config.gap); + } + if (conditions != HS_CFG_CANCEL) { + set_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags); + } else { + clear_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags); + if (adapter->hs_activated) + nxpwifi_hs_activated_event(priv, false); + } + +done: + return 0; +} + +/* This function wakes up the adapter and generates a Host Sleep + * cancel event on receiving the power up interrupt. + */ +void +nxpwifi_process_hs_config(struct nxpwifi_adapter *adapter) +{ + nxpwifi_dbg(adapter, INFO, + "info: %s: auto cancelling host sleep\t" + "since there is interrupt from the firmware\n", + __func__); + + adapter->if_ops.wakeup(adapter); + + if (adapter->hs_activated_manually) { + nxpwifi_cancel_hs(nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY), + NXPWIFI_ASYNC_CMD); + adapter->hs_activated_manually = false; + } + + adapter->hs_activated = false; + clear_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags); + clear_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags); + nxpwifi_hs_activated_event(nxpwifi_get_priv(adapter, + NXPWIFI_BSS_ROLE_ANY), + false); +} +EXPORT_SYMBOL_GPL(nxpwifi_process_hs_config); + +/* This function handles the command response of a sleep confirm command. + * + * The function sets the card state to SLEEP if the response indicates success. + */ +void +nxpwifi_process_sleep_confirm_resp(struct nxpwifi_adapter *adapter, + u8 *pbuf, u32 upld_len) +{ + struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *)pbuf; + u16 result = le16_to_cpu(cmd->result); + u16 command = le16_to_cpu(cmd->command); + u16 seq_num = le16_to_cpu(cmd->seq_num); + + if (!upld_len) { + nxpwifi_dbg(adapter, ERROR, + "%s: cmd size is 0\n", __func__); + return; + } + + nxpwifi_dbg(adapter, CMD, + "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n", + command, result, le16_to_cpu(cmd->size), seq_num); + + /* Update sequence number */ + seq_num = HOST_GET_SEQ_NO(seq_num); + /* Clear RET_BIT from HOST */ + command &= HOST_CMD_ID_MASK; + + if (command != HOST_CMD_802_11_PS_MODE_ENH) { + nxpwifi_dbg(adapter, ERROR, + "%s: rcvd unexpected resp for cmd %#x, result = %x\n", + __func__, command, result); + return; + } + + if (result) { + nxpwifi_dbg(adapter, ERROR, + "%s: sleep confirm cmd failed\n", + __func__); + adapter->pm_wakeup_card_req = false; + adapter->ps_state = PS_STATE_AWAKE; + return; + } + adapter->pm_wakeup_card_req = true; + if (test_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags)) + nxpwifi_hs_activated_event(nxpwifi_get_priv + (adapter, NXPWIFI_BSS_ROLE_ANY), + true); + adapter->ps_state = PS_STATE_SLEEP; + cmd->command = cpu_to_le16(command); + cmd->seq_num = cpu_to_le16(seq_num); +} +EXPORT_SYMBOL_GPL(nxpwifi_process_sleep_confirm_resp); From patchwork Fri Aug 9 09:45:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818277 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3E13C195FD1; Fri, 9 Aug 2024 09:46:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196812; cv=fail; b=hAcZxJmoqBEpM8pniAYttQwix02kvxImLuFVT+vrOBbDF83TcnEFU5jlFKFbG7OWSZw5oBXofPD4nbQLrMKRk0sFtb4aQT0kJ4uFgKOawO1PfGhIaqssVpbylfWR7MInc9OoqG5Jognf8W2NmUdskAIcxZ2UNi3N6/gvDetMwzw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196812; c=relaxed/simple; bh=sByoiV5NuBr0ysCpf+1cJYFnV3SLEXnzmkAnOe4dkWA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=jDRGqAtVMCpbbTpze8+ZCd79Nv8vAk7VSvmJu9Im04A8RbiuOYhm3TlbgvMgyF2Oq7zJ8QRL0XmHSZR6rLFUUU4OJF4HpzfaMwf6wcQXACUdD5UogFtzXxorZAiZq9sxct4+LUL+WMaYlQHcBRMBS5aHB/L6Xnc68Iw2fIKLPY4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=QXHs0eM9; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="QXHs0eM9" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=rKL8LRqNbW8d+pK4RE7GKxbyhZ/C7murC1/vP9u1so9LXuNFJACzLGXPH+gWg+Sgx7dF21jHp/idsguLxIaU6HEW1heTJa90mgBHAamznnAVi3OBsclxOMYWkMBI+cWCGxhML5krAwhJXehKpCp9rb3j0rvoxjpWTrkJqT1vrRyOhOyIUj3EgmbzRVRQLmh4b4ACkLgmODqEtpqlyHqa/LbPgNA5F0QUXzoTd/ysTHJnOOjEuTJnBMpYlCxxMtVfPsivknApjwK6hlemxVdmyT+LQ63fHIF4o+1opOBQ9vhPSB0lPAzi/z+XiySer60CGYQUJo4roZEnVVA58JAJVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=WGvR0ke1v2oz4HbFeWbRfJE+qQcT48Bau5a3yFnvMvI=; b=rpBUCGhSkLdZnldI2jxJrd270TFPmHLnKfuqXPR5p1iEzHJxZ08K3WXG1twchYQc0XHb58v3msXU+EVlBtWE+WObZ/2/edrOsP+4VeH5v5VBC1G9RhC6jwa+XLFJDqgoOkTVYY89buiQDcOgB2dunwwzhcPmq/fwYnogDNOxPPj7NmGuadvJWvdZZU9fja8IsfVcuMoB5fxJuyp1H+xik7nHjFG6DwySJOpG6VQ/gjPqpaBzTLVMcRHgSP7Q2EdW9nS2tzDR6o49+Y3K8eRKRAHgy6WSB6YjQVzM7Iiv0m29qt86jse+/+Q/1dY8CZn/gD0AYlVsYSqTX+vxLrgqOQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=WGvR0ke1v2oz4HbFeWbRfJE+qQcT48Bau5a3yFnvMvI=; b=QXHs0eM9Lfw+dJFKpOP0QhCwveB9/XxL1wksVI1gkLs4OR8xhPN1kJVhRoWGQNdFbQXW4NHda1rL6v6waBBfrdEgYnw16AcqENdpqmXXwt45e1kH+1LFryoSx/hqUpS9y7KrYJ0ZlblwD3IW7PNRiYVh65/v0Nu+elI7iUowO1ajZj9u6KkLTTB+LyEseGjctxBqqywn69TzcVxzTZ/+slkHFo0PUmuC+FZ8TZDkgowhck4xvoDQaoK7Lp3fq61/yao2L/s0Knp/cPFSkOqjRc9w7ZNRl3Kegj6tgPSFibKi95MdWJKLY+7kLoyfnKBVWkrJfUJ3TzjTyWIaoLVsrQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:46:40 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:40 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 15/43] wifi: nxpwifi: add cmdevt.h Date: Fri, 9 Aug 2024 17:45:05 +0800 Message-Id: <20240809094533.1660-16-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: 1223687d-3b3c-43c3-48ae-08dcb8582b82 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: vn7QgSK4FTTpuCYxU30O9Zr1DRrnasqQUhzGn163yFGiwAUC7ZJQmf97XilVwp/tHQbnJzB5VaoLn6+Y50mItvjBjwMzpFcmh+qcYvNMcmCGNabJX72gcgH9WiOuOFzE/p+TcKMyUZFu7q/2gwpwY7drBO2jQb6LvpQs8z6EpWgzoMI2PT9D4sQz02L0gmU6gQZ0PSZVSnpNvCfGNurp5J/NE9jD1KI1PPipdj25aRJwLwQKajqvH5Ge8RRlCUU5mpCNGPpo63/VANoRM1pn1oLqK1KZ0t81lbEY8GCxOjn6r258FZX++QbRYS8oI5PKm5PJqZ2E5HATk2F/NmbZ/tf2FVT0Wfek4lo543TTanojkU2k+EZ0jqvDkwl4zxOpRZY2YGwiZmp+Tfz8JwwmHczpf8WtIlvQFImlAM3SDMu/ST6lUh+E89vnsT3RQN7yvkWCVSq4NJv+3DndDJBqpOE80zJBzPdLBfNaXyiZqaFvMk9EJrU+OROY8byFH+03pIPAbfRera5pz1nsHRU3eFBEQZFRZ/Q3QX+scGkzRKd+y4dFFtt6yde9fLpuzNUarDcvlGYVv7cA80Gx3XFqKPHrDyu3JcJzj2caRlVOyNk49AeymTIeXvb/M3IuIHFqk6dgrHiym+tUuc8M1YCOyLb1+6415TrNbghZ2F0+z8Z5LpyuaLRdcThx2wFAMPh6jIfpfhlz/mZyLok+9Q5egd4uLZB8CTR8dXAO7KWWSorhu0U3FC3Y1Qp6QwOrKBXDS3Ll7DPTsurhqfk35b43/mcRgtuGCmOKW6t1KDfdTlDxkt/6YJ9UJR9CYYjdBGmINFIDeopU3I8pNcrIAbz2NwWOAnfiyehlw5980V03+Cctjkbkv0JAzAzn7LepexdR4Za/AatIlSKWfXOdazzm1MDucZwRvLFDSIJBcyGU/LOvWvBbPLiapzS9GQha56TbQueJkZGwLRYZQj3llvSDWtI0hqqhM9k13XGcQnIKSWo3KRehf2BC+T9Wwrhu4JSgV0cRTBEryjxW0kR+2sWkge7m7UqfHFm8hSjZIE+BE8cX3znBj3h2h6YlY7lY1CM/YihAFIzxpSYZY6/RzSpwcB+SUi7JIzWc/szdWOaY2iRtduxf/GL+P24hUGn0VBwCCDJR2sR39u4rhUetZ+AtFyU0k3W+7bv4KVzgpc+1ncqk6Pvs3hOEkLDxhVxapd+aNleeYEiZ8t40tzuTpf9HWIE83lik8vjzKuCsCQ+yBQ4T7s9LK9DIObu0G4KAGomQ/U4ncDlOPwpIXqVtMRwM3wBQCsg8cqRclyf23yzTsoyX/Xeqx+0ZjuFSrRrIT3i4hfXZVpfssWDPbFqpZDlqfw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: cfpJc6JF4Y1wbEpSSJXuGRfLbDS+7V+qeok8gV5Le71q7JZ00xSsWRcvHYAMwZMLONvfcs9sYkTCbwbzx14ZrSbYvmfNVhrJ+/yWgDimnXuYzvHWsqmhz0ExNXwrcoRXmieRlGlBXQI7KCo1W2i42o965UGVdsSdIKUwM2PpbmyPqtEkFpRoJldjMrO1pPpdF2Gue+TEhCk8mVZxpB1Cz+g1RkYUvuX5CNSCOAFF1dWfcgCBBTXKtJ+66gmV2i5oeCUulm2JmE5qlOamlpnyTavTo1VuKH0UUQZzWG/he+bp9eOY3JuDaGqI0qqs76Qu4EIvk9aiO/c8TbjndTXQhOlbLWvnL66Rez225IZ5Wh1+JLr6skKWdXHl2BFsHOs4WZ7x3boGaa8cNiKP/hARyg0wH6H4+STTIsuZBgh88dylB3WJi7AslMn4OA2lN6g33VAtMAzzkK8pyQRp64H3MPMt0mCHwCZqeXwP7V4eD4sld/XQydJgIrGifObNww30T5FliLL/SjYqlO6tdJOf3TnGveBmBq4qwtIzxWWr3LqXBOaaSKLgr8ffJTTOj/qUy6/FtQ2kgnrG+Aj/NGsNCLnVFd2Xjtl8lWa6HohgK+vbUXwiTS5I4BzlPoG3/LeIy/wxNeA7UKwxmNHwgMYIiF06hZJ65LUhg1dcdWVnEnpMrMZcu/QQs45xG7rt14L9R14cgRFuYGtA75hWOcNWYXM4MbtrCgacJXhvXx1x2OJzFo6efFVj/SajeaLoTi24o5TTTlw7janbVVPV2j0yTWvNQtbdJNF09LpWvBCsKzCOUwDwL+jkpUCzuDBFT06WN/uurd9f4h029WSfyZ8yI27X39wE64TPyb+DrYM5enXyRixzZpNl2nBGm5iYEtq9MZhMHGEgaFvi+f/X8aT3xjvAF6T+nKQqy286NueOpSfjyFp0DPSChsNUU+MMB0dBOhD+y46a3Xb2v0hinBC64yCPhj47vKxSoo2HCeG6j8bVG3IMUvq3+o+anfetZL3myXOIEVVP93eP8RrPqgo6jINp6yHrSMJxfQWbsVW+x3rpaZjlv8+rpuunQEH7xuypzkUHOfXlT9FLAfH/j4PixvuW521SXTPC0T0Yjf45E+sUPP3EMKUVp7h7dVE20kNIB7DOaB5lPvXavWWk4CuQ/jOfPIVO+wBCpni19mXKZZKYQxM17DYNKz3I4+tu10nFPSj65u690yD+jOA4M4CF4MjN4PaExD1kWi/qSd4+GedYIVcmzUZ+agVngS3BPI8NTuk+jczo5KXybOpNT/h8nTjnahHVV3Mns3Lapbryg9YeuEozbJeBoy84RUYX12b379ShH0DyDhQJp5NANuQ0w6j9jzskhoy1tD4S7m+oCpxkFLPVE/XKcYTKlUxfXNeqUy4s6VNMWKAfSwAuQI5nvjh0VH07JrQl8SkLniLe3MwXLfWSGZeeaSP3RDHVXR9ZeICIKV+YxbMtvNVFHG+YlphTZoHlFMk+BfvtpdNr4uusIDyhSK+mSDgwODVvsA8HSkK+ZcTheVecyH3cKvYHdPYf0SzZtONZsM3sxsTdZ/d+Dk6ABqvHNH77H2eG188VlephQeAqVA5kXECERDqQ9aoCEjhx9DLb0dFV2Elav/2+l7iLUNJQASo9yFVU4q7h X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1223687d-3b3c-43c3-48ae-08dcb8582b82 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:40.7761 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: IgTsWdsRO/dpL8cDoeaAK6MkzQ32HsPOBzwXCqfVwH46Nk2WbsYmbIP/si6TrWABOz4r+o4mDuvCp5iPPLV4KA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/cmdevt.h | 92 +++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/cmdevt.h diff --git a/drivers/net/wireless/nxp/nxpwifi/cmdevt.h b/drivers/net/wireless/nxp/nxpwifi/cmdevt.h new file mode 100644 index 000000000000..a7774151fa5d --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/cmdevt.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: commands and events + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_CMD_EVT_H_ +#define _NXPWIFI_CMD_EVT_H_ + +struct nxpwifi_cmd_entry { + u16 cmd_no; + int (*prepare_cmd)(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type); + int (*cmd_resp)(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf); +}; + +struct nxpwifi_evt_entry { + u32 event_cause; + int (*event_handler)(struct nxpwifi_private *priv); +}; + +static inline int +nxpwifi_cmd_fill_head_only(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + cmd->command = cpu_to_le16(cmd_no); + cmd->size = cpu_to_le16(S_DS_GEN); + + return 0; +} + +int nxpwifi_send_cmd(struct nxpwifi_private *priv, u16 cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync); +int nxpwifi_sta_prepare_cmd(struct nxpwifi_private *priv, + struct cmd_ctrl_node *cmd_node, + u16 cmd_action, u32 cmd_oid); +int nxpwifi_dnld_dt_cfgdata(struct nxpwifi_private *priv, + struct device_node *node, const char *prefix); +int nxpwifi_sta_init_cmd(struct nxpwifi_private *priv, u8 first_sta, bool init); +int nxpwifi_uap_prepare_cmd(struct nxpwifi_private *priv, + struct cmd_ctrl_node *cmd_node, + u16 cmd_action, u32 type); +int nxpwifi_set_secure_params(struct nxpwifi_private *priv, + struct nxpwifi_uap_bss_param *bss_config, + struct cfg80211_ap_settings *params); +void nxpwifi_set_ht_params(struct nxpwifi_private *priv, + struct nxpwifi_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params); +void nxpwifi_set_vht_params(struct nxpwifi_private *priv, + struct nxpwifi_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params); +void nxpwifi_set_tpc_params(struct nxpwifi_private *priv, + struct nxpwifi_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params); +void nxpwifi_set_uap_rates(struct nxpwifi_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params); +void nxpwifi_set_vht_width(struct nxpwifi_private *priv, + enum nl80211_chan_width width, + bool ap_11ac_disable); +void nxpwifi_set_sys_config_invalid_data(struct nxpwifi_uap_bss_param *config); +void nxpwifi_set_wmm_params(struct nxpwifi_private *priv, + struct nxpwifi_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params); +void nxpwifi_config_uap_11d(struct nxpwifi_private *priv, + struct cfg80211_beacon_data *beacon_data); +void nxpwifi_uap_set_channel(struct nxpwifi_private *priv, + struct nxpwifi_uap_bss_param *bss_cfg, + struct cfg80211_chan_def chandef); +int nxpwifi_config_start_uap(struct nxpwifi_private *priv, + struct nxpwifi_uap_bss_param *bss_cfg); + +int nxpwifi_process_event(struct nxpwifi_adapter *adapter); +int nxpwifi_process_sta_event(struct nxpwifi_private *priv); +int nxpwifi_process_uap_event(struct nxpwifi_private *priv); +void nxpwifi_reset_connect_state(struct nxpwifi_private *priv, u16 reason, + bool from_ap); +void nxpwifi_process_multi_chan_event(struct nxpwifi_private *priv, + struct sk_buff *event_skb); +void nxpwifi_process_tx_pause_event(struct nxpwifi_private *priv, + struct sk_buff *event); +void nxpwifi_bt_coex_wlan_param_update_event(struct nxpwifi_private *priv, + struct sk_buff *event_skb); + +#endif /* !_NXPWIFI_CMD_EVT_H_ */ From patchwork Fri Aug 9 09:45:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818391 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A25A1974FE; Fri, 9 Aug 2024 09:46:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196815; cv=fail; b=qfGY2yx6K2qVXIKRjlwi6ZbDcQxs4M3SZrtfipgsWNEDk+lCnXdaH83qcVvnzCuR2GIDNL78d0Ws5npy18bv2GazNP1jOXkxNZQ2j/d78+22nQmEhHPAIJNKJV/vvA5Qjstmm1G5VHIouDN24aLCWPJlNN50YHJ1CeM7+pq/hQk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196815; c=relaxed/simple; bh=rCuRIgysCkC8jmUYDplCaucoyYkXkw9glgGZxByP5Lk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=cJO8kcx9b+OSLCjuaJu0FOiq7NnIRoR/aULHJxWqIRgl0VfC6kuWYB2DA0UJr4n8iCb3NI+bVl//4+Rigz6LMsueDr5Kk9Mv6zZOdDGNWVt5ByU5NIO4WaenLzcnzR7dcWFYuJBfSZ7T7qUI4YsJf+xl/BAAGjAPnzfzdnd3J4g= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=FGinxDfo; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="FGinxDfo" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=KdgobPyAiEZ8UiYekprT2NFkqFIgEfjcJAbnI0nzOfFydsMYQn8FNAJVKBMdDInEvbqMLXu96qt1x91nh3d8vAbLHxoNf4rhUSmf4jgdPfCvKmGCMD1cT/xyBR8QNhOPG+I2nMxUOYttDqNq9OtJR/kM89F83r8LDkvR4W+n1O5x/le3g1DVH3x+Iev9bHUFds6RB02xxGT3V/rX8z0+AU7hw8RcgfhPaWhGidkA6Y872P23e7I8LPOIgwuR9FhHE8PvWpDXqBAH1SlbE0sjfpReF+dIlqcC8rXYKIrwsEtp9EII1OSDbT9zTUQcMD/U9yQTNU0MPbEYa7NdqSGaJQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=dPFrIYLL82q+pqGXLwMyp/wE9AFpwXImrMeLmKCD9t4=; b=ufnZPuhog7MW8BHZWvB4VGXsZBTXO9xuL8Q7Cw5wI/ktgvQBxP1J9YpnZDAhP+tchysHa8Qv1dOWJTpESbmVmaIfqw4/8Zet7ciasc4MMsbyHIDUIk7OGayOS7IYzKVxyVi80X1NZbRh1m5BwaDEn4KJ4XveQe/t5bkXr3hC68iQ596pQ/4NibI56OWyhfMhnZohzWsfRTE2eZCec7C6ibdmylGtWHfm7HS0eXlEg7eHho1JWJInTx+u5NOyr9TSsznp68H4lf3vz6P2an4VQHc/KjmDZdeRhiutcZdd9wXO/Ca+wYghTt9f0R2cHKVzLinGymzGF6GFXWScLIKKCQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=dPFrIYLL82q+pqGXLwMyp/wE9AFpwXImrMeLmKCD9t4=; b=FGinxDfogfxsfWjb/qo5RwaDtBLpxZzs/nllTw5F4hE9ByLMXyuCoj3jm2Rk4VGvgluYtMaC3DuJW2L82hary4m3Jeh2OYAqbw2aUn//EvCsiYZInOJIu8C5xb0OObmf0Gh5K142gWcNj0DrIzUh1VPQY9c/cG8W9oSxlj7PxoYTAEFN91snTnzKxrTI0S+K5KAs8zaqiTe2wkYdydC1Vt2qAl8Osh+iUu/6dEvjU+FiCsUWqGKtSHHC+lJLdlbDdM9rX8S70lpKYVwcd9puZPekeXe64LfXZZXsvx4UbxbW7H8acnH9RZltLu1qswAal3V7BR/5gxTxU8PGlruJYw== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:46:44 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:44 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 16/43] wifi: nxpwifi: add debugfs.c Date: Fri, 9 Aug 2024 17:45:06 +0800 Message-Id: <20240809094533.1660-17-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: da044a13-78ac-4199-6abb-08dcb8582d5e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: dD84lBPtIPMhU3WFX/Qwlb/5qY4VaRFvpLaPbqqrYctPgX65mgUGC2rk3Q6v/NmFMKUofrTQdHKxsvTHrzd85IJOIcCbQinvCMJT+k6/VAT7qRRe94IKc+fk3hBkooJj4xEqfHiKaDpqfp5cLTeOdjccXvk1UEI1B6UC42TZBVtj1B8dcmTYcLaUNWpwWZdR0/b9OORa3M4+gOri+UXWnjfLs1Jg7bGBWKhGm+VQlYwvuVJgYVFg0DhDESUFXrXi2Js4dGzMNRY3mTzReABBPpd1i9vprd8JVj42EQU8haVOPJ6cxQJczuAo5GR23J9WY9PU71SS1voa8HSDkvEBaokOJLWgxgLmHCECJZeltfZvez76re7VdhNXlNmhTOQ43DTI5qJcGTxSPb7WArxZ7+V4D5z02pX/bTmqvpnuHCuMe8OKjzknGVmpx3sHvyTESnYIyqQtc7ybq5/1SUkXfWSah61ToCuFMzd5tzZ/3semwcAEDIfNsmW4HGOELtRkvEuiFIW570Pqv2GI53aThfDoxmi+EZS3Y5t1eNbwOA98ItJQjTbnQJDgNFY4TrPPAHSYnlN358FWEKBqQ9qfkaoRnwfZ5STbmyTmVbrN4PtNACR3N83Cyst3p0P2P+X3PzUYZ2N6O3oNIBKmEe7Y6NTYWe9wRHnraOCmmNc1wX5RwBkp2fuwG8L+2yAmnPOVNhNNxAfgcwMfRQNOT9Z2v27qZkjREvoRFs6V93h+f4IGWAbcvyi4rioxr5hW+GPWicFCQmgLuja/bW+iVB0nrXklo92+KAqUvGXq1KVrfBXTubNsjWdB/mUS4p/J/4uVOgk+FZUOYpHEvwhWUoceZsi1elo4GFJYh3vAXEVcrXrMU7yHFwLsGcCC6OM/RQeuuYmtaUX1R+fRmtY1cnwwHnA1GfXmP1u6ujm4Y6AJ+J/WWve+YuOm4Cv8bkN+WtBa7s8YK2dXfHCSjp2GzAMLFhyxkR/HWYjXG63aAtH2XIj9bro51HvgK4kizb0FButwPAIc3pHc6FcrrMU2I5ynk5sDbbTx+IU6i631NzptXhKyPoIjXVMvUiG0XRCqg1Z+R3uhOY2hFjRi5MjNjxui81Gcb2+cVGpwuy5HPPhfDyvX1fSa2xGGuRIslmQfd6cYFOQBd6wacaGSnGrIhyG5ZTUqyOBYudT8udacO/Vqz7ZCgG0vN6EPZuWwQ02pW0z7dlS/Foy9rENDM+ZHc5xccKjsmX51PXXiuHvq1TNjmDa/+ZpJFv+9Dp2q2jNBlOC4IdLoUfCa1EOF0c/UyPCGTAWn+b3lQ1a8WTNK8gezp45SyjRu5d7vmB6YSP9I3FPA0hiIXWH5NZnjAOgqEM5Lbg== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: L4t7M7EM24DI/OzUlSW3KoRJ+Zxo5cLTvy9F6EhqpF3yHEswv7jns1nJOBEZuQAN4wGUksttUWba+OV2MgqoXV4rS0N3j6xgQjErVUx2uJsqgBDfP0+FuedkTxyaamcwyCkWko2pV8q5bhXVbQrqQ4A9miVdxVobbenZdPMyUrE1MaBYfIYfQL4SB9FLSZzKJyBBBruuDVaKzOQozJ1n9elaHiITj6+y9U8lFqYPtoTtzkGQy/jfT5kCFDpyTXiy8xUGOH8/0kIczwWjULx+spo5IZhJk6WWHK01jbsaFu+2E/F5FLtQ8aoTxY09t6CjEFylB6jr1e4hRAsTSV9sYxNDNTp651xqwgbu0Jnq+Rx4m4eQa1ArIMB1pir2XqJ/FWFvucjsvK3BDNUkHLPAGCJL45I8cmIcxr73Kt+ZQcz3ehq0acMT6uui1wMsV/0/7oFA1Kza+CO7M64Fzy9umhP3W2rZoFPBMh0nF60px/X8XzF77Jr7j/NgZJpOEe6vCu4oxiO8cH2Xf9Gj29NNDlTgg7vV8m0u7JX/AwI7BDawDEYHgWPr7nZBmADQJkoxxuU8/7Y0EBbXqAe4hDEeh7cYSObqlAMModHX6v7syzfpnkYNw/Pe+3QsXPGasobN91v/kGRiouJx3Jmb80u8DWAdyqqdk2sW6aYoN8K91V8a+LvLbYF8GE4e1EiJknRmLqRBo+hSCnGBPin1Z7LJ0HPl31dh2jAKWGKG91ihJ4fYdhdm6QFoAck8Ceal0kQrMXgCf+//IXkNE6k42h55akPmw+5nSPCSjdrdwMEpuWfUv83i0uk3tOtK/4vV9cFUWQpuMtjD0rzIXFubHADMOZjLagPNu3VX/YB6bLv4n9cuvLd79Eyf7mtwDxcpYMT9SOLOumqwFn3Q79kHWCUcribcj9MSNJCpeIGfAzuuuSta9XKa83EgC5d+2O+nCHhBriANMaAXOUpXQkbPVFpxr1PE6JwOB7jmU6fjEBU1qnnqVnyNxEx87q2+/KC1IRJhMYJRfO/q/rxt08BXU0tW+5Me7srzGx/OrF564mZv2rxoxdXYByu3HeOPZIr3b84T4E3zQDDgPSRvD2U99fFGX9MuieI0AyrdY2rcx93p3wOF1fPt9l3FQpa/aiD8w7oJxg9f9cbAHw/Xlva9MQZ52JnAl2s4Rkzwdmd6DsRX08kRNKNDbNAM5J6pTUZwA1lANuQ277kiHD37Z9GjvbL9fwJSAL/8BRBEqK9ZCgRttUboGazfJ3sxtMQdBoDDMryTo+VKV9qt+fOkELjaam0Ex5TeMWQY397jmKDlVfD0RRW83KUXklPexr5sQprijRdO93CQ/zpZauA8545MUwAuzVmapjNlef2AfaZU1ID0RrUNFZp+3E3DEDzPJW9SE0AqgAO4zprcMMGN1EEfdwq1hA60bFbVbgxWVgJl+wq+fOXFvqm93g3ecyOI1FAySOMsVa7dWEwQDEaI6+MrA59CSafTjmxfXvMNPjvlv2Mk3/LrkDEX8nWj/FQEMbWb3Oe+RlwaQm33TdHR/l79Nmg+ES7nAXJ30dbbh8pdg/Qx7ViwJXqdwppf2e80vwaJkKemso3jgFtIspCVY68L1OftIPjr8wskL0adXW4MsNCOCTZMYh3PYVPvinnjQpDE25kf X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: da044a13-78ac-4199-6abb-08dcb8582d5e X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:43.9589 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: VuKHy6ApfbTQDQzWJEWFwpwz5KwdwsXQXjDqSphl2B/mQhKvvcVuF72D4/XUq3wnlgUL+wvowuDzH6UpkbagxA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/debugfs.c | 1041 ++++++++++++++++++++ 1 file changed, 1041 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/debugfs.c diff --git a/drivers/net/wireless/nxp/nxpwifi/debugfs.c b/drivers/net/wireless/nxp/nxpwifi/debugfs.c new file mode 100644 index 000000000000..a8a5f815f7fa --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/debugfs.c @@ -0,0 +1,1041 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: debugfs + * + * Copyright 2011-2024 NXP + */ + +#include + +#include "main.h" +#include "cmdevt.h" +#include "11n.h" + +static struct dentry *nxpwifi_dfs_dir; + +static char *bss_modes[] = { + "UNSPECIFIED", + "ADHOC", + "STATION", + "AP", + "AP_VLAN", + "WDS", + "MONITOR", + "MESH_POINT", + "P2P_CLIENT", + "P2P_GO", + "P2P_DEVICE", +}; + +/* Proc info file read handler. + * + * This function is called when the 'info' file is opened for reading. + * It prints the following driver related information - + * - Driver name + * - Driver version + * - Driver extended version + * - Interface name + * - BSS mode + * - Media state (connected or disconnected) + * - MAC address + * - Total number of Tx bytes + * - Total number of Rx bytes + * - Total number of Tx packets + * - Total number of Rx packets + * - Total number of dropped Tx packets + * - Total number of dropped Rx packets + * - Total number of corrupted Tx packets + * - Total number of corrupted Rx packets + * - Carrier status (on or off) + * - Tx queue status (started or stopped) + * + * For STA mode drivers, it also prints the following extra - + * - ESSID + * - BSSID + * - Channel + * - Region code + * - Multicast count + * - Multicast addresses + */ +static ssize_t +nxpwifi_info_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = + (struct nxpwifi_private *)file->private_data; + struct net_device *netdev = priv->netdev; + struct netdev_hw_addr *ha; + struct netdev_queue *txq; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *)page, fmt[64]; + struct nxpwifi_bss_info info; + ssize_t ret; + int i = 0; + + if (!p) + return -ENOMEM; + + memset(&info, 0, sizeof(info)); + ret = nxpwifi_get_bss_info(priv, &info); + if (ret) + goto free_and_exit; + + nxpwifi_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); + + nxpwifi_get_ver_ext(priv, 0); + + p += sprintf(p, "driver_name = "); + p += sprintf(p, "\"nxpwifi\"\n"); + p += sprintf(p, "driver_version = %s", fmt); + p += sprintf(p, "\nverext = %s", priv->version_str); + p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); + + if (info.bss_mode >= ARRAY_SIZE(bss_modes)) + p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode); + else + p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); + + p += sprintf(p, "media_state=\"%s\"\n", + (!priv->media_connected ? "Disconnected" : "Connected")); + p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr); + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA) { + p += sprintf(p, "multicast_count=\"%d\"\n", + netdev_mc_count(netdev)); + p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len, + info.ssid.ssid); + p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); + p += sprintf(p, "channel=\"%d\"\n", (int)info.bss_chan); + p += sprintf(p, "country_code = \"%s\"\n", info.country_code); + p += sprintf(p, "region_code=\"0x%x\"\n", + priv->adapter->region_code); + + netdev_for_each_mc_addr(ha, netdev) + p += sprintf(p, "multicast_address[%d]=\"%pM\"\n", + i++, ha->addr); + } + + p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); + p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); + p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); + p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); + p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); + p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); + p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); + p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); + p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) + ? "on" : "off")); + p += sprintf(p, "tx queue"); + for (i = 0; i < netdev->num_tx_queues; i++) { + txq = netdev_get_tx_queue(netdev, i); + p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ? + "stopped" : "started"); + } + p += sprintf(p, "\n"); + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, + (unsigned long)p - page); + +free_and_exit: + free_page(page); + return ret; +} + +/* Proc getlog file read handler. + * + * This function is called when the 'getlog' file is opened for reading + * It prints the following log information - + * - Number of multicast Tx frames + * - Number of failed packets + * - Number of Tx retries + * - Number of multicast Tx retries + * - Number of duplicate frames + * - Number of RTS successes + * - Number of RTS failures + * - Number of ACK failures + * - Number of fragmented Rx frames + * - Number of multicast Rx frames + * - Number of FCS errors + * - Number of Tx frames + * - WEP ICV error counts + * - Number of received beacons + * - Number of missed beacons + */ +static ssize_t +nxpwifi_getlog_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = + (struct nxpwifi_private *)file->private_data; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *)page; + ssize_t ret; + struct nxpwifi_ds_get_stats stats; + + if (!p) + return -ENOMEM; + + memset(&stats, 0, sizeof(stats)); + ret = nxpwifi_get_stats_info(priv, &stats); + if (ret) + goto free_and_exit; + + p += sprintf(p, "\n" + "mcasttxframe %u\n" + "failed %u\n" + "retry %u\n" + "multiretry %u\n" + "framedup %u\n" + "rtssuccess %u\n" + "rtsfailure %u\n" + "ackfailure %u\n" + "rxfrag %u\n" + "mcastrxframe %u\n" + "fcserror %u\n" + "txframe %u\n" + "wepicverrcnt-1 %u\n" + "wepicverrcnt-2 %u\n" + "wepicverrcnt-3 %u\n" + "wepicverrcnt-4 %u\n" + "bcn_rcv_cnt %u\n" + "bcn_miss_cnt %u\n", + stats.mcast_tx_frame, + stats.failed, + stats.retry, + stats.multi_retry, + stats.frame_dup, + stats.rts_success, + stats.rts_failure, + stats.ack_failure, + stats.rx_frag, + stats.mcast_rx_frame, + stats.fcs_error, + stats.tx_frame, + stats.wep_icv_error[0], + stats.wep_icv_error[1], + stats.wep_icv_error[2], + stats.wep_icv_error[3], + stats.bcn_rcv_cnt, + stats.bcn_miss_cnt); + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, + (unsigned long)p - page); + +free_and_exit: + free_page(page); + return ret; +} + +/* Sysfs histogram file read handler. + * + * This function is called when the 'histogram' file is opened for reading + * It prints the following histogram information - + * - Number of histogram samples + * - Receive packet number of each rx_rate + * - Receive packet number of each snr + * - Receive packet number of each nosie_flr + * - Receive packet number of each signal streath + */ +static ssize_t +nxpwifi_histogram_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = + (struct nxpwifi_private *)file->private_data; + ssize_t ret; + struct nxpwifi_histogram_data *phist_data; + int i, value; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *)page; + + if (!p) + return -ENOMEM; + + if (!priv || !priv->hist_data) { + ret = -EFAULT; + goto free_and_exit; + } + + phist_data = priv->hist_data; + + p += sprintf(p, "\n" + "total samples = %d\n", + atomic_read(&phist_data->num_samples)); + + p += sprintf(p, + "rx rates (in Mbps): 0=1M 1=2M 2=5.5M 3=11M 4=6M 5=9M 6=12M\n" + "7=18M 8=24M 9=36M 10=48M 11=54M 12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n"); + + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { + p += sprintf(p, + "44-53=MCS0-9(VHT:BW20) 54-63=MCS0-9(VHT:BW40) 64-73=MCS0-9(VHT:BW80)\n\n"); + } else { + p += sprintf(p, "\n"); + } + + for (i = 0; i < NXPWIFI_MAX_RX_RATES; i++) { + value = atomic_read(&phist_data->rx_rate[i]); + if (value) + p += sprintf(p, "rx_rate[%02d] = %d\n", i, value); + } + + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { + for (i = NXPWIFI_MAX_RX_RATES; i < NXPWIFI_MAX_AC_RX_RATES; + i++) { + value = atomic_read(&phist_data->rx_rate[i]); + if (value) + p += sprintf(p, "rx_rate[%02d] = %d\n", + i, value); + } + } + + for (i = 0; i < NXPWIFI_MAX_SNR; i++) { + value = atomic_read(&phist_data->snr[i]); + if (value) + p += sprintf(p, "snr[%02ddB] = %d\n", i, value); + } + for (i = 0; i < NXPWIFI_MAX_NOISE_FLR; i++) { + value = atomic_read(&phist_data->noise_flr[i]); + if (value) + p += sprintf(p, "noise_flr[%02ddBm] = %d\n", + (int)(i - 128), value); + } + for (i = 0; i < NXPWIFI_MAX_SIG_STRENGTH; i++) { + value = atomic_read(&phist_data->sig_str[i]); + if (value) + p += sprintf(p, "sig_strength[-%02ddBm] = %d\n", + i, value); + } + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, + (unsigned long)p - page); + +free_and_exit: + free_page(page); + return ret; +} + +static ssize_t +nxpwifi_histogram_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = (void *)file->private_data; + + if (priv && priv->hist_data) + nxpwifi_hist_data_reset(priv); + return 0; +} + +static struct nxpwifi_debug_info info; + +/* Proc debug file read handler. + * + * This function is called when the 'debug' file is opened for reading + * It prints the following log information - + * - Interrupt count + * - WMM AC VO packets count + * - WMM AC VI packets count + * - WMM AC BE packets count + * - WMM AC BK packets count + * - Maximum Tx buffer size + * - Tx buffer size + * - Current Tx buffer size + * - Power Save mode + * - Power Save state + * - Deep Sleep status + * - Device wakeup required status + * - Number of wakeup tries + * - Host Sleep configured status + * - Host Sleep activated status + * - Number of Tx timeouts + * - Number of command timeouts + * - Last timed out command ID + * - Last timed out command action + * - Last command ID + * - Last command action + * - Last command index + * - Last command response ID + * - Last command response index + * - Last event + * - Last event index + * - Number of host to card command failures + * - Number of sleep confirm command failures + * - Number of host to card data failure + * - Number of deauthentication events + * - Number of disassociation events + * - Number of link lost events + * - Number of deauthentication commands + * - Number of association success commands + * - Number of association failure commands + * - Number of commands sent + * - Number of data packets sent + * - Number of command responses received + * - Number of events received + * - Tx BA stream table (TID, RA) + * - Rx reorder table (TID, TA, Start window, Window size, Buffer) + */ +static ssize_t +nxpwifi_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = + (struct nxpwifi_private *)file->private_data; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *)page; + ssize_t ret; + + if (!p) + return -ENOMEM; + + ret = nxpwifi_get_debug_info(priv, &info); + if (ret) + goto free_and_exit; + + p += nxpwifi_debug_info_to_buffer(priv, p, &info); + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, + (unsigned long)p - page); + +free_and_exit: + free_page(page); + return ret; +} + +static u32 saved_reg_type, saved_reg_offset, saved_reg_value; + +/* Proc regrdwr file write handler. + * + * This function is called when the 'regrdwr' file is opened for writing + * + * This function can be used to write to a register. + */ +static ssize_t +nxpwifi_regrdwr_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + char *buf; + int ret; + u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; + int rv; + + buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + rv = sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); + + if (rv != 3) { + ret = -EINVAL; + goto done; + } + + if (reg_type == 0 || reg_offset == 0) { + ret = -EINVAL; + goto done; + } else { + saved_reg_type = reg_type; + saved_reg_offset = reg_offset; + saved_reg_value = reg_value; + ret = count; + } +done: + kfree(buf); + return ret; +} + +/* Proc regrdwr file read handler. + * + * This function is called when the 'regrdwr' file is opened for reading + * + * This function can be used to read from a register. + */ +static ssize_t +nxpwifi_regrdwr_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = + (struct nxpwifi_private *)file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + int pos = 0, ret = 0; + u32 reg_value; + + if (!buf) + return -ENOMEM; + + if (!saved_reg_type) { + /* No command has been given */ + pos += snprintf(buf, PAGE_SIZE, "0"); + goto done; + } + /* Set command has been given */ + if (saved_reg_value != UINT_MAX) { + ret = nxpwifi_reg_write(priv, saved_reg_type, saved_reg_offset, + saved_reg_value); + + pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", + saved_reg_type, saved_reg_offset, + saved_reg_value); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + + goto done; + } + /* Get command has been given */ + ret = nxpwifi_reg_read(priv, saved_reg_type, + saved_reg_offset, ®_value); + if (ret) { + ret = -EINVAL; + goto done; + } + + pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, + saved_reg_offset, reg_value); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + +done: + free_page(addr); + return ret; +} + +/* Proc debug_mask file read handler. + * This function is called when the 'debug_mask' file is opened for reading + * This function can be used read driver debugging mask value. + */ +static ssize_t +nxpwifi_debug_mask_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = + (struct nxpwifi_private *)file->private_data; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)page; + size_t ret = 0; + int pos = 0; + + if (!buf) + return -ENOMEM; + + pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n", + priv->adapter->debug_mask); + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + + free_page(page); + return ret; +} + +/* Proc debug_mask file read handler. + * This function is called when the 'debug_mask' file is opened for reading + * This function can be used read driver debugging mask value. + */ +static ssize_t +nxpwifi_debug_mask_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + int ret; + unsigned long debug_mask; + struct nxpwifi_private *priv = (void *)file->private_data; + char *buf; + + buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + if (kstrtoul(buf, 0, &debug_mask)) { + ret = -EINVAL; + goto done; + } + + priv->adapter->debug_mask = debug_mask; + ret = count; +done: + kfree(buf); + return ret; +} + +/* debugfs verext file write handler. + * This function is called when the 'verext' file is opened for write + */ +static ssize_t +nxpwifi_verext_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + int ret; + u32 versionstrsel; + struct nxpwifi_private *priv = (void *)file->private_data; + + ret = kstrtou32_from_user(ubuf, count, 10, &versionstrsel); + if (ret) + return ret; + + priv->versionstrsel = versionstrsel; + + return count; +} + +/* Proc verext file read handler. + * This function is called when the 'verext' file is opened for reading + * This function can be used read driver exteneed verion string. + */ +static ssize_t +nxpwifi_verext_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = + (struct nxpwifi_private *)file->private_data; + char buf[256]; + int ret; + + nxpwifi_get_ver_ext(priv, priv->versionstrsel); + ret = snprintf(buf, sizeof(buf), "version string: %s\n", + priv->version_str); + + return simple_read_from_buffer(ubuf, count, ppos, buf, ret); +} + +/* Proc memrw file write handler. + * This function is called when the 'memrw' file is opened for writing + * This function can be used to write to a memory location. + */ +static ssize_t +nxpwifi_memrw_write(struct file *file, const char __user *ubuf, size_t count, + loff_t *ppos) +{ + int ret; + char cmd; + struct nxpwifi_ds_mem_rw mem_rw; + u16 cmd_action; + struct nxpwifi_private *priv = (void *)file->private_data; + char *buf; + + buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value); + if (ret != 3) { + ret = -EINVAL; + goto done; + } + + if ((cmd == 'r') || (cmd == 'R')) { + cmd_action = HOST_ACT_GEN_GET; + mem_rw.value = 0; + } else if ((cmd == 'w') || (cmd == 'W')) { + cmd_action = HOST_ACT_GEN_SET; + } else { + ret = -EINVAL; + goto done; + } + + memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw)); + ret = nxpwifi_send_cmd(priv, HOST_CMD_MEM_ACCESS, cmd_action, 0, + &mem_rw, true); + if (!ret) + ret = count; + +done: + kfree(buf); + return ret; +} + +/* Proc memrw file read handler. + * This function is called when the 'memrw' file is opened for reading + * This function can be used to read from a memory location. + */ +static ssize_t +nxpwifi_memrw_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = (void *)file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + int ret, pos = 0; + + if (!buf) + return -ENOMEM; + + pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr, + priv->mem_rw.value); + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + + free_page(addr); + return ret; +} + +static u32 saved_offset = -1, saved_bytes = -1; + +/* Proc rdeeprom file write handler. + * + * This function is called when the 'rdeeprom' file is opened for writing + * + * This function can be used to write to a RDEEPROM location. + */ +static ssize_t +nxpwifi_rdeeprom_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + char *buf; + int ret = 0; + int offset = -1, bytes = -1; + int rv; + + buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + rv = sscanf(buf, "%d %d", &offset, &bytes); + + if (rv != 2) { + ret = -EINVAL; + goto done; + } + + if (offset == -1 || bytes == -1) { + ret = -EINVAL; + goto done; + } else { + saved_offset = offset; + saved_bytes = bytes; + ret = count; + } +done: + kfree(buf); + return ret; +} + +/* Proc rdeeprom read write handler. + * + * This function is called when the 'rdeeprom' file is opened for reading + * + * This function can be used to read from a RDEEPROM location. + */ +static ssize_t +nxpwifi_rdeeprom_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = + (struct nxpwifi_private *)file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + int pos, ret, i; + u8 value[MAX_EEPROM_DATA]; + + if (!buf) + return -ENOMEM; + + if (saved_offset == -1) { + /* No command has been given */ + pos = snprintf(buf, PAGE_SIZE, "0"); + goto done; + } + + /* Get command has been given */ + ret = nxpwifi_eeprom_read(priv, (u16)saved_offset, + (u16)saved_bytes, value); + if (ret) { + ret = -EINVAL; + goto out_free; + } + + pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); + + for (i = 0; i < saved_bytes; i++) + pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]); + +done: + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); +out_free: + free_page(addr); + return ret; +} + +/* Proc hscfg file write handler + * This function can be used to configure the host sleep parameters. + */ +static ssize_t +nxpwifi_hscfg_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = (void *)file->private_data; + char *buf; + int ret, arg_num; + struct nxpwifi_ds_hs_cfg hscfg; + int conditions = HS_CFG_COND_DEF; + u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF; + + buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap); + + memset(&hscfg, 0, sizeof(struct nxpwifi_ds_hs_cfg)); + + if (arg_num > 3) { + nxpwifi_dbg(priv->adapter, ERROR, + "Too many arguments\n"); + ret = -EINVAL; + goto done; + } + + if (arg_num >= 1 && arg_num < 3) + nxpwifi_set_hs_params(priv, HOST_ACT_GEN_GET, + NXPWIFI_SYNC_CMD, &hscfg); + + if (arg_num) { + if (conditions == HS_CFG_CANCEL) { + nxpwifi_cancel_hs(priv, NXPWIFI_ASYNC_CMD); + ret = count; + goto done; + } + hscfg.conditions = conditions; + } + if (arg_num >= 2) + hscfg.gpio = gpio; + if (arg_num == 3) + hscfg.gap = gap; + + hscfg.is_invoke_hostcmd = false; + nxpwifi_set_hs_params(priv, HOST_ACT_GEN_SET, + NXPWIFI_SYNC_CMD, &hscfg); + + nxpwifi_enable_hs(priv->adapter); + clear_bit(NXPWIFI_IS_HS_ENABLING, &priv->adapter->work_flags); + ret = count; +done: + kfree(buf); + return ret; +} + +/* Proc hscfg file read handler + * This function can be used to read host sleep configuration + * parameters from driver. + */ +static ssize_t +nxpwifi_hscfg_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = (void *)file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + int pos, ret; + struct nxpwifi_ds_hs_cfg hscfg; + + if (!buf) + return -ENOMEM; + + nxpwifi_set_hs_params(priv, HOST_ACT_GEN_GET, + NXPWIFI_SYNC_CMD, &hscfg); + + pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions, + hscfg.gpio, hscfg.gap); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + + free_page(addr); + return ret; +} + +static ssize_t +nxpwifi_timeshare_coex_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = file->private_data; + char buf[3]; + bool timeshare_coex; + int ret; + unsigned int len; + + if (priv->adapter->fw_api_ver != NXPWIFI_FW_V15) + return -EOPNOTSUPP; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_ROBUST_COEX, + HOST_ACT_GEN_GET, 0, ×hare_coex, true); + if (ret) + return ret; + + len = sprintf(buf, "%d\n", timeshare_coex); + return simple_read_from_buffer(ubuf, count, ppos, buf, len); +} + +static ssize_t +nxpwifi_timeshare_coex_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + bool timeshare_coex; + struct nxpwifi_private *priv = file->private_data; + int ret; + + if (priv->adapter->fw_api_ver != NXPWIFI_FW_V15) + return -EOPNOTSUPP; + + ret = kstrtobool_from_user(ubuf, count, ×hare_coex); + if (ret) + return ret; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_ROBUST_COEX, + HOST_ACT_GEN_SET, 0, ×hare_coex, true); + if (ret) + return ret; + else + return count; +} + +static ssize_t +nxpwifi_reset_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = file->private_data; + struct nxpwifi_adapter *adapter = priv->adapter; + bool result; + int rc; + + rc = kstrtobool_from_user(ubuf, count, &result); + if (rc) + return rc; + + if (!result) + return -EINVAL; + + if (adapter->if_ops.card_reset) { + dev_info(adapter->dev, "Resetting per request\n"); + adapter->if_ops.card_reset(adapter); + } + + return count; +} + +static ssize_t +nxpwifi_fake_radar_detect_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct nxpwifi_private *priv = file->private_data; + struct nxpwifi_adapter *adapter = priv->adapter; + bool result; + int rc; + + rc = kstrtobool_from_user(ubuf, count, &result); + if (rc) + return rc; + + if (!result) + return -EINVAL; + + if (priv->wdev.cac_started) { + nxpwifi_dbg(adapter, MSG, + "Generate fake radar detected during CAC\n"); + if (nxpwifi_stop_radar_detection(priv, &priv->dfs_chandef)) + nxpwifi_dbg(adapter, ERROR, + "Failed to stop CAC in FW\n"); + cancel_delayed_work_sync(&priv->dfs_cac_work); + cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); + cfg80211_radar_event(adapter->wiphy, &priv->dfs_chandef, + GFP_KERNEL); + } else { + if (priv->bss_chandef.chan->dfs_cac_ms) { + nxpwifi_dbg(adapter, MSG, + "Generate fake radar detected\n"); + cfg80211_radar_event(adapter->wiphy, + &priv->dfs_chandef, + GFP_KERNEL); + } + } + + return count; +} + +#define NXPWIFI_DFS_ADD_FILE(name) debugfs_create_file(#name, 0644, \ + priv->dfs_dev_dir, priv, \ + &nxpwifi_dfs_##name##_fops) + +#define NXPWIFI_DFS_FILE_OPS(name) \ +static const struct file_operations nxpwifi_dfs_##name##_fops = { \ + .read = nxpwifi_##name##_read, \ + .write = nxpwifi_##name##_write, \ + .open = simple_open, \ +} + +#define NXPWIFI_DFS_FILE_READ_OPS(name) \ +static const struct file_operations nxpwifi_dfs_##name##_fops = { \ + .read = nxpwifi_##name##_read, \ + .open = simple_open, \ +} + +#define NXPWIFI_DFS_FILE_WRITE_OPS(name) \ +static const struct file_operations nxpwifi_dfs_##name##_fops = { \ + .write = nxpwifi_##name##_write, \ + .open = simple_open, \ +} + +NXPWIFI_DFS_FILE_READ_OPS(info); +NXPWIFI_DFS_FILE_READ_OPS(debug); +NXPWIFI_DFS_FILE_READ_OPS(getlog); +NXPWIFI_DFS_FILE_OPS(regrdwr); +NXPWIFI_DFS_FILE_OPS(rdeeprom); +NXPWIFI_DFS_FILE_OPS(memrw); +NXPWIFI_DFS_FILE_OPS(hscfg); +NXPWIFI_DFS_FILE_OPS(histogram); +NXPWIFI_DFS_FILE_OPS(debug_mask); +NXPWIFI_DFS_FILE_OPS(timeshare_coex); +NXPWIFI_DFS_FILE_WRITE_OPS(reset); +NXPWIFI_DFS_FILE_WRITE_OPS(fake_radar_detect); +NXPWIFI_DFS_FILE_OPS(verext); + +/* This function creates the debug FS directory structure and the files. + */ +void +nxpwifi_dev_debugfs_init(struct nxpwifi_private *priv) +{ + if (!nxpwifi_dfs_dir || !priv) + return; + + priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, + nxpwifi_dfs_dir); + + NXPWIFI_DFS_ADD_FILE(info); + NXPWIFI_DFS_ADD_FILE(debug); + NXPWIFI_DFS_ADD_FILE(getlog); + NXPWIFI_DFS_ADD_FILE(regrdwr); + NXPWIFI_DFS_ADD_FILE(rdeeprom); + + NXPWIFI_DFS_ADD_FILE(memrw); + NXPWIFI_DFS_ADD_FILE(hscfg); + NXPWIFI_DFS_ADD_FILE(histogram); + NXPWIFI_DFS_ADD_FILE(debug_mask); + NXPWIFI_DFS_ADD_FILE(timeshare_coex); + NXPWIFI_DFS_ADD_FILE(reset); + NXPWIFI_DFS_ADD_FILE(fake_radar_detect); + NXPWIFI_DFS_ADD_FILE(verext); +} + +/* This function removes the debug FS directory structure and the files. + */ +void +nxpwifi_dev_debugfs_remove(struct nxpwifi_private *priv) +{ + if (!priv) + return; + + debugfs_remove_recursive(priv->dfs_dev_dir); +} + +/* This function creates the top level proc directory. + */ +void +nxpwifi_debugfs_init(void) +{ + if (!nxpwifi_dfs_dir) + nxpwifi_dfs_dir = debugfs_create_dir("nxpwifi", NULL); +} + +/* This function removes the top level proc directory. + */ +void +nxpwifi_debugfs_remove(void) +{ + debugfs_remove(nxpwifi_dfs_dir); +} From patchwork Fri Aug 9 09:45:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818276 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A427192B87; Fri, 9 Aug 2024 09:46:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196818; cv=fail; b=lJ/4R1b2tNpdgd5XHSbD7d9n8xznvwZkEOw8dyLJXzbPdixEFmbu4ScBMR6f8/sW4z+N7Nx4kOxjTwbYLQOabEBEh28zpKfIbbOoPusSs4qQab4jB1ZVAERM4wedQcpk7C8eas34fHEoL/3WLqstRQVmvEufMaKb5zlhgtxVoNE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196818; c=relaxed/simple; bh=4jneY9QPHv+/KYl3GvjaaIAsVBkH1CncQL74fk8/1a4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=pTS/zpBrx9CPddVmJw/WQcM0PQJcivX4zVQveygPpq5wDo65q75xwdoyIrxKslRjjFTBzU2pli3tBYxn6uNzkro3zS94hl2BR/TfWrlF8akUOqvjSCzkIqn3nqrHt9NKsPketCAJeg2fzG+uVIcWh0DVbevE17pgSXb4ShnNt/k= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=JV8E0KLJ; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="JV8E0KLJ" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ClYYBGGKwo2f3FePuv41N1mwVjZNfk2assR6zoiKZONtNkm3HMhVQjDo2lzgbx8liaBIkSDKFeEhDPdZ3bhDG+LLF+AgMT7p9Dbua4VK4Wf4CgMGEbgzwYbExNRyROGpK6255y/G/7/uwZejAmOHnxmEi7PXu5elLlg9ZD4gVlTwztFuJCQ8mQnggDGp56V6nSQh8vRuOC0Q7N9HeX076NwoyTEXBQGXYJVYHhWty984T8BWjQ9ZWXjA1NZuU0UdSqdgZlmXvI34vhuen0W3os550Hv+G4ZW0fMYGAQtqWjIEnOR3ZIFLpKwzRTHFQhcD07b8was3Vj3O4rN4p8/fg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=0+9PUGqbaRn9zMe5jATArZOPJPjoi0ukRVI0tRimJfM=; b=y9LKuNZON1uO6odCHQUCSFQClTsthEAQg5pcX0I6CWr8zBz28XPrbEGihz/DOH+lzOvzKbBPsDRrT5uf4HnHthPaDe2P3m6Qiz5YWgiT0aNfbx8trgMzDKifpwZ3HPU6Rn0a8d4Uew191zKTdBDJHnF/u/kTlMSdDgaB5Dtr83LEyV5pvxsJiiNop0oM/vspfiKjGTk7jQGeWZgxXlEPplO3ZjbDVtumNrVzHYKoKcgI9F4GgII5j59Ez1qDXsRqZWNpYV3UyIAt/wddxSxq/PsQDY6aJK7YKpcBf8oftveQB/q0LMIGf37XIklUc/ekSRG/7RB0LOaB1rWAFLCewA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=0+9PUGqbaRn9zMe5jATArZOPJPjoi0ukRVI0tRimJfM=; b=JV8E0KLJC2cSVG+p3BV2Ku5YrSH4n58ZUjNOpbHJME2ngl5m2etEYItEzYwf9G3FsZG38pFH+gf1xTqiCDlFFqPkfF9QDHo6VcxzQWi8Xgnao5OfwnuK0bQKxtvhqOlmNPh5OGFx0h6P7Wo9pGKg2M+fEfp53/YrPf2V60TOLjhfGNnW5M4tEdiIcNA64BsuWLfqBgTtRkmu6p1vT7FNR/jIkI610jSBrl5iw9x6KUYVziDqFVUeQfNR2nEPqquYk+Ym3/3m3RhCOyBi9Ica0yX5E0Hj/Y9IIvDEDFVjmTdw+k5j697axXnsEAOYQyBg+IY6RK6P+fqH7AP8YB3RhQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:46:47 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:47 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 17/43] wifi: nxpwifi: add decl.h Date: Fri, 9 Aug 2024 17:45:07 +0800 Message-Id: <20240809094533.1660-18-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: c37f16b2-f20a-49eb-0c5c-08dcb8582f45 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: BjWGqmRi3nheJPT1L5LRzgYpDgSqsjOtYygViRzPTENVxElMkwHlQyTVqDqZJhbZ6cSZm738sSRmU62dBc4zJCnwaNeV52/ISz8vDVBa5SjNV4/Z6V5aEnrVaLCoCTUqzUTBML9CixFujV9zSt2shQMd7MGUH7vRIUVk8sMWagHSwuulKTQWlDOqVcRVx0b8RHF6joEZBJayrHJHSgBsn8b3OrcXZnHPOf8iL+c+S8169tU2g63c4CvUFnonr1CliUCv+aOgdrQZEjFZPD9icZayU3OBYbuSrmH3tFZXLXEAOwsN6jn3oHUylgspe8sZNND7yzG1hEd/rbWpDw797REun67fPY3Pstq3rIufGz5FT65gd9h+6Jnd5savGpah3d9/ykeiwNZ384cdRJyyT91eSaFgPshRYo8TA1YBf1c/t2FncGVyuq4LKiN+qKdxTK+dZcyabUDnGzbqd0T47iCB0d4iQNa4bJrnS+OYjYwwGktWAeg3UVCbyDAqeXMs7TGBIl5Sw55AqLqUf5i4eRo+Ov5vTK/vRZFCY13T/cbDemL9PwqWxtjmIygr9qOwCc5uRaV/NJxnmy9im2BEjzHb/6PdMeGvwRyD40+opw51kt8w5l0QGtKQPQSsl4kFv83z5ZBrrABk1zliVIypf467cQqhJf5vJ3ySJhUCn/Gunm8zdcBPzR3bPnL9ra4lRUENt1d6YNi/o/27dr3Vl9uVkpBI0PP4IvxsiuqN3yDsGlal53o7n+gRO8KgYpIzqx40Cwi+cREWVOUgRLbFcZz1i0bjqmA/Be7luTMLg9b4jR37nqumddBYFx4bMixuHgVmUrS6tQQSQajjewCAwEHibk5O5pgbssEMQSX9z9tkrG97aD5xlHVhD9hK3QEV44MHgsRlwHmjTnoT3Mw4cUNbPhe9WOp2dORkwp5izrN5gUbziy/4bHq4x2WGTKAVVn3xqMwiw6t9pYWyHO6zhevADD8XyeWWVn8qjY2SQbMrVKF1kazNcBR5VGaZD/yjwhBx7LAl1z//8Q7Cl0OkkmT2JcRnCYk2vrbGJO4boVdGFD6yrueWKnYleKnT9btrjkrVpWDZEpZpu5LQINDrHL1TP/HqR541iiTM71ccS+ZwdMnzMCXsOdFWeiVJS/WvO3wtLX4n/qeRLUFQUTZ2BHF3OwDbnGieARL6JmUCmqVqgRJvZNCLRLP87/ZU8YngeHOoZEKMSCeSN6ht+UqAz3UlMj0uLIZvVSjhT0e1L1lRHJ6vjFMUyjj+a/6DRbKLI728Bripj7zMvIom68Xo3aCIR4UH5WG6qbvun6idZMaknBUFWwoMBdYTqoyZCOrczaejqnlxkS+2TZHUnICjVw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: z2UmRLwNd/7P4/qvFkiDzUFmXo6cNmWCzglgKhUKqGqtv1V1RcMF6vEcIzEmP70aS2tZ9grYWzAdTh2y9uf0gryi8ZjI2OHAK+sbwADaxVxlpbZkQAHDCkC8QS1jRMFSxgimTAnVWLGmzB6gkDIzIvZL15ysrK0kbzq5SgYWfFTgpp7dbpej8RvxfKDovF+bsYvULsaudD6cBIHFf8J3QStU8YRFqvQFho1l8VH5pASFcBIJDzLL4cxjyMQUG3IYDlihhrtC6UYu0/2Ifn4SMH0AYe1GjMn37+09XqPG3KrTIZO2eGRkbQcW6/ehq32FYSzv7pUKThz49ydgOKezqzjeUOuLAxuD+SqqOvpT4eg5xNDTeLPotMZOCqOoMxI8TAEZP3chcPUYObGkk3X20zoCO4NlxdwA5FYiuD27NBcznr6UYbaGUDzcM2mWlZ/qRzXRp/2RDBV0CsdtdfWo+fITgwid6yvTOSLaF4DIzk1fViN2Zrp0TAmy/RYuk83xfd8mCWR/yVBzsrIFw+tsaIReNFyjpml9o6lAWG9DnAbZkks0RpTu0Fqnw+0N20S/K9r/f1WlzGv5I99yfbEK0+L9q09SyX2CzRhoGFplWZDmc9LMvw4CZgmTEmeJ4HKqI09ZhEiaEQQx1bptyBLQZfCoE5eG1DcIWS/AZ+9Qm5XUGZETNoPW/hyCiavqXqkWiqsHx3vgJUDcEKnkUw70pG5xzmF8KLxxneGu0drh7oYGTi/I404AeHg7E6E99aeqqTZZ5/U7aY8ej1Nf9Nb3ypuGhYbSqshsZTyAIrtTVuaP7NvrEdaCdvsO9kawVyX6vsUPgkxnzNpJgKhhBd0NBvk+7Ab/D5ilYkLXZTkuo6b2qdFvFPhMhgba3PulVfc44oQ7IGg9ru2Q+XATKFD9BvcvIEQPCBdR3gLi0FBxTalFPp01ZaSAI2AQJu+bbJFWCs+KAcnx3JeVjGSF3Klc4ZQz4G1t7qudnU3ypdPdfGMTqrmokFcjNNos9+gWO1lmV7L5Y4GNQIv5LRcQj6hy11za8X5nCtXpGcVZPmNhwtBImM7LCMVVkvTleuQookQBSgcO9StmU9Faa7gumkPgq9ZHB0QM4t7PX0PqEoJBs4q5wtyXAOExko/c0BaDOzVg4AcGXncM4APOdj2iXFEVGhiggULykxzbe6AyJvhBF67m/zIyL8ud+NX/hPXZJjbxWATLuizJD+B856SgEgbRK42cPnoxCoKn+saCV3epxLQay4rkCNFV4gOOIigbgV3zPcQ1hW0JSa0AOoEbUQqhNjzEXoVGGXDiHQYgMXB09OxWyYLwUsk0jCsuxN/Q8FZKKdFSYPZcKeKUCVrv9aEgiHWjdqjAw72kn1EK6aRl91L/YK5d6ncopZ5JY2P0ukH8usBVxp+ZkQzzd1b93NK/HYDdONUD97Y7olV4GgOIBeKDJ/GcLuktqsNI/ZWuqgb4+Wm1CGqDHHNeEox+3INYdCKpyrD42x/TcFqcL+W5SPLNGK1CPST5qLYP9tU+9sgquMg8/B48JxE/MxfrYRkak8me/4LkelwcyLpAd18Ms5+Eyc9XIt+E67ZZMTCA5u2O2ZsjUcEcfjPg6QX+Ie6X6kiWKgVB0ckHRVoqT76I8ygpLUxJDz48EDhVo1LbfrT4 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: c37f16b2-f20a-49eb-0c5c-08dcb8582f45 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:47.1008 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: mmQI055HW92zTc1nxgN4H95ey6zQ7tSOxU89iRLv+Mfk3lezhWXp465lxGxpHKQpda9s1kNKhH8pP+tH2zm+ug== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/decl.h | 294 ++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/decl.h diff --git a/drivers/net/wireless/nxp/nxpwifi/decl.h b/drivers/net/wireless/nxp/nxpwifi/decl.h new file mode 100644 index 000000000000..930f777f064f --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/decl.h @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: generic data structures and APIs + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_DECL_H_ +#define _NXPWIFI_DECL_H_ + +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#define NXPWIFI_BSS_COEX_COUNT 2 +#define NXPWIFI_MAX_BSS_NUM (2) + +#define NXPWIFI_MAX_CSA_COUNTERS 5 + +#define NXPWIFI_DMA_ALIGN_SZ 64 +#define NXPWIFI_RX_HEADROOM 64 +#define MAX_TXPD_SZ 32 +#define INTF_HDR_ALIGN 4 +/* special FW 4 address management header */ +#define NXPWIFI_MIN_DATA_HEADER_LEN (NXPWIFI_DMA_ALIGN_SZ + INTF_HDR_ALIGN + \ + MAX_TXPD_SZ) + +#define NXPWIFI_MGMT_FRAME_HEADER_SIZE 8 /* sizeof(pkt_type) + * + sizeof(tx_control) + */ + +#define FRMCTL_LEN 2 +#define DURATION_LEN 2 +#define SEQCTL_LEN 2 +#define NXPWIFI_MGMT_HEADER_LEN (FRMCTL_LEN + FRMCTL_LEN + ETH_ALEN + \ + ETH_ALEN + ETH_ALEN + SEQCTL_LEN + ETH_ALEN) + +#define AUTH_ALG_LEN 2 +#define AUTH_TRANSACTION_LEN 2 +#define AUTH_STATUS_LEN 2 +#define NXPWIFI_AUTH_BODY_LEN (AUTH_ALG_LEN + AUTH_TRANSACTION_LEN + \ + AUTH_STATUS_LEN) + +#define HOST_MLME_AUTH_PENDING BIT(0) +#define HOST_MLME_AUTH_DONE BIT(1) + +#define HOST_MLME_MGMT_MASK (BIT(IEEE80211_STYPE_AUTH >> 4) | \ + BIT(IEEE80211_STYPE_DEAUTH >> 4) | \ + BIT(IEEE80211_STYPE_DISASSOC >> 4)) + +#define AUTH_TX_DEFAULT_WAIT_TIME 2400 + +#define WLAN_AUTH_NONE 0xFFFF + +#define NXPWIFI_MAX_TX_BASTREAM_SUPPORTED 2 +#define NXPWIFI_MAX_RX_BASTREAM_SUPPORTED 16 + +#define NXPWIFI_STA_AMPDU_DEF_TXWINSIZE 64 +#define NXPWIFI_STA_AMPDU_DEF_RXWINSIZE 64 +#define NXPWIFI_STA_COEX_AMPDU_DEF_RXWINSIZE 16 + +#define NXPWIFI_UAP_AMPDU_DEF_TXWINSIZE 32 + +#define NXPWIFI_UAP_COEX_AMPDU_DEF_RXWINSIZE 16 + +#define NXPWIFI_UAP_AMPDU_DEF_RXWINSIZE 16 +#define NXPWIFI_11AC_STA_AMPDU_DEF_TXWINSIZE 64 +#define NXPWIFI_11AC_STA_AMPDU_DEF_RXWINSIZE 64 +#define NXPWIFI_11AC_UAP_AMPDU_DEF_TXWINSIZE 64 +#define NXPWIFI_11AC_UAP_AMPDU_DEF_RXWINSIZE 64 + +#define NXPWIFI_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff + +#define NXPWIFI_RATE_BITMAP_MCS0 32 + +#define NXPWIFI_RX_DATA_BUF_SIZE (4 * 1024) +#define NXPWIFI_RX_CMD_BUF_SIZE (2 * 1024) + +#define MAX_BEACON_PERIOD (4000) +#define MIN_BEACON_PERIOD (50) +#define MAX_DTIM_PERIOD (100) +#define MIN_DTIM_PERIOD (1) + +#define NXPWIFI_RTS_MIN_VALUE (0) +#define NXPWIFI_RTS_MAX_VALUE (2347) +#define NXPWIFI_FRAG_MIN_VALUE (256) +#define NXPWIFI_FRAG_MAX_VALUE (2346) +#define NXPWIFI_WMM_VERSION 0x01 +#define NXPWIFI_WMM_SUBTYPE 0x01 + +#define NXPWIFI_RETRY_LIMIT 14 +#define NXPWIFI_SDIO_BLOCK_SIZE 256 + +#define NXPWIFI_BUF_FLAG_REQUEUED_PKT BIT(0) +#define NXPWIFI_BUF_FLAG_BRIDGED_PKT BIT(1) +#define NXPWIFI_BUF_FLAG_EAPOL_TX_STATUS BIT(3) +#define NXPWIFI_BUF_FLAG_ACTION_TX_STATUS BIT(4) +#define NXPWIFI_BUF_FLAG_AGGR_PKT BIT(5) + +#define NXPWIFI_BRIDGED_PKTS_THR_HIGH 1024 +#define NXPWIFI_BRIDGED_PKTS_THR_LOW 128 + +/* 54M rates, index from 0 to 11 */ +#define NXPWIFI_RATE_INDEX_MCS0 12 +/* 12-27=MCS0-15(BW20) */ +#define NXPWIFI_BW20_MCS_NUM 15 + +/* Rate index for OFDM 0 */ +#define NXPWIFI_RATE_INDEX_OFDM0 4 + +#define NXPWIFI_MAX_STA_NUM 3 +#define NXPWIFI_MAX_UAP_NUM 3 + +#define NXPWIFI_A_BAND_START_FREQ 5000 + +/* SDIO Aggr data packet special info */ +#define SDIO_MAX_AGGR_BUF_SIZE (256 * 255) +#define BLOCK_NUMBER_OFFSET 15 +#define SDIO_HEADER_OFFSET 28 + +#define NXPWIFI_SIZE_4K 0x4000 + +enum nxpwifi_bss_type { + NXPWIFI_BSS_TYPE_STA = 0, + NXPWIFI_BSS_TYPE_UAP = 1, + NXPWIFI_BSS_TYPE_ANY = 0xff, +}; + +enum nxpwifi_bss_role { + NXPWIFI_BSS_ROLE_STA = 0, + NXPWIFI_BSS_ROLE_UAP = 1, + NXPWIFI_BSS_ROLE_ANY = 0xff, +}; + +#define BSS_ROLE_BIT_MASK BIT(0) + +#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK) + +enum nxpwifi_data_frame_type { + NXPWIFI_DATA_FRAME_TYPE_ETH_II = 0, + NXPWIFI_DATA_FRAME_TYPE_802_11, +}; + +struct nxpwifi_fw_image { + u8 *helper_buf; + u32 helper_len; + u8 *fw_buf; + u32 fw_len; +}; + +struct nxpwifi_802_11_ssid { + u32 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +}; + +struct nxpwifi_wait_queue { + wait_queue_head_t wait; + int status; +}; + +struct nxpwifi_rxinfo { + struct sk_buff *parent; + u8 bss_num; + u8 bss_type; + u8 use_count; + u8 buf_type; + u16 pkt_len; +}; + +struct nxpwifi_txinfo { + u8 flags; + u8 bss_num; + u8 bss_type; + u8 aggr_num; + u32 pkt_len; + u8 ack_frame_id; + u64 cookie; +}; + +enum nxpwifi_wmm_ac_e { + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VO +} __packed; + +struct nxpwifi_types_wmm_info { + u8 oui[4]; + u8 subtype; + u8 version; + u8 qos_info; + u8 reserved; + struct ieee80211_wmm_ac_param ac[IEEE80211_NUM_ACS]; +} __packed; + +struct nxpwifi_arp_eth_header { + struct arphdr hdr; + u8 ar_sha[ETH_ALEN]; + u8 ar_sip[4]; + u8 ar_tha[ETH_ALEN]; + u8 ar_tip[4]; +} __packed; + +struct nxpwifi_chan_stats { + u8 chan_num; + u8 bandcfg; + u8 flags; + s8 noise; + u16 total_bss; + u16 cca_scan_dur; + u16 cca_busy_dur; +} __packed; + +#define NXPWIFI_HIST_MAX_SAMPLES 1048576 +#define NXPWIFI_MAX_RX_RATES 44 +#define NXPWIFI_MAX_AC_RX_RATES 74 +#define NXPWIFI_MAX_SNR 256 +#define NXPWIFI_MAX_NOISE_FLR 256 +#define NXPWIFI_MAX_SIG_STRENGTH 256 + +struct nxpwifi_histogram_data { + atomic_t rx_rate[NXPWIFI_MAX_AC_RX_RATES]; + atomic_t snr[NXPWIFI_MAX_SNR]; + atomic_t noise_flr[NXPWIFI_MAX_NOISE_FLR]; + atomic_t sig_str[NXPWIFI_MAX_SIG_STRENGTH]; + atomic_t num_samples; +}; + +struct nxpwifi_iface_comb { + u8 sta_intf; + u8 uap_intf; +}; + +struct nxpwifi_radar_params { + struct cfg80211_chan_def *chandef; + u32 cac_time_ms; +} __packed; + +struct nxpwifi_11h_intf_state { + bool is_11h_enabled; + bool is_11h_active; +} __packed; + +#define NXPWIFI_FW_DUMP_IDX 0xff +#define NXPWIFI_FW_DUMP_MAX_MEMSIZE 0x160000 +#define NXPWIFI_DRV_INFO_IDX 20 +#define FW_DUMP_MAX_NAME_LEN 8 +#define FW_DUMP_HOST_READY 0xEE +#define FW_DUMP_DONE 0xFF +#define FW_DUMP_READ_DONE 0xFE + +struct memory_type_mapping { + u8 mem_name[FW_DUMP_MAX_NAME_LEN]; + u8 *mem_ptr; + u32 mem_size; + u8 done_flag; +}; + +enum rdwr_status { + RDWR_STATUS_SUCCESS = 0, + RDWR_STATUS_FAILURE = 1, + RDWR_STATUS_DONE = 2 +}; + +enum nxpwifi_chan_band { + BAND_2GHZ = 0, + BAND_5GHZ, + BAND_6GHZ, + BAND_4GHZ, +}; + +enum nxpwifi_chan_width { + CHAN_BW_20MHZ = 0, + CHAN_BW_10MHZ, + CHAN_BW_40MHZ, + CHAN_BW_80MHZ, + CHAN_BW_8080MHZ, + CHAN_BW_160MHZ, + CHAN_BW_5MHZ, +}; + +enum nxpwifi_chan_offset { + SEC_CHAN_NONE = 0, + SEC_CHAN_ABOVE = 1, + SEC_CHAN_5MHZ = 2, + SEC_CHAN_BELOW = 3 +}; + +#endif /* !_NXPWIFI_DECL_H_ */ From patchwork Fri Aug 9 09:45:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818390 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8355E197A9F; Fri, 9 Aug 2024 09:46:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196820; cv=fail; b=Yi6n1n3MU8FZrwqm5H1eMONAXNIY3UPgoYD92Io5OM3xkF6QRZQ0LeV0BsD6WtDJ6Tj5f2JqQyS3IVAKSJU2iCEbWXYJTKf1WPwbHrdArsohcI/G1XXRWe6TTr7O8skK01T1ao1VbF7H/+Moqyp4dU3AcvpvHXxmaoe3QQQzPj0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196820; c=relaxed/simple; bh=iPW7EHV4dQiVydUK5ulmopwJMF61KcLFxV9VKtsRCjA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=LCqCfLgGW0ASUaPVzoFt3DELHoyYzbzXRJDLMta7fChWSb550HC7VhqqBsGls+eW0eBNOd9XL0RILt6hOvaC81htpH/hKM6O2JjAKqiCUy6HTZJLOvVobCSP8JOtRHio+HDRGgIE7sDSpwyZssvEmCOsQ7OPK6ahzQS92H7psHY= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=T/hmNLA2; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="T/hmNLA2" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=HyA+qKbl4OM6JoGDokQvb/tQOB6Zm7rz/iUbuWtSv6KlS9CAEX/eruP1sdJhzyvRXL3ZvBmaNvgZrscNu7pF6iTaAHnOiBTth12tzK8V+MGwJJF/Z+muw0nTjSIPdOeK4sBaqBSNBq+6eFuyjF6taPvERa0rR+ls5KV1eIf2oajZEiqN0oS4OzHuEfxLXjlXYtZp3OMnTHJrpVt8Wv2G1d4vjvgh9ah+NyWA0MXH+4imZwisc6iVS824bTQQLDI2MIssAirocF7FVoLpa47p3gbcq45Wkc+/XMHwi8ngbtSuc2Vi6M9psM7nSlIjr1C6CCdlnr+Q+LfTWTo2h8svtA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Kp/RnIW8RGclZufIVPDrZzne5U+G9qMYZazV6y6yN1o=; b=GTPphNxh/GXjDOWevUPlv9rUNwX/UFtOqV/YMAbCrVrpqFbQym5y/PfTY1f7y+4OpIVJ/Y9P1SMr8zNyiySRxvfX/dDqziRtvsfxSUCGq6MhhR+l9vunXyyS/aC/wqxSXyou/EoBvppEYX8dDZ1xnLq+bKQ6Dgyks9REVo/jqpcXqsrmKxTVTkTn7Gm+uI9b2AICCMGUSMhA37hOH7Eb0Bjmd7PesHGg3YF/nfgBcvQ8ie7jIjB7OV7I8vvsFphK6DhhZuakIOOXVDoiIuOtJcl27ahBjMFOEJwtNfEr9uNwPcS9yFXSZ7DoeONR+jSODP9hvDQQLqf5v2/MhvYElw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Kp/RnIW8RGclZufIVPDrZzne5U+G9qMYZazV6y6yN1o=; b=T/hmNLA2VdEnKJROxaPm7cLClIHcdKQbd1nWN/L0xBNMWOKd8332v23ve1tHU63tZzlYsAtKz/4RWaV+dmBvwHlVfdqXPZBdS9HLb8vTE2gZwbuUU8vAEzJOmYPSIE/Mvi4lY+7/PWpyBDVCl4UhoaloUHjfWuixWwjNP1ly/mueZ7F3c1HyxBH14nv+NoAaWyj5NligNu2Hy4PxUR3Dm9IHTJjYlVbsTsGTb1I3MumqFCYUfjU33A3VHT2AA6cHUZgiD1886w9SJCWK3MTUXz/da8QJ9lrd+vjHuEJSVvzm3jHSd7Bsz58qyxO2pye4/vAhPF4msLBcnlR8vXXRSg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:46:50 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:50 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 18/43] wifi: nxpwifi: add ethtool.c Date: Fri, 9 Aug 2024 17:45:08 +0800 Message-Id: <20240809094533.1660-19-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: 6311fd95-07d1-45f9-76f8-08dcb858311e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: YYBA6ZwFrWZ3LsfEcFHyMBYniIfMSGQghhhuVP3KTbs+zsi7G1I/yipCxGTfmegnmUhERjnd7hxG2XG07ntWz8tupFJTNeqdjt//MlobxqiBeyG80b/NNCIPRBrl2SLJsGrEjJWcS3C8RyChjNEXfEWwXunhdkI6fZXBESIgGmM2zW5GneQ08HGS2tlH4/opwLOiMMvu0o7en2dtHgaxCZyrn8BZRjZZUn5Hx1CUWhIGVisI+9MAJGvGSdNqlChiRvm6nBUXOOVhgoD0Rx2n+C/WUHfjhMPk/rjbAyYBg81FmyBgkmTOTbKlZTVaW/X/zwzWsQ8gbdEiwWixn84QgqKK1uIlGr9viAqsINPE6DrBNulaMjmla+J3vCcjuSBL3jjK/R5SWymGWjFYx5r4ehUUtpyiNEVTZGLSr+mW47PnRDwH0RO6MbYulQoxfGI+27rRz/lkZ6QCBEG4YtTwyaQsDfuHxdOkXWrxlDhCpPqKlmmcvLnU1NrkA3umgLy6KfevR9khxwRYYLePxFT9kXwoh6/epozmScckd9vLsbPl2mGUEtbI2FewVaHWaD8nM8Oiju8yYXJazl5ehq9MJ38BQjfA847ofPaWCDrvx0AEP6HvO5g/SBExTBoah4Y6vAxElEAzY8365WtVWwM4uafH19PxRDyE817Aesvi3WErcDQ3XgRv+i62npw+iHmh9KjNuDtCkkUdAb+NIXhBEKWkk0CdY7Lh7J3x7IY8z7Q4bciI+0LlFbbNS26ze2LW8Ttcbfspy+j5cC6N+mE+gWo4Sc51uA3UE95OOVaLYnk2k9Hee94cwk83WtUhdLfEbEttRQHmHr4x94SOMvt6TV7FalHfebLMw/uEdbz2RsiN4wa7VMV1puVyBPBfwifGw4eu2MYxF5LgJ9mYKZ7sS42cY81rz/wHjflAKpy1tyTlUyIjL8LrUn4PGsUiAsUBUM7Eb4HAnFPSTLIDP3/V2fWiwPAAPQ/eMAA8pfIhleRZQPJ8WTUqt4oqyxQGUBFPRANXaCeoairshOy9AkulAx9j+dHeY57LAOn6FwL1+EbrLKnVWDBMEDIaD0U34kcjkWkPxT/FJioI9TpeOx+6WAmwLTOHQLThIYiwQnCMaLTVV0XJZntdeOzuwy+JLPQ96vbBpfFH75qfLbhYuL8RUgh/g+e6Drq2tgp5YELe22jKF+CrvDRqEm6PcmwCjEtGuEgQ54kZEavjyNVewVridBLwxtzLrXuAAhoN+RUO6Cs/WlIpAPwJQ5eC+LFm2lfWnGG3iZFXJnkuOxDWMy6mT4G+6fAmMduAhgs4N4rQ0utcSCe33KjLRdcgwlv0LHcTq4d7s8ezIVHAdl3/BwLnIw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: +3OlpeWA0FDIf3rdAcc97iZ1wcsJAV9IS4v6Tfujl39m2jsP33Jyu1DBX/Cf03KPtcJCv58Un60qTyuo4X+uUfwTWEVY6OEZ9PIoMcDtmaUkF1BOwNP8E/Y86okvyjXrfPR9G+sdh2YnB1f5aIZ7ot1GK1QX7dab6WUpyL61GZzt1XEhQrr7P/t3qhW53FvAEBUmjM1SO45/8YrqcPd07nb/v6OiqGH4Sf/EbRJ9iMC09T46NiiBie9v93VUAar2Ux8NtkQeW7kZXqOD+MOZAhOTeWS4Ps9st94Gv3pwMsDWGPE91ifUmDivhJCg6rA0YESny+ORmsrdMDE/bco4lzHAfRnwsHI08XmffVNeUXdlGMWKvzRJy6x98ZIHGF+eTQWsGzird1VFlgiLIs+UQ/R5rxRlDP0eSA4bTTsJlYx3WiVIV6AX0NA9yUXK4swajieqHkSj4te27jzvUnkzdw83R4M5VWkS/T1x7Xyjx+NR622hNy9BqVwIsJhoXeSpOkFO5HxMI71fJRwhtb2kqsKAQ7krp8g5uSqEJPtAMuXIa9TugewBEla02wyPSbWp/dIt5+yz+6m+dZVVroihO/JHrACR8ekSBH5aiy489ZQE7uudmN9ljZrIzvv025ibWa1VhvtJgnR+5trac7KUGa2OojJoK+mNmvwY9saTRoq8fPxG3AbfZXW29iShVu9pljWmWqfsAJUmnYBPpd/PfOJpxFoTPSjUMVB1TMW3baBDWU5o+2OM9lZ4vuAGPKJvgef3i4czon8bWGrw9umo664ReVbzm7BE7mQohS7YLX2o4aKGUeCdcV6xt58rnrnPfdiXuOAf8fSJvf5NFsvlrg5nbpTKznCCDDXDPIl0hc6l5W9alC3r1WjAn00kHrqT34F1fXMcfXSAlUfCMkNpULZn3sW+DA2rGsjcg9sBVaU8SRYhrnxOYdvUTy6Ubj65PYCwBY6TOFGZ7ed95eEeqmxplaafXF0V8F0xAlX1GCO1bmarg3r42SxwqKszPMQzkbhxT7fbS/EuFT+ty3nsRAw2aJF2bHFt4mjzt0Dd6+u0LEKX/sHkjsdgBQgSe2QBUQZoaafB6v8EsHnx5Gqej9OgYTlY4D9syKC/OSJJK40G9No8Ugj4pxsrQSQXZo/2qxsJvUQJudbqmK65yElheEFhj49CP3w73o/bMpg9BEUF6wqZ1c2CNCNwlvaqxSqRzfcTrcNs+vqrhb4T8e7MA0qf+yj6pVTNv8T8pZk9JMgF/XKXDPz6wjcXsomzl/DH7+6DgBwgB0K9OC6IzNUbOImONgipJ2uplCyBmebx+nFGNjmCJSNt1iYyU599mmXq588Qi3xLVOExjC7HI1C7DxMsEiRdTzG5cgFQwTaIAFO5ng7itJx/wRdf9Fje+r0pRFIkg2eZ98blDum3iHDNckh12nS4aLQHwiuqkbIeDj8o5Z0UYADjrHl5h2QTR4vUC7zwuyuxMenScvB30/vVCCNoNuY+qoMDp0t1xJCgBjERp6ZtnYYz4SikMcwH9YrfoO+dkPvP9PtG9E/BtaymOvnepjWAXHpRewH48nonyDAURkrK1lb5sT78kqtDfJL/Eweu7hnnlRFpRPKj4/5whdIhXesyLWsT8GJsi4lEJZt/fwaoCh514/YBbK13FvS8 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 6311fd95-07d1-45f9-76f8-08dcb858311e X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:50.1682 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Hy4jXdfSqiqY8CjPJMSsmTS2IEEtKT276UrQOb9V7r6hBFDD+sFZcZw44ena4ZCTzhbPqDc58+5YdT6VkEGevQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/ethtool.c | 58 ++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/ethtool.c diff --git a/drivers/net/wireless/nxp/nxpwifi/ethtool.c b/drivers/net/wireless/nxp/nxpwifi/ethtool.c new file mode 100644 index 000000000000..6cefa6e6f5b3 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/ethtool.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: ethtool + * + * Copyright 2011-2024 NXP + */ + +#include "main.h" + +static void nxpwifi_ethtool_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + u32 conditions = le32_to_cpu(priv->adapter->hs_cfg.conditions); + + wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_PHY; + + if (conditions == HS_CFG_COND_DEF) + return; + + if (conditions & HS_CFG_COND_UNICAST_DATA) + wol->wolopts |= WAKE_UCAST; + if (conditions & HS_CFG_COND_MULTICAST_DATA) + wol->wolopts |= WAKE_MCAST; + if (conditions & HS_CFG_COND_BROADCAST_DATA) + wol->wolopts |= WAKE_BCAST; + if (conditions & HS_CFG_COND_MAC_EVENT) + wol->wolopts |= WAKE_PHY; +} + +static int nxpwifi_ethtool_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + u32 conditions = 0; + + if (wol->wolopts & ~(WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_PHY)) + return -EOPNOTSUPP; + + if (wol->wolopts & WAKE_UCAST) + conditions |= HS_CFG_COND_UNICAST_DATA; + if (wol->wolopts & WAKE_MCAST) + conditions |= HS_CFG_COND_MULTICAST_DATA; + if (wol->wolopts & WAKE_BCAST) + conditions |= HS_CFG_COND_BROADCAST_DATA; + if (wol->wolopts & WAKE_PHY) + conditions |= HS_CFG_COND_MAC_EVENT; + if (wol->wolopts == 0) + conditions |= HS_CFG_COND_DEF; + priv->adapter->hs_cfg.conditions = cpu_to_le32(conditions); + + return 0; +} + +const struct ethtool_ops nxpwifi_ethtool_ops = { + .get_wol = nxpwifi_ethtool_get_wol, + .set_wol = nxpwifi_ethtool_set_wol, +}; From patchwork Fri Aug 9 09:45:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818275 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 99FA119884B; Fri, 9 Aug 2024 09:47:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196824; cv=fail; b=U89Or+j104lyyiXqrzMM/zz9nOhpV/TN2X3iXwb467nVNVs+PMafwbXLnrZvIZ/egi1/9UApYgeNXLyaJqPyZ5L2nvt8DUcGWMigwXccoqCXlKpZR9Q79Jva3h6CH2SaMt4O4Wv5qbUcHpjpIILoF0n3LrJ3xIoFWc46/7waroI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196824; c=relaxed/simple; bh=v+F2pLrCwK5EGVDolUE0zv9WoBEvaARFWs0gxLvtaIo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=PUtthq1i08LAv6LYrqMzBZfCMhhIILn1k1lo3iYkTbd8zkpaTRU8hIgxZhG+dz0lri6qZt+tLIUEVh4Y0NylCdfINV0bmVTJnyqhGKH0gcjWnaKK4ohuQsBt4gkowYhJoVr5PQZwM9CYPtKW3TtSYXM3L7kQq7HCrqL0EwYd8c8= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=nPXomsdk; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="nPXomsdk" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Y1Yy1UKOpoKu6ScF5ERNeyqX5rNVNkHcmVxDpf8HQkoHTixfFiaEzh30sMN+s8+lGD33U3q78dEsYN7RKY48kbi0JQBff06rs29+OONSSJ4yXtsNvKKTG4W+761ThxqQQJIB8m8z+x6tnB0stN+gUmTuYtx1UTns3q8a8n3Po+DQAio3EpvA7BRjDJzmB3wvJVNtF585rYd2dkJ/uCCP6JUtIQ4CT38PWUmMU0Xs5XQwDNOeYN+vkrKoDsjkvzs7XA4EGAMCgO5Oxa+Fs70WmAhI6i6oK+a5QD+4p54X64Cc0ut9Z/uFZHEPwj3fIl2rhI7TbujMRo8EFOPkPtOGLA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=VRNYumgjhs9hspnO5aZmcVnKf/zEpc3qh4VleNSTR6A=; b=Hi8gK27xLd98Ar4UDEKzq95hvFQ/+yhaV1wcpiTZVOiLEdOIfnBeC5+lVF4A6UyeNNU5hQTSFW2mDuaws9M7WXZ8PjXbtc/wXA/omu84LilKodYbg7B1o1UI4t5rbWtt4me73/7mE1vmycjKm/TQu29ic1Vw34l3lTWJA9gyYIXT9irJJmlCi3sJ/sStP+ks8q0tLthXjKeLpC1ZJCbQpiyu5XJAi/evtC6Aapbnj5MVkbDp0400lyDe2eraQkuIA5tYzasFu2qltS7iD/STHtIs6nPHFrN2Vw2cag0RGP9vPkXGqR+K6eEgbFwVYvx9izeSfxe+280y6uGpFuzepg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=VRNYumgjhs9hspnO5aZmcVnKf/zEpc3qh4VleNSTR6A=; b=nPXomsdkci7SqfPbrFgLauPvFEfLEkKar3v3yQPFRzsKtSqKyCAe6pcVyZDmXVJYU04si5hTl29JAFDDUwI+8eoM7hqqnRtkv8ZFswkGegf90XYKTVrJ6lNSv/nd1lZ27uxSMtapzTsIkLFGxxjOy4Gw6aGQCngfAnaZiveNovOR2MPZM1c1Ybwkx32v204nelQmLeIzsIfnoxsMjuudCwkAP6OkdrJgzaiCmU1QiJyc80vn/bEMylY5h9I/leTSZbN4aAiJT0Mn4lmo04vKjy0rSk8S+15t7nwi0PShbmOMxjvPvW/HOlpPrxfB/sA5/eDzbRAkGkBdSctles0sVg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:46:53 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:53 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 19/43] wifi: nxpwifi: add fw.h Date: Fri, 9 Aug 2024 17:45:09 +0800 Message-Id: <20240809094533.1660-20-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: e8e39864-e0ff-4176-4f4a-08dcb85832f0 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: gWfe2Lbf351qrXMs/6K9ZLwz8Yaxfss+YAZ4TgE2uj1xRFamjPhRY4FvtZ/OaxMzfQIywWwyZsLUoIh7AsIZj13YzqJg2IFdd8tyKmJPDdV3pGRvOSUdTY4sKwF68Jnt2NjC6anmm/LiH3W0VF/geoF3+UreaSU/JK2Gg4GDh5MxDa9CHYnq9VPB7mKjFF0YdA4ih5/4h4A7t0n+V5otQHI6lKThkhdYcS5ivtiCdoSWizOHHM/q8Ff+zDxUcaRG+i8yQbL5/hRCLndWEQVTV7BfG5K/XOheGavBvMAIwtP/Kt0Fm5qTTJoIqf/QtK2so5ig82k594KWoXoxXXDBz9zMrfRUWqQCXB2sZ77pN+Vv1PMC29h67nav6ciCG46WeTu9E/3a9NG3ONEsbjao/0Wbwbr4UjRrQioptMI0v4L86NQcTsucVCCtFfiih8Chpq6OsYai2AmZtXYRImqweLdytetrVu9vnHhX4TbgRKwjTZM6/uyFtwVDOPwGGMn0wMs6WAkLttUxogbwJU4F6R6/VNUab5v0ZFG80Wd3UpkRRRWeKLMmel9dPSb3k4Ajn+zxn2JUro5sVeW+LQsZbfA3hgE4ImeNxj4zXAquEvqtE3+4WPEbPQutMcITqH8XucmPjOfQGZboE7msfhN9FCjYZtYGYZLGfbOBKu4Y2uHKK/SK77MzmPNTSEjCgkSqNAn8F5pnIXVrbi8+8KAi8BcJn8OFHvWj9RaB7ogKdLq6wi+Yllc7/HLRH25RTZRLmFLMgKiPLhRiAY0Hn6G9KvvlBhDQIp4REzF6AAGGi1Yv56lATxoSWZUoRoX40I4tn+snC70JkJKcjzB8Cvo24mo4AE9RttcJf4aUmEuEY2wF0YSzyX2riedo1GRhK7x5FoMNm0EKB6Q3fxVTV6980KX7M29CJMeCyTKRTq6NlWAUhUJwB75SI4aF8+nAHwOAFgMpD1OlPWPAS4hNSW6XG8A7MKV9iT/zXe/vcmaNCC4CJEL+N1R5dtHIkkf5l7NBIF73/qQ3ns8lR4vF5T16ZkGZcuSB/RKnj/b8IT6RNth1n/v2Xl11XJgK+lLzYv9zkQLolW+S4P2uZUaXehxR60ks4itQVD6+2E+PX84R9ZOjD+JPNVgnCunxt/0OM+DjTmsQpp6Gx/vr8Xjb8OHbFIDHJe+rNOlfkbeasVxnlWeNjqgE3yYaJCxJCrj/sCOm/LfGMdF7BBAz/LWAjETH6mft5zYLtzh62ElImyHLS8+GiIA03pKi0oeMvtuNdzlATG1n8OR+0NPwe3efiG4qlZVHrq/cp9CnvacVWCHMdm7t0Kr4uPKilZvNMNvaxaXDXaRrevqld6bZu5ZKK8+kBA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: nKvfW3ze5JRF/vfUZwwH4GVMTat6dQKdlFl4SU1N6+cHPRCQFny3CbjzJKRR5WAHzVFu0P66+Mc5566Ic9iZ6CD/SyHumkm8PJBCEo1lnlit8gYNku1gj+Ju+ap0QJJNpRf2TEHofsKYnp4b+h4SbPl+9vON11OkuC8m1uLnsYrBBpNjbB/TvoGOf6O07ZaturFWQGZg0b6i3BI5a5lchr9KhNkhGlk7WCRKesHXSAlm3YJsHrSVsA7LuHhju0pXfdtZc8EsZlSfeh3zIfTNV5VUrt8mTN2UQPjtWyUCf6VL8U3GB/UpIBpS2RuaGOcfn9gBILHCpQPG075r9RvYBN2pdAetFZqeKNFt/ehOfdrF/N6Lewa81BHo7hSDwrth0aa8PXpuIYP3TvGZsOiZdD7GWU6+1dNZ8auYehGcfbgKzqTMPc/ZLw5g3eVP37XFomy5yDqrfP+vkGdg9IfLhVYShTApQIegGHL/g4hy+mKSpzcNzsozl8O/hYA31OMvZhS6GJKwsZqW3L+EDp3yAW+31TVSGCFVK1ftaN5Vgw3pUN5l/H8zvOvPbKn5HSRX2LLUNZyHIKqZzeDN0PWn4IA86RHXNQf/b3HNVBP//dJF3nUqq5Et7NmGFGQQO7OR3cJuVVw/SrnyTZxh2VTcHk41AMuvZkXNMfVr8OErosdClHKnTUeaKBWIRHEyLNzjCH3c7LtuebR+//I523bvThpTjWrC6UhLQ6llorLSp6ONANa9BQtFQxiKo68MX/CLiSZjTwT3rr8ekrhbgevg8yetwU+GsuGdVhdPR+UvAO8jmZNRe8Q8BiDtbXp8sQOSrJyP9kPlA7icMJPulRHjbJRF0W6nes/Y31nKgrWuvIR3Z1agQRSgXrDdcggs0Z9kdM5WaTbHuDzEmktjMcxWcc4eqNKsas2hakMgWoOC9y1jU9IhSemG/461kRnOkSeux0uNC5gTBsetnfEmtxXsVPhuSogHPb3GywvvJqnR9kuFGQGQ/Qc80NAmIFlHAvVndx98D46fBoRRymWHd08sStIkjOVHCKfnSnD4EosSw8voiZ1d76Nr3jPdIBhxEo8U3QvDYAyAnPO3Zj31PYhhl90xOPC9ZWPoFxCrEOYj8LqI17yvdwE9C3qGSllNMMhVaJ3O1lmcvDN2TSelWR/k9U3TyoTDZC/T1iS95FddqHixOMoVZmA20zNhj0H3s3p0IckVq78jrTwfUEbmxfXLsmqOr3rllRBJK/68BuU56BfrS3MkqOs5GX1S1ZtV91Id0ty9ouD5UThAb9K+f73P8kUW28IOegqoCRu6b3akotKY61rQjEMuzSv+EkQuI+3rzUV66NakUWDm2eMb3gCXflIL096S369K34daJCWu05I0vgKBlRWgRYDaIADiNSfGne6w3rL/Bvn2ezxthz8/4rxt/UrWP7PEMg71xegtNw6riTvSfwK6Wf0A+KbjnKw7W7KRUbtASfe7mN+ApWDwYYrb0Yq9+mvIBXh0jGJhHh9ipXTDBK8greSTgjm/ysEfaAsoWQSXWafnJdlb/8uj8mwv9v2gvjkQv8SV9FmmJGWhXgYVmskwkeFUIDWAP+VLMM9y+GzwV0CtC/BqJHDGDviWYNZ0mo5/RF2/7qo/6u7gVorftsjco4/f00X4BY40 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: e8e39864-e0ff-4176-4f4a-08dcb85832f0 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:53.4043 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: PpI7Ikp7Bq+HsInAUIjVNkRdXGt7pmMI8Jf67yW2UzHPBAJAjCaFGATQZv1jbZ7IAYOKw2WrjRM6BUuXUnY/3g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/fw.h | 2249 +++++++++++++++++++++++++ 1 file changed, 2249 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/fw.h diff --git a/drivers/net/wireless/nxp/nxpwifi/fw.h b/drivers/net/wireless/nxp/nxpwifi/fw.h new file mode 100644 index 000000000000..0bdf3ce16597 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/fw.h @@ -0,0 +1,2249 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: Firmware specific macros & structures + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_FW_H_ +#define _NXPWIFI_FW_H_ + +#include + +#define INTF_HEADER_LEN 4 + +struct rfc_1042_hdr { + u8 llc_dsap; + u8 llc_ssap; + u8 llc_ctrl; + u8 snap_oui[3]; + __be16 snap_type; +} __packed; + +struct rx_packet_hdr { + struct ethhdr eth803_hdr; + struct rfc_1042_hdr rfc1042_hdr; +} __packed; + +struct tx_packet_hdr { + struct ethhdr eth803_hdr; + struct rfc_1042_hdr rfc1042_hdr; +} __packed; + +struct nxpwifi_fw_header { + __le32 dnld_cmd; + __le32 base_addr; + __le32 data_length; + __le32 crc; +} __packed; + +struct nxpwifi_fw_data { + struct nxpwifi_fw_header header; + __le32 seq_num; + u8 data[]; +} __packed; + +struct nxpwifi_fw_dump_header { + __le16 seq_num; + __le16 reserved; + __le16 type; + __le16 len; +} __packed; + +#define FW_DUMP_INFO_ENDED 0x0002 + +#define NXPWIFI_FW_DNLD_CMD_1 0x1 +#define NXPWIFI_FW_DNLD_CMD_5 0x5 +#define NXPWIFI_FW_DNLD_CMD_6 0x6 +#define NXPWIFI_FW_DNLD_CMD_7 0x7 + +#define B_SUPPORTED_RATES 5 +#define G_SUPPORTED_RATES 9 +#define BG_SUPPORTED_RATES 13 +#define A_SUPPORTED_RATES 9 +#define HOSTCMD_SUPPORTED_RATES 14 +#define N_SUPPORTED_RATES 3 +#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN | \ + BAND_AN | BAND_AAC) + +#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11) | \ + BIT(13)) +#define IS_SUPPORT_MULTI_BANDS(adapter) \ + ((adapter)->fw_cap_info & FW_MULTI_BANDS_SUPPORT) + +/* bit 13: 11ac BAND_AAC + * bit 12: reserved for lab testing, will be reused for BAND_AN + * bit 11: 11n BAND_GN + * bit 10: 11a BAND_A + * bit 9: 11g BAND_G + * bit 8: 11b BAND_B + * Map these bits to band capability by right shifting 8 bits. + */ +#define GET_FW_DEFAULT_BANDS(adapter) \ + ((((adapter)->fw_cap_info & 0x2f00) >> 8) & \ + ALL_802_11_BANDS) + +#define HOST_WEP_KEY_INDEX_MASK 0x3fff + +#define KEY_INFO_ENABLED 0x01 +enum KEY_TYPE_ID { + KEY_TYPE_ID_WEP = 0, + KEY_TYPE_ID_TKIP, + KEY_TYPE_ID_AES, + KEY_TYPE_ID_WAPI, + KEY_TYPE_ID_AES_CMAC, + KEY_TYPE_ID_AES_CMAC_DEF, +}; + +#define WPA_PN_SIZE 8 +#define KEY_PARAMS_FIXED_LEN 10 +#define KEY_INDEX_MASK 0xf +#define KEY_API_VER_MAJOR_V2 2 + +#define KEY_MCAST BIT(0) +#define KEY_UNICAST BIT(1) +#define KEY_ENABLED BIT(2) +#define KEY_DEFAULT BIT(3) +#define KEY_TX_KEY BIT(4) +#define KEY_RX_KEY BIT(5) +#define KEY_IGTK BIT(10) + +#define MAX_POLL_TRIES 10000 +#define MAX_FIRMWARE_POLL_TRIES 300 + +#define FIRMWARE_READY_SDIO 0xfedc +#define FIRMWARE_READY_PCIE 0xfedcba00 + +#define NXPWIFI_COEX_MODE_TIMESHARE 0x01 +#define NXPWIFI_COEX_MODE_SPATIAL 0x82 + +enum nxpwifi_usb_ep { + NXPWIFI_USB_EP_CMD_EVENT = 1, + NXPWIFI_USB_EP_DATA = 2, + NXPWIFI_USB_EP_DATA_CH2 = 3, +}; + +enum NXPWIFI_802_11_PRIVACY_FILTER { + NXPWIFI_802_11_PRIV_FILTER_ACCEPT_ALL, + NXPWIFI_802_11_PRIV_FILTER_8021X_WEP +}; + +#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI) - (s16)(NF))) +#define CAL_RSSI(SNR, NF) ((s16)((s16)(SNR) + (s16)(NF))) + +#define UAP_BSS_PARAMS_I 0 +#define UAP_CUSTOM_IE_I 1 +#define NXPWIFI_AUTO_IDX_MASK 0xffff +#define NXPWIFI_DELETE_MASK 0x0000 +#define MGMT_MASK_ASSOC_REQ 0x01 +#define MGMT_MASK_REASSOC_REQ 0x04 +#define MGMT_MASK_ASSOC_RESP 0x02 +#define MGMT_MASK_REASSOC_RESP 0x08 +#define MGMT_MASK_PROBE_REQ 0x10 +#define MGMT_MASK_PROBE_RESP 0x20 +#define MGMT_MASK_BEACON 0x100 + +#define TLV_TYPE_UAP_SSID 0x0000 +#define TLV_TYPE_UAP_RATES 0x0001 +#define TLV_TYPE_PWR_CONSTRAINT 0x0020 + +#define PROPRIETARY_TLV_BASE_ID 0x0100 +#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) +#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) +#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) +#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4) +#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) +#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) +#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) +#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) +#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) +#define TLV_TYPE_BGSCAN_START_LATER (PROPRIETARY_TLV_BASE_ID + 30) +#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) +#define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32) +#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35) +#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) +#define TLV_TYPE_UAP_MAC_ADDRESS (PROPRIETARY_TLV_BASE_ID + 43) +#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44) +#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45) +#define TLV_TYPE_UAP_BCAST_SSID (PROPRIETARY_TLV_BASE_ID + 48) +#define TLV_TYPE_UAP_PREAMBLE_CTL (PROPRIETARY_TLV_BASE_ID + 49) +#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51) +#define TLV_TYPE_UAP_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 57) +#define TLV_TYPE_UAP_WEP_KEY (PROPRIETARY_TLV_BASE_ID + 59) +#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60) +#define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64) +#define TLV_TYPE_UAP_AKMP (PROPRIETARY_TLV_BASE_ID + 65) +#define TLV_TYPE_UAP_FRAG_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 70) +#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) +#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) +#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) +#define TLV_TYPE_BSS_SCAN_RSP (PROPRIETARY_TLV_BASE_ID + 86) +#define TLV_TYPE_BSS_SCAN_INFO (PROPRIETARY_TLV_BASE_ID + 87) +#define TLV_TYPE_CHANRPT_11H_BASIC (PROPRIETARY_TLV_BASE_ID + 91) +#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93) +#define TLV_TYPE_ROBUST_COEX (PROPRIETARY_TLV_BASE_ID + 96) +#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104) +#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 105) +#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) +#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) +#define TLV_TYPE_UAP_PS_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 123) +#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145) +#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146) +#define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148) +#define TLV_TYPE_RXBA_SYNC (PROPRIETARY_TLV_BASE_ID + 153) +#define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) +#define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) +#define TLV_TYPE_REGION_DOMAIN_CODE (PROPRIETARY_TLV_BASE_ID + 171) +#define TLV_TYPE_REPEAT_COUNT (PROPRIETARY_TLV_BASE_ID + 176) +#define TLV_TYPE_PS_PARAMS_IN_HS (PROPRIETARY_TLV_BASE_ID + 181) +#define TLV_TYPE_MULTI_CHAN_INFO (PROPRIETARY_TLV_BASE_ID + 183) +#define TLV_TYPE_MC_GROUP_INFO (PROPRIETARY_TLV_BASE_ID + 184) +#define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197) +#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199) +#define TLV_TYPE_CHANNEL_STATS (PROPRIETARY_TLV_BASE_ID + 198) +#define TLV_BTCOEX_WL_AGGR_WINSIZE (PROPRIETARY_TLV_BASE_ID + 202) +#define TLV_BTCOEX_WL_SCANTIME (PROPRIETARY_TLV_BASE_ID + 203) +#define TLV_TYPE_BSS_MODE (PROPRIETARY_TLV_BASE_ID + 206) +#define TLV_TYPE_RANDOM_MAC (PROPRIETARY_TLV_BASE_ID + 236) +#define TLV_TYPE_CHAN_ATTR_CFG (PROPRIETARY_TLV_BASE_ID + 237) +#define TLV_TYPE_MAX_CONN (PROPRIETARY_TLV_BASE_ID + 279) +#define TLV_TYPE_HOST_MLME (PROPRIETARY_TLV_BASE_ID + 307) +#define TLV_TYPE_UAP_STA_FLAGS (PROPRIETARY_TLV_BASE_ID + 313) +#define TLV_TYPE_SAE_PWE_MODE (PROPRIETARY_TLV_BASE_ID + 339) + +#define NXPWIFI_TX_DATA_BUF_SIZE_2K 2048 + +#define SSN_MASK 0xfff0 + +#define BA_RESULT_SUCCESS 0x0 +#define BA_RESULT_TIMEOUT 0x2 + +#define IS_BASTREAM_SETUP(ptr) ((ptr)->ba_status) + +#define BA_STREAM_NOT_ALLOWED 0xff + +#define IS_11N_ENABLED(priv) ({ \ + typeof(priv) (_priv) = priv; \ + (((_priv)->adapter->config_bands & BAND_GN || \ + (_priv)->adapter->config_bands & BAND_AN) && \ + (_priv)->curr_bss_params.bss_descriptor.bcn_ht_cap && \ + !(_priv)->curr_bss_params.bss_descriptor.disable_11n); \ + }) +#define INITIATOR_BIT(del_ba_param_set) (((del_ba_param_set) &\ + BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS) + +#define NXPWIFI_TX_DATA_BUF_SIZE_4K 4096 +#define NXPWIFI_TX_DATA_BUF_SIZE_8K 8192 +#define NXPWIFI_TX_DATA_BUF_SIZE_12K 12288 + +#define ISSUPP_11NENABLED(fw_cap_info) ((fw_cap_info) & BIT(11)) +#define ISSUPP_DRCS_ENABLED(fw_cap_info) ((fw_cap_info) & BIT(15)) +#define ISSUPP_SDIO_SPA_ENABLED(fw_cap_info) ((fw_cap_info) & BIT(16)) +#define ISSUPP_RANDOM_MAC(fw_cap_info) ((fw_cap_info) & BIT(27)) +#define ISSUPP_FIRMWARE_SUPPLICANT(fw_cap_info) ((fw_cap_info) & BIT(21)) + +#define NXPWIFI_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \ + (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \ + IEEE80211_HT_CAP_SM_PS) + +#define NXPWIFI_DEF_11N_TX_BF_CAP 0x09E1E008 + +#define NXPWIFI_DEF_AMPDU IEEE80211_HT_AMPDU_PARM_FACTOR + +/* dev_cap bitmap + * BIT + * 0-16 reserved + * 17 IEEE80211_HT_CAP_SUP_WIDTH_20_40 + * 18-22 reserved + * 23 IEEE80211_HT_CAP_SGI_20 + * 24 IEEE80211_HT_CAP_SGI_40 + * 25 IEEE80211_HT_CAP_TX_STBC + * 26 IEEE80211_HT_CAP_RX_STBC + * 27-28 reserved + * 29 IEEE80211_HT_CAP_GRN_FLD + * 30-31 reserved + */ +#define ISSUPP_CHANWIDTH40(dot_11n_dev_cap) ((dot_11n_dev_cap) & BIT(17)) +#define ISSUPP_SHORTGI20(dot_11n_dev_cap) ((dot_11n_dev_cap) & BIT(23)) +#define ISSUPP_SHORTGI40(dot_11n_dev_cap) ((dot_11n_dev_cap) & BIT(24)) +#define ISSUPP_TXSTBC(dot_11n_dev_cap) ((dot_11n_dev_cap) & BIT(25)) +#define ISSUPP_RXSTBC(dot_11n_dev_cap) ((dot_11n_dev_cap) & BIT(26)) +#define ISSUPP_GREENFIELD(dot_11n_dev_cap) ((dot_11n_dev_cap) & BIT(29)) +#define ISENABLED_40MHZ_INTOLERANT(dot_11n_dev_cap) ((dot_11n_dev_cap) & BIT(8)) +#define ISSUPP_RXLDPC(dot_11n_dev_cap) ((dot_11n_dev_cap) & BIT(22)) +#define ISSUPP_BEAMFORMING(dot_11n_dev_cap) ((dot_11n_dev_cap) & BIT(30)) +#define ISALLOWED_CHANWIDTH40(ht_param) ((ht_param) & BIT(2)) +#define GETSUPP_TXBASTREAMS(dot_11n_dev_cap) (((dot_11n_dev_cap) >> 18) & 0xF) + +/* httxcfg bitmap + * 0 reserved + * 1 20/40 Mhz enable(1)/disable(0) + * 2-3 reserved + * 4 green field enable(1)/disable(0) + * 5 short GI in 20 Mhz enable(1)/disable(0) + * 6 short GI in 40 Mhz enable(1)/disable(0) + * 7-15 reserved + */ +#define NXPWIFI_FW_DEF_HTTXCFG (BIT(1) | BIT(4) | BIT(5) | BIT(6)) + +/* 11AC Tx and Rx MCS map for 1x1 mode: + * IEEE80211_VHT_MCS_SUPPORT_0_9 for stream 1 + * IEEE80211_VHT_MCS_NOT_SUPPORTED for remaining 7 streams + */ +#define NXPWIFI_11AC_MCS_MAP_1X1 0xfffefffe + +/* 11AC Tx and Rx MCS map for 2x2 mode: + * IEEE80211_VHT_MCS_SUPPORT_0_9 for stream 1 and 2 + * IEEE80211_VHT_MCS_NOT_SUPPORTED for remaining 6 streams + */ +#define NXPWIFI_11AC_MCS_MAP_2X2 0xfffafffa + +#define GET_RXMCSSUPP(dev_mcs_supported) ((dev_mcs_supported) & 0x0f) +#define SETHT_MCS32(x) (x[4] |= 1) +#define HT_STREAM_1X1 0x11 +#define HT_STREAM_2X2 0x22 + +#define SET_SECONDARYCHAN(radio_type, sec_chan) \ + ((radio_type) |= ((sec_chan) << 4)) + +#define LLC_SNAP_LEN 8 + +/* HW_SPEC fw_cap_info */ + +#define ISSUPP_11ACENABLED(fw_cap_info) ((fw_cap_info) & BIT(13)) + +#define GET_VHTCAP_CHWDSET(vht_cap_info) (((vht_cap_info) >> 2) & 0x3) +#define GET_VHTNSSMCS(mcs_mapset, nss) \ + (((mcs_mapset) >> (2 * ((nss) - 1))) & 0x3) +#define SET_VHTNSSMCS(mcs_mapset, nss, value) \ + ((mcs_mapset) |= ((value) & 0x3) << (2 * ((nss) - 1))) +#define GET_DEVTXMCSMAP(dev_mcs_map) ((dev_mcs_map) >> 16) +#define GET_DEVRXMCSMAP(dev_mcs_map) ((dev_mcs_map) & 0xFFFF) + +/* Clear SU Beanformer, MU beanformer, MU beanformee and + * sounding dimensions bits + */ +#define NXPWIFI_DEF_11AC_CAP_BF_RESET_MASK \ + (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | \ + IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE | \ + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | \ + IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK) + +#define MOD_CLASS_HR_DSSS 0x03 +#define MOD_CLASS_OFDM 0x07 +#define MOD_CLASS_HT 0x08 +#define HT_BW_20 0 +#define HT_BW_40 1 + +#define DFS_CHAN_MOVE_TIME 10000 + +#define HOST_CMD_GET_HW_SPEC 0x0003 +#define HOST_CMD_802_11_SCAN 0x0006 +#define HOST_CMD_802_11_GET_LOG 0x000b +#define HOST_CMD_MAC_MULTICAST_ADR 0x0010 +#define HOST_CMD_802_11_ASSOCIATE 0x0012 +#define HOST_CMD_802_11_SNMP_MIB 0x0016 +#define HOST_CMD_MAC_REG_ACCESS 0x0019 +#define HOST_CMD_BBP_REG_ACCESS 0x001a +#define HOST_CMD_RF_REG_ACCESS 0x001b +#define HOST_CMD_RF_TX_PWR 0x001e +#define HOST_CMD_RF_ANTENNA 0x0020 +#define HOST_CMD_802_11_DEAUTHENTICATE 0x0024 +#define HOST_CMD_MAC_CONTROL 0x0028 +#define HOST_CMD_802_11_MAC_ADDRESS 0x004D +#define HOST_CMD_802_11_EEPROM_ACCESS 0x0059 +#define HOST_CMD_802_11D_DOMAIN_INFO 0x005b +#define HOST_CMD_802_11_KEY_MATERIAL 0x005e +#define HOST_CMD_802_11_BG_SCAN_CONFIG 0x006b +#define HOST_CMD_802_11_BG_SCAN_QUERY 0x006c +#define HOST_CMD_WMM_GET_STATUS 0x0071 +#define HOST_CMD_802_11_SUBSCRIBE_EVENT 0x0075 +#define HOST_CMD_802_11_TX_RATE_QUERY 0x007f +#define HOST_CMD_MEM_ACCESS 0x0086 +#define HOST_CMD_CFG_DATA 0x008f +#define HOST_CMD_VERSION_EXT 0x0097 +#define HOST_CMD_MEF_CFG 0x009a +#define HOST_CMD_RSSI_INFO 0x00a4 +#define HOST_CMD_FUNC_INIT 0x00a9 +#define HOST_CMD_FUNC_SHUTDOWN 0x00aa +#define HOST_CMD_PMIC_REG_ACCESS 0x00ad +#define HOST_CMD_APCMD_SYS_RESET 0x00af +#define HOST_CMD_UAP_SYS_CONFIG 0x00b0 +#define HOST_CMD_UAP_BSS_START 0x00b1 +#define HOST_CMD_UAP_BSS_STOP 0x00b2 +#define HOST_CMD_APCMD_STA_LIST 0x00b3 +#define HOST_CMD_UAP_STA_DEAUTH 0x00b5 +#define HOST_CMD_11N_CFG 0x00cd +#define HOST_CMD_11N_ADDBA_REQ 0x00ce +#define HOST_CMD_11N_ADDBA_RSP 0x00cf +#define HOST_CMD_11N_DELBA 0x00d0 +#define HOST_CMD_TXPWR_CFG 0x00d1 +#define HOST_CMD_TX_RATE_CFG 0x00d6 +#define HOST_CMD_RECONFIGURE_TX_BUFF 0x00d9 +#define HOST_CMD_CHAN_REPORT_REQUEST 0x00dd +#define HOST_CMD_AMSDU_AGGR_CTRL 0x00df +#define HOST_CMD_ROBUST_COEX 0x00e0 +#define HOST_CMD_802_11_PS_MODE_ENH 0x00e4 +#define HOST_CMD_802_11_HS_CFG_ENH 0x00e5 +#define HOST_CMD_CAU_REG_ACCESS 0x00ed +#define HOST_CMD_SET_BSS_MODE 0x00f7 +#define HOST_CMD_PCIE_DESC_DETAILS 0x00fa +#define HOST_CMD_802_11_SCAN_EXT 0x0107 +#define HOST_CMD_COALESCE_CFG 0x010a +#define HOST_CMD_MGMT_FRAME_REG 0x010c +#define HOST_CMD_REMAIN_ON_CHAN 0x010d +#define HOST_CMD_GTK_REKEY_OFFLOAD_CFG 0x010f +#define HOST_CMD_11AC_CFG 0x0112 +#define HOST_CMD_HS_WAKEUP_REASON 0x0116 +#define HOST_CMD_MC_POLICY 0x0121 +#define HOST_CMD_FW_DUMP_EVENT 0x0125 +#define HOST_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 +#define HOST_CMD_STA_CONFIGURE 0x023f +#define HOST_CMD_VDLL 0x0240 +#define HOST_CMD_CHAN_REGION_CFG 0x0242 +#define HOST_CMD_PACKET_AGGR_CTRL 0x0251 +#define HOST_CMD_ADD_NEW_STATION 0x025f + +#define PROTOCOL_NO_SECURITY 0x01 +#define PROTOCOL_STATIC_WEP 0x02 +#define PROTOCOL_WPA 0x08 +#define PROTOCOL_WPA2 0x20 +#define PROTOCOL_WPA2_MIXED 0x28 +#define PROTOCOL_EAP 0x40 +#define KEY_MGMT_EAP 0x01 +#define KEY_MGMT_PSK 0x02 +#define KEY_MGMT_NONE 0x04 +#define KEY_MGMT_PSK_SHA256 0x100 +#define KEY_MGMT_OWE 0x200 +#define KEY_MGMT_SAE 0x400 +#define CIPHER_TKIP 0x04 +#define CIPHER_AES_CCMP 0x08 +#define VALID_CIPHER_BITMAP 0x0c + +enum ENH_PS_MODES { + EN_PS = 1, + DIS_PS = 2, + EN_AUTO_DS = 3, + DIS_AUTO_DS = 4, + SLEEP_CONFIRM = 5, + GET_PS = 0, + EN_AUTO_PS = 0xff, + DIS_AUTO_PS = 0xfe, +}; + +enum nxpwifi_channel_flags { + NXPWIFI_CHANNEL_PASSIVE = BIT(0), + NXPWIFI_CHANNEL_DFS = BIT(1), + NXPWIFI_CHANNEL_NOHT40 = BIT(2), + NXPWIFI_CHANNEL_NOHT80 = BIT(3), + NXPWIFI_CHANNEL_DISABLED = BIT(7), +}; + +#define HOST_RET_BIT 0x8000 +#define HOST_ACT_GEN_GET 0x0000 +#define HOST_ACT_GEN_SET 0x0001 +#define HOST_ACT_GEN_REMOVE 0x0004 +#define HOST_ACT_BITWISE_SET 0x0002 +#define HOST_ACT_BITWISE_CLR 0x0003 +#define HOST_RESULT_OK 0x0000 +#define HOST_ACT_MAC_RX_ON BIT(0) +#define HOST_ACT_MAC_TX_ON BIT(1) +#define HOST_ACT_MAC_WEP_ENABLE BIT(3) +#define HOST_ACT_MAC_ETHERNETII_ENABLE BIT(4) +#define HOST_ACT_MAC_PROMISCUOUS_ENABLE BIT(7) +#define HOST_ACT_MAC_ALL_MULTICAST_ENABLE BIT(8) +#define HOST_ACT_MAC_DYNAMIC_BW_ENABLE BIT(16) + +#define HOST_BSS_MODE_IBSS 0x0002 +#define HOST_BSS_MODE_ANY 0x0003 + +#define HOST_SCAN_RADIO_TYPE_BG 0 +#define HOST_SCAN_RADIO_TYPE_A 1 + +#define HS_CFG_CANCEL 0xffffffff +#define HS_CFG_COND_DEF 0x00000000 +#define HS_CFG_GPIO_DEF 0xff +#define HS_CFG_GAP_DEF 0xff +#define HS_CFG_COND_BROADCAST_DATA 0x00000001 +#define HS_CFG_COND_UNICAST_DATA 0x00000002 +#define HS_CFG_COND_MAC_EVENT 0x00000004 +#define HS_CFG_COND_MULTICAST_DATA 0x00000008 + +#define CONNECT_ERR_AUTH_ERR_STA_FAILURE 0xFFFB +#define CONNECT_ERR_ASSOC_ERR_TIMEOUT 0xFFFC +#define CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED 0xFFFD +#define CONNECT_ERR_AUTH_MSG_UNHANDLED 0xFFFE +#define CONNECT_ERR_STA_FAILURE 0xFFFF + +#define CMD_F_HOSTCMD BIT(0) + +#define HOST_CMD_ID_MASK 0x0fff + +#define HOST_SEQ_NUM_MASK 0x00ff + +#define HOST_BSS_NUM_MASK 0x0f00 + +#define HOST_BSS_TYPE_MASK 0xf000 + +#define HOST_ACT_SET_RX 0x0001 +#define HOST_ACT_SET_TX 0x0002 +#define HOST_ACT_SET_BOTH 0x0003 +#define HOST_ACT_GET_RX 0x0004 +#define HOST_ACT_GET_TX 0x0008 +#define HOST_ACT_GET_BOTH 0x000c + +#define HOST_ACT_REMOVE_STA 0x0 +#define HOST_ACT_ADD_STA 0x1 + +#define RF_ANTENNA_AUTO 0xFFFF + +#define HOST_SET_SEQ_NO_BSS_INFO(seq, num, type) \ + ((((seq) & 0x00ff) | \ + (((num) & 0x000f) << 8)) | \ + (((type) & 0x000f) << 12)) + +#define HOST_GET_SEQ_NO(seq) \ + ((seq) & HOST_SEQ_NUM_MASK) + +#define HOST_GET_BSS_NO(seq) \ + (((seq) & HOST_BSS_NUM_MASK) >> 8) + +#define HOST_GET_BSS_TYPE(seq) \ + (((seq) & HOST_BSS_TYPE_MASK) >> 12) + +#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001 +#define EVENT_LINK_LOST 0x00000003 +#define EVENT_LINK_SENSED 0x00000004 +#define EVENT_MIB_CHANGED 0x00000006 +#define EVENT_INIT_DONE 0x00000007 +#define EVENT_DEAUTHENTICATED 0x00000008 +#define EVENT_DISASSOCIATED 0x00000009 +#define EVENT_PS_AWAKE 0x0000000a +#define EVENT_PS_SLEEP 0x0000000b +#define EVENT_MIC_ERR_MULTICAST 0x0000000d +#define EVENT_MIC_ERR_UNICAST 0x0000000e +#define EVENT_DEEP_SLEEP_AWAKE 0x00000010 +#define EVENT_WMM_STATUS_CHANGE 0x00000017 +#define EVENT_BG_SCAN_REPORT 0x00000018 +#define EVENT_RSSI_LOW 0x00000019 +#define EVENT_SNR_LOW 0x0000001a +#define EVENT_MAX_FAIL 0x0000001b +#define EVENT_RSSI_HIGH 0x0000001c +#define EVENT_SNR_HIGH 0x0000001d +#define EVENT_DATA_RSSI_LOW 0x00000024 +#define EVENT_DATA_SNR_LOW 0x00000025 +#define EVENT_DATA_RSSI_HIGH 0x00000026 +#define EVENT_DATA_SNR_HIGH 0x00000027 +#define EVENT_LINK_QUALITY 0x00000028 +#define EVENT_PORT_RELEASE 0x0000002b +#define EVENT_UAP_STA_DEAUTH 0x0000002c +#define EVENT_UAP_STA_ASSOC 0x0000002d +#define EVENT_UAP_BSS_START 0x0000002e +#define EVENT_PRE_BEACON_LOST 0x00000031 +#define EVENT_ADDBA 0x00000033 +#define EVENT_DELBA 0x00000034 +#define EVENT_BA_STREAM_TIEMOUT 0x00000037 +#define EVENT_AMSDU_AGGR_CTRL 0x00000042 +#define EVENT_UAP_BSS_IDLE 0x00000043 +#define EVENT_UAP_BSS_ACTIVE 0x00000044 +#define EVENT_WEP_ICV_ERR 0x00000046 +#define EVENT_HS_ACT_REQ 0x00000047 +#define EVENT_BW_CHANGE 0x00000048 +#define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c +#define EVENT_HOSTWAKE_STAIE 0x0000004d +#define EVENT_CHANNEL_SWITCH_ANN 0x00000050 +#define EVENT_RADAR_DETECTED 0x00000053 +#define EVENT_CHANNEL_REPORT_RDY 0x00000054 +#define EVENT_TX_DATA_PAUSE 0x00000055 +#define EVENT_EXT_SCAN_REPORT 0x00000058 +#define EVENT_RXBA_SYNC 0x00000059 +#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f +#define EVENT_UNKNOWN_DEBUG 0x00000063 +#define EVENT_BG_SCAN_STOPPED 0x00000065 +#define EVENT_MULTI_CHAN_INFO 0x0000006a +#define EVENT_FW_DUMP_INFO 0x00000073 +#define EVENT_TX_STATUS_REPORT 0x00000074 +#define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076 +#define EVENT_VDLL_IND 0x00000081 + + +#define EVENT_ID_MASK 0xffff +#define BSS_NUM_MASK 0xf + +#define EVENT_GET_BSS_NUM(event_cause) \ + (((event_cause) >> 16) & BSS_NUM_MASK) + +#define EVENT_GET_BSS_TYPE(event_cause) \ + (((event_cause) >> 24) & 0x00ff) + +#define NXPWIFI_MAX_PATTERN_LEN 40 +#define NXPWIFI_MAX_OFFSET_LEN 100 +#define NXPWIFI_MAX_ND_MATCH_SETS 10 + +#define STACK_NBYTES 100 +#define TYPE_DNUM 1 +#define TYPE_BYTESEQ 2 +#define MAX_OPERAND 0x40 +#define TYPE_EQ (MAX_OPERAND + 1) +#define TYPE_EQ_DNUM (MAX_OPERAND + 2) +#define TYPE_EQ_BIT (MAX_OPERAND + 3) +#define TYPE_AND (MAX_OPERAND + 4) +#define TYPE_OR (MAX_OPERAND + 5) +#define MEF_MODE_HOST_SLEEP 1 +#define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3 +#define MEF_ACTION_AUTO_ARP 0x10 +#define NXPWIFI_CRITERIA_BROADCAST BIT(0) +#define NXPWIFI_CRITERIA_UNICAST BIT(1) +#define NXPWIFI_CRITERIA_MULTICAST BIT(3) +#define NXPWIFI_MAX_SUPPORTED_IPADDR 4 + +#define NXPWIFI_DEF_CS_UNIT_TIME 2 +#define NXPWIFI_DEF_CS_THR_OTHERLINK 10 +#define NXPWIFI_DEF_THR_DIRECTLINK 0 +#define NXPWIFI_DEF_CS_TIME 10 +#define NXPWIFI_DEF_CS_TIMEOUT 16 +#define NXPWIFI_DEF_CS_REG_CLASS 12 +#define NXPWIFI_DEF_CS_PERIODICITY 1 + +#define NXPWIFI_FW_V15 15 + +#define NXPWIFI_MASTER_RADAR_DET_MASK BIT(1) + +struct nxpwifi_ie_types_header { + __le16 type; + __le16 len; +} __packed; + +struct nxpwifi_ie_types_data { + struct nxpwifi_ie_types_header header; + u8 data[]; +} __packed; + +#define NXPWIFI_TxPD_POWER_MGMT_NULL_PACKET 0x01 +#define NXPWIFI_TxPD_POWER_MGMT_LAST_PACKET 0x08 +#define NXPWIFI_TXPD_FLAGS_REQ_TX_STATUS 0x20 + +enum HS_WAKEUP_REASON { + NO_HSWAKEUP_REASON = 0, + BCAST_DATA_MATCHED, + MCAST_DATA_MATCHED, + UCAST_DATA_MATCHED, + MASKTABLE_EVENT_MATCHED, + NON_MASKABLE_EVENT_MATCHED, + NON_MASKABLE_CONDITION_MATCHED, + MAGIC_PATTERN_MATCHED, + CONTROL_FRAME_MATCHED, + MANAGEMENT_FRAME_MATCHED, + GTK_REKEY_FAILURE, + RESERVED +}; + +struct txpd { + u8 bss_type; + u8 bss_num; + __le16 tx_pkt_length; + __le16 tx_pkt_offset; + __le16 tx_pkt_type; + __le32 tx_control; + u8 priority; + u8 flags; + u8 pkt_delay_2ms; + u8 reserved1[2]; + u8 tx_token_id; + u8 reserved[2]; +} __packed; + +struct rxpd { + u8 bss_type; + u8 bss_num; + __le16 rx_pkt_length; + __le16 rx_pkt_offset; + __le16 rx_pkt_type; + __le16 seq_num; + u8 priority; + u8 rx_rate; + s8 snr; + s8 nf; + + /* For: Non-802.11 AC cards + * + * Ht Info [Bit 0] RxRate format: LG=0, HT=1 + * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 + * + * For: 802.11 AC cards + * [Bit 1] [Bit 0] RxRate format: legacy rate = 00 HT = 01 VHT = 10 + * [Bit 3] [Bit 2] HT/VHT Bandwidth BW20 = 00 BW40 = 01 + * BW80 = 10 BW160 = 11 + * [Bit 4] HT/VHT Guard interval LGI = 0 SGI = 1 + * [Bit 5] STBC support Enabled = 1 + * [Bit 6] LDPC support Enabled = 1 + * [Bit 7] Reserved + */ + u8 ht_info; + u8 reserved[3]; + u8 flags; +} __packed; + +struct uap_txpd { + u8 bss_type; + u8 bss_num; + __le16 tx_pkt_length; + __le16 tx_pkt_offset; + __le16 tx_pkt_type; + __le32 tx_control; + u8 priority; + u8 flags; + u8 pkt_delay_2ms; + u8 reserved1[2]; + u8 tx_token_id; + u8 reserved[2]; +} __packed; + +struct uap_rxpd { + u8 bss_type; + u8 bss_num; + __le16 rx_pkt_length; + __le16 rx_pkt_offset; + __le16 rx_pkt_type; + __le16 seq_num; + u8 priority; + u8 rx_rate; + s8 snr; + s8 nf; + u8 ht_info; + u8 reserved[3]; + u8 flags; +} __packed; + +struct nxpwifi_auth { + __le16 auth_alg; + __le16 auth_transaction; + __le16 status_code; + /* possibly followed by Challenge text */ + u8 variable[]; +} __packed; + +struct nxpwifi_ieee80211_mgmt { + __le16 frame_control; + __le16 duration; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 seq_ctrl; + u8 addr4[ETH_ALEN]; + struct nxpwifi_auth auth; +} __packed; + +struct nxpwifi_fw_chan_stats { + u8 chan_num; + u8 bandcfg; + u8 flags; + s8 noise; + __le16 total_bss; + __le16 cca_scan_dur; + __le16 cca_busy_dur; +} __packed; + +enum nxpwifi_chan_scan_mode_bitmasks { + NXPWIFI_PASSIVE_SCAN = BIT(0), + NXPWIFI_DISABLE_CHAN_FILT = BIT(1), + NXPWIFI_HIDDEN_SSID_REPORT = BIT(4), +}; + +struct nxpwifi_chan_scan_param_set { + u8 radio_type; + u8 chan_number; + u8 chan_scan_mode_bmap; + __le16 min_scan_time; + __le16 max_scan_time; +} __packed; + +struct nxpwifi_ie_types_chan_list_param_set { + struct nxpwifi_ie_types_header header; + struct nxpwifi_chan_scan_param_set chan_scan_param[]; +} __packed; + +struct nxpwifi_ie_types_rxba_sync { + struct nxpwifi_ie_types_header header; + u8 mac[ETH_ALEN]; + u8 tid; + u8 reserved; + __le16 seq_num; + __le16 bitmap_len; + u8 bitmap[]; +} __packed; + +struct chan_band_param_set { + u8 radio_type; + u8 chan_number; +}; + +struct nxpwifi_ie_types_chan_band_list_param_set { + struct nxpwifi_ie_types_header header; + struct chan_band_param_set chan_band_param[]; +} __packed; + +struct nxpwifi_ie_types_rates_param_set { + struct nxpwifi_ie_types_header header; + u8 rates[]; +} __packed; + +struct nxpwifi_ie_types_ssid_param_set { + struct nxpwifi_ie_types_header header; + u8 ssid[]; +} __packed; + +struct nxpwifi_ie_types_host_mlme { + struct nxpwifi_ie_types_header header; + u8 host_mlme; +} __packed; + +struct nxpwifi_ie_types_num_probes { + struct nxpwifi_ie_types_header header; + __le16 num_probes; +} __packed; + +struct nxpwifi_ie_types_repeat_count { + struct nxpwifi_ie_types_header header; + __le16 repeat_count; +} __packed; + +struct nxpwifi_ie_types_min_rssi_threshold { + struct nxpwifi_ie_types_header header; + __le16 rssi_threshold; +} __packed; + +struct nxpwifi_ie_types_bgscan_start_later { + struct nxpwifi_ie_types_header header; + __le16 start_later; +} __packed; + +struct nxpwifi_ie_types_scan_chan_gap { + struct nxpwifi_ie_types_header header; + /* time gap in TUs to be used between two consecutive channels scan */ + __le16 chan_gap; +} __packed; + +struct nxpwifi_ie_types_random_mac { + struct nxpwifi_ie_types_header header; + u8 mac[ETH_ALEN]; +} __packed; + +struct nxpwifi_ietypes_chanstats { + struct nxpwifi_ie_types_header header; + struct nxpwifi_fw_chan_stats chanstats[]; +} __packed; + +struct nxpwifi_ie_types_wildcard_ssid_params { + struct nxpwifi_ie_types_header header; + u8 max_ssid_length; + u8 ssid[]; +} __packed; + +#define TSF_DATA_SIZE 8 +struct nxpwifi_ie_types_tsf_timestamp { + struct nxpwifi_ie_types_header header; + u8 tsf_data[]; +} __packed; + +struct nxpwifi_cf_param_set { + u8 cfp_cnt; + u8 cfp_period; + __le16 cfp_max_duration; + __le16 cfp_duration_remaining; +} __packed; + +struct nxpwifi_ibss_param_set { + __le16 atim_window; +} __packed; + +struct nxpwifi_ie_types_ss_param_set { + struct nxpwifi_ie_types_header header; + union { + struct nxpwifi_cf_param_set cf_param_set[1]; + struct nxpwifi_ibss_param_set ibss_param_set[1]; + } cf_ibss; +} __packed; + +struct nxpwifi_fh_param_set { + __le16 dwell_time; + u8 hop_set; + u8 hop_pattern; + u8 hop_index; +} __packed; + +struct nxpwifi_ds_param_set { + u8 current_chan; +} __packed; + +struct nxpwifi_ie_types_phy_param_set { + struct nxpwifi_ie_types_header header; + union { + struct nxpwifi_fh_param_set fh_param_set[1]; + struct nxpwifi_ds_param_set ds_param_set[1]; + } fh_ds; +} __packed; + +struct nxpwifi_ie_types_auth_type { + struct nxpwifi_ie_types_header header; + __le16 auth_type; +} __packed; + +struct nxpwifi_ie_types_vendor_param_set { + struct nxpwifi_ie_types_header header; + u8 ie[NXPWIFI_MAX_VSIE_LEN]; +}; + +#define NXPWIFI_AUTHTYPE_SAE 6 + +struct nxpwifi_ie_types_sae_pwe_mode { + struct nxpwifi_ie_types_header header; + u8 pwe[]; +} __packed; + +struct nxpwifi_ie_types_rsn_param_set { + struct nxpwifi_ie_types_header header; + u8 rsn_ie[]; +} __packed; + +#define KEYPARAMSET_FIXED_LEN 6 + +#define IGTK_PN_LEN 8 + +struct nxpwifi_cmac_param { + u8 ipn[IGTK_PN_LEN]; + u8 key[WLAN_KEY_LEN_AES_CMAC]; +} __packed; + +struct nxpwifi_wep_param { + __le16 key_len; + u8 key[WLAN_KEY_LEN_WEP104]; +} __packed; + +struct nxpwifi_tkip_param { + u8 pn[WPA_PN_SIZE]; + __le16 key_len; + u8 key[WLAN_KEY_LEN_TKIP]; +} __packed; + +struct nxpwifi_aes_param { + u8 pn[WPA_PN_SIZE]; + __le16 key_len; + u8 key[WLAN_KEY_LEN_CCMP_256]; +} __packed; + +struct nxpwifi_cmac_aes_param { + u8 ipn[IGTK_PN_LEN]; + __le16 key_len; + u8 key[WLAN_KEY_LEN_AES_CMAC]; +} __packed; + +struct nxpwifi_ie_type_key_param_set { + __le16 type; + __le16 len; + u8 mac_addr[ETH_ALEN]; + u8 key_idx; + u8 key_type; + __le16 key_info; + union { + struct nxpwifi_wep_param wep; + struct nxpwifi_tkip_param tkip; + struct nxpwifi_aes_param aes; + struct nxpwifi_cmac_aes_param cmac_aes; + } key_params; +} __packed; + +struct host_cmd_ds_802_11_key_material { + __le16 action; + struct nxpwifi_ie_type_key_param_set key_param_set; +} __packed; + +struct host_cmd_ds_gen { + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; +}; + +#define S_DS_GEN sizeof(struct host_cmd_ds_gen) + +enum sleep_resp_ctrl { + RESP_NOT_NEEDED = 0, + RESP_NEEDED, +}; + +struct nxpwifi_ps_param { + __le16 null_pkt_interval; + __le16 multiple_dtims; + __le16 bcn_miss_timeout; + __le16 local_listen_interval; + __le16 reserved; + __le16 mode; + __le16 delay_to_ps; +} __packed; + +#define HS_DEF_WAKE_INTERVAL 100 +#define HS_DEF_INACTIVITY_TIMEOUT 50 + +struct nxpwifi_ps_param_in_hs { + struct nxpwifi_ie_types_header header; + __le32 hs_wake_int; + __le32 hs_inact_timeout; +} __packed; + +#define BITMAP_AUTO_DS 0x01 +#define BITMAP_STA_PS 0x10 + +struct nxpwifi_ie_types_auto_ds_param { + struct nxpwifi_ie_types_header header; + __le16 deep_sleep_timeout; +} __packed; + +struct nxpwifi_ie_types_ps_param { + struct nxpwifi_ie_types_header header; + struct nxpwifi_ps_param param; +} __packed; + +struct host_cmd_ds_802_11_ps_mode_enh { + __le16 action; + + union { + struct nxpwifi_ps_param opt_ps; + __le16 ps_bitmap; + } params; +} __packed; + +enum API_VER_ID { + KEY_API_VER_ID = 1, + FW_API_VER_ID = 2, + UAP_FW_API_VER_ID = 3, + CHANRPT_API_VER_ID = 4, + FW_HOTFIX_VER_ID = 5, +}; + +struct hw_spec_api_rev { + struct nxpwifi_ie_types_header header; + __le16 api_id; + u8 major_ver; + u8 minor_ver; +} __packed; + +struct host_cmd_ds_get_hw_spec { + __le16 hw_if_version; + __le16 version; + __le16 reserved; + __le16 num_of_mcast_adr; + u8 permanent_addr[ETH_ALEN]; + __le16 region_code; + __le16 number_of_antenna; + __le32 fw_release_number; + __le32 reserved_1; + __le32 reserved_2; + __le32 reserved_3; + __le32 fw_cap_info; + __le32 dot_11n_dev_cap; + u8 dev_mcs_support; + __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 mgmt_buf_count; /* mgmt IE buffer count */ + __le32 reserved_4; + __le32 reserved_5; + __le32 dot_11ac_dev_cap; + __le32 dot_11ac_mcs_support; + u8 tlvs[]; +} __packed; + +struct host_cmd_ds_802_11_rssi_info { + __le16 action; + __le16 ndata; + __le16 nbcn; + __le16 reserved[9]; + long long reserved_1; +} __packed; + +struct host_cmd_ds_802_11_rssi_info_rsp { + __le16 action; + __le16 ndata; + __le16 nbcn; + __le16 data_rssi_last; + __le16 data_nf_last; + __le16 data_rssi_avg; + __le16 data_nf_avg; + __le16 bcn_rssi_last; + __le16 bcn_nf_last; + __le16 bcn_rssi_avg; + __le16 bcn_nf_avg; + long long tsf_bcn; +} __packed; + +struct host_cmd_ds_802_11_mac_address { + __le16 action; + u8 mac_addr[ETH_ALEN]; +} __packed; + +struct host_cmd_ds_mac_control { + __le32 action; +}; + +struct host_cmd_ds_mac_multicast_adr { + __le16 action; + __le16 num_of_adrs; + u8 mac_list[NXPWIFI_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; +} __packed; + +struct host_cmd_ds_802_11_deauthenticate { + u8 mac_addr[ETH_ALEN]; + __le16 reason_code; +} __packed; + +struct host_cmd_ds_802_11_associate { + u8 peer_sta_addr[ETH_ALEN]; + __le16 cap_info_bitmap; + __le16 listen_interval; + __le16 beacon_period; + u8 dtim_period; +} __packed; + +struct ieee_types_assoc_rsp { + __le16 cap_info_bitmap; + __le16 status_code; + __le16 a_id; + u8 ie_buffer[]; +} __packed; + +struct host_cmd_ds_802_11_associate_rsp { + struct ieee_types_assoc_rsp assoc_rsp; +} __packed; + +struct ieee_types_cf_param_set { + u8 element_id; + u8 len; + u8 cfp_cnt; + u8 cfp_period; + __le16 cfp_max_duration; + __le16 cfp_duration_remaining; +} __packed; + +struct ieee_types_fh_param_set { + u8 element_id; + u8 len; + __le16 dwell_time; + u8 hop_set; + u8 hop_pattern; + u8 hop_index; +} __packed; + +struct ieee_types_ds_param_set { + u8 element_id; + u8 len; + u8 current_chan; +} __packed; + +union ieee_types_phy_param_set { + struct ieee_types_fh_param_set fh_param_set; + struct ieee_types_ds_param_set ds_param_set; +} __packed; + +struct ieee_types_oper_mode_ntf { + u8 element_id; + u8 len; + u8 oper_mode; +} __packed; + +struct host_cmd_ds_802_11_get_log { + __le32 mcast_tx_frame; + __le32 failed; + __le32 retry; + __le32 multi_retry; + __le32 frame_dup; + __le32 rts_success; + __le32 rts_failure; + __le32 ack_failure; + __le32 rx_frag; + __le32 mcast_rx_frame; + __le32 fcs_error; + __le32 tx_frame; + __le32 reserved; + __le32 wep_icv_err_cnt[4]; + __le32 bcn_rcv_cnt; + __le32 bcn_miss_cnt; +} __packed; + +/* Enumeration for rate format */ +enum nxpwifi_rate_format { + NXPWIFI_RATE_FORMAT_LG = 0, + NXPWIFI_RATE_FORMAT_HT, + NXPWIFI_RATE_FORMAT_VHT, + NXPWIFI_RATE_FORMAT_AUTO = 0xFF, +}; + +struct host_cmd_ds_tx_rate_query { + u8 tx_rate; + /* Tx Rate Info: For 802.11 AC cards + * + * [Bit 0-1] tx rate formate: LG = 0, HT = 1, VHT = 2 + * [Bit 2-3] HT/VHT Bandwidth: BW20 = 0, BW40 = 1, BW80 = 2, BW160 = 3 + * [Bit 4] HT/VHT Guard Interval: LGI = 0, SGI = 1 + * + * For non-802.11 AC cards + * Ht Info [Bit 0] RxRate format: LG=0, HT=1 + * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 + */ + u8 ht_info; +} __packed; + +struct nxpwifi_tx_pause_tlv { + struct nxpwifi_ie_types_header header; + u8 peermac[ETH_ALEN]; + u8 tx_pause; + u8 pkt_cnt; +} __packed; + +enum host_sleep_action { + HS_CONFIGURE = 0x0001, + HS_ACTIVATE = 0x0002, +}; + +struct nxpwifi_hs_config_param { + __le32 conditions; + u8 gpio; + u8 gap; +} __packed; + +struct hs_activate_param { + __le16 resp_ctrl; +} __packed; + +struct host_cmd_ds_802_11_hs_cfg_enh { + __le16 action; + + union { + struct nxpwifi_hs_config_param hs_config; + struct hs_activate_param hs_activate; + } params; +} __packed; + +enum SNMP_MIB_INDEX { + OP_RATE_SET_I = 1, + DTIM_PERIOD_I = 3, + RTS_THRESH_I = 5, + SHORT_RETRY_LIM_I = 6, + LONG_RETRY_LIM_I = 7, + FRAG_THRESH_I = 8, + DOT11D_I = 9, + DOT11H_I = 10, +}; + +enum nxpwifi_assocmd_failurepoint { + NXPWIFI_ASSOC_CMD_SUCCESS = 0, + NXPWIFI_ASSOC_CMD_FAILURE_ASSOC, + NXPWIFI_ASSOC_CMD_FAILURE_AUTH, + NXPWIFI_ASSOC_CMD_FAILURE_JOIN +}; + +#define MAX_SNMP_BUF_SIZE 128 + +struct host_cmd_ds_802_11_snmp_mib { + __le16 query_type; + __le16 oid; + __le16 buf_size; + u8 value[]; +} __packed; + +struct nxpwifi_rate_scope { + __le16 type; + __le16 length; + __le16 hr_dsss_rate_bitmap; + __le16 ofdm_rate_bitmap; + __le16 ht_mcs_rate_bitmap[8]; + __le16 vht_mcs_rate_bitmap[8]; +} __packed; + +struct nxpwifi_rate_drop_pattern { + __le16 type; + __le16 length; + __le32 rate_drop_mode; +} __packed; + +struct host_cmd_ds_tx_rate_cfg { + __le16 action; + __le16 cfg_index; +} __packed; + +struct nxpwifi_power_group { + u8 modulation_class; + u8 first_rate_code; + u8 last_rate_code; + s8 power_step; + s8 power_min; + s8 power_max; + u8 ht_bandwidth; + u8 reserved; +} __packed; + +struct nxpwifi_types_power_group { + __le16 type; + __le16 length; +} __packed; + +struct host_cmd_ds_txpwr_cfg { + __le16 action; + __le16 cfg_index; + __le32 mode; +} __packed; + +struct host_cmd_ds_rf_tx_pwr { + __le16 action; + __le16 cur_level; + u8 max_power; + u8 min_power; +} __packed; + +struct host_cmd_ds_rf_ant_mimo { + __le16 action_tx; + __le16 tx_ant_mode; + __le16 action_rx; + __le16 rx_ant_mode; +} __packed; + +struct host_cmd_ds_rf_ant_siso { + __le16 action; + __le16 ant_mode; +} __packed; + +#define BAND_CFG_CHAN_BAND_MASK 0x03 +#define BAND_CFG_CHAN_BAND_SHIFT_BIT 0 +#define BAND_CFG_CHAN_WIDTH_MASK 0x0C +#define BAND_CFG_CHAN_WIDTH_SHIFT_BIT 2 +#define BAND_CFG_CHAN2_OFFSET_MASK 0x30 +#define BAND_CFG_CHAN2_SHIFT_BIT 4 + +struct nxpwifi_chan_desc { + __le16 start_freq; + u8 band_cfg; + u8 chan_num; +} __packed; + +struct host_cmd_ds_chan_rpt_req { + struct nxpwifi_chan_desc chan_desc; + __le32 msec_dwell_time; +} __packed; + +struct host_cmd_ds_chan_rpt_event { + __le32 result; + __le64 start_tsf; + __le32 duration; + u8 tlvbuf[]; +} __packed; + +struct host_cmd_sdio_sp_rx_aggr_cfg { + u8 action; + u8 enable; + __le16 block_size; +} __packed; + +struct nxpwifi_fixed_bcn_param { + __le64 timestamp; + __le16 beacon_period; + __le16 cap_info_bitmap; +} __packed; + +struct nxpwifi_event_scan_result { + __le16 event_id; + u8 bss_index; + u8 bss_type; + u8 more_event; + u8 reserved[3]; + __le16 buf_size; + u8 num_of_set; +} __packed; + +struct tx_status_event { + u8 packet_type; + u8 tx_token_id; + u8 status; +} __packed; + +#define NXPWIFI_USER_SCAN_CHAN_MAX 50 + +#define NXPWIFI_MAX_SSID_LIST_LENGTH 10 + +struct nxpwifi_scan_cmd_config { + /* BSS mode to be sent in the firmware command + */ + u8 bss_mode; + + /* Specific BSSID used to filter scan results in the firmware */ + u8 specific_bssid[ETH_ALEN]; + + /* Length of TLVs sent in command starting at tlvBuffer */ + u32 tlv_buf_len; + + /* SSID TLV(s) and ChanList TLVs to be sent in the firmware command + * + * TLV_TYPE_CHANLIST, nxpwifi_ie_types_chan_list_param_set + * WLAN_EID_SSID, nxpwifi_ie_types_ssid_param_set + */ + u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored here */ +} __packed; + +struct nxpwifi_user_scan_chan { + u8 chan_number; + u8 radio_type; + u8 scan_type; + u8 reserved; + u32 scan_time; +} __packed; + +struct nxpwifi_user_scan_cfg { + /* BSS mode to be sent in the firmware command + */ + u8 bss_mode; + /* Configure the number of probe requests for active chan scans */ + u8 num_probes; + u8 reserved; + /* BSSID filter sent in the firmware command to limit the results */ + u8 specific_bssid[ETH_ALEN]; + /* SSID filter list used in the firmware to limit the scan results */ + struct cfg80211_ssid *ssid_list; + u8 num_ssids; + /* Variable number (fixed maximum) of channels to scan up */ + struct nxpwifi_user_scan_chan chan_list[NXPWIFI_USER_SCAN_CHAN_MAX]; + u16 scan_chan_gap; + u8 random_mac[ETH_ALEN]; +} __packed; + +#define NXPWIFI_BG_SCAN_CHAN_MAX 38 +#define NXPWIFI_BSS_MODE_INFRA 1 +#define NXPWIFI_BGSCAN_ACT_GET 0x0000 +#define NXPWIFI_BGSCAN_ACT_SET 0x0001 +#define NXPWIFI_BGSCAN_ACT_SET_ALL 0xff01 +/** ssid match */ +#define NXPWIFI_BGSCAN_SSID_MATCH 0x0001 +/** ssid match and RSSI exceeded */ +#define NXPWIFI_BGSCAN_SSID_RSSI_MATCH 0x0004 +/**wait for all channel scan to complete to report scan result*/ +#define NXPWIFI_BGSCAN_WAIT_ALL_CHAN_DONE 0x80000000 + +struct nxpwifi_bg_scan_cfg { + u16 action; + u8 enable; + u8 bss_type; + u8 chan_per_scan; + u32 scan_interval; + u32 report_condition; + u8 num_probes; + u8 rssi_threshold; + u8 snr_threshold; + u16 repeat_count; + u16 start_later; + struct cfg80211_match_set *ssid_list; + u8 num_ssids; + struct nxpwifi_user_scan_chan chan_list[NXPWIFI_BG_SCAN_CHAN_MAX]; + u16 scan_chan_gap; +} __packed; + +struct ie_body { + u8 grp_key_oui[4]; + u8 ptk_cnt[2]; + u8 ptk_body[4]; +} __packed; + +struct host_cmd_ds_802_11_scan { + u8 bss_mode; + u8 bssid[ETH_ALEN]; + u8 tlv_buffer[]; +} __packed; + +struct host_cmd_ds_802_11_scan_rsp { + __le16 bss_descript_size; + u8 number_of_sets; + u8 bss_desc_and_tlv_buffer[]; +} __packed; + +struct host_cmd_ds_802_11_scan_ext { + u32 reserved; + u8 tlv_buffer[]; +} __packed; + +struct nxpwifi_ie_types_bss_mode { + struct nxpwifi_ie_types_header header; + u8 bss_mode; +} __packed; + +struct nxpwifi_ie_types_bss_scan_rsp { + struct nxpwifi_ie_types_header header; + u8 bssid[ETH_ALEN]; + u8 frame_body[]; +} __packed; + +struct nxpwifi_ie_types_bss_scan_info { + struct nxpwifi_ie_types_header header; + __le16 rssi; + __le16 anpi; + u8 cca_busy_fraction; + u8 radio_type; + u8 channel; + u8 reserved; + __le64 tsf; +} __packed; + +struct host_cmd_ds_802_11_bg_scan_config { + __le16 action; + u8 enable; + u8 bss_type; + u8 chan_per_scan; + u8 reserved; + __le16 reserved1; + __le32 scan_interval; + __le32 reserved2; + __le32 report_condition; + __le16 reserved3; + u8 tlv[]; +} __packed; + +struct host_cmd_ds_802_11_bg_scan_query { + u8 flush; +} __packed; + +struct host_cmd_ds_802_11_bg_scan_query_rsp { + __le32 report_condition; + struct host_cmd_ds_802_11_scan_rsp scan_resp; +} __packed; + +struct nxpwifi_ietypes_domain_code { + struct nxpwifi_ie_types_header header; + u8 domain_code; + u8 reserved; +} __packed; + +struct nxpwifi_ietypes_domain_param_set { + struct nxpwifi_ie_types_header header; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + struct ieee80211_country_ie_triplet triplet[]; +} __packed; + +struct host_cmd_ds_802_11d_domain_info { + __le16 action; + struct nxpwifi_ietypes_domain_param_set domain; +} __packed; + +struct host_cmd_ds_802_11d_domain_info_rsp { + __le16 action; + struct nxpwifi_ietypes_domain_param_set domain; +} __packed; + +struct host_cmd_ds_11n_addba_req { + u8 add_req_result; + u8 peer_mac_addr[ETH_ALEN]; + u8 dialog_token; + __le16 block_ack_param_set; + __le16 block_ack_tmo; + __le16 ssn; +} __packed; + +struct host_cmd_ds_11n_addba_rsp { + u8 add_rsp_result; + u8 peer_mac_addr[ETH_ALEN]; + u8 dialog_token; + __le16 status_code; + __le16 block_ack_param_set; + __le16 block_ack_tmo; + __le16 ssn; +} __packed; + +struct host_cmd_ds_11n_delba { + u8 del_result; + u8 peer_mac_addr[ETH_ALEN]; + __le16 del_ba_param_set; + __le16 reason_code; + u8 reserved; +} __packed; + +struct host_cmd_ds_11n_batimeout { + u8 tid; + u8 peer_mac_addr[ETH_ALEN]; + u8 origninator; +} __packed; + +struct host_cmd_ds_11n_cfg { + __le16 action; + __le16 ht_tx_cap; + __le16 ht_tx_info; + __le16 misc_config; /* Needed for 802.11AC cards only */ +} __packed; + +struct host_cmd_ds_txbuf_cfg { + __le16 action; + __le16 buff_size; + __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 reserved3; +} __packed; + +struct host_cmd_ds_amsdu_aggr_ctrl { + __le16 action; + __le16 enable; + __le16 curr_buf_size; +} __packed; + +struct host_cmd_ds_sta_deauth { + u8 mac[ETH_ALEN]; + __le16 reason; +} __packed; + +struct nxpwifi_ie_types_sta_info { + struct nxpwifi_ie_types_header header; + u8 mac[ETH_ALEN]; + u8 power_mfg_status; + s8 rssi; +}; + +struct host_cmd_ds_sta_list { + __le16 sta_count; + u8 tlv[]; +} __packed; + +struct nxpwifi_ie_types_pwr_capability { + struct nxpwifi_ie_types_header header; + s8 min_pwr; + s8 max_pwr; +}; + +struct nxpwifi_ie_types_local_pwr_constraint { + struct nxpwifi_ie_types_header header; + u8 chan; + u8 constraint; +}; + +struct nxpwifi_ie_types_wmm_param_set { + struct nxpwifi_ie_types_header header; + u8 wmm_ie[]; +} __packed; + +struct nxpwifi_ie_types_mgmt_frame { + struct nxpwifi_ie_types_header header; + __le16 frame_control; + u8 frame_contents[]; +}; + +struct nxpwifi_ie_types_wmm_queue_status { + struct nxpwifi_ie_types_header header; + u8 queue_index; + u8 disabled; + __le16 medium_time; + u8 flow_required; + u8 flow_created; + u32 reserved; +}; + +struct ieee_types_wmm_info { + /* WMM Info IE - Vendor Specific Header: + * element_id [221/0xdd] + * Len [7] + * Oui [00:50:f2] + * OuiType [2] + * OuiSubType [0] + * Version [1] + */ + struct ieee80211_vendor_ie vend_hdr; + u8 oui_subtype; + u8 version; + + u8 qos_info_bitmap; +} __packed; + +struct host_cmd_ds_wmm_get_status { + u8 queue_status_tlv[sizeof(struct nxpwifi_ie_types_wmm_queue_status) * + IEEE80211_NUM_ACS]; + u8 wmm_param_tlv[sizeof(struct ieee80211_wmm_param_ie) + 2]; +} __packed; + +struct nxpwifi_wmm_ac_status { + u8 disabled; + u8 flow_required; + u8 flow_created; +}; + +struct nxpwifi_ie_types_htcap { + struct nxpwifi_ie_types_header header; + struct ieee80211_ht_cap ht_cap; +} __packed; + +struct nxpwifi_ie_types_vhtcap { + struct nxpwifi_ie_types_header header; + struct ieee80211_vht_cap vht_cap; +} __packed; + +struct nxpwifi_ie_types_aid { + struct nxpwifi_ie_types_header header; + __le16 aid; +} __packed; + +struct nxpwifi_ie_types_oper_mode_ntf { + struct nxpwifi_ie_types_header header; + u8 oper_mode; +} __packed; + +/* VHT Operations IE */ +struct nxpwifi_ie_types_vht_oper { + struct nxpwifi_ie_types_header header; + u8 chan_width; + u8 chan_center_freq_1; + u8 chan_center_freq_2; + /* Basic MCS set map, each 2 bits stands for a NSS */ + __le16 basic_mcs_map; +} __packed; + +struct nxpwifi_ie_types_wmmcap { + struct nxpwifi_ie_types_header header; + struct nxpwifi_types_wmm_info wmm_info; +} __packed; + +struct nxpwifi_ie_types_htinfo { + struct nxpwifi_ie_types_header header; + struct ieee80211_ht_operation ht_oper; +} __packed; + +struct nxpwifi_ie_types_2040bssco { + struct nxpwifi_ie_types_header header; + u8 bss_co_2040; +} __packed; + +struct nxpwifi_ie_types_extcap { + struct nxpwifi_ie_types_header header; + u8 ext_capab[]; +} __packed; + +struct host_cmd_ds_mem_access { + __le16 action; + __le16 reserved; + __le32 addr; + __le32 value; +} __packed; + +struct nxpwifi_ie_types_qos_info { + struct nxpwifi_ie_types_header header; + u8 qos_info; +} __packed; + +struct host_cmd_ds_mac_reg_access { + __le16 action; + __le16 offset; + __le32 value; +} __packed; + +struct host_cmd_ds_bbp_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_rf_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_pmic_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_802_11_eeprom_access { + __le16 action; + + __le16 offset; + __le16 byte_count; + u8 value; +} __packed; + +struct nxpwifi_assoc_event { + u8 sta_addr[ETH_ALEN]; + __le16 type; + __le16 len; + __le16 frame_control; + __le16 cap_info; + __le16 listen_interval; + u8 data[]; +} __packed; + +struct host_cmd_ds_sys_config { + __le16 action; + u8 tlv[]; +}; + +struct host_cmd_11ac_vht_cfg { + __le16 action; + u8 band_config; + u8 misc_config; + __le32 cap_info; + __le32 mcs_tx_set; + __le32 mcs_rx_set; +} __packed; + +struct host_cmd_tlv_akmp { + struct nxpwifi_ie_types_header header; + __le16 key_mgmt; + __le16 key_mgmt_operation; +} __packed; + +struct host_cmd_tlv_pwk_cipher { + struct nxpwifi_ie_types_header header; + __le16 proto; + u8 cipher; + u8 reserved; +} __packed; + +struct host_cmd_tlv_gwk_cipher { + struct nxpwifi_ie_types_header header; + u8 cipher; + u8 reserved; +} __packed; + +struct host_cmd_tlv_passphrase { + struct nxpwifi_ie_types_header header; + u8 passphrase[]; +} __packed; + +struct host_cmd_tlv_wep_key { + struct nxpwifi_ie_types_header header; + u8 key_index; + u8 is_default; + u8 key[]; +}; + +struct host_cmd_tlv_auth_type { + struct nxpwifi_ie_types_header header; + u8 auth_type; + u8 pwe_derivation; + u8 transition_disable; +} __packed; + +struct host_cmd_tlv_encrypt_protocol { + struct nxpwifi_ie_types_header header; + __le16 proto; +} __packed; + +struct host_cmd_tlv_ssid { + struct nxpwifi_ie_types_header header; + u8 ssid[]; +} __packed; + +struct host_cmd_tlv_rates { + struct nxpwifi_ie_types_header header; + u8 rates[]; +} __packed; + +struct nxpwifi_ie_types_bssid_list { + struct nxpwifi_ie_types_header header; + u8 bssid[ETH_ALEN]; +} __packed; + +struct host_cmd_tlv_bcast_ssid { + struct nxpwifi_ie_types_header header; + u8 bcast_ctl; +} __packed; + +struct host_cmd_tlv_beacon_period { + struct nxpwifi_ie_types_header header; + __le16 period; +} __packed; + +struct host_cmd_tlv_dtim_period { + struct nxpwifi_ie_types_header header; + u8 period; +} __packed; + +struct host_cmd_tlv_frag_threshold { + struct nxpwifi_ie_types_header header; + __le16 frag_thr; +} __packed; + +struct host_cmd_tlv_rts_threshold { + struct nxpwifi_ie_types_header header; + __le16 rts_thr; +} __packed; + +struct host_cmd_tlv_retry_limit { + struct nxpwifi_ie_types_header header; + u8 limit; +} __packed; + +struct host_cmd_tlv_mac_addr { + struct nxpwifi_ie_types_header header; + u8 mac_addr[ETH_ALEN]; +} __packed; + +struct host_cmd_tlv_channel_band { + struct nxpwifi_ie_types_header header; + u8 band_config; + u8 channel; +} __packed; + +struct host_cmd_tlv_ageout_timer { + struct nxpwifi_ie_types_header header; + __le32 sta_ao_timer; +} __packed; + +struct host_cmd_tlv_power_constraint { + struct nxpwifi_ie_types_header header; + u8 constraint; +} __packed; + +struct nxpwifi_ie_types_btcoex_scan_time { + struct nxpwifi_ie_types_header header; + u8 coex_scan; + u8 reserved; + __le16 min_scan_time; + __le16 max_scan_time; +} __packed; + +struct nxpwifi_ie_types_btcoex_aggr_win_size { + struct nxpwifi_ie_types_header header; + u8 coex_win_size; + u8 tx_win_size; + u8 rx_win_size; + u8 reserved; +} __packed; + +struct nxpwifi_ie_types_robust_coex { + struct nxpwifi_ie_types_header header; + __le32 mode; +} __packed; + +#define NXPWIFI_VERSION_STR_LENGTH 128 + +struct host_cmd_ds_version_ext { + u8 version_str_sel; + char version_str[NXPWIFI_VERSION_STR_LENGTH]; +} __packed; + +struct host_cmd_ds_mgmt_frame_reg { + __le16 action; + __le32 mask; +} __packed; + +struct host_cmd_ds_remain_on_chan { + __le16 action; + u8 status; + u8 reserved; + u8 band_cfg; + u8 channel; + __le32 duration; +} __packed; + +struct host_cmd_ds_802_11_ibss_status { + __le16 action; + __le16 enable; + u8 bssid[ETH_ALEN]; + __le16 beacon_interval; + __le16 atim_window; + __le16 use_g_rate_protect; +} __packed; + +struct nxpwifi_fw_mef_entry { + u8 mode; + u8 action; + __le16 exprsize; + u8 expr[]; +} __packed; + +struct host_cmd_ds_mef_cfg { + __le32 criteria; + __le16 num_entries; + u8 mef_entry_data[]; +} __packed; + +#define CONNECTION_TYPE_INFRA 0 +#define CONNECTION_TYPE_AP 2 + +struct host_cmd_ds_set_bss_mode { + u8 con_type; +} __packed; + +struct host_cmd_ds_pcie_details { + /* TX buffer descriptor ring address */ + __le32 txbd_addr_lo; + __le32 txbd_addr_hi; + /* TX buffer descriptor ring count */ + __le32 txbd_count; + + /* RX buffer descriptor ring address */ + __le32 rxbd_addr_lo; + __le32 rxbd_addr_hi; + /* RX buffer descriptor ring count */ + __le32 rxbd_count; + + /* Event buffer descriptor ring address */ + __le32 evtbd_addr_lo; + __le32 evtbd_addr_hi; + /* Event buffer descriptor ring count */ + __le32 evtbd_count; + + /* Sleep cookie buffer physical address */ + __le32 sleep_cookie_addr_lo; + __le32 sleep_cookie_addr_hi; +} __packed; + +struct nxpwifi_ie_types_rssi_threshold { + struct nxpwifi_ie_types_header header; + u8 abs_value; + u8 evt_freq; +} __packed; + +#define NXPWIFI_DFS_REC_HDR_LEN 8 +#define NXPWIFI_DFS_REC_HDR_NUM 10 +#define NXPWIFI_BIN_COUNTER_LEN 7 + +struct nxpwifi_radar_det_event { + __le32 detect_count; + u8 reg_domain; /*1=fcc, 2=etsi, 3=mic*/ + u8 det_type; /*0=none, 1=pw(chirp), 2=pri(radar)*/ + __le16 pw_chirp_type; + u8 pw_chirp_idx; + u8 pw_value; + u8 pri_radar_type; + u8 pri_bincnt; + u8 bin_counter[NXPWIFI_BIN_COUNTER_LEN]; + u8 num_dfs_records; + u8 dfs_record_hdr[NXPWIFI_DFS_REC_HDR_NUM][NXPWIFI_DFS_REC_HDR_LEN]; + __le32 passed; +} __packed; + +struct nxpwifi_ie_types_multi_chan_info { + struct nxpwifi_ie_types_header header; + __le16 status; + u8 tlv_buffer[]; +} __packed; + +struct nxpwifi_ie_types_mc_group_info { + struct nxpwifi_ie_types_header header; + u8 chan_group_id; + u8 chan_buf_weight; + u8 band_config; + u8 chan_num; + __le32 chan_time; + __le32 reserved; + union { + u8 sdio_func_num; + u8 usb_ep_num; + } hid_num; + u8 intf_num; + u8 bss_type_numlist[]; +} __packed; + +#define MEAS_RPT_MAP_RADAR_MASK 0x08 +#define MEAS_RPT_MAP_RADAR_SHIFT_BIT 3 + +struct nxpwifi_ie_types_chan_rpt_data { + struct nxpwifi_ie_types_header header; + u8 meas_rpt_map; +} __packed; + +struct host_cmd_ds_802_11_subsc_evt { + __le16 action; + __le16 events; +} __packed; + +struct chan_switch_result { + u8 cur_chan; + u8 status; + u8 reason; +} __packed; + +struct nxpwifi_ie { + __le16 ie_index; + __le16 mgmt_subtype_mask; + __le16 ie_length; + u8 ie_buffer[IEEE_MAX_IE_SIZE]; +} __packed; + +#define MAX_MGMT_IE_INDEX 16 +struct nxpwifi_ie_list { + __le16 type; + __le16 len; + struct nxpwifi_ie ie_list[MAX_MGMT_IE_INDEX]; +} __packed; + +struct coalesce_filt_field_param { + u8 operation; + u8 operand_len; + __le16 offset; + u8 operand_byte_stream[4]; +}; + +struct coalesce_receive_filt_rule { + struct nxpwifi_ie_types_header header; + u8 num_of_fields; + u8 pkt_type; + __le16 max_coalescing_delay; + struct coalesce_filt_field_param params[]; +} __packed; + +struct host_cmd_ds_coalesce_cfg { + __le16 action; + __le16 num_of_rules; + u8 rule_data[]; +} __packed; + +struct host_cmd_ds_multi_chan_policy { + __le16 action; + __le16 policy; +} __packed; + +struct host_cmd_ds_robust_coex { + __le16 action; + __le16 reserved; +} __packed; + +struct host_cmd_ds_wakeup_reason { + __le16 wakeup_reason; +} __packed; + +struct host_cmd_ds_gtk_rekey_params { + __le16 action; + u8 kck[NL80211_KCK_LEN]; + u8 kek[NL80211_KEK_LEN]; + __le32 replay_ctr_low; + __le32 replay_ctr_high; +} __packed; + +struct host_cmd_ds_chan_region_cfg { + __le16 action; +} __packed; + +struct host_cmd_ds_pkt_aggr_ctrl { + __le16 action; + __le16 enable; + __le16 tx_aggr_max_size; + __le16 tx_aggr_max_num; + __le16 tx_aggr_align; +} __packed; + +struct host_cmd_ds_sta_configure { + __le16 action; + u8 tlv_buffer[]; +} __packed; + +struct nxpwifi_ie_types_sta_flag { + struct nxpwifi_ie_types_header header; + __le32 sta_flags; +} __packed; + +struct host_cmd_ds_add_station { + __le16 action; + __le16 aid; + u8 peer_mac[ETH_ALEN]; + __le32 listen_interval; + __le16 cap_info; + u8 tlv[]; +} __packed; + +struct host_cmd_ds_command { + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; + union { + struct host_cmd_ds_get_hw_spec hw_spec; + struct host_cmd_ds_mac_control mac_ctrl; + struct host_cmd_ds_802_11_mac_address mac_addr; + struct host_cmd_ds_mac_multicast_adr mc_addr; + struct host_cmd_ds_802_11_get_log get_log; + struct host_cmd_ds_802_11_rssi_info rssi_info; + struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp; + struct host_cmd_ds_802_11_snmp_mib smib; + struct host_cmd_ds_tx_rate_query tx_rate; + struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; + struct host_cmd_ds_txpwr_cfg txp_cfg; + struct host_cmd_ds_rf_tx_pwr txp; + struct host_cmd_ds_rf_ant_mimo ant_mimo; + struct host_cmd_ds_rf_ant_siso ant_siso; + struct host_cmd_ds_802_11_ps_mode_enh psmode_enh; + struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg; + struct host_cmd_ds_802_11_scan scan; + struct host_cmd_ds_802_11_scan_ext ext_scan; + struct host_cmd_ds_802_11_scan_rsp scan_resp; + struct host_cmd_ds_802_11_bg_scan_config bg_scan_config; + struct host_cmd_ds_802_11_bg_scan_query bg_scan_query; + struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp; + struct host_cmd_ds_802_11_associate associate; + struct host_cmd_ds_802_11_associate_rsp associate_rsp; + struct host_cmd_ds_802_11_deauthenticate deauth; + struct host_cmd_ds_802_11d_domain_info domain_info; + struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp; + struct host_cmd_ds_11n_addba_req add_ba_req; + struct host_cmd_ds_11n_addba_rsp add_ba_rsp; + struct host_cmd_ds_11n_delba del_ba; + struct host_cmd_ds_txbuf_cfg tx_buf; + struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl; + struct host_cmd_ds_11n_cfg htcfg; + struct host_cmd_ds_wmm_get_status get_wmm_status; + struct host_cmd_ds_802_11_key_material key_material; + struct host_cmd_ds_version_ext verext; + struct host_cmd_ds_mgmt_frame_reg reg_mask; + struct host_cmd_ds_remain_on_chan roc_cfg; + struct host_cmd_ds_802_11_ibss_status ibss_coalescing; + struct host_cmd_ds_mef_cfg mef_cfg; + struct host_cmd_ds_mem_access mem; + struct host_cmd_ds_mac_reg_access mac_reg; + struct host_cmd_ds_bbp_reg_access bbp_reg; + struct host_cmd_ds_rf_reg_access rf_reg; + struct host_cmd_ds_pmic_reg_access pmic_reg; + struct host_cmd_ds_set_bss_mode bss_mode; + struct host_cmd_ds_pcie_details pcie_host_spec; + struct host_cmd_ds_802_11_eeprom_access eeprom; + struct host_cmd_ds_802_11_subsc_evt subsc_evt; + struct host_cmd_ds_sys_config uap_sys_config; + struct host_cmd_ds_sta_deauth sta_deauth; + struct host_cmd_ds_sta_list sta_list; + struct host_cmd_11ac_vht_cfg vht_cfg; + struct host_cmd_ds_coalesce_cfg coalesce_cfg; + struct host_cmd_ds_chan_rpt_req chan_rpt_req; + struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; + struct host_cmd_ds_multi_chan_policy mc_policy; + struct host_cmd_ds_robust_coex coex; + struct host_cmd_ds_wakeup_reason hs_wakeup_reason; + struct host_cmd_ds_gtk_rekey_params rekey; + struct host_cmd_ds_chan_region_cfg reg_cfg; + struct host_cmd_ds_pkt_aggr_ctrl pkt_aggr_ctrl; + struct host_cmd_ds_sta_configure sta_cfg; + struct host_cmd_ds_add_station sta_info; + } params; +} __packed; + +struct nxpwifi_opt_sleep_confirm { + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; + __le16 action; + __le16 resp_ctrl; +} __packed; + +struct hw_spec_max_conn { + struct nxpwifi_ie_types_header header; + u8 reserved; + u8 max_sta_conn; +} __packed; + +#define VDLL_IND_TYPE_REQ 0 +#define VDLL_IND_TYPE_OFFSET 1 +#define VDLL_IND_TYPE_ERR_SIG 2 +#define VDLL_IND_TYPE_ERR_ID 3 +#define VDLL_IND_TYPE_SEC_ERR_ID 4 +#define VDLL_IND_TYPE_INTF_RESET 5 + +struct vdll_ind_event { + __le16 type; + __le16 vdll_id; + __le32 offset; + __le16 block_len; +} __packed; + +#endif /* !_NXPWIFI_FW_H_ */ From patchwork Fri Aug 9 09:45:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818389 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 12DF21953AB; Fri, 9 Aug 2024 09:47:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196827; cv=fail; b=BjxVbxDHoP17Ix0bVr7DQGyzLC4H9/ENPZeF4PVhv7xJOkF1vMJanMZervQkvgGylEzzurPDYPTZNB+zlKKJjoL8btkt2q1MzLig2qEhoFqfVbOATliIGOzm71OQxW5Wo+RLYTXwY17x7I3RlW3e2MagUj0RnuCBJvSH1ZAnJQ4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196827; c=relaxed/simple; bh=hK7zOgcNjCbIKSwTuKqkFzBfM58GUiUG2NZiiwmSfnE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=YgIYgkWswuOEf/8/24Vk2kdeD1WCal2weYsKcPtTG5c7UZTjsnWzFrQoJTApX5J97NZVSN/QbBgpbPPb8eoBg1wswig+5pyA7/VsmI8zCaLZknn/8tVhgtDvswJp/z34hkIzESQdd7rdzKELjCzL/SNzs+pKbhDuUg7lSz3ML6o= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=i/WEKTQL; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="i/WEKTQL" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=zDZivfAiMM2hYl0UIndA3i47xLpB7OY2PkKTFosfuS02ltr6zbGEXtZ5XObq8osJTtO5VWSRA0G0bQystgt8dk9Z8TRIXqnDbzy8MoY0Hk/ilNXQpG3rA0JEEF+mwhgJGO8riRRGluVH2fQCpB+UFMQfJ/8fyP8jDFY40H2uFreDXTzmiG5b4ga6lrdKs4ufIHwKJgA1pzyZFSG0BdWGJOFnYYde1CR7GipVp6CSia12fs7i/dpxOKywv2PVSjrwQ4b8bGh5AaoBhAbMr0RWE9xuFlTbli39lsK5sQvuf3xPis+xYL+XVR/5Di8/dmJE5JWZalRQAHkk4Rk1vzBOIw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=GlL3lNRkNR2Ks9TWo9qIvoqcIZ83j5ygjGypIb8mm10=; b=tZYFivJXfFpLXu3VDjYdPD9p8Uo4QX3R+XV1nYnpYgCW4XT1Quqj5prAmgNYR5RcOYI6zqrTeACzxy2esurJHzWhAev3vS/0y9YzIgwbQkrqrANOuhPDxGdK6OgWWrgmVY4rpdn6TtOlqlru3RHYAUjjehnCWykrRpTWP3PErofxZaUV2RbIS6pmkTzQBxShmBgv9Td5e4YxZzf0lkjZP9WIa/gAwLiLTia0x5rJZ5yuqxLjDhmivleSLPJJ16cOps8JBTHjTlnV1sEgy9tL8EXYWGoY3zt6CUoF0ZWo1oPI4RWSstr1+owLnDlNr8CJCGtUrGyhe5rWXMKjszkY4Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=GlL3lNRkNR2Ks9TWo9qIvoqcIZ83j5ygjGypIb8mm10=; b=i/WEKTQL0zEiS5DRVy5vJjxKGGfP6nuydWWPkNeL29W9wWxjRhhPtxk1GjLwaKgwZi6TXJjAUaD+8GRzG7V56F9M6Lf2qGkTeJW7Dqraj/HvLyfBmhKORUfFwWf64055k4YnVJuNDal1zSVOv0DKT6wHUuXOG23oUjwJUK8lp6mQkZBocl3eNd3d8jDDxXOQhW4uX3V/mSj9kw4Vl+rj1FZ7DcN28QTm6cDp8zCwmQWMl7L6jg/54NkRhIcX++BlXcCDKUm+upBiA9+cuo8k3vpoF5+tRtyCXY6eoraSxdQzoshr76fiOE1hG3jsGjIHgktVZ4UeTNp2ooPctPqUIg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:46:56 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:46:56 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 20/43] wifi: nxpwifi: add ie.c Date: Fri, 9 Aug 2024 17:45:10 +0800 Message-Id: <20240809094533.1660-21-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: 898e70b0-5eee-4a10-f227-08dcb85834da X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: 5wzXYlrDG2h6kMb1fPKxpqq6hLIp32o2EGCRD8U/YDB0Gwe8BGs1eZVSzHH5EDofhzCsPE/3MUmxjGbaRBSqYMOtTMWrKw5HFG9c/+3bnE45HklR1MIm4POBSkWpaeKZyroixUfbkoXyKjGMI9Zuq6KoPVPU1PW+ODXay5PiZh8V/57pIP1H3kd05+kMiNP/skO5ZGlVR6OzpsxzrNv58l1F+myVK3Luga9dmq5ilB2hNKy5NnwYMKFEshKgKFeqxm3/NQ/JqZbIA8EFXLMUdVVVydaxFrByH1a+KLW8u8iZj9EZhJHHlIazUQP5qQcFCFAf5wH+wRYXUM5HFrUzgIVWHWl3T04O/dFmAfqwMkK8VElsuW0f/DRVVfTpgMzO4PnMjdxz00sPZUiCQxqK+AUNMhtHremZbmFlZXRQ6J9TyHXSspEp0M7cFSe0aTcCAPFnYRqKLhNlgsAEVYS+LOhc0ljBpvkAKNTu+lu5T8pCKRpBmSSjO1Ic5kXRHZmL5nuO3a4pfE+vpTZEP2v4EeXTxLvz9IXqJgA8q1YZo4rc3DR0QyNwzmnT/1JQXfxvTAIxvr+g6HVdIFXvcOZ3A369VaUS2LyNM04fas/ED2xAdlIeEgZLuiC3jfDPe2MfwZXg9O+RXflj3SLywx4JMRE4ZX+Y3m7C7IeubFzXsCl0FZOWRPeN3pcOP3O9BI6CKfNBa+waVdUP0SXhnB4fUC9tciNbO8OkjCdffEOK14l1gGnK8BRiedfw5MgpB8YbNORxteOiiJR3MKQu6335hO89bWt2k6IPuduDCo6V0wyAhpnWHUfoaOhlzPKmflyxPSdofKMxpEJHw0IMLoHjo3YHZ0U/v4bNyDKBIs7Sr46Qq+lLF1q8q4MJAAvjsjy5Zxl++A53E35L9VCHMrp8olkVaeJtdsGvG8gVFLmhxyhFIz51WAQX2BpE6uECu5/jbSdCKoa1y5nf0WAellI14unCrA7PPkwu6BJ5aGdL2Eb9ffnfQdC7j3vF8bUzTIfiZVEPbAsRCbtElDbhvhroknokoN/TAB5IxjzgslgoCw1euSCb3ym02CThncUPW1u7hJV5CfADShemL07YBwE9aSdpNmUvZXSRMrHpByq4Eov1W0J8Q3JROeLBVcZlOurbI9I+Wi2ayNbSsRw5KZRn4cLPbLiVAJwzPT2FtM5WoKP24E880M+Wi6dKZ1niyLKeSF6IdZlBhnjmFnFWXyxj0SUXFUseDjPOj3xS355HHyPh/TgThj4O4i4C9qMqwgk3GpA0Ae1Xuvy83TXOxJ8aPnOawBon9YSIsU+mHmYShqP8LjmzGgnTxY+cTCsOSPldcPG8DoiG18jRUAXnSv4ULw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: fbZXaNYiyCxrOnQgDYBup9wk0s3iR5mMnWz7xA5FkGT1K8pPs5h9KZIOjCu5ZEUxH8KFOnPnwf2TDp98FdBHQTbS4/KRU6AEKc5HQE8dyyX3azKSGOZ3JQGzQyyXa2q7HRrlPHnEV/xJU023y1umKZu3Na22d/G0c8wAZGmrahZ/mGwaiMq3MRiMFFBqn6ahB9DkAF87QyH0svny01hYcXZaw4mePTqc8HIqabW//F+2Z5p2Vg2v/pz6fjleWkWeB7LbHwWSqxIVzho/2PN7GCyCGVS6LMfEzxolVN23IKzHESpvIoHbScgJ6cbDSRZ5snMq2SDfL2wKUJ74n26dwq4TNSACmr2tGBI+wrtRUK1lEfZM7NnI4bCxLb7WLVE9JhZNGpv3Ls4U5A1QJd9enB2Zmgs9o8zssfcgUSBHv3KzrGAHTHNYDUtwC2qNpVw/y20F5oolhZG1ik+qV+PjKrAgi7BfVIK7+YE+pyAqPTBQki7zvIg974LIdV49Wc0eQT12WwSGdT+MNZHaYbgXiTv/qfiL83h5f5ElHhO3b9cleT6E32FDdjV2Ukwc3HsDR/2z0mHMbSfDpwyvEtjWROBTqyJ9MdN1AysMmmqWbG/EiIWMAlWIhXMb6eorlIXZan9e1vMljCZ8WXMFlocP7k28COkAu8JyboIAmIC1xMMjzsrOo5jkz+0fdKBsr1ELYGONUcFh8e3El1kXMfowyl+yYoZ1F/5/A7BbNGUt1jd49M2rSvqUUnwOY+HnuDF5P09QWBPa2iBK3b7WHXmfI7pYA15ns1NWnPsZqX6gkX4jliTbKShO00SMhvoYhUBIg0sqCZ2haq0sxucqcomhiIQ3cukqbtJpDLJTtjFCGwChkBEU/ahkdfk43z4KtS1wp28AQ6wMHz0PQv1xPp2AlaAmGJK1oRZanedL9E1+wvVPuyoK09H8Oh3K/+St88eEHdpBxWGQCiKSr0MPFDjtfAXPhVjh2fn5tXvIec2dN4ivWFHbwBJOyvXGraExf3BBvaN4jw2WAy80JiPiCy1Ac7bZV7S52dVIavtEKORtlj0JGkIYectDBHgk0IXsaKvShqkXJXkx9brE5imI4fZjDkSdi1GMcEctUX6oOLQngDkTG7DLgaLOR2kC7OrdVFXr0BUeoOLsr03NPM1H3dCnyeNNoRS1+dudV746YXphDhNe72yuj5krNS4b82YWVYY5nN4wuM9NqHCr3RbpYpnPSPO13UVagsx66G+40pDrS9dP3ppFtDz4hRqPzfau9GES8TQa56rH4Drb7AoiIxeMr+OjI0l1/2eLN/Mhg7XCjpmWWrzsGSDP9JtMCu9+jLgx0FTlp63q58VXEfXgzD9YFrpGfiLpV1VYDzi8jOKcFfhEpkzyZ8c9Bg0NVgStmptgHDDghTtYwJRZhLl+rKjitGfJBfxPo/8zZ3QJs9hkZPW8n9TE99GKIwFTCw2pgLOB9IGsLVTyhBEtdVYdZer8ENs0YoOMuYYSuzJ/PfE+Ok3OZ9/oMyb+HZmH0ykGVV5OqLkWwDCUag2/4rhN8wIPXJc8jkRqGmzVHjYnkrh+gIgaaTWYdxlSPH32B8HWHdJIJJqLs0IByUUrzxU1Kuhz9ZBqPMCEDOb+vwNc9jMWhlSXkjcMPT9jajqSN2q5AoJ5 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 898e70b0-5eee-4a10-f227-08dcb85834da X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:56.6735 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: mXnAMe67PhX7UZI3NARWw5cej0gpXiiblq3DSOCyKmqpJQZ/PmZWO8QREwHIlVNBFU5ovPvzm/z5DvNToUcb0w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/ie.c | 501 ++++++++++++++++++++++++++ 1 file changed, 501 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/ie.c diff --git a/drivers/net/wireless/nxp/nxpwifi/ie.c b/drivers/net/wireless/nxp/nxpwifi/ie.c new file mode 100644 index 000000000000..15bdc3c7a6fa --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/ie.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: management IE handling- setting and + * deleting IE. + * + * Copyright 2011-2024 NXP + */ + +#include "main.h" +#include "cmdevt.h" + +/* This function checks if current IE index is used by any on other interface. + * Return: true: yes, current IE index is used by someone else. + * false: no, current IE index is NOT used by other interface. + */ +static bool +nxpwifi_ie_index_used_by_other_intf(struct nxpwifi_private *priv, u16 idx) +{ + int i; + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_ie *ie; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i] != priv) { + ie = &adapter->priv[i]->mgmt_ie[idx]; + if (ie->mgmt_subtype_mask && ie->ie_length) + return true; + } + } + + return false; +} + +/* Get unused IE index. This index will be used for setting new IE */ +static int +nxpwifi_ie_get_autoidx(struct nxpwifi_private *priv, u16 subtype_mask, + struct nxpwifi_ie *ie, u16 *index) +{ + u16 mask, len, i; + + for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) { + mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask); + len = le16_to_cpu(ie->ie_length); + + if (mask == NXPWIFI_AUTO_IDX_MASK) + continue; + + if (mask == subtype_mask) { + if (len > IEEE_MAX_IE_SIZE) + continue; + + *index = i; + return 0; + } + + if (!priv->mgmt_ie[i].ie_length) { + if (nxpwifi_ie_index_used_by_other_intf(priv, i)) + continue; + + *index = i; + return 0; + } + } + + return -ENOENT; +} + +/* This function prepares IE data buffer for command to be sent to FW */ +static int +nxpwifi_update_autoindex_ies(struct nxpwifi_private *priv, + struct nxpwifi_ie_list *ie_list) +{ + u16 travel_len, index, mask; + s16 input_len, tlv_len; + struct nxpwifi_ie *ie; + u8 *tmp; + + input_len = le16_to_cpu(ie_list->len); + travel_len = sizeof(struct nxpwifi_ie_types_header); + + ie_list->len = 0; + + while (input_len >= sizeof(struct nxpwifi_ie_types_header)) { + ie = (struct nxpwifi_ie *)(((u8 *)ie_list) + travel_len); + tlv_len = le16_to_cpu(ie->ie_length); + travel_len += tlv_len + NXPWIFI_IE_HDR_SIZE; + + if (input_len < tlv_len + NXPWIFI_IE_HDR_SIZE) + return -EINVAL; + index = le16_to_cpu(ie->ie_index); + mask = le16_to_cpu(ie->mgmt_subtype_mask); + + if (index == NXPWIFI_AUTO_IDX_MASK) { + /* automatic addition */ + if (nxpwifi_ie_get_autoidx(priv, mask, ie, &index)) + return -ENOENT; + if (index == NXPWIFI_AUTO_IDX_MASK) + return -EINVAL; + + tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer; + memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length)); + priv->mgmt_ie[index].ie_length = ie->ie_length; + priv->mgmt_ie[index].ie_index = cpu_to_le16(index); + priv->mgmt_ie[index].mgmt_subtype_mask = + cpu_to_le16(mask); + + ie->ie_index = cpu_to_le16(index); + } else { + if (mask != NXPWIFI_DELETE_MASK) + return -EINVAL; + /* Check if this index is being used on any + * other interface. + */ + if (nxpwifi_ie_index_used_by_other_intf(priv, index)) + return -EPERM; + + ie->ie_length = 0; + memcpy(&priv->mgmt_ie[index], ie, + sizeof(struct nxpwifi_ie)); + } + + le16_unaligned_add_cpu + (&ie_list->len, + le16_to_cpu(priv->mgmt_ie[index].ie_length) + + NXPWIFI_IE_HDR_SIZE); + input_len -= tlv_len + NXPWIFI_IE_HDR_SIZE; + } + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) + return nxpwifi_send_cmd(priv, HOST_CMD_UAP_SYS_CONFIG, + HOST_ACT_GEN_SET, + UAP_CUSTOM_IE_I, ie_list, true); + + return 0; +} + +/* Copy individual custom IEs for beacon, probe response and assoc response + * and prepare single structure for IE setting. + * This function also updates allocated IE indices from driver. + */ +static int +nxpwifi_update_uap_custom_ie(struct nxpwifi_private *priv, + struct nxpwifi_ie *beacon_ie, u16 *beacon_idx, + struct nxpwifi_ie *pr_ie, u16 *probe_idx, + struct nxpwifi_ie *ar_ie, u16 *assoc_idx) +{ + struct nxpwifi_ie_list *ap_custom_ie; + u8 *pos; + u16 len; + int ret; + + ap_custom_ie = kzalloc(sizeof(*ap_custom_ie), GFP_KERNEL); + if (!ap_custom_ie) + return -ENOMEM; + + ap_custom_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE); + pos = (u8 *)ap_custom_ie->ie_list; + + if (beacon_ie) { + len = sizeof(struct nxpwifi_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(beacon_ie->ie_length); + memcpy(pos, beacon_ie, len); + pos += len; + le16_unaligned_add_cpu(&ap_custom_ie->len, len); + } + if (pr_ie) { + len = sizeof(struct nxpwifi_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(pr_ie->ie_length); + memcpy(pos, pr_ie, len); + pos += len; + le16_unaligned_add_cpu(&ap_custom_ie->len, len); + } + if (ar_ie) { + len = sizeof(struct nxpwifi_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(ar_ie->ie_length); + memcpy(pos, ar_ie, len); + pos += len; + le16_unaligned_add_cpu(&ap_custom_ie->len, len); + } + + ret = nxpwifi_update_autoindex_ies(priv, ap_custom_ie); + + pos = (u8 *)(&ap_custom_ie->ie_list[0].ie_index); + if (beacon_ie && *beacon_idx == NXPWIFI_AUTO_IDX_MASK) { + /* save beacon ie index after auto-indexing */ + *beacon_idx = le16_to_cpu(ap_custom_ie->ie_list[0].ie_index); + len = sizeof(*beacon_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(beacon_ie->ie_length); + pos += len; + } + if (pr_ie && le16_to_cpu(pr_ie->ie_index) == NXPWIFI_AUTO_IDX_MASK) { + /* save probe resp ie index after auto-indexing */ + *probe_idx = *((u16 *)pos); + len = sizeof(*pr_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(pr_ie->ie_length); + pos += len; + } + if (ar_ie && le16_to_cpu(ar_ie->ie_index) == NXPWIFI_AUTO_IDX_MASK) + /* save assoc resp ie index after auto-indexing */ + *assoc_idx = *((u16 *)pos); + + kfree(ap_custom_ie); + return ret; +} + +/* This function checks if the vendor specified IE is present in passed buffer + * and copies it to nxpwifi_ie structure. + * Function takes pointer to struct nxpwifi_ie pointer as argument. + * If the vendor specified IE is present then memory is allocated for + * nxpwifi_ie pointer and filled in with IE. Caller should take care of freeing + * this memory. + */ +static int nxpwifi_update_vs_ie(const u8 *ies, int ies_len, + struct nxpwifi_ie **ie_ptr, u16 mask, + unsigned int oui, u8 oui_type) +{ + struct element *vs_ie; + struct nxpwifi_ie *ie = *ie_ptr; + const u8 *vendor_ie; + + vendor_ie = cfg80211_find_vendor_ie(oui, oui_type, ies, ies_len); + if (vendor_ie) { + if (!*ie_ptr) { + *ie_ptr = kzalloc(sizeof(*ie_ptr), GFP_KERNEL); + if (!*ie_ptr) + return -ENOMEM; + ie = *ie_ptr; + } + + vs_ie = (struct element *)vendor_ie; + if (le16_to_cpu(ie->ie_length) + vs_ie->datalen + 2 > + IEEE_MAX_IE_SIZE) + return -EINVAL; + memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length), + vs_ie, vs_ie->datalen + 2); + le16_unaligned_add_cpu(&ie->ie_length, vs_ie->datalen + 2); + ie->mgmt_subtype_mask = cpu_to_le16(mask); + ie->ie_index = cpu_to_le16(NXPWIFI_AUTO_IDX_MASK); + } + + *ie_ptr = ie; + return 0; +} + +/* This function parses beacon IEs, probe response IEs, association response IEs + * from cfg80211_ap_settings->beacon and sets these IE to FW. + */ +static int nxpwifi_set_mgmt_beacon_data_ies(struct nxpwifi_private *priv, + struct cfg80211_beacon_data *data) +{ + struct nxpwifi_ie *beacon_ie = NULL, *pr_ie = NULL, *ar_ie = NULL; + u16 beacon_idx = NXPWIFI_AUTO_IDX_MASK, pr_idx = NXPWIFI_AUTO_IDX_MASK; + u16 ar_idx = NXPWIFI_AUTO_IDX_MASK; + int ret = 0; + + if (data->beacon_ies && data->beacon_ies_len) { + nxpwifi_update_vs_ie(data->beacon_ies, data->beacon_ies_len, + &beacon_ie, MGMT_MASK_BEACON, + WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPS); + nxpwifi_update_vs_ie(data->beacon_ies, data->beacon_ies_len, + &beacon_ie, MGMT_MASK_BEACON, + WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P); + } + + if (data->proberesp_ies && data->proberesp_ies_len) { + nxpwifi_update_vs_ie(data->proberesp_ies, + data->proberesp_ies_len, &pr_ie, + MGMT_MASK_PROBE_RESP, WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPS); + nxpwifi_update_vs_ie(data->proberesp_ies, + data->proberesp_ies_len, &pr_ie, + MGMT_MASK_PROBE_RESP, + WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P); + } + + if (data->assocresp_ies && data->assocresp_ies_len) { + nxpwifi_update_vs_ie(data->assocresp_ies, + data->assocresp_ies_len, &ar_ie, + MGMT_MASK_ASSOC_RESP | + MGMT_MASK_REASSOC_RESP, + WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPS); + nxpwifi_update_vs_ie(data->assocresp_ies, + data->assocresp_ies_len, &ar_ie, + MGMT_MASK_ASSOC_RESP | + MGMT_MASK_REASSOC_RESP, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P); + } + + if (beacon_ie || pr_ie || ar_ie) { + ret = nxpwifi_update_uap_custom_ie(priv, beacon_ie, + &beacon_idx, pr_ie, + &pr_idx, ar_ie, &ar_idx); + if (ret) + goto done; + } + + priv->beacon_idx = beacon_idx; + priv->proberesp_idx = pr_idx; + priv->assocresp_idx = ar_idx; + +done: + kfree(beacon_ie); + kfree(pr_ie); + kfree(ar_ie); + + return ret; +} + +/* This function parses head and tail IEs, from cfg80211_beacon_data and sets + * these IE to FW. + */ +static int nxpwifi_uap_parse_tail_ies(struct nxpwifi_private *priv, + struct cfg80211_beacon_data *info) +{ + struct nxpwifi_ie *gen_ie; + struct element *hdr; + struct ieee80211_vendor_ie *vendorhdr; + u16 gen_idx = NXPWIFI_AUTO_IDX_MASK, ie_len = 0; + int left_len, parsed_len = 0; + unsigned int token_len; + int ret = 0; + + if (!info->tail || !info->tail_len) + return 0; + + gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL); + if (!gen_ie) + return -ENOMEM; + + left_len = info->tail_len; + + /* Many IEs are generated in FW by parsing bss configuration. + * Let's not add them here; else we may end up duplicating these IEs + */ + while (left_len > sizeof(struct element)) { + hdr = (void *)(info->tail + parsed_len); + token_len = hdr->datalen + sizeof(struct element); + if (token_len > left_len) { + ret = -EINVAL; + goto done; + } + + switch (hdr->id) { + case WLAN_EID_SSID: + case WLAN_EID_SUPP_RATES: + case WLAN_EID_COUNTRY: + case WLAN_EID_PWR_CONSTRAINT: + case WLAN_EID_ERP_INFO: + case WLAN_EID_EXT_SUPP_RATES: + case WLAN_EID_HT_CAPABILITY: + case WLAN_EID_HT_OPERATION: + case WLAN_EID_VHT_CAPABILITY: + case WLAN_EID_VHT_OPERATION: + break; + case WLAN_EID_VENDOR_SPECIFIC: + /* Skip only Microsoft WMM IE */ + if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WMM, + (const u8 *)hdr, + token_len)) + break; + fallthrough; + default: + if (ie_len + token_len > IEEE_MAX_IE_SIZE) { + ret = -EINVAL; + goto done; + } + memcpy(gen_ie->ie_buffer + ie_len, hdr, token_len); + ie_len += token_len; + break; + } + left_len -= token_len; + parsed_len += token_len; + } + + /* parse only WPA vendor IE from tail, WMM IE is configured by + * bss_config command + */ + vendorhdr = (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + info->tail, info->tail_len); + if (vendorhdr) { + token_len = vendorhdr->len + sizeof(struct element); + if (ie_len + token_len > IEEE_MAX_IE_SIZE) { + ret = -EINVAL; + goto done; + } + memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, token_len); + ie_len += token_len; + } + + if (!ie_len) + goto done; + + gen_ie->ie_index = cpu_to_le16(gen_idx); + gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | + MGMT_MASK_PROBE_RESP | + MGMT_MASK_ASSOC_RESP); + gen_ie->ie_length = cpu_to_le16(ie_len); + + ret = nxpwifi_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, + NULL, NULL, NULL); + + if (ret) + goto done; + + priv->gen_idx = gen_idx; + + done: + kfree(gen_ie); + return ret; +} + +/* This function parses different IEs-head & tail IEs, beacon IEs, + * probe response IEs, association response IEs from cfg80211_ap_settings + * function and sets these IE to FW. + */ +int nxpwifi_set_mgmt_ies(struct nxpwifi_private *priv, + struct cfg80211_beacon_data *info) +{ + int ret; + + ret = nxpwifi_uap_parse_tail_ies(priv, info); + + if (ret) + return ret; + + return nxpwifi_set_mgmt_beacon_data_ies(priv, info); +} + +/* This function removes management IE set */ +int nxpwifi_del_mgmt_ies(struct nxpwifi_private *priv) +{ + struct nxpwifi_ie *beacon_ie = NULL, *pr_ie = NULL; + struct nxpwifi_ie *ar_ie = NULL, *gen_ie = NULL; + int ret = 0; + + if (priv->gen_idx != NXPWIFI_AUTO_IDX_MASK) { + gen_ie = kmalloc(sizeof(*gen_ie), GFP_KERNEL); + if (!gen_ie) + return -ENOMEM; + + gen_ie->ie_index = cpu_to_le16(priv->gen_idx); + gen_ie->mgmt_subtype_mask = cpu_to_le16(NXPWIFI_DELETE_MASK); + gen_ie->ie_length = 0; + ret = nxpwifi_update_uap_custom_ie(priv, gen_ie, &priv->gen_idx, + NULL, &priv->proberesp_idx, + NULL, &priv->assocresp_idx); + if (ret) + goto done; + + priv->gen_idx = NXPWIFI_AUTO_IDX_MASK; + } + + if (priv->beacon_idx != NXPWIFI_AUTO_IDX_MASK) { + beacon_ie = kmalloc(sizeof(*beacon_ie), GFP_KERNEL); + if (!beacon_ie) { + ret = -ENOMEM; + goto done; + } + beacon_ie->ie_index = cpu_to_le16(priv->beacon_idx); + beacon_ie->mgmt_subtype_mask = cpu_to_le16(NXPWIFI_DELETE_MASK); + beacon_ie->ie_length = 0; + } + if (priv->proberesp_idx != NXPWIFI_AUTO_IDX_MASK) { + pr_ie = kmalloc(sizeof(*pr_ie), GFP_KERNEL); + if (!pr_ie) { + ret = -ENOMEM; + goto done; + } + pr_ie->ie_index = cpu_to_le16(priv->proberesp_idx); + pr_ie->mgmt_subtype_mask = cpu_to_le16(NXPWIFI_DELETE_MASK); + pr_ie->ie_length = 0; + } + if (priv->assocresp_idx != NXPWIFI_AUTO_IDX_MASK) { + ar_ie = kmalloc(sizeof(*ar_ie), GFP_KERNEL); + if (!ar_ie) { + ret = -ENOMEM; + goto done; + } + ar_ie->ie_index = cpu_to_le16(priv->assocresp_idx); + ar_ie->mgmt_subtype_mask = cpu_to_le16(NXPWIFI_DELETE_MASK); + ar_ie->ie_length = 0; + } + + if (beacon_ie || pr_ie || ar_ie) + ret = nxpwifi_update_uap_custom_ie(priv, + beacon_ie, &priv->beacon_idx, + pr_ie, &priv->proberesp_idx, + ar_ie, &priv->assocresp_idx); + +done: + kfree(gen_ie); + kfree(beacon_ie); + kfree(pr_ie); + kfree(ar_ie); + + return ret; +} From patchwork Fri Aug 9 09:45:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818274 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 97F55198E7A; Fri, 9 Aug 2024 09:47:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196830; cv=fail; b=pIZItuPSEkYfFYk9Wi9zS8ojIxd3PA+AVgJyXDrWcfEIy/HS8vVczMI7s2578uUcUfDRjA0V/tQCt9AjdC++z1NJXnGuO+CddMovXbLt62Mn/857i9CWkvH4HA0fWf0HRtk+49DNNN67uikNvDUe/1UfNzMjTXixdDEXStkHoQg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196830; c=relaxed/simple; bh=xKvPKqhPFcxDvxRT+XlZNSbIopHFE17bNCvofgIkhLk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=V20zr9/zAsL57vcdPp8gaIxqbghReltE1em74qvEbd3rb1ltgiJNPogwMU9KCpXiEJCCwhKxl6HpugZJoXIvqu+WqXn9PuR1f785JmOA25M3RXosJQSQvTsc/N2JIUlNjtCoTrX83nle4EdV/YDrw4mn/1YqisKKdZmPJdG2Z2I= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=JCMBySCC; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="JCMBySCC" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=xgXhGrjcSx5hh8VzF3/SslH+ChT3GArYgc/LHYC2UjvoXEq/TS438dwghv2qpE1Ezqp4OL+Nv6cyMd+A4Zg8PKf85ugWgYkWuItQFzIguCUtpRsucAeRLlUOFIVZBL/v++d8h92UmVUNOuHIG+1xR4QK+mUnl1BaWqFPQuvs1JH8z04redo1b6mkK1c2QcpBSzaDcI1I22/3EXMF5XdcpEUtJTqPwcHUPh7n+daOgEMrVB/c4euGMPkSubRyRx8Ejtg+KDxVwRC2LgcVXkheAQYthrKh1IbvP4Iiqa0WBeM86qpojMQApqrM966BsNANCGvvsgcVAKBnHAih8FvY+A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=RX4zDpOaQmJjyeDmV1jRuzlR3oeTKyOqQha4c+FLJ2o=; b=wledxYsNZSHzKQCRIb1V41DJjRZQE2wImYbYuXUrtIWh4EWtyq/QhSOe7pTMmTPHIHCK+ecfpV26lyj3maivezDlDEP9r/fBcn4DoXx+Hk67w/NBoosDfuTKSihfFd+eAYB53HCMN31mwRvQX3joBJzynGKSIr2OmZyaTdYwtKPWYIfboUGKmtCTpevBm0zAxOIPgqnpIo8cPNGmQHeOZCVq54XaCwF/SS+nsvBapTgayNJFJf+UxAWCW3YK3o8XTjkuoPnxiREzSaE3cb7UfkrZOqUIVyYaI5kOAAZ2ped1twW7G0ieDFPn0E8iP2NDTvIrUJ7C3y5MC2aJYY3YBw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=RX4zDpOaQmJjyeDmV1jRuzlR3oeTKyOqQha4c+FLJ2o=; b=JCMBySCC4RnqU/n41agO2OSojueJaZsSLz5yYsAYLtZ8lPVt2ObPVvUJ4g+J2tg6uayMoypRBqlJNCoUviStrGUNBERhlhk7MqEl76+PydPExAUy3HMYcHfLk8afy0N3AmdCTytdtrjni13yCQE53YMQukEangjEGcOBb8aPU+BGPtJDcnZ4Lm14zUTeHPHx14UcNlbJ57v+rBAGgIUoTS6sfUmSq7r3ORd/DWyW+AbeNLYURJnDY7Q/9kP8wsj8TwdO8MDyymly+iiBrgPkGc8Ml4QmbVndFRNafLiZFQYUIiviufytjIZ/03IVMY84LxNxchnhE/AZG2FFKqlgyg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:47:00 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:47:00 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 21/43] wifi: nxpwifi: add init.c Date: Fri, 9 Aug 2024 17:45:11 +0800 Message-Id: <20240809094533.1660-22-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: 02b93104-c698-47d7-a8ba-08dcb85836d1 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: Ukg7Xr0Bv3OFMzT27qLUYfEoo/sXkLcnnKwkr4tJNe4u/fVRqhhPf9cUPsok9xz+ANGYrAl5Sq1uNnt8Y00xmnOAk4jrdhtGwM20MyAVNqRisFMgC7VtuMItQAp3QJCiSMo45OzdsqOq5A1IX8n3Oxw0CfuUPnYc10hr9vH8IgugFIpluEnERAbzLy/kBK8iZsHLbpGaKFbuP9NZ4uKoauWepI/lB/y4thvjXIRNAbTWyaj2pNoX4MsaLksIDV+qbVYExEvUXtKXu/SJdYcY9t9ME12KEf8NZA3R7ZwDAnYEIbhvglw+qZUQ5vJXb0Ne2EKxaswHAeaFd3w18BVAkNSbqrSpsavOw7cFN88N5FYEe9rRvazW5El22JHU/+1+mSuxEg3/7G52zsUjFaaJraka2IPo6vJFTOumftI53rlF9TSfeZVs0eNuJq4dPilCHgN78hsPYrusV5YdzIv8MEKdSYR2uie58VoFqaQLNx5Zt2lR8oZaNoaQyXlXwMMuLPBoS3L6ifxlKLXPUU3orMYWUU5PxytVpj0/alhOxr/F0sW7sulaQJLPCord4LBtG7lIBfnp1IMOSaAJDCR81mSdIm8rSpBQDAOpBGTxw0VP5SXUTsyjiVl45tTdoR74G7QilRwWWSmTcSJtQPsOuu50v/dx5clrISw6n/eQhPs/fni3xzADfNpZhj+YO49a7/6R5F4KA8vhd3KNcLo4dHCqN6YZ9sI2WYj22jyHd3k5ye29vlGT39icM4/j2sS17/VCZ/3npacqitBN5wh5uZvqQ69ciKpchbb65L7TUVEOH3rJtIV62/DX2o3BR49xg4/nHKLV71yXadJdW2FruvMFTLhQetVe6ck8C9qqs1pUM0TpbMqL40BBRatqx+L4kzVt8uLbTKdUrc2FApCP3+eESU7Gc3zJHZkpfI561RrsqHNtWtpNaiSPphRYnKdooEQ8+88lFGk58/LeTmZaqprKYPRrqXRYNuB9rWHlBAIb1H+FJ63SHAUkeyOLCPNJutyuAdPkxVxJu05BY7YHoZlUU/abljQA+44GzZCdjbPXHkxGKlNErGtn1BC5wb/CFklPe+WXjNJGgBWd3R0SfIjRpE3xuhVqZoKdJk0hhWhmZU26iMeQLtT96iXPv/Ib2b871W55Z6vRrx+VuyAC3PXhBtYnLRPB32JJlGFc+dKTipAA+v3VIDR9+OwrF1A0NEm3l4ah1pt+iMy+iq85muBnvXmAGz88PfEsT12WOQBkrY8OhbrftJ25tQrVmpn6tdc6DPRW5YAFriBtjONXaO1nQ9V5AJ5Nkj1i/kjKkEuDHZBQzStgyuk7wHPWgPyx5d7xVa81OJL/+5KFYCMutw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 5nCvtqB1INoTecuF+I+WvJoNm6OjWMnkndPus/9yEBXVmhV9DUMf1y75BM7fSpfbdOFubtXOKDWE8kP/40kTS5egZCWSe975pPPtyo5gfg6Gyf3vlPbUD32gagRXK2dtL6wDGWVurB/VNJNMrXTy5VGPnf5sFBAq5OZIQICRtZ+AZwC5y5cJ/8X3w9yEn7F8VQJeEg1jVSK6+wRNGim1aNTrll4N0hwoAG7VkG8QB1gM7fyc5Q9cGrvoFF/6HVzfXdFGZZmVPbN7n09AtHBi6xs1S/m0B7KaowTx0g93sR0Gk80UBTIbGlLfym3OO31VmNX7E66binibzN0ptdEMrdwiw3EAXvDnM+A6mgZ8vKv36IkMC1Y3WamViX+kc0u7XSWdqmEzQNBUhVzvtrynubllTOYqT7gQm3p4NZ+OlYgkwMH6FzYSMGNzZ47X5sS8PDpSOEgcEWOmutgfw3gUYwZUQtLdJGDVXX5yGsz1UWUh6uyBwIifJEmZS4RvfORYiira5bEfVQDDLXQFDzVO1uP+H5pc4Riss+KT0OxOfMeQPA5rBkUVf9TiN8ZYEGhgZUjUjX90ppcjXrYiM5IfXjg18dWJ+jNxtd/8pEgOKgZeEVf05Axo/muALeq2oNtr9Rk68tf9UNMVD10zc0Cy3t6F2icuMjCATmePzjyIY92+g3i1gL2cDTnnNYkLLobWJA1foKmXsmaS1OvhzCVlQrSrr7i5fnvyCLlPVx3kOTvme0yq0sVTj1UzvGX97tvC9GG7Mfp9wE6s/c6Vw76mOE9MzcTTZ3kIuxNS5mP6NFXSa4Ja7NiwvQewvlej+j1i7owSiKPHoW7nKKxnDY3J54FU68DjpNzCWwVs0B6NpdqblOCwqxEcb2X5YyNrvHlSCfpzCYRKig92qU9m7TuigMJvwi8l+pwPK6JoidFGpRVKWMw6zwZfw7JJNoIZd6XxfHjv+LDIlGtOqVFuR66GeXLTd6mxvDWh2LMtOiUv59tlls2qtspFubU/ZlKasTVsjZtC8+/LtRYymrHaGGeWz7pkPqjgq0vx+cmczAknizrRZFWvEF6jIeoeLaFqMCStSXZ/akWjuwXhZw5/YeKIhcdqG7RTRUcFwyYGBB1mJGuxzTzA8pVKk58KJvLmbFXHA4A1wLPnOui+Tsea9wzOPtoQ/GEQZ2f+AkXNjXCTClT/uviRpgjENLwVRrvJE1+7d35Y77LdSsgiHrapczLEsFUZa/qp5W0Phl2VAmuuvE8prrse5K4K66YV+0GYZUTJXYQrj6HQcQxj8xPBVqdQzCPhwVNMGnRkzSY6lLeyvraH5kJnjoyd0tCgx/bXL8Mtox1thI+JUmBSqGkx0w7FKRyMLPgEsVSiC/7s0VftbFCzrCurZgRcDJCmv4WagrfWgX403pe1heAkMUZA4E0eLTiMD9TWVbvhayGBRukHkuleWzgCvRADli4Mwb7gPc8KRhC39zPPxADkXuaW7N13f7HWfEcWvFcWax1OO9jhiIO8bPX+5xgtdEAxc2KOEEzH7KhpMPbXuEYkVh44kkTFCJz5kc4llwO5Scj3oiAsJF4nnw04TmYWRxi0mM+sUkCa63rtvTHPa81wR0vuedgZ7NPzeTNCULrurT2qSQOkZUWlgJ0eZNZjstmH9S4QTzPl X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 02b93104-c698-47d7-a8ba-08dcb85836d1 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:46:59.9684 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: LG2tbCWYJsqyDQ8W8gLvNffKMvBdkiLRTrkyvp0LHIKAS6Jjj6p7fPzzUPtIEv8iUd62whpzNg+zlvo+cshmLw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/init.c | 694 ++++++++++++++++++++++++ 1 file changed, 694 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/init.c diff --git a/drivers/net/wireless/nxp/nxpwifi/init.c b/drivers/net/wireless/nxp/nxpwifi/init.c new file mode 100644 index 000000000000..05631f65aece --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/init.c @@ -0,0 +1,694 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: HW/FW Initialization + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cmdevt.h" +#include "wmm.h" +#include "11n.h" + +/* This function adds a BSS priority table to the table list. + * + * The function allocates a new BSS priority table node and adds it to + * the end of BSS priority table list, kept in driver memory. + */ +static int nxpwifi_add_bss_prio_tbl(struct nxpwifi_private *priv) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_bss_prio_node *bss_prio; + struct nxpwifi_bss_prio_tbl *tbl = adapter->bss_prio_tbl; + + bss_prio = kzalloc(sizeof(*bss_prio), GFP_KERNEL); + if (!bss_prio) + return -ENOMEM; + + bss_prio->priv = priv; + INIT_LIST_HEAD(&bss_prio->list); + + spin_lock_bh(&tbl[priv->bss_priority].bss_prio_lock); + list_add_tail(&bss_prio->list, &tbl[priv->bss_priority].bss_prio_head); + spin_unlock_bh(&tbl[priv->bss_priority].bss_prio_lock); + + return 0; +} + +static void wakeup_timer_fn(struct timer_list *t) +{ + struct nxpwifi_adapter *adapter = from_timer(adapter, t, wakeup_timer); + + nxpwifi_dbg(adapter, ERROR, "Firmware wakeup failed\n"); + adapter->hw_status = NXPWIFI_HW_STATUS_RESET; + nxpwifi_cancel_all_pending_cmd(adapter); + + if (adapter->if_ops.card_reset) + adapter->if_ops.card_reset(adapter); +} + +/* This function initializes the private structure and sets default + * values to the members. + * + * Additionally, it also initializes all the locks and sets up all the + * lists. + */ +int nxpwifi_init_priv(struct nxpwifi_private *priv) +{ + u32 i; + + priv->media_connected = false; + eth_broadcast_addr(priv->curr_addr); + priv->port_open = false; + priv->usb_port = NXPWIFI_USB_EP_DATA; + priv->pkt_tx_ctrl = 0; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + priv->data_rate = 0; /* Initially indicate the rate as auto */ + priv->is_data_rate_auto = true; + priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; + priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; + + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + + priv->sec_info.wep_enabled = 0; + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; + priv->sec_info.encryption_mode = 0; + for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++) + memset(&priv->wep_key[i], 0, sizeof(struct nxpwifi_wep_key)); + priv->wep_key_curr_index = 0; + priv->curr_pkt_filter = HOST_ACT_MAC_DYNAMIC_BW_ENABLE | + HOST_ACT_MAC_RX_ON | HOST_ACT_MAC_TX_ON | + HOST_ACT_MAC_ETHERNETII_ENABLE; + + priv->beacon_period = 100; /* beacon interval */ + priv->attempted_bss_desc = NULL; + memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params)); + priv->listen_interval = NXPWIFI_DEFAULT_LISTEN_INTERVAL; + + memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid)); + memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid)); + memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf)); + priv->assoc_rsp_size = 0; + priv->atim_window = 0; + priv->tx_power_level = 0; + priv->max_tx_power_level = 0; + priv->min_tx_power_level = 0; + priv->tx_ant = 0; + priv->rx_ant = 0; + priv->tx_rate = 0; + priv->rxpd_htinfo = 0; + priv->rxpd_rate = 0; + priv->rate_bitmap = 0; + priv->data_rssi_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->data_nf_last = 0; + priv->bcn_rssi_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->bcn_nf_last = 0; + memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie)); + memset(&priv->aes_key, 0, sizeof(priv->aes_key)); + priv->wpa_ie_len = 0; + priv->wpa_is_gtk_set = false; + + memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf)); + priv->assoc_tlv_buf_len = 0; + memset(&priv->wps, 0, sizeof(priv->wps)); + memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf)); + priv->gen_ie_buf_len = 0; + memset(priv->vs_ie, 0, sizeof(priv->vs_ie)); + + priv->wmm_required = true; + priv->wmm_enabled = false; + priv->wmm_qosinfo = 0; + priv->curr_bcn_buf = NULL; + priv->curr_bcn_size = 0; + priv->wps_ie = NULL; + priv->wps_ie_len = 0; + priv->ap_11n_enabled = 0; + memset(&priv->roc_cfg, 0, sizeof(priv->roc_cfg)); + + priv->scan_block = false; + + priv->csa_chan = 0; + priv->csa_expire_time = 0; + priv->del_list_idx = 0; + priv->hs2_enabled = false; + memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID); + + nxpwifi_init_11h_params(priv); + + return nxpwifi_add_bss_prio_tbl(priv); +} + +/* This function allocates buffers for members of the adapter + * structure. + * + * The memory allocated includes scan table, command buffers, and + * sleep confirm command buffer. In addition, the queues are + * also initialized. + */ +static int nxpwifi_allocate_adapter(struct nxpwifi_adapter *adapter) +{ + int ret; + + /* Allocate command buffer */ + ret = nxpwifi_alloc_cmd_buffer(adapter); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "%s: failed to alloc cmd buffer\n", + __func__); + return ret; + } + + adapter->sleep_cfm = + dev_alloc_skb(sizeof(struct nxpwifi_opt_sleep_confirm) + + INTF_HEADER_LEN); + + if (!adapter->sleep_cfm) { + nxpwifi_dbg(adapter, ERROR, + "%s: failed to alloc sleep cfm\t" + " cmd buffer\n", __func__); + return -ENOMEM; + } + skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN); + + return 0; +} + +/* This function initializes the adapter structure and sets default + * values to the members of adapter. + * + * This also initializes the WMM related parameters in the driver private + * structures. + */ +static void nxpwifi_init_adapter(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_opt_sleep_confirm *sleep_cfm_buf = NULL; + + skb_put(adapter->sleep_cfm, sizeof(struct nxpwifi_opt_sleep_confirm)); + + adapter->cmd_sent = false; + adapter->data_sent = true; + + adapter->intf_hdr_len = INTF_HEADER_LEN; + + adapter->cmd_resp_received = false; + adapter->event_received = false; + adapter->data_received = false; + adapter->assoc_resp_received = false; + adapter->priv_link_lost = NULL; + adapter->host_mlme_link_lost = false; + + clear_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags); + + adapter->hw_status = NXPWIFI_HW_STATUS_INITIALIZING; + + adapter->ps_mode = NXPWIFI_802_11_POWER_MODE_CAM; + adapter->ps_state = PS_STATE_AWAKE; + adapter->need_to_wakeup = false; + + adapter->scan_mode = HOST_BSS_MODE_ANY; + adapter->specific_scan_time = NXPWIFI_SPECIFIC_SCAN_CHAN_TIME; + adapter->active_scan_time = NXPWIFI_ACTIVE_SCAN_CHAN_TIME; + adapter->passive_scan_time = NXPWIFI_PASSIVE_SCAN_CHAN_TIME; + adapter->scan_chan_gap_time = NXPWIFI_DEF_SCAN_CHAN_GAP_TIME; + + adapter->scan_probes = 1; + + adapter->multiple_dtim = 1; + + /* default value in firmware will be used */ + adapter->local_listen_interval = 0; + + adapter->is_deep_sleep = false; + + adapter->delay_null_pkt = false; + adapter->delay_to_ps = 1000; + adapter->enhanced_ps_mode = PS_MODE_AUTO; + + /* Disable NULL Pkg generation by default */ + adapter->gen_null_pkt = false; + /* Disable pps/uapsd mode by default */ + adapter->pps_uapsd_mode = false; + adapter->pm_wakeup_card_req = false; + + adapter->pm_wakeup_fw_try = false; + + adapter->curr_tx_buf_size = NXPWIFI_TX_DATA_BUF_SIZE_2K; + + clear_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags); + adapter->hs_cfg.conditions = cpu_to_le32(HS_CFG_COND_DEF); + adapter->hs_cfg.gpio = HS_CFG_GPIO_DEF; + adapter->hs_cfg.gap = HS_CFG_GAP_DEF; + adapter->hs_activated = false; + + memset(adapter->event_body, 0, sizeof(adapter->event_body)); + adapter->hw_dot_11n_dev_cap = 0; + adapter->hw_dev_mcs_support = 0; + adapter->sec_chan_offset = 0; + + nxpwifi_wmm_init(adapter); + atomic_set(&adapter->tx_hw_pending, 0); + + sleep_cfm_buf = (struct nxpwifi_opt_sleep_confirm *) + adapter->sleep_cfm->data; + memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len); + sleep_cfm_buf->command = cpu_to_le16(HOST_CMD_802_11_PS_MODE_ENH); + sleep_cfm_buf->size = cpu_to_le16(adapter->sleep_cfm->len); + sleep_cfm_buf->result = 0; + sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM); + sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED); + + memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period)); + adapter->tx_lock_flag = false; + adapter->null_pkt_interval = 0; + adapter->fw_bands = 0; + adapter->config_bands = 0; + adapter->fw_release_number = 0; + adapter->fw_cap_info = 0; + memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf)); + adapter->event_cause = 0; + adapter->region_code = 0; + adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT; + memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); + adapter->arp_filter_size = 0; + adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; + adapter->key_api_major_ver = 0; + adapter->key_api_minor_ver = 0; + eth_broadcast_addr(adapter->perm_addr); + adapter->iface_limit.sta_intf = NXPWIFI_MAX_STA_NUM; + adapter->iface_limit.uap_intf = NXPWIFI_MAX_UAP_NUM; + adapter->active_scan_triggered = false; + timer_setup(&adapter->wakeup_timer, wakeup_timer_fn, 0); + adapter->devdump_len = 0; + memset(&adapter->vdll_ctrl, 0, sizeof(adapter->vdll_ctrl)); + adapter->vdll_ctrl.skb = dev_alloc_skb(NXPWIFI_SIZE_OF_CMD_BUFFER); +} + +/* This function sets trans_start per tx_queue + */ +void nxpwifi_set_trans_start(struct net_device *dev) +{ + int i; + + for (i = 0; i < dev->num_tx_queues; i++) + txq_trans_cond_update(netdev_get_tx_queue(dev, i)); + + netif_trans_update(dev); +} + +/* This function wakes up all queues in net_device + */ +void nxpwifi_wake_up_net_dev_queue(struct net_device *netdev, + struct nxpwifi_adapter *adapter) +{ + spin_lock_bh(&adapter->queue_lock); + netif_tx_wake_all_queues(netdev); + spin_unlock_bh(&adapter->queue_lock); +} + +/* This function stops all queues in net_device + */ +void nxpwifi_stop_net_dev_queue(struct net_device *netdev, + struct nxpwifi_adapter *adapter) +{ + spin_lock_bh(&adapter->queue_lock); + netif_tx_stop_all_queues(netdev); + spin_unlock_bh(&adapter->queue_lock); +} + +/* This function invalidates the list heads. + */ +static void nxpwifi_invalidate_lists(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + s32 i, j; + + list_del(&adapter->cmd_free_q); + list_del(&adapter->cmd_pending_q); + list_del(&adapter->scan_pending_q); + + for (i = 0; i < adapter->priv_num; i++) + list_del(&adapter->bss_prio_tbl[i].bss_prio_head); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) + list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); + list_del(&priv->tx_ba_stream_tbl_ptr); + list_del(&priv->rx_reorder_tbl_ptr); + list_del(&priv->sta_list); + } + } +} + +/* This function performs cleanup for adapter structure. + * + * The cleanup is done recursively, by canceling all pending + * commands, freeing the member buffers previously allocated + * (command buffers, scan table buffer, sleep confirm command + * buffer), stopping the timers and calling the cleanup routines + * for every interface. + */ +static void +nxpwifi_adapter_cleanup(struct nxpwifi_adapter *adapter) +{ + del_timer(&adapter->wakeup_timer); + nxpwifi_cancel_all_pending_cmd(adapter); + wake_up_interruptible(&adapter->cmd_wait_q.wait); + wake_up_interruptible(&adapter->hs_activate_wait_q); + if (adapter->vdll_ctrl.vdll_mem) { + vfree(adapter->vdll_ctrl.vdll_mem); + adapter->vdll_ctrl.vdll_mem = NULL; + adapter->vdll_ctrl.vdll_len = 0; + } + if (adapter->vdll_ctrl.skb) { + dev_kfree_skb_any(adapter->vdll_ctrl.skb); + adapter->vdll_ctrl.skb = NULL; + } +} + +void nxpwifi_free_cmd_buffers(struct nxpwifi_adapter *adapter) +{ + nxpwifi_invalidate_lists(adapter); + + /* Free command buffer */ + nxpwifi_dbg(adapter, INFO, "info: free cmd buffer\n"); + nxpwifi_free_cmd_buffer(adapter); + + if (adapter->sleep_cfm) + dev_kfree_skb_any(adapter->sleep_cfm); +} + +/* This function intializes the lock variables and + * the list heads. + */ +void nxpwifi_init_lock_list(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + s32 i, j; + + spin_lock_init(&adapter->int_lock); + spin_lock_init(&adapter->main_proc_lock); + spin_lock_init(&adapter->nxpwifi_cmd_lock); + spin_lock_init(&adapter->queue_lock); + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + spin_lock_init(&priv->wmm.ra_list_spinlock); + spin_lock_init(&priv->curr_bcn_buf_lock); + spin_lock_init(&priv->sta_list_spinlock); + } + } + + /* Initialize cmd_free_q */ + INIT_LIST_HEAD(&adapter->cmd_free_q); + /* Initialize cmd_pending_q */ + INIT_LIST_HEAD(&adapter->cmd_pending_q); + /* Initialize scan_pending_q */ + INIT_LIST_HEAD(&adapter->scan_pending_q); + + spin_lock_init(&adapter->cmd_free_q_lock); + spin_lock_init(&adapter->cmd_pending_q_lock); + spin_lock_init(&adapter->scan_pending_q_lock); + + skb_queue_head_init(&adapter->rx_mlme_q); + skb_queue_head_init(&adapter->rx_data_q); + skb_queue_head_init(&adapter->tx_data_q); + + for (i = 0; i < adapter->priv_num; ++i) { + INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); + spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock); + } + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i]) + continue; + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) + INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list); + INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); + INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); + INIT_LIST_HEAD(&priv->sta_list); + skb_queue_head_init(&priv->bypass_txq); + + spin_lock_init(&priv->tx_ba_stream_tbl_lock); + spin_lock_init(&priv->rx_reorder_tbl_lock); + + spin_lock_init(&priv->ack_status_lock); + idr_init(&priv->ack_status_frames); + } +} + +/* This function initializes the firmware. + * + * The following operations are performed sequentially - + * - Allocate adapter structure + * - Initialize the adapter structure + * - Initialize the private structure + * - Add BSS priority tables to the adapter structure + * - For each interface, send the init commands to firmware + * - Send the first command in command pending queue, if available + */ +int nxpwifi_init_fw(struct nxpwifi_adapter *adapter) +{ + int ret; + struct nxpwifi_private *priv; + u8 i; + bool first_sta = true; + int is_cmd_pend_q_empty; + + adapter->hw_status = NXPWIFI_HW_STATUS_INITIALIZING; + + /* Allocate memory for member of adapter structure */ + ret = nxpwifi_allocate_adapter(adapter); + if (ret) + return ret; + + /* Initialize adapter structure */ + nxpwifi_init_adapter(adapter); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + + /* Initialize private structure */ + ret = nxpwifi_init_priv(priv); + if (ret) + return ret; + } + } + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + ret = nxpwifi_sta_init_cmd(adapter->priv[i], + first_sta, true); + if (ret && ret != -EINPROGRESS) + return ret; + + first_sta = false; + } + } + + spin_lock_bh(&adapter->cmd_pending_q_lock); + is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); + spin_unlock_bh(&adapter->cmd_pending_q_lock); + if (!is_cmd_pend_q_empty) + /* Send the first command in queue and return */ + nxpwifi_main_process(adapter); + else + adapter->hw_status = NXPWIFI_HW_STATUS_READY; + + return ret; +} + +/* This function deletes the BSS priority tables. + * + * The function traverses through all the allocated BSS priority nodes + * in every BSS priority table and frees them. + */ +static void nxpwifi_delete_bss_prio_tbl(struct nxpwifi_private *priv) +{ + int i; + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_bss_prio_node *bssprio_node, *tmp_node; + struct list_head *head; + spinlock_t *lock; /* bss priority lock */ + + for (i = 0; i < adapter->priv_num; ++i) { + head = &adapter->bss_prio_tbl[i].bss_prio_head; + lock = &adapter->bss_prio_tbl[i].bss_prio_lock; + nxpwifi_dbg(adapter, INFO, + "info: delete BSS priority table,\t" + "bss_type = %d, bss_num = %d, i = %d,\t" + "head = %p\n", + priv->bss_type, priv->bss_num, i, head); + + { + spin_lock_bh(lock); + list_for_each_entry_safe(bssprio_node, tmp_node, head, + list) { + if (bssprio_node->priv == priv) { + nxpwifi_dbg(adapter, INFO, + "info: Delete\t" + "node %p, next = %p\n", + bssprio_node, tmp_node); + list_del(&bssprio_node->list); + kfree(bssprio_node); + } + } + spin_unlock_bh(lock); + } + } +} + +/* This function frees the private structure, including cleans + * up the TX and RX queues and frees the BSS priority tables. + */ +void nxpwifi_free_priv(struct nxpwifi_private *priv) +{ + nxpwifi_clean_txrx(priv); + nxpwifi_delete_bss_prio_tbl(priv); + nxpwifi_free_curr_bcn(priv); +} + +/* This function is used to shutdown the driver. + * + * The following operations are performed sequentially - + * - Check if already shut down + * - Make sure the main process has stopped + * - Clean up the Tx and Rx queues + * - Delete BSS priority tables + * - Free the adapter + * - Notify completion + */ +void +nxpwifi_shutdown_drv(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + s32 i; + struct sk_buff *skb; + + /* nxpwifi already shutdown */ + if (adapter->hw_status == NXPWIFI_HW_STATUS_NOT_READY) + return; + + /* cancel current command */ + if (adapter->curr_cmd) { + nxpwifi_dbg(adapter, WARN, + "curr_cmd is still in processing\n"); + del_timer_sync(&adapter->cmd_timer); + nxpwifi_recycle_cmd_node(adapter, adapter->curr_cmd); + adapter->curr_cmd = NULL; + } + + /* shut down nxpwifi */ + nxpwifi_dbg(adapter, MSG, + "info: shutdown nxpwifi...\n"); + + /* Clean up Tx/Rx queues and delete BSS priority table */ + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + + nxpwifi_abort_cac(priv); + nxpwifi_free_priv(priv); + } + } + + atomic_set(&adapter->tx_queued, 0); + while ((skb = skb_dequeue(&adapter->tx_data_q))) + nxpwifi_write_data_complete(adapter, skb, 0, 0); + + tasklet_disable(&adapter->rx_task); + + while ((skb = skb_dequeue(&adapter->rx_mlme_q))) + dev_kfree_skb_any(skb); + + while ((skb = skb_dequeue(&adapter->rx_data_q))) { + struct nxpwifi_rxinfo *rx_info = NXPWIFI_SKB_RXCB(skb); + + priv = adapter->priv[rx_info->bss_num]; + if (priv) + priv->stats.rx_dropped++; + + dev_kfree_skb_any(skb); + } + + nxpwifi_adapter_cleanup(adapter); + + adapter->hw_status = NXPWIFI_HW_STATUS_NOT_READY; +} + +/* This function downloads the firmware to the card. + * + * The actual download is preceded by two sanity checks - + * - Check if firmware is already running + * - Check if the interface is the winner to download the firmware + * + * ...and followed by another - + * - Check if the firmware is downloaded successfully + * + * After download is successfully completed, the host interrupts are enabled. + */ +int nxpwifi_dnld_fw(struct nxpwifi_adapter *adapter, + struct nxpwifi_fw_image *pmfw) +{ + int ret; + u32 poll_num = 1; + + /* check if firmware is already running */ + ret = adapter->if_ops.check_fw_status(adapter, poll_num); + if (!ret) { + nxpwifi_dbg(adapter, MSG, + "WLAN FW already running! Skip FW dnld\n"); + return 0; + } + + /* check if we are the winner for downloading FW */ + if (adapter->if_ops.check_winner_status) { + adapter->winner = 0; + ret = adapter->if_ops.check_winner_status(adapter); + + poll_num = MAX_FIRMWARE_POLL_TRIES; + if (ret) { + nxpwifi_dbg(adapter, MSG, + "WLAN read winner status failed!\n"); + return ret; + } + + if (!adapter->winner) { + nxpwifi_dbg(adapter, MSG, + "WLAN is not the winner! Skip FW dnld\n"); + goto poll_fw; + } + } + + if (pmfw) { + /* Download firmware with helper */ + ret = adapter->if_ops.prog_fw(adapter, pmfw); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "prog_fw failed ret=%#x\n", ret); + return ret; + } + } + +poll_fw: + /* Check if the firmware is downloaded successfully or not */ + ret = adapter->if_ops.check_fw_status(adapter, poll_num); + if (ret) + nxpwifi_dbg(adapter, ERROR, + "FW failed to be active in time\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(nxpwifi_dnld_fw); From patchwork Fri Aug 9 09:45:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818388 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5DA421990B5; Fri, 9 Aug 2024 09:47:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196833; cv=fail; b=EBRlRMdRgpk1Yx2UgE5OrAE9WsZ+/l6ozb9uIDHojTBw/6dd7ToIduQTiWR4tBACmw+u/uHTFLUHpsbF01TonIwPv2jdvgRFgFpUBgW5XPzq5A5tAl4b6fEVkmnCTzeMdhqBm2v0ewOYj9KZ9F5dRUz6uPpqM5rripc1hBmZa54= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196833; c=relaxed/simple; bh=Oi3qnNJt4LJk4DKV3ZKW5yBOjnZGOw3kse3oFKNuv/s=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=TMf+PWA4H+hnC2rDM17Rt2/n0/V6UuKkU+cVcYWazH9WXe/cT9ZY9/QhSB1rkCG1TR+HR/KPwOKjKaG5z/8F5fhJ4DvLmVTlTq9nlcPLw73MdCa0ilPv3aL9QGwb611d4Az1xVbzPFsELMq1xCWo/BHZKw0kUz9xXYiHw2mvgAE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=hqSE+bHk; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="hqSE+bHk" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=kQi+4Mo4bOCjcDp3njwteGgzmhI7jwxjroEYNXDJ2eLB3mN66KNwctWZd/imWUKmCusDpt6S92fquKwVpVrAiWH6BHZZ6Q9+pceXN1AZU0MhLh6i+FQQI3MNxBeex9QgYk9q11Uqg6t9hMc6dWFX1UISEx/8OOVdCrusBwnvVJWED+VnGbHtc5r3gTgARIS5ud8m16A/4M3AQxBABZJWJQG69TbZMLDDgnUDDjin/ELvleDnOSaPVIhZBoSfW3xvRmWarss0HdHOJEbmqvIAN3P9y4LDLONnw43n/XIfArSaBSnUkveUN/47CsC2ui8Yww5WuERqZ+k6jjP3Xvd2TA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Kx9huRG0RutdMrwCNrm5ho5HOnFBZiLXN721mVqGhVk=; b=hUTf5VyF/C63BUen1zmjw60PeA3YtnCWipxM1mMLo4IpO+a2BZXmnAUYXq9y6u9bSjgAahgXKGSXKNoimgkErjQOm5Ur7TvRvHIewls3b5+yDb7c+whQaL655QuoyhZ8aBrWvMMUPunn7gVkE+VevpFFlwHMg0Ecy5rZOqQJKOwMCxyYgGVaNX03KpD9u/QGhefyYBFT/KJMdljfhvcby9qiQPP39GfE0W1ZFHvZ/Lt8dcgNNJ53SaojTPmuti7jql2tdnwb66wZJhCzTddGWjJPWuTtwSOV1/aX5r+mPwG2Xxh/Yv8p3qoQ5ZfHH13y5NOriYFkyOldos4ad+K1/A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Kx9huRG0RutdMrwCNrm5ho5HOnFBZiLXN721mVqGhVk=; b=hqSE+bHkC+blcoKhz70xLdxhz1wl9IBneEQPvFLRWYXYCD1fws2WwnAhTsbc17sbZLVU74Hn9IhSYJmH9z0qcq24OTTP9DoqAvJLMwoEJ5ZPGKGSgCzakTQxhKBr04ntfDvSjxilrTqCBFq7isIRM3FNRhXSYrWuuzTfgZAAZ9GMTuTf+ANllYE/BOVrEQx6u2S5BHuzdOtR0kq9LRR2miRPdFZMRpmNLVa2bA2csA4Dsk02cnetUFgszGBwiHNquyV3yqXkDY3cmmhPs9J7Wydxjs1odwN3qmhpBUTg7kA7Vh0iEzb+tGTUa9Sr5pCh7eP6gNJk3ltaKojfHEAZyw== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:47:03 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:47:03 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 22/43] wifi: nxpwifi: add join.c Date: Fri, 9 Aug 2024 17:45:12 +0800 Message-Id: <20240809094533.1660-23-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: 25f7acd3-dc91-4bd1-1193-08dcb85838cd X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: xsYeKU9cruEIC8xHWJsgl6ErC6tn/+VeLnEDkg1XxnFcy8P9DdsYd5BQnLQltqduZmcy0UHd8GNtuqGWczLLJo/5eJCaXw/Cn+6rC7hsuh9KtdCimxmfsDB28MLf3OJ3ylJ4zeG7ma4b5orFkXMbqo782Q8ENnwKT9lLJGE1PC0E1lMZsyo2oJucUErUN1WezwfJA4mwj3PkyGLiCw/w7LK4IvluA4u+RolS7kXvSEmzSXDKNen8Y4XsudebqY1dtbId9CrX6JC42gmMOtyrLyG4D+6CjBAs/K5GVOGsyK9NV6FkDXCZb17Fnnq8e4ahSEjaXExYEwfqGFpjX7HFjeQXsd4/S2/HTdQJfCALLgxYmQpCps5C2JOZgW+/fig1wiWCVYelj0RHiVo+ahuUDDr0K3N3OgkrZuSXZL+xk0Ln4TeFA29MIq4bJcebP7NRPKhE8FB+O7U/wC+AL5Wo8v7fAYgBwHUhfZ1rRUlGUybh25I6KNL7fpYJlR40Btu6YIMBLaEvo3PPXpVnMPs88IefYAz8bG0cnpE5ERwvrx/Bs9twcevyWsEPh8dEy8XNI1U5qExeDpBJvdJGWVPxur1hyAT19KoJgHKj6fcnb6DNjLleXhdmPOxby0mzXdTWoXISQXNWFddZIYfXKFluE0Uu9moADJoqBcUByWHj9oMD8DhF2zYjKokY7Eh0ypWJDbVzEF2C0XZuLODjtOBiaxx8JVV54/2gR0nrS8Gtz67yopFmaZbJuOBsVjK6/I+8BIg/rTKXosWDVeqJXvn8Z4cvRMvksO9ihMQKgHnRHdL2MqUq3cg1jn9dExXPwneF/Pdi/X6m0A8EktxaedARZ2lvSyXNUKI4cF/8gyySkJY0ai1ZPFTW+ktOBAhPCd58Bz0gkOWV5Yni2sjeIg1Q6o4Op1wykX3L/8/IHPFIuK37MuKsRKdsQo6MXK7Tqst6OighjTT+/JSyT9g2rrbUzS84xJjDUrPukrO9yPJ9nSEnjd6ogY4ABpBHHV+Gam2d01AzT5DCRqv0ibiq40MdlrG0BNtwjGNLOoZJ4UzMMWWx1XK6mHwi3xnDPN8KIZzvAvzI7oPuAT2jlACFXHpYoyepRmrPAQ4vi8Mkv2yNSO2BJ9WemrPhcF9H4WksdUvID5C81GbwLQLztxobLB8R+p0gzMCPgSHIoteDiZXsUObvqpIjvfG1u+NoDQtgAL37I4DnXlTj2J20Xw/jOhQ/AJf7t8A7yd7U9Gw/M0dfAaAeXOWanFkJB+izEiEqSJTDVqzNfSdgi+eEyVFxR2NgQfydbW6vao2i6nq4ddlaTGCcxSk2U9nrhdICQXoJoFoErGXKbyJoPOvLoWsxC15fZQ== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: H5IQ32ar6uFHPwXd2daPZvia1PpcwoLVKN3jqvTUCq1YOUIErqgJi/Dd+vM1zSWhdIDB++ceaWHIH2RDpTu4cQioZgIqtnjqcRIPDAJ0Mx2Obvdg05U1bY2c2ATe/J1AAUpgnsVA36QTtox8xfcT6HR0ZJThLIwvXdL5vUR0ETL2lA7byU956igdWscLnMEZgbONl2SVsE7NGz6ZGC03Rw4uyVHK1vSMnksocZEZRUjP9eD4Qg+c9XYzGh5Jqj4h7wiuTePbS81fINGnHL0XqPWBYhNzLcsFBnOw9NgivArzJJK1UZZxRnXkrOdRQ4RjL2xN6VlagjtYMM1VrzTaPqTJ7rq30XcY7PfxVTJi/BOAdM8io6ERHw2wxD4iR1lnjvGc4lTr88qzICT6naE2duuqfvSCykkKouOAB8ZbF0rqtgfZLBmnDDum7EOQFtuzgxftqQaiXOlaxu46ZQxudnBGqka9l8F9q0eHY+QGzRtIx+226lBSrG8YRYrajAkDTFp/KyAunU++qhXdnXmx8mAUviCrD8jprCRhIN3EtLoGGz4pTXpwj38bl4HZES7Alq5e52QRFNc7sMnUiFBJfjXTj2j/lhaXASwd6B2UaP5SiwBybCSYTzmzzNY6rokuFnygKf30H8kyU7xUlYX+jwvhVfPxjhUO/6ZUaR0VbztMxWT2ZDtxt0K12fukmEzOBO73oBg99H8U3ysbPtYoc3l3WX7VeSFwTaAy+zod5YsLVRSIycL8M4oiQF48DT8jyvSdyRFGyThJFlhUhru0Gp30etlBzBfeGI1jJCl7C/ES4cX8K+UPlRcXGpdWG0tmUeuiIFWapL7tnG6jLVMini6Eg8v7zxePzBfz2j1w+oCpuUbEfkcVij2205Mv1djJEqshtSkRokQWdloSgkdIT3E7Tb0m1LHepJk0B5deBg1E3/Yn/yJOEtgvctqEr8pxpY9kJziGICN6cfLuRtmeT7pDdqWUXnhQcAYiMqN3sgO1thMuiOxkOnudFZGisHza7kTd1kujpCZ4DoNO3e/YT7G2x/XtA6UbSuG4v/sU5WyspHtBu4eAEtcuwtyIB1OlCdCp/scO0HKugfGvGx64NpMoxHPIWm7sXZAszYRJPGr9EYs0qW06ct/F7WayJ7ft9Qrb0TouURy0egeJtW+bk7+J2cVxCukbJNs4EAgf7JJ8TI14IzjB/6ZK+B2dj/zcym6yAY1BM3rKBC70FNU1uJEecjCqabeZIBfR/6A5BSbLlmqUw/RhfA9TvMzlHrItdTpd7Jnnu29Zoy326/mKeymRGaGdLMTrlkFGTFEPXV7YbEN/K1NEV8ByTDkPizC/OHJnneW4g6KlQ93p+wzaxj1zVIkCaXSsLYLqvHZ54GZewarVIv4wTTF+GqI27BwoTcxSv0OEkGU57AntpYMIoowG0MPWtHZe3eE5/Wv5kGyzuJmzpkDfVRRlT5CsWVuIV6+o9CaRfrqwZHmlYQnvtJFzAdV6DnB0L7hgxliYA3v6kV+cHF0mykxIP+3kplEqrXgTfFdiWtbmyaaQ/tHpTnGlVqIqFY6LhjDD6m5+XQWkYEIJIofpiBTMruCEU/4igzi1VYR4fF7cGHhqX4MmXFPZV22/sB3IWYEru2WuSp139LaYAnGfEeR6z7GG91vb X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 25f7acd3-dc91-4bd1-1193-08dcb85838cd X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:47:03.2829 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 9oZkTU9s51AdscErQ9TUrA8F2I2QCvHjGP6byrGFbk6qtzOI5gGlVw3YRbPUIqhi44Sy+kvK6XzZLIQWNMpUDg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/join.c | 915 ++++++++++++++++++++++++ 1 file changed, 915 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/join.c diff --git a/drivers/net/wireless/nxp/nxpwifi/join.c b/drivers/net/wireless/nxp/nxpwifi/join.c new file mode 100644 index 000000000000..842f26987728 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/join.c @@ -0,0 +1,915 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: association and ad-hoc start/join + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cmdevt.h" +#include "wmm.h" +#include "11n.h" +#include "11ac.h" + +#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) + +/* Append a generic IE as a pass through TLV to a TLV buffer. + * + * This function is called from the network join command preparation routine. + * + * If the IE buffer has been setup by the application, this routine appends + * the buffer as a pass through TLV type to the request. + */ +static int +nxpwifi_cmd_append_generic_ie(struct nxpwifi_private *priv, u8 **buffer) +{ + int ret_len = 0; + struct nxpwifi_ie_types_header ie_header; + + /* Null Checks */ + if (!buffer) + return 0; + if (!(*buffer)) + return 0; + + /* If there is a generic ie buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->gen_ie_buf_len) { + nxpwifi_dbg(priv->adapter, INFO, + "info: %s: append generic ie len %d to %p\n", + __func__, priv->gen_ie_buf_len, *buffer); + + /* Wrap the generic IE buffer with a pass through TLV type */ + ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); + ie_header.len = cpu_to_le16(priv->gen_ie_buf_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + + /* Increment the return size and the return buffer pointer + * param + */ + *buffer += sizeof(ie_header); + ret_len += sizeof(ie_header); + + /* Copy the generic IE buffer to the output buffer, advance + * pointer + */ + memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len); + + /* Increment the return size and the return buffer pointer + * param + */ + *buffer += priv->gen_ie_buf_len; + ret_len += priv->gen_ie_buf_len; + + /* Reset the generic IE buffer */ + priv->gen_ie_buf_len = 0; + } + + /* return the length appended to the buffer */ + return ret_len; +} + +/* Append TSF tracking info from the scan table for the target AP. + * + * This function is called from the network join command preparation routine. + * + * The TSF table TSF sent to the firmware contains two TSF values: + * - The TSF of the target AP from its previous beacon/probe response + * - The TSF timestamp of our local MAC at the time we observed the + * beacon/probe response. + * + * The firmware uses the timestamp values to set an initial TSF value + * in the MAC for the new association after a reassociation attempt. + */ +static int +nxpwifi_cmd_append_tsf_tlv(struct nxpwifi_private *priv, u8 **buffer, + struct nxpwifi_bssdescriptor *bss_desc) +{ + struct nxpwifi_ie_types_tsf_timestamp tsf_tlv; + __le64 tsf_val; + + /* Null Checks */ + if (!buffer) + return 0; + if (!*buffer) + return 0; + + memset(&tsf_tlv, 0x00, sizeof(struct nxpwifi_ie_types_tsf_timestamp)); + + tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP); + tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val)); + + memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); + *buffer += sizeof(tsf_tlv.header); + + /* TSF at the time when beacon/probe_response was received */ + tsf_val = cpu_to_le64(bss_desc->fw_tsf); + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer += sizeof(tsf_val); + + tsf_val = cpu_to_le64(bss_desc->timestamp); + + nxpwifi_dbg(priv->adapter, INFO, + "info: %s: TSF offset calc: %016llx - %016llx\n", + __func__, bss_desc->timestamp, bss_desc->fw_tsf); + + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer += sizeof(tsf_val); + + return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)); +} + +/* This function finds out the common rates between rate1 and rate2. + * + * It will fill common rates in rate1 as output if found. + * + * NOTE: Setting the MSB of the basic rates needs to be taken + * care of, either before or after calling this function. + */ +static int nxpwifi_get_common_rates(struct nxpwifi_private *priv, u8 *rate1, + u32 rate1_size, u8 *rate2, u32 rate2_size) +{ + int ret; + u8 *ptr = rate1, *tmp; + u32 i, j; + + tmp = kmemdup(rate1, rate1_size, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + memset(rate1, 0, rate1_size); + + for (i = 0; i < rate2_size && rate2[i]; i++) { + for (j = 0; j < rate1_size && tmp[j]; j++) { + /* Check common rate, excluding the bit for + * basic rate + */ + if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { + *rate1++ = tmp[j]; + break; + } + } + } + + nxpwifi_dbg(priv->adapter, INFO, "info: Tx data rate set to %#x\n", + priv->data_rate); + + if (!priv->is_data_rate_auto) { + while (*ptr) { + if ((*ptr & 0x7f) == priv->data_rate) { + ret = 0; + goto done; + } + ptr++; + } + nxpwifi_dbg(priv->adapter, ERROR, + "previously set fixed data rate %#x\t" + "is not compatible with the network\n", + priv->data_rate); + + ret = -EPERM; + goto done; + } + + ret = 0; +done: + kfree(tmp); + return ret; +} + +/* This function creates the intersection of the rates supported by a + * target BSS and our adapter settings for use in an assoc/join command. + */ +static int +nxpwifi_setup_rates_from_bssdesc(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc, + u8 *out_rates, u32 *out_rates_size) +{ + u8 card_rates[NXPWIFI_SUPPORTED_RATES]; + u32 card_rates_size; + int ret; + + /* Copy AP supported rates */ + memcpy(out_rates, bss_desc->supported_rates, NXPWIFI_SUPPORTED_RATES); + /* Get the STA supported rates */ + card_rates_size = nxpwifi_get_active_data_rates(priv, card_rates); + /* Get the common rates between AP and STA supported rates */ + ret = nxpwifi_get_common_rates(priv, out_rates, NXPWIFI_SUPPORTED_RATES, + card_rates, card_rates_size); + if (ret) { + *out_rates_size = 0; + nxpwifi_dbg(priv->adapter, ERROR, + "%s: cannot get common rates\n", + __func__); + } else { + *out_rates_size = + min_t(size_t, strlen(out_rates), NXPWIFI_SUPPORTED_RATES); + } + + return ret; +} + +/* This function appends a WPS IE. It is called from the network join command + * preparation routine. + * + * If the IE buffer has been setup by the application, this routine appends + * the buffer as a WPS TLV type to the request. + */ +static int +nxpwifi_cmd_append_wps_ie(struct nxpwifi_private *priv, u8 **buffer) +{ + int ret_len = 0; + struct nxpwifi_ie_types_header ie_header; + + if (!buffer || !*buffer) + return 0; + + /* If there is a wps ie buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->wps_ie_len) { + nxpwifi_dbg(priv->adapter, CMD, + "cmd: append wps ie %d to %p\n", + priv->wps_ie_len, *buffer); + + /* Wrap the generic IE buffer with a pass through TLV type */ + ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); + ie_header.len = cpu_to_le16(priv->wps_ie_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + *buffer += sizeof(ie_header); + ret_len += sizeof(ie_header); + + memcpy(*buffer, priv->wps_ie, priv->wps_ie_len); + *buffer += priv->wps_ie_len; + ret_len += priv->wps_ie_len; + } + + kfree(priv->wps_ie); + priv->wps_ie_len = 0; + return ret_len; +} + +/* This function appends rsn ie tlv for wpa/wpa2 security modes. + * It is called from the network join command preparation routine. + */ +static int nxpwifi_append_rsn_ie_wpa_wpa2(struct nxpwifi_private *priv, + u8 **buffer) +{ + struct nxpwifi_ie_types_rsn_param_set *rsn_ie_tlv; + int rsn_ie_len; + + if (!buffer || !(*buffer)) + return 0; + + rsn_ie_tlv = (struct nxpwifi_ie_types_rsn_param_set *)(*buffer); + rsn_ie_tlv->header.type = cpu_to_le16((u16)priv->wpa_ie[0]); + rsn_ie_tlv->header.type = + cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF); + rsn_ie_tlv->header.len = cpu_to_le16((u16)priv->wpa_ie[1]); + rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len) + & 0x00FF); + if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2)) + memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2], + le16_to_cpu(rsn_ie_tlv->header.len)); + else + return -ENOMEM; + + rsn_ie_len = sizeof(rsn_ie_tlv->header) + + le16_to_cpu(rsn_ie_tlv->header.len); + *buffer += rsn_ie_len; + + return rsn_ie_len; +} + +/* This function prepares command for association. + * + * This sets the following parameters - + * - Peer MAC address + * - Listen interval + * - Beacon interval + * - Capability information + * + * ...and the following TLVs, as required - + * - SSID TLV + * - PHY TLV + * - SS TLV + * - Rates TLV + * - Authentication TLV + * - Channel TLV + * - WPA/WPA2 IE + * - 11n TLV + * - Vendor specific TLV + * - WMM TLV + * - Generic IE + * - TSF TLV + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int nxpwifi_cmd_802_11_associate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + struct nxpwifi_bssdescriptor *bss_desc) +{ + struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; + struct nxpwifi_ie_types_host_mlme *host_mlme_tlv; + struct nxpwifi_ie_types_ssid_param_set *ssid_tlv; + struct nxpwifi_ie_types_phy_param_set *phy_tlv; + struct nxpwifi_ie_types_ss_param_set *ss_tlv; + struct nxpwifi_ie_types_rates_param_set *rates_tlv; + struct nxpwifi_ie_types_auth_type *auth_tlv; + struct nxpwifi_ie_types_sae_pwe_mode *sae_pwe_tlv; + struct nxpwifi_ie_types_chan_list_param_set *chan_tlv; + u8 rates[NXPWIFI_SUPPORTED_RATES]; + u32 rates_size; + u16 tmp_cap; + u8 *pos; + int rsn_ie_len = 0; + int ret; + + pos = (u8 *)assoc; + + cmd->command = cpu_to_le16(HOST_CMD_802_11_ASSOCIATE); + + /* Save so we know which BSS Desc to use in the response handler */ + priv->attempted_bss_desc = bss_desc; + + memcpy(assoc->peer_sta_addr, + bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); + pos += sizeof(assoc->peer_sta_addr); + + /* Set the listen interval */ + assoc->listen_interval = cpu_to_le16(priv->listen_interval); + /* Set the beacon period */ + assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); + + pos += sizeof(assoc->cap_info_bitmap); + pos += sizeof(assoc->listen_interval); + pos += sizeof(assoc->beacon_period); + pos += sizeof(assoc->dtim_period); + + host_mlme_tlv = (struct nxpwifi_ie_types_host_mlme *)pos; + host_mlme_tlv->header.type = cpu_to_le16(TLV_TYPE_HOST_MLME); + host_mlme_tlv->header.len = cpu_to_le16(sizeof(host_mlme_tlv->host_mlme)); + host_mlme_tlv->host_mlme = 1; + pos += sizeof(host_mlme_tlv->header) + sizeof(host_mlme_tlv->host_mlme); + + ssid_tlv = (struct nxpwifi_ie_types_ssid_param_set *)pos; + ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); + ssid_tlv->header.len = cpu_to_le16((u16)bss_desc->ssid.ssid_len); + memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, + le16_to_cpu(ssid_tlv->header.len)); + pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); + + phy_tlv = (struct nxpwifi_ie_types_phy_param_set *)pos; + phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); + phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); + memcpy(&phy_tlv->fh_ds.ds_param_set, + &bss_desc->phy_param_set.ds_param_set.current_chan, + sizeof(phy_tlv->fh_ds.ds_param_set)); + pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); + + ss_tlv = (struct nxpwifi_ie_types_ss_param_set *)pos; + ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); + ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); + pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); + + /* Get the common rates supported between the driver and the BSS Desc */ + ret = nxpwifi_setup_rates_from_bssdesc(priv, bss_desc, + rates, &rates_size); + if (ret) + return ret; + + /* Save the data rates into Current BSS state structure */ + priv->curr_bss_params.num_of_rates = rates_size; + memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); + + /* Setup the Rates TLV in the association command */ + rates_tlv = (struct nxpwifi_ie_types_rates_param_set *)pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16)rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + pos += sizeof(rates_tlv->header) + rates_size; + nxpwifi_dbg(priv->adapter, INFO, "info: ASSOC_CMD: rates size = %d\n", + rates_size); + + /* Add the Authentication type */ + auth_tlv = (struct nxpwifi_ie_types_auth_type *)pos; + auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); + if (priv->sec_info.wep_enabled) + auth_tlv->auth_type = + cpu_to_le16((u16)priv->sec_info.authentication_mode); + else + auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); + + pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); + + if (priv->sec_info.authentication_mode == WLAN_AUTH_SAE) { + auth_tlv->auth_type = cpu_to_le16(NXPWIFI_AUTHTYPE_SAE); + if (bss_desc->bcn_rsnx_ie && + bss_desc->bcn_rsnx_ie->datalen && + (bss_desc->bcn_rsnx_ie->data[0] & + WLAN_RSNX_CAPA_SAE_H2E)) { + sae_pwe_tlv = + (struct nxpwifi_ie_types_sae_pwe_mode *)pos; + sae_pwe_tlv->header.type = + cpu_to_le16(TLV_TYPE_SAE_PWE_MODE); + sae_pwe_tlv->header.len = + cpu_to_le16(sizeof(sae_pwe_tlv->pwe[0])); + sae_pwe_tlv->pwe[0] = bss_desc->bcn_rsnx_ie->data[0]; + pos += sizeof(sae_pwe_tlv->header) + + sizeof(sae_pwe_tlv->pwe[0]); + } + } + + if (IS_SUPPORT_MULTI_BANDS(priv->adapter) && + !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && + !bss_desc->disable_11n && + (priv->adapter->config_bands & BAND_GN || + priv->adapter->config_bands & BAND_AN) && + bss_desc->bcn_ht_cap)) { + /* Append a channel TLV for the channel the attempted AP was + * found on + */ + chan_tlv = (struct nxpwifi_ie_types_chan_list_param_set *)pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct nxpwifi_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct nxpwifi_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (bss_desc->phy_param_set.ds_param_set.current_chan); + nxpwifi_dbg(priv->adapter, INFO, "info: Assoc: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type = + nxpwifi_band_to_radio_type((u8)bss_desc->bss_band); + + nxpwifi_dbg(priv->adapter, INFO, "info: Assoc: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct nxpwifi_chan_scan_param_set); + } + + if (!priv->wps.session_enable) { + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + rsn_ie_len = nxpwifi_append_rsn_ie_wpa_wpa2(priv, &pos); + + if (rsn_ie_len == -ENOMEM) + return -ENOMEM; + } + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && + !bss_desc->disable_11n && + (priv->adapter->config_bands & BAND_GN || + priv->adapter->config_bands & BAND_AN)) + nxpwifi_cmd_append_11n_tlv(priv, bss_desc, &pos); + + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && + !bss_desc->disable_11n && !bss_desc->disable_11ac && + priv->adapter->config_bands & BAND_AAC) + nxpwifi_cmd_append_11ac_tlv(priv, bss_desc, &pos); + + /* Append vendor specific IE TLV */ + nxpwifi_cmd_append_vsie_tlv(priv, NXPWIFI_VSIE_MASK_ASSOC, &pos); + + nxpwifi_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, + bss_desc->bcn_ht_cap); + + if (priv->wps.session_enable && priv->wps_ie_len) + nxpwifi_cmd_append_wps_ie(priv, &pos); + + nxpwifi_cmd_append_generic_ie(priv, &pos); + + nxpwifi_cmd_append_tsf_tlv(priv, &pos, bss_desc); + + nxpwifi_11h_process_join(priv, &pos, bss_desc); + + cmd->size = cpu_to_le16((u16)(pos - (u8 *)assoc) + S_DS_GEN); + + /* Set the Capability info at last */ + tmp_cap = bss_desc->cap_info_bitmap; + + if (priv->adapter->config_bands == BAND_B) + tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; + + tmp_cap &= CAPINFO_MASK; + nxpwifi_dbg(priv->adapter, INFO, + "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", + tmp_cap, CAPINFO_MASK); + assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); + + return ret; +} + +static const char *assoc_failure_reason_to_str(u16 cap_info) +{ + switch (cap_info) { + case CONNECT_ERR_AUTH_ERR_STA_FAILURE: + return "CONNECT_ERR_AUTH_ERR_STA_FAILURE"; + case CONNECT_ERR_AUTH_MSG_UNHANDLED: + return "CONNECT_ERR_AUTH_MSG_UNHANDLED"; + case CONNECT_ERR_ASSOC_ERR_TIMEOUT: + return "CONNECT_ERR_ASSOC_ERR_TIMEOUT"; + case CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED: + return "CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED"; + case CONNECT_ERR_STA_FAILURE: + return "CONNECT_ERR_STA_FAILURE"; + } + + return "Unknown connect failure"; +} + +/* Association firmware command response handler + * + * The response buffer for the association command has the following + * memory layout. + * + * For cases where an association response was not received (indicated + * by the CapInfo and AId field): + * + * .------------------------------------------------------------. + * | Header(4 * sizeof(t_u16)): Standard command response hdr | + * .------------------------------------------------------------. + * | cap_info/Error Return(t_u16): | + * | 0xFFFF(-1): Internal error | + * | 0xFFFE(-2): Authentication unhandled message | + * | 0xFFFD(-3): Authentication refused | + * | 0xFFFC(-4): Timeout waiting for AP response | + * .------------------------------------------------------------. + * | status_code(t_u16): | + * | If cap_info is -1: | + * | An internal firmware failure prevented the | + * | command from being processed. The status_code | + * | will be set to 1. | + * | | + * | If cap_info is -2: | + * | An authentication frame was received but was | + * | not handled by the firmware. IEEE Status | + * | code for the failure is returned. | + * | | + * | If cap_info is -3: | + * | An authentication frame was received and the | + * | status_code is the IEEE Status reported in the | + * | response. | + * | | + * | If cap_info is -4: | + * | (1) Association response timeout | + * | (2) Authentication response timeout | + * .------------------------------------------------------------. + * | a_id(t_u16): 0xFFFF | + * .------------------------------------------------------------. + * + * + * For cases where an association response was received, the IEEE + * standard association response frame is returned: + * + * .------------------------------------------------------------. + * | Header(4 * sizeof(t_u16)): Standard command response hdr | + * .------------------------------------------------------------. + * | cap_info(t_u16): IEEE Capability | + * .------------------------------------------------------------. + * | status_code(t_u16): IEEE Status Code | + * .------------------------------------------------------------. + * | a_id(t_u16): IEEE Association ID | + * .------------------------------------------------------------. + * | IEEE IEs(variable): Any received IEs comprising the | + * | remaining portion of a received | + * | association response frame. | + * .------------------------------------------------------------. + * + * For simplistic handling, the status_code field can be used to determine + * an association success (0) or failure (non-zero). + */ +int nxpwifi_ret_802_11_associate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + int ret = 0; + struct ieee_types_assoc_rsp *assoc_rsp; + struct nxpwifi_bssdescriptor *bss_desc; + bool enable_data = true; + u16 cap_info, status_code, aid; + const u8 *ie_ptr; + struct ieee80211_ht_operation *assoc_resp_ht_oper; + struct ieee80211_mgmt *hdr; + + if (!priv->attempted_bss_desc) { + nxpwifi_dbg(priv->adapter, ERROR, + "%s: failed, association terminated by host\n", + __func__); + goto done; + } + + hdr = (struct ieee80211_mgmt *)&resp->params; + if (!memcmp(hdr->bssid, priv->attempted_bss_desc->mac_address, + ETH_ALEN)) + assoc_rsp = (struct ieee_types_assoc_rsp *)&hdr->u.assoc_resp; + else + assoc_rsp = (struct ieee_types_assoc_rsp *)&resp->params; + + cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap); + status_code = le16_to_cpu(assoc_rsp->status_code); + aid = le16_to_cpu(assoc_rsp->a_id); + + if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) + dev_err(priv->adapter->dev, + "invalid AID value 0x%x; bits 15:14 not set\n", + aid); + + aid &= ~(BIT(15) | BIT(14)); + + priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, + sizeof(priv->assoc_rsp_buf)); + + assoc_rsp->a_id = cpu_to_le16(aid); + memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); + + if (status_code) { + priv->adapter->dbg.num_cmd_assoc_failure++; + nxpwifi_dbg(priv->adapter, ERROR, + "ASSOC_RESP: failed,\t" + "status code=%d err=%#x a_id=%#x\n", + status_code, cap_info, + le16_to_cpu(assoc_rsp->a_id)); + + nxpwifi_dbg(priv->adapter, ERROR, "assoc failure: reason %s\n", + assoc_failure_reason_to_str(cap_info)); + if (cap_info == CONNECT_ERR_ASSOC_ERR_TIMEOUT) { + if (status_code == NXPWIFI_ASSOC_CMD_FAILURE_AUTH) { + ret = WLAN_STATUS_AUTH_TIMEOUT; + nxpwifi_dbg(priv->adapter, ERROR, + "ASSOC_RESP: AUTH timeout\n"); + } else { + ret = WLAN_STATUS_UNSPECIFIED_FAILURE; + nxpwifi_dbg(priv->adapter, ERROR, + "ASSOC_RESP: UNSPECIFIED failure\n"); + } + + priv->assoc_rsp_size = 0; + } else { + ret = status_code; + } + + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->media_connected = true; + + priv->adapter->ps_state = PS_STATE_AWAKE; + priv->adapter->pps_uapsd_mode = false; + priv->adapter->tx_lock_flag = false; + + /* Set the attempted BSSID Index to current */ + bss_desc = priv->attempted_bss_desc; + + nxpwifi_dbg(priv->adapter, INFO, "info: ASSOC_RESP: %s\n", + bss_desc->ssid.ssid); + + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, + bss_desc, sizeof(struct nxpwifi_bssdescriptor)); + + /* Update curr_bss_params */ + priv->curr_bss_params.bss_descriptor.channel = + bss_desc->phy_param_set.ds_param_set.current_chan; + + priv->curr_bss_params.band = (u8)bss_desc->bss_band; + + if (bss_desc->wmm_ie.element_id == WLAN_EID_VENDOR_SPECIFIC) + priv->curr_bss_params.wmm_enabled = true; + else + priv->curr_bss_params.wmm_enabled = false; + + if ((priv->wmm_required || bss_desc->bcn_ht_cap) && + priv->curr_bss_params.wmm_enabled) + priv->wmm_enabled = true; + else + priv->wmm_enabled = false; + + priv->curr_bss_params.wmm_uapsd_enabled = false; + + if (priv->wmm_enabled) + priv->curr_bss_params.wmm_uapsd_enabled = + ((bss_desc->wmm_ie.qos_info & + IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); + + /* Store the bandwidth information from assoc response */ + ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer, + priv->assoc_rsp_size + - sizeof(struct ieee_types_assoc_rsp)); + if (ie_ptr) { + assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr + + sizeof(struct element)); + priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param; + priv->ht_param_present = true; + } else { + priv->ht_param_present = false; + } + + nxpwifi_dbg(priv->adapter, INFO, + "info: ASSOC_RESP: curr_pkt_filter is %#x\n", + priv->curr_pkt_filter); + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->wpa_is_gtk_set = false; + + if (priv->wmm_enabled) { + /* Don't re-enable carrier until we get the WMM_GET_STATUS + * event + */ + enable_data = false; + } else { + /* Since WMM is not enabled, setup the queues with the + * defaults + */ + nxpwifi_wmm_setup_queue_priorities(priv, NULL); + nxpwifi_wmm_setup_ac_downgrade(priv); + } + + if (enable_data) + nxpwifi_dbg(priv->adapter, INFO, + "info: post association, re-enabling data flow\n"); + + /* Reset SNR/NF/RSSI values */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->rxpd_rate = 0; + priv->rxpd_htinfo = 0; + + nxpwifi_save_curr_bcn(priv); + + priv->adapter->dbg.num_cmd_assoc_success++; + + nxpwifi_dbg(priv->adapter, MSG, "assoc: associated with %pM\n", + priv->attempted_bss_desc->mac_address); + + /* Add the ra_list here for infra mode as there will be only 1 ra + * always + */ + nxpwifi_ralist_add(priv, + priv->curr_bss_params.bss_descriptor.mac_address); + + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + nxpwifi_wake_up_net_dev_queue(priv->netdev, adapter); + + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->scan_block = true; + else + priv->port_open = true; + +done: + /* Need to indicate IOCTL complete */ + if (adapter->curr_cmd->wait_q_enabled) { + if (ret) + adapter->cmd_wait_q.status = -1; + else + adapter->cmd_wait_q.status = 0; + } + + return ret; +} + +/* This function associates to a specific BSS discovered in a scan. + * + * It clears any past association response stored for application + * retrieval and calls the command preparation routine to send the + * command to firmware. + */ +int nxpwifi_associate(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc) +{ + /* Return error if the adapter is not STA role or table entry + * is not marked as infra. + */ + if ((GET_BSS_ROLE(priv) != NXPWIFI_BSS_ROLE_STA) || + bss_desc->bss_mode != NL80211_IFTYPE_STATION) + return -EINVAL; + + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && + !bss_desc->disable_11n && !bss_desc->disable_11ac && + priv->adapter->config_bands & BAND_AAC) + nxpwifi_set_11ac_ba_params(priv); + else + nxpwifi_set_ba_params(priv); + + /* Clear any past association response stored for application + * retrieval + */ + priv->assoc_rsp_size = 0; + + return nxpwifi_send_cmd(priv, HOST_CMD_802_11_ASSOCIATE, + HOST_ACT_GEN_SET, 0, bss_desc, true); +} + +/* This function deauthenticates/disconnects from infra network by sending + * deauthentication request. + */ +static int nxpwifi_deauthenticate_infra(struct nxpwifi_private *priv, u8 *mac) +{ + u8 mac_address[ETH_ALEN]; + int ret; + + if (!mac || is_zero_ether_addr(mac)) + memcpy(mac_address, + priv->curr_bss_params.bss_descriptor.mac_address, + ETH_ALEN); + else + memcpy(mac_address, mac, ETH_ALEN); + + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_DEAUTHENTICATE, + HOST_ACT_GEN_SET, 0, mac_address, true); + + return ret; +} + +/* This function deauthenticates/disconnects from a BSS. + * + * In case of infra made, it sends deauthentication request, and + * in case of ad-hoc mode, a stop network request is sent to the firmware. + * In AP mode, a command to stop bss is sent to firmware. + */ +int nxpwifi_deauthenticate(struct nxpwifi_private *priv, u8 *mac) +{ + int ret = 0; + + if (!priv->media_connected) + return 0; + + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + priv->host_mlme_reg = false; + priv->mgmt_frame_mask = 0; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_MGMT_FRAME_REG, + HOST_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "could not unregister mgmt frame rx\n"); + return ret; + } + + switch (priv->bss_mode) { + case NL80211_IFTYPE_STATION: + ret = nxpwifi_deauthenticate_infra(priv, mac); + if (ret) + cfg80211_disconnected(priv->netdev, 0, NULL, 0, + true, GFP_KERNEL); + break; + case NL80211_IFTYPE_AP: + ret = nxpwifi_send_cmd(priv, HOST_CMD_UAP_BSS_STOP, + HOST_ACT_GEN_SET, 0, NULL, true); + default: + break; + } + + return ret; +} + +/* This function deauthenticates/disconnects from all BSS. */ +void nxpwifi_deauthenticate_all(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + int i; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) + nxpwifi_deauthenticate(priv, NULL); + } +} +EXPORT_SYMBOL_GPL(nxpwifi_deauthenticate_all); + +/* This function converts band to radio type used in channel TLV. + */ +u8 +nxpwifi_band_to_radio_type(u8 band) +{ + switch (band) { + case BAND_A: + case BAND_AN: + case BAND_A | BAND_AN: + case BAND_A | BAND_AN | BAND_AAC: + return HOST_SCAN_RADIO_TYPE_A; + case BAND_B: + case BAND_G: + case BAND_B | BAND_G: + default: + return HOST_SCAN_RADIO_TYPE_BG; + } +} From patchwork Fri Aug 9 09:45:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818273 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 536AA1990D7; Fri, 9 Aug 2024 09:47:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196836; cv=fail; b=VISpPRC4kKtZ2pQzqyZ1HkNwH6NQKY8aE1+ZxVBP4IoV7RjrCTF4Z45GpOc+3/5tiVzXEzGVRAXgmXck/aTktiE2w3MJKtKz4WCl9g8d+K3XjjUxQrG6yS3TMwGMkhEMPDq9mr4NAJ12bWkyIozwGpp8fwWpB4lXAJTsbRhdIuE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196836; c=relaxed/simple; bh=o0Dnw1GFJxV5F057desk0J4NecduvhXjZumLM20HBNU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=uNk4zvtUXfqtHgH8AGm/KoyYlqLLZ8fFpzOr6UlmyJoYm5uOKsCFFjgUaJRCQJxtJFynO6QuBCUyroD3QZ4K66pjmLCo6eWVGL0appdLojZw0kQWzSc4ybRzUGxSJgVMeKOq0ZDau95KAQo7Xqt+olHmPjycDnk0LXZoHr3yVco= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=YKSMf/3x; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="YKSMf/3x" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=sJl0uvbuGI3LhBwf6Ze0nQuDqOprbRwGuwME3w9nxagNmCS+GldCiQC+84fynrnyt7QPu1KtKWXBleTRjIDk7aDTGOu/G0ANvVOzP/G8pQVnwYmWuH+Na89S8k7LH1YiRrEnGHP2RS17M5vdvNSP5do7HjEVCM0M5zD4JZvRWqlN62scApNrkqsw/wo0j4F+KNL48lnRhQHOVtAEdAIdf72Cnm1ohxF5hxyY+O8Tu7Qm4aQnR6wXztchvrTekoeStP1ZER7fSW/h3d3tgu0dhrNltsNHofFcH7uB6isD4J8XLB6VaxlKzoImDJIQfxeaTo6ytNgzFtLbsSTD8qP44w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=+PDxQ7KNVQbH3U4uOMSyCEbWweJKkkV0P/s14apq1LQ=; b=qVkVykax7/6fv+gCwwlkWYpS3ZVB4V5NxDWLl52sQwSg59ruUJCBZKRT0uvSrSwarewxscVCUOs8YbXI0E5Y1HClyMEB/e9XvUrSCniKL8gkLbp9ybBGL4fTCbg4RWNswMoSQ3/TiQrBENAlPuJCDB8i2Jz3ujBE0lrcTxMsSmYmE0w9hYBoRJ0/iJVHuDWpP6LR7QdJ3VkQpXfDknlhk2OMreG9pKiHucbvSZaAZY0v4UAVSAZUrx3GeRiKurSK/sfj8y6eKpKnPy7f7wPiPQ4qY9X/N7QlKJYtTpiLO+dd0TBFc2Y9EMdxCJcbcOT1jfyW7Y37R+sAvmP/1fKmpw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=+PDxQ7KNVQbH3U4uOMSyCEbWweJKkkV0P/s14apq1LQ=; b=YKSMf/3xdO/pntPHV8mu9RrEP4sbjc8qnwOPP41tvWTT6NzrQMWDNzpBuOvu0OgP6O2qZ1EJpMGqhqOzFF+wGdG+jQ58pRP8jjRgWgxobV6PFVHdmQBVyIyYnF3oY08wK2x7vQ6NoEu96pLUCIZ5leiBvhc5r/WUJEXj22hn5/ugRq16JiGlEWMvklt30TXoGAG2VbfbznX+Exo4a7oORdPmoyjuk4QfozsvcDhRT6Kaq4scx56Rgc+jkwrV0Ym9XHIuiYf/X+5JBl4oYLuKyR6DqoxdO2uukyEWxrYXmZ989+PWocvyLv0JWn8fBMQ2GRBd30RQ4rXwNkT3GUrVmg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:47:06 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:47:06 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 23/43] wifi: nxpwifi: add main.c Date: Fri, 9 Aug 2024 17:45:13 +0800 Message-Id: <20240809094533.1660-24-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: 81c0bff3-fe33-4e81-34d4-08dcb8583af2 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: nPFRgA1ZmeowMMmgS92A94AeLiZt+3TpRZLxJe66LDWawanubd53PIMEQAty93Vw4TytGbtf2CNKgR38NZvquygMYIBynNpuA8TANFm7lqznhlBhVhqBrNyMlBHDE2NH5a7Pz+Ew6PL4fXmLS9L4vAqY5xZ07zfXB/ugLr0lD8iDsyE8lOxpmTpVuiJ+umAS/OvsKDACcMdgGPRLCOwPFQZK2PVstkQuCTF++nPsNDHr0i+6ZPX6hKMQrGW4aKS+I+bVEtqs21VGMOH9B8L+5L2e5kfQdjrlfHpWPxHw5O512QFA1t8xm2MS2T2VUagV4xxsLGO8iXlqrWtQTbt7uOufVg4Vl64hPUx0r5f2QDrg4HKT9izGc+pcVX3Lj0RyGbaROiGHi7zOma9Vq2e36ST4+7qLC9oaTgXpNrEAF5BYpRtcuqQMVJFs7aqhvQ7Swt/FDDdJHSb1+Zd7t2R/irnjU8BjyEyisD3VGtWp9YcGfDyWLElwycUEHR2KQa6aTSD4HW+4c6pP53lq88ISlmBNaRIwkb44hFtXg+bxvjOP7tdTFxWPu0AaXtvioHxO+FDW6uFgrGJdJsuypYoCSxGzLkSIputyH7cpYVMqBbOLcR3hbxC5fufhz/lcHUw7T1MUligbOCoDh+caMMBvet8eeaM2nSFlHldWKh9XWEmAXQ4I+ydJlBKBBZJ5WrFbq8qCkiMlaIPSqURi6qSnUHl6idOlvtVsYsG67YtGkhcmGUn3Ykx+3xoVFsh4YNFcs1r9Gq+RLvyVpbT3YHK3eGY5HM06wDDjlRiyJB5FUIIKcLNUnaGPTuIwZ5b+2EazVvWxB4ISNoBsucV+io32yjBzV0cyTG55qvhLL3Dr6JvJvSH9LQRNHw/qBry/aNlHN0w5CDCmGfBxFJbbCAzhhGOHDSbSvUKsmHWdvJI7WoECzNSIc6mGTECGIfcAlyrwykoShvDjW+8RVfLshNNk57hH5dDBuX4Y8Tme9ZEgJCCJlTFl61YjSKtIcVuOyw6bexXfX2nFZt5pF40fl+WVRle0Ib7JUC7BMsEvn0Xpf2RoH4PB9CsAPHBjYApdcFsbY6eiAInlEPovENClegIzvtafXjkX5Tf9SLLKcrzZttF/wwuP7irW9uAYiiaYLia3A/DVVG0mlcSE8pdgBwi1v99YJyxYy3i4Z22zbjDjtFJ6X9nl1A0ozu3uzXxwwAJ5QlEh9Ouo8rILKfM/Uu53QOQqrJ2FsStAYEzFYey6m8/c9tQNsygo661Bp3rk2rmBrAEnU3+dbJ7cu9zyl7jn0MzkfiK6rHRLke7ejj8PbGcpOoj31YYkxoGvxwwXlFeMSDnsJF9mywq+tyEiZzZVlg== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: QAKiE0LcJjUmh4FNU+TX66hF1hgogz/ZFd8k+6D/gZKekbrjgwE+BHGktSiXUBUOzVrvCRGLQbd2K8BnHbp89/Be7POa8zDkn7pGmrC3JXpR/TXPGtRjq4c71mE46KLO0sBpjwRB2mAwaH41iJJnMq+gA4CaypQ/Zy0DSxKHUAACa3c4A3o1RVjByjc66o7UmvTBD21X+pt+3JCiwpdCjQC+GEFHGQvY+uVq3uCXjdClImU45IWSeXjnSPKbu7lDp/4W7r2rtSxUZsp0ROKGtaeHKmsM06ZzK2h0ov1Mhd3rd3IqV6kwntPAEOjpf6URR5WY02cjFOoKOg1TApWVYyQWKjuuBzMqPebGdC8ZrU2Tgo+C2qKruUCunbQI9Dqfr9nA04oy9Msp17AvaJn6CYsekMg/4Pl906g8m22kEQJVEGghTc8n5NSWLB8i0Rm4GfJ/YBZxTWuPUIBsCmfvAMaiFOP7uG272o7Tpyf+oQY/Wqefv7ACnRTuxaVI08WIW/vjfPlldffLHxx/3T65qD4TeV8uybePW5iKpEgFFa4T27Mgj0gyRKoOt6O+viwY7+S7GU3C9JEetvVpwgRkqRXu8fZF3DQ9xhc6dJ9Z0KwMIjCAMN+6x10bj/WtwjTLV3HzR6GV2yS/xTO+V84HCRNuRqWAR9SnsRqf7bHinWkLrVoZ6KOZK02rzQDWjjk3jtJe1e3tvXOGWK4LHE9ACe20bqD2H5pStnXlYJcQZmvKGTW1GnHHik90r4vITIVFmWF7pbu+JfT/x5sNkYgfciCnwNbw03A+GqTEDT7AreWpYEmVYNnA24nz9xvlOitu46Cwn3TfK0AKd7I2bMuTjrn6yDvJXkQyv/MMQ2YtxnLh1E2JiKx3m3exCWQJ8tOChdfVLWslmTdaUcTEMm86r/Ul9Iqg00nhRN4pbHRBTpAO3cLDEs0u4Ra1L6JChGZ3tnuRYJVOyck67bE2IT6/FPX/a8aeyafA6/GQiugduSkagjTIQpdz3whAIJDqV3x871nbctZxZT+TTz8/hWqDyiZEelabIZnW22vWJxn9HlzE5eFhxcYJ70MkEB0LXJH8mEZCTAhj9f9CZGC5PNeQ8hp0RGqoqabIim63cWGnKZF/gIULL9OmztPXp+bhYcLmndNNpDtUKTK25uCiXpAr1HIiTBOnPkM6ra+Z2lbNo9F8P01dF0/ueNjUDHSvJOY12vR64WELXeHaQfTbi6i7ndHwPkRI2k/lox95CojjzNMfX3XGV36uvBpqlZi7vdTpMT7o002DSBv2m2o1YImye4tDwp79E2DdRNCRUsq/GAkT9Rd77JP3Wv+dgr5MlzZwgo5U6/J2WizygBkA8jFG3rWuZly3oOnTwxX5fZFLOUvGg0A6gXLf6WLaKFUt82mF4xFh6Csdqxbq3OUi61iSZXLWkLn0xuQVSJvfDaE0ozy45B3CgA0Cup2+M0SlOwQNW6005BXQ3FRF7M4dMx0vzIECRAQKXqSgcoCpOHWiRFXcpDsNK1S38WQpjfWvW4j5Rhpcjm8XGRmfEAdgiJocs15rUF7VpHoElzVA4kklV5ozNq/bnCsVdMZbO75zomcAaapg/hHDdXOtmmHspMcjOLQgVeVns1qKNELgCxjwIoF6WwAWapqT8Fs6hMpWxQA3 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 81c0bff3-fe33-4e81-34d4-08dcb8583af2 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:47:06.6276 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: JFuRK7yU5RllKWN9eeW4WEtJdMJWNUIzWr2PVePF+xxktDIIceRqfQWp5ro0VSPySTT7F9mC5ZpR5ku6BfwP/A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/main.c | 1666 +++++++++++++++++++++++ 1 file changed, 1666 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/main.c diff --git a/drivers/net/wireless/nxp/nxpwifi/main.c b/drivers/net/wireless/nxp/nxpwifi/main.c new file mode 100644 index 000000000000..296a54240c2b --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/main.c @@ -0,0 +1,1666 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: major functions + * + * Copyright 2011-2024 NXP + */ + +#include + +#include "main.h" +#include "cmdevt.h" +#include "wmm.h" +#include "cfg80211.h" +#include "11n.h" + +#define VERSION "1.0" + +static unsigned int debug_mask = NXPWIFI_DEFAULT_DEBUG_MASK; + +char driver_version[] = "nxpwifi " VERSION " (%s) "; + +const u16 nxpwifi_1d_to_wmm_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + +/* This function registers the device and performs all the necessary + * initializations. + * + * The following initialization operations are performed - + * - Allocate adapter structure + * - Save interface specific operations table in adapter + * - Call interface specific initialization routine + * - Allocate private structures + * - Set default adapter structure parameters + * - Initialize locks + * + * In case of any errors during initialization, this function also ensures + * proper cleanup before exiting. + */ +static struct nxpwifi_adapter *nxpwifi_register(void *card, struct device *dev, + struct nxpwifi_if_ops *if_ops) +{ + struct nxpwifi_adapter *adapter; + int ret = 0; + int i; + + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); + if (!adapter) + return ERR_PTR(-ENOMEM); + + adapter->dev = dev; + adapter->card = card; + + /* Save interface specific operations in adapter */ + memmove(&adapter->if_ops, if_ops, sizeof(struct nxpwifi_if_ops)); + adapter->debug_mask = debug_mask; + + /* card specific initialization has been deferred until now .. */ + if (adapter->if_ops.init_if) { + ret = adapter->if_ops.init_if(adapter); + if (ret) + goto error; + } + + adapter->priv_num = 0; + + for (i = 0; i < NXPWIFI_MAX_BSS_NUM; i++) { + /* Allocate memory for private structure */ + adapter->priv[i] = + kzalloc(sizeof(struct nxpwifi_private), GFP_KERNEL); + if (!adapter->priv[i]) { + ret = -ENOMEM; + goto error; + } + + adapter->priv[i]->adapter = adapter; + adapter->priv_num++; + } + nxpwifi_init_lock_list(adapter); + + timer_setup(&adapter->cmd_timer, nxpwifi_cmd_timeout_func, 0); + + if (ret) + return ERR_PTR(ret); + else + return adapter; + +error: + nxpwifi_dbg(adapter, ERROR, + "info: leave %s with error\n", __func__); + + for (i = 0; i < adapter->priv_num; i++) + kfree(adapter->priv[i]); + + kfree(adapter); + + return ERR_PTR(ret); +} + +/* This function unregisters the device and performs all the necessary + * cleanups. + * + * The following cleanup operations are performed - + * - Free the timers + * - Free beacon buffers + * - Free private structures + * - Free adapter structure + */ +static void nxpwifi_unregister(struct nxpwifi_adapter *adapter) +{ + s32 i; + + if (adapter->if_ops.cleanup_if) + adapter->if_ops.cleanup_if(adapter); + + del_timer_sync(&adapter->cmd_timer); + + /* Free private structures */ + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + nxpwifi_free_curr_bcn(adapter->priv[i]); + kfree(adapter->priv[i]); + } + } + + if (adapter->nd_info) { + for (i = 0 ; i < adapter->nd_info->n_matches ; i++) + kfree(adapter->nd_info->matches[i]); + kfree(adapter->nd_info); + adapter->nd_info = NULL; + } + + kfree(adapter->regd); + + kfree(adapter); +} + +static void nxpwifi_process_rx(struct nxpwifi_adapter *adapter) +{ + struct sk_buff *skb; + struct nxpwifi_rxinfo *rx_info; + + /* Check for Rx data */ + while ((skb = skb_dequeue(&adapter->rx_data_q))) { + rx_info = NXPWIFI_SKB_RXCB(skb); + if (rx_info->buf_type == NXPWIFI_TYPE_AGGR_DATA) { + if (adapter->if_ops.deaggr_pkt) + adapter->if_ops.deaggr_pkt(adapter, skb); + dev_kfree_skb_any(skb); + } else { + nxpwifi_handle_rx_packet(adapter, skb); + } + } +} + +static void maybe_quirk_fw_disable_ds(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA); + struct nxpwifi_ver_ext ver_ext; + + if (test_and_set_bit(NXPWIFI_IS_REQUESTING_FW_VEREXT, &adapter->work_flags)) + return; + + memset(&ver_ext, 0, sizeof(ver_ext)); + ver_ext.version_str_sel = 1; + if (nxpwifi_send_cmd(priv, HOST_CMD_VERSION_EXT, + HOST_ACT_GEN_GET, 0, &ver_ext, false)) { + nxpwifi_dbg(priv->adapter, MSG, + "Checking hardware revision failed.\n"); + } +} + +/* The main process. + * + * This function is the main procedure of the driver and handles various driver + * operations. It runs in a loop and provides the core functionalities. + * + * The main responsibilities of this function are - + * - Ensure concurrency control + * - Handle pending interrupts and call interrupt handlers + * - Wake up the card if required + * - Handle command responses and call response handlers + * - Handle events and call event handlers + * - Execute pending commands + * - Transmit pending data packets + */ +void nxpwifi_main_process(struct nxpwifi_adapter *adapter) +{ + unsigned long flags; + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + + /* Check if already processing */ + if (adapter->nxpwifi_processing || adapter->main_locked) { + adapter->more_task_flag = true; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + return; + } + + adapter->nxpwifi_processing = true; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + +process_start: + do { + if (adapter->hw_status == NXPWIFI_HW_STATUS_NOT_READY) + break; + + /* Handle pending interrupt if any */ + if (adapter->int_status) { + if (adapter->hs_activated) + nxpwifi_process_hs_config(adapter); + if (adapter->if_ops.process_int_status) + adapter->if_ops.process_int_status(adapter); + } + + /* Need to wake up the card ? */ + if (adapter->ps_state == PS_STATE_SLEEP && + (adapter->pm_wakeup_card_req && + !adapter->pm_wakeup_fw_try) && + (is_command_pending(adapter) || + !skb_queue_empty(&adapter->tx_data_q) || + !nxpwifi_bypass_txlist_empty(adapter) || + !nxpwifi_wmm_lists_empty(adapter))) { + adapter->pm_wakeup_fw_try = true; + mod_timer(&adapter->wakeup_timer, jiffies + (HZ * 3)); + adapter->if_ops.wakeup(adapter); + continue; + } + + if (IS_CARD_RX_RCVD(adapter)) { + adapter->data_received = false; + adapter->pm_wakeup_fw_try = false; + del_timer(&adapter->wakeup_timer); + if (adapter->ps_state == PS_STATE_SLEEP) + adapter->ps_state = PS_STATE_AWAKE; + } else { + /* We have tried to wakeup the card already */ + if (adapter->pm_wakeup_fw_try) + break; + if (adapter->ps_state == PS_STATE_PRE_SLEEP) + nxpwifi_check_ps_cond(adapter); + + if (adapter->ps_state != PS_STATE_AWAKE) + break; + if (adapter->tx_lock_flag) + break; + + if ((!adapter->scan_chan_gap_enabled && + adapter->scan_processing) || adapter->data_sent || + (nxpwifi_wmm_lists_empty(adapter) && + nxpwifi_bypass_txlist_empty(adapter) && + skb_queue_empty(&adapter->tx_data_q))) { + if (adapter->cmd_sent || adapter->curr_cmd || + (!is_command_pending(adapter))) + break; + } + } + + /* Check for event */ + if (adapter->event_received) { + adapter->event_received = false; + nxpwifi_process_event(adapter); + } + + /* Check for Cmd Resp */ + if (adapter->cmd_resp_received) { + adapter->cmd_resp_received = false; + nxpwifi_process_cmdresp(adapter); + + /* call nxpwifi back when init_fw is done */ + if (adapter->hw_status == NXPWIFI_HW_STATUS_INIT_DONE) { + adapter->hw_status = NXPWIFI_HW_STATUS_READY; + nxpwifi_init_fw_complete(adapter); + maybe_quirk_fw_disable_ds(adapter); + } + } + + /* Check if we need to confirm Sleep Request + * received previously + */ + if (adapter->ps_state == PS_STATE_PRE_SLEEP) + nxpwifi_check_ps_cond(adapter); + + /* * The ps_state may have been changed during processing of + * Sleep Request event. + */ + if (adapter->ps_state == PS_STATE_SLEEP || + adapter->ps_state == PS_STATE_PRE_SLEEP || + adapter->ps_state == PS_STATE_SLEEP_CFM) { + continue; + } + + if (adapter->tx_lock_flag) + continue; + + if (!adapter->cmd_sent && + adapter->vdll_ctrl.pending_block) { + struct vdll_dnld_ctrl *ctrl = &adapter->vdll_ctrl; + + nxpwifi_download_vdll_block(adapter, ctrl->pending_block, + ctrl->pending_block_len); + ctrl->pending_block = NULL; + } + + if (!adapter->cmd_sent && !adapter->curr_cmd) { + if (nxpwifi_exec_next_cmd(adapter)) + break; + } + + if ((adapter->scan_chan_gap_enabled || + !adapter->scan_processing) && + !adapter->data_sent && + !skb_queue_empty(&adapter->tx_data_q)) { + if (adapter->hs_activated_manually) { + nxpwifi_cancel_hs(nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY), + NXPWIFI_ASYNC_CMD); + adapter->hs_activated_manually = false; + } + + nxpwifi_process_tx_queue(adapter); + if (adapter->hs_activated) { + clear_bit(NXPWIFI_IS_HS_CONFIGURED, + &adapter->work_flags); + nxpwifi_hs_activated_event + (nxpwifi_get_priv + (adapter, NXPWIFI_BSS_ROLE_ANY), + false); + } + } + + if ((adapter->scan_chan_gap_enabled || + !adapter->scan_processing) && + !adapter->data_sent && + !nxpwifi_bypass_txlist_empty(adapter)) { + if (adapter->hs_activated_manually) { + nxpwifi_cancel_hs(nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY), + NXPWIFI_ASYNC_CMD); + adapter->hs_activated_manually = false; + } + + nxpwifi_process_bypass_tx(adapter); + if (adapter->hs_activated) { + clear_bit(NXPWIFI_IS_HS_CONFIGURED, + &adapter->work_flags); + nxpwifi_hs_activated_event + (nxpwifi_get_priv + (adapter, NXPWIFI_BSS_ROLE_ANY), + false); + } + } + + if ((adapter->scan_chan_gap_enabled || + !adapter->scan_processing) && + !adapter->data_sent && !nxpwifi_wmm_lists_empty(adapter)) { + if (adapter->hs_activated_manually) { + nxpwifi_cancel_hs(nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY), + NXPWIFI_ASYNC_CMD); + adapter->hs_activated_manually = false; + } + + nxpwifi_wmm_process_tx(adapter); + if (adapter->hs_activated) { + clear_bit(NXPWIFI_IS_HS_CONFIGURED, + &adapter->work_flags); + nxpwifi_hs_activated_event + (nxpwifi_get_priv + (adapter, NXPWIFI_BSS_ROLE_ANY), + false); + } + } + + if (adapter->delay_null_pkt && !adapter->cmd_sent && + !adapter->curr_cmd && !is_command_pending(adapter) && + (nxpwifi_wmm_lists_empty(adapter) && + nxpwifi_bypass_txlist_empty(adapter) && + skb_queue_empty(&adapter->tx_data_q))) { + if (!nxpwifi_send_null_packet + (nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA), + NXPWIFI_TxPD_POWER_MGMT_NULL_PACKET | + NXPWIFI_TxPD_POWER_MGMT_LAST_PACKET)) { + adapter->delay_null_pkt = false; + adapter->ps_state = PS_STATE_SLEEP; + } + break; + } + } while (true); + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + if (adapter->more_task_flag) { + adapter->more_task_flag = false; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + goto process_start; + } + adapter->nxpwifi_processing = false; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); +} +EXPORT_SYMBOL_GPL(nxpwifi_main_process); + +/* This function frees the adapter structure. + * + * Additionally, this closes the netlink socket, frees the timers + * and private structures. + */ +static void nxpwifi_free_adapter(struct nxpwifi_adapter *adapter) +{ + if (!adapter) { + pr_err("%s: adapter is NULL\n", __func__); + return; + } + + nxpwifi_unregister(adapter); + pr_debug("info: %s: free adapter\n", __func__); +} + +/* This function cancels all works in the queue and destroys + * the main workqueue. + */ +static void nxpwifi_terminate_workqueue(struct nxpwifi_adapter *adapter) +{ + if (adapter->workqueue) { + destroy_workqueue(adapter->workqueue); + adapter->workqueue = NULL; + } +} + +/* This function gets firmware and initializes it. + * + * The main initialization steps followed are - + * - Download the correct firmware to card + * - Issue the init commands to firmware + */ +static int _nxpwifi_fw_dpc(const struct firmware *firmware, void *context) +{ + int ret = 0; + char fmt[64]; + struct nxpwifi_adapter *adapter = context; + struct nxpwifi_fw_image fw; + bool init_failed = false; + struct wireless_dev *wdev; + struct completion *fw_done = adapter->fw_done; + + if (!firmware) { + nxpwifi_dbg(adapter, ERROR, + "Failed to get firmware %s\n", adapter->fw_name); + ret = -EINVAL; + goto err_dnld_fw; + } + + memset(&fw, 0, sizeof(struct nxpwifi_fw_image)); + adapter->firmware = firmware; + fw.fw_buf = (u8 *)adapter->firmware->data; + fw.fw_len = adapter->firmware->size; + + if (adapter->if_ops.dnld_fw) + ret = adapter->if_ops.dnld_fw(adapter, &fw); + else + ret = nxpwifi_dnld_fw(adapter, &fw); + + if (ret) + goto err_dnld_fw; + + nxpwifi_dbg(adapter, MSG, "WLAN FW is active\n"); + + /* enable host interrupt after fw dnld is successful */ + if (adapter->if_ops.enable_int) { + ret = adapter->if_ops.enable_int(adapter); + if (ret) + goto err_dnld_fw; + } + + adapter->init_wait_q_woken = false; + ret = nxpwifi_init_fw(adapter); + if (ret != -EINPROGRESS) { + goto err_init_fw; + } else if (!ret) { + adapter->hw_status = NXPWIFI_HW_STATUS_READY; + goto done; + } + /* Wait for nxpwifi_init to complete */ + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + if (adapter->hw_status != NXPWIFI_HW_STATUS_READY) + goto err_init_fw; + + if (!adapter->wiphy) { + if (nxpwifi_register_cfg80211(adapter)) { + nxpwifi_dbg(adapter, ERROR, + "cannot register with cfg80211\n"); + goto err_init_fw; + } + } + + if (nxpwifi_init_channel_scan_gap(adapter)) { + nxpwifi_dbg(adapter, ERROR, + "could not init channel stats table\n"); + goto err_init_chan_scan; + } + + rtnl_lock(); + wiphy_lock(adapter->wiphy); + /* Create station interface by default */ + wdev = nxpwifi_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM, + NL80211_IFTYPE_STATION, NULL); + if (IS_ERR(wdev)) { + nxpwifi_dbg(adapter, ERROR, + "cannot create default STA interface\n"); + wiphy_unlock(adapter->wiphy); + rtnl_unlock(); + goto err_add_intf; + } + + wdev = nxpwifi_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM, + NL80211_IFTYPE_AP, NULL); + if (IS_ERR(wdev)) { + nxpwifi_dbg(adapter, ERROR, + "cannot create AP interface\n"); + wiphy_unlock(adapter->wiphy); + rtnl_unlock(); + goto err_add_intf; + } + + wiphy_unlock(adapter->wiphy); + rtnl_unlock(); + + nxpwifi_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); + nxpwifi_dbg(adapter, MSG, "driver_version = %s\n", fmt); + adapter->is_up = true; + goto done; + +err_add_intf: + vfree(adapter->chan_stats); +err_init_chan_scan: + wiphy_unregister(adapter->wiphy); + wiphy_free(adapter->wiphy); +err_init_fw: + if (adapter->if_ops.disable_int) + adapter->if_ops.disable_int(adapter); +err_dnld_fw: + nxpwifi_dbg(adapter, ERROR, + "info: %s: unregister device\n", __func__); + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); + + set_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags); + tasklet_kill(&adapter->rx_task); + nxpwifi_terminate_workqueue(adapter); + + if (adapter->hw_status == NXPWIFI_HW_STATUS_READY) { + pr_debug("info: %s: shutdown nxpwifi\n", __func__); + nxpwifi_shutdown_drv(adapter); + nxpwifi_free_cmd_buffers(adapter); + } + + init_failed = true; +done: + if (adapter->cal_data) { + release_firmware(adapter->cal_data); + adapter->cal_data = NULL; + } + if (adapter->firmware) { + release_firmware(adapter->firmware); + adapter->firmware = NULL; + } + if (init_failed) { + if (adapter->irq_wakeup >= 0) + device_init_wakeup(adapter->dev, false); + nxpwifi_free_adapter(adapter); + } + /* Tell all current and future waiters we're finished */ + complete_all(fw_done); + + return ret; +} + +static void nxpwifi_fw_dpc(const struct firmware *firmware, void *context) +{ + _nxpwifi_fw_dpc(firmware, context); +} + +/* This function gets the firmware and (if called asynchronously) kicks off the + * HW init when done. + */ +static int nxpwifi_init_hw_fw(struct nxpwifi_adapter *adapter, + bool req_fw_nowait) +{ + int ret; + + if (req_fw_nowait) { + ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name, + adapter->dev, GFP_KERNEL, adapter, + nxpwifi_fw_dpc); + } else { + ret = request_firmware(&adapter->firmware, + adapter->fw_name, + adapter->dev); + } + + if (ret < 0) + nxpwifi_dbg(adapter, ERROR, "request_firmware%s error %d\n", + req_fw_nowait ? "_nowait" : "", ret); + return ret; +} + +/* CFG802.11 network device handler for open. + * + * Starts the data queue. + */ +static int +nxpwifi_open(struct net_device *dev) +{ + netif_carrier_off(dev); + + return 0; +} + +/* CFG802.11 network device handler for close. + */ +static int +nxpwifi_close(struct net_device *dev) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + + if (priv->scan_request) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + nxpwifi_dbg(priv->adapter, INFO, + "aborting scan on ndo_stop\n"); + cfg80211_scan_done(priv->scan_request, &info); + priv->scan_request = NULL; + priv->scan_aborting = true; + } + + if (priv->sched_scanning) { + nxpwifi_dbg(priv->adapter, INFO, + "aborting bgscan on ndo_stop\n"); + nxpwifi_stop_bg_scan(priv); + cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0); + } + + return 0; +} + +static bool +nxpwifi_bypass_tx_queue(struct nxpwifi_private *priv, + struct sk_buff *skb) +{ + struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; + + if (eth_hdr->h_proto == htons(ETH_P_PAE) || + nxpwifi_is_skb_mgmt_frame(skb)) { + nxpwifi_dbg(priv->adapter, DATA, + "bypass txqueue; eth type %#x, mgmt %d\n", + ntohs(eth_hdr->h_proto), + nxpwifi_is_skb_mgmt_frame(skb)); + if (eth_hdr->h_proto == htons(ETH_P_PAE)) + nxpwifi_dbg(priv->adapter, MSG, + "key: send EAPOL to %pM\n", + eth_hdr->h_dest); + return true; + } + + return false; +} + +/* Add buffer into wmm tx queue and queue work to transmit it. + */ +void nxpwifi_queue_tx_pkt(struct nxpwifi_private *priv, struct sk_buff *skb) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct netdev_queue *txq; + int index = nxpwifi_1d_to_wmm_queue[skb->priority]; + + if (atomic_inc_return(&priv->wmm_tx_pending[index]) >= MAX_TX_PENDING) { + txq = netdev_get_tx_queue(priv->netdev, index); + if (!netif_tx_queue_stopped(txq)) { + netif_tx_stop_queue(txq); + nxpwifi_dbg(adapter, DATA, + "stop queue: %d\n", index); + } + } + + if (nxpwifi_bypass_tx_queue(priv, skb)) { + atomic_inc(&adapter->tx_pending); + atomic_inc(&adapter->bypass_tx_pending); + nxpwifi_wmm_add_buf_bypass_txqueue(priv, skb); + } else { + atomic_inc(&adapter->tx_pending); + nxpwifi_wmm_add_buf_txqueue(priv, skb); + } + + nxpwifi_queue_work(adapter, &adapter->main_work); +} + +struct sk_buff * +nxpwifi_clone_skb_for_tx_status(struct nxpwifi_private *priv, + struct sk_buff *skb, u8 flag, u64 *cookie) +{ + struct sk_buff *orig_skb = skb; + struct nxpwifi_txinfo *tx_info, *orig_tx_info; + + skb = skb_clone(skb, GFP_ATOMIC); + if (skb) { + int id; + + spin_lock_bh(&priv->ack_status_lock); + id = idr_alloc(&priv->ack_status_frames, orig_skb, + 1, 0x10, GFP_ATOMIC); + spin_unlock_bh(&priv->ack_status_lock); + + if (id >= 0) { + tx_info = NXPWIFI_SKB_TXCB(skb); + tx_info->ack_frame_id = id; + tx_info->flags |= flag; + orig_tx_info = NXPWIFI_SKB_TXCB(orig_skb); + orig_tx_info->ack_frame_id = id; + orig_tx_info->flags |= flag; + + if (flag == NXPWIFI_BUF_FLAG_ACTION_TX_STATUS && cookie) + orig_tx_info->cookie = *cookie; + + } else if (skb_shared(skb)) { + kfree_skb(orig_skb); + } else { + kfree_skb(skb); + skb = orig_skb; + } + } else { + /* couldn't clone -- lose tx status ... */ + skb = orig_skb; + } + + return skb; +} + +/* CFG802.11 network device handler for data transmission. + */ +static netdev_tx_t +nxpwifi_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct sk_buff *new_skb; + struct nxpwifi_txinfo *tx_info; + bool multicast; + + nxpwifi_dbg(priv->adapter, DATA, + "data: %lu BSS(%d-%d): Data <= kernel\n", + jiffies, priv->bss_type, priv->bss_num); + + if (test_bit(NXPWIFI_SURPRISE_REMOVED, &priv->adapter->work_flags)) { + kfree_skb(skb); + priv->stats.tx_dropped++; + return 0; + } + if (!skb->len || skb->len > ETH_FRAME_LEN) { + nxpwifi_dbg(priv->adapter, ERROR, + "Tx: bad skb len %d\n", skb->len); + kfree_skb(skb); + priv->stats.tx_dropped++; + return 0; + } + if (skb_headroom(skb) < NXPWIFI_MIN_DATA_HEADER_LEN) { + nxpwifi_dbg(priv->adapter, DATA, + "data: Tx: insufficient skb headroom %d\n", + skb_headroom(skb)); + /* Insufficient skb headroom - allocate a new skb */ + new_skb = + skb_realloc_headroom(skb, NXPWIFI_MIN_DATA_HEADER_LEN); + if (unlikely(!new_skb)) { + nxpwifi_dbg(priv->adapter, ERROR, + "Tx: cannot alloca new_skb\n"); + kfree_skb(skb); + priv->stats.tx_dropped++; + return 0; + } + kfree_skb(skb); + skb = new_skb; + nxpwifi_dbg(priv->adapter, INFO, + "info: new skb headroomd %d\n", + skb_headroom(skb)); + } + + tx_info = NXPWIFI_SKB_TXCB(skb); + memset(tx_info, 0, sizeof(*tx_info)); + tx_info->bss_num = priv->bss_num; + tx_info->bss_type = priv->bss_type; + tx_info->pkt_len = skb->len; + + multicast = is_multicast_ether_addr(skb->data); + + if (unlikely(!multicast && skb->sk && + skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS && + priv->adapter->fw_api_ver == NXPWIFI_FW_V15)) + skb = nxpwifi_clone_skb_for_tx_status(priv, + skb, + NXPWIFI_BUF_FLAG_EAPOL_TX_STATUS, NULL); + + /* Record the current time the packet was queued; used to + * determine the amount of time the packet was queued in + * the driver before it was sent to the firmware. + * The delay is then sent along with the packet to the + * firmware for aggregate delay calculation for stats and + * MSDU lifetime expiry. + */ + __net_timestamp(skb); + + nxpwifi_queue_tx_pkt(priv, skb); + + return 0; +} + +int nxpwifi_set_mac_address(struct nxpwifi_private *priv, + struct net_device *dev, bool external, + u8 *new_mac) +{ + int ret; + u64 mac_addr, old_mac_addr; + + old_mac_addr = ether_addr_to_u64(priv->curr_addr); + + if (external) { + mac_addr = ether_addr_to_u64(new_mac); + } else { + /* Internal mac address change */ + if (priv->bss_type == NXPWIFI_BSS_TYPE_ANY) + return -EOPNOTSUPP; + + mac_addr = old_mac_addr; + + if (priv->adapter->priv[0] != priv) { + /* Set mac address based on bss_type/bss_num */ + mac_addr ^= BIT_ULL(priv->bss_type + 8); + mac_addr += priv->bss_num; + } + } + + u64_to_ether_addr(mac_addr, priv->curr_addr); + + /* Send request to firmware */ + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_MAC_ADDRESS, + HOST_ACT_GEN_SET, 0, NULL, true); + + if (ret) { + u64_to_ether_addr(old_mac_addr, priv->curr_addr); + nxpwifi_dbg(priv->adapter, ERROR, + "set mac address failed: ret=%d\n", ret); + return ret; + } + + eth_hw_addr_set(dev, priv->curr_addr); + return 0; +} + +/* CFG802.11 network device handler for setting MAC address. + */ +static int +nxpwifi_ndo_set_mac_address(struct net_device *dev, void *addr) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct sockaddr *hw_addr = addr; + + return nxpwifi_set_mac_address(priv, dev, true, hw_addr->sa_data); +} + +/* CFG802.11 network device handler for setting multicast list. + */ +static void nxpwifi_set_multicast_list(struct net_device *dev) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + struct nxpwifi_multicast_list mcast_list; + + if (dev->flags & IFF_PROMISC) { + mcast_list.mode = NXPWIFI_PROMISC_MODE; + } else if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > NXPWIFI_MAX_MULTICAST_LIST_SIZE) { + mcast_list.mode = NXPWIFI_ALL_MULTI_MODE; + } else { + mcast_list.mode = NXPWIFI_MULTICAST_MODE; + mcast_list.num_multicast_addr = + nxpwifi_copy_mcast_addr(&mcast_list, dev); + } + nxpwifi_request_set_multicast_list(priv, &mcast_list); +} + +/* CFG802.11 network device handler for transmission timeout. + */ +static void +nxpwifi_tx_timeout(struct net_device *dev, unsigned int txqueue) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + + priv->num_tx_timeout++; + priv->tx_timeout_cnt++; + nxpwifi_dbg(priv->adapter, ERROR, + "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n", + jiffies, priv->tx_timeout_cnt, priv->bss_type, + priv->bss_num); + nxpwifi_set_trans_start(dev); + + if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD && + priv->adapter->if_ops.card_reset) { + nxpwifi_dbg(priv->adapter, ERROR, + "tx_timeout_cnt exceeds threshold.\t" + "Triggering card reset!\n"); + priv->adapter->if_ops.card_reset(priv->adapter); + } +} + +void nxpwifi_upload_device_dump(struct nxpwifi_adapter *adapter) +{ + /* Dump all the memory data into single file, a userspace script will + * be used to split all the memory data to multiple files + */ + nxpwifi_dbg(adapter, MSG, + "== nxpwifi dump information to /sys/class/devcoredump start\n"); + dev_coredumpv(adapter->dev, adapter->devdump_data, adapter->devdump_len, + GFP_KERNEL); + nxpwifi_dbg(adapter, MSG, + "== nxpwifi dump information to /sys/class/devcoredump end\n"); + + /* Device dump data will be freed in device coredump release function + * after 5 min. Here reset adapter->devdump_data and ->devdump_len + * to avoid it been accidentally reused. + */ + adapter->devdump_data = NULL; + adapter->devdump_len = 0; +} +EXPORT_SYMBOL_GPL(nxpwifi_upload_device_dump); + +void nxpwifi_drv_info_dump(struct nxpwifi_adapter *adapter) +{ + char *p; + char drv_version[64]; + struct sdio_mmc_card *sdio_card; + struct nxpwifi_private *priv; + int i, idx; + struct netdev_queue *txq; + struct nxpwifi_debug_info *debug_info; + + nxpwifi_dbg(adapter, MSG, "===nxpwifi driverinfo dump start===\n"); + + p = adapter->devdump_data; + strscpy(p, "========Start dump driverinfo========\n", NXPWIFI_FW_DUMP_SIZE); + p += strlen("========Start dump driverinfo========\n"); + p += sprintf(p, "driver_name = "); + p += sprintf(p, "\"nxpwifi\"\n"); + + nxpwifi_drv_get_driver_version(adapter, drv_version, + sizeof(drv_version) - 1); + p += sprintf(p, "driver_version = %s\n", drv_version); + + p += sprintf(p, "tx_pending = %d\n", + atomic_read(&adapter->tx_pending)); + + if (adapter->iface_type == NXPWIFI_SDIO) { + sdio_card = (struct sdio_mmc_card *)adapter->card; + p += sprintf(p, "\nmp_rd_bitmap=0x%x curr_rd_port=0x%x\n", + sdio_card->mp_rd_bitmap, sdio_card->curr_rd_port); + p += sprintf(p, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n", + sdio_card->mp_wr_bitmap, sdio_card->curr_wr_port); + } + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i] || !adapter->priv[i]->netdev) + continue; + priv = adapter->priv[i]; + p += sprintf(p, "\n[interface : \"%s\"]\n", + priv->netdev->name); + p += sprintf(p, "wmm_tx_pending[0] = %d\n", + atomic_read(&priv->wmm_tx_pending[0])); + p += sprintf(p, "wmm_tx_pending[1] = %d\n", + atomic_read(&priv->wmm_tx_pending[1])); + p += sprintf(p, "wmm_tx_pending[2] = %d\n", + atomic_read(&priv->wmm_tx_pending[2])); + p += sprintf(p, "wmm_tx_pending[3] = %d\n", + atomic_read(&priv->wmm_tx_pending[3])); + p += sprintf(p, "media_state=\"%s\"\n", !priv->media_connected ? + "Disconnected" : "Connected"); + p += sprintf(p, "carrier %s\n", (netif_carrier_ok(priv->netdev) + ? "on" : "off")); + for (idx = 0; idx < priv->netdev->num_tx_queues; idx++) { + txq = netdev_get_tx_queue(priv->netdev, idx); + p += sprintf(p, "tx queue %d:%s ", idx, + netif_tx_queue_stopped(txq) ? + "stopped" : "started"); + } + p += sprintf(p, "\n%s: num_tx_timeout = %d\n", + priv->netdev->name, priv->num_tx_timeout); + } + + if (adapter->iface_type == NXPWIFI_SDIO) { + p += sprintf(p, "\n=== %s register dump===\n", "SDIO"); + if (adapter->if_ops.reg_dump) + p += adapter->if_ops.reg_dump(adapter, p); + } + p += sprintf(p, "\n=== more debug information\n"); + debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL); + if (debug_info) { + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i] || !adapter->priv[i]->netdev) + continue; + priv = adapter->priv[i]; + nxpwifi_get_debug_info(priv, debug_info); + p += nxpwifi_debug_info_to_buffer(priv, p, debug_info); + break; + } + kfree(debug_info); + } + + p += sprintf(p, "\n========End dump========\n"); + nxpwifi_dbg(adapter, MSG, "===nxpwifi driverinfo dump end===\n"); + adapter->devdump_len = p - (char *)adapter->devdump_data; +} +EXPORT_SYMBOL_GPL(nxpwifi_drv_info_dump); + +void nxpwifi_prepare_fw_dump_info(struct nxpwifi_adapter *adapter) +{ + u8 idx; + char *fw_dump_ptr; + u32 dump_len = 0; + + for (idx = 0; idx < adapter->num_mem_types; idx++) { + struct memory_type_mapping *entry = + &adapter->mem_type_mapping_tbl[idx]; + + if (entry->mem_ptr) { + dump_len += (strlen("========Start dump ") + + strlen(entry->mem_name) + + strlen("========\n") + + (entry->mem_size + 1) + + strlen("\n========End dump========\n")); + } + } + + if (dump_len + 1 + adapter->devdump_len > NXPWIFI_FW_DUMP_SIZE) { + /* Realloc in case buffer overflow */ + fw_dump_ptr = vzalloc(dump_len + 1 + adapter->devdump_len); + nxpwifi_dbg(adapter, MSG, "Realloc device dump data.\n"); + if (!fw_dump_ptr) { + vfree(adapter->devdump_data); + nxpwifi_dbg(adapter, ERROR, + "vzalloc devdump data failure!\n"); + return; + } + + memmove(fw_dump_ptr, adapter->devdump_data, + adapter->devdump_len); + vfree(adapter->devdump_data); + adapter->devdump_data = fw_dump_ptr; + } + + fw_dump_ptr = (char *)adapter->devdump_data + adapter->devdump_len; + + for (idx = 0; idx < adapter->num_mem_types; idx++) { + struct memory_type_mapping *entry = + &adapter->mem_type_mapping_tbl[idx]; + + if (entry->mem_ptr) { + fw_dump_ptr += sprintf(fw_dump_ptr, "========Start dump "); + fw_dump_ptr += sprintf(fw_dump_ptr, "%s", entry->mem_name); + fw_dump_ptr += sprintf(fw_dump_ptr, "========\n"); + memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size); + fw_dump_ptr += entry->mem_size; + fw_dump_ptr += sprintf(fw_dump_ptr, "\n========End dump========\n"); + } + } + + adapter->devdump_len = fw_dump_ptr - (char *)adapter->devdump_data; + + for (idx = 0; idx < adapter->num_mem_types; idx++) { + struct memory_type_mapping *entry = + &adapter->mem_type_mapping_tbl[idx]; + + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + entry->mem_size = 0; + } +} +EXPORT_SYMBOL_GPL(nxpwifi_prepare_fw_dump_info); + +/* CFG802.11 network device handler for statistics retrieval. + */ +static struct net_device_stats *nxpwifi_get_stats(struct net_device *dev) +{ + struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(dev); + + return &priv->stats; +} + +static u16 +nxpwifi_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev) +{ + skb->priority = cfg80211_classify8021d(skb, NULL); + return nxpwifi_1d_to_wmm_queue[skb->priority]; +} + +/* Network device handlers */ +static const struct net_device_ops nxpwifi_netdev_ops = { + .ndo_open = nxpwifi_open, + .ndo_stop = nxpwifi_close, + .ndo_start_xmit = nxpwifi_hard_start_xmit, + .ndo_set_mac_address = nxpwifi_ndo_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = nxpwifi_tx_timeout, + .ndo_get_stats = nxpwifi_get_stats, + .ndo_set_rx_mode = nxpwifi_set_multicast_list, + .ndo_select_queue = nxpwifi_netdev_select_wmm_queue, +}; + +/* This function initializes the private structure parameters. + * + * The following wait queues are initialized - + * - IOCTL wait queue + * - Command wait queue + * - Statistics wait queue + * + * ...and the following default parameters are set - + * - Current key index : Set to 0 + * - Rate index : Set to auto + * - Media connected : Set to disconnected + * - Nick name : Set to null + * - Number of Tx timeout : Set to 0 + * - Device address : Set to current address + * - Rx histogram statistc : Set to 0 + * + * In addition, the CFG80211 work queue is also created. + */ +void nxpwifi_init_priv_params(struct nxpwifi_private *priv, + struct net_device *dev) +{ + dev->netdev_ops = &nxpwifi_netdev_ops; + dev->needs_free_netdev = true; + /* Initialize private structure */ + priv->current_key_index = 0; + priv->media_connected = false; + memset(priv->mgmt_ie, 0, + sizeof(struct nxpwifi_ie) * MAX_MGMT_IE_INDEX); + priv->beacon_idx = NXPWIFI_AUTO_IDX_MASK; + priv->proberesp_idx = NXPWIFI_AUTO_IDX_MASK; + priv->assocresp_idx = NXPWIFI_AUTO_IDX_MASK; + priv->gen_idx = NXPWIFI_AUTO_IDX_MASK; + priv->num_tx_timeout = 0; + if (is_valid_ether_addr(dev->dev_addr)) + ether_addr_copy(priv->curr_addr, dev->dev_addr); + else + ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr); + + if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) { + priv->hist_data = kmalloc(sizeof(*priv->hist_data), GFP_KERNEL); + if (priv->hist_data) + nxpwifi_hist_data_reset(priv); + } +} + +/* This function check if command is pending. + */ +int is_command_pending(struct nxpwifi_adapter *adapter) +{ + int is_cmd_pend_q_empty; + + spin_lock_bh(&adapter->cmd_pending_q_lock); + is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); + spin_unlock_bh(&adapter->cmd_pending_q_lock); + + return !is_cmd_pend_q_empty; +} + +/* This is the RX tasklet function. + * + * It handles the RX operations. + */ +static void nxpwifi_rx_recv(unsigned long data) +{ + struct nxpwifi_adapter *adapter = (struct nxpwifi_adapter *)data; + + if (test_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags)) + return; + + nxpwifi_process_rx(adapter); +} + +/* This is the main work function. + * + * It handles the main process, which in turn handles the complete + * driver operations. + */ +static void nxpwifi_main_work(struct work_struct *work) +{ + struct nxpwifi_adapter *adapter = + container_of(work, struct nxpwifi_adapter, main_work); + + if (test_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags)) + return; + + nxpwifi_main_process(adapter); +} + +/* This is the host mlme work function. + * It handles the host mlme operations. + */ +static void nxpwifi_host_mlme_work(struct work_struct *work) +{ + struct nxpwifi_adapter *adapter = + container_of(work, struct nxpwifi_adapter, host_mlme_work); + + if (test_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags)) + return; + + /* Check for host mlme disconnection */ + if (adapter->host_mlme_link_lost) { + if (adapter->priv_link_lost) { + nxpwifi_reset_connect_state(adapter->priv_link_lost, + WLAN_REASON_DEAUTH_LEAVING, + true); + adapter->priv_link_lost = NULL; + } + adapter->host_mlme_link_lost = false; + } + + /* Check for host mlme Assoc Resp */ + if (adapter->assoc_resp_received) { + nxpwifi_process_assoc_resp(adapter); + adapter->assoc_resp_received = false; + } +} + +/* This is the rx mlme work function. + * It handles rx mlme packets. + */ +static void nxpwifi_rx_mlme_work(struct work_struct *work) +{ + struct nxpwifi_adapter *adapter = + container_of(work, struct nxpwifi_adapter, rx_mlme_work); + struct sk_buff *skb; + struct nxpwifi_rxinfo *rx_info; + struct nxpwifi_private *priv; + + if (test_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags)) + return; + + while ((skb = skb_dequeue(&adapter->rx_mlme_q))) { + rx_info = NXPWIFI_SKB_RXCB(skb); + priv = adapter->priv[rx_info->bss_num]; + cfg80211_rx_mlme_mgmt(priv->netdev, + skb->data, + rx_info->pkt_len); + } +} + +/* Common teardown code used for both device removal and reset */ +static void nxpwifi_uninit_sw(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + int i; + + /* We can no longer handle interrupts once we start doing the teardown + * below. + */ + if (adapter->if_ops.disable_int) + adapter->if_ops.disable_int(adapter); + + set_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags); + tasklet_kill(&adapter->rx_task); + nxpwifi_terminate_workqueue(adapter); + adapter->int_status = 0; + + /* Stop data */ + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv && priv->netdev) { + nxpwifi_stop_net_dev_queue(priv->netdev, adapter); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + netif_device_detach(priv->netdev); + } + } + + nxpwifi_dbg(adapter, CMD, "cmd: calling nxpwifi_shutdown_drv...\n"); + nxpwifi_shutdown_drv(adapter); + nxpwifi_dbg(adapter, CMD, "cmd: nxpwifi_shutdown_drv done\n"); + + if (atomic_read(&adapter->tx_pending) || + atomic_read(&adapter->cmd_pending)) { + nxpwifi_dbg(adapter, ERROR, + "tx_pending=%d,cmd_pending=%d\n", + atomic_read(&adapter->tx_pending), + atomic_read(&adapter->cmd_pending)); + } + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (!priv) + continue; + rtnl_lock(); + if (priv->netdev && + priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) { + /* Close the netdev now, because if we do it later, the + * netdev notifiers will need to acquire the wiphy lock + * again --> deadlock. + */ + dev_close(priv->wdev.netdev); + wiphy_lock(adapter->wiphy); + nxpwifi_del_virtual_intf(adapter->wiphy, &priv->wdev); + wiphy_unlock(adapter->wiphy); + } + rtnl_unlock(); + } + + wiphy_unregister(adapter->wiphy); + wiphy_free(adapter->wiphy); + adapter->wiphy = NULL; + + vfree(adapter->chan_stats); + nxpwifi_free_cmd_buffers(adapter); +} + +/* This function can be used for shutting down the adapter SW. + */ +void nxpwifi_shutdown_sw(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + + if (!adapter) + return; + + wait_for_completion(adapter->fw_done); + /* Caller should ensure we aren't suspending while this happens */ + reinit_completion(adapter->fw_done); + + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + nxpwifi_deauthenticate(priv, NULL); + + nxpwifi_init_shutdown_fw(priv, NXPWIFI_FUNC_SHUTDOWN); + + nxpwifi_uninit_sw(adapter); + adapter->is_up = false; +} +EXPORT_SYMBOL_GPL(nxpwifi_shutdown_sw); + +/* This function can be used for reinitting the adapter SW. Required + * code is extracted from nxpwifi_add_card() + */ +int +nxpwifi_reinit_sw(struct nxpwifi_adapter *adapter) +{ + int ret = 0; + + nxpwifi_init_lock_list(adapter); + if (adapter->if_ops.up_dev) + adapter->if_ops.up_dev(adapter); + + adapter->hw_status = NXPWIFI_HW_STATUS_INITIALIZING; + clear_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags); + init_waitqueue_head(&adapter->init_wait_q); + clear_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags); + adapter->hs_activated = false; + clear_bit(NXPWIFI_IS_CMD_TIMEDOUT, &adapter->work_flags); + init_waitqueue_head(&adapter->hs_activate_wait_q); + init_waitqueue_head(&adapter->cmd_wait_q.wait); + adapter->cmd_wait_q.status = 0; + adapter->scan_wait_q_woken = false; + + tasklet_init(&adapter->rx_task, + (void *)nxpwifi_rx_recv, (unsigned long)adapter); + tasklet_disable(&adapter->rx_task); + + adapter->workqueue = + alloc_workqueue("NXPWIFI_WORK_QUEUE", + WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 0); + if (!adapter->workqueue) { + ret = -ENOMEM; + goto err_kmalloc; + } + + INIT_WORK(&adapter->main_work, nxpwifi_main_work); + INIT_WORK(&adapter->host_mlme_work, nxpwifi_host_mlme_work); + INIT_WORK(&adapter->rx_mlme_work, nxpwifi_rx_mlme_work); + + /* Register the device. Fill up the private data structure with + * relevant information from the card. Some code extracted from + * nxpwifi_register_dev() + */ + nxpwifi_dbg(adapter, INFO, "%s, nxpwifi_init_hw_fw()...\n", __func__); + + ret = nxpwifi_init_hw_fw(adapter, false); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "%s: firmware init failed\n", __func__); + goto err_init_fw; + } + + /* _nxpwifi_fw_dpc() does its own cleanup */ + ret = _nxpwifi_fw_dpc(adapter->firmware, adapter); + if (ret) { + pr_err("Failed to bring up adapter: %d\n", ret); + return ret; + } + nxpwifi_dbg(adapter, INFO, "%s, successful\n", __func__); + + tasklet_enable(&adapter->rx_task); + + return ret; + +err_init_fw: + nxpwifi_dbg(adapter, ERROR, "info: %s: unregister device\n", __func__); + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); + +err_kmalloc: + set_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags); + tasklet_kill(&adapter->rx_task); + nxpwifi_terminate_workqueue(adapter); + if (adapter->hw_status == NXPWIFI_HW_STATUS_READY) { + nxpwifi_dbg(adapter, ERROR, + "info: %s: shutdown nxpwifi\n", __func__); + nxpwifi_shutdown_drv(adapter); + nxpwifi_free_cmd_buffers(adapter); + } + + complete_all(adapter->fw_done); + nxpwifi_dbg(adapter, INFO, "%s, error\n", __func__); + + return ret; +} +EXPORT_SYMBOL_GPL(nxpwifi_reinit_sw); + +static irqreturn_t nxpwifi_irq_wakeup_handler(int irq, void *priv) +{ + struct nxpwifi_adapter *adapter = priv; + + dev_dbg(adapter->dev, "%s: wake by wifi", __func__); + adapter->wake_by_wifi = true; + disable_irq_nosync(irq); + + /* Notify PM core we are wakeup source */ + pm_wakeup_event(adapter->dev, 0); + pm_system_wakeup(); + + return IRQ_HANDLED; +} + +static void nxpwifi_probe_of(struct nxpwifi_adapter *adapter) +{ + int ret; + struct device *dev = adapter->dev; + + if (!dev->of_node) + goto err_exit; + + adapter->dt_node = dev->of_node; + adapter->irq_wakeup = irq_of_parse_and_map(adapter->dt_node, 0); + if (!adapter->irq_wakeup) { + dev_dbg(dev, "fail to parse irq_wakeup from device tree\n"); + goto err_exit; + } + + ret = devm_request_irq(dev, adapter->irq_wakeup, + nxpwifi_irq_wakeup_handler, IRQF_TRIGGER_LOW, + "wifi_wake", adapter); + if (ret) { + dev_err(dev, "Failed to request irq_wakeup %d (%d)\n", + adapter->irq_wakeup, ret); + goto err_exit; + } + + disable_irq(adapter->irq_wakeup); + if (device_init_wakeup(dev, true)) { + dev_err(dev, "fail to init wakeup for nxpwifi\n"); + goto err_exit; + } + return; + +err_exit: + adapter->irq_wakeup = -1; +} + +/* This function adds the card. + * + * This function follows the following major steps to set up the device - + * - Initialize software. This includes probing the card, registering + * the interface operations table, and allocating/initializing the + * adapter structure + * - Set up the netlink socket + * - Create and start the main work queue + * - Register the device + * - Initialize firmware and hardware + * - Add logical interfaces + */ +int +nxpwifi_add_card(void *card, struct completion *fw_done, + struct nxpwifi_if_ops *if_ops, u8 iface_type, + struct device *dev) +{ + struct nxpwifi_adapter *adapter; + int ret = 0; + + adapter = nxpwifi_register(card, dev, if_ops); + if (IS_ERR(adapter)) { + ret = PTR_ERR(adapter); + pr_err("%s: adapter register failed %d\n", __func__, ret); + goto err_init_sw; + } + + nxpwifi_probe_of(adapter); + + adapter->iface_type = iface_type; + adapter->fw_done = fw_done; + + adapter->hw_status = NXPWIFI_HW_STATUS_INITIALIZING; + clear_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags); + init_waitqueue_head(&adapter->init_wait_q); + clear_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags); + adapter->hs_activated = false; + init_waitqueue_head(&adapter->hs_activate_wait_q); + init_waitqueue_head(&adapter->cmd_wait_q.wait); + adapter->cmd_wait_q.status = 0; + adapter->scan_wait_q_woken = false; + + tasklet_init(&adapter->rx_task, + (void *)nxpwifi_rx_recv, (unsigned long)adapter); + tasklet_disable(&adapter->rx_task); + + adapter->workqueue = + alloc_workqueue("NXPWIFI_WORK_QUEUE", + WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 0); + if (!adapter->workqueue) { + ret = -ENOMEM; + goto err_kmalloc; + } + + INIT_WORK(&adapter->main_work, nxpwifi_main_work); + INIT_WORK(&adapter->host_mlme_work, nxpwifi_host_mlme_work); + INIT_WORK(&adapter->rx_mlme_work, nxpwifi_rx_mlme_work); + + /* Register the device. Fill up the private data structure with relevant + * information from the card. + */ + ret = adapter->if_ops.register_dev(adapter); + if (ret) { + pr_err("%s: failed to register nxpwifi device\n", __func__); + goto err_registerdev; + } + + ret = nxpwifi_init_hw_fw(adapter, true); + if (ret) { + pr_err("%s: firmware init failed\n", __func__); + goto err_init_fw; + } + + tasklet_enable(&adapter->rx_task); + + return ret; + +err_init_fw: + pr_debug("info: %s: unregister device\n", __func__); + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); +err_registerdev: + set_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags); + tasklet_kill(&adapter->rx_task); + nxpwifi_terminate_workqueue(adapter); + if (adapter->hw_status == NXPWIFI_HW_STATUS_READY) { + pr_debug("info: %s: shutdown nxpwifi\n", __func__); + nxpwifi_shutdown_drv(adapter); + nxpwifi_free_cmd_buffers(adapter); + } +err_kmalloc: + if (adapter->irq_wakeup >= 0) + device_init_wakeup(adapter->dev, false); + nxpwifi_free_adapter(adapter); + +err_init_sw: + + return ret; +} +EXPORT_SYMBOL_GPL(nxpwifi_add_card); + +/* This function removes the card. + * + * This function follows the following major steps to remove the device - + * - Stop data traffic + * - Shutdown firmware + * - Remove the logical interfaces + * - Terminate the work queue + * - Unregister the device + * - Free the adapter structure + */ +void nxpwifi_remove_card(struct nxpwifi_adapter *adapter) +{ + if (!adapter) + return; + + if (adapter->is_up) + nxpwifi_uninit_sw(adapter); + + if (adapter->irq_wakeup >= 0) + device_init_wakeup(adapter->dev, false); + + /* Unregister device */ + nxpwifi_dbg(adapter, INFO, + "info: unregister device\n"); + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); + /* Free adapter structure */ + nxpwifi_dbg(adapter, INFO, + "info: free adapter\n"); + nxpwifi_free_adapter(adapter); +} +EXPORT_SYMBOL_GPL(nxpwifi_remove_card); + +void _nxpwifi_dbg(const struct nxpwifi_adapter *adapter, int mask, + const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + if (!(adapter->debug_mask & mask)) + return; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + if (adapter->dev) + dev_info(adapter->dev, "%pV", &vaf); + else + pr_info("%pV", &vaf); + + va_end(args); +} +EXPORT_SYMBOL_GPL(_nxpwifi_dbg); + +/* This function initializes the module. + * + * The debug FS is also initialized if configured. + */ +static int +nxpwifi_init_module(void) +{ +#ifdef CONFIG_DEBUG_FS + nxpwifi_debugfs_init(); +#endif + return 0; +} + +/* This function cleans up the module. + * + * The debug FS is removed if available. + */ +static void +nxpwifi_cleanup_module(void) +{ +#ifdef CONFIG_DEBUG_FS + nxpwifi_debugfs_remove(); +#endif +} + +module_init(nxpwifi_init_module); +module_exit(nxpwifi_cleanup_module); + +MODULE_AUTHOR("NXP International Ltd."); +MODULE_DESCRIPTION("NXP WiFi Driver version " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); From patchwork Fri Aug 9 09:45:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818387 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EEA991991BB; Fri, 9 Aug 2024 09:47:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196841; cv=fail; b=QruSE6wy7byV5BAlz/2kNBQRmrMy+UEjmJNvDwXvCs2TzvIioQFhmicsoGa7uF1yS5ykChKMzOkKLpv7oVN4ZID0XIQsvfNDtAU0IsMvlAiH2281pMJnJOySyq+/AeSy4LZspemM1hUIBuILGsv7qqFVJM5xBB7ftzE9BUGMEFI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196841; c=relaxed/simple; bh=wG9KO3wyO5/+VlP9FWt+0iWhmYP42qArz/oeSaBwMSg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=jrRX7pmGIIR33STqjxa2rm4C1Nz6dWkw8vxVoZiscDvrb1LBolQpoofhvhx0ECA2pZbKpj3jZr4cNBax1WKq8fAAfO5oDmZ+nQTarpg2qwaZsDu+0DTvzHraVX1eSokucMMkb0j6pjBtpSACN7M3WJFCCNSVooCC/OIpYRDnLJo= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=YdexqPV1; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="YdexqPV1" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=GVfGIHkpIICc7TYALRq8ohHUMwy/9yvLTIMpsrkZfuC4C3Ttt4PxfyUr7XoBPt/tPpnJaYtvp+3kJaUgfgA/qNHRPyKKfup4NXc69DdG8Hy1ANvuLTMrHbwe5J9Ym05vvgtzcAAIx40ogjIdtVEe9MKXsfQoW1jPSd+EZY0s0Xz7w1blAcBPTwf2ozdz1mdJOaBqDte+hnFTC0cJeCBUBB1ZEVvCfcepktcwjK3/LS7KYWd1MvZLww3A7rC2qWMSHR60DbTyD2xNNDeCFy59hA8tU/EnvGb/YC/rdKB5cRFNd+bDTCT8X1Q1J+8edapMuLSii1VxfO5RZiHJ6Cu4rw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=vkAavaoGg43VlHv1lz0t3EQfOLCfry6Jlwy/EcVvtW4=; b=QkjH9twdtqAeIE5WCbN87iGblU71Afxt5weDgVS4oZFQlDnjk2sce6ixH1t0vSzM3x94SHvv9I5o2k9TsLvKFybbFTSDRY0LgKDhub1uhY08FkTM2WWfmBu1XtHuJCBbXFCD0q/RE6CndSb3Lr02BlgDCkD+QIdzRjL8GekqMPkEuGpaqfSbSnMdl5/gPCuMToPvFp9DBa8OOTPWmdPGwVxi5rLeDpjUVL+82berLA3b/owNyAYz+RAEN1VYEQFQU93cRr0BsvoZYrr3SqYNhy5J5/BfWGZ3Dq+AjwefoTzTDmGP9i035aJbVQc2wkHcEV5SwqdTl2fVw0rWKPQe8Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=vkAavaoGg43VlHv1lz0t3EQfOLCfry6Jlwy/EcVvtW4=; b=YdexqPV1PYe+CYybKRbxmRH6CJt+En3jGrmZr26e8Hgm+ygYLsWDosILfo7qQw+ufV4yM1rmoQ1HkhHw9VxdQPMDEvvMT/q93G0m7ronzfud7rtTbhkg6A0YmJeia5EIMB7qcREFEZt8eslRZB4pjfusfe7SPTsUcYyOpUmGU6k7tLMgtkukKiox/8W1DaV8Srz2EzM1Xhyeu1Z1eUE3ZT6xgRiRGReCK8FpaVC13OdZcLhIWCYrlKMp6nPBgD+jqY7clhiRfynzPHe02nRbhIuXb+AL63claAZ414r+PIXffEe9zgnkWxN8/KHp0LshDjH2u3TcDrs7JSdX41sbLA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:47:10 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:47:10 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 24/43] wifi: nxpwifi: add main.h Date: Fri, 9 Aug 2024 17:45:14 +0800 Message-Id: <20240809094533.1660-25-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: f4a61959-a58d-44d9-eb1d-08dcb8583ccf X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: 2WgnONESMjAlBF2Ci0GWfFoymP5jA1XtX+3ovdWlnJDN3dewPIba+YIL5oxQA8Zvktwzer2xGusDYgxeoSb/rVhKhk7Yti2PKBAwL0BxSQ1hY5ABpJYU8b2yJSvCFWaHe/aOtao/LQImiy3MDVkNViQoDCaCYmWEyx3Nd7wmFIa73FH1B2ipN/O/FKZSbh1t93WkT8e4XxBlYHur8cH5gvBJo6AXOjD9obVFOoMRYzVWVv4/U//MGX0qtDH+V41gpM7ptgY+lmISehKdH58eqpglRtBEwFIN/xYqkz5OqenCrw/ELdy80QQZWhjyrDTo7GrUc4BBCLipxCSSTOxkEUeEUelbXBE5LNkw1gePmGhkvr0hSNXe7g4FsaJdl9bDBnhRCIli6hH23SeSwlQ+HU8AjY2ooIaURpTFpmzE2p6stF6C5LLCwk43YcoetCi2yIbvthvf4LTmDjrPSZcri9iFrNtwecw7JD0EiOJB0HKOWjDdqP/djZdTO8Jpsb+drCCJl8zhWrwZJh3MIUsSI5XrjoXmlp12duEiXqu1pjM4wWNE7f7zIsCICK7Tm6vo1bVOQERT5L1UNoZFXuwYjGXAR+GA849bAtXMtwoHWZrCaN+47EpTM3JblXVpRvNglez0gja1KWKMC9yl064zIh/Zc3thCfjYSaGuYS964XWc6A8Xisy8gkkCKC6djL+lzlyqU6uWuQslKCiY4PNIh4N7UKqUiI4JgOVy1aMQEla3ro2x5rUds4z2h43lucvro2jHKRfv2fg2R7hohk07IwNoMqKF65LiYa0q8qUINxZXKItREZsxZYqJRIC5pmFj7NfiXJigWm2+xl6JtYxxEyIdx2HsBM64VC7xx+IVhee2EiUl+ZuyVwlV2Nu//qwQOqt+G74/G05KZXlVN/eNmpUUtEaC0s2mTjYA9J03EreBiUbieWQedxNUoZLgT9vusFMnqoY0H7Q5joVj2WH71cMB15egMS7MxnpeAkxjPVgit4b4R3qkrYfx5iuq6BUpyUw7nrNVOYgkj7A5dErPA69RdG6CmqqR9wJbgFkZGAtMI0uyrxCz7q2r6BcLurpnHx42ZekYl0/F9fy3bWyOVwjh5JZ3cr3nFkcgL65TrKnwEqmZzv2c1RRWkXqr5HMCp5RD9sRhUydzIsLxesCrM9nM10um+3msu6r7yxWiIfnH/sDxkuT6PMdBp7qUHdK5glwLPA92iZY3TBZ7XvvnR9ouMQe80Fo9rG5gitaXQp5EcDL6QfOAUXDcwNMx1XtF7X4YaiRp3EEL9QJsMiJHMv5hkJtSNY6kq1d057tY6Hdx6etXU62cdHfR8jb9DRGnE7n6HMvU3a4C+R5PXa1OfQ== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: jz1NQXg6jhIEoJ5v1jW92tNBvCQfA2OnaEUB1CdRXL6yFrfJ7xzFXzR484mOWJpKnyBgWEmZVBOui6hGhbCtQy6wtcaA/x82L2UVzq3bALvniYx+oev3ZatEaeCxIWoQwUVt4n3o4yQ/F83a1g4HoRY/rg+DkwxtDeZOhNdDBAAPFiSBTSMAoreO42s7PiWfRxqoFvlzzYo4kzhtZRFKTPq48iP59elqoJgcuIa9M8xtcQr4J5dNfUI9fd3Ae2F2QonkwJ+9HBXHwhWNOHBbKTRweU2YyHGw7ViiXudAtTnCoZHP1RV0b83X2sArMU6Dp2A23ZpBKqalLvShDkgWEI8nkocVBENyFMWqnTwbtffEX6WGGS32Q3aQA5Usue9ZgU+vIuNLdpjUeBGbSKw/Exsgycz0p+JunvxZbVAUYW47eQeok0VmmpjgQD08XWYM2pR6YT1eoA7U/fXZKgSvYExbiTfUwBlIDtfSGdZnlqwyG2UfM4qy66h5aWLhMvUDbuhWu/TqSXDY3y2fUTWzBhQaWSBaHpX5M3Dgei8FT1psmWqxsDKCjbLPBiUj6ihhtFRWwetHM4sEZJdhHGh+t8eTf0T/o01GMQ5LOxDyJAB7iOhSLmPL7v3alSj4eNU+a1bYIFDI2aSV/DA5rtokcowwxDi6MRi85UbuaTK3JNJEWVXt3HXB6mG6Epxe0HvqqeGcxAo53Ip29vThIFMAFFr5CjTGZweMoPmW6VJZCPqpWUXO65pnudsy4YBmXhh4ZSskGS357j9iyfNC9VdY+tqq/7psCRgvae8Du27uEtPwWx27qkmtBNuh3ZiOa9uEjjf8ZCRp/R4YrzziUASx/qZrpXjAxPvx+DTPbrPqj+CJIYTCzBsMUqFN2F83yjrZnR/WxkYwkNF27ZzyuG2yNh7HEwWdfjpEblZjeBS+SFLC4YwS5xBy8C6/QGQIGx9isN8mWeFBIkTMaEz5/8vgvBmU8Nulw6tQHRqKw8iXeGuNtOXpi9mCinaeDJtAr/ESnrzvWywPGZS3fOl07EICH2tzX3FU2OIROyRnWjl1W0GGAnaJDyV/4eOCjw6mt9JJ/iubpYDTzIAMXgXfuYiNlOnA26N0QCI4c4a4fOy/y8MHxReyMS9U8rj6KyC98voSy2tqeUZSfmXVZjYoLQ215UGq8DPowVaVfF5M4MuiID6nYqtziG2Wx91mL/6m00TLJEWuESC5k5R3KoY98FpTCnElmZ1+NP6roAuBueolwrRbooBYhjzBZjlXAM2/9usmdGYUgxLK/hiE0ZbyUqy41rYaUivM2H/ssmYvG93neE1Il+/2A+H1U2XH9zrARw8QYrhtegsggnoS61IVgSWq5gAJ5unBJb7wsGHMiTgZ/H94n6D+zI4phjDeg9VH1BZS32607k+HOwutvyDqkTuBra9Ht19QjxMwHfwqUub0kmVllMxQ2HmL/g+IMrC/QIRdU57HDr5b5lKD1s7x+uX47AjDN+E3s/S8FuCzBmvsmZtUgLI+BypYsrKnaYIkfgb0FKWkIx/QiaBq5DYF+d4MhyYMxBVcZsxYXtGEt3B62dHKfSKbqXl40COBX3ki74LTamA755zvtVRa0WpwZHbYghXGQH5N9sOA51fyx7I8v/g/JPdaG9baTtPLwS+wRTl7 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: f4a61959-a58d-44d9-eb1d-08dcb8583ccf X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:47:10.0321 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: CA1VBVLRTVVpoWemLxy+hlzM8uMWBVv3k5CfgDaAWp5URFWE8s3xav0VEnwdG0VU7+F9eqwEsoAuLZZ4sM3RMg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/main.h | 1478 +++++++++++++++++++++++ 1 file changed, 1478 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/main.h diff --git a/drivers/net/wireless/nxp/nxpwifi/main.h b/drivers/net/wireless/nxp/nxpwifi/main.h new file mode 100644 index 000000000000..62a0f4a7e37d --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/main.h @@ -0,0 +1,1478 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: major data structures and prototypes + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_MAIN_H_ +#define _NXPWIFI_MAIN_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "sdio.h" + +extern char driver_version[]; + +struct nxpwifi_adapter; +struct nxpwifi_private; + +enum { + NXPWIFI_ASYNC_CMD, + NXPWIFI_SYNC_CMD +}; + +#define NXPWIFI_MAX_AP 64 + +#define NXPWIFI_MAX_PKTS_TXQ 16 + +#define NXPWIFI_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) + +#define NXPWIFI_TIMER_10S 10000 +#define NXPWIFI_TIMER_1S 1000 + +#define MAX_TX_PENDING 400 +#define LOW_TX_PENDING 380 + +#define HIGH_RX_PENDING 50 +#define LOW_RX_PENDING 20 + +#define NXPWIFI_UPLD_SIZE (2312) + +#define MAX_EVENT_SIZE 2048 + +#define NXPWIFI_FW_DUMP_SIZE (2 * 1024 * 1024) + +#define ARP_FILTER_MAX_BUF_SIZE 68 + +#define NXPWIFI_KEY_BUFFER_SIZE 16 +#define NXPWIFI_DEFAULT_LISTEN_INTERVAL 10 +#define NXPWIFI_MAX_REGION_CODE 9 + +#define DEFAULT_BCN_AVG_FACTOR 8 +#define DEFAULT_DATA_AVG_FACTOR 8 + +#define FIRST_VALID_CHANNEL 0xff + +#define DEFAULT_BCN_MISS_TIMEOUT 5 + +#define MAX_SCAN_BEACON_BUFFER 8000 + +#define SCAN_BEACON_ENTRY_PAD 6 + +#define NXPWIFI_PASSIVE_SCAN_CHAN_TIME 110 +#define NXPWIFI_ACTIVE_SCAN_CHAN_TIME 40 +#define NXPWIFI_SPECIFIC_SCAN_CHAN_TIME 40 +#define NXPWIFI_DEF_SCAN_CHAN_GAP_TIME 50 + +#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) + +#define NXPWIFI_MAX_TOTAL_SCAN_TIME (NXPWIFI_TIMER_10S - NXPWIFI_TIMER_1S) + +#define WPA_GTK_OUI_OFFSET 2 +#define RSN_GTK_OUI_OFFSET 2 + +#define NXPWIFI_OUI_NOT_PRESENT 0 +#define NXPWIFI_OUI_PRESENT 1 + +#define PKT_TYPE_MGMT 0xE5 + +/* Do not check for data_received for USB, as data_received + * is handled in nxpwifi_usb_recv for USB + */ +#define IS_CARD_RX_RCVD(adapter) ({ \ + typeof(adapter) (_adapter) = adapter; \ + ((_adapter)->cmd_resp_received || \ + (_adapter)->event_received || \ + (_adapter)->data_received); \ + }) + +#define NXPWIFI_TYPE_DATA 0 +#define NXPWIFI_TYPE_CMD 1 +#define NXPWIFI_TYPE_EVENT 3 +#define NXPWIFI_TYPE_VDLL 4 +#define NXPWIFI_TYPE_AGGR_DATA 10 + +#define MAX_BITMAP_RATES_SIZE 18 + +#define MAX_CHANNEL_BAND_BG 14 +#define MAX_CHANNEL_BAND_A 165 + +#define MAX_FREQUENCY_BAND_BG 2484 + +#define NXPWIFI_EVENT_HEADER_LEN 4 +#define NXPWIFI_UAP_EVENT_EXTRA_HEADER 2 + +#define NXPWIFI_TYPE_LEN 4 +#define NXPWIFI_USB_TYPE_CMD 0xF00DFACE +#define NXPWIFI_USB_TYPE_DATA 0xBEADC0DE +#define NXPWIFI_USB_TYPE_EVENT 0xBEEFFACE + +/* Threshold for tx_timeout_cnt before we trigger a card reset */ +#define TX_TIMEOUT_THRESHOLD 6 + +#define NXPWIFI_DRV_INFO_SIZE_MAX 0x40000 + +/* Address alignment */ +#define NXPWIFI_ALIGN_ADDR(p, a) ({ \ + typeof(a) (_a) = a; \ + (((long)(p) + (_a) - 1) & ~((_a) - 1)); \ + }) + +#define NXPWIFI_MAC_LOCAL_ADMIN_BIT 41 + +/** + *enum nxpwifi_debug_level - nxp wifi debug level + */ +enum NXPWIFI_DEBUG_LEVEL { + NXPWIFI_DBG_MSG = 0x00000001, + NXPWIFI_DBG_FATAL = 0x00000002, + NXPWIFI_DBG_ERROR = 0x00000004, + NXPWIFI_DBG_DATA = 0x00000008, + NXPWIFI_DBG_CMD = 0x00000010, + NXPWIFI_DBG_EVENT = 0x00000020, + NXPWIFI_DBG_INTR = 0x00000040, + NXPWIFI_DBG_IOCTL = 0x00000080, + + NXPWIFI_DBG_MPA_D = 0x00008000, + NXPWIFI_DBG_DAT_D = 0x00010000, + NXPWIFI_DBG_CMD_D = 0x00020000, + NXPWIFI_DBG_EVT_D = 0x00040000, + NXPWIFI_DBG_FW_D = 0x00080000, + NXPWIFI_DBG_IF_D = 0x00100000, + + NXPWIFI_DBG_ENTRY = 0x10000000, + NXPWIFI_DBG_WARN = 0x20000000, + NXPWIFI_DBG_INFO = 0x40000000, + NXPWIFI_DBG_DUMP = 0x80000000, + + NXPWIFI_DBG_ANY = 0xffffffff +}; + +#define NXPWIFI_DEFAULT_DEBUG_MASK (NXPWIFI_DBG_MSG | \ + NXPWIFI_DBG_FATAL | \ + NXPWIFI_DBG_ERROR) + +__printf(3, 4) +void _nxpwifi_dbg(const struct nxpwifi_adapter *adapter, int mask, + const char *fmt, ...); +#define nxpwifi_dbg(adapter, mask, fmt, ...) \ + _nxpwifi_dbg(adapter, NXPWIFI_DBG_##mask, fmt, ##__VA_ARGS__) + +#define DEBUG_DUMP_DATA_MAX_LEN 128 +#define nxpwifi_dbg_dump(adapter, dbg_mask, str, buf, len) \ +do { \ + if ((adapter)->debug_mask & NXPWIFI_DBG_##dbg_mask) \ + print_hex_dump(KERN_DEBUG, str, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, len, false); \ +} while (0) + +/** Min BGSCAN interval 15 second */ +#define NXPWIFI_BGSCAN_INTERVAL 15000 +/** default repeat count */ +#define NXPWIFI_BGSCAN_REPEAT_COUNT 6 + +struct nxpwifi_dbg { + u32 num_cmd_host_to_card_failure; + u32 num_cmd_sleep_cfm_host_to_card_failure; + u32 num_tx_host_to_card_failure; + u32 num_event_deauth; + u32 num_event_disassoc; + u32 num_event_link_lost; + u32 num_cmd_deauth; + u32 num_cmd_assoc_success; + u32 num_cmd_assoc_failure; + u32 num_tx_timeout; + u16 timeout_cmd_id; + u16 timeout_cmd_act; + u16 last_cmd_id[DBG_CMD_NUM]; + u16 last_cmd_act[DBG_CMD_NUM]; + u16 last_cmd_index; + u16 last_cmd_resp_id[DBG_CMD_NUM]; + u16 last_cmd_resp_index; + u16 last_event[DBG_CMD_NUM]; + u16 last_event_index; + u32 last_mp_wr_bitmap[NXPWIFI_DBG_SDIO_MP_NUM]; + u32 last_mp_wr_ports[NXPWIFI_DBG_SDIO_MP_NUM]; + u32 last_mp_wr_len[NXPWIFI_DBG_SDIO_MP_NUM]; + u32 last_mp_curr_wr_port[NXPWIFI_DBG_SDIO_MP_NUM]; + u8 last_sdio_mp_index; +}; + +enum NXPWIFI_HARDWARE_STATUS { + NXPWIFI_HW_STATUS_READY, + NXPWIFI_HW_STATUS_INITIALIZING, + NXPWIFI_HW_STATUS_INIT_DONE, + NXPWIFI_HW_STATUS_RESET, + NXPWIFI_HW_STATUS_NOT_READY +}; + +enum NXPWIFI_802_11_POWER_MODE { + NXPWIFI_802_11_POWER_MODE_CAM, + NXPWIFI_802_11_POWER_MODE_PSP +}; + +struct nxpwifi_tx_param { + u32 next_pkt_len; +}; + +enum NXPWIFI_PS_STATE { + PS_STATE_AWAKE, + PS_STATE_PRE_SLEEP, + PS_STATE_SLEEP_CFM, + PS_STATE_SLEEP +}; + +enum nxpwifi_iface_type { + NXPWIFI_SDIO +}; + +struct nxpwifi_add_ba_param { + u32 tx_win_size; + u32 rx_win_size; + u32 timeout; + u8 tx_amsdu; + u8 rx_amsdu; +}; + +struct nxpwifi_tx_aggr { + u8 ampdu_user; + u8 ampdu_ap; + u8 amsdu; +}; + +enum nxpwifi_ba_status { + BA_SETUP_NONE = 0, + BA_SETUP_INPROGRESS, + BA_SETUP_COMPLETE +}; + +struct nxpwifi_ra_list_tbl { + struct list_head list; + struct sk_buff_head skb_head; + u8 ra[ETH_ALEN]; + u32 is_11n_enabled; + u16 max_amsdu; + u16 ba_pkt_count; + u8 ba_packet_thr; + enum nxpwifi_ba_status ba_status; + u8 amsdu_in_ampdu; + u16 total_pkt_count; + bool tx_paused; +}; + +struct nxpwifi_tid_tbl { + struct list_head ra_list; +}; + +#define WMM_HIGHEST_PRIORITY 7 +#define HIGH_PRIO_TID 7 +#define LOW_PRIO_TID 0 +#define NO_PKT_PRIO_TID -1 +#define NXPWIFI_WMM_DRV_DELAY_MAX 510 + +struct nxpwifi_wmm_desc { + struct nxpwifi_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; + u32 packets_out[MAX_NUM_TID]; + u32 pkts_paused[MAX_NUM_TID]; + /* spin lock to protect ra_list */ + spinlock_t ra_list_spinlock; + struct nxpwifi_wmm_ac_status ac_status[IEEE80211_NUM_ACS]; + enum nxpwifi_wmm_ac_e ac_down_graded_vals[IEEE80211_NUM_ACS]; + u32 drv_pkt_delay_max; + u8 queue_priority[IEEE80211_NUM_ACS]; + u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */ + /* Number of transmit packets queued */ + atomic_t tx_pkts_queued; + /* Tracks highest priority with a packet queued */ + atomic_t highest_queued_prio; +}; + +struct nxpwifi_802_11_security { + u8 wpa_enabled; + u8 wpa2_enabled; + u8 wep_enabled; + u32 authentication_mode; + u8 is_authtype_auto; + u32 encryption_mode; +}; + +struct ieee_types_vendor_specific { + struct ieee80211_vendor_ie vend_hdr; + u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee80211_vendor_ie)]; +} __packed; + +struct nxpwifi_bssdescriptor { + u8 mac_address[ETH_ALEN]; + struct cfg80211_ssid ssid; + u32 privacy; + s32 rssi; + u32 channel; + u32 freq; + u16 beacon_period; + u8 erp_flags; + u32 bss_mode; + u8 supported_rates[NXPWIFI_SUPPORTED_RATES]; + u8 data_rates[NXPWIFI_SUPPORTED_RATES]; + /* Network band. + * BAND_B(0x01): 'b' band + * BAND_G(0x02): 'g' band + * BAND_A(0X04): 'a' band + */ + u16 bss_band; + u64 fw_tsf; + u64 timestamp; + union ieee_types_phy_param_set phy_param_set; + struct ieee_types_cf_param_set cf_param_set; + u16 cap_info_bitmap; + struct ieee80211_wmm_param_ie wmm_ie; + u8 disable_11n; + struct ieee80211_ht_cap *bcn_ht_cap; + u16 ht_cap_offset; + struct ieee80211_ht_operation *bcn_ht_oper; + u16 ht_info_offset; + u8 *bcn_bss_co_2040; + u16 bss_co_2040_offset; + u8 *bcn_ext_cap; + u16 ext_cap_offset; + struct ieee80211_vht_cap *bcn_vht_cap; + u16 vht_cap_offset; + struct ieee80211_vht_operation *bcn_vht_oper; + u16 vht_info_offset; + struct ieee_types_oper_mode_ntf *oper_mode; + u16 oper_mode_offset; + u8 disable_11ac; + struct ieee_types_vendor_specific *bcn_wpa_ie; + u16 wpa_offset; + struct element *bcn_rsn_ie; + u16 rsn_offset; + struct element *bcn_rsnx_ie; + u16 rsnx_offset; + u8 *beacon_buf; + u32 beacon_buf_size; + u8 sensed_11h; + u8 local_constraint; + u8 chan_sw_ie_present; +}; + +struct nxpwifi_current_bss_params { + struct nxpwifi_bssdescriptor bss_descriptor; + u8 wmm_enabled; + u8 wmm_uapsd_enabled; + u8 band; + u32 num_of_rates; + u8 data_rates[NXPWIFI_SUPPORTED_RATES]; +}; + +struct nxpwifi_sleep_period { + u16 period; + u16 reserved; +}; + +struct nxpwifi_wep_key { + u32 length; + u32 key_index; + u32 key_length; + u8 key_material[NXPWIFI_KEY_BUFFER_SIZE]; +}; + +#define MAX_REGION_CHANNEL_NUM 2 + +struct nxpwifi_chan_freq_power { + u16 channel; + u32 freq; + u16 max_tx_power; + u8 unsupported; +}; + +enum state_11d_t { + DISABLE_11D = 0, + ENABLE_11D = 1, +}; + +#define NXPWIFI_MAX_TRIPLET_802_11D 83 + +struct nxpwifi_802_11d_domain_reg { + u8 dfs_region; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + u8 no_of_triplet; + struct ieee80211_country_ie_triplet + triplet[NXPWIFI_MAX_TRIPLET_802_11D]; +}; + +struct nxpwifi_vendor_spec_cfg_ie { + u16 mask; + u16 flag; + u8 ie[NXPWIFI_MAX_VSIE_LEN]; +}; + +struct wps { + u8 session_enable; +}; + +struct nxpwifi_roc_cfg { + u64 cookie; + struct ieee80211_channel chan; +}; + +enum nxpwifi_iface_work_flags { + NXPWIFI_IFACE_WORK_DEVICE_DUMP, + NXPWIFI_IFACE_WORK_CARD_RESET, +}; + +enum nxpwifi_adapter_work_flags { + NXPWIFI_SURPRISE_REMOVED, + NXPWIFI_IS_CMD_TIMEDOUT, + NXPWIFI_IS_SUSPENDED, + NXPWIFI_IS_HS_CONFIGURED, + NXPWIFI_IS_HS_ENABLING, + NXPWIFI_IS_REQUESTING_FW_VEREXT, +}; + +struct nxpwifi_band_config { + u8 chan_band:2; + u8 chan_width:2; + u8 chan2_offset:2; + u8 scan_mode:2; +} __packed; + +struct nxpwifi_channel_band { + struct nxpwifi_band_config band_config; + u8 channel; +}; + +struct nxpwifi_private { + struct nxpwifi_adapter *adapter; + u8 bss_type; + u8 bss_role; + u8 bss_priority; + u8 bss_num; + u8 bss_started; + u8 auth_flag; + u16 auth_alg; + u8 frame_type; + u8 curr_addr[ETH_ALEN]; + u8 media_connected; + u8 port_open; + u8 usb_port; + u32 num_tx_timeout; + /* track consecutive timeout */ + u8 tx_timeout_cnt; + struct net_device *netdev; + struct net_device_stats stats; + u32 curr_pkt_filter; + u32 bss_mode; + u32 pkt_tx_ctrl; + u16 tx_power_level; + u8 max_tx_power_level; + u8 min_tx_power_level; + u32 tx_ant; + u32 rx_ant; + u8 tx_rate; + u8 tx_htinfo; + u8 rxpd_htinfo; + u8 rxpd_rate; + u16 rate_bitmap; + u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + u32 data_rate; + u8 is_data_rate_auto; + u16 bcn_avg_factor; + u16 data_avg_factor; + s16 data_rssi_last; + s16 data_nf_last; + s16 data_rssi_avg; + s16 data_nf_avg; + s16 bcn_rssi_last; + s16 bcn_nf_last; + s16 bcn_rssi_avg; + s16 bcn_nf_avg; + struct nxpwifi_bssdescriptor *attempted_bss_desc; + struct cfg80211_ssid prev_ssid; + u8 prev_bssid[ETH_ALEN]; + struct nxpwifi_current_bss_params curr_bss_params; + u16 beacon_period; + u8 dtim_period; + u16 listen_interval; + u16 atim_window; + struct nxpwifi_802_11_security sec_info; + struct nxpwifi_wep_key wep_key[NUM_WEP_KEYS]; + u16 wep_key_curr_index; + u8 wpa_ie[256]; + u16 wpa_ie_len; + u8 wpa_is_gtk_set; + struct host_cmd_ds_802_11_key_material aes_key; + u8 *wps_ie; + u16 wps_ie_len; + u8 wmm_required; + u8 wmm_enabled; + u8 wmm_qosinfo; + struct nxpwifi_wmm_desc wmm; + atomic_t wmm_tx_pending[IEEE80211_NUM_ACS]; + struct list_head sta_list; + /* spin lock for associated station list */ + spinlock_t sta_list_spinlock; + struct list_head tx_ba_stream_tbl_ptr; + /* spin lock for tx_ba_stream_tbl_ptr queue */ + spinlock_t tx_ba_stream_tbl_lock; + struct nxpwifi_tx_aggr aggr_prio_tbl[MAX_NUM_TID]; + struct nxpwifi_add_ba_param add_ba_param; + u16 rx_seq[MAX_NUM_TID]; + u8 tos_to_tid_inv[MAX_NUM_TID]; + struct list_head rx_reorder_tbl_ptr; + /* spin lock for rx_reorder_tbl_ptr queue */ + spinlock_t rx_reorder_tbl_lock; +#define NXPWIFI_ASSOC_RSP_BUF_SIZE 500 + u8 assoc_rsp_buf[NXPWIFI_ASSOC_RSP_BUF_SIZE]; + u32 assoc_rsp_size; + struct cfg80211_bss *req_bss; + +#define NXPWIFI_GENIE_BUF_SIZE 256 + u8 gen_ie_buf[NXPWIFI_GENIE_BUF_SIZE]; + u8 gen_ie_buf_len; + + struct nxpwifi_vendor_spec_cfg_ie vs_ie[NXPWIFI_MAX_VSIE_NUM]; + +#define NXPWIFI_ASSOC_TLV_BUF_SIZE 256 + u8 assoc_tlv_buf[NXPWIFI_ASSOC_TLV_BUF_SIZE]; + u8 assoc_tlv_buf_len; + + u8 *curr_bcn_buf; + u32 curr_bcn_size; + /* spin lock for beacon buffer */ + spinlock_t curr_bcn_buf_lock; + struct wireless_dev wdev; + struct nxpwifi_chan_freq_power cfp; + u32 versionstrsel; + char version_str[NXPWIFI_VERSION_STR_LENGTH]; +#ifdef CONFIG_DEBUG_FS + struct dentry *dfs_dev_dir; +#endif + u16 current_key_index; + struct cfg80211_scan_request *scan_request; + u8 cfg_bssid[6]; + struct wps wps; + u8 scan_block; + s32 cqm_rssi_thold; + u32 cqm_rssi_hyst; + u8 subsc_evt_rssi_state; + struct nxpwifi_ds_misc_subsc_evt async_subsc_evt_storage; + struct nxpwifi_ie mgmt_ie[MAX_MGMT_IE_INDEX]; + u16 beacon_idx; + u16 proberesp_idx; + u16 assocresp_idx; + u16 gen_idx; + u8 ap_11n_enabled; + u8 ap_11ac_enabled; + bool host_mlme_reg; + u32 mgmt_frame_mask; + struct nxpwifi_roc_cfg roc_cfg; + bool scan_aborting; + u8 sched_scanning; + u8 csa_chan; + unsigned long csa_expire_time; + u8 del_list_idx; + bool hs2_enabled; + struct nxpwifi_uap_bss_param bss_cfg; + struct cfg80211_chan_def bss_chandef; + struct station_parameters *sta_params; + struct idr ack_status_frames; + /* spin lock for ack status */ + spinlock_t ack_status_lock; + /** rx histogram data */ + struct nxpwifi_histogram_data *hist_data; + struct cfg80211_chan_def dfs_chandef; + struct delayed_work dfs_cac_work; + struct delayed_work dfs_chan_sw_work; + bool uap_stop_tx; + struct cfg80211_beacon_data beacon_after; + struct nxpwifi_11h_intf_state state_11h; + struct nxpwifi_ds_mem_rw mem_rw; + struct sk_buff_head bypass_txq; + struct nxpwifi_user_scan_chan hidden_chan[NXPWIFI_USER_SCAN_CHAN_MAX]; + u8 assoc_resp_ht_param; + bool ht_param_present; +}; + +struct nxpwifi_tx_ba_stream_tbl { + struct list_head list; + int tid; + u8 ra[ETH_ALEN]; + enum nxpwifi_ba_status ba_status; + u8 amsdu; +}; + +struct nxpwifi_rx_reorder_tbl; + +struct reorder_tmr_cnxt { + struct timer_list timer; + struct nxpwifi_rx_reorder_tbl *ptr; + struct nxpwifi_private *priv; + u8 timer_is_set; +}; + +struct nxpwifi_rx_reorder_tbl { + struct list_head list; + int tid; + u8 ta[ETH_ALEN]; + int init_win; + int start_win; + int win_size; + void **rx_reorder_ptr; + struct reorder_tmr_cnxt timer_context; + u8 amsdu; + u8 flags; +}; + +struct nxpwifi_bss_prio_node { + struct list_head list; + struct nxpwifi_private *priv; +}; + +struct nxpwifi_bss_prio_tbl { + struct list_head bss_prio_head; + /* spin lock for bss priority */ + spinlock_t bss_prio_lock; + struct nxpwifi_bss_prio_node *bss_prio_cur; +}; + +struct cmd_ctrl_node { + struct list_head list; + struct nxpwifi_private *priv; + u32 cmd_no; + u32 cmd_flag; + struct sk_buff *cmd_skb; + struct sk_buff *resp_skb; + void *data_buf; + u32 wait_q_enabled; + struct sk_buff *skb; + u8 *condition; + u8 cmd_wait_q_woken; + int (*cmd_resp)(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf); +}; + +struct nxpwifi_bss_priv { + u8 band; + u64 fw_tsf; +}; + +struct nxpwifi_station_stats { + u64 last_rx; + s8 rssi; + u64 rx_bytes; + u64 tx_bytes; + u32 rx_packets; + u32 tx_packets; + u32 tx_failed; + u8 last_tx_rate; + u8 last_tx_htinfo; +}; + +/* This is AP specific structure which stores information + * about associated/peer STA + */ +struct nxpwifi_sta_node { + struct list_head list; + u8 mac_addr[ETH_ALEN]; + u8 is_wmm_enabled; + u8 is_11n_enabled; + u8 is_11ac_enabled; + u8 ampdu_sta[MAX_NUM_TID]; + u16 rx_seq[MAX_NUM_TID]; + u16 max_amsdu; + struct nxpwifi_station_stats stats; + u8 tx_pause; +}; + +#define NXPWIFI_TYPE_AGGR_DATA_V2 11 +#define NXPWIFI_BUS_AGGR_MODE_LEN_V2 (2) +#define NXPWIFI_BUS_AGGR_MAX_LEN 16000 +#define NXPWIFI_BUS_AGGR_MAX_NUM 10 +struct bus_aggr_params { + u16 enable; + u16 mode; + u16 tx_aggr_max_size; + u16 tx_aggr_max_num; + u16 tx_aggr_align; +}; + +struct vdll_dnld_ctrl { + u8 *pending_block; + u16 pending_block_len; + u8 *vdll_mem; + u32 vdll_len; + struct sk_buff *skb; +}; + +struct nxpwifi_if_ops { + int (*init_if)(struct nxpwifi_adapter *adapter); + void (*cleanup_if)(struct nxpwifi_adapter *adapter); + int (*check_fw_status)(struct nxpwifi_adapter *adapter, u32 poll_num); + int (*check_winner_status)(struct nxpwifi_adapter *adapter); + int (*prog_fw)(struct nxpwifi_adapter *adapter, + struct nxpwifi_fw_image *fw); + int (*register_dev)(struct nxpwifi_adapter *adapter); + void (*unregister_dev)(struct nxpwifi_adapter *adapter); + int (*enable_int)(struct nxpwifi_adapter *adapter); + void (*disable_int)(struct nxpwifi_adapter *adapter); + int (*process_int_status)(struct nxpwifi_adapter *adapter); + int (*host_to_card)(struct nxpwifi_adapter *adapter, u8 type, + struct sk_buff *skb, + struct nxpwifi_tx_param *tx_param); + int (*wakeup)(struct nxpwifi_adapter *adapter); + int (*wakeup_complete)(struct nxpwifi_adapter *adapter); + + /* Interface specific functions */ + void (*update_mp_end_port)(struct nxpwifi_adapter *adapter, u16 port); + void (*cleanup_mpa_buf)(struct nxpwifi_adapter *adapter); + int (*cmdrsp_complete)(struct nxpwifi_adapter *adapter, + struct sk_buff *skb); + int (*event_complete)(struct nxpwifi_adapter *adapter, + struct sk_buff *skb); + int (*dnld_fw)(struct nxpwifi_adapter *adapter, + struct nxpwifi_fw_image *fw); + void (*card_reset)(struct nxpwifi_adapter *adapter); + int (*reg_dump)(struct nxpwifi_adapter *adapter, char *drv_buf); + void (*device_dump)(struct nxpwifi_adapter *adapter); + void (*deaggr_pkt)(struct nxpwifi_adapter *adapter, + struct sk_buff *skb); + void (*up_dev)(struct nxpwifi_adapter *adapter); +}; + +struct nxpwifi_adapter { + u8 iface_type; + unsigned int debug_mask; + struct nxpwifi_iface_comb iface_limit; + struct nxpwifi_iface_comb curr_iface_comb; + struct nxpwifi_private *priv[NXPWIFI_MAX_BSS_NUM]; + u8 priv_num; + const struct firmware *firmware; + char fw_name[32]; + int winner; + struct device *dev; + struct wiphy *wiphy; + u8 perm_addr[ETH_ALEN]; + unsigned long work_flags; + u32 fw_release_number; + u8 intf_hdr_len; + u16 init_wait_q_woken; + wait_queue_head_t init_wait_q; + void *card; + struct nxpwifi_if_ops if_ops; + atomic_t bypass_tx_pending; + atomic_t tx_pending; + atomic_t cmd_pending; + atomic_t tx_hw_pending; + struct workqueue_struct *workqueue; + struct work_struct main_work; + struct work_struct host_mlme_work; + struct work_struct rx_mlme_work; + struct tasklet_struct rx_task; + + /* spin lock for following variables which + * are used to synchronize main process function + */ + spinlock_t main_proc_lock; + /* avoid execution of main process function */ + bool main_locked; + /* indicate if main process function is running */ + u32 nxpwifi_processing; + /* indicate if there are more tasks should be done + * by main process function + */ + u8 more_task_flag; + + struct nxpwifi_bss_prio_tbl bss_prio_tbl[NXPWIFI_MAX_BSS_NUM]; + u16 tx_buf_size; + u16 curr_tx_buf_size; + /* sdio single port rx aggregation capability */ + bool host_disable_sdio_rx_aggr; + bool sdio_rx_aggr_enable; + u16 sdio_rx_block_size; + u32 ioport; + enum NXPWIFI_HARDWARE_STATUS hw_status; + u16 number_of_antenna; + u32 fw_cap_info; + /* spin lock for interrupt handling */ + spinlock_t int_lock; + u8 int_status; + u32 event_cause; + struct sk_buff *event_skb; + u8 upld_buf[NXPWIFI_UPLD_SIZE]; + u8 data_sent; + u8 cmd_sent; + u8 cmd_resp_received; + u8 event_received; + u8 data_received; + u8 assoc_resp_received; + struct nxpwifi_private *priv_link_lost; + u8 host_mlme_link_lost; + u16 seq_num; + struct cmd_ctrl_node *cmd_pool; + struct cmd_ctrl_node *curr_cmd; + /* spin lock for command */ + spinlock_t nxpwifi_cmd_lock; + u16 last_init_cmd; + struct timer_list cmd_timer; + struct list_head cmd_free_q; + /* spin lock for cmd_free_q */ + spinlock_t cmd_free_q_lock; + struct list_head cmd_pending_q; + /* spin lock for cmd_pending_q */ + spinlock_t cmd_pending_q_lock; + struct list_head scan_pending_q; + /* spin lock for scan_pending_q */ + spinlock_t scan_pending_q_lock; + struct sk_buff_head tx_data_q; + atomic_t tx_queued; + u32 scan_processing; + u16 region_code; + struct nxpwifi_802_11d_domain_reg domain_reg; + u16 scan_probes; + u32 scan_mode; + u16 specific_scan_time; + u16 active_scan_time; + u16 passive_scan_time; + u16 scan_chan_gap_time; + u8 fw_bands; + u8 config_bands; + u8 tx_lock_flag; + struct nxpwifi_sleep_period sleep_period; + u16 ps_mode; + u32 ps_state; + u8 need_to_wakeup; + u16 multiple_dtim; + u16 local_listen_interval; + u16 null_pkt_interval; + struct sk_buff *sleep_cfm; + u16 bcn_miss_time_out; + u8 is_deep_sleep; + u8 delay_null_pkt; + u16 delay_to_ps; + u16 enhanced_ps_mode; + u8 pm_wakeup_card_req; + u16 gen_null_pkt; + u16 pps_uapsd_mode; + u32 pm_wakeup_fw_try; + struct timer_list wakeup_timer; + struct nxpwifi_hs_config_param hs_cfg; + u8 hs_activated; + u8 hs_activated_manually; + u16 hs_activate_wait_q_woken; + wait_queue_head_t hs_activate_wait_q; + u8 event_body[MAX_EVENT_SIZE]; + u32 hw_dot_11n_dev_cap; + u8 hw_dev_mcs_support; + u8 user_dev_mcs_support; + u8 sec_chan_offset; + struct nxpwifi_dbg dbg; + u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE]; + u32 arp_filter_size; + struct nxpwifi_wait_queue cmd_wait_q; + u8 scan_wait_q_woken; + spinlock_t queue_lock; /* lock for tx queues */ + u8 dfs_region; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + u16 max_mgmt_ie_index; + const struct firmware *cal_data; + struct device_node *dt_node; + + /* 11AC */ + u32 is_hw_11ac_capable; + u32 hw_dot_11ac_dev_cap; + u32 hw_dot_11ac_mcs_support; + u32 usr_dot_11ac_dev_cap_bg; + u32 usr_dot_11ac_dev_cap_a; + u32 usr_dot_11ac_mcs_support; + + atomic_t pending_bridged_pkts; + + /* For synchronizing FW initialization with device lifecycle. */ + struct completion *fw_done; + bool is_up; + + bool ext_scan; + u8 fw_api_ver; + u8 key_api_major_ver, key_api_minor_ver; + u8 max_sta_conn; + struct memory_type_mapping *mem_type_mapping_tbl; + u8 num_mem_types; + bool scan_chan_gap_enabled; + struct sk_buff_head rx_mlme_q; + struct sk_buff_head rx_data_q; + struct nxpwifi_chan_stats *chan_stats; + u32 num_in_chan_stats; + int survey_idx; + u8 coex_scan; + u8 coex_min_scan_time; + u8 coex_max_scan_time; + u8 coex_win_size; + u8 coex_tx_win_size; + u8 coex_rx_win_size; + u8 active_scan_triggered; + bool usb_mc_status; + bool usb_mc_setup; + struct cfg80211_wowlan_nd_info *nd_info; + struct ieee80211_regdomain *regd; + + /* Wake-on-WLAN (WoWLAN) */ + int irq_wakeup; + bool wake_by_wifi; + /* Aggregation parameters*/ + struct bus_aggr_params bus_aggr; + /* Device dump data/length */ + void *devdump_data; + int devdump_len; + + bool ignore_btcoex_events; + + struct vdll_dnld_ctrl vdll_ctrl; + u64 roc_cookie_counter; +}; + +void nxpwifi_process_tx_queue(struct nxpwifi_adapter *adapter); + +void nxpwifi_init_lock_list(struct nxpwifi_adapter *adapter); + +void nxpwifi_set_trans_start(struct net_device *dev); + +void nxpwifi_stop_net_dev_queue(struct net_device *netdev, + struct nxpwifi_adapter *adapter); + +void nxpwifi_wake_up_net_dev_queue(struct net_device *netdev, + struct nxpwifi_adapter *adapter); + +int nxpwifi_init_priv(struct nxpwifi_private *priv); +void nxpwifi_free_priv(struct nxpwifi_private *priv); + +int nxpwifi_init_fw(struct nxpwifi_adapter *adapter); + +void nxpwifi_init_fw_complete(struct nxpwifi_adapter *adapter); + +void nxpwifi_shutdown_drv(struct nxpwifi_adapter *adapter); + +int nxpwifi_dnld_fw(struct nxpwifi_adapter *adapter, + struct nxpwifi_fw_image *fw); + +int nxpwifi_recv_packet(struct nxpwifi_private *priv, struct sk_buff *skb); +int nxpwifi_uap_recv_packet(struct nxpwifi_private *priv, + struct sk_buff *skb); + +void nxpwifi_host_mlme_disconnect(struct nxpwifi_private *priv, + u16 reason_code, u8 *sa); + +int nxpwifi_process_mgmt_packet(struct nxpwifi_private *priv, + struct sk_buff *skb); + +int nxpwifi_complete_cmd(struct nxpwifi_adapter *adapter, + struct cmd_ctrl_node *cmd_node); + +void nxpwifi_cmd_timeout_func(struct timer_list *t); + +int nxpwifi_get_debug_info(struct nxpwifi_private *priv, + struct nxpwifi_debug_info *info); + +int nxpwifi_alloc_cmd_buffer(struct nxpwifi_adapter *adapter); +void nxpwifi_free_cmd_buffer(struct nxpwifi_adapter *adapter); +void nxpwifi_free_cmd_buffers(struct nxpwifi_adapter *adapter); +void nxpwifi_cancel_all_pending_cmd(struct nxpwifi_adapter *adapter); +void nxpwifi_cancel_pending_scan_cmd(struct nxpwifi_adapter *adapter); +void nxpwifi_cancel_scan(struct nxpwifi_adapter *adapter); + +void nxpwifi_recycle_cmd_node(struct nxpwifi_adapter *adapter, + struct cmd_ctrl_node *cmd_node); + +void nxpwifi_insert_cmd_to_pending_q(struct nxpwifi_adapter *adapter, + struct cmd_ctrl_node *cmd_node); + +int nxpwifi_exec_next_cmd(struct nxpwifi_adapter *adapter); +int nxpwifi_process_cmdresp(struct nxpwifi_adapter *adapter); +void nxpwifi_process_assoc_resp(struct nxpwifi_adapter *adapter); +int nxpwifi_handle_rx_packet(struct nxpwifi_adapter *adapter, + struct sk_buff *skb); +int nxpwifi_process_tx(struct nxpwifi_private *priv, struct sk_buff *skb, + struct nxpwifi_tx_param *tx_param); +int nxpwifi_send_null_packet(struct nxpwifi_private *priv, u8 flags); +int nxpwifi_write_data_complete(struct nxpwifi_adapter *adapter, + struct sk_buff *skb, int aggr, int status); +void nxpwifi_clean_txrx(struct nxpwifi_private *priv); +u8 nxpwifi_check_last_packet_indication(struct nxpwifi_private *priv); +void nxpwifi_check_ps_cond(struct nxpwifi_adapter *adapter); +void nxpwifi_process_sleep_confirm_resp(struct nxpwifi_adapter *adapter, + u8 *pbuf, u32 upld_len); +void nxpwifi_process_hs_config(struct nxpwifi_adapter *adapter); +void nxpwifi_hs_activated_event(struct nxpwifi_private *priv, + u8 activated); +int nxpwifi_set_hs_params(struct nxpwifi_private *priv, u16 action, + int cmd_type, struct nxpwifi_ds_hs_cfg *hs_cfg); +int nxpwifi_ret_802_11_hs_cfg(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp); +int nxpwifi_process_rx_packet(struct nxpwifi_private *priv, + struct sk_buff *skb); +int nxpwifi_process_sta_rx_packet(struct nxpwifi_private *priv, + struct sk_buff *skb); +int nxpwifi_process_uap_rx_packet(struct nxpwifi_private *priv, + struct sk_buff *skb); +int nxpwifi_handle_uap_rx_forward(struct nxpwifi_private *priv, + struct sk_buff *skb); +void nxpwifi_delete_all_station_list(struct nxpwifi_private *priv); +void nxpwifi_wmm_del_peer_ra_list(struct nxpwifi_private *priv, + const u8 *ra_addr); +void nxpwifi_process_sta_txpd(struct nxpwifi_private *priv, + struct sk_buff *skb); +void nxpwifi_process_uap_txpd(struct nxpwifi_private *priv, + struct sk_buff *skb); +int nxpwifi_cmd_802_11_scan(struct host_cmd_ds_command *cmd, + struct nxpwifi_scan_cmd_config *scan_cfg); +void nxpwifi_queue_scan_cmd(struct nxpwifi_private *priv, + struct cmd_ctrl_node *cmd_node); +int nxpwifi_ret_802_11_scan(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp); +int nxpwifi_associate(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc); +int nxpwifi_cmd_802_11_associate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + struct nxpwifi_bssdescriptor *bss_desc); +int nxpwifi_ret_802_11_associate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp); +u8 nxpwifi_band_to_radio_type(u8 band); +int nxpwifi_deauthenticate(struct nxpwifi_private *priv, u8 *mac); +void nxpwifi_deauthenticate_all(struct nxpwifi_adapter *adapter); +int nxpwifi_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd); +struct nxpwifi_chan_freq_power *nxpwifi_get_cfp(struct nxpwifi_private *priv, + u8 band, u16 channel, u32 freq); +u32 nxpwifi_index_to_data_rate(struct nxpwifi_private *priv, + u8 index, u8 ht_info); +u32 nxpwifi_index_to_acs_data_rate(struct nxpwifi_private *priv, + u8 index, u8 ht_info); +int nxpwifi_cmd_append_vsie_tlv(struct nxpwifi_private *priv, u16 vsie_mask, + u8 **buffer); +u32 nxpwifi_get_active_data_rates(struct nxpwifi_private *priv, + u8 *rates); +u32 nxpwifi_get_supported_rates(struct nxpwifi_private *priv, u8 *rates); +u32 nxpwifi_get_rates_from_cfg80211(struct nxpwifi_private *priv, + u8 *rates, u8 radio_type); +u8 nxpwifi_is_rate_auto(struct nxpwifi_private *priv); +extern u16 region_code_index[NXPWIFI_MAX_REGION_CODE]; +void nxpwifi_save_curr_bcn(struct nxpwifi_private *priv); +void nxpwifi_free_curr_bcn(struct nxpwifi_private *priv); +int is_command_pending(struct nxpwifi_adapter *adapter); +void nxpwifi_init_priv_params(struct nxpwifi_private *priv, + struct net_device *dev); +void nxpwifi_set_ba_params(struct nxpwifi_private *priv); +void nxpwifi_update_ampdu_txwinsize(struct nxpwifi_adapter *pmadapter); +void nxpwifi_set_11ac_ba_params(struct nxpwifi_private *priv); +int nxpwifi_cmd_802_11_scan_ext(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int nxpwifi_ret_802_11_scan_ext(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp); +int nxpwifi_handle_event_ext_scan_report(struct nxpwifi_private *priv, + void *buf); +int nxpwifi_cmd_802_11_bg_scan_config(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int nxpwifi_stop_bg_scan(struct nxpwifi_private *priv); + +/* This function checks if the queuing is RA based or not. + */ +static inline u8 +nxpwifi_queuing_ra_based(struct nxpwifi_private *priv) +{ + /* Currently we assume if we are in Infra, then DA=RA. This might not be + * true in the future + */ + if (priv->bss_mode == NL80211_IFTYPE_STATION && + (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA)) + return false; + + return true; +} + +/* This function copies rates. + */ +static inline u32 +nxpwifi_copy_rates(u8 *dest, u32 pos, u8 *src, int len) +{ + int i; + + for (i = 0; i < len && src[i]; i++, pos++) { + if (pos >= NXPWIFI_SUPPORTED_RATES) + break; + dest[pos] = src[i]; + } + + return pos; +} + +/* This function returns the correct private structure pointer based + * upon the BSS type and BSS number. + */ +static inline struct nxpwifi_private * +nxpwifi_get_priv_by_id(struct nxpwifi_adapter *adapter, + u8 bss_num, u8 bss_type) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if (adapter->priv[i]->bss_num == bss_num && + adapter->priv[i]->bss_type == bss_type) + break; + } + } + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + +/* This function returns the first available private structure pointer + * based upon the BSS role. + */ +static inline struct nxpwifi_private * +nxpwifi_get_priv(struct nxpwifi_adapter *adapter, + enum nxpwifi_bss_role bss_role) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if (bss_role == NXPWIFI_BSS_ROLE_ANY || + GET_BSS_ROLE(adapter->priv[i]) == bss_role) + break; + } + } + + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + +/* This function checks available bss_num when adding new interface or + * changing interface type. + */ +static inline u8 +nxpwifi_get_unused_bss_num(struct nxpwifi_adapter *adapter, u8 bss_type) +{ + u8 i, j; + int index[NXPWIFI_MAX_BSS_NUM]; + + memset(index, 0, sizeof(index)); + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i]) { + if (adapter->priv[i]->bss_type == bss_type && + !(adapter->priv[i]->bss_mode == + NL80211_IFTYPE_UNSPECIFIED)) { + index[adapter->priv[i]->bss_num] = 1; + } + } + for (j = 0; j < NXPWIFI_MAX_BSS_NUM; j++) + if (!index[j]) + return j; + return -ENOENT; +} + +/* This function returns the first available unused private structure pointer. + */ +static inline struct nxpwifi_private * +nxpwifi_get_unused_priv_by_bss_type(struct nxpwifi_adapter *adapter, + u8 bss_type) +{ + u8 i; + + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i]->bss_mode == + NL80211_IFTYPE_UNSPECIFIED) { + adapter->priv[i]->bss_num = + nxpwifi_get_unused_bss_num(adapter, bss_type); + break; + } + + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + +/* This function returns the driver private structure of a network device. + */ +static inline struct nxpwifi_private * +nxpwifi_netdev_get_priv(struct net_device *dev) +{ + return (struct nxpwifi_private *)(*(unsigned long *)netdev_priv(dev)); +} + +/* This function checks if a skb holds a management frame. + */ +static inline bool nxpwifi_is_skb_mgmt_frame(struct sk_buff *skb) +{ + return (get_unaligned_le32(skb->data) == PKT_TYPE_MGMT); +} + +/* This function retrieves channel closed for operation by Channel + * Switch Announcement. + */ +static inline u8 +nxpwifi_11h_get_csa_closed_channel(struct nxpwifi_private *priv) +{ + if (!priv->csa_chan) + return 0; + + /* Clear csa channel, if DFS channel move time has passed */ + if (time_after(jiffies, priv->csa_expire_time)) { + priv->csa_chan = 0; + priv->csa_expire_time = 0; + } + + return priv->csa_chan; +} + +static inline u8 nxpwifi_is_any_intf_active(struct nxpwifi_private *priv) +{ + struct nxpwifi_private *priv_num; + int i; + + for (i = 0; i < priv->adapter->priv_num; i++) { + priv_num = priv->adapter->priv[i]; + if (priv_num) { + if ((GET_BSS_ROLE(priv_num) == NXPWIFI_BSS_ROLE_UAP && + priv_num->bss_started) || + (GET_BSS_ROLE(priv_num) == NXPWIFI_BSS_ROLE_STA && + priv_num->media_connected)) + return 1; + } + } + + return 0; +} + +/* Disable platform specific wakeup interrupt */ +static inline void nxpwifi_disable_wake(struct nxpwifi_adapter *adapter) +{ + if (adapter->irq_wakeup >= 0) { + disable_irq_wake(adapter->irq_wakeup); + disable_irq(adapter->irq_wakeup); + if (adapter->wake_by_wifi) + /* Undo our disable, since interrupt handler already + * did this. + */ + enable_irq(adapter->irq_wakeup); + } +} + +/* Enable platform specific wakeup interrupt */ +static inline void nxpwifi_enable_wake(struct nxpwifi_adapter *adapter) +{ + /* Enable platform specific wakeup interrupt */ + if (adapter->irq_wakeup >= 0) { + adapter->wake_by_wifi = false; + enable_irq(adapter->irq_wakeup); + enable_irq_wake(adapter->irq_wakeup); + } +} + +int nxpwifi_init_shutdown_fw(struct nxpwifi_private *priv, + u32 func_init_shutdown); + +int nxpwifi_add_card(void *card, struct completion *fw_done, + struct nxpwifi_if_ops *if_ops, u8 iface_type, + struct device *dev); +void nxpwifi_remove_card(struct nxpwifi_adapter *adapter); + +void nxpwifi_get_version(struct nxpwifi_adapter *adapter, char *version, + int maxlen); +int +nxpwifi_request_set_multicast_list(struct nxpwifi_private *priv, + struct nxpwifi_multicast_list *mcast_list); +int nxpwifi_copy_mcast_addr(struct nxpwifi_multicast_list *mlist, + struct net_device *dev); +int nxpwifi_wait_queue_complete(struct nxpwifi_adapter *adapter, + struct cmd_ctrl_node *cmd_queued); +int nxpwifi_bss_start(struct nxpwifi_private *priv, struct cfg80211_bss *bss, + struct cfg80211_ssid *req_ssid); +int nxpwifi_cancel_hs(struct nxpwifi_private *priv, int cmd_type); +bool nxpwifi_enable_hs(struct nxpwifi_adapter *adapter); +int nxpwifi_disable_auto_ds(struct nxpwifi_private *priv); +int nxpwifi_drv_get_data_rate(struct nxpwifi_private *priv, u32 *rate); + +int nxpwifi_scan_networks(struct nxpwifi_private *priv, + const struct nxpwifi_user_scan_cfg *user_scan_in); +int nxpwifi_set_radio(struct nxpwifi_private *priv, u8 option); + +int nxpwifi_set_encode(struct nxpwifi_private *priv, struct key_params *kp, + const u8 *key, int key_len, u8 key_index, + const u8 *mac_addr, int disable); + +int nxpwifi_set_gen_ie(struct nxpwifi_private *priv, const u8 *ie, int ie_len); + +int nxpwifi_get_ver_ext(struct nxpwifi_private *priv, u32 version_str_sel); + +int nxpwifi_remain_on_chan_cfg(struct nxpwifi_private *priv, u16 action, + struct ieee80211_channel *chan, + unsigned int duration); + +int nxpwifi_get_stats_info(struct nxpwifi_private *priv, + struct nxpwifi_ds_get_stats *log); + +int nxpwifi_reg_write(struct nxpwifi_private *priv, u32 reg_type, + u32 reg_offset, u32 reg_value); + +int nxpwifi_reg_read(struct nxpwifi_private *priv, u32 reg_type, + u32 reg_offset, u32 *value); + +int nxpwifi_eeprom_read(struct nxpwifi_private *priv, u16 offset, u16 bytes, + u8 *value); + +int nxpwifi_set_11n_httx_cfg(struct nxpwifi_private *priv, int data); + +int nxpwifi_get_11n_httx_cfg(struct nxpwifi_private *priv, int *data); + +int nxpwifi_set_tx_rate_cfg(struct nxpwifi_private *priv, int tx_rate_index); + +int nxpwifi_get_tx_rate_cfg(struct nxpwifi_private *priv, int *tx_rate_index); + +int nxpwifi_drv_set_power(struct nxpwifi_private *priv, u32 *ps_mode); + +int nxpwifi_drv_get_driver_version(struct nxpwifi_adapter *adapter, + char *version, int max_len); + +int nxpwifi_set_tx_power(struct nxpwifi_private *priv, + struct nxpwifi_power_cfg *power_cfg); + +void nxpwifi_main_process(struct nxpwifi_adapter *adapter); + +void nxpwifi_queue_tx_pkt(struct nxpwifi_private *priv, struct sk_buff *skb); + +int nxpwifi_get_bss_info(struct nxpwifi_private *priv, + struct nxpwifi_bss_info *info); +int nxpwifi_fill_new_bss_desc(struct nxpwifi_private *priv, + struct cfg80211_bss *bss, + struct nxpwifi_bssdescriptor *bss_desc); +int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, + struct nxpwifi_bssdescriptor *bss_entry); +int nxpwifi_check_network_compatibility(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc); + +u8 nxpwifi_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type); +u8 nxpwifi_get_chan_type(struct nxpwifi_private *priv); + +struct wireless_dev *nxpwifi_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params); +int nxpwifi_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); + +int nxpwifi_add_wowlan_magic_pkt_filter(struct nxpwifi_adapter *adapter); + +int nxpwifi_set_mgmt_ies(struct nxpwifi_private *priv, + struct cfg80211_beacon_data *data); +int nxpwifi_del_mgmt_ies(struct nxpwifi_private *priv); +u8 *nxpwifi_11d_code_2_region(u8 code); +void nxpwifi_init_11h_params(struct nxpwifi_private *priv); +int nxpwifi_is_11h_active(struct nxpwifi_private *priv); +int nxpwifi_11h_activate(struct nxpwifi_private *priv, bool flag); +void nxpwifi_11h_process_join(struct nxpwifi_private *priv, u8 **buffer, + struct nxpwifi_bssdescriptor *bss_desc); +int nxpwifi_11h_handle_event_chanswann(struct nxpwifi_private *priv); +void nxpwifi_dnld_txpwr_table(struct nxpwifi_private *priv); + +extern const struct ethtool_ops nxpwifi_ethtool_ops; + +void nxpwifi_del_all_sta_list(struct nxpwifi_private *priv); +void nxpwifi_del_sta_entry(struct nxpwifi_private *priv, const u8 *mac); +void +nxpwifi_set_sta_ht_cap(struct nxpwifi_private *priv, const u8 *ies, + int ies_len, struct nxpwifi_sta_node *node); +struct nxpwifi_sta_node * +nxpwifi_add_sta_entry(struct nxpwifi_private *priv, const u8 *mac); +struct nxpwifi_sta_node * +nxpwifi_get_sta_entry(struct nxpwifi_private *priv, const u8 *mac); +bool nxpwifi_is_bss_in_11ac_mode(struct nxpwifi_private *priv); +u8 nxpwifi_get_center_freq_index(struct nxpwifi_private *priv, u8 band, + u32 pri_chan, u8 chan_bw); +int nxpwifi_init_channel_scan_gap(struct nxpwifi_adapter *adapter); + +int nxpwifi_cmd_issue_chan_report_request(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int nxpwifi_11h_handle_chanrpt_ready(struct nxpwifi_private *priv, + struct sk_buff *skb); + +void nxpwifi_parse_tx_status_event(struct nxpwifi_private *priv, + void *event_body); + +struct sk_buff * +nxpwifi_clone_skb_for_tx_status(struct nxpwifi_private *priv, + struct sk_buff *skb, u8 flag, u64 *cookie); +void nxpwifi_dfs_cac_work(struct work_struct *work); +void nxpwifi_dfs_chan_sw_work(struct work_struct *work); +void nxpwifi_abort_cac(struct nxpwifi_private *priv); +int nxpwifi_stop_radar_detection(struct nxpwifi_private *priv, + struct cfg80211_chan_def *chandef); +int nxpwifi_11h_handle_radar_detected(struct nxpwifi_private *priv, + struct sk_buff *skb); + +void nxpwifi_hist_data_set(struct nxpwifi_private *priv, u8 rx_rate, s8 snr, + s8 nflr); +void nxpwifi_hist_data_reset(struct nxpwifi_private *priv); +void nxpwifi_hist_data_add(struct nxpwifi_private *priv, + u8 rx_rate, s8 snr, s8 nflr); +u8 nxpwifi_adjust_data_rate(struct nxpwifi_private *priv, + u8 rx_rate, u8 ht_info); + +void nxpwifi_drv_info_dump(struct nxpwifi_adapter *adapter); +void nxpwifi_prepare_fw_dump_info(struct nxpwifi_adapter *adapter); +void nxpwifi_upload_device_dump(struct nxpwifi_adapter *adapter); +void *nxpwifi_alloc_dma_align_buf(int rx_len, gfp_t flags); +void nxpwifi_fw_dump_event(struct nxpwifi_private *priv); +int nxpwifi_get_wakeup_reason(struct nxpwifi_private *priv, u16 action, + int cmd_type, + struct nxpwifi_ds_wakeup_reason *wakeup_reason); +int nxpwifi_get_chan_info(struct nxpwifi_private *priv, + struct nxpwifi_channel_band *channel_band); +void nxpwifi_coex_ampdu_rxwinsize(struct nxpwifi_adapter *adapter); +void nxpwifi_11n_delba(struct nxpwifi_private *priv, int tid); +int nxpwifi_send_domain_info_cmd_fw(struct wiphy *wiphy); +int nxpwifi_set_mac_address(struct nxpwifi_private *priv, + struct net_device *dev, + bool external, u8 *new_mac); +void nxpwifi_devdump_tmo_func(unsigned long function_context); + +#ifdef CONFIG_DEBUG_FS +void nxpwifi_debugfs_init(void); +void nxpwifi_debugfs_remove(void); + +void nxpwifi_dev_debugfs_init(struct nxpwifi_private *priv); +void nxpwifi_dev_debugfs_remove(struct nxpwifi_private *priv); +#endif +int nxpwifi_reinit_sw(struct nxpwifi_adapter *adapter); +void nxpwifi_shutdown_sw(struct nxpwifi_adapter *adapter); +#endif /* !_NXPWIFI_MAIN_H_ */ From patchwork Fri Aug 9 09:45:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818272 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A16351991D9; Fri, 9 Aug 2024 09:47:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196846; cv=fail; b=Rh1GlwFdd5JiH8kkONBUt/gzT+pc7D3mm0na8IAEKOhJLL0ZcDWCDqzZjT3KpfpIayUwz/Zq3cxoyODQ534tZyYEULwHU6+ifkHTrDXWKF2tJx3rW/HF6UUeUQ2XRQ/zIhL/oWeSpMgNfqTxwQb2AARx19axGVgRZ2ghNY/d7Tw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196846; c=relaxed/simple; bh=QTGnfu0mS4vB6JQghPd5On84dS9pp+8pfV8mP1q2gJA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=BBasMGJOy/9JiOLNDazcAAGyRcfnEbpL6JkIjHjGBzSm6MQvYp1QP2A/KFM2QWtV9aK+DUzGjLdlI3kJuMQaKMJjbQt3SWqgR63+fn3/BA/gUwQWWn26GPT1bxanI053UBtoq3ldFr1jr5cHqse5A6zBJQZHaJ1C7F6gl0TQdE8= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=ON8G1GHD; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="ON8G1GHD" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=MJFUSmLBhWtO3R7r0wDX3kC90RoahCgVEj43eShIOF8K3srT3KUyKB/djFmGRA7zsrLsnYd52w4swZmpEDNDN6USm5VavrBoB/Z1MlrngOXwl+eiSadRd+ShYvN+Pa8bZB88DVecELtl60y8Qqsb6B4Vii6lOJY/02tT/9O4wSXuiI44PJmlNmgA01eQ+/C7XmOCLGG//Q6PMO3ZELNXPg+RrrH7N4ZnvhuzCo7BcTzxwjhIWqCgKSNe5LPglhKzHbr1qUVO1SCl+4xaaNhw61jnmloty492+tzJKPVVrmP/5Lr6zEX2hocNMC18EKIGO7wUcx8/C5IriWEBioqkFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=a27E56q0pFGuCYuL3b2T1ysBahWQneZjOFnQAlEJpeM=; b=xSQ9MAHaODbVJ6DeF3/Ke559GoHT7Z8nboU6y0F1EhvS3aa+lgMiNp8uW4u+HGr1bEna4S6aGGbRrPC+E6jaJuM9sBWsVzCCJ3K08ZnVVXptmlbbEtzVe/kA7kd3EgfxCmyKXuVVJG4UwojGk9vZePfdaLP2ucBOnWrPLRSB+XVqEcK++KKd4QN+cIjNfmHucBMdl1Rfypzl7mrDIucYygtwM3ComrenAp6cym08QE0oF+at074ne76Bgoei4fOMvS4Kfbc28W+aGpScIh2xiZfcMMuG9ZnSmlBSH/ulhTJGLMnUXJNZY4z1BNnIb6cOkvgBV+My3CInWBhmYzMt8A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=a27E56q0pFGuCYuL3b2T1ysBahWQneZjOFnQAlEJpeM=; b=ON8G1GHDfnJusP0EmQ8ieTefVhcESyTiddF22nrI8OZBx+OUhuMnwN5UArIDBSojCRXY9dlEFxJJKdrV79cp2l5V1VBilZgC3GNps8yMoglQFCHp2WMImOCYqBMIfoIxLYKaJrFlaxyFyhC3a2pvkf9mWuQ1930WkeY2CjRMinECqM2EnCupVqs6fwG2K1zzQmD7loDSrH9kouyFl10lhFEZWs5ElO96AjgazyyEiPxVwT/sqHzZn8+n/BRr/zk7vhFiohOLGyRuJrjGQcaSodUvtfXyuReZ9ecNrAs/Vd1ZMbDNVd4dgbnf67cRO8i7qLWjtM06MZUCqfrKMuljyQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:47:13 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:47:13 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 25/43] wifi: nxpwifi: add scan.c Date: Fri, 9 Aug 2024 17:45:15 +0800 Message-Id: <20240809094533.1660-26-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: 8389a0f4-b238-429f-b4a6-08dcb8583ed7 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: +dJ2YGLQpQAfbHbnJjTRqYXemx/FBOAKLQu12eQS7kvRAtHb6u7e70pYMjuPmL04glFtP2zygttef9xOMI3GCyh17N4m8NcXsNQbJIBKgztTVYoLOd3kWN6ft8C+N/rPV6zAPPviV9D+XxxqvyvGlTeenLwLhIc8HMWcK+39b/Sw/VMuKzNW7Ri3y/YurUeh8csbyfMFO1/3zFQNiQ5U3731HpnsnSmd9aP7Dxh3bHSxZpd98Le/WeJaWHFqSgSNKJQh3dUpKs3oRi5MJ3zLbaEmoOeHt6yBY+XlQMTKWQPF/0rBq094sh6CCkizEbF+qjnwQbQgQkRT5zXr7IM5t4ekVCLIUUmnE4b+OAx9P8yia8NWOLPLzEv7LmIL3i6CVF733gGoXMXAv/kNmtw9RYOTuvhnU7TyvgRGgWJVY/+NbRBVeNvQC7WAp+eMjwP5d1JjbzkGsdWfCfaJZbDdBNNR7Ga39oaLx15XwQpqnyeltnpjlZLp+YwdnWVMo+kH3UsrzkouV3dAfVPhp8mlSt/uydAnKjBUIloHkGDrH6RZMDhTmFBKBtLJkTisPW5+TXXegkt3yXMEkvtOTh61+dkm/VnjvQTPYgAFMdy1MXNOaeHrSN98n96epdpzIHVth7N8tkhWFpAUXWMwIXYiYeYgxe+AmH145GUfpCLy7yTbe5Bu/g/u9+jfi/aWeP0JjmHgC2aMHdHgHG5MH/udS1fECaIKanggoVMaC/kve16DY5VE0MSZB8cg+tI9OjU3CfOPXLx82cvBdkuF+S81RbKmGpAKSq6/GCKbm0dVKSjIu+1lcnDnMwPaEyL4NdRBmzjPV27L6IHkFDO5SeWOehuRaniOonvXOwR0tt3BGXVqAf03ClTVa3hyxz9cLhfoTuxvh93hiMRFP/pfy+H7RSW7ubbJOAD8toCCljAczPzMoMqr+rCELoPqUImNx509kIQ2mB8KeEBsWpjftYhfvzpwH+iK3tk3Sw1t0VQ3XBk1t5enpSzPjoaT7iafEZ8PPkA/s8v5rKgdhbaR8w3WtRF222qPaCQ4/X3WI93VXVCn4GABFfb2cgu2OW2mgYv4AbA89Uyi08swIn0MZZlrQ13nEoO/dkY3zDwG/fBW6H34aLkBoijXqMS/djfiXSuOTpOkj4054UWN+JX7nmHORuTtmRLH/4MqKcnB86owTE2MVi+AFNQL0NAgu76qoS9z5liyFjva8aH4VdaC3/JsJkoix+EHDR6arCcAOlxWDdaNZECenZsKerf6e8HrELBQvs8FUFykCH5H2KrBvxVTOzOUxKEAi3b8uMFjKZ2DDRUQFruL93+4HsOj6KQojB/TQcNZYveKneVXHktH1G0s5A== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: GNWUUS40Sh7YiW8WcP6A0vUbqAIkBU37A/HRPzgm+jSNgrBz5jIf4sglI7UU18culJENfnIQgIJ9vTPY5rrVwTDpAsFCJhBbFU5yfLSQciQMR6fUgSIW3uF49lG7GtgaHI0NMCXwRrjZNu7ss/HWr7Lb52200slKFVmivw1bEiz2c8hyfwwWkXN76U14lw85kgzB3YGgrljLKMmc4h4F6UwVLPDHxy/4jfKXctFolDOlTux0mQwquXSKJ7SidFrCip0SNXcCyGWumOmuUnwSJ/EWwg71um6gN5kWaM7NcBl7hScZzEp+A3z72/TM1xnIAo5DiOYTe2hqrpC9gyIMR8NG7rHDz1t7z6LcMKEhMY5qA9G7qJv+/UjyM9dIQU8gxQ/Vy4RFK/SkcO/x70U5syDlEoFjv7jF2cXSiU7Vp/TDif5yQ6ovJ755W2+7uzD1hdO9paVJ1eBpPpgmEzZeTBLvbL4NcsDp+KbHzrmdnwfOQ8qTCh2dVqgyulzsVg4i/hsVA7UTL1B9EvEf/bPi9vjshxNOl5svL1kiakZTn7YWPBp0TJs7KiGUc7AfDZezrboG9ah8KqPzed9tNwTr56bXHiqFnjbDv5rExP1Al285JoafbjjrpBpwCe5/eZtd/lbuuZMk2LgcdbHu72h9wUhW1liacDrZ2nE9OcGwBIv/5b1XrjcajOTLt5uZ44fK2nlgD3jNM2CvnzqKE0iL8OckmP+7ADKXXozidQnfwBKU1pgnWSCr7GYQr6B+cm+sVGXpVelOrbG0LsCHRR4RO5lb2xkD5dfebl1o4XfFVTYBtG2YNBC9mOpA+DQKE4bUFRyktcaDny9SwnPw/pHnYekQPtSxWNgv7Vw3nFJwuNvS7Va9oDPoHUmwcSkWES3WqI7nlrlxU6ZyahMPoZtNfJQsZyzyXEjnOkh9d5xGCtyrRn5/0M/5sYUe/wyslkLsO+xmKibDSy7bXJC4bOXWjNs4O4VpdYWBSRGLgkPuk+1ZgcHcSmytVuPtIavtJ3puaVnBfhc2+Kyenn8EOZ5yTr1yc1+t8hfHOUsDDia3A5Xz8znQ+RLEGp3aE+I3VxUneNFX4ncD9Zq2pR7w/TmB4HzIk+dfb28EmHprlqQsrxFI0g2OEE9Cmekvq26EKYJo9vz5wyqxBRkt9KBcjfoMvkS6enUNj+qG4Lfy+GRa7Nj1/qD/QLDq4V6P6/gs/y8AXc8AP5feRBE9rxNxi0IJZmOUFqMAZaN2+KoVfQJSJoO0TrnCuV0glOmo/yUWXKWLjhodwlNDmVvG88tQGbr6muX9zbs1HzH4V7NrmgowK/nQrX/1wIXcHavhAPxUTd0lov19/3mX74fSKa/45+AG9VF3oj9yWKnhAt5+bSDubEAizK5RA3cGmZ7W+eIJZmdeZWFMBVG7ld4bla4vg/aC6KQPUx14vYctnXJSUNWbvbUq6KIf81fdHkyrBA0ojhGVmwTNCjFV/NLLKj0PBjZGYBG7ugss9w+rqaBobocoBjIIpvX3VLtQgVuVHA259ORrAxQvRlEWV2gHuJwxLSvCqraUfyw6Di64yNe6cShcz3LKp4OFzd6uEvnPu6XtOuoNHCDOM4tlyvHTi/7eEhIbCftQ27ZBPQkMmpM8DHUcnX5ntmL5aH3yO58rmKf5WaAk X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 8389a0f4-b238-429f-b4a6-08dcb8583ed7 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:47:13.4552 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: UJT+1e6ny997nQFCA9htrcKzUNkZiNEGg0w2ZvFh8bFJF+TNuPFAPBuM83t82ISq8FY9deSu420Fn5JpS2iEyg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/scan.c | 2806 +++++++++++++++++++++++ 1 file changed, 2806 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/scan.c diff --git a/drivers/net/wireless/nxp/nxpwifi/scan.c b/drivers/net/wireless/nxp/nxpwifi/scan.c new file mode 100644 index 000000000000..47037f2c2fb6 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/scan.c @@ -0,0 +1,2806 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: scan ioctl and command handling + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cmdevt.h" +#include "11n.h" +#include "cfg80211.h" + +/* The maximum number of channels the firmware can scan per command */ +#define NXPWIFI_MAX_CHANNELS_PER_SPECIFIC_SCAN 14 + +#define NXPWIFI_DEF_CHANNELS_PER_SCAN_CMD 4 + +/* Memory needed to store a max sized Channel List TLV for a firmware scan */ +#define CHAN_TLV_MAX_SIZE (sizeof(struct nxpwifi_ie_types_header) \ + + (NXPWIFI_MAX_CHANNELS_PER_SPECIFIC_SCAN \ + * sizeof(struct nxpwifi_chan_scan_param_set))) + +/* Memory needed to store supported rate */ +#define RATE_TLV_MAX_SIZE (sizeof(struct nxpwifi_ie_types_rates_param_set) \ + + HOSTCMD_SUPPORTED_RATES) + +/* Memory needed to store a max number/size WildCard SSID TLV for a firmware + * scan + */ +#define WILDCARD_SSID_TLV_MAX_SIZE \ + (NXPWIFI_MAX_SSID_LIST_LENGTH * \ + (sizeof(struct nxpwifi_ie_types_wildcard_ssid_params) \ + + IEEE80211_MAX_SSID_LEN)) + +/* Maximum memory needed for a nxpwifi_scan_cmd_config with all TLVs at max */ +#define MAX_SCAN_CFG_ALLOC (sizeof(struct nxpwifi_scan_cmd_config) \ + + sizeof(struct nxpwifi_ie_types_num_probes) \ + + sizeof(struct nxpwifi_ie_types_htcap) \ + + CHAN_TLV_MAX_SIZE \ + + RATE_TLV_MAX_SIZE \ + + WILDCARD_SSID_TLV_MAX_SIZE) + +union nxpwifi_scan_cmd_config_tlv { + /* Scan configuration (variable length) */ + struct nxpwifi_scan_cmd_config config; + /* Max allocated block */ + u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC]; +}; + +enum cipher_suite { + CIPHER_SUITE_TKIP, + CIPHER_SUITE_CCMP, + CIPHER_SUITE_MAX +}; + +static u8 nxpwifi_wpa_oui[CIPHER_SUITE_MAX][4] = { + { 0x00, 0x50, 0xf2, 0x02 }, /* TKIP */ + { 0x00, 0x50, 0xf2, 0x04 }, /* AES */ +}; + +static u8 nxpwifi_rsn_oui[CIPHER_SUITE_MAX][4] = { + { 0x00, 0x0f, 0xac, 0x02 }, /* TKIP */ + { 0x00, 0x0f, 0xac, 0x04 }, /* AES */ +}; + +static void +_dbg_security_flags(int log_level, const char *func, const char *desc, + struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc) +{ + _nxpwifi_dbg(priv->adapter, log_level, + "info: %s: %s:\twpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\tEncMode=%#x privacy=%#x\n", + func, desc, + bss_desc->bcn_wpa_ie ? + bss_desc->bcn_wpa_ie->vend_hdr.element_id : 0, + bss_desc->bcn_rsn_ie ? + bss_desc->bcn_rsn_ie->id : 0, + priv->sec_info.wep_enabled ? "e" : "d", + priv->sec_info.wpa_enabled ? "e" : "d", + priv->sec_info.wpa2_enabled ? "e" : "d", + priv->sec_info.encryption_mode, + bss_desc->privacy); +} + +#define dbg_security_flags(mask, desc, priv, bss_desc) \ + _dbg_security_flags(NXPWIFI_DBG_##mask, desc, __func__, priv, bss_desc) + +static bool +has_ieee_hdr(struct element *ie, u8 key) +{ + return (ie && ie->id == key); +} + +static bool +has_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key) +{ + return (ie && ie->vend_hdr.element_id == key); +} + +/* This function parses a given IE for a given OUI. + * + * This is used to parse a WPA/RSN IE to find if it has + * a given oui in PTK. + */ +static u8 +nxpwifi_search_oui_in_ie(struct ie_body *iebody, u8 *oui) +{ + u8 count; + + count = iebody->ptk_cnt[0]; + + /* There could be multiple OUIs for PTK hence + * 1) Take the length. + * 2) Check all the OUIs for AES. + * 3) If one of them is AES then pass success. + */ + while (count) { + if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body))) + return NXPWIFI_OUI_PRESENT; + + --count; + if (count) + iebody = (struct ie_body *)((u8 *)iebody + + sizeof(iebody->ptk_body)); + } + + pr_debug("info: %s: OUI is not found in PTK\n", __func__); + return NXPWIFI_OUI_NOT_PRESENT; +} + +/* This function checks if a given OUI is present in a RSN IE. + * + * The function first checks if a RSN IE is present or not in the + * BSS descriptor. It tries to locate the OUI only if such an IE is + * present. + */ +static u8 +nxpwifi_is_rsn_oui_present(struct nxpwifi_bssdescriptor *bss_desc, u32 cipher) +{ + u8 *oui; + struct ie_body *iebody; + u8 ret = NXPWIFI_OUI_NOT_PRESENT; + + if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) { + iebody = (struct ie_body *) + (((u8 *)bss_desc->bcn_rsn_ie->data) + + RSN_GTK_OUI_OFFSET); + oui = &nxpwifi_rsn_oui[cipher][0]; + ret = nxpwifi_search_oui_in_ie(iebody, oui); + if (ret) + return ret; + } + return ret; +} + +/* This function checks if a given OUI is present in a WPA IE. + * + * The function first checks if a WPA IE is present or not in the + * BSS descriptor. It tries to locate the OUI only if such an IE is + * present. + */ +static u8 +nxpwifi_is_wpa_oui_present(struct nxpwifi_bssdescriptor *bss_desc, u32 cipher) +{ + u8 *oui; + struct ie_body *iebody; + u8 ret = NXPWIFI_OUI_NOT_PRESENT; + + if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) { + iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data + + WPA_GTK_OUI_OFFSET); + oui = &nxpwifi_wpa_oui[cipher][0]; + ret = nxpwifi_search_oui_in_ie(iebody, oui); + if (ret) + return ret; + } + return ret; +} + +/* This function checks if driver is configured with no security mode and + * scanned network is compatible with it. + */ +static bool +nxpwifi_is_bss_no_sec(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc) +{ + if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && + !priv->sec_info.wpa2_enabled && + !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) && + !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) && + !priv->sec_info.encryption_mode && !bss_desc->privacy) { + return true; + } + return false; +} + +/* This function checks if static WEP is enabled in driver and scanned network + * is compatible with it. + */ +static bool +nxpwifi_is_bss_static_wep(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && + !priv->sec_info.wpa2_enabled && bss_desc->privacy) { + return true; + } + return false; +} + +/* This function checks if wpa is enabled in driver and scanned network is + * compatible with it. + */ +static bool +nxpwifi_is_bss_wpa(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc) +{ + if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled && + !priv->sec_info.wpa2_enabled && + has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) + /* Privacy bit may NOT be set in some APs like + * LinkSys WRT54G && bss_desc->privacy + */ + ) { + dbg_security_flags(INFO, "WPA", priv, bss_desc); + return true; + } + return false; +} + +/* This function checks if wpa2 is enabled in driver and scanned network is + * compatible with it. + */ +static bool +nxpwifi_is_bss_wpa2(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc) +{ + if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && + priv->sec_info.wpa2_enabled && + has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) { + /* Privacy bit may NOT be set in some APs like + * LinkSys WRT54G && bss_desc->privacy + */ + dbg_security_flags(INFO, "WAP2", priv, bss_desc); + return true; + } + return false; +} + +/* This function checks if dynamic WEP is enabled in driver and scanned network + * is compatible with it. + */ +static bool +nxpwifi_is_bss_dynamic_wep(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc) +{ + if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && + !priv->sec_info.wpa2_enabled && + !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) && + !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) && + priv->sec_info.encryption_mode && bss_desc->privacy) { + dbg_security_flags(INFO, "dynamic", priv, bss_desc); + return true; + } + return false; +} + +/* This function checks if a scanned network is compatible with the driver + * settings. + * + * WEP WPA WPA2 encrypt Network + * -enabled -enabled -enabled mode Privacy WPA WPA2 Compatible + * 0 0 0 NONE 0 0 0 yes No security + * 0 1 0 x 1x 1 x yes WPA (disable + * HT if no AES) + * 0 0 1 x 1x x 1 yes WPA2 (disable + * HT if no AES) + * 1 0 0 NONE 1 0 0 yes Static WEP + * (disable HT) + * 0 0 0 !=NONE 1 0 0 yes Dynamic WEP + * + * Compatibility is not matched while roaming, except for mode. + */ +static int +nxpwifi_is_network_compatible(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc, u32 mode) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + + bss_desc->disable_11n = false; + + /* Don't check for compatibility if roaming */ + if (priv->media_connected && + priv->bss_mode == NL80211_IFTYPE_STATION && + bss_desc->bss_mode == NL80211_IFTYPE_STATION) + return 0; + + if (priv->wps.session_enable) { + nxpwifi_dbg(adapter, IOCTL, + "info: return success directly in WPS period\n"); + return 0; + } + + if (bss_desc->chan_sw_ie_present) { + nxpwifi_dbg(adapter, INFO, + "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n"); + return -EPERM; + } + + if (bss_desc->bss_mode == mode) { + if (nxpwifi_is_bss_no_sec(priv, bss_desc)) { + /* No security */ + return 0; + } else if (nxpwifi_is_bss_static_wep(priv, bss_desc)) { + /* Static WEP enabled */ + nxpwifi_dbg(adapter, INFO, + "info: Disable 11n in WEP mode.\n"); + bss_desc->disable_11n = true; + return 0; + } else if (nxpwifi_is_bss_wpa(priv, bss_desc)) { + /* WPA enabled */ + if (((priv->adapter->config_bands & BAND_GN || + priv->adapter->config_bands & BAND_AN) && + bss_desc->bcn_ht_cap) && + !nxpwifi_is_wpa_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + if (nxpwifi_is_wpa_oui_present + (bss_desc, CIPHER_SUITE_TKIP)) { + nxpwifi_dbg(adapter, INFO, + "info: Disable 11n if AES\t" + "is not supported by AP\n"); + bss_desc->disable_11n = true; + } else { + return -EINVAL; + } + } + return 0; + } else if (nxpwifi_is_bss_wpa2(priv, bss_desc)) { + /* WPA2 enabled */ + if (((priv->adapter->config_bands & BAND_GN || + priv->adapter->config_bands & BAND_AN) && + bss_desc->bcn_ht_cap) && + !nxpwifi_is_rsn_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + if (nxpwifi_is_rsn_oui_present + (bss_desc, CIPHER_SUITE_TKIP)) { + nxpwifi_dbg(adapter, INFO, + "info: Disable 11n if AES\t" + "is not supported by AP\n"); + bss_desc->disable_11n = true; + } else { + return -EINVAL; + } + } + return 0; + } else if (nxpwifi_is_bss_dynamic_wep(priv, bss_desc)) { + /* Dynamic WEP enabled */ + return 0; + } + + /* Security doesn't match */ + dbg_security_flags(ERROR, "failed", priv, bss_desc); + return -EINVAL; + } + + /* Mode doesn't match */ + return -EINVAL; +} + +/* This function creates a channel list for the driver to scan, based + * on region/band information. + * + * This routine is used for any scan that is not provided with a + * specific channel list to scan. + */ +static int +nxpwifi_scan_create_channel_list(struct nxpwifi_private *priv, + const struct nxpwifi_user_scan_cfg + *user_scan_in, + struct nxpwifi_chan_scan_param_set + *scan_chan_list, + u8 filtered_scan) +{ + enum nl80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct nxpwifi_adapter *adapter = priv->adapter; + int chan_idx = 0, i; + u16 scan_time = 0; + + if (user_scan_in) + scan_time = (u16)user_scan_in->chan_list[0].scan_time; + + for (band = 0; (band < NUM_NL80211_BANDS) ; band++) { + if (!priv->wdev.wiphy->bands[band]) + continue; + + sband = priv->wdev.wiphy->bands[band]; + + for (i = 0; (i < sband->n_channels) ; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + scan_chan_list[chan_idx].radio_type = band; + + if (scan_time) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(scan_time); + else if ((ch->flags & IEEE80211_CHAN_NO_IR) || + (ch->flags & IEEE80211_CHAN_RADAR)) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->passive_scan_time); + else + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->active_scan_time); + + if (ch->flags & IEEE80211_CHAN_NO_IR) + scan_chan_list[chan_idx].chan_scan_mode_bmap |= + (NXPWIFI_PASSIVE_SCAN | NXPWIFI_HIDDEN_SSID_REPORT); + else + scan_chan_list[chan_idx].chan_scan_mode_bmap &= + ~NXPWIFI_PASSIVE_SCAN; + + scan_chan_list[chan_idx].chan_number = (u32)ch->hw_value; + scan_chan_list[chan_idx].chan_scan_mode_bmap |= + NXPWIFI_DISABLE_CHAN_FILT; + + if (filtered_scan && + !((ch->flags & IEEE80211_CHAN_NO_IR) || + (ch->flags & IEEE80211_CHAN_RADAR))) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->specific_scan_time); + + chan_idx++; + } + } + return chan_idx; +} + +/* This function creates a channel list tlv for bgscan config, based + * on region/band information. + */ +static int +nxpwifi_bgscan_create_channel_list(struct nxpwifi_private *priv, + const struct nxpwifi_bg_scan_cfg + *bgscan_cfg_in, + struct nxpwifi_chan_scan_param_set + *scan_chan_list) +{ + enum nl80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct nxpwifi_adapter *adapter = priv->adapter; + int chan_idx = 0, i; + u16 scan_time = 0, specific_scan_time = adapter->specific_scan_time; + + if (bgscan_cfg_in) + scan_time = (u16)bgscan_cfg_in->chan_list[0].scan_time; + + for (band = 0; (band < NUM_NL80211_BANDS); band++) { + if (!priv->wdev.wiphy->bands[band]) + continue; + + sband = priv->wdev.wiphy->bands[band]; + + for (i = 0; (i < sband->n_channels) ; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + scan_chan_list[chan_idx].radio_type = band; + + if (scan_time) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(scan_time); + else if (ch->flags & IEEE80211_CHAN_NO_IR) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->passive_scan_time); + else + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(specific_scan_time); + + if (ch->flags & IEEE80211_CHAN_NO_IR) + scan_chan_list[chan_idx].chan_scan_mode_bmap |= + NXPWIFI_PASSIVE_SCAN; + else + scan_chan_list[chan_idx].chan_scan_mode_bmap &= + ~NXPWIFI_PASSIVE_SCAN; + + scan_chan_list[chan_idx].chan_number = (u32)ch->hw_value; + chan_idx++; + } + } + return chan_idx; +} + +/* This function appends rate TLV to scan config command. */ +static int +nxpwifi_append_rate_tlv(struct nxpwifi_private *priv, + struct nxpwifi_scan_cmd_config *scan_cfg_out, + u8 radio) +{ + struct nxpwifi_ie_types_rates_param_set *rates_tlv; + u8 rates[NXPWIFI_SUPPORTED_RATES], *tlv_pos; + u32 rates_size; + + memset(rates, 0, sizeof(rates)); + + tlv_pos = (u8 *)scan_cfg_out->tlv_buf + scan_cfg_out->tlv_buf_len; + + if (priv->scan_request) + rates_size = nxpwifi_get_rates_from_cfg80211(priv, rates, + radio); + else + rates_size = nxpwifi_get_supported_rates(priv, rates); + + nxpwifi_dbg(priv->adapter, CMD, + "info: SCAN_CMD: Rates size = %d\n", + rates_size); + rates_tlv = (struct nxpwifi_ie_types_rates_param_set *)tlv_pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16)rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + scan_cfg_out->tlv_buf_len += sizeof(rates_tlv->header) + rates_size; + + return rates_size; +} + +/* This function constructs and sends multiple scan config commands to + * the firmware. + * + * Previous routines in the code flow have created a scan command configuration + * with any requested TLVs. This function splits the channel TLV into maximum + * channels supported per scan lists and sends the portion of the channel TLV, + * along with the other TLVs, to the firmware. + */ +static int +nxpwifi_scan_channel_list(struct nxpwifi_private *priv, + u32 max_chan_per_scan, u8 filtered_scan, + struct nxpwifi_scan_cmd_config *scan_cfg_out, + struct nxpwifi_ie_types_chan_list_param_set *tlv_o, + struct nxpwifi_chan_scan_param_set *scan_chan_list) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + int ret = 0; + struct nxpwifi_chan_scan_param_set *tmp_chan_list; + u32 tlv_idx, rates_size, cmd_no; + u32 total_scan_time; + u32 done_early; + u8 radio_type; + + if (!scan_cfg_out || !tlv_o || !scan_chan_list) { + nxpwifi_dbg(priv->adapter, ERROR, + "info: Scan: Null detect: %p, %p, %p\n", + scan_cfg_out, tlv_o, scan_chan_list); + return -EINVAL; + } + + /* Check csa channel expiry before preparing scan list */ + nxpwifi_11h_get_csa_closed_channel(priv); + + tlv_o->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + + /* Set the temp channel struct pointer to the start of the desired + * list + */ + tmp_chan_list = scan_chan_list; + + /* Loop through the desired channel list, sending a new firmware scan + * commands for each max_chan_per_scan channels (or for 1,6,11 + * individually if configured accordingly) + */ + while (tmp_chan_list->chan_number) { + tlv_idx = 0; + total_scan_time = 0; + radio_type = 0; + tlv_o->header.len = 0; + done_early = false; + + /* Construct the Channel TLV for the scan command. Continue to + * insert channel TLVs until: + * - the tlv_idx hits the maximum configured per scan command + * - the next channel to insert is 0 (end of desired channel + * list) + * - done_early is set (controlling individual scanning of + * 1,6,11) + */ + while (tlv_idx < max_chan_per_scan && + tmp_chan_list->chan_number && !done_early) { + if (tmp_chan_list->chan_number == priv->csa_chan) { + tmp_chan_list++; + continue; + } + + radio_type = tmp_chan_list->radio_type; + nxpwifi_dbg(priv->adapter, INFO, + "info: Scan: Chan(%3d), Radio(%d),\t" + "Mode(%d, %d), Dur(%d)\n", + tmp_chan_list->chan_number, + tmp_chan_list->radio_type, + tmp_chan_list->chan_scan_mode_bmap + & NXPWIFI_PASSIVE_SCAN, + (tmp_chan_list->chan_scan_mode_bmap + & NXPWIFI_DISABLE_CHAN_FILT) >> 1, + le16_to_cpu(tmp_chan_list->max_scan_time)); + + /* Copy the current channel TLV to the command being + * prepared + */ + memcpy(&tlv_o->chan_scan_param[tlv_idx], + tmp_chan_list, + sizeof(*tlv_o->chan_scan_param)); + + /* Increment the TLV header length by the size + * appended + */ + le16_unaligned_add_cpu(&tlv_o->header.len, + sizeof(*tlv_o->chan_scan_param)); + + /* The tlv buffer length is set to the number of bytes + * of the between the channel tlv pointer and the start + * of the tlv buffer. This compensates for any TLVs + * that were appended before the channel list. + */ + scan_cfg_out->tlv_buf_len = (u32)((u8 *)tlv_o - + scan_cfg_out->tlv_buf); + + /* Add the size of the channel tlv header and the data + * length + */ + scan_cfg_out->tlv_buf_len += + (sizeof(tlv_o->header) + + le16_to_cpu(tlv_o->header.len)); + + /* Increment the index to the channel tlv we are + * constructing + */ + tlv_idx++; + + /* Count the total scan time per command */ + total_scan_time += + le16_to_cpu(tmp_chan_list->max_scan_time); + + done_early = false; + + /* Stop the loop if the *current* channel is in the + * 1,6,11 set and we are not filtering on a BSSID + * or SSID. + */ + if (!filtered_scan && + (tmp_chan_list->chan_number == 1 || + tmp_chan_list->chan_number == 6 || + tmp_chan_list->chan_number == 11)) + done_early = true; + + /* Increment the tmp pointer to the next channel to + * be scanned + */ + tmp_chan_list++; + + /* Stop the loop if the *next* channel is in the 1,6,11 + * set. This will cause it to be the only channel + * scanned on the next interation + */ + if (!filtered_scan && + (tmp_chan_list->chan_number == 1 || + tmp_chan_list->chan_number == 6 || + tmp_chan_list->chan_number == 11)) + done_early = true; + } + + /* The total scan time should be less than scan command timeout + * value + */ + if (total_scan_time > NXPWIFI_MAX_TOTAL_SCAN_TIME) { + nxpwifi_dbg(priv->adapter, ERROR, + "total scan time %dms\t" + "is over limit (%dms), scan skipped\n", + total_scan_time, + NXPWIFI_MAX_TOTAL_SCAN_TIME); + ret = -EINVAL; + break; + } + + rates_size = nxpwifi_append_rate_tlv(priv, scan_cfg_out, + radio_type); + + /* Send the scan command to the firmware with the specified + * cfg + */ + if (priv->adapter->ext_scan) + cmd_no = HOST_CMD_802_11_SCAN_EXT; + else + cmd_no = HOST_CMD_802_11_SCAN; + + ret = nxpwifi_send_cmd(priv, cmd_no, HOST_ACT_GEN_SET, + 0, scan_cfg_out, false); + + /* rate IE is updated per scan command but same starting + * pointer is used each time so that rate IE from earlier + * scan_cfg_out->buf is overwritten with new one. + */ + scan_cfg_out->tlv_buf_len -= + sizeof(struct nxpwifi_ie_types_header) + rates_size; + + if (ret) { + nxpwifi_cancel_pending_scan_cmd(adapter); + break; + } + } + + return ret; +} + +/* This function constructs a scan command configuration structure to use + * in scan commands. + * + * Application layer or other functions can invoke network scanning + * with a scan configuration supplied in a user scan configuration structure. + * This structure is used as the basis of one or many scan command configuration + * commands that are sent to the command processing module and eventually to the + * firmware. + * + * This function creates a scan command configuration structure based on the + * following user supplied parameters (if present): + * - SSID filter + * - BSSID filter + * - Number of Probes to be sent + * - Channel list + * + * If the SSID or BSSID filter is not present, the filter is disabled/cleared. + * If the number of probes is not set, adapter default setting is used. + */ +static void +nxpwifi_config_scan(struct nxpwifi_private *priv, + const struct nxpwifi_user_scan_cfg *user_scan_in, + struct nxpwifi_scan_cmd_config *scan_cfg_out, + struct nxpwifi_ie_types_chan_list_param_set **chan_list_out, + struct nxpwifi_chan_scan_param_set *scan_chan_list, + u8 *max_chan_per_scan, u8 *filtered_scan, + u8 *scan_current_only) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_ie_types_num_probes *num_probes_tlv; + struct nxpwifi_ie_types_scan_chan_gap *chan_gap_tlv; + struct nxpwifi_ie_types_random_mac *random_mac_tlv; + struct nxpwifi_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; + struct nxpwifi_ie_types_bssid_list *bssid_tlv; + u8 *tlv_pos; + u32 num_probes; + u32 ssid_len; + u32 chan_idx; + u32 scan_time; + u32 scan_type; + u16 scan_dur; + u8 channel; + u8 radio_type; + int i; + u8 ssid_filter; + struct nxpwifi_ie_types_htcap *ht_cap; + struct nxpwifi_ie_types_bss_mode *bss_mode; + + /* The tlv_buf_len is calculated for each scan command. The TLVs added + * in this routine will be preserved since the routine that sends the + * command will append channelTLVs at *chan_list_out. The difference + * between the *chan_list_out and the tlv_buf start will be used to + * calculate the size of anything we add in this routine. + */ + scan_cfg_out->tlv_buf_len = 0; + + /* Running tlv pointer. Assigned to chan_list_out at end of function + * so later routines know where channels can be added to the command + * buf + */ + tlv_pos = scan_cfg_out->tlv_buf; + + /* Initialize the scan as un-filtered; the flag is later set to TRUE + * below if a SSID or BSSID filter is sent in the command + */ + *filtered_scan = false; + + /* Initialize the scan as not being only on the current channel. If + * the channel list is customized, only contains one channel, and is + * the active channel, this is set true and data flow is not halted. + */ + *scan_current_only = false; + + if (user_scan_in) { + u8 tmpaddr[ETH_ALEN]; + + /* Default the ssid_filter flag to TRUE, set false under + * certain wildcard conditions and qualified by the existence + * of an SSID list before marking the scan as filtered + */ + ssid_filter = true; + + /* Set the BSS type scan filter, use Adapter setting if + * unset + */ + scan_cfg_out->bss_mode = + (u8)(user_scan_in->bss_mode ?: adapter->scan_mode); + + /* Set the number of probes to send, use Adapter setting + * if unset + */ + num_probes = user_scan_in->num_probes ?: adapter->scan_probes; + + /* Set the BSSID filter to the incoming configuration, + * if non-zero. If not set, it will remain disabled + * (all zeros). + */ + memcpy(scan_cfg_out->specific_bssid, + user_scan_in->specific_bssid, + sizeof(scan_cfg_out->specific_bssid)); + + memcpy(tmpaddr, scan_cfg_out->specific_bssid, ETH_ALEN); + + if (adapter->ext_scan && + !is_zero_ether_addr(tmpaddr)) { + bssid_tlv = + (struct nxpwifi_ie_types_bssid_list *)tlv_pos; + bssid_tlv->header.type = cpu_to_le16(TLV_TYPE_BSSID); + bssid_tlv->header.len = cpu_to_le16(ETH_ALEN); + memcpy(bssid_tlv->bssid, user_scan_in->specific_bssid, + ETH_ALEN); + tlv_pos += sizeof(struct nxpwifi_ie_types_bssid_list); + } + + for (i = 0; i < user_scan_in->num_ssids; i++) { + ssid_len = user_scan_in->ssid_list[i].ssid_len; + + wildcard_ssid_tlv = + (struct nxpwifi_ie_types_wildcard_ssid_params *) + tlv_pos; + wildcard_ssid_tlv->header.type = + cpu_to_le16(TLV_TYPE_WILDCARDSSID); + wildcard_ssid_tlv->header.len = + cpu_to_le16((u16)(ssid_len + sizeof(u8))); + + /* max_ssid_length = 0 tells firmware to perform + * specific scan for the SSID filled, whereas + * max_ssid_length = IEEE80211_MAX_SSID_LEN is for + * wildcard scan. + */ + if (ssid_len) + wildcard_ssid_tlv->max_ssid_length = 0; + else + wildcard_ssid_tlv->max_ssid_length = + IEEE80211_MAX_SSID_LEN; + + if (!memcmp(user_scan_in->ssid_list[i].ssid, + "DIRECT-", 7)) + wildcard_ssid_tlv->max_ssid_length = 0xfe; + + memcpy(wildcard_ssid_tlv->ssid, + user_scan_in->ssid_list[i].ssid, ssid_len); + + tlv_pos += (sizeof(wildcard_ssid_tlv->header) + + le16_to_cpu(wildcard_ssid_tlv->header.len)); + + nxpwifi_dbg(adapter, INFO, + "info: scan: ssid[%d]: %s, %d\n", + i, wildcard_ssid_tlv->ssid, + wildcard_ssid_tlv->max_ssid_length); + + /* Empty wildcard ssid with a maxlen will match many or + * potentially all SSIDs (maxlen == 32), therefore do + * not treat the scan as + * filtered. + */ + if (!ssid_len && wildcard_ssid_tlv->max_ssid_length) + ssid_filter = false; + } + + /* The default number of channels sent in the command is low to + * ensure the response buffer from the firmware does not + * truncate scan results. That is not an issue with an SSID + * or BSSID filter applied to the scan results in the firmware. + */ + memcpy(tmpaddr, scan_cfg_out->specific_bssid, ETH_ALEN); + if ((i && ssid_filter) || + !is_zero_ether_addr(tmpaddr)) + *filtered_scan = true; + + if (user_scan_in->scan_chan_gap) { + nxpwifi_dbg(adapter, INFO, + "info: scan: channel gap = %d\n", + user_scan_in->scan_chan_gap); + *max_chan_per_scan = + NXPWIFI_MAX_CHANNELS_PER_SPECIFIC_SCAN; + + chan_gap_tlv = (void *)tlv_pos; + chan_gap_tlv->header.type = + cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP); + chan_gap_tlv->header.len = + cpu_to_le16(sizeof(chan_gap_tlv->chan_gap)); + chan_gap_tlv->chan_gap = + cpu_to_le16((user_scan_in->scan_chan_gap)); + tlv_pos += + sizeof(struct nxpwifi_ie_types_scan_chan_gap); + } + + if (!is_zero_ether_addr(user_scan_in->random_mac)) { + random_mac_tlv = (void *)tlv_pos; + random_mac_tlv->header.type = + cpu_to_le16(TLV_TYPE_RANDOM_MAC); + random_mac_tlv->header.len = + cpu_to_le16(sizeof(random_mac_tlv->mac)); + ether_addr_copy(random_mac_tlv->mac, + user_scan_in->random_mac); + tlv_pos += + sizeof(struct nxpwifi_ie_types_random_mac); + } + } else { + scan_cfg_out->bss_mode = (u8)adapter->scan_mode; + num_probes = adapter->scan_probes; + } + + /* If a specific BSSID or SSID is used, the number of channels in the + * scan command will be increased to the absolute maximum. + */ + if (*filtered_scan) { + *max_chan_per_scan = NXPWIFI_MAX_CHANNELS_PER_SPECIFIC_SCAN; + } else { + if (!priv->media_connected) + *max_chan_per_scan = NXPWIFI_DEF_CHANNELS_PER_SCAN_CMD; + else + *max_chan_per_scan = + NXPWIFI_DEF_CHANNELS_PER_SCAN_CMD / 2; + } + + if (adapter->ext_scan) { + bss_mode = (struct nxpwifi_ie_types_bss_mode *)tlv_pos; + bss_mode->header.type = cpu_to_le16(TLV_TYPE_BSS_MODE); + bss_mode->header.len = cpu_to_le16(sizeof(bss_mode->bss_mode)); + bss_mode->bss_mode = scan_cfg_out->bss_mode; + tlv_pos += sizeof(bss_mode->header) + + le16_to_cpu(bss_mode->header.len); + } + + /* If the input config or adapter has the number of Probes set, + * add tlv + */ + if (num_probes) { + nxpwifi_dbg(adapter, INFO, + "info: scan: num_probes = %d\n", + num_probes); + + num_probes_tlv = (struct nxpwifi_ie_types_num_probes *)tlv_pos; + num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); + num_probes_tlv->header.len = + cpu_to_le16(sizeof(num_probes_tlv->num_probes)); + num_probes_tlv->num_probes = cpu_to_le16((u16)num_probes); + + tlv_pos += sizeof(num_probes_tlv->header) + + le16_to_cpu(num_probes_tlv->header.len); + } + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && + (priv->adapter->config_bands & BAND_GN || + priv->adapter->config_bands & BAND_AN)) { + ht_cap = (struct nxpwifi_ie_types_htcap *)tlv_pos; + memset(ht_cap, 0, sizeof(struct nxpwifi_ie_types_htcap)); + ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + radio_type = + nxpwifi_band_to_radio_type(priv->adapter->config_bands); + nxpwifi_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); + tlv_pos += sizeof(struct nxpwifi_ie_types_htcap); + } + + /* Append vendor specific IE TLV */ + nxpwifi_cmd_append_vsie_tlv(priv, NXPWIFI_VSIE_MASK_SCAN, &tlv_pos); + + /* Set the output for the channel TLV to the address in the tlv buffer + * past any TLVs that were added in this function (SSID, num_probes). + * Channel TLVs will be added past this for each scan command, + * preserving the TLVs that were previously added. + */ + *chan_list_out = + (struct nxpwifi_ie_types_chan_list_param_set *)tlv_pos; + + if (user_scan_in && user_scan_in->chan_list[0].chan_number) { + nxpwifi_dbg(adapter, INFO, + "info: Scan: Using supplied channel list\n"); + + for (chan_idx = 0; + chan_idx < NXPWIFI_USER_SCAN_CHAN_MAX && + user_scan_in->chan_list[chan_idx].chan_number; + chan_idx++) { + channel = user_scan_in->chan_list[chan_idx].chan_number; + scan_chan_list[chan_idx].chan_number = channel; + + radio_type = + user_scan_in->chan_list[chan_idx].radio_type; + scan_chan_list[chan_idx].radio_type = radio_type; + + scan_type = user_scan_in->chan_list[chan_idx].scan_type; + + if (scan_type == NXPWIFI_SCAN_TYPE_PASSIVE) + scan_chan_list[chan_idx].chan_scan_mode_bmap |= + (NXPWIFI_PASSIVE_SCAN | + NXPWIFI_HIDDEN_SSID_REPORT); + else + scan_chan_list[chan_idx].chan_scan_mode_bmap &= + ~NXPWIFI_PASSIVE_SCAN; + + scan_chan_list[chan_idx].chan_scan_mode_bmap |= + NXPWIFI_DISABLE_CHAN_FILT; + + scan_time = user_scan_in->chan_list[chan_idx].scan_time; + + if (scan_time) { + scan_dur = (u16)scan_time; + } else { + if (scan_type == NXPWIFI_SCAN_TYPE_PASSIVE) + scan_dur = adapter->passive_scan_time; + else if (*filtered_scan) + scan_dur = adapter->specific_scan_time; + else + scan_dur = adapter->active_scan_time; + } + + scan_chan_list[chan_idx].min_scan_time = + cpu_to_le16(scan_dur); + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(scan_dur); + } + + /* Check if we are only scanning the current channel */ + if (chan_idx == 1 && + user_scan_in->chan_list[0].chan_number == + priv->curr_bss_params.bss_descriptor.channel) { + *scan_current_only = true; + nxpwifi_dbg(adapter, INFO, + "info: Scan: Scanning current channel only\n"); + } + } else { + nxpwifi_dbg(adapter, INFO, + "info: Scan: Creating full region channel list\n"); + nxpwifi_scan_create_channel_list(priv, user_scan_in, + scan_chan_list, + *filtered_scan); + } +} + +/* This function inspects the scan response buffer for pointers to + * expected TLVs. + * + * TLVs can be included at the end of the scan response BSS information. + * + * Data in the buffer is parsed pointers to TLVs that can potentially + * be passed back in the response. + */ +static void +nxpwifi_ret_802_11_scan_get_tlv_ptrs(struct nxpwifi_adapter *adapter, + struct nxpwifi_ie_types_data *tlv, + u32 tlv_buf_size, u32 req_tlv_type, + struct nxpwifi_ie_types_data **tlv_data) +{ + struct nxpwifi_ie_types_data *current_tlv; + u32 tlv_buf_left; + u32 tlv_type; + u32 tlv_len; + + current_tlv = tlv; + tlv_buf_left = tlv_buf_size; + *tlv_data = NULL; + + nxpwifi_dbg(adapter, INFO, + "info: SCAN_RESP: tlv_buf_size = %d\n", + tlv_buf_size); + + while (tlv_buf_left >= sizeof(struct nxpwifi_ie_types_header)) { + tlv_type = le16_to_cpu(current_tlv->header.type); + tlv_len = le16_to_cpu(current_tlv->header.len); + + if (sizeof(tlv->header) + tlv_len > tlv_buf_left) { + nxpwifi_dbg(adapter, ERROR, + "SCAN_RESP: TLV buffer corrupt\n"); + break; + } + + if (req_tlv_type == tlv_type) { + switch (tlv_type) { + case TLV_TYPE_TSFTIMESTAMP: + nxpwifi_dbg(adapter, INFO, + "info: SCAN_RESP: TSF\t" + "timestamp TLV, len = %d\n", + tlv_len); + *tlv_data = current_tlv; + break; + case TLV_TYPE_CHANNELBANDLIST: + nxpwifi_dbg(adapter, INFO, + "info: SCAN_RESP: channel\t" + "band list TLV, len = %d\n", + tlv_len); + *tlv_data = current_tlv; + break; + default: + nxpwifi_dbg(adapter, ERROR, + "SCAN_RESP: unhandled TLV = %d\n", + tlv_type); + /* Give up, this seems corrupted */ + return; + } + } + + if (*tlv_data) + break; + + tlv_buf_left -= (sizeof(tlv->header) + tlv_len); + current_tlv = + (struct nxpwifi_ie_types_data *)(current_tlv->data + + tlv_len); + } /* while */ +} + +/* This function parses provided beacon buffer and updates + * respective fields in bss descriptor structure. + */ +int nxpwifi_update_bss_desc_with_ie(struct nxpwifi_adapter *adapter, + struct nxpwifi_bssdescriptor *bss_entry) +{ + u8 element_id; + struct ieee_types_fh_param_set *fh_param_set; + struct ieee_types_ds_param_set *ds_param_set; + struct ieee_types_cf_param_set *cf_param_set; + u8 *current_ptr; + u8 *rate; + u8 element_len; + u16 total_ie_len; + u8 bytes_to_copy; + u8 rate_size; + u8 found_data_rate_ie; + u32 bytes_left; + struct ieee_types_vendor_specific *vendor_ie; + const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; + const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; + + found_data_rate_ie = false; + rate_size = 0; + current_ptr = bss_entry->beacon_buf; + bytes_left = bss_entry->beacon_buf_size; + + /* Process variable IE */ + while (bytes_left >= 2) { + element_id = *current_ptr; + element_len = *(current_ptr + 1); + total_ie_len = element_len + sizeof(struct element); + + if (bytes_left < total_ie_len) { + nxpwifi_dbg(adapter, ERROR, + "err: InterpretIE: in processing\t" + "IE, bytes left < IE length\n"); + return -EINVAL; + } + switch (element_id) { + case WLAN_EID_SSID: + if (element_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + bss_entry->ssid.ssid_len = element_len; + memcpy(bss_entry->ssid.ssid, (current_ptr + 2), + element_len); + nxpwifi_dbg(adapter, INFO, + "info: InterpretIE: ssid: %-32s\n", + bss_entry->ssid.ssid); + break; + + case WLAN_EID_SUPP_RATES: + if (element_len > NXPWIFI_SUPPORTED_RATES) + return -EINVAL; + memcpy(bss_entry->data_rates, current_ptr + 2, + element_len); + memcpy(bss_entry->supported_rates, current_ptr + 2, + element_len); + rate_size = element_len; + found_data_rate_ie = true; + break; + + case WLAN_EID_FH_PARAMS: + if (total_ie_len < sizeof(*fh_param_set)) + return -EINVAL; + fh_param_set = + (struct ieee_types_fh_param_set *)current_ptr; + memcpy(&bss_entry->phy_param_set.fh_param_set, + fh_param_set, + sizeof(struct ieee_types_fh_param_set)); + break; + + case WLAN_EID_DS_PARAMS: + if (total_ie_len < sizeof(*ds_param_set)) + return -EINVAL; + ds_param_set = + (struct ieee_types_ds_param_set *)current_ptr; + + bss_entry->channel = ds_param_set->current_chan; + + memcpy(&bss_entry->phy_param_set.ds_param_set, + ds_param_set, + sizeof(struct ieee_types_ds_param_set)); + break; + + case WLAN_EID_CF_PARAMS: + if (total_ie_len < sizeof(*cf_param_set)) + return -EINVAL; + cf_param_set = + (struct ieee_types_cf_param_set *)current_ptr; + memcpy(&bss_entry->cf_param_set, + cf_param_set, + sizeof(struct ieee_types_cf_param_set)); + break; + + case WLAN_EID_ERP_INFO: + if (!element_len) + return -EINVAL; + bss_entry->erp_flags = *(current_ptr + 2); + break; + + case WLAN_EID_PWR_CONSTRAINT: + if (!element_len) + return -EINVAL; + bss_entry->local_constraint = *(current_ptr + 2); + bss_entry->sensed_11h = true; + break; + + case WLAN_EID_CHANNEL_SWITCH: + bss_entry->chan_sw_ie_present = true; + fallthrough; + case WLAN_EID_PWR_CAPABILITY: + case WLAN_EID_TPC_REPORT: + case WLAN_EID_QUIET: + bss_entry->sensed_11h = true; + break; + + case WLAN_EID_EXT_SUPP_RATES: + /* Only process extended supported rate + * if data rate is already found. + * Data rate IE should come before + * extended supported rate IE + */ + if (found_data_rate_ie) { + if ((element_len + rate_size) > + NXPWIFI_SUPPORTED_RATES) + bytes_to_copy = + (NXPWIFI_SUPPORTED_RATES - + rate_size); + else + bytes_to_copy = element_len; + + rate = (u8 *)bss_entry->data_rates; + rate += rate_size; + memcpy(rate, current_ptr + 2, bytes_to_copy); + + rate = (u8 *)bss_entry->supported_rates; + rate += rate_size; + memcpy(rate, current_ptr + 2, bytes_to_copy); + } + break; + + case WLAN_EID_VENDOR_SPECIFIC: + vendor_ie = (struct ieee_types_vendor_specific *) + current_ptr; + + /* 802.11 requires at least 3-byte OUI. */ + if (element_len < sizeof(vendor_ie->vend_hdr.oui)) + return -EINVAL; + + /* Not long enough for a match? Skip it. */ + if (element_len < sizeof(wpa_oui)) + break; + + if (!memcmp(&vendor_ie->vend_hdr.oui, wpa_oui, + sizeof(wpa_oui))) { + bss_entry->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + current_ptr; + bss_entry->wpa_offset = (u16) + (current_ptr - bss_entry->beacon_buf); + } else if (!memcmp(&vendor_ie->vend_hdr.oui, wmm_oui, + sizeof(wmm_oui))) { + if (total_ie_len == + sizeof(struct ieee80211_wmm_param_ie) || + total_ie_len == + sizeof(struct ieee_types_wmm_info)) + /* Only accept and copy the WMM IE if + * it matches the size expected for the + * WMM Info IE or the WMM Parameter IE. + */ + memcpy((u8 *)&bss_entry->wmm_ie, + current_ptr, total_ie_len); + } + break; + case WLAN_EID_RSN: + bss_entry->bcn_rsn_ie = + (struct element *)current_ptr; + bss_entry->rsn_offset = + (u16)(current_ptr - bss_entry->beacon_buf); + break; + case WLAN_EID_RSNX: + bss_entry->bcn_rsnx_ie = + (struct element *)current_ptr; + bss_entry->rsnx_offset = + (u16)(current_ptr - bss_entry->beacon_buf); + break; + case WLAN_EID_HT_CAPABILITY: + bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *) + (current_ptr + + sizeof(struct element)); + bss_entry->ht_cap_offset = (u16)(current_ptr + + sizeof(struct element) - + bss_entry->beacon_buf); + break; + case WLAN_EID_HT_OPERATION: + bss_entry->bcn_ht_oper = + (struct ieee80211_ht_operation *)(current_ptr + + sizeof(struct element)); + bss_entry->ht_info_offset = (u16)(current_ptr + + sizeof(struct element) - + bss_entry->beacon_buf); + break; + case WLAN_EID_VHT_CAPABILITY: + bss_entry->disable_11ac = false; + bss_entry->bcn_vht_cap = + (void *)(current_ptr + + sizeof(struct element)); + bss_entry->vht_cap_offset = + (u16)((u8 *)bss_entry->bcn_vht_cap - + bss_entry->beacon_buf); + break; + case WLAN_EID_VHT_OPERATION: + bss_entry->bcn_vht_oper = + (void *)(current_ptr + + sizeof(struct element)); + bss_entry->vht_info_offset = + (u16)((u8 *)bss_entry->bcn_vht_oper - + bss_entry->beacon_buf); + break; + case WLAN_EID_BSS_COEX_2040: + bss_entry->bcn_bss_co_2040 = current_ptr; + bss_entry->bss_co_2040_offset = + (u16)(current_ptr - bss_entry->beacon_buf); + break; + case WLAN_EID_EXT_CAPABILITY: + bss_entry->bcn_ext_cap = current_ptr; + bss_entry->ext_cap_offset = + (u16)(current_ptr - bss_entry->beacon_buf); + break; + case WLAN_EID_OPMODE_NOTIF: + bss_entry->oper_mode = (void *)current_ptr; + bss_entry->oper_mode_offset = + (u16)((u8 *)bss_entry->oper_mode - + bss_entry->beacon_buf); + break; + default: + break; + } + + current_ptr += total_ie_len; + bytes_left -= total_ie_len; + + } /* while (bytes_left > 2) */ + return 0; +} + +/* This function converts radio type scan parameter to a band configuration + * to be used in join command. + */ +static u8 +nxpwifi_radio_type_to_band(u8 radio_type) +{ + switch (radio_type) { + case HOST_SCAN_RADIO_TYPE_A: + return BAND_A; + case HOST_SCAN_RADIO_TYPE_BG: + default: + return BAND_G; + } +} + +/* This is an internal function used to start a scan based on an input + * configuration. + * + * This uses the input user scan configuration information when provided in + * order to send the appropriate scan commands to firmware to populate or + * update the internal driver scan table. + */ +int nxpwifi_scan_networks(struct nxpwifi_private *priv, + const struct nxpwifi_user_scan_cfg *user_scan_in) +{ + int ret; + struct nxpwifi_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node; + union nxpwifi_scan_cmd_config_tlv *scan_cfg_out; + struct nxpwifi_ie_types_chan_list_param_set *chan_list_out; + struct nxpwifi_chan_scan_param_set *scan_chan_list; + u8 filtered_scan; + u8 scan_current_chan_only; + u8 max_chan_per_scan; + + if (adapter->scan_processing) { + nxpwifi_dbg(adapter, WARN, + "cmd: Scan already in process...\n"); + return -EBUSY; + } + + if (priv->scan_block) { + nxpwifi_dbg(adapter, WARN, + "cmd: Scan is blocked during association...\n"); + return -EBUSY; + } + + if (test_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags) || + test_bit(NXPWIFI_IS_CMD_TIMEDOUT, &adapter->work_flags)) { + nxpwifi_dbg(adapter, ERROR, + "Ignore scan. Card removed or firmware in bad state\n"); + return -EPERM; + } + + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->scan_processing = true; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + + scan_cfg_out = kzalloc(sizeof(union nxpwifi_scan_cmd_config_tlv), + GFP_KERNEL); + if (!scan_cfg_out) { + ret = -ENOMEM; + goto done; + } + + scan_chan_list = kcalloc(NXPWIFI_USER_SCAN_CHAN_MAX, + sizeof(struct nxpwifi_chan_scan_param_set), + GFP_KERNEL); + if (!scan_chan_list) { + kfree(scan_cfg_out); + ret = -ENOMEM; + goto done; + } + + nxpwifi_config_scan(priv, user_scan_in, &scan_cfg_out->config, + &chan_list_out, scan_chan_list, &max_chan_per_scan, + &filtered_scan, &scan_current_chan_only); + + ret = nxpwifi_scan_channel_list(priv, max_chan_per_scan, filtered_scan, + &scan_cfg_out->config, chan_list_out, + scan_chan_list); + + /* Get scan command from scan_pending_q and put to cmd_pending_q */ + if (!ret) { + spin_lock_bh(&adapter->scan_pending_q_lock); + if (!list_empty(&adapter->scan_pending_q)) { + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_bh(&adapter->scan_pending_q_lock); + nxpwifi_insert_cmd_to_pending_q(adapter, cmd_node); + nxpwifi_queue_work(adapter, &adapter->main_work); + + /* Perform internal scan synchronously */ + if (!priv->scan_request) { + nxpwifi_dbg(adapter, INFO, + "wait internal scan\n"); + nxpwifi_wait_queue_complete(adapter, cmd_node); + } + } else { + spin_unlock_bh(&adapter->scan_pending_q_lock); + } + } + + kfree(scan_cfg_out); + kfree(scan_chan_list); +done: + if (ret) { + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->scan_processing = false; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + } + return ret; +} + +/* This function prepares a scan command to be sent to the firmware. + * + * This uses the scan command configuration sent to the command processing + * module in command preparation stage to configure a scan command structure + * to send to firmware. + * + * The fixed fields specifying the BSS type and BSSID filters as well as a + * variable number/length of TLVs are sent in the command to firmware. + * + * Preparation also includes - + * - Setting command ID, and proper size + * - Ensuring correct endian-ness + */ +int nxpwifi_cmd_802_11_scan(struct host_cmd_ds_command *cmd, + struct nxpwifi_scan_cmd_config *scan_cfg) +{ + struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; + + /* Set fixed field variables in scan command */ + scan_cmd->bss_mode = scan_cfg->bss_mode; + memcpy(scan_cmd->bssid, scan_cfg->specific_bssid, + sizeof(scan_cmd->bssid)); + memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); + + cmd->command = cpu_to_le16(HOST_CMD_802_11_SCAN); + + /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ + cmd->size = cpu_to_le16((u16)(sizeof(scan_cmd->bss_mode) + + sizeof(scan_cmd->bssid) + + scan_cfg->tlv_buf_len + S_DS_GEN)); + + return 0; +} + +/* This function checks compatibility of requested network with current + * driver settings. + */ +int nxpwifi_check_network_compatibility(struct nxpwifi_private *priv, + struct nxpwifi_bssdescriptor *bss_desc) +{ + int ret = 0; + + if (!bss_desc) + return -EINVAL; + + if ((nxpwifi_get_cfp(priv, (u8)bss_desc->bss_band, + (u16)bss_desc->channel, 0))) { + switch (priv->bss_mode) { + case NL80211_IFTYPE_STATION: + ret = nxpwifi_is_network_compatible(priv, bss_desc, + priv->bss_mode); + if (ret) + nxpwifi_dbg(priv->adapter, ERROR, + "Incompatible network settings\n"); + break; + default: + ret = 0; + } + } + + return ret; +} + +/* This function checks if SSID string contains all zeroes or length is zero */ +static bool nxpwifi_is_hidden_ssid(struct cfg80211_ssid *ssid) +{ + int idx; + + for (idx = 0; idx < ssid->ssid_len; idx++) { + if (ssid->ssid[idx]) + return false; + } + + return true; +} + +/* This function checks if any hidden SSID found in passive scan channels + * and save those channels for specific SSID active scan + */ +static int nxpwifi_save_hidden_ssid_channels(struct nxpwifi_private *priv, + struct cfg80211_bss *bss) +{ + struct nxpwifi_bssdescriptor *bss_desc; + int ret; + int chid; + + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(*bss_desc), GFP_KERNEL); + if (!bss_desc) + return -ENOMEM; + + ret = nxpwifi_fill_new_bss_desc(priv, bss, bss_desc); + if (ret) + goto done; + + if (nxpwifi_is_hidden_ssid(&bss_desc->ssid)) { + nxpwifi_dbg(priv->adapter, INFO, "found hidden SSID\n"); + for (chid = 0 ; chid < NXPWIFI_USER_SCAN_CHAN_MAX; chid++) { + if (priv->hidden_chan[chid].chan_number == + bss->channel->hw_value) + break; + + if (!priv->hidden_chan[chid].chan_number) { + priv->hidden_chan[chid].chan_number = + bss->channel->hw_value; + priv->hidden_chan[chid].radio_type = + bss->channel->band; + priv->hidden_chan[chid].scan_type = + NXPWIFI_SCAN_TYPE_ACTIVE; + break; + } + } + } + +done: + /* beacon_ie buffer was allocated in function + * nxpwifi_fill_new_bss_desc(). Free it now. + */ + kfree(bss_desc->beacon_buf); + kfree(bss_desc); + return ret; +} + +static int nxpwifi_update_curr_bss_params(struct nxpwifi_private *priv, + struct cfg80211_bss *bss) +{ + struct nxpwifi_bssdescriptor *bss_desc; + int ret; + + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(*bss_desc), GFP_KERNEL); + if (!bss_desc) + return -ENOMEM; + + ret = nxpwifi_fill_new_bss_desc(priv, bss, bss_desc); + if (ret) + goto done; + + ret = nxpwifi_check_network_compatibility(priv, bss_desc); + if (ret) + goto done; + + spin_lock_bh(&priv->curr_bcn_buf_lock); + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc, + sizeof(priv->curr_bss_params.bss_descriptor)); + + /* The contents of beacon_ie will be copied to its own buffer + * in nxpwifi_save_curr_bcn() + */ + nxpwifi_save_curr_bcn(priv); + spin_unlock_bh(&priv->curr_bcn_buf_lock); + +done: + /* beacon_ie buffer was allocated in function + * nxpwifi_fill_new_bss_desc(). Free it now. + */ + kfree(bss_desc->beacon_buf); + kfree(bss_desc); + return ret; +} + +static int +nxpwifi_parse_single_response_buf(struct nxpwifi_private *priv, u8 **bss_info, + u32 *bytes_left, u64 fw_tsf, u8 *radio_type, + bool ext_scan, s32 rssi_val) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_chan_freq_power *cfp; + struct cfg80211_bss *bss; + u8 bssid[ETH_ALEN]; + s32 rssi; + const u8 *ie_buf; + size_t ie_len; + u16 channel = 0; + u16 beacon_size = 0; + u32 curr_bcn_bytes; + u32 freq; + u16 beacon_period; + u16 cap_info_bitmap; + u8 *current_ptr; + u64 timestamp; + struct nxpwifi_fixed_bcn_param *bcn_param; + struct nxpwifi_bss_priv *bss_priv; + + if (*bytes_left >= sizeof(beacon_size)) { + /* Extract & convert beacon size from command buffer */ + beacon_size = get_unaligned_le16((*bss_info)); + *bytes_left -= sizeof(beacon_size); + *bss_info += sizeof(beacon_size); + } + + if (!beacon_size || beacon_size > *bytes_left) { + *bss_info += *bytes_left; + *bytes_left = 0; + return -EINVAL; + } + + /* Initialize the current working beacon pointer for this BSS + * iteration + */ + current_ptr = *bss_info; + + /* Advance the return beacon pointer past the current beacon */ + *bss_info += beacon_size; + *bytes_left -= beacon_size; + + curr_bcn_bytes = beacon_size; + + /* First 5 fields are bssid, RSSI(for legacy scan only), + * time stamp, beacon interval, and capability information + */ + if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) + + sizeof(struct nxpwifi_fixed_bcn_param)) { + nxpwifi_dbg(adapter, ERROR, + "InterpretIE: not enough bytes left\n"); + return -EINVAL; + } + + memcpy(bssid, current_ptr, ETH_ALEN); + current_ptr += ETH_ALEN; + curr_bcn_bytes -= ETH_ALEN; + + if (!ext_scan) { + rssi = (s32)*current_ptr; + rssi = (-rssi) * 100; /* Convert dBm to mBm */ + current_ptr += sizeof(u8); + curr_bcn_bytes -= sizeof(u8); + nxpwifi_dbg(adapter, INFO, + "info: InterpretIE: RSSI=%d\n", rssi); + } else { + rssi = rssi_val; + } + + bcn_param = (struct nxpwifi_fixed_bcn_param *)current_ptr; + current_ptr += sizeof(*bcn_param); + curr_bcn_bytes -= sizeof(*bcn_param); + + timestamp = le64_to_cpu(bcn_param->timestamp); + beacon_period = le16_to_cpu(bcn_param->beacon_period); + + cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap); + nxpwifi_dbg(adapter, INFO, + "info: InterpretIE: capabilities=0x%X\n", + cap_info_bitmap); + + /* Rest of the current buffer are IE's */ + ie_buf = current_ptr; + ie_len = curr_bcn_bytes; + nxpwifi_dbg(adapter, INFO, + "info: InterpretIE: IELength for this AP = %d\n", + curr_bcn_bytes); + + while (curr_bcn_bytes >= sizeof(struct element)) { + u8 element_id, element_len; + + element_id = *current_ptr; + element_len = *(current_ptr + 1); + if (curr_bcn_bytes < element_len + + sizeof(struct element)) { + nxpwifi_dbg(adapter, ERROR, + "%s: bytes left < IE length\n", __func__); + return -EFAULT; + } + if (element_id == WLAN_EID_DS_PARAMS) { + channel = *(current_ptr + + sizeof(struct element)); + break; + } + + current_ptr += element_len + sizeof(struct element); + curr_bcn_bytes -= element_len + + sizeof(struct element); + } + + if (channel) { + struct ieee80211_channel *chan; + struct nxpwifi_bssdescriptor *bss_desc; + u8 band; + + /* Skip entry if on csa closed channel */ + if (channel == priv->csa_chan) { + nxpwifi_dbg(adapter, WARN, + "Dropping entry on csa closed channel\n"); + return 0; + } + + band = BAND_G; + if (radio_type) + band = nxpwifi_radio_type_to_band(*radio_type & + (BIT(0) | BIT(1))); + + cfp = nxpwifi_get_cfp(priv, band, channel, 0); + + freq = cfp ? cfp->freq : 0; + + chan = ieee80211_get_channel(priv->wdev.wiphy, freq); + + if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { + bss = cfg80211_inform_bss(priv->wdev.wiphy, chan, + CFG80211_BSS_FTYPE_UNKNOWN, + bssid, timestamp, + cap_info_bitmap, + beacon_period, + ie_buf, ie_len, rssi, + GFP_ATOMIC); + if (bss) { + bss_priv = (struct nxpwifi_bss_priv *)bss->priv; + bss_priv->band = band; + bss_priv->fw_tsf = fw_tsf; + bss_desc = + &priv->curr_bss_params.bss_descriptor; + if (priv->media_connected && + !memcmp(bssid, bss_desc->mac_address, + ETH_ALEN)) + nxpwifi_update_curr_bss_params(priv, + bss); + + if ((chan->flags & IEEE80211_CHAN_RADAR) || + (chan->flags & IEEE80211_CHAN_NO_IR)) { + nxpwifi_dbg(adapter, INFO, + "radar or passive channel %d\n", + channel); + nxpwifi_save_hidden_ssid_channels(priv, + bss); + } + + cfg80211_put_bss(priv->wdev.wiphy, bss); + } + } + } else { + nxpwifi_dbg(adapter, WARN, "missing BSS channel IE\n"); + } + + return 0; +} + +static void nxpwifi_complete_scan(struct nxpwifi_private *priv) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + + adapter->survey_idx = 0; + if (adapter->curr_cmd->wait_q_enabled) { + adapter->cmd_wait_q.status = 0; + if (!priv->scan_request) { + nxpwifi_dbg(adapter, INFO, + "complete internal scan\n"); + nxpwifi_complete_cmd(adapter, adapter->curr_cmd); + } + } +} + +/* This function checks if any hidden SSID found in passive scan channels + * and do specific SSID active scan for those channels + */ +static int +nxpwifi_active_scan_req_for_passive_chan(struct nxpwifi_private *priv) +{ + int ret; + struct nxpwifi_adapter *adapter = priv->adapter; + u8 id = 0; + struct nxpwifi_user_scan_cfg *user_scan_cfg; + + if (adapter->active_scan_triggered || !priv->scan_request || + priv->scan_aborting) { + adapter->active_scan_triggered = false; + return 0; + } + + if (!priv->hidden_chan[0].chan_number) { + nxpwifi_dbg(adapter, INFO, "No BSS with hidden SSID found on DFS channels\n"); + return 0; + } + user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); + + if (!user_scan_cfg) + return -ENOMEM; + + for (id = 0; id < NXPWIFI_USER_SCAN_CHAN_MAX; id++) { + if (!priv->hidden_chan[id].chan_number) + break; + memcpy(&user_scan_cfg->chan_list[id], + &priv->hidden_chan[id], + sizeof(struct nxpwifi_user_scan_chan)); + } + + adapter->active_scan_triggered = true; + if (priv->scan_request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) + ether_addr_copy(user_scan_cfg->random_mac, + priv->scan_request->mac_addr); + user_scan_cfg->num_ssids = priv->scan_request->n_ssids; + user_scan_cfg->ssid_list = priv->scan_request->ssids; + + ret = nxpwifi_scan_networks(priv, user_scan_cfg); + kfree(user_scan_cfg); + + memset(&priv->hidden_chan, 0, sizeof(priv->hidden_chan)); + + if (ret) + dev_err(priv->adapter->dev, "scan failed: %d\n", ret); + + return ret; +} + +static void nxpwifi_check_next_scan_command(struct nxpwifi_private *priv) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node; + + spin_lock_bh(&adapter->scan_pending_q_lock); + if (list_empty(&adapter->scan_pending_q)) { + spin_unlock_bh(&adapter->scan_pending_q_lock); + + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->scan_processing = false; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + + nxpwifi_active_scan_req_for_passive_chan(priv); + + if (!adapter->ext_scan) + nxpwifi_complete_scan(priv); + + if (priv->scan_request) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + + nxpwifi_dbg(adapter, INFO, + "info: notifying scan done\n"); + cfg80211_scan_done(priv->scan_request, &info); + priv->scan_request = NULL; + priv->scan_aborting = false; + } else { + priv->scan_aborting = false; + nxpwifi_dbg(adapter, INFO, + "info: scan already aborted\n"); + } + } else if ((priv->scan_aborting && !priv->scan_request) || + priv->scan_block) { + spin_unlock_bh(&adapter->scan_pending_q_lock); + + nxpwifi_cancel_pending_scan_cmd(adapter); + + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->scan_processing = false; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + + if (!adapter->active_scan_triggered) { + if (priv->scan_request) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + nxpwifi_dbg(adapter, INFO, + "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, &info); + priv->scan_request = NULL; + priv->scan_aborting = false; + } else { + priv->scan_aborting = false; + nxpwifi_dbg(adapter, INFO, + "info: scan already aborted\n"); + } + } + } else { + /* Get scan command from scan_pending_q and put to + * cmd_pending_q + */ + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_bh(&adapter->scan_pending_q_lock); + nxpwifi_insert_cmd_to_pending_q(adapter, cmd_node); + } +} + +void nxpwifi_cancel_scan(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_private *priv; + int i; + + nxpwifi_cancel_pending_scan_cmd(adapter); + + if (adapter->scan_processing) { + spin_lock_bh(&adapter->nxpwifi_cmd_lock); + adapter->scan_processing = false; + spin_unlock_bh(&adapter->nxpwifi_cmd_lock); + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (!priv) + continue; + if (priv->scan_request) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + nxpwifi_dbg(adapter, INFO, + "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, &info); + priv->scan_request = NULL; + priv->scan_aborting = false; + } + } + } +} + +/* This function handles the command response of scan. + * + * The response buffer for the scan command has the following + * memory layout: + * + * .-------------------------------------------------------------. + * | Header (4 * sizeof(t_u16)): Standard command response hdr | + * .-------------------------------------------------------------. + * | BufSize (t_u16) : sizeof the BSS Description data | + * .-------------------------------------------------------------. + * | NumOfSet (t_u8) : Number of BSS Descs returned | + * .-------------------------------------------------------------. + * | BSSDescription data (variable, size given in BufSize) | + * .-------------------------------------------------------------. + * | TLV data (variable, size calculated using Header->Size, | + * | BufSize and sizeof the fixed fields above) | + * .-------------------------------------------------------------. + */ +int nxpwifi_ret_802_11_scan(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp) +{ + int ret = 0; + struct nxpwifi_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_scan_rsp *scan_rsp; + struct nxpwifi_ie_types_data *tlv_data; + struct nxpwifi_ie_types_tsf_timestamp *tsf_tlv; + u8 *bss_info; + u32 scan_resp_size; + u32 bytes_left; + u32 idx; + u32 tlv_buf_size; + struct nxpwifi_ie_types_chan_band_list_param_set *chan_band_tlv; + struct chan_band_param_set *chan_band; + u8 is_bgscan_resp; + __le64 fw_tsf = 0; + u8 *radio_type; + struct cfg80211_wowlan_nd_match *pmatch; + struct cfg80211_sched_scan_request *nd_config = NULL; + + is_bgscan_resp = (le16_to_cpu(resp->command) + == HOST_CMD_802_11_BG_SCAN_QUERY); + if (is_bgscan_resp) + scan_rsp = &resp->params.bg_scan_query_resp.scan_resp; + else + scan_rsp = &resp->params.scan_resp; + + if (scan_rsp->number_of_sets > NXPWIFI_MAX_AP) { + nxpwifi_dbg(adapter, ERROR, + "SCAN_RESP: too many AP returned (%d)\n", + scan_rsp->number_of_sets); + ret = -EINVAL; + goto check_next_scan; + } + + /* Check csa channel expiry before parsing scan response */ + nxpwifi_11h_get_csa_closed_channel(priv); + + bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); + nxpwifi_dbg(adapter, INFO, + "info: SCAN_RESP: bss_descript_size %d\n", + bytes_left); + + scan_resp_size = le16_to_cpu(resp->size); + + nxpwifi_dbg(adapter, INFO, + "info: SCAN_RESP: returned %d APs before parsing\n", + scan_rsp->number_of_sets); + + bss_info = scan_rsp->bss_desc_and_tlv_buffer; + + /* The size of the TLV buffer is equal to the entire command response + * size (scan_resp_size) minus the fixed fields (sizeof()'s), the + * BSS Descriptions (bss_descript_size as bytesLef) and the command + * response header (S_DS_GEN) + */ + tlv_buf_size = scan_resp_size - (bytes_left + + sizeof(scan_rsp->bss_descript_size) + + sizeof(scan_rsp->number_of_sets) + + S_DS_GEN); + + tlv_data = (struct nxpwifi_ie_types_data *) + (scan_rsp->bss_desc_and_tlv_buffer + bytes_left); + + /* Search the TLV buffer space in the scan response for any valid + * TLVs + */ + nxpwifi_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, + TLV_TYPE_TSFTIMESTAMP, + (struct nxpwifi_ie_types_data **) + &tsf_tlv); + + /* Search the TLV buffer space in the scan response for any valid + * TLVs + */ + nxpwifi_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, + TLV_TYPE_CHANNELBANDLIST, + (struct nxpwifi_ie_types_data **) + &chan_band_tlv); + +#ifdef CONFIG_PM + if (priv->wdev.wiphy->wowlan_config) + nd_config = priv->wdev.wiphy->wowlan_config->nd_config; +#endif + + if (nd_config) { + adapter->nd_info = + kzalloc(struct_size(adapter->nd_info, matches, + scan_rsp->number_of_sets), + GFP_ATOMIC); + + if (adapter->nd_info) + adapter->nd_info->n_matches = scan_rsp->number_of_sets; + } + + for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { + /* If the TSF TLV was appended to the scan results, save this + * entry's TSF value in the fw_tsf field. It is the firmware's + * TSF value at the time the beacon or probe response was + * received. + */ + if (tsf_tlv) + memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], + sizeof(fw_tsf)); + + if (chan_band_tlv) { + chan_band = &chan_band_tlv->chan_band_param[idx]; + radio_type = &chan_band->radio_type; + } else { + radio_type = NULL; + } + + if (chan_band_tlv && adapter->nd_info) { + adapter->nd_info->matches[idx] = + kzalloc(sizeof(*pmatch) + sizeof(u32), + GFP_ATOMIC); + + pmatch = adapter->nd_info->matches[idx]; + + if (pmatch) { + pmatch->n_channels = 1; + pmatch->channels[0] = chan_band->chan_number; + } + } + + ret = nxpwifi_parse_single_response_buf(priv, &bss_info, + &bytes_left, + le64_to_cpu(fw_tsf), + radio_type, false, 0); + if (ret) + goto check_next_scan; + } + +check_next_scan: + nxpwifi_check_next_scan_command(priv); + return ret; +} + +/* This function prepares an extended scan command to be sent to the firmware + * + * This uses the scan command configuration sent to the command processing + * module in command preparation stage to configure a extended scan command + * structure to send to firmware. + */ +int nxpwifi_cmd_802_11_scan_ext(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_scan_ext *ext_scan = &cmd->params.ext_scan; + struct nxpwifi_scan_cmd_config *scan_cfg = data_buf; + + memcpy(ext_scan->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); + + cmd->command = cpu_to_le16(HOST_CMD_802_11_SCAN_EXT); + + /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ + cmd->size = cpu_to_le16((u16)(sizeof(ext_scan->reserved) + + scan_cfg->tlv_buf_len + S_DS_GEN)); + + return 0; +} + +/* This function prepares an background scan config command to be sent + * to the firmware + */ +int nxpwifi_cmd_802_11_bg_scan_config(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_bg_scan_config *bgscan_config = + &cmd->params.bg_scan_config; + struct nxpwifi_bg_scan_cfg *bgscan_cfg_in = data_buf; + u8 *tlv_pos = bgscan_config->tlv; + u8 num_probes; + u32 ssid_len, chan_idx, scan_time, scan_type, scan_dur, chan_num; + int i; + struct nxpwifi_ie_types_num_probes *num_probes_tlv; + struct nxpwifi_ie_types_repeat_count *repeat_count_tlv; + struct nxpwifi_ie_types_min_rssi_threshold *rssi_threshold_tlv; + struct nxpwifi_ie_types_bgscan_start_later *start_later_tlv; + struct nxpwifi_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; + struct nxpwifi_ie_types_chan_list_param_set *tlv_l; + struct nxpwifi_chan_scan_param_set *temp_chan; + + cmd->command = cpu_to_le16(HOST_CMD_802_11_BG_SCAN_CONFIG); + cmd->size = cpu_to_le16(sizeof(*bgscan_config) + S_DS_GEN); + + bgscan_config->action = cpu_to_le16(bgscan_cfg_in->action); + bgscan_config->enable = bgscan_cfg_in->enable; + bgscan_config->bss_type = bgscan_cfg_in->bss_type; + bgscan_config->scan_interval = + cpu_to_le32(bgscan_cfg_in->scan_interval); + bgscan_config->report_condition = + cpu_to_le32(bgscan_cfg_in->report_condition); + + /* stop sched scan */ + if (!bgscan_config->enable) + return 0; + + bgscan_config->chan_per_scan = bgscan_cfg_in->chan_per_scan; + + num_probes = (bgscan_cfg_in->num_probes ? + bgscan_cfg_in->num_probes : priv->adapter->scan_probes); + + if (num_probes) { + num_probes_tlv = (struct nxpwifi_ie_types_num_probes *)tlv_pos; + num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); + num_probes_tlv->header.len = + cpu_to_le16(sizeof(num_probes_tlv->num_probes)); + num_probes_tlv->num_probes = cpu_to_le16((u16)num_probes); + + tlv_pos += sizeof(num_probes_tlv->header) + + le16_to_cpu(num_probes_tlv->header.len); + } + + if (bgscan_cfg_in->repeat_count) { + repeat_count_tlv = + (struct nxpwifi_ie_types_repeat_count *)tlv_pos; + repeat_count_tlv->header.type = + cpu_to_le16(TLV_TYPE_REPEAT_COUNT); + repeat_count_tlv->header.len = + cpu_to_le16(sizeof(repeat_count_tlv->repeat_count)); + repeat_count_tlv->repeat_count = + cpu_to_le16(bgscan_cfg_in->repeat_count); + + tlv_pos += sizeof(repeat_count_tlv->header) + + le16_to_cpu(repeat_count_tlv->header.len); + } + + if (bgscan_cfg_in->rssi_threshold) { + rssi_threshold_tlv = + (struct nxpwifi_ie_types_min_rssi_threshold *)tlv_pos; + rssi_threshold_tlv->header.type = + cpu_to_le16(TLV_TYPE_RSSI_LOW); + rssi_threshold_tlv->header.len = + cpu_to_le16(sizeof(rssi_threshold_tlv->rssi_threshold)); + rssi_threshold_tlv->rssi_threshold = + cpu_to_le16(bgscan_cfg_in->rssi_threshold); + + tlv_pos += sizeof(rssi_threshold_tlv->header) + + le16_to_cpu(rssi_threshold_tlv->header.len); + } + + for (i = 0; i < bgscan_cfg_in->num_ssids; i++) { + ssid_len = bgscan_cfg_in->ssid_list[i].ssid.ssid_len; + + wildcard_ssid_tlv = + (struct nxpwifi_ie_types_wildcard_ssid_params *)tlv_pos; + wildcard_ssid_tlv->header.type = + cpu_to_le16(TLV_TYPE_WILDCARDSSID); + wildcard_ssid_tlv->header.len = + cpu_to_le16((u16)(ssid_len + sizeof(u8))); + + /* max_ssid_length = 0 tells firmware to perform + * specific scan for the SSID filled, whereas + * max_ssid_length = IEEE80211_MAX_SSID_LEN is for + * wildcard scan. + */ + if (ssid_len) + wildcard_ssid_tlv->max_ssid_length = 0; + else + wildcard_ssid_tlv->max_ssid_length = + IEEE80211_MAX_SSID_LEN; + + memcpy(wildcard_ssid_tlv->ssid, + bgscan_cfg_in->ssid_list[i].ssid.ssid, ssid_len); + + tlv_pos += (sizeof(wildcard_ssid_tlv->header) + + le16_to_cpu(wildcard_ssid_tlv->header.len)); + } + + tlv_l = (struct nxpwifi_ie_types_chan_list_param_set *)tlv_pos; + + if (bgscan_cfg_in->chan_list[0].chan_number) { + dev_dbg(priv->adapter->dev, "info: bgscan: Using supplied channel list\n"); + + tlv_l->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + + for (chan_idx = 0; + chan_idx < NXPWIFI_BG_SCAN_CHAN_MAX && + bgscan_cfg_in->chan_list[chan_idx].chan_number; + chan_idx++) { + temp_chan = &tlv_l->chan_scan_param[chan_idx]; + + /* Increment the TLV header length by size appended */ + le16_unaligned_add_cpu(&tlv_l->header.len, + sizeof(*tlv_l->chan_scan_param)); + + temp_chan->chan_number = + bgscan_cfg_in->chan_list[chan_idx].chan_number; + temp_chan->radio_type = + bgscan_cfg_in->chan_list[chan_idx].radio_type; + + scan_type = + bgscan_cfg_in->chan_list[chan_idx].scan_type; + + if (scan_type == NXPWIFI_SCAN_TYPE_PASSIVE) + temp_chan->chan_scan_mode_bmap |= + NXPWIFI_PASSIVE_SCAN; + else + temp_chan->chan_scan_mode_bmap &= + ~NXPWIFI_PASSIVE_SCAN; + + scan_time = bgscan_cfg_in->chan_list[chan_idx].scan_time; + + if (scan_time) { + scan_dur = (u16)scan_time; + } else { + scan_dur = (scan_type == + NXPWIFI_SCAN_TYPE_PASSIVE) ? + priv->adapter->passive_scan_time : + priv->adapter->specific_scan_time; + } + + temp_chan->min_scan_time = cpu_to_le16(scan_dur); + temp_chan->max_scan_time = cpu_to_le16(scan_dur); + } + } else { + dev_dbg(priv->adapter->dev, + "info: bgscan: Creating full region channel list\n"); + chan_num = + nxpwifi_bgscan_create_channel_list + (priv, bgscan_cfg_in, + tlv_l->chan_scan_param); + le16_unaligned_add_cpu(&tlv_l->header.len, + chan_num * + sizeof(*tlv_l->chan_scan_param)); + } + + tlv_pos += (sizeof(tlv_l->header) + + le16_to_cpu(tlv_l->header.len)); + + if (bgscan_cfg_in->start_later) { + start_later_tlv = + (struct nxpwifi_ie_types_bgscan_start_later *)tlv_pos; + start_later_tlv->header.type = + cpu_to_le16(TLV_TYPE_BGSCAN_START_LATER); + start_later_tlv->header.len = + cpu_to_le16(sizeof(start_later_tlv->start_later)); + start_later_tlv->start_later = + cpu_to_le16(bgscan_cfg_in->start_later); + + tlv_pos += sizeof(start_later_tlv->header) + + le16_to_cpu(start_later_tlv->header.len); + } + + /* Append vendor specific IE TLV */ + nxpwifi_cmd_append_vsie_tlv(priv, NXPWIFI_VSIE_MASK_BGSCAN, &tlv_pos); + + le16_unaligned_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv); + + return 0; +} + +int nxpwifi_stop_bg_scan(struct nxpwifi_private *priv) +{ + struct nxpwifi_bg_scan_cfg *bgscan_cfg; + int ret; + + if (!priv->sched_scanning) { + dev_dbg(priv->adapter->dev, "bgscan already stopped!\n"); + return 0; + } + + bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL); + if (!bgscan_cfg) + return -ENOMEM; + + bgscan_cfg->bss_type = NXPWIFI_BSS_MODE_INFRA; + bgscan_cfg->action = NXPWIFI_BGSCAN_ACT_SET; + bgscan_cfg->enable = false; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_BG_SCAN_CONFIG, + HOST_ACT_GEN_SET, 0, bgscan_cfg, true); + if (!ret) + priv->sched_scanning = false; + + kfree(bgscan_cfg); + return ret; +} + +static void +nxpwifi_update_chan_statistics(struct nxpwifi_private *priv, + struct nxpwifi_ietypes_chanstats *tlv_stat) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + u8 i, num_chan; + struct nxpwifi_fw_chan_stats *fw_chan_stats; + struct nxpwifi_chan_stats chan_stats; + + fw_chan_stats = (void *)((u8 *)tlv_stat + + sizeof(struct nxpwifi_ie_types_header)); + num_chan = le16_to_cpu(tlv_stat->header.len) / + sizeof(struct nxpwifi_chan_stats); + + for (i = 0 ; i < num_chan; i++) { + if (adapter->survey_idx >= adapter->num_in_chan_stats) { + nxpwifi_dbg(adapter, WARN, + "FW reported too many channel results (max %d)\n", + adapter->num_in_chan_stats); + return; + } + chan_stats.chan_num = fw_chan_stats->chan_num; + chan_stats.bandcfg = fw_chan_stats->bandcfg; + chan_stats.flags = fw_chan_stats->flags; + chan_stats.noise = fw_chan_stats->noise; + chan_stats.total_bss = le16_to_cpu(fw_chan_stats->total_bss); + chan_stats.cca_scan_dur = + le16_to_cpu(fw_chan_stats->cca_scan_dur); + chan_stats.cca_busy_dur = + le16_to_cpu(fw_chan_stats->cca_busy_dur); + nxpwifi_dbg(adapter, INFO, + "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n", + chan_stats.chan_num, + chan_stats.noise, + chan_stats.total_bss, + chan_stats.cca_scan_dur, + chan_stats.cca_busy_dur); + memcpy(&adapter->chan_stats[adapter->survey_idx++], &chan_stats, + sizeof(struct nxpwifi_chan_stats)); + fw_chan_stats++; + } +} + +/* This function handles the command response of extended scan */ +int nxpwifi_ret_802_11_scan_ext(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_scan_ext *ext_scan_resp; + struct nxpwifi_ie_types_header *tlv; + struct nxpwifi_ietypes_chanstats *tlv_stat; + u16 buf_left, type, len; + + struct host_cmd_ds_command *cmd_ptr; + struct cmd_ctrl_node *cmd_node; + bool complete_scan = false; + + nxpwifi_dbg(adapter, INFO, "info: EXT scan returns successfully\n"); + + ext_scan_resp = &resp->params.ext_scan; + + tlv = (void *)ext_scan_resp->tlv_buffer; + buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN + - 1); + + while (buf_left >= sizeof(struct nxpwifi_ie_types_header)) { + type = le16_to_cpu(tlv->type); + len = le16_to_cpu(tlv->len); + + if (buf_left < (sizeof(struct nxpwifi_ie_types_header) + len)) { + nxpwifi_dbg(adapter, ERROR, + "error processing scan response TLVs"); + break; + } + + switch (type) { + case TLV_TYPE_CHANNEL_STATS: + tlv_stat = (void *)tlv; + nxpwifi_update_chan_statistics(priv, tlv_stat); + break; + default: + break; + } + + buf_left -= len + sizeof(struct nxpwifi_ie_types_header); + tlv = (void *)((u8 *)tlv + len + + sizeof(struct nxpwifi_ie_types_header)); + } + + spin_lock_bh(&adapter->cmd_pending_q_lock); + spin_lock_bh(&adapter->scan_pending_q_lock); + if (list_empty(&adapter->scan_pending_q)) { + complete_scan = true; + list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) { + cmd_ptr = (void *)cmd_node->cmd_skb->data; + if (le16_to_cpu(cmd_ptr->command) == + HOST_CMD_802_11_SCAN_EXT) { + nxpwifi_dbg(adapter, INFO, + "Scan pending in command pending list"); + complete_scan = false; + break; + } + } + } + spin_unlock_bh(&adapter->scan_pending_q_lock); + spin_unlock_bh(&adapter->cmd_pending_q_lock); + + if (complete_scan) + nxpwifi_complete_scan(priv); + + return 0; +} + +/* This function This function handles the event extended scan report. It + * parses extended scan results and informs to cfg80211 stack. + */ +int nxpwifi_handle_event_ext_scan_report(struct nxpwifi_private *priv, + void *buf) +{ + int ret = 0; + struct nxpwifi_adapter *adapter = priv->adapter; + u8 *bss_info; + u32 bytes_left, bytes_left_for_tlv, idx; + u16 type, len; + struct nxpwifi_ie_types_data *tlv; + struct nxpwifi_ie_types_bss_scan_rsp *scan_rsp_tlv; + struct nxpwifi_ie_types_bss_scan_info *scan_info_tlv; + u8 *radio_type; + u64 fw_tsf = 0; + s32 rssi = 0; + struct nxpwifi_event_scan_result *event_scan = buf; + u8 num_of_set = event_scan->num_of_set; + u8 *scan_resp = buf + sizeof(struct nxpwifi_event_scan_result); + u16 scan_resp_size = le16_to_cpu(event_scan->buf_size); + + if (num_of_set > NXPWIFI_MAX_AP) { + nxpwifi_dbg(adapter, ERROR, + "EXT_SCAN: Invalid number of AP returned (%d)!!\n", + num_of_set); + ret = -EINVAL; + goto check_next_scan; + } + + bytes_left = scan_resp_size; + nxpwifi_dbg(adapter, INFO, + "EXT_SCAN: size %d, returned %d APs...", + scan_resp_size, num_of_set); + nxpwifi_dbg_dump(adapter, CMD_D, "EXT_SCAN buffer:", buf, + scan_resp_size + + sizeof(struct nxpwifi_event_scan_result)); + + tlv = (struct nxpwifi_ie_types_data *)scan_resp; + + for (idx = 0; idx < num_of_set && bytes_left; idx++) { + type = le16_to_cpu(tlv->header.type); + len = le16_to_cpu(tlv->header.len); + if (bytes_left < sizeof(struct nxpwifi_ie_types_header) + len) { + nxpwifi_dbg(adapter, ERROR, + "EXT_SCAN: Error bytes left < TLV length\n"); + break; + } + scan_rsp_tlv = NULL; + scan_info_tlv = NULL; + bytes_left_for_tlv = bytes_left; + + /* BSS response TLV with beacon or probe response buffer + * at the initial position of each descriptor + */ + if (type != TLV_TYPE_BSS_SCAN_RSP) + break; + + bss_info = (u8 *)tlv; + scan_rsp_tlv = (struct nxpwifi_ie_types_bss_scan_rsp *)tlv; + tlv = (struct nxpwifi_ie_types_data *)(tlv->data + len); + bytes_left_for_tlv -= + (len + sizeof(struct nxpwifi_ie_types_header)); + + while (bytes_left_for_tlv >= + sizeof(struct nxpwifi_ie_types_header) && + le16_to_cpu(tlv->header.type) != TLV_TYPE_BSS_SCAN_RSP) { + type = le16_to_cpu(tlv->header.type); + len = le16_to_cpu(tlv->header.len); + if (bytes_left_for_tlv < + sizeof(struct nxpwifi_ie_types_header) + len) { + nxpwifi_dbg(adapter, ERROR, + "EXT_SCAN: Error in processing TLV,\t" + "bytes left < TLV length\n"); + scan_rsp_tlv = NULL; + bytes_left_for_tlv = 0; + continue; + } + switch (type) { + case TLV_TYPE_BSS_SCAN_INFO: + scan_info_tlv = + (struct nxpwifi_ie_types_bss_scan_info *)tlv; + if (len != + sizeof(struct nxpwifi_ie_types_bss_scan_info) - + sizeof(struct nxpwifi_ie_types_header)) { + bytes_left_for_tlv = 0; + continue; + } + break; + default: + break; + } + tlv = (struct nxpwifi_ie_types_data *)(tlv->data + len); + bytes_left -= + (len + sizeof(struct nxpwifi_ie_types_header)); + bytes_left_for_tlv -= + (len + sizeof(struct nxpwifi_ie_types_header)); + } + + if (!scan_rsp_tlv) + break; + + /* Advance pointer to the beacon buffer length and + * update the bytes count so that the function + * wlan_interpret_bss_desc_with_ie() can handle the + * scan buffer withut any change + */ + bss_info += sizeof(u16); + bytes_left -= sizeof(u16); + + if (scan_info_tlv) { + rssi = (s32)(s16)(le16_to_cpu(scan_info_tlv->rssi)); + rssi *= 100; /* Convert dBm to mBm */ + nxpwifi_dbg(adapter, INFO, + "info: InterpretIE: RSSI=%d\n", rssi); + fw_tsf = le64_to_cpu(scan_info_tlv->tsf); + radio_type = &scan_info_tlv->radio_type; + } else { + radio_type = NULL; + } + ret = nxpwifi_parse_single_response_buf(priv, &bss_info, + &bytes_left, fw_tsf, + radio_type, true, rssi); + if (ret) + goto check_next_scan; + } + +check_next_scan: + if (!event_scan->more_event) + nxpwifi_check_next_scan_command(priv); + + return ret; +} + +/* This function prepares command for background scan query. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting background scan flush parameter + * - Ensuring correct endian-ness + */ +int nxpwifi_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd) +{ + struct host_cmd_ds_802_11_bg_scan_query *bg_query = + &cmd->params.bg_scan_query; + + cmd->command = cpu_to_le16(HOST_CMD_802_11_BG_SCAN_QUERY); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query) + + S_DS_GEN); + + bg_query->flush = 1; + + return 0; +} + +/* This function inserts scan command node to the scan pending queue. + */ +void +nxpwifi_queue_scan_cmd(struct nxpwifi_private *priv, + struct cmd_ctrl_node *cmd_node) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + + cmd_node->wait_q_enabled = true; + cmd_node->condition = &adapter->scan_wait_q_woken; + spin_lock_bh(&adapter->scan_pending_q_lock); + list_add_tail(&cmd_node->list, &adapter->scan_pending_q); + spin_unlock_bh(&adapter->scan_pending_q_lock); +} + +/* This function appends the vendor specific IE TLV to a buffer. + */ +int +nxpwifi_cmd_append_vsie_tlv(struct nxpwifi_private *priv, + u16 vsie_mask, u8 **buffer) +{ + int id, ret_len = 0; + struct nxpwifi_ie_types_vendor_param_set *vs_param_set; + + if (!buffer) + return 0; + if (!(*buffer)) + return 0; + + /* Traverse through the saved vendor specific IE array and append + * the selected(scan/assoc) IE as TLV to the command + */ + for (id = 0; id < NXPWIFI_MAX_VSIE_NUM; id++) { + if (priv->vs_ie[id].mask & vsie_mask) { + vs_param_set = + (struct nxpwifi_ie_types_vendor_param_set *) + *buffer; + vs_param_set->header.type = + cpu_to_le16(TLV_TYPE_PASSTHROUGH); + vs_param_set->header.len = + cpu_to_le16((((u16)priv->vs_ie[id].ie[1]) + & 0x00FF) + 2); + if (le16_to_cpu(vs_param_set->header.len) > + NXPWIFI_MAX_VSIE_LEN) { + nxpwifi_dbg(priv->adapter, ERROR, + "Invalid param length!\n"); + break; + } + + memcpy(vs_param_set->ie, priv->vs_ie[id].ie, + le16_to_cpu(vs_param_set->header.len)); + *buffer += le16_to_cpu(vs_param_set->header.len) + + sizeof(struct nxpwifi_ie_types_header); + ret_len += le16_to_cpu(vs_param_set->header.len) + + sizeof(struct nxpwifi_ie_types_header); + } + } + return ret_len; +} + +/* This function saves a beacon buffer of the current BSS descriptor. + * + * The current beacon buffer is saved so that it can be restored in the + * following cases that makes the beacon buffer not to contain the current + * ssid's beacon buffer. + * - The current ssid was not found somehow in the last scan. + * - The current ssid was the last entry of the scan table and overloaded. + */ +void +nxpwifi_save_curr_bcn(struct nxpwifi_private *priv) +{ + struct nxpwifi_bssdescriptor *curr_bss = + &priv->curr_bss_params.bss_descriptor; + + if (!curr_bss->beacon_buf_size) + return; + + /* allocate beacon buffer at 1st time; or if it's size has changed */ + if (!priv->curr_bcn_buf || + priv->curr_bcn_size != curr_bss->beacon_buf_size) { + priv->curr_bcn_size = curr_bss->beacon_buf_size; + + kfree(priv->curr_bcn_buf); + priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size, + GFP_ATOMIC); + if (!priv->curr_bcn_buf) + return; + } + + memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, + curr_bss->beacon_buf_size); + nxpwifi_dbg(priv->adapter, INFO, + "info: current beacon saved %d\n", + priv->curr_bcn_size); + + curr_bss->beacon_buf = priv->curr_bcn_buf; + + /* adjust the pointers in the current BSS descriptor */ + if (curr_bss->bcn_wpa_ie) + curr_bss->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (curr_bss->beacon_buf + + curr_bss->wpa_offset); + + if (curr_bss->bcn_rsn_ie) + curr_bss->bcn_rsn_ie = + (struct element *)(curr_bss->beacon_buf + + curr_bss->rsn_offset); + + if (curr_bss->bcn_ht_cap) + curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) + (curr_bss->beacon_buf + + curr_bss->ht_cap_offset); + + if (curr_bss->bcn_ht_oper) + curr_bss->bcn_ht_oper = (struct ieee80211_ht_operation *) + (curr_bss->beacon_buf + + curr_bss->ht_info_offset); + + if (curr_bss->bcn_vht_cap) + curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf + + curr_bss->vht_cap_offset); + + if (curr_bss->bcn_vht_oper) + curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf + + curr_bss->vht_info_offset); + + if (curr_bss->bcn_bss_co_2040) + curr_bss->bcn_bss_co_2040 = + (curr_bss->beacon_buf + curr_bss->bss_co_2040_offset); + + if (curr_bss->bcn_ext_cap) + curr_bss->bcn_ext_cap = curr_bss->beacon_buf + + curr_bss->ext_cap_offset; + + if (curr_bss->oper_mode) + curr_bss->oper_mode = (void *)(curr_bss->beacon_buf + + curr_bss->oper_mode_offset); +} + +/* This function frees the current BSS descriptor beacon buffer. + */ +void +nxpwifi_free_curr_bcn(struct nxpwifi_private *priv) +{ + kfree(priv->curr_bcn_buf); + priv->curr_bcn_buf = NULL; +} From patchwork Fri Aug 9 09:45:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818386 Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11012065.outbound.protection.outlook.com [52.101.66.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A08419925A; Fri, 9 Aug 2024 09:47:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.66.65 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196851; cv=fail; b=kWzc0hL9VXBOBJypk3FOOuR67+4WYFWVGueSlCV3VY9jylospMLlXVtBhaJ69UPXs/hJXGKwl2qiNLHpx5a3Ysu1FYn0GDCR4ZVKbU++ElQrojQtS8h+JuvxD3EW9MzMyML3LCm7Wk9cuD/ynozyo35FtO+PoI0l9+EhXiYBmlo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196851; c=relaxed/simple; bh=nq9Sc81f10bkSfDZ58iCByMCvtTlYprErYi1ww86wE8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=MElrpND7nmANHbwA/dQ66oo8MZmc4vhJyTI8ye2yPIRpmSMY3ltEU4FQD9Xl+vZl7X8IdpXeGwH1VNHnI0zc/6Y3t3nbJ/vHIOMugOS07W+Ca5A5zNM+AAQtCQP9q2LYfo9OA6YJXEjp2uB0OTYzqjH2LvKjqkfc1Ms8H7jIuIE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=mljDJDls; arc=fail smtp.client-ip=52.101.66.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="mljDJDls" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=LL4+RmJYMkpLqQrcc38XnTy8LZB4kh2PnFHt4ocsmM8SUvldax6S+fHrzaT5G+qkXYkrEFTq4j3PbeplAfF3I9CUCFUCMKHbFH9HVFgfO/fwOJ2tnR75OMEKzFpl5TwAHW0v8lM7go+Xp/hBK/4EDJHnu/A0eWrRwu3QTZVgDtsc+S6ncUhfRb8MhbQRDbzy56uWLmAkHxGtghg5pgZcCTz3UsqJxFEvaL0QpCSEH/BFVG3EcL4RQRo5IZrg9p9nPaPakRBw31Nqyt9FvBmfombqwNNtSquLeXBPI6wM+uus9C8TqxOZmfbbTmmm/XjaQ831GalSW1bevs8QH7vbWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=nw3MO4WDySgZxM8eqJR4mSnIZaDWuxgOFKERpZo1CMQ=; b=Vle2Q76/NrP1vJ5UgKbOMW/tEEHpLyXH1zNuh04cHVI3Nl5PVHr172IxFtMhPhgp03eHjuIR2nelO9wGpCyWCsQUgDhAgsvgqixyqh8WJZAU09WJi5cmnlgX9bfO2CQrQUraNu03rmSLTyB4Kft6d1EXabnjzhlgnAtDc6d6vozdJU7+qnSMGlltylvWPp2wKdFp3IBlvrFjquVBa7Hk/6xiUamar4Nf1626Bg29dc2yOLAwHh3vx+pBE6mvJmuMLPhlcK8zskQ37l3tC1AXB1GIkWhngAd2t+tEdvWPz/D5OOjYGJPU/p6r7HlIqR9RSKePod5k+uuhULHiUj8Nug== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=nw3MO4WDySgZxM8eqJR4mSnIZaDWuxgOFKERpZo1CMQ=; b=mljDJDlsGBMGC8Oy81UGNPuEy/8Ox7xdvIaaXndbNZqG9LdT0T+9zU7/LOEaN55YeWifuv/77UJQICmJnrcPKo5HXrV1vBZJYTv2Tz+IEkC8lJqz17xqcg3VVpoLG6gOOvGmZtSvNhBtv+KHHQX+UBhD5ZfeJrL2k5umb+RZCrsKJrh2kGnO2N0XHXWfXRvoYKB1pAyxMX0SPxVJvPl1RY6ne/cBMWs1WS7o2GYV+CxhPQFgVCzA5KbaTbwWR+m4UXoBSWs5Ff886kQQmO3stQVzyNZkw73zU/1WPkPyjUYJ5JRHS1pKP7SkIWQMy+e1GS42lxSkO43U9OAszzgPDA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:47:16 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:47:16 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 26/43] wifi: nxpwifi: add sdio.c Date: Fri, 9 Aug 2024 17:45:16 +0800 Message-Id: <20240809094533.1660-27-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: 2da3a220-56f8-40e5-750d-08dcb85840df X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: hn5oThla6Fhqvfqvsez6jS0Ny6tEhn3PLcGs2URo23vR6HjRICdgAGBxf/6YaTcn5r3IQGVjixzlZsF9CyaYz9FL5Z8+qtXvMHLMLq5uGiY4tfdbxo3jXEpT0wsyxUSX61+8wHJQSYP5ZjGubwcAkFmFrW1Hvw3UopAyeFntswxSnsp1CJQN3q9L3In0SxqKqQodKPxNn9TMYMiV+1fakeccbgFO3H9JArTAmeV0o+zDwXyrFGzB66ZPuiLV9ssiLVZ3qAf8YBAWyita3+5B+ePBJigWOu0wlboN6+k0BAURe9akfzTxZPWXiGaXb5W6QvzhxSpi63bpOhV+nHQr2vbvFhcWUdlhGArUdXFLig8JO7OF81s+XxwMHK2I/Que26yBeUf0h09OjqoKtZPp0WBQIYCMS1Fbdrp4lvV5ofva4lC0c9G5JeZZj8iJH9d0h50WGlO1DzeWQnGGRz5ICUA16IGijnpneNigus3p8Jeoa3C6s/BEx6CoxWnGg5dBkRAFZUXeP7uKnJ0FpqdngqLBL5Oz1kby4pZaSSe0FCiIXZiE5LJ+ootPKjJW89WACRZfxZJVqHnkuiiTYGnOt4KrJikguOmyt6Y3vlpf3Oz1qvc5OSqZowmC9epL0KUKTureiv942Ip867RBDYGzvtbVwHpPJMjHJzE56d+8Lje2rO9HZs3qgn8T8PhHtL6y4uq3aHRQetYqXMBi6nqU7Foo1EC0lK3s4734TM/mF14mz1IsjAmMDcBms31fNW+D9mJV+X85Awj8hsyXTBqS4bZ/3KGmPQ5b1Lu7KqKo3CFE7ve5ciGKMkxrpwkCxAelS6icTYpkDkblS6ZzOH2W/Pr/3AyFt2e7II0nxcT6UGCdwCg1UHkxl6kprVckcOUnyQNlf3hhnG3Ux7tEDjZUDRV1vG6JtXCdicKAlhP3O/i23wccwp/Pe04mB5hwd1ktPuFp1uVO5xJdS2bAQWmto09qlAQaRkU7RDL+3S6QZCMfXIcziQas1HgUcwiXnnH4bAYleKcHZYtb9Anll0MS+CNwB78iS9kYNNBLnO0aFmDQTOfeF9YJZQ00YS+LHs5DfbK5P8ICTqgRso8/QwSdBH8eWrwIrNOVYk3Fj3uI9DPvxpc1le5IC2VQe803XBjZnnPDsd6ivjt1WkOsRjSLMlrfbt570IFrXBuzsm4XvK0p8GHzw/cFIahgEgbT42CV/a0lxyuM1Wdge8ulfrv32m8s3XXAJNjBDTPwbb6PMN7Nr08DHsjbWX5DOuApil+hbhmIGCazkXeRVwIzH8ob0wUHPrGW42AEUfR1EEJYWWcfCLZMtxU7MJEa3mhLbKn8xArguJD3YM7u+4EVo2qWMw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: vJED5H/nYq2ZJ+eto8tUKIDIrxX0EZ/E7pG6ti7uz5OjdosiL/15tvzbgA/9V5b+1t0ntudySIHm1spiSj9HACG/eL3H74PyzKg/8ScAyiqKh0+MN4YU3w1nVTGz8j59z+INZ8Ymkrj19pJ2/w9qNIDVt/FEyw1rmV7UzgC/FpCH53HCNCG0OVrHle0RgA3tjL4/u1FZMiIW9ff8PH7Xdk0kz0jb1pas4q3/7MVut5kiXhwGaXj9KQOILe2A3yQE5H+n4l4mGp5tu9XdWQrgWeMRqsUuDCB3TTVj7tJVCoEHk3Gd91pBIXN9NWu/IVOHjz/OsCVshvLWa9l/yIFlEhvz078/1o1PR+HFbroRCu9Q5HjuaqykWcirzNuQVz7APKPjNvqY0fwMC3odjsaswEHLgHRVrLJBkodNjtZDJwXZVHnCQHvP5/dWEKCNgyADDMrk7WwqCwYp0fORDHV9smVoWvcDsuLBOmlw5GRW9pNdvBpy+OcNCx+8mbtgSmFGhwUASFRQvmwUAA7vBq289PKYeuCe1aXoz2iDcVdwDJOvG/+NiorVXV+4tImyerFyf9Us+GZARZBYrFkTOK1mZyXItVdUJ8eUoN29/qYfgPw/BOrfkPwQGBIaQnmF1Xmj08Kk09e/sgv+Chq980auwn/PDI+PeFNqBD2IHY3DCyLYTeWGDi24HtIW7myyViPeEVRutbAPChizzRVskvmXpcHzOFs3Uv7kSMsPx3a5RiMM0aBJrhxlX6zptbSQZ7HydbPgZjF0J8xLfSG8LEyLnqjSI/QN0N8DvF8I/gq5tGWPtrqUJa1dW6vi0OJRKIL0g4uFhC/NNs6MZF6y/UuJr+gzqFH/8MyWXoka68/+pFh+WzmNYhTPhX5digLqjat+7h7di/pI1kHckQRkSeogadiZAD4pHIBW9anBgMzBPjYlvu4TtQmeO2dJ2HKS6S8Y8iPQ3Gmxq/EEN+R27dB0nqSkQO0Jg7PDJb0gBh06fdNYNliPa983UF/yz3r24Kzf1dtVIzwNtHFjSbvxZyHvpWMbY89gSFK9DWIsSxyVF/1rwse62MGbbGF++KMPkcTJbg1vRAOMtaLL/PFojTH1gXfA9yr88VcypzJvQ6GeILbSniwVrCGndfE3SLhI4p+GKz0uFKX6T4KDa99M4zPe0PSzCnGUrZ7LqQMlZXMfqt0QRkpf7BTm8NxBPPGlPVAwwsL+7K92OWMOiiFB2wKWNRLchUC49cf4gfyj0kpgVuBktGgH8Q178kPnyN2iiUQv+avMzixmzoSxsdYeMwl4UmJIsX6h/V/5jPoYaZkDdDjYTNjaALmu+TkaN8sZeKYgQ4TeERIh4C7xF+P1BDFlNOqf22pIKhH2puyceoDqWK6+ss2+FDc0YP755JiEVNojbLudEUhcBd4V6+MYd7ixh5qGbhgXtyATciW3vkVS/BGDUTmU32eNzTw+wMGfqwRA+qKVUB93MvWqPtRm94wBGPiA613cTJDHkHbbBrxurjRpswZciAmxdfjmgJoElTrKAsSDHlpOHDszhI4KtQf6RF+C77ANHiv0pinOd7CKAeeeQB3SIYafKvecEHYgOE30UWO63ciY3DdAtKpcVhYbgRHroy7bRXe3c6b+sHk6SRmU2XGPJ7StrCOJLvVmISiQ X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 2da3a220-56f8-40e5-750d-08dcb85840df X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:47:16.8139 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: SsAn9NIYv6FEtY5SmHJ+gdFS4oLFofudIntHHyHb5wqexs2ruchOx+kYNNjl6toxZeYp9wiwuoINJzOl0R7sNw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/sdio.c | 2648 +++++++++++++++++++++++ 1 file changed, 2648 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/sdio.c diff --git a/drivers/net/wireless/nxp/nxpwifi/sdio.c b/drivers/net/wireless/nxp/nxpwifi/sdio.c new file mode 100644 index 000000000000..9bc6338c95ec --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/sdio.c @@ -0,0 +1,2648 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: SDIO specific handling + * + * Copyright 2011-2024 NXP + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "sdio.h" + +#define SDIO_VERSION "1.0" + +static void nxpwifi_sdio_work(struct work_struct *work); + +static struct nxpwifi_if_ops sdio_ops; + +static const struct nxpwifi_sdio_card_reg nxpwifi_reg_iw61x = { + .start_rd_port = 0, + .start_wr_port = 0, + .base_0_reg = 0xF8, + .base_1_reg = 0xF9, + .poll_reg = 0x5C, + .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | + CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK, + .host_int_rsr_reg = 0x4, + .host_int_status_reg = 0x0C, + .host_int_mask_reg = 0x08, + .host_strap_reg = 0xF4, + .host_strap_mask = 0x01, + .host_strap_value = 0x00, + .status_reg_0 = 0xE8, + .status_reg_1 = 0xE9, + .sdio_int_mask = 0xff, + .data_port_mask = 0xffffffff, + .io_port_0_reg = 0xE4, + .io_port_1_reg = 0xE5, + .io_port_2_reg = 0xE6, + .max_mp_regs = 196, + .rd_bitmap_l = 0x10, + .rd_bitmap_u = 0x11, + .rd_bitmap_1l = 0x12, + .rd_bitmap_1u = 0x13, + .wr_bitmap_l = 0x14, + .wr_bitmap_u = 0x15, + .wr_bitmap_1l = 0x16, + .wr_bitmap_1u = 0x17, + .rd_len_p0_l = 0x18, + .rd_len_p0_u = 0x19, + .card_misc_cfg_reg = 0xd8, + .card_cfg_2_1_reg = 0xd9, + .cmd_rd_len_0 = 0xc0, + .cmd_rd_len_1 = 0xc1, + .cmd_rd_len_2 = 0xc2, + .cmd_rd_len_3 = 0xc3, + .cmd_cfg_0 = 0xc4, + .cmd_cfg_1 = 0xc5, + .cmd_cfg_2 = 0xc6, + .cmd_cfg_3 = 0xc7, + .fw_dump_host_ready = 0xcc, + .fw_dump_ctrl = 0xf9, + .fw_dump_start = 0xf1, + .fw_dump_end = 0xf8, + .func1_dump_reg_start = 0x10, + .func1_dump_reg_end = 0x17, + .func1_scratch_reg = 0xE8, + .func1_spec_reg_num = 13, + .func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, + 0x61, 0x62, 0x64, 0x65, 0x66, + 0x68, 0x69, 0x6a}, +}; + +static const struct nxpwifi_sdio_device nxpwifi_sdio_iw61x = { + .firmware = IW61X_SDIO_FW_NAME, + .reg = &nxpwifi_reg_iw61x, + .max_ports = 32, + .mp_agg_pkt_limit = 16, + .tx_buf_size = NXPWIFI_TX_DATA_BUF_SIZE_4K, + .mp_tx_agg_buf_size = NXPWIFI_MP_AGGR_BSIZE_MAX, + .mp_rx_agg_buf_size = NXPWIFI_MP_AGGR_BSIZE_MAX, + .can_dump_fw = true, + .fw_dump_enh = true, + .can_ext_scan = true, +}; + +static struct memory_type_mapping generic_mem_type_map[] = { + {"DUMP", NULL, 0, 0xDD}, +}; + +static struct memory_type_mapping mem_type_mapping_tbl[] = { + {"ITCM", NULL, 0, 0xF0}, + {"DTCM", NULL, 0, 0xF1}, + {"SQRAM", NULL, 0, 0xF2}, + {"APU", NULL, 0, 0xF3}, + {"CIU", NULL, 0, 0xF4}, + {"ICU", NULL, 0, 0xF5}, + {"MAC", NULL, 0, 0xF6}, + {"EXT7", NULL, 0, 0xF7}, + {"EXT8", NULL, 0, 0xF8}, + {"EXT9", NULL, 0, 0xF9}, + {"EXT10", NULL, 0, 0xFA}, + {"EXT11", NULL, 0, 0xFB}, + {"EXT12", NULL, 0, 0xFC}, + {"EXT13", NULL, 0, 0xFD}, + {"EXTLAST", NULL, 0, 0xFE}, +}; + +static const struct of_device_id nxpwifi_sdio_of_match_table[] __maybe_unused = { + { .compatible = "nxp,iw61x" }, + { } +}; + +/* This function parse device tree node using mmc subnode devicetree API. + * The device node is saved in card->plt_of_node. + * if the device tree node exist and include interrupts attributes, this + * function will also request platform specific wakeup interrupt. + */ +static int nxpwifi_sdio_probe_of(struct device *dev) +{ + if (!of_match_node(nxpwifi_sdio_of_match_table, dev->of_node)) { + dev_err(dev, "required compatible string missing\n"); + return -EINVAL; + } + + return 0; +} + +/* SDIO probe. + * + * This function probes an nxpwifi device and registers it. It allocates + * the card structure, enables SDIO function number and initiates the + * device registration and initialization procedure by adding a logical + * interface. + */ +static int +nxpwifi_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret; + struct sdio_mmc_card *card = NULL; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", + func->vendor, func->device, func->class, func->num); + + card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + init_completion(&card->fw_done); + + card->func = func; + + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + + if (id->driver_data) { + struct nxpwifi_sdio_device *data = (void *)id->driver_data; + + card->firmware = data->firmware; + card->firmware_sdiouart = data->firmware_sdiouart; + card->reg = data->reg; + card->max_ports = data->max_ports; + card->mp_agg_pkt_limit = data->mp_agg_pkt_limit; + card->tx_buf_size = data->tx_buf_size; + card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; + card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; + card->can_dump_fw = data->can_dump_fw; + card->fw_dump_enh = data->fw_dump_enh; + card->can_ext_scan = data->can_ext_scan; + INIT_WORK(&card->work, nxpwifi_sdio_work); + } + + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + + if (ret) { + dev_err(&func->dev, "failed to enable function\n"); + return ret; + } + + /* device tree node parsing and platform specific configuration*/ + if (func->dev.of_node) { + ret = nxpwifi_sdio_probe_of(&func->dev); + if (ret) + goto err_disable; + } + + ret = nxpwifi_add_card(card, &card->fw_done, &sdio_ops, + NXPWIFI_SDIO, &func->dev); + if (ret) { + dev_err(&func->dev, "add card failed\n"); + goto err_disable; + } + + return 0; + +err_disable: + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + + return ret; +} + +/* SDIO resume. + * + * Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not resumed, this function turns on the traffic and + * sends a host sleep cancel request to the firmware. + */ +static int nxpwifi_sdio_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + struct nxpwifi_adapter *adapter; + + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + dev_err(dev, "resume: invalid card or adapter\n"); + return 0; + } + + adapter = card->adapter; + + if (!test_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags)) { + nxpwifi_dbg(adapter, WARN, + "device already resumed\n"); + return 0; + } + + clear_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags); + + /* Disable Host Sleep */ + nxpwifi_cancel_hs(nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA), + NXPWIFI_SYNC_CMD); + + nxpwifi_disable_wake(adapter); + + return 0; +} + +/* Write data into SDIO card register. Caller claims SDIO device. */ +static int +nxpwifi_write_reg_locked(struct sdio_func *func, u32 reg, u8 data) +{ + int ret; + + sdio_writeb(func, data, reg, &ret); + return ret; +} + +/* This function writes data into SDIO card register. + */ +static int +nxpwifi_write_reg(struct nxpwifi_adapter *adapter, u32 reg, u8 data) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + + sdio_claim_host(card->func); + ret = nxpwifi_write_reg_locked(card->func, reg, data); + sdio_release_host(card->func); + + return ret; +} + +/* This function reads data from SDIO card register. + */ +static int +nxpwifi_read_reg(struct nxpwifi_adapter *adapter, u32 reg, u8 *data) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + u8 val; + + sdio_claim_host(card->func); + val = sdio_readb(card->func, reg, &ret); + sdio_release_host(card->func); + + *data = val; + + return ret; +} + +/* This function writes multiple data into SDIO card memory. + * + * This does not work in suspended mode. + */ +static int +nxpwifi_write_data_sync(struct nxpwifi_adapter *adapter, + u8 *buffer, u32 pkt_len, u32 port) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + u8 blk_mode = + (port & NXPWIFI_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + u32 blk_size = (blk_mode == BLOCK_MODE) ? NXPWIFI_SDIO_BLOCK_SIZE : 1; + u32 blk_cnt = + (blk_mode == + BLOCK_MODE) ? (pkt_len / + NXPWIFI_SDIO_BLOCK_SIZE) : pkt_len; + u32 ioport = (port & NXPWIFI_SDIO_IO_PORT_MASK); + + if (test_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags)) { + nxpwifi_dbg(adapter, ERROR, + "%s: not allowed while suspended\n", __func__); + return -EPERM; + } + + sdio_claim_host(card->func); + + ret = sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size); + + sdio_release_host(card->func); + + return ret; +} + +/* This function reads multiple data from SDIO card memory. + */ +static int nxpwifi_read_data_sync(struct nxpwifi_adapter *adapter, u8 *buffer, + u32 len, u32 port, u8 claim) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + u8 blk_mode = (port & NXPWIFI_SDIO_BYTE_MODE_MASK) ? BYTE_MODE + : BLOCK_MODE; + u32 blk_size = (blk_mode == BLOCK_MODE) ? NXPWIFI_SDIO_BLOCK_SIZE : 1; + u32 blk_cnt = (blk_mode == BLOCK_MODE) ? (len / NXPWIFI_SDIO_BLOCK_SIZE) + : len; + u32 ioport = (port & NXPWIFI_SDIO_IO_PORT_MASK); + + if (claim) + sdio_claim_host(card->func); + + ret = sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size); + + if (claim) + sdio_release_host(card->func); + + return ret; +} + +/* This function reads the firmware status. + */ +static int +nxpwifi_sdio_read_fw_status(struct nxpwifi_adapter *adapter, u16 *dat) +{ + struct sdio_mmc_card *card = adapter->card; + const struct nxpwifi_sdio_card_reg *reg = card->reg; + u8 fws0, fws1; + int ret; + + ret = nxpwifi_read_reg(adapter, reg->status_reg_0, &fws0); + if (ret) + return ret; + + ret = nxpwifi_read_reg(adapter, reg->status_reg_1, &fws1); + if (ret) + return ret; + + *dat = (u16)((fws1 << 8) | fws0); + return ret; +} + +/* This function checks the firmware status in card. + */ +static int nxpwifi_check_fw_status(struct nxpwifi_adapter *adapter, + u32 poll_num) +{ + int ret = 0; + u16 firmware_stat = 0; + u32 tries; + + for (tries = 0; tries < poll_num; tries++) { + ret = nxpwifi_sdio_read_fw_status(adapter, &firmware_stat); + if (ret) + continue; + if (firmware_stat == FIRMWARE_READY_SDIO) { + ret = 0; + break; + } + + msleep(100); + ret = -EPERM; + } + + if (firmware_stat == FIRMWARE_READY_SDIO) + /* firmware might pretend to be ready, when it's not. + * Wait a little bit more as a workaround. + */ + msleep(100); + + return ret; +} + +/* This function checks if WLAN is the winner. + */ +static int nxpwifi_check_winner_status(struct nxpwifi_adapter *adapter) +{ + int ret; + u8 winner = 0; + struct sdio_mmc_card *card = adapter->card; + + ret = nxpwifi_read_reg(adapter, card->reg->status_reg_0, &winner); + if (ret) + return ret; + + if (winner) + adapter->winner = 0; + else + adapter->winner = 1; + + return ret; +} + +/* SDIO remove. + * + * This function removes the interface and frees up the card structure. + */ +static void +nxpwifi_sdio_remove(struct sdio_func *func) +{ + struct sdio_mmc_card *card; + struct nxpwifi_adapter *adapter; + struct nxpwifi_private *priv; + int ret = 0; + u16 firmware_stat; + + card = sdio_get_drvdata(func); + if (!card) + return; + + wait_for_completion(&card->fw_done); + + adapter = card->adapter; + if (!adapter || !adapter->priv_num) + return; + + nxpwifi_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num); + + ret = nxpwifi_sdio_read_fw_status(adapter, &firmware_stat); + if (!ret && firmware_stat == FIRMWARE_READY_SDIO) { + nxpwifi_deauthenticate_all(adapter); + + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY); + nxpwifi_disable_auto_ds(priv); + nxpwifi_init_shutdown_fw(priv, NXPWIFI_FUNC_SHUTDOWN); + } + + nxpwifi_remove_card(adapter); +} + +/* SDIO suspend. + * + * Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not suspended, this function allocates and sends a host + * sleep activate request to the firmware and turns off the traffic. + */ +static int nxpwifi_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + struct nxpwifi_adapter *adapter; + mmc_pm_flag_t pm_flag = 0; + int ret = 0; + + pm_flag = sdio_get_host_pm_caps(func); + pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", + sdio_func_id(func), pm_flag); + if (!(pm_flag & MMC_PM_KEEP_POWER)) { + dev_err(dev, + "%s: cannot remain alive while host is suspended\n", + sdio_func_id(func)); + return -EPERM; + } + + card = sdio_get_drvdata(func); + if (!card) { + dev_err(dev, "suspend: invalid card\n"); + return 0; + } + + /* Might still be loading firmware */ + wait_for_completion(&card->fw_done); + + adapter = card->adapter; + if (!adapter) { + dev_err(dev, "adapter is not valid\n"); + return 0; + } + + if (!adapter->is_up) + return -EBUSY; + + nxpwifi_enable_wake(adapter); + + /* Enable the Host Sleep */ + if (!nxpwifi_enable_hs(adapter)) { + nxpwifi_dbg(adapter, ERROR, + "cmd: failed to suspend\n"); + clear_bit(NXPWIFI_IS_HS_ENABLING, &adapter->work_flags); + nxpwifi_disable_wake(adapter); + return -EPERM; + } + + nxpwifi_dbg(adapter, INFO, + "cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + + /* Indicate device suspended */ + set_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags); + clear_bit(NXPWIFI_IS_HS_ENABLING, &adapter->work_flags); + + return ret; +} + +static void nxpwifi_sdio_coredump(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + + card = sdio_get_drvdata(func); + if (!test_and_set_bit(NXPWIFI_IFACE_WORK_DEVICE_DUMP, + &card->work_flags)) + nxpwifi_queue_work(card->adapter, &card->work); +} + +/* WLAN IDs */ +static const struct sdio_device_id nxpwifi_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_NXP, SDIO_DEVICE_ID_NXP_IW61X), + .driver_data = (unsigned long)&nxpwifi_sdio_iw61x}, + {}, +}; + +MODULE_DEVICE_TABLE(sdio, nxpwifi_ids); + +static const struct dev_pm_ops nxpwifi_sdio_pm_ops = { + .suspend = nxpwifi_sdio_suspend, + .resume = nxpwifi_sdio_resume, +}; + +static struct sdio_driver nxpwifi_sdio = { + .name = "nxpwifi_sdio", + .id_table = nxpwifi_ids, + .probe = nxpwifi_sdio_probe, + .remove = nxpwifi_sdio_remove, + .drv = { + .owner = THIS_MODULE, + .coredump = nxpwifi_sdio_coredump, + .pm = &nxpwifi_sdio_pm_ops, + } +}; + +/* This function wakes up the card. + * + * A host power up command is written to the card configuration + * register to wake up the card. + */ +static int nxpwifi_pm_wakeup_card(struct nxpwifi_adapter *adapter) +{ + nxpwifi_dbg(adapter, EVENT, + "event: wakeup device...\n"); + + return nxpwifi_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); +} + +/* This function is called after the card has woken up. + * + * The card configuration register is reset. + */ +static int nxpwifi_pm_wakeup_card_complete(struct nxpwifi_adapter *adapter) +{ + nxpwifi_dbg(adapter, EVENT, + "cmd: wakeup device completed\n"); + + return nxpwifi_write_reg(adapter, CONFIGURATION_REG, 0); +} + +static int nxpwifi_sdio_dnld_fw(struct nxpwifi_adapter *adapter, + struct nxpwifi_fw_image *fw) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + + sdio_claim_host(card->func); + ret = nxpwifi_dnld_fw(adapter, fw); + sdio_release_host(card->func); + + return ret; +} + +/* This function is used to initialize IO ports for the + * chipsets supporting SDIO new mode. + */ +static int nxpwifi_init_sdio_new_mode(struct nxpwifi_adapter *adapter) +{ + u8 reg; + struct sdio_mmc_card *card = adapter->card; + int ret; + + adapter->ioport = MEM_PORT; + + /* enable sdio new mode */ + ret = nxpwifi_read_reg(adapter, card->reg->card_cfg_2_1_reg, ®); + if (ret) + return ret; + ret = nxpwifi_write_reg(adapter, card->reg->card_cfg_2_1_reg, + reg | CMD53_NEW_MODE); + if (ret) + return ret; + + /* Configure cmd port and enable reading rx length from the register */ + ret = nxpwifi_read_reg(adapter, card->reg->cmd_cfg_0, ®); + if (ret) + return ret; + ret = nxpwifi_write_reg(adapter, card->reg->cmd_cfg_0, + reg | CMD_PORT_RD_LEN_EN); + if (ret) + return ret; + + /* Enable Dnld/Upld ready auto reset for cmd port after cmd53 is + * completed + */ + ret = nxpwifi_read_reg(adapter, card->reg->cmd_cfg_1, ®); + if (ret) + return ret; + ret = nxpwifi_write_reg(adapter, card->reg->cmd_cfg_1, + reg | CMD_PORT_AUTO_EN); + + return ret; +} + +/* This function initializes the IO ports. + * + * The following operations are performed - + * - Read the IO ports (0, 1 and 2) + * - Set host interrupt Reset-To-Read to clear + * - Set auto re-enable interrupt + */ +static int nxpwifi_init_sdio_ioport(struct nxpwifi_adapter *adapter) +{ + u8 reg; + struct sdio_mmc_card *card = adapter->card; + int ret; + + ret = nxpwifi_init_sdio_new_mode(adapter); + if (ret) + return ret; + + nxpwifi_dbg(adapter, INFO, + "info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); + + /* Set Host interrupt reset to read to clear */ + ret = nxpwifi_read_reg(adapter, card->reg->host_int_rsr_reg, ®); + if (ret) + return ret; + ret = nxpwifi_write_reg(adapter, card->reg->host_int_rsr_reg, + reg | card->reg->sdio_int_mask); + if (ret) + return ret; + + /* Dnld/Upld ready set to auto reset */ + ret = nxpwifi_read_reg(adapter, card->reg->card_misc_cfg_reg, ®); + if (ret) + return ret; + ret = nxpwifi_write_reg(adapter, card->reg->card_misc_cfg_reg, + reg | AUTO_RE_ENABLE_INT); + + return ret; +} + +/* This function sends data to the card. + */ +static int nxpwifi_write_data_to_card(struct nxpwifi_adapter *adapter, + u8 *payload, u32 pkt_len, u32 port) +{ + u32 i = 0; + int ret; + + do { + ret = nxpwifi_write_data_sync(adapter, payload, pkt_len, port); + if (ret) { + i++; + nxpwifi_dbg(adapter, ERROR, + "host_to_card, write iomem\t" + "(%d) failed: %d\n", i, ret); + if (nxpwifi_write_reg(adapter, CONFIGURATION_REG, 0x04)) + nxpwifi_dbg(adapter, ERROR, + "write CFG reg failed\n"); + + if (i > MAX_WRITE_IOMEM_RETRY) + return ret; + } + } while (ret); + + return ret; +} + +/* This function gets the read port. + * + * If control port bit is set in MP read bitmap, the control port + * is returned, otherwise the current read port is returned and + * the value is increased (provided it does not reach the maximum + * limit, in which case it is reset to 1) + */ +static int nxpwifi_get_rd_port(struct nxpwifi_adapter *adapter, u8 *port) +{ + struct sdio_mmc_card *card = adapter->card; + const struct nxpwifi_sdio_card_reg *reg = card->reg; + u32 rd_bitmap = card->mp_rd_bitmap; + + nxpwifi_dbg(adapter, DATA, + "data: mp_rd_bitmap=0x%08x\n", rd_bitmap); + + if (!(rd_bitmap & reg->data_port_mask)) + return -EINVAL; + + if (!(card->mp_rd_bitmap & (1 << card->curr_rd_port))) + return -EINVAL; + + /* We are now handling the SDIO data ports */ + card->mp_rd_bitmap &= (u32)(~(1 << card->curr_rd_port)); + *port = card->curr_rd_port; + + if (++card->curr_rd_port == card->max_ports) + card->curr_rd_port = reg->start_rd_port; + + nxpwifi_dbg(adapter, DATA, + "data: port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n", + *port, rd_bitmap, card->mp_rd_bitmap); + + return 0; +} + +/* This function gets the write port for data. + * + * The current write port is returned if available and the value is + * increased (provided it does not reach the maximum limit, in which + * case it is reset to 1) + */ +static int nxpwifi_get_wr_port_data(struct nxpwifi_adapter *adapter, u32 *port) +{ + struct sdio_mmc_card *card = adapter->card; + const struct nxpwifi_sdio_card_reg *reg = card->reg; + u32 wr_bitmap = card->mp_wr_bitmap; + + nxpwifi_dbg(adapter, DATA, + "data: mp_wr_bitmap=0x%08x\n", wr_bitmap); + + if (!(wr_bitmap & card->mp_data_port_mask)) { + adapter->data_sent = true; + return -EBUSY; + } + + if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { + card->mp_wr_bitmap &= (u32)(~(1 << card->curr_wr_port)); + *port = card->curr_wr_port; + if (++card->curr_wr_port == card->mp_end_port) + card->curr_wr_port = reg->start_wr_port; + } else { + adapter->data_sent = true; + return -EBUSY; + } + + nxpwifi_dbg(adapter, DATA, + "data: port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n", + *port, wr_bitmap, card->mp_wr_bitmap); + + return 0; +} + +/* This function polls the card status. + */ +static int +nxpwifi_sdio_poll_card_status(struct nxpwifi_adapter *adapter, u8 bits) +{ + struct sdio_mmc_card *card = adapter->card; + u32 tries; + u8 cs; + int ret; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ret = nxpwifi_read_reg(adapter, card->reg->poll_reg, &cs); + if (ret) + break; + else if ((cs & bits) == bits) + return 0; + + usleep_range(10, 20); + } + + nxpwifi_dbg(adapter, ERROR, + "poll card status failed, tries = %d\n", tries); + + return ret; +} + +/* This function disables the host interrupt. + * + * The host interrupt mask is read, the disable bit is reset and + * written back to the card host interrupt mask register. + */ +static void nxpwifi_sdio_disable_host_int(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; + + sdio_claim_host(func); + nxpwifi_write_reg_locked(func, card->reg->host_int_mask_reg, 0); + sdio_release_irq(func); + sdio_release_host(func); +} + +/* This function reads the interrupt status from card. + */ +static void nxpwifi_interrupt_status(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + u8 sdio_ireg; + unsigned long flags; + + if (nxpwifi_read_data_sync(adapter, card->mp_regs, + card->reg->max_mp_regs, + REG_PORT | NXPWIFI_SDIO_BYTE_MODE_MASK, 0)) { + nxpwifi_dbg(adapter, ERROR, "read mp_regs failed\n"); + return; + } + + sdio_ireg = card->mp_regs[card->reg->host_int_status_reg]; + if (sdio_ireg) { + nxpwifi_dbg(adapter, INTR, + "int: sdio_ireg = %#x\n", sdio_ireg); + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status |= sdio_ireg; + spin_unlock_irqrestore(&adapter->int_lock, flags); + } +} + +/* SDIO interrupt handler. + * + * This function reads the interrupt status from firmware and handles + * the interrupt in current thread (ksdioirqd) right away. + */ +static void +nxpwifi_sdio_interrupt(struct sdio_func *func) +{ + struct nxpwifi_adapter *adapter; + struct sdio_mmc_card *card; + + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_err("int: func=%p card=%p adapter=%p\n", + func, card, card ? card->adapter : NULL); + return; + } + adapter = card->adapter; + + if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) + adapter->ps_state = PS_STATE_AWAKE; + + nxpwifi_interrupt_status(adapter); + nxpwifi_main_process(adapter); +} + +/* This function enables the host interrupt. + * + * The host interrupt enable mask is written to the card + * host interrupt mask register. + */ +static int nxpwifi_sdio_enable_host_int(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; + int ret; + + sdio_claim_host(func); + + /* Request the SDIO IRQ */ + ret = sdio_claim_irq(func, nxpwifi_sdio_interrupt); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "claim irq failed: ret=%d\n", ret); + goto done; + } + + /* Simply write the mask to the register */ + ret = nxpwifi_write_reg_locked(func, card->reg->host_int_mask_reg, + card->reg->host_int_enable); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "enable host interrupt failed\n"); + sdio_release_irq(func); + } + +done: + sdio_release_host(func); + return ret; +} + +/* This function gets a data buffer from the card. + */ +static int nxpwifi_sdio_card_to_host(struct nxpwifi_adapter *adapter, + u32 *type, u8 *buffer, + u32 npayload, u32 ioport) +{ + int ret; + u32 nb; + + if (!buffer) { + nxpwifi_dbg(adapter, ERROR, + "%s: buffer is NULL\n", __func__); + return -EINVAL; + } + + ret = nxpwifi_read_data_sync(adapter, buffer, npayload, ioport, 1); + + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "%s: read iomem failed: %d\n", __func__, + ret); + return ret; + } + + nb = get_unaligned_le16((buffer)); + if (nb > npayload) { + nxpwifi_dbg(adapter, ERROR, + "%s: invalid packet, nb=%d npayload=%d\n", + __func__, nb, npayload); + return -EINVAL; + } + + *type = get_unaligned_le16((buffer + 2)); + + return ret; +} + +/* This function downloads the firmware to the card. + * + * Firmware is downloaded to the card in blocks. Every block download + * is tested for CRC errors, and retried a number of times before + * returning failure. + */ +static int nxpwifi_prog_fw_w_helper(struct nxpwifi_adapter *adapter, + struct nxpwifi_fw_image *fw) +{ + struct sdio_mmc_card *card = adapter->card; + const struct nxpwifi_sdio_card_reg *reg = card->reg; + int ret; + u8 *firmware = fw->fw_buf; + u32 firmware_len = fw->fw_len; + u32 offset = 0; + u8 base0, base1; + u8 *fwbuf; + u16 len = 0; + u32 txlen, tx_blocks = 0, tries; + u32 i = 0; + + if (!firmware_len) { + nxpwifi_dbg(adapter, ERROR, + "firmware image not found! Terminating download\n"); + return -EINVAL; + } + + nxpwifi_dbg(adapter, INFO, + "info: downloading FW image (%d bytes)\n", + firmware_len); + + /* Assume that the allocated buffer is 8-byte aligned */ + fwbuf = kzalloc(NXPWIFI_UPLD_SIZE, GFP_KERNEL); + if (!fwbuf) + return -ENOMEM; + + sdio_claim_host(card->func); + + /* Perform firmware data transfer */ + do { + /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY + * bits + */ + ret = nxpwifi_sdio_poll_card_status(adapter, CARD_IO_READY | + DN_LD_CARD_RDY); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "FW download with helper:\t" + "poll status timeout @ %d\n", offset); + goto done; + } + + /* More data? */ + if (offset >= firmware_len) + break; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ret = nxpwifi_read_reg(adapter, reg->base_0_reg, + &base0); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "dev BASE0 register read failed:\t" + "base0=%#04X(%d). Terminating dnld\n", + base0, base0); + goto done; + } + ret = nxpwifi_read_reg(adapter, reg->base_1_reg, + &base1); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "dev BASE1 register read failed:\t" + "base1=%#04X(%d). Terminating dnld\n", + base1, base1); + goto done; + } + len = (u16)(((base1 & 0xff) << 8) | (base0 & 0xff)); + + if (len) + break; + + usleep_range(10, 20); + } + + if (!len) { + break; + } else if (len > NXPWIFI_UPLD_SIZE) { + nxpwifi_dbg(adapter, ERROR, + "FW dnld failed @ %d, invalid length %d\n", + offset, len); + ret = -EINVAL; + goto done; + } + + txlen = len; + + if (len & BIT(0)) { + i++; + if (i > MAX_WRITE_IOMEM_RETRY) { + nxpwifi_dbg(adapter, ERROR, + "FW dnld failed @ %d, over max retry\n", + offset); + ret = -EIO; + goto done; + } + nxpwifi_dbg(adapter, ERROR, + "CRC indicated by the helper:\t" + "len = 0x%04X, txlen = %d\n", len, txlen); + len &= ~BIT(0); + /* Setting this to 0 to resend from same offset */ + txlen = 0; + } else { + i = 0; + + /* Set blocksize to transfer - checking for last + * block + */ + if (firmware_len - offset < txlen) + txlen = firmware_len - offset; + + tx_blocks = (txlen + NXPWIFI_SDIO_BLOCK_SIZE - 1) + / NXPWIFI_SDIO_BLOCK_SIZE; + + /* Copy payload to buffer */ + memmove(fwbuf, &firmware[offset], txlen); + } + + ret = nxpwifi_write_data_sync(adapter, fwbuf, tx_blocks * + NXPWIFI_SDIO_BLOCK_SIZE, + adapter->ioport); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "FW download, write iomem (%d) failed @ %d\n", + i, offset); + if (nxpwifi_write_reg(adapter, CONFIGURATION_REG, 0x04)) + nxpwifi_dbg(adapter, ERROR, + "write CFG reg failed\n"); + + goto done; + } + + offset += txlen; + } while (true); + + nxpwifi_dbg(adapter, MSG, + "info: FW download over, size %d bytes\n", offset); + + ret = 0; +done: + sdio_release_host(card->func); + kfree(fwbuf); + return ret; +} + +/* This function decodes sdio aggregation pkt. + * + * Based on the data block size and pkt_len, + * skb data will be decoded to few packets. + */ +static void nxpwifi_deaggr_sdio_pkt(struct nxpwifi_adapter *adapter, + struct sk_buff *skb) +{ + u32 total_pkt_len, pkt_len; + struct sk_buff *skb_deaggr; + u16 blk_size; + u8 blk_num; + u8 *data; + + data = skb->data; + total_pkt_len = skb->len; + + while (total_pkt_len >= (SDIO_HEADER_OFFSET + adapter->intf_hdr_len)) { + if (total_pkt_len < adapter->sdio_rx_block_size) + break; + blk_num = *(data + BLOCK_NUMBER_OFFSET); + blk_size = adapter->sdio_rx_block_size * blk_num; + if (blk_size > total_pkt_len) { + nxpwifi_dbg(adapter, ERROR, + "%s: error in blk_size,\t" + "blk_num=%d, blk_size=%d, total_pkt_len=%d\n", + __func__, blk_num, blk_size, total_pkt_len); + break; + } + pkt_len = get_unaligned_le16((data + + SDIO_HEADER_OFFSET)); + if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) { + nxpwifi_dbg(adapter, ERROR, + "%s: error in pkt_len,\t" + "pkt_len=%d, blk_size=%d\n", + __func__, pkt_len, blk_size); + break; + } + + skb_deaggr = nxpwifi_alloc_dma_align_buf(pkt_len, GFP_KERNEL); + if (!skb_deaggr) + break; + skb_put(skb_deaggr, pkt_len); + memcpy(skb_deaggr->data, data + SDIO_HEADER_OFFSET, pkt_len); + skb_pull(skb_deaggr, adapter->intf_hdr_len); + + nxpwifi_handle_rx_packet(adapter, skb_deaggr); + data += blk_size; + total_pkt_len -= blk_size; + } +} + +/* This function decodes a received packet. + * + * Based on the type, the packet is treated as either a data, or + * a command response, or an event, and the correct handler + * function is invoked. + */ +static void nxpwifi_decode_rx_packet(struct nxpwifi_adapter *adapter, + struct sk_buff *skb, u32 upld_typ) +{ + u8 *cmd_buf; + u16 pkt_len; + struct nxpwifi_rxinfo *rx_info; + + pkt_len = get_unaligned_le16(skb->data); + + if (upld_typ != NXPWIFI_TYPE_AGGR_DATA) { + skb_trim(skb, pkt_len); + skb_pull(skb, adapter->intf_hdr_len); + } + + switch (upld_typ) { + case NXPWIFI_TYPE_AGGR_DATA: + nxpwifi_dbg(adapter, INFO, + "info: --- Rx: Aggr Data packet ---\n"); + rx_info = NXPWIFI_SKB_RXCB(skb); + rx_info->buf_type = NXPWIFI_TYPE_AGGR_DATA; + skb_queue_tail(&adapter->rx_data_q, skb); + adapter->data_received = true; + tasklet_schedule(&adapter->rx_task); + break; + + case NXPWIFI_TYPE_DATA: + nxpwifi_dbg(adapter, DATA, + "info: --- Rx: Data packet ---\n"); + skb_queue_tail(&adapter->rx_data_q, skb); + adapter->data_received = true; + tasklet_schedule(&adapter->rx_task); + break; + + case NXPWIFI_TYPE_CMD: + nxpwifi_dbg(adapter, CMD, + "info: --- Rx: Cmd Response ---\n"); + /* take care of curr_cmd = NULL case */ + if (!adapter->curr_cmd) { + cmd_buf = adapter->upld_buf; + + if (adapter->ps_state == PS_STATE_SLEEP_CFM) + nxpwifi_process_sleep_confirm_resp(adapter, + skb->data, + skb->len); + + memcpy(cmd_buf, skb->data, + min_t(u32, NXPWIFI_SIZE_OF_CMD_BUFFER, + skb->len)); + + dev_kfree_skb_any(skb); + } else { + adapter->cmd_resp_received = true; + adapter->curr_cmd->resp_skb = skb; + } + break; + + case NXPWIFI_TYPE_EVENT: + nxpwifi_dbg(adapter, EVENT, + "info: --- Rx: Event ---\n"); + adapter->event_cause = get_unaligned_le32(skb->data); + + if (skb->len > 0 && skb->len < MAX_EVENT_SIZE) + memcpy(adapter->event_body, + skb->data + NXPWIFI_EVENT_HEADER_LEN, + skb->len); + + /* event cause has been saved to adapter->event_cause */ + adapter->event_received = true; + adapter->event_skb = skb; + + break; + + default: + nxpwifi_dbg(adapter, ERROR, + "unknown upload type %#x\n", upld_typ); + dev_kfree_skb_any(skb); + break; + } +} + +/* This function transfers received packets from card to driver, performing + * aggregation if required. + * + * For data received on control port, or if aggregation is disabled, the + * received buffers are uploaded as separate packets. However, if aggregation + * is enabled and required, the buffers are copied onto an aggregation buffer, + * provided there is space left, processed and finally uploaded. + */ +static int nxpwifi_sdio_card_to_host_mp_aggr(struct nxpwifi_adapter *adapter, + u16 rx_len, u8 port) +{ + struct sdio_mmc_card *card = adapter->card; + s32 f_do_rx_aggr = 0; + s32 f_do_rx_cur = 0; + s32 f_aggr_cur = 0; + s32 f_post_aggr_cur = 0; + struct sk_buff *skb_deaggr; + struct sk_buff *skb = NULL; + u32 pkt_len, pkt_type, mport, pind; + u8 *curr_ptr; + int ret = 0; + + if (!card->mpa_rx.enabled) { + nxpwifi_dbg(adapter, WARN, + "info: %s: rx aggregation disabled\n", + __func__); + + f_do_rx_cur = 1; + goto rx_curr_single; + } + + if (card->mp_rd_bitmap & card->reg->data_port_mask) { + /* Some more data RX pending */ + nxpwifi_dbg(adapter, INFO, + "info: %s: not last packet\n", __func__); + + if (MP_RX_AGGR_IN_PROGRESS(card)) { + if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) { + f_aggr_cur = 1; + } else { + /* No room in Aggr buf, do rx aggr now */ + f_do_rx_aggr = 1; + f_post_aggr_cur = 1; + } + } else { + /* Rx aggr not in progress */ + f_aggr_cur = 1; + } + + } else { + /* No more data RX pending */ + nxpwifi_dbg(adapter, INFO, + "info: %s: last packet\n", __func__); + + if (MP_RX_AGGR_IN_PROGRESS(card)) { + f_do_rx_aggr = 1; + if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) + f_aggr_cur = 1; + else + /* No room in Aggr buf, do rx aggr now */ + f_do_rx_cur = 1; + } else { + f_do_rx_cur = 1; + } + } + + if (f_aggr_cur) { + nxpwifi_dbg(adapter, INFO, + "info: current packet aggregation\n"); + /* Curr pkt can be aggregated */ + mp_rx_aggr_setup(card, rx_len, port); + + if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || + mp_rx_aggr_port_limit_reached(card)) { + nxpwifi_dbg(adapter, INFO, + "info: %s: aggregated packet\t" + "limit reached\n", __func__); + /* No more pkts allowed in Aggr buf, rx it */ + f_do_rx_aggr = 1; + } + } + + if (f_do_rx_aggr) { + u32 port_count; + int i; + + /* do aggr RX now */ + nxpwifi_dbg(adapter, DATA, + "info: do_rx_aggr: num of packets: %d\n", + card->mpa_rx.pkt_cnt); + + for (i = 0, port_count = 0; i < card->max_ports; i++) + if (card->mpa_rx.ports & BIT(i)) + port_count++; + + /* Reading data from "start_port + 0" to "start_port + + * port_count -1", so decrease the count by 1 + */ + port_count--; + mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | + (port_count << 8)) + card->mpa_rx.start_port; + + if (card->mpa_rx.pkt_cnt == 1) + mport = adapter->ioport + card->mpa_rx.start_port; + + ret = nxpwifi_read_data_sync(adapter, card->mpa_rx.buf, + card->mpa_rx.buf_len, mport, 1); + if (ret) + goto error; + + curr_ptr = card->mpa_rx.buf; + + for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { + u32 *len_arr = card->mpa_rx.len_arr; + + /* get curr PKT len & type */ + pkt_len = get_unaligned_le16(&curr_ptr[0]); + pkt_type = get_unaligned_le16(&curr_ptr[2]); + + /* copy pkt to deaggr buf */ + skb_deaggr = nxpwifi_alloc_dma_align_buf(len_arr[pind], + GFP_KERNEL); + if (!skb_deaggr) { + nxpwifi_dbg(adapter, ERROR, "skb allocation failure\t" + "drop pkt len=%d type=%d\n", + pkt_len, pkt_type); + curr_ptr += len_arr[pind]; + continue; + } + + skb_put(skb_deaggr, len_arr[pind]); + + if ((pkt_type == NXPWIFI_TYPE_DATA || + (pkt_type == NXPWIFI_TYPE_AGGR_DATA && + adapter->sdio_rx_aggr_enable)) && + pkt_len <= len_arr[pind]) { + memcpy(skb_deaggr->data, curr_ptr, pkt_len); + + skb_trim(skb_deaggr, pkt_len); + + /* Process de-aggr packet */ + nxpwifi_decode_rx_packet(adapter, skb_deaggr, + pkt_type); + } else { + nxpwifi_dbg(adapter, ERROR, + "drop wrong aggr pkt:\t" + "sdio_single_port_rx_aggr=%d\t" + "type=%d len=%d max_len=%d\n", + adapter->sdio_rx_aggr_enable, + pkt_type, pkt_len, len_arr[pind]); + dev_kfree_skb_any(skb_deaggr); + } + curr_ptr += len_arr[pind]; + } + MP_RX_AGGR_BUF_RESET(card); + } + +rx_curr_single: + if (f_do_rx_cur) { + nxpwifi_dbg(adapter, INFO, "info: RX: port: %d, rx_len: %d\n", + port, rx_len); + + skb = nxpwifi_alloc_dma_align_buf(rx_len, GFP_KERNEL); + if (!skb) { + nxpwifi_dbg(adapter, ERROR, + "single skb allocated fail,\t" + "drop pkt port=%d len=%d\n", port, rx_len); + ret = nxpwifi_sdio_card_to_host(adapter, &pkt_type, + card->mpa_rx.buf, + rx_len, + adapter->ioport + port); + if (ret) + goto error; + return 0; + } + + skb_put(skb, rx_len); + + ret = nxpwifi_sdio_card_to_host(adapter, &pkt_type, + skb->data, skb->len, + adapter->ioport + port); + if (ret) + goto error; + if (!adapter->sdio_rx_aggr_enable && + pkt_type == NXPWIFI_TYPE_AGGR_DATA) { + nxpwifi_dbg(adapter, ERROR, "drop wrong pkt type %d\t" + "current SDIO RX Aggr not enabled\n", + pkt_type); + dev_kfree_skb_any(skb); + return 0; + } + + nxpwifi_decode_rx_packet(adapter, skb, pkt_type); + } + if (f_post_aggr_cur) { + nxpwifi_dbg(adapter, INFO, + "info: current packet aggregation\n"); + /* Curr pkt can be aggregated */ + mp_rx_aggr_setup(card, rx_len, port); + } + + return 0; +error: + if (MP_RX_AGGR_IN_PROGRESS(card)) + MP_RX_AGGR_BUF_RESET(card); + + if (f_do_rx_cur && skb) + /* Single transfer pending. Free curr buff also */ + dev_kfree_skb_any(skb); + + return ret; +} + +/* This function checks the current interrupt status. + * + * The following interrupts are checked and handled by this function - + * - Data sent + * - Command sent + * - Packets received + * + * Since the firmware does not generate download ready interrupt if the + * port updated is command port only, command sent interrupt checking + * should be done manually, and for every SDIO interrupt. + * + * In case of Rx packets received, the packets are uploaded from card to + * host and processed accordingly. + */ +static int nxpwifi_process_int_status(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + const struct nxpwifi_sdio_card_reg *reg = card->reg; + int ret = 0; + u8 sdio_ireg; + struct sk_buff *skb; + u8 port; + u32 len_reg_l, len_reg_u; + u32 rx_blocks; + u16 rx_len; + unsigned long flags; + u32 bitmap; + u8 cr; + + spin_lock_irqsave(&adapter->int_lock, flags); + sdio_ireg = adapter->int_status; + adapter->int_status = 0; + spin_unlock_irqrestore(&adapter->int_lock, flags); + + if (!sdio_ireg) + return ret; + + if (sdio_ireg & DN_LD_CMD_PORT_HOST_INT_STATUS && adapter->cmd_sent) + adapter->cmd_sent = false; + + if (sdio_ireg & UP_LD_CMD_PORT_HOST_INT_STATUS) { + u32 pkt_type; + + /* read the len of control packet */ + rx_len = card->mp_regs[reg->cmd_rd_len_1] << 8; + rx_len |= (u16)card->mp_regs[reg->cmd_rd_len_0]; + rx_blocks = DIV_ROUND_UP(rx_len, NXPWIFI_SDIO_BLOCK_SIZE); + if (rx_len <= adapter->intf_hdr_len || + (rx_blocks * NXPWIFI_SDIO_BLOCK_SIZE) > + NXPWIFI_RX_DATA_BUF_SIZE) + return -EINVAL; + rx_len = (u16)(rx_blocks * NXPWIFI_SDIO_BLOCK_SIZE); + nxpwifi_dbg(adapter, INFO, "info: rx_len = %d\n", rx_len); + + skb = nxpwifi_alloc_dma_align_buf(rx_len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + skb_put(skb, rx_len); + + ret = nxpwifi_sdio_card_to_host(adapter, &pkt_type, skb->data, + skb->len, adapter->ioport | + CMD_PORT_SLCT); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "%s: failed to card_to_host", __func__); + dev_kfree_skb_any(skb); + goto term_cmd; + } + + if (pkt_type != NXPWIFI_TYPE_CMD && + pkt_type != NXPWIFI_TYPE_EVENT) + nxpwifi_dbg(adapter, ERROR, + "%s:Received wrong packet on cmd port", + __func__); + + nxpwifi_decode_rx_packet(adapter, skb, pkt_type); + } + + if (sdio_ireg & DN_LD_HOST_INT_STATUS) { + bitmap = (u32)card->mp_regs[reg->wr_bitmap_l]; + bitmap |= ((u32)card->mp_regs[reg->wr_bitmap_u]) << 8; + bitmap |= ((u32)card->mp_regs[reg->wr_bitmap_1l]) << 16; + bitmap |= ((u32)card->mp_regs[reg->wr_bitmap_1u]) << 24; + card->mp_wr_bitmap = bitmap; + + nxpwifi_dbg(adapter, INTR, + "int: DNLD: wr_bitmap=0x%x\n", + card->mp_wr_bitmap); + if (adapter->data_sent && + (card->mp_wr_bitmap & card->mp_data_port_mask)) { + nxpwifi_dbg(adapter, INTR, + "info: <--- Tx DONE Interrupt --->\n"); + adapter->data_sent = false; + } + } + + nxpwifi_dbg(adapter, INTR, "info: cmd_sent=%d data_sent=%d\n", + adapter->cmd_sent, adapter->data_sent); + if (sdio_ireg & UP_LD_HOST_INT_STATUS) { + bitmap = (u32)card->mp_regs[reg->rd_bitmap_l]; + bitmap |= ((u32)card->mp_regs[reg->rd_bitmap_u]) << 8; + bitmap |= ((u32)card->mp_regs[reg->rd_bitmap_1l]) << 16; + bitmap |= ((u32)card->mp_regs[reg->rd_bitmap_1u]) << 24; + card->mp_rd_bitmap = bitmap; + nxpwifi_dbg(adapter, INTR, + "int: UPLD: rd_bitmap=0x%x\n", + card->mp_rd_bitmap); + + while (true) { + ret = nxpwifi_get_rd_port(adapter, &port); + if (ret) { + nxpwifi_dbg(adapter, INFO, + "info: no more rd_port available\n"); + break; + } + len_reg_l = reg->rd_len_p0_l + (port << 1); + len_reg_u = reg->rd_len_p0_u + (port << 1); + rx_len = ((u16)card->mp_regs[len_reg_u]) << 8; + rx_len |= (u16)card->mp_regs[len_reg_l]; + nxpwifi_dbg(adapter, INFO, + "info: RX: port=%d rx_len=%u\n", + port, rx_len); + rx_blocks = + (rx_len + NXPWIFI_SDIO_BLOCK_SIZE - + 1) / NXPWIFI_SDIO_BLOCK_SIZE; + if (rx_len <= adapter->intf_hdr_len || + (card->mpa_rx.enabled && + ((rx_blocks * NXPWIFI_SDIO_BLOCK_SIZE) > + card->mpa_rx.buf_size))) { + nxpwifi_dbg(adapter, ERROR, + "invalid rx_len=%d\n", + rx_len); + return -EINVAL; + } + + rx_len = (u16)(rx_blocks * NXPWIFI_SDIO_BLOCK_SIZE); + nxpwifi_dbg(adapter, INFO, "info: rx_len = %d\n", + rx_len); + + ret = nxpwifi_sdio_card_to_host_mp_aggr(adapter, rx_len, + port); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "card_to_host_mpa failed: int status=%#x\n", + sdio_ireg); + goto term_cmd; + } + } + } + + return 0; + +term_cmd: + /* terminate cmd */ + if (nxpwifi_read_reg(adapter, CONFIGURATION_REG, &cr)) + nxpwifi_dbg(adapter, ERROR, "read CFG reg failed\n"); + else + nxpwifi_dbg(adapter, INFO, + "info: CFG reg val = %d\n", cr); + + if (nxpwifi_write_reg(adapter, CONFIGURATION_REG, (cr | 0x04))) + nxpwifi_dbg(adapter, ERROR, + "write CFG reg failed\n"); + else + nxpwifi_dbg(adapter, INFO, "info: write success\n"); + + if (nxpwifi_read_reg(adapter, CONFIGURATION_REG, &cr)) + nxpwifi_dbg(adapter, ERROR, + "read CFG reg failed\n"); + else + nxpwifi_dbg(adapter, INFO, + "info: CFG reg val =%x\n", cr); + + return ret; +} + +/* This function aggregates transmission buffers in driver and downloads + * the aggregated packet to card. + * + * The individual packets are aggregated by copying into an aggregation + * buffer and then downloaded to the card. Previous unsent packets in the + * aggregation buffer are pre-copied first before new packets are added. + * Aggregation is done till there is space left in the aggregation buffer, + * or till new packets are available. + * + * The function will only download the packet to the card when aggregation + * stops, otherwise it will just aggregate the packet in aggregation buffer + * and return. + */ +static int nxpwifi_host_to_card_mp_aggr(struct nxpwifi_adapter *adapter, + u8 *payload, u32 pkt_len, u32 port, + u32 next_pkt_len) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + s32 f_send_aggr_buf = 0; + s32 f_send_cur_buf = 0; + s32 f_precopy_cur_buf = 0; + s32 f_postcopy_cur_buf = 0; + u32 mport; + int index; + + if (!card->mpa_tx.enabled || port == CMD_PORT_SLCT) { + nxpwifi_dbg(adapter, WARN, + "info: %s: tx aggregation disabled\n", + __func__); + + f_send_cur_buf = 1; + goto tx_curr_single; + } + + if (next_pkt_len) { + /* More pkt in TX queue */ + nxpwifi_dbg(adapter, INFO, + "info: %s: more packets in queue.\n", + __func__); + + if (MP_TX_AGGR_IN_PROGRESS(card)) { + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { + f_precopy_cur_buf = 1; + + if (!(card->mp_wr_bitmap & + (1 << card->curr_wr_port)) || + !MP_TX_AGGR_BUF_HAS_ROOM + (card, pkt_len + next_pkt_len)) + f_send_aggr_buf = 1; + } else { + /* No room in Aggr buf, send it */ + f_send_aggr_buf = 1; + + if (!(card->mp_wr_bitmap & + (1 << card->curr_wr_port))) + f_send_cur_buf = 1; + else + f_postcopy_cur_buf = 1; + } + } else { + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len) && + (card->mp_wr_bitmap & (1 << card->curr_wr_port))) + f_precopy_cur_buf = 1; + else + f_send_cur_buf = 1; + } + } else { + /* Last pkt in TX queue */ + nxpwifi_dbg(adapter, INFO, + "info: %s: Last packet in Tx Queue.\n", + __func__); + + if (MP_TX_AGGR_IN_PROGRESS(card)) { + /* some packs in Aggr buf already */ + f_send_aggr_buf = 1; + + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) + f_precopy_cur_buf = 1; + else + /* No room in Aggr buf, send it */ + f_send_cur_buf = 1; + } else { + f_send_cur_buf = 1; + } + } + + if (f_precopy_cur_buf) { + nxpwifi_dbg(adapter, DATA, + "data: %s: precopy current buffer\n", + __func__); + MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); + + if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || + mp_tx_aggr_port_limit_reached(card)) + /* No more pkts allowed in Aggr buf, send it */ + f_send_aggr_buf = 1; + } + + if (f_send_aggr_buf) { + u32 port_count; + int i; + + nxpwifi_dbg(adapter, DATA, + "data: %s: send aggr buffer: %d %d\n", + __func__, card->mpa_tx.start_port, + card->mpa_tx.ports); + + for (i = 0, port_count = 0; i < card->max_ports; i++) + if (card->mpa_tx.ports & BIT(i)) + port_count++; + + /* Writing data from "start_port + 0" to "start_port + + * port_count -1", so decrease the count by 1 + */ + port_count--; + mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | + (port_count << 8)) + card->mpa_tx.start_port; + + if (card->mpa_tx.pkt_cnt == 1) + mport = adapter->ioport + card->mpa_tx.start_port; + + ret = nxpwifi_write_data_to_card(adapter, card->mpa_tx.buf, + card->mpa_tx.buf_len, mport); + + /* Save the last multi port tx aggregation info to debug log */ + index = adapter->dbg.last_sdio_mp_index; + index = (index + 1) % NXPWIFI_DBG_SDIO_MP_NUM; + adapter->dbg.last_sdio_mp_index = index; + adapter->dbg.last_mp_wr_ports[index] = mport; + adapter->dbg.last_mp_wr_bitmap[index] = card->mp_wr_bitmap; + adapter->dbg.last_mp_wr_len[index] = card->mpa_tx.buf_len; + adapter->dbg.last_mp_curr_wr_port[index] = card->curr_wr_port; + + MP_TX_AGGR_BUF_RESET(card); + } + +tx_curr_single: + if (f_send_cur_buf) { + nxpwifi_dbg(adapter, DATA, + "data: %s: send current buffer %d\n", + __func__, port); + ret = nxpwifi_write_data_to_card(adapter, payload, pkt_len, + adapter->ioport + port); + } + + if (f_postcopy_cur_buf) { + nxpwifi_dbg(adapter, DATA, + "data: %s: postcopy current buffer\n", + __func__); + MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); + } + + return ret; +} + +/* This function downloads data from driver to card. + * + * Both commands and data packets are transferred to the card by this + * function. + * + * This function adds the SDIO specific header to the front of the buffer + * before transferring. The header contains the length of the packet and + * the type. The firmware handles the packets based upon this set type. + */ +static int nxpwifi_sdio_host_to_card(struct nxpwifi_adapter *adapter, + u8 type, struct sk_buff *skb, + struct nxpwifi_tx_param *tx_param) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + u32 buf_block_len; + u32 blk_size; + u32 port; + u8 *payload = (u8 *)skb->data; + u32 pkt_len = skb->len; + + /* Allocate buffer and copy payload */ + blk_size = NXPWIFI_SDIO_BLOCK_SIZE; + buf_block_len = (pkt_len + blk_size - 1) / blk_size; + put_unaligned_le16((u16)pkt_len, payload + 0); + put_unaligned_le16((u16)type, payload + 2); + + /* This is SDIO specific header + * u16 length, + * u16 type (NXPWIFI_TYPE_DATA = 0, NXPWIFI_TYPE_CMD = 1, + * NXPWIFI_TYPE_EVENT = 3) + */ + if (type == NXPWIFI_TYPE_DATA) { + ret = nxpwifi_get_wr_port_data(adapter, &port); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "%s: no wr_port available\n", + __func__); + return ret; + } + } else { + adapter->cmd_sent = true; + + if (pkt_len <= adapter->intf_hdr_len || + pkt_len > NXPWIFI_UPLD_SIZE) + nxpwifi_dbg(adapter, ERROR, + "%s: payload=%p, nb=%d\n", + __func__, payload, pkt_len); + + port = CMD_PORT_SLCT; + } + + /* Transfer data to card */ + pkt_len = buf_block_len * blk_size; + + if (tx_param) + ret = nxpwifi_host_to_card_mp_aggr(adapter, payload, pkt_len, + port, tx_param->next_pkt_len + ); + else + ret = nxpwifi_host_to_card_mp_aggr(adapter, payload, pkt_len, + port, 0); + + if (ret) { + if (type == NXPWIFI_TYPE_CMD || + type == NXPWIFI_TYPE_VDLL) + adapter->cmd_sent = false; + if (type == NXPWIFI_TYPE_DATA) { + adapter->data_sent = false; + /* restore curr_wr_port in error cases */ + card->curr_wr_port = port; + card->mp_wr_bitmap |= (u32)(1 << card->curr_wr_port); + } + } else { + if (type == NXPWIFI_TYPE_DATA) { + if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) + adapter->data_sent = true; + else + adapter->data_sent = false; + } + } + + return ret; +} + +/* This function allocates the MPA Tx and Rx buffers. + */ +static int nxpwifi_alloc_sdio_mpa_buffers(struct nxpwifi_adapter *adapter, + u32 mpa_tx_buf_size, + u32 mpa_rx_buf_size) +{ + struct sdio_mmc_card *card = adapter->card; + u32 rx_buf_size; + int ret = 0; + + card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); + if (!card->mpa_tx.buf) { + ret = -ENOMEM; + goto error; + } + + card->mpa_tx.buf_size = mpa_tx_buf_size; + + rx_buf_size = max_t(u32, mpa_rx_buf_size, + (u32)SDIO_MAX_AGGR_BUF_SIZE); + card->mpa_rx.buf = kzalloc(rx_buf_size, GFP_KERNEL); + if (!card->mpa_rx.buf) { + ret = -ENOMEM; + goto error; + } + + card->mpa_rx.buf_size = rx_buf_size; + +error: + if (ret) { + kfree(card->mpa_tx.buf); + kfree(card->mpa_rx.buf); + card->mpa_tx.buf_size = 0; + card->mpa_rx.buf_size = 0; + card->mpa_tx.buf = NULL; + card->mpa_rx.buf = NULL; + } + + return ret; +} + +/* This function unregisters the SDIO device. + * + * The function is disabled and driver + * data is set to null. + */ +static void +nxpwifi_unregister_dev(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + if (adapter->card) { + card->adapter = NULL; + sdio_claim_host(card->func); + sdio_disable_func(card->func); + sdio_release_host(card->func); + } +} + +/* This function registers the SDIO device. + * + * SDIO IRQ is claimed, block size is set and driver data is initialized. + */ +static int nxpwifi_register_dev(struct nxpwifi_adapter *adapter) +{ + int ret; + struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; + const char *firmware = card->firmware; + + /* save adapter pointer in card */ + card->adapter = adapter; + adapter->tx_buf_size = card->tx_buf_size; + + sdio_claim_host(func); + + /* Set block size */ + ret = sdio_set_block_size(card->func, NXPWIFI_SDIO_BLOCK_SIZE); + sdio_release_host(func); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "cannot set SDIO block size\n"); + return ret; + } + + /* Select correct firmware (sdsd or sdiouart) firmware based on the strapping + * option + */ + if (card->firmware_sdiouart) { + u8 val; + + nxpwifi_read_reg(adapter, card->reg->host_strap_reg, &val); + if ((val & card->reg->host_strap_mask) == card->reg->host_strap_value) + firmware = card->firmware_sdiouart; + } + strscpy(adapter->fw_name, firmware, sizeof(adapter->fw_name)); + + if (card->fw_dump_enh) { + adapter->mem_type_mapping_tbl = generic_mem_type_map; + adapter->num_mem_types = 1; + } else { + adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; + adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); + } + + return 0; +} + +/* This function initializes the SDIO driver. + * + * The following initializations steps are followed - + * - Read the Host interrupt status register to acknowledge + * the first interrupt got from bootloader + * - Disable host interrupt mask register + * - Get SDIO port + * - Initialize SDIO variables in card + * - Allocate MP registers + * - Allocate MPA Tx and Rx buffers + */ +static int nxpwifi_init_sdio(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + const struct nxpwifi_sdio_card_reg *reg = card->reg; + int ret; + u8 sdio_ireg; + + sdio_set_drvdata(card->func, card); + + /* Read the host_int_status_reg for ACK the first interrupt got + * from the bootloader. If we don't do this we get a interrupt + * as soon as we register the irq. + */ + nxpwifi_read_reg(adapter, card->reg->host_int_status_reg, &sdio_ireg); + + /* Get SDIO ioport */ + if (nxpwifi_init_sdio_ioport(adapter)) + return -EIO; + + /* Initialize SDIO variables in card */ + card->mp_rd_bitmap = 0; + card->mp_wr_bitmap = 0; + card->curr_rd_port = reg->start_rd_port; + card->curr_wr_port = reg->start_wr_port; + + card->mp_data_port_mask = reg->data_port_mask; + + card->mpa_tx.buf_len = 0; + card->mpa_tx.pkt_cnt = 0; + card->mpa_tx.start_port = 0; + + card->mpa_tx.enabled = 1; + card->mpa_tx.pkt_aggr_limit = card->mp_agg_pkt_limit; + + card->mpa_rx.buf_len = 0; + card->mpa_rx.pkt_cnt = 0; + card->mpa_rx.start_port = 0; + + card->mpa_rx.enabled = 1; + card->mpa_rx.pkt_aggr_limit = card->mp_agg_pkt_limit; + + /* Allocate buffers for SDIO MP-A */ + card->mp_regs = kzalloc(reg->max_mp_regs, GFP_KERNEL); + if (!card->mp_regs) + return -ENOMEM; + + card->mpa_rx.len_arr = kcalloc(card->mp_agg_pkt_limit, + sizeof(*card->mpa_rx.len_arr), + GFP_KERNEL); + if (!card->mpa_rx.len_arr) { + kfree(card->mp_regs); + return -ENOMEM; + } + + ret = nxpwifi_alloc_sdio_mpa_buffers(adapter, + card->mp_tx_agg_buf_size, + card->mp_rx_agg_buf_size); + + /* Allocate 32k MPA Tx/Rx buffers if 64k memory allocation fails */ + if (ret && (card->mp_tx_agg_buf_size == NXPWIFI_MP_AGGR_BSIZE_MAX || + card->mp_rx_agg_buf_size == NXPWIFI_MP_AGGR_BSIZE_MAX)) { + /* Disable rx single port aggregation */ + adapter->host_disable_sdio_rx_aggr = true; + + ret = nxpwifi_alloc_sdio_mpa_buffers(adapter, + NXPWIFI_MP_AGGR_BSIZE_32K, + NXPWIFI_MP_AGGR_BSIZE_32K); + if (ret) { + /* Disable multi port aggregation */ + card->mpa_tx.enabled = 0; + card->mpa_rx.enabled = 0; + } + } + + adapter->ext_scan = card->can_ext_scan; + return ret; +} + +/* This function resets the MPA Tx and Rx buffers. + */ +static void nxpwifi_cleanup_mpa_buf(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + MP_TX_AGGR_BUF_RESET(card); + MP_RX_AGGR_BUF_RESET(card); +} + +/* This function cleans up the allocated card buffers. + * + * The following are freed by this function - + * - MP registers + * - MPA Tx buffer + * - MPA Rx buffer + */ +static void nxpwifi_cleanup_sdio(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + cancel_work_sync(&card->work); + + kfree(card->mp_regs); + kfree(card->mpa_rx.len_arr); + kfree(card->mpa_tx.buf); + kfree(card->mpa_rx.buf); +} + +/* This function updates the MP end port in card. + */ +static void +nxpwifi_update_mp_end_port(struct nxpwifi_adapter *adapter, u16 port) +{ + struct sdio_mmc_card *card = adapter->card; + const struct nxpwifi_sdio_card_reg *reg = card->reg; + int i; + + card->mp_end_port = port; + + card->mp_data_port_mask = reg->data_port_mask; + + if (reg->start_wr_port) { + for (i = 1; i <= card->max_ports - card->mp_end_port; i++) + card->mp_data_port_mask &= + ~(1 << (card->max_ports - i)); + } + + card->curr_wr_port = reg->start_wr_port; + + nxpwifi_dbg(adapter, CMD, + "cmd: mp_end_port %d, data port mask 0x%x\n", + port, card->mp_data_port_mask); +} + +static void nxpwifi_sdio_card_reset_work(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; + int ret; + + /* Prepare the adapter for the reset. */ + nxpwifi_shutdown_sw(adapter); + clear_bit(NXPWIFI_IFACE_WORK_DEVICE_DUMP, &card->work_flags); + clear_bit(NXPWIFI_IFACE_WORK_CARD_RESET, &card->work_flags); + + /* Run a HW reset of the SDIO interface. */ + sdio_claim_host(func); + ret = mmc_hw_reset(func->card); + sdio_release_host(func); + + switch (ret) { + case 1: + dev_dbg(&func->dev, "SDIO HW reset asynchronous\n"); + complete_all(adapter->fw_done); + break; + case 0: + ret = nxpwifi_reinit_sw(adapter); + if (ret) + dev_err(&func->dev, "reinit failed: %d\n", ret); + break; + default: + dev_err(&func->dev, "SDIO HW reset failed: %d\n", ret); + break; + } +} + +/* This function read/write firmware */ +static enum +rdwr_status nxpwifi_sdio_rdwr_firmware(struct nxpwifi_adapter *adapter, + u8 doneflag) +{ + struct sdio_mmc_card *card = adapter->card; + int ret, tries; + u8 ctrl_data = 0; + + sdio_writeb(card->func, card->reg->fw_dump_host_ready, + card->reg->fw_dump_ctrl, &ret); + if (ret) { + nxpwifi_dbg(adapter, ERROR, "SDIO Write ERR\n"); + return RDWR_STATUS_FAILURE; + } + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl, + &ret); + if (ret) { + nxpwifi_dbg(adapter, ERROR, "SDIO read err\n"); + return RDWR_STATUS_FAILURE; + } + if (ctrl_data == FW_DUMP_DONE) + break; + if (doneflag && ctrl_data == doneflag) + return RDWR_STATUS_DONE; + if (ctrl_data != card->reg->fw_dump_host_ready) { + nxpwifi_dbg(adapter, WARN, + "The ctrl reg was changed, re-try again\n"); + sdio_writeb(card->func, card->reg->fw_dump_host_ready, + card->reg->fw_dump_ctrl, &ret); + if (ret) { + nxpwifi_dbg(adapter, ERROR, "SDIO write err\n"); + return RDWR_STATUS_FAILURE; + } + } + usleep_range(100, 200); + } + if (ctrl_data == card->reg->fw_dump_host_ready) { + nxpwifi_dbg(adapter, ERROR, + "Fail to pull ctrl_data\n"); + return RDWR_STATUS_FAILURE; + } + + return RDWR_STATUS_SUCCESS; +} + +/* This function dump firmware memory to file */ +static void nxpwifi_sdio_fw_dump(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + unsigned int reg, reg_start, reg_end; + u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0; + enum rdwr_status stat; + u32 memory_size; + + if (!card->can_dump_fw) + return; + + for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) { + struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + + if (entry->mem_ptr) { + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + } + entry->mem_size = 0; + } + + nxpwifi_pm_wakeup_card(adapter); + sdio_claim_host(card->func); + + nxpwifi_dbg(adapter, MSG, "== nxpwifi firmware dump start ==\n"); + + stat = nxpwifi_sdio_rdwr_firmware(adapter, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + reg = card->reg->fw_dump_start; + /* Read the number of the memories which will dump */ + dump_num = sdio_readb(card->func, reg, &ret); + if (ret) { + nxpwifi_dbg(adapter, ERROR, "SDIO read memory length err\n"); + goto done; + } + + /* Read the length of every memory which will dump */ + for (idx = 0; idx < dump_num; idx++) { + struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + + stat = nxpwifi_sdio_rdwr_firmware(adapter, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + memory_size = 0; + reg = card->reg->fw_dump_start; + for (i = 0; i < 4; i++) { + read_reg = sdio_readb(card->func, reg, &ret); + if (ret) { + nxpwifi_dbg(adapter, ERROR, "SDIO read err\n"); + goto done; + } + memory_size |= (read_reg << i * 8); + reg++; + } + + if (memory_size == 0) { + nxpwifi_dbg(adapter, DUMP, "Firmware dump Finished!\n"); + ret = nxpwifi_write_reg(adapter, + card->reg->fw_dump_ctrl, + FW_DUMP_READ_DONE); + if (ret) { + nxpwifi_dbg(adapter, ERROR, "SDIO write err\n"); + return; + } + break; + } + + nxpwifi_dbg(adapter, DUMP, + "%s_SIZE=0x%x\n", entry->mem_name, memory_size); + entry->mem_ptr = vmalloc(memory_size + 1); + entry->mem_size = memory_size; + if (!entry->mem_ptr) + goto done; + dbg_ptr = entry->mem_ptr; + end_ptr = dbg_ptr + memory_size; + + doneflag = entry->done_flag; + nxpwifi_dbg(adapter, DUMP, + "Start %s output, please wait...\n", + entry->mem_name); + + do { + stat = nxpwifi_sdio_rdwr_firmware(adapter, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + reg_start = card->reg->fw_dump_start; + reg_end = card->reg->fw_dump_end; + for (reg = reg_start; reg <= reg_end; reg++) { + *dbg_ptr = sdio_readb(card->func, reg, &ret); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "SDIO read err\n"); + goto done; + } + if (dbg_ptr < end_ptr) + dbg_ptr++; + else + nxpwifi_dbg(adapter, ERROR, + "Allocated buf not enough\n"); + } + + if (stat != RDWR_STATUS_DONE) + continue; + + nxpwifi_dbg(adapter, DUMP, "%s done: size=0x%tx\n", + entry->mem_name, dbg_ptr - entry->mem_ptr); + break; + } while (1); + } + nxpwifi_dbg(adapter, MSG, "== nxpwifi firmware dump end ==\n"); + +done: + sdio_release_host(card->func); +} + +static void nxpwifi_sdio_generic_fw_dump(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + struct memory_type_mapping *entry = &generic_mem_type_map[0]; + unsigned int reg, reg_start, reg_end; + u8 start_flag = 0, done_flag = 0; + u8 *dbg_ptr, *end_ptr; + enum rdwr_status stat; + int ret = -EPERM, tries; + + if (!card->fw_dump_enh) + return; + + if (entry->mem_ptr) { + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + } + entry->mem_size = 0; + + nxpwifi_pm_wakeup_card(adapter); + sdio_claim_host(card->func); + + nxpwifi_dbg(adapter, MSG, "== nxpwifi firmware dump start ==\n"); + + stat = nxpwifi_sdio_rdwr_firmware(adapter, done_flag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + reg_start = card->reg->fw_dump_start; + reg_end = card->reg->fw_dump_end; + for (reg = reg_start; reg <= reg_end; reg++) { + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + start_flag = sdio_readb(card->func, reg, &ret); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "SDIO read err\n"); + goto done; + } + if (start_flag == 0) + break; + if (tries == MAX_POLL_TRIES) { + nxpwifi_dbg(adapter, ERROR, + "FW not ready to dump\n"); + ret = -EPERM; + goto done; + } + } + usleep_range(100, 200); + } + + entry->mem_ptr = vmalloc(0xf0000 + 1); + if (!entry->mem_ptr) { + ret = -ENOMEM; + goto done; + } + dbg_ptr = entry->mem_ptr; + entry->mem_size = 0xf0000; + end_ptr = dbg_ptr + entry->mem_size; + + done_flag = entry->done_flag; + nxpwifi_dbg(adapter, DUMP, + "Start %s output, please wait...\n", entry->mem_name); + + while (true) { + stat = nxpwifi_sdio_rdwr_firmware(adapter, done_flag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + for (reg = reg_start; reg <= reg_end; reg++) { + *dbg_ptr = sdio_readb(card->func, reg, &ret); + if (ret) { + nxpwifi_dbg(adapter, ERROR, + "SDIO read err\n"); + goto done; + } + dbg_ptr++; + if (dbg_ptr >= end_ptr) { + u8 *tmp_ptr; + + tmp_ptr = vmalloc(entry->mem_size + 0x4000 + 1); + if (!tmp_ptr) + goto done; + + memcpy(tmp_ptr, entry->mem_ptr, + entry->mem_size); + vfree(entry->mem_ptr); + entry->mem_ptr = tmp_ptr; + tmp_ptr = NULL; + dbg_ptr = entry->mem_ptr + entry->mem_size; + entry->mem_size += 0x4000; + end_ptr = entry->mem_ptr + entry->mem_size; + } + } + if (stat == RDWR_STATUS_DONE) { + entry->mem_size = dbg_ptr - entry->mem_ptr; + nxpwifi_dbg(adapter, DUMP, "dump %s done size=0x%x\n", + entry->mem_name, entry->mem_size); + ret = 0; + break; + } + } + nxpwifi_dbg(adapter, MSG, "== nxpwifi firmware dump end ==\n"); + +done: + if (ret) { + nxpwifi_dbg(adapter, ERROR, "firmware dump failed\n"); + if (entry->mem_ptr) { + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + } + entry->mem_size = 0; + } + sdio_release_host(card->func); +} + +static void nxpwifi_sdio_device_dump_work(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + adapter->devdump_data = vzalloc(NXPWIFI_FW_DUMP_SIZE); + if (!adapter->devdump_data) + return; + + nxpwifi_drv_info_dump(adapter); + if (card->fw_dump_enh) + nxpwifi_sdio_generic_fw_dump(adapter); + else + nxpwifi_sdio_fw_dump(adapter); + nxpwifi_prepare_fw_dump_info(adapter); + nxpwifi_upload_device_dump(adapter); +} + +static void nxpwifi_sdio_work(struct work_struct *work) +{ + struct sdio_mmc_card *card = + container_of(work, struct sdio_mmc_card, work); + + if (test_and_clear_bit(NXPWIFI_IFACE_WORK_DEVICE_DUMP, + &card->work_flags)) + nxpwifi_sdio_device_dump_work(card->adapter); + if (test_and_clear_bit(NXPWIFI_IFACE_WORK_CARD_RESET, + &card->work_flags)) + nxpwifi_sdio_card_reset_work(card->adapter); +} + +/* This function resets the card */ +static void nxpwifi_sdio_card_reset(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + if (!test_and_set_bit(NXPWIFI_IFACE_WORK_CARD_RESET, &card->work_flags)) + nxpwifi_queue_work(adapter, &card->work); +} + +/* This function dumps FW information */ +static void nxpwifi_sdio_device_dump(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + if (!test_and_set_bit(NXPWIFI_IFACE_WORK_DEVICE_DUMP, + &card->work_flags)) + nxpwifi_queue_work(adapter, &card->work); +} + +/* Function to dump SDIO function registers and SDIO scratch registers in case + * of FW crash + */ +static int +nxpwifi_sdio_reg_dump(struct nxpwifi_adapter *adapter, char *drv_buf) +{ + char *p = drv_buf; + struct sdio_mmc_card *cardp = adapter->card; + int ret = 0; + u8 count, func, data, index = 0, size = 0; + u8 reg, reg_start, reg_end; + char buf[256], *ptr; + + if (!p) + return 0; + + nxpwifi_dbg(adapter, MSG, "SDIO register dump start\n"); + + nxpwifi_pm_wakeup_card(adapter); + + sdio_claim_host(cardp->func); + + for (count = 0; count < 5; count++) { + memset(buf, 0, sizeof(buf)); + ptr = buf; + + switch (count) { + case 0: + /* Read the registers of SDIO function0 */ + func = count; + reg_start = 0; + reg_end = 9; + break; + case 1: + /* Read the registers of SDIO function1 */ + func = count; + reg_start = cardp->reg->func1_dump_reg_start; + reg_end = cardp->reg->func1_dump_reg_end; + break; + case 2: + index = 0; + func = 1; + reg_start = cardp->reg->func1_spec_reg_table[index++]; + size = cardp->reg->func1_spec_reg_num; + reg_end = cardp->reg->func1_spec_reg_table[size - 1]; + break; + default: + /* Read the scratch registers of SDIO function1 */ + if (count == 4) + mdelay(100); + func = 1; + reg_start = cardp->reg->func1_scratch_reg; + reg_end = reg_start + NXPWIFI_SDIO_SCRATCH_SIZE; + } + + if (count != 2) + ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", + func, reg_start, reg_end); + else + ptr += sprintf(ptr, "SDIO Func%d: ", func); + + for (reg = reg_start; reg <= reg_end;) { + if (func == 0) + data = sdio_f0_readb(cardp->func, reg, &ret); + else + data = sdio_readb(cardp->func, reg, &ret); + + if (count == 2) + ptr += sprintf(ptr, "(%#x) ", reg); + if (!ret) { + ptr += sprintf(ptr, "%02x ", data); + } else { + ptr += sprintf(ptr, "ERR"); + break; + } + + if (count == 2 && reg < reg_end) + reg = cardp->reg->func1_spec_reg_table[index++]; + else + reg++; + } + + nxpwifi_dbg(adapter, MSG, "%s\n", buf); + p += sprintf(p, "%s\n", buf); + } + + sdio_release_host(cardp->func); + + nxpwifi_dbg(adapter, MSG, "SDIO register dump end\n"); + + return p - drv_buf; +} + +/* sdio device/function initialization, code is extracted + * from init_if handler and register_dev handler. + */ +static void nxpwifi_sdio_up_dev(struct nxpwifi_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + u8 sdio_ireg; + + sdio_claim_host(card->func); + sdio_enable_func(card->func); + sdio_set_block_size(card->func, NXPWIFI_SDIO_BLOCK_SIZE); + sdio_release_host(card->func); + + /* tx_buf_size might be changed to 3584 by firmware during + * data transfer, we will reset to default size. + */ + adapter->tx_buf_size = card->tx_buf_size; + + /* Read the host_int_status_reg for ACK the first interrupt got + * from the bootloader. If we don't do this we get a interrupt + * as soon as we register the irq. + */ + nxpwifi_read_reg(adapter, card->reg->host_int_status_reg, &sdio_ireg); + + if (nxpwifi_init_sdio_ioport(adapter)) + dev_err(&card->func->dev, "error enabling SDIO port\n"); +} + +static struct nxpwifi_if_ops sdio_ops = { + .init_if = nxpwifi_init_sdio, + .cleanup_if = nxpwifi_cleanup_sdio, + .check_fw_status = nxpwifi_check_fw_status, + .check_winner_status = nxpwifi_check_winner_status, + .prog_fw = nxpwifi_prog_fw_w_helper, + .register_dev = nxpwifi_register_dev, + .unregister_dev = nxpwifi_unregister_dev, + .enable_int = nxpwifi_sdio_enable_host_int, + .disable_int = nxpwifi_sdio_disable_host_int, + .process_int_status = nxpwifi_process_int_status, + .host_to_card = nxpwifi_sdio_host_to_card, + .wakeup = nxpwifi_pm_wakeup_card, + .wakeup_complete = nxpwifi_pm_wakeup_card_complete, + + /* SDIO specific */ + .update_mp_end_port = nxpwifi_update_mp_end_port, + .cleanup_mpa_buf = nxpwifi_cleanup_mpa_buf, + .cmdrsp_complete = nxpwifi_sdio_cmdrsp_complete, + .event_complete = nxpwifi_sdio_event_complete, + .dnld_fw = nxpwifi_sdio_dnld_fw, + .card_reset = nxpwifi_sdio_card_reset, + .reg_dump = nxpwifi_sdio_reg_dump, + .device_dump = nxpwifi_sdio_device_dump, + .deaggr_pkt = nxpwifi_deaggr_sdio_pkt, + .up_dev = nxpwifi_sdio_up_dev, +}; + +module_driver(nxpwifi_sdio, sdio_register_driver, sdio_unregister_driver); + +MODULE_AUTHOR("NXP International Ltd."); +MODULE_DESCRIPTION("NXP WiFi SDIO Driver version " SDIO_VERSION); +MODULE_VERSION(SDIO_VERSION); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(IW61X_SDIO_FW_NAME); From patchwork Fri Aug 9 09:45:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818385 Received: from DUZPR83CU001.outbound.protection.outlook.com (mail-northeuropeazon11013017.outbound.protection.outlook.com [52.101.67.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BD6141993B8; Fri, 9 Aug 2024 09:47:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.67.17 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196856; cv=fail; b=ELGHwiERkqO/kKXo948f+oqpmPYrlsOXRJMSDrXBME8k3/ToMSrKdrmA0orM5ztkPneDntT7z1nFNMkGcirt70oneLxyzrL6zEYP+iidJ/Nt4IW/n9Y8FvynFknjF4yRBWAFyB47CCqx5gk4zXfXKT4DD4y5i9AMLlaPbVDM32A= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196856; c=relaxed/simple; bh=DCwTnVB3QlB/eS0QSPmcBDEI3KgoxehEPKS7GWgAOuI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=n1y6IFquh7m9GnuD2IBOzOV7/D4ko1vOPgSghDHOpiaA+GNktD2yf+bOxvvB9T+c1h+G7WxthjK9iYqZkHPWP09jPvYzg7kONt8aEwjdSrctDsjM/zizTf3khcMfUbW8OiwiVwjTR9ihk+y1g/zF3yb8Osnx3QbciyuFW5YnF78= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=RALnBJII; arc=fail smtp.client-ip=52.101.67.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="RALnBJII" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=cYrBsRRbz3J02lbrCJtKxPMphED6gK/yOFmp1e1+bU+yL3ZsbgcXqggj1SnboV8MxihdxGEjR0Qb6othv4s4jwYYtf9t0bRVkAqrVk/ij/2W2WaIO61DYwJT8DImZGx0kGrKwpvPWCRuY22oieR6KI8liRkHhLJxA/mBh2D6jV/4is26usJD/h7qvzQVsLW8gEmGXHSBVDsFCdYbr3gtMSIIDJYf1aogOYVqgQh0pkqWZsp6a8Azqw/irpjlvSlyZ1jJr/WbaAkL3G8j52l1zaAatuHqGnjB2bUITDZrqk5/eM+jZwfJnvY8ERj0eeQDqUECXOX3Yur+BexrofYOxQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=mazPM+XPfTLPhbUwAP6PEzMSUhyWb3BuoHixzO33xNI=; b=jzR6gJiCrHJYD6DuJe3UQag53AMo1Rv/ETA3PpoQw9LMt6xGnaYxlNiZmrUKjOw+6Wt27NSbuPJ6b/nL9tAbzqJgLw6wr9aD6nQrUIC2dD1pUVxZUJizDd2tIaRa1HzZAtsgH+9n2a8cJOCDAbgNjab12KN8aZke6c9vo3DAfAVIs8XtPT/1rHZyr5EjudBPj+UJt7sGwAgFGEE8aVazp2eGp0nzh2zfEv6ONDbFmYutF62kxuSrIKFhSTlJdkmsWonZEjHHl4qKVNhEzfOt33gcAEnz/MrUCIXynjygtsly+G+ziy4RyEL8Nd+HjkoJF/56fEqx7FzOUpPWDcHZjQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=mazPM+XPfTLPhbUwAP6PEzMSUhyWb3BuoHixzO33xNI=; b=RALnBJIIOCHgreMFuMOxHEpg+RP6G8mD8fQRTwTofodTz5CORT1Q6mWpWh9Zrr6dV2S0McSY9JJa+5073FY+eseY0v8fzt5YAlpC3TRciPfufaLFX59Y1gOaycGSyO03H1WIxfcfaZ5dzj12dpgf3jHLuk2maM6eFu2/7FDc+EhaVbEHwDcwjLNzpDWTHTlm4dSw/J8VYJcUZv6c5jrcZiru3brjMp6GKTJj1odhHM1c3hSHjUMyJn1/6kGnvGSU9uU/f9+MQA/xnoxgXw7KCMr9Y5B+0MbB+dU/LB9x1QKkLuFDiJ3utu00ewplSAkyb1DPoY6b9JNsF+/TJ23yZA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GVXPR04MB9949.eurprd04.prod.outlook.com (2603:10a6:150:112::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:47:20 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:47:20 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 27/43] wifi: nxpwifi: add sdio.h Date: Fri, 9 Aug 2024 17:45:17 +0800 Message-Id: <20240809094533.1660-28-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GVXPR04MB9949:EE_ X-MS-Office365-Filtering-Correlation-Id: a7e7692b-fc04-499f-e8bf-08dcb85842eb X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|1800799024|52116014; X-Microsoft-Antispam-Message-Info: QTWoNaKQnHL2hI4GxUIQ5yVI1CcO/e84SeUgAZv9syxR3I95snrjvFVxomoFVArYMrxvGkKEl7cWA90mL/fY5ok1seolJGYpUtoPTYjLpSqjJFL6gU9qSlzdVET7cRv6+7ghI+L8K3xM0NEq4BdJcN5M9HRbHpOtCuzxFcj3Bu5JZoMEsztKAbn6YoxyNhHuYIEyeypjKzdJaelJBjkEgw++YN434f8PPVK0PaEznxGkFM9XzCVpUiGc3m5YqRzxhAIrRMH8+jJGFwfocdRDHVGVKkvQDPbx/BGwdhAk0u38+RAEsqmMKPWBvo9dEM3rJFUgBRPp7dFA2F+EzBranIaYTUVdqQDh2QZKFhDhrKM05ss3jkzOX25jQMszO9szSp/5C+BwmGBh9O7hWST8k+/owtjf0YsDxq/a7Rb5Q0gBtPkXiwVeNmQDrJr0Fw3HpgGTvSTEu8WsyOTPsKrVt/YVb+qmy+QZNMqBidHXkjsTnvalb3nCJE7+FwScr4pNkFPcXRE9h5sC80DNrKg1zPPCU9jXL5yI/QpbBgM83dtHlVMZMymazMMaiuRySAuHFpLmSzDjO6bPeQyOpNiHMVd+vlPhQddAhb2xFyM5xCJsMp3PksIPCLVIQCmfHx58YGmqCSGT4FT872Sz9t6wuTj9i39ZZ5TT0fUwCvFfTjUBvvnd3pRb+VrzH2PEVyb8S9vN4t1CD9xeDF8c6pogV1eTiRe0uvR4G6LFUAnVl9LcicTexQFnkWTbyW05RKN+p6JFiF1GnPxtbtUsB1i3gKkexoF/dJjfoNw5jYWKPkEwQAzOzluBI89TKDgd0vB0HRmm02xfspvrr1nQu61Defb1aca4aLCXGxG84zUTv5fKG//WLwNwI8KpsZKOqllOxC/qQgWmO8AfzBGWFnY4F3WaaOhZp4aBHERW6ZxzGcFWkPU0K/fta5eW6w/GQW3Zq6qF6NcQNEpgLBkB9n0UpKZvI2a64KJqT/7YgrZgozf44XKqRkApo+b+SpNfVd/vqB84iYw3Vxem++2QYf1LOubGzQwFnxyUCCLZOWL9/2nFDRiTD4kcL/5hKvvpCcoJR2RerfOskafGmiQuXg2PUtr0E+uUTjJ6ZCLNwMOQr+M4pqAM/Jcuc30d5GNnwtlQAWVgsbGqtzNQzEMvh55mGH15yt5073vn71tvi8Km76sQOdVHqi/hW/QXGxre6YdZ2QhuK3+ghG8fXSY4gjGaE2IeV83s279CtgJMpHGMZympOMUEQLD+KcSSn3I/l/beAVO3k8C0DFDru0tM64Ug+45gMfL10DiomwhT+aRVeOeQjpDQ7BVshfrRv7IYTw0Z/1O1wvfQ3s9iW/CPGzt+RA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(1800799024)(52116014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: DIdBi7b/uKINwYBjCeeZFPqq9FCnhVZU9Nt+1ZEWFzcPciZHT2Qcj4ohQTQSx+pYYfBOAI41L6j7iuoO4cCaWapqbgGSNXsjU5hbItDdMREnt2Tbc75tXoEQ0SfFpY5Gd6DokXQgfcNoHSzmAzSC7r6XKOA3jQPBP6piqGWu5mltR8f05L1IXDTm1HkdkFc/AzhQVDQkM4QNqPrHtLY4V5lC93DaHYa6exDIs41hN6bwTAV+IjH2gtXQo0cwUXjMospfrJpGhZU57e2/DnPeeG7TtzgPEG4tl2byIRH4MkP2wlwILCqBejDsxFekbldS9tyyqZt/yS1+2cLhdbun79eiG0f7Ffa3wnEvE+QRS+YOeFwsXz6OBrvIdq8Dtjw5WRX1UL1X3TBo4c1NikwK2AyJoVGhmp3A6p9Juhi2ENeNYW2xXgCH7obZzcidlFjCIbWJ2G8an3Gn9nphFHy2Las2ZDMotGOiHe2F2qKg3eAUHpLIhG47vjr4IojCZ601f14wwdszfwBydT7M6XmLHd1jduFwavBFGa26lChmGq0njsnq9jhjvWKmvYcQrhF4O5Lr4wlcwNn2lq2ke295MOw/dgM+MGI7tONrbLpm0t9OpsKzZ8e5m/QvCtanzg6xUNiCdIsmtisqayfYAUGhvKuzDAa7wUxI+DgKEcq8XcYkRK85kHZ+LN6hdqGtXdBQL1ubpw4De0RZCmw+eJeVkweW/IXuViqrHZCMVwsbWbztOAfZkY4nEtDZ/61aPn/ftyDqTBcZvVtsYeM0rvr7WrpNtuy9gQ4kwY4Gky7tBXrKxCi4fXFbNwfQp5T4KNHwusALe8S8YQAP73VKh9i+C0fLBKQdpcOTddW5XAHe1RmapRxQWdpaDmoZQJwj+BCHhDs/hEpc1gM5snFw/AYj76SHu32JMro74Ax8VSGxUd78oE/yHWfN3urrJjO/pfDCZxBNdwz6i3l66SaMj3d6gX47IrgriED+aU+Ec45YBqh/d3auoWFhW9YCqX2Fnu687YKLQoNlFrGgjgM+7rwuvv2Y7Xpr4MExYwUYrcaFb14tZo/y1p5un/Ytw7X49+yHvjuJd65KXozfngir+NGiy+Y39qEMdRen6C8Lg8gVFLOdvKgF/yqDdGQIRRP4/UxySt5J/WdWVDQDyrCCJNaXoBkUmjQun0g4L4ZYwCMwOVhVWESKs56Y6cwk9FIX2bjOY0KGfsOswVah5eHUDDDi+xmagcM2yb65Io0ZDnsJ2zWEwqB2Tef3Z+RiqYhhVUHHH3jC0qU8Q4nLhvsWhR3y+0VK5RHnMZggo5tBNpK1Zm92GkIXX7KsPzEi5iURjyUg7z0IhQCBW/dvGGb2bxQOkQitCP8ridDz0wDY246h/MiChlt9WLz8v7ZWjijvTxcSsYQyYHwm8duydtNmsSVGSwu8Ggg1wPAKQYj1zTlEHEAaN+M2DI5kXrT8tAaBJYgLa1idbLzx/MpvW+cIc97UGba1BmOZNmfCT0SkCknthNAohvQPr8KE6LQ8iW4EUL1ZK7DLUMI4I0J+KjMI+OUN5yGqDNzeKYyhpLI/g00KGurJSFDqlp3SQvxa04oxWgdrDHJ7BqWh4wwuNkpJH9iGJQOP2xgwTYf+SGRsnnz2tq6OQ7ZAr4kAAz/5dTVR3f6g X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: a7e7692b-fc04-499f-e8bf-08dcb85842eb X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:47:20.2537 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Pdb3IS9uvLevAoZBCT1rNU2ysAi/MtBWETQ9XbnCHOw8Qgurvpwfa9p5ueJI0NH+dahjFC4VjN4aLmzyGnE/Ag== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR04MB9949 --- drivers/net/wireless/nxp/nxpwifi/sdio.h | 340 ++++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/sdio.h diff --git a/drivers/net/wireless/nxp/nxpwifi/sdio.h b/drivers/net/wireless/nxp/nxpwifi/sdio.h new file mode 100644 index 000000000000..de5c884a5b14 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/sdio.h @@ -0,0 +1,340 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * NXP Wireless LAN device driver: SDIO specific definitions + * + * Copyright 2011-2024 NXP + */ + +#ifndef _NXPWIFI_SDIO_H +#define _NXPWIFI_SDIO_H + +#include "main.h" + +#define IW61X_SDIO_FW_NAME "nxp/sd_w61x_v1.bin.se" + +#define BLOCK_MODE 1 +#define BYTE_MODE 0 + +#define NXPWIFI_SDIO_IO_PORT_MASK 0xfffff + +#define NXPWIFI_SDIO_BYTE_MODE_MASK 0x80000000 + +#define NXPWIFI_MAX_FUNC2_REG_NUM 13 +#define NXPWIFI_SDIO_SCRATCH_SIZE 10 + +#define SDIO_MPA_ADDR_BASE 0x1000 + +#define CMD_PORT_UPLD_INT_MASK (0x1U << 6) +#define CMD_PORT_DNLD_INT_MASK (0x1U << 7) +#define HOST_TERM_CMD53 (0x1U << 2) +#define REG_PORT 0 +#define MEM_PORT 0x10000 + +#define CMD53_NEW_MODE (0x1U << 0) +#define CMD_PORT_RD_LEN_EN (0x1U << 2) +#define CMD_PORT_AUTO_EN (0x1U << 0) +#define CMD_PORT_SLCT 0x8000 +#define UP_LD_CMD_PORT_HOST_INT_STATUS (0x40U) +#define DN_LD_CMD_PORT_HOST_INT_STATUS (0x80U) + +#define NXPWIFI_MP_AGGR_BSIZE_32K (32768) +/* we leave one block of 256 bytes for DMA alignment*/ +#define NXPWIFI_MP_AGGR_BSIZE_MAX (65280) + +/* Misc. Config Register : Auto Re-enable interrupts */ +#define AUTO_RE_ENABLE_INT BIT(4) + +/* Host Control Registers : Configuration */ +#define CONFIGURATION_REG 0x00 +/* Host Control Registers : Host power up */ +#define HOST_POWER_UP (0x1U << 1) + +/* Host Control Registers : Upload host interrupt mask */ +#define UP_LD_HOST_INT_MASK (0x1U) +/* Host Control Registers : Download host interrupt mask */ +#define DN_LD_HOST_INT_MASK (0x2U) + +/* Host Control Registers : Upload host interrupt status */ +#define UP_LD_HOST_INT_STATUS (0x1U) +/* Host Control Registers : Download host interrupt status */ +#define DN_LD_HOST_INT_STATUS (0x2U) + +/* Host Control Registers : Host interrupt status */ +#define CARD_INT_STATUS_REG 0x28 + +/* Card Control Registers : Card I/O ready */ +#define CARD_IO_READY (0x1U << 3) +/* Card Control Registers : Download card ready */ +#define DN_LD_CARD_RDY (0x1U << 0) + +/* Max retry number of CMD53 write */ +#define MAX_WRITE_IOMEM_RETRY 2 + +/* SDIO Tx aggregation in progress ? */ +#define MP_TX_AGGR_IN_PROGRESS(a) ((a)->mpa_tx.pkt_cnt > 0) + +/* SDIO Tx aggregation buffer room for next packet ? */ +#define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ({ \ + typeof(a) (_a) = a; \ + (((_a)->mpa_tx.buf_len + (len)) <= (_a)->mpa_tx.buf_size); \ + }) + +/* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */ +#define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \ + typeof(a) (_a) = (a); \ + typeof(pkt_len) (_pkt_len) = pkt_len; \ + typeof(port) (_port) = port; \ + memmove(&(_a)->mpa_tx.buf[(_a)->mpa_tx.buf_len], \ + payload, (_pkt_len)); \ + (_a)->mpa_tx.buf_len += (_pkt_len); \ + if (!(_a)->mpa_tx.pkt_cnt) \ + (_a)->mpa_tx.start_port = (_port); \ + if ((_a)->mpa_tx.start_port <= (_port)) \ + (_a)->mpa_tx.ports |= (1 << ((_a)->mpa_tx.pkt_cnt)); \ + else \ + (_a)->mpa_tx.ports |= (1 << ((_a)->mpa_tx.pkt_cnt + 1 + \ + ((_a)->max_ports - \ + (_a)->mp_end_port))); \ + (_a)->mpa_tx.pkt_cnt++; \ +} while (0) + +/* SDIO Tx aggregation limit ? */ +#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) ({ \ + typeof(a) (_a) = a; \ + ((_a)->mpa_tx.pkt_cnt == (_a)->mpa_tx.pkt_aggr_limit); \ + }) + +/* Reset SDIO Tx aggregation buffer parameters */ +#define MP_TX_AGGR_BUF_RESET(a) do { \ + typeof(a) (_a) = (a); \ + (_a)->mpa_tx.pkt_cnt = 0; \ + (_a)->mpa_tx.buf_len = 0; \ + (_a)->mpa_tx.ports = 0; \ + (_a)->mpa_tx.start_port = 0; \ +} while (0) + +/* SDIO Rx aggregation limit ? */ +#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) ({ \ + typeof(a) (_a) = a; \ + ((_a)->mpa_rx.pkt_cnt == (_a)->mpa_rx.pkt_aggr_limit); \ + }) + +/* SDIO Rx aggregation in progress ? */ +#define MP_RX_AGGR_IN_PROGRESS(a) ((a)->mpa_rx.pkt_cnt > 0) + +/* SDIO Rx aggregation buffer room for next packet ? */ +#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) ({ \ + typeof(a) (_a) = a; \ + ((((_a)->mpa_rx.buf_len + (rx_len))) <= (_a)->mpa_rx.buf_size); \ + }) + +/* Reset SDIO Rx aggregation buffer parameters */ +#define MP_RX_AGGR_BUF_RESET(a) do { \ + typeof(a) (_a) = (a); \ + (_a)->mpa_rx.pkt_cnt = 0; \ + (_a)->mpa_rx.buf_len = 0; \ + (_a)->mpa_rx.ports = 0; \ + (_a)->mpa_rx.start_port = 0; \ +} while (0) + +/* data structure for SDIO MPA TX */ +struct nxpwifi_sdio_mpa_tx { + /* multiport tx aggregation buffer pointer */ + u8 *buf; + u32 buf_len; + u32 pkt_cnt; + u32 ports; + u16 start_port; + u8 enabled; + u32 buf_size; + u32 pkt_aggr_limit; +}; + +struct nxpwifi_sdio_mpa_rx { + u8 *buf; + u32 buf_len; + u32 pkt_cnt; + u32 ports; + u16 start_port; + u32 *len_arr; + u8 enabled; + u32 buf_size; + u32 pkt_aggr_limit; +}; + +int nxpwifi_bus_register(void); +void nxpwifi_bus_unregister(void); + +struct nxpwifi_sdio_card_reg { + u8 start_rd_port; + u8 start_wr_port; + u8 base_0_reg; + u8 base_1_reg; + u8 poll_reg; + u8 host_int_enable; + u8 host_int_rsr_reg; + u8 host_int_status_reg; + u8 host_int_mask_reg; + u8 host_strap_reg; + u8 host_strap_mask; + u8 host_strap_value; + u8 status_reg_0; + u8 status_reg_1; + u8 sdio_int_mask; + u32 data_port_mask; + u8 io_port_0_reg; + u8 io_port_1_reg; + u8 io_port_2_reg; + u8 max_mp_regs; + u8 rd_bitmap_l; + u8 rd_bitmap_u; + u8 rd_bitmap_1l; + u8 rd_bitmap_1u; + u8 wr_bitmap_l; + u8 wr_bitmap_u; + u8 wr_bitmap_1l; + u8 wr_bitmap_1u; + u8 rd_len_p0_l; + u8 rd_len_p0_u; + u8 card_misc_cfg_reg; + u8 card_cfg_2_1_reg; + u8 cmd_rd_len_0; + u8 cmd_rd_len_1; + u8 cmd_rd_len_2; + u8 cmd_rd_len_3; + u8 cmd_cfg_0; + u8 cmd_cfg_1; + u8 cmd_cfg_2; + u8 cmd_cfg_3; + u8 fw_dump_host_ready; + u8 fw_dump_ctrl; + u8 fw_dump_start; + u8 fw_dump_end; + u8 func1_dump_reg_start; + u8 func1_dump_reg_end; + u8 func1_scratch_reg; + u8 func1_spec_reg_num; + u8 func1_spec_reg_table[NXPWIFI_MAX_FUNC2_REG_NUM]; +}; + +struct sdio_mmc_card { + struct sdio_func *func; + struct nxpwifi_adapter *adapter; + + struct completion fw_done; + const char *firmware; + const char *firmware_sdiouart; + const struct nxpwifi_sdio_card_reg *reg; + u8 max_ports; + u8 mp_agg_pkt_limit; + u16 tx_buf_size; + u32 mp_tx_agg_buf_size; + u32 mp_rx_agg_buf_size; + + u32 mp_rd_bitmap; + u32 mp_wr_bitmap; + + u16 mp_end_port; + u32 mp_data_port_mask; + + u8 curr_rd_port; + u8 curr_wr_port; + + u8 *mp_regs; + bool can_dump_fw; + bool fw_dump_enh; + bool can_ext_scan; + + struct nxpwifi_sdio_mpa_tx mpa_tx; + struct nxpwifi_sdio_mpa_rx mpa_rx; + + struct work_struct work; + unsigned long work_flags; +}; + +struct nxpwifi_sdio_device { + const char *firmware; + const char *firmware_sdiouart; + const struct nxpwifi_sdio_card_reg *reg; + u8 max_ports; + u8 mp_agg_pkt_limit; + u16 tx_buf_size; + u32 mp_tx_agg_buf_size; + u32 mp_rx_agg_buf_size; + bool can_dump_fw; + bool fw_dump_enh; + bool can_ext_scan; +}; + +/* .cmdrsp_complete handler + */ +static inline int nxpwifi_sdio_cmdrsp_complete(struct nxpwifi_adapter *adapter, + struct sk_buff *skb) +{ + dev_kfree_skb_any(skb); + return 0; +} + +/* .event_complete handler + */ +static inline int nxpwifi_sdio_event_complete(struct nxpwifi_adapter *adapter, + struct sk_buff *skb) +{ + dev_kfree_skb_any(skb); + return 0; +} + +static inline bool +mp_rx_aggr_port_limit_reached(struct sdio_mmc_card *card) +{ + u8 tmp; + + if (card->curr_rd_port < card->mpa_rx.start_port) { + tmp = card->mp_end_port >> 1; + + if (((card->max_ports - card->mpa_rx.start_port) + + card->curr_rd_port) >= tmp) + return true; + } + + if ((card->curr_rd_port - card->mpa_rx.start_port) >= + (card->mp_end_port >> 1)) + return true; + + return false; +} + +static inline bool +mp_tx_aggr_port_limit_reached(struct sdio_mmc_card *card) +{ + u16 tmp; + + if (card->curr_wr_port < card->mpa_tx.start_port) { + tmp = card->mp_end_port >> 1; + + if (((card->max_ports - card->mpa_tx.start_port) + + card->curr_wr_port) >= tmp) + return true; + } + + if ((card->curr_wr_port - card->mpa_tx.start_port) >= + (card->mp_end_port >> 1)) + return true; + + return false; +} + +/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ +static inline void mp_rx_aggr_setup(struct sdio_mmc_card *card, + u16 rx_len, u8 port) +{ + card->mpa_rx.buf_len += rx_len; + + if (!card->mpa_rx.pkt_cnt) + card->mpa_rx.start_port = port; + + card->mpa_rx.ports |= (1 << port); + card->mpa_rx.len_arr[card->mpa_rx.pkt_cnt] = rx_len; + card->mpa_rx.pkt_cnt++; +} +#endif /* _NXPWIFI_SDIO_H */ From patchwork Fri Aug 9 09:45:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818271 Received: from DB3PR0202CU003.outbound.protection.outlook.com (mail-northeuropeazon11011015.outbound.protection.outlook.com [52.101.65.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D3E3019925B; Fri, 9 Aug 2024 09:47:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.65.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196853; cv=fail; b=uwVaym3lQA9qYsUirK3RjMrmtfCwztIpO9kgHbMycRr6OZb6gByLHzAebiDWxT4e4qTfwKFjXniQpjXMLNchbZGnUTYLCSnA4VnI3evATIkVZ3kDzg3xQ5sq83HIZpYJG1vqqGeJ3W6sRXIL86BqAagUCAn1h0H2txLfFgCJgPQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196853; c=relaxed/simple; bh=iiRPE9BO7GBA46vg5R1pXog4fvuY0yPClrA9jKkNGD0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=bDArBmuPHL0pKII5vZcrux/tBdKuY1uuj9qM088F0OpolWlqIdujuH9ofKhNyEBzAv5NXBWdpTNvTvf3kNolA7T+/6aHKhnStD7ZYPxC1WK7a4nryclAyVkLgOpDHJciiVoWW76j5Dup40h68uyAJ5MSLzO+Ac5SVAGp1GMwJcE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=Uw5qBRPy; arc=fail smtp.client-ip=52.101.65.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="Uw5qBRPy" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ISJZDwngbmXp0vWBKZjhmk+MMM5oOKvr5dlpBiE3lmvloZRwwGByqcGSaTTNmWAhrDkPAhf8h35Ct9sDKUKr1vvlabQUdaHFHJLiuTZuP5NlnG2NH8M7U6WWRBENgj18Xe9sGxOG3JtHbQqXtbeINihua5obApvkg9TNh4KvsSpt7+/Ro19I7I3mu5LwbilvWAXFy4qUSbOvRgkaU/igeAeJoG/uICaodpwojiZnD0eCI4hl/mWg4UF5l9cpi+AsauNONvotLMG90ULss4yKJL7MkeidkSSLXeEn50rMjUUYRNK7503x3duzAJY2v7n18dNcqHpTN43/t4aCHddSBQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ebtt6Jg/w20urXUJwQ5PxMsaKp49U7eC8wCDwgmiSj4=; b=RNMfs0gWhVo8yOEx1u6HFj7Y7MKnUybKXgw/1qwOcJuZYFqOIAlks+abwNg0IlxIZay5LTwEycOA5BwSSJ3e+/YDegtYDY3B5VKAMn2wI+2m65E+E3aQDKvUAuqucWTPiMDZ8qGJPyxtqcHLuGVb4BgZ6aUsYKFEO5ktvLzNCOY7UEFn5+b3wBpHX9JGfKT2jLLQsiCxIHOr/kM4cP10q7If1ikL2EZ591GQWX3h7OZAj5C2/bOXx00ftYBQFLuSXi6fz8M/FtRXcS4khoO6iUGT/cJuu93K9NsX13H5krMcivdBG3pAgA41fclNfXSvvLXyepRFA7VYtQgQh7Zgag== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ebtt6Jg/w20urXUJwQ5PxMsaKp49U7eC8wCDwgmiSj4=; b=Uw5qBRPyvwxUqp2ry6cfogO+YV/Z0FhasyFfkF4YXTs7jGyVf58/t+y+Nl8c2yEj65QzMwUGtNJjMZT08TWUqA81fLg4FIrDnDMV2Na7O6Y/joC7qVw2iS9Y523GzJ9SlyrDId2gPhDKh3oqhD/BU4wDvTNo4oyo72vR28To0rM0PXlzFxd6IdgwrAuTM6GhVEYUkO83O24krHNxFrLGmXMDCO2GOtJnuzozMLWyGZA3Vcgsu+zx6Kv79QbP+SO3+z18dbbzPJRtersRi3EQnUfO4njlBM5dFoAHQvYPUzasieCM6SY7UXBCkylPy/0JzH5sVNj0xYydMJoMxvwCWA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GV1PR04MB9120.eurprd04.prod.outlook.com (2603:10a6:150:27::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:47:24 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:47:23 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 28/43] wifi: nxpwifi: add sta_cfg.c Date: Fri, 9 Aug 2024 17:45:18 +0800 Message-Id: <20240809094533.1660-29-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GV1PR04MB9120:EE_ X-MS-Office365-Filtering-Correlation-Id: 90b6b9ab-1a26-4c90-cab8-08dcb85844e7 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|52116014|1800799024; X-Microsoft-Antispam-Message-Info: 1Tx2o3E254XeORnI7Bi8PO0CzPYMenRo9h7ERjLk9hCH38UwWaJLMmMDBM5hZ+dj65bi/IadYY0PAYo6IluVjv2vAsO+jfbbX31PdsVPVbmIc7cCmILXfbxKmExi+OcViQIXOJ3JjfsfMgyjGMno2irXN+PCA9shC8DDOFZWDAakrScGfT9aqeOUtjZcQKvRIXRv78mGyrF75b5JHuiSeMyuxo7uwtU7ji5mKexBOTHXcHwDCJyh2ySoIU2pXRzKertr56dAjHfXuUtEGfOINoXdoUexqSaJ4sI1zlyrM+bUC2l3hNloKAOYNdVU8zCL/+d64yQ4TPx2DCJ1dFObxfozISTto+yQtmNj9TK4VRgcDsenu3VKYsVi/WE6yTEqvPZFMDmnqzExibJjXnToznbZM0BGGSwCc2RQ1A8CTKpQ0LlrARchNYuxLQQza2AEP9UwBz0bk6RYoq8Dl0lvwuwGHKy2tqh5AzCDNlEJY4wwyqClY01HqQwc4m05FVTB8/FPWEkDl4Ce6tc9qKKpashAGMxbZQPZ3Qa/EpDtzYZHREL0kfw9VcgL1YglhplE/aXsz/hjf4DpMQCv9QZQADr8QNENWNENYc1x17EBydrRh0zuEOjwJvktziTLv4AZozSdMoRrBYGcb6e5KIq1XUCIW2+dUGMlFdm2FQ2+8yS7urhlRpxxulxj7yzkAlP1EOpDXC3WN+HpZ1VEecslOohKtlaFkYLyuXmiM0aLVa2+8DQGXAhW2Qomj+4lOUUz5GDux07UHkkIItRaQUFf2Zl8D6Ms0fz2cR+7WzsroEqPXXOB/brlC2ayZudIOmXdPsoMr/61lBtGrNMlUYBPPBs3HtowrgDlDX/82atSdu+ENnG71FW0izyhQaCZxd4GcXkU+QHVLJQYjGCv0CWqWJ/BWHI/BPZ1SVzn7bnngKJ2NFqbj5Ke47/MvWOCWTHbmZLqtSQ5G160Z20TmKEGqJp06WveNymfD4Dwpbhc+lb9V0y3Mf7spui16rk1FmzRUob1TJ4rg8ut74xs0hfUymR9kJe7XRiwWn2SqH/xGtWnS5x7fq/YHLeRQLiLPomEzz17t/5VOIC5IS/rQYlkK6j9adUcoS+myLy8qlrGDZYKBQOgcgA855bed1ishkC5R59YBZaNBTn2zFSvrDiEDDoCSdcVqNumI6YKfgpKEbk09LeQ1YlWu7sA6GmCIsaGUhaHIOMIy4JmvFynKg9j8vzWMvnk34IKMQlblWJFl2VyurLWQ5h4SpotSpoXyY5UxjQirA5jp74GQg+0MHiJ9VUu9YlY4IezrHbLCJikP7WnACqhn3RmjQiT+3dJ1p99Klmr0K96MD+Z/GK7RiGTWA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(52116014)(1800799024); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: eT44+gjFHYYF/34li9DU1wmmahp/osbfln7N/gBpRIhCzXqD1ztNjYgfS+zIVAYkmg4e/8i77u1YjONQgfYgB4shWYQQQCWYRLdWP/MqqnPdRo3qLDQaNS0xQBVdPkRKXR4oUYQXmylpF34NUFd4ZlkCkqVJB1za0aBVJasnkQDgHLOLw13TeTsCFLrhBb6t1SwQCNKQDH48CS1O8jBkVjqzdmaNrR6o/I4Osmq49wHne4DzrqCYFYWAqn8D7LbrZH0B7QbY4zGQtxNr+TGXWyM4PKtIhyeR/7Ts+l3ro03FOtNDScxawJJ5QVp5CFEwN0hD2Zcnwt+dR/gI9zUsAcPOBlQ0VFd58Z6XemUQR0NjxbbZwTa6e4bgct8UCy3BJETwk9CSVJJyespmgSqiAN5SxdL6p9LCk5a3ip4TurIaZRgPTGrzls/ZqPjHH6f0F48CCAIXxuJPUDx8NNoV5/mnvivqzHnRR+1Y4hRhhh3mf9hXryH1yAP3ESlGzEqCqm09Evxy1nUwOV1RG5CG69vNAitr2Hhg68JODOmQcHYY+rEg9G7WMKvOFz3HadjfKCvc1mcksMdEFo1bG9CF2PqtZ5P1dgzsiqHukpTL9zoglU+uuqA2pGHwLDtN2sngQCFzOyI+D6iSRN29cq5igjJ9JviPHtjmcXueuYq/TfBSX7EGevtHE2iHb863nIGoWfUXWDIec/hOFNo6vTIhShCwBaGPMfhpjzeLUVTKJ/HudBI7fLU2jAQkoPInL9TOjf/7nnfZ5xoJ8EpeqUwlM8vTd6ESjFQTSi5N6BHi5Krbf/it9fxGmnwmunOxIlPdF5BXPkAKPsMek1YEY0pLMDVQKwQhgfAqWNVwSzpVQ6vsg5qWyojB0wosHd054M+9tYNc35F85jwTRWumbeUfKzB3skeObvNd9/WumXzkozhJDfEV7EczAjEd1QEeUykw+WDoXLZ0RHujo9S75rX5lCqTOwthSCi5s9BCyqSjnB3WJzEzSoA1LM/wc2D7yED+PworxdUtYLbaQ6fZuS+XvNvPneu+n9MlNXbnelQ1Ur34Hv3sf9vDprDpfn0SpflrfM3Rl992KYLUi4vZZqhDYTWZRYfciKvu3MzWfKYDK8o1WiX8WCpbyUKJxx1Acg1GwBLku1IN9XGW7BGR/Q2LKl2GIDTYPpL38w0pbKA0XT7siE9vwjetYlthBb37GBpQcUxhsHRlJAhnHXYgFV2V5E0XliN/6EVEqO/ckkKuog8kVnxD8HZJ3xZ+tKR0cNkM2+htkPjDJHSaudoHaqpj/EEmU293v8quQTrRirzT5RYj/VTLJheX6ucfSBxbv1bHGSlKPvQ+F7dECXgSs1ftowgLjDtKCRqFhrpSrOt3ofrA1DKJqHtU4dgY163r5BX9GNr3RjqgwD66lhTG5vC5TKrFf2zZO9Tfs3Cf6/aS0IGLhB7hLHimFK7ERoFjiThqHm+Rdjkw15FxNhxjSCHsm+mFti4+b8vbCA5kT7wz/nZwox9XBBM+2wEahIOdX/0RM1IZyD+E+rdTVtOzcoSxtJyEtEUmxU2k1m8upCmuvJIUW5/ot7+wexpnR1JTEsbdhdRNF60o/+kbm1IM40cYk03lmtlBPChQTfeI4uD87fr6YXe0UmltQyMAUFTcD8g4 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 90b6b9ab-1a26-4c90-cab8-08dcb85844e7 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:47:23.6349 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: MOZdXFo6L1L2mrEyECPsc78sXvEM3vVmc/tKqM2O6hfTJ38NkwOvWV+GbJfrFAQhPULj2wiCtffUUWLGoyQIJQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GV1PR04MB9120 --- drivers/net/wireless/nxp/nxpwifi/sta_cfg.c | 1307 ++++++++++++++++++++ 1 file changed, 1307 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/sta_cfg.c diff --git a/drivers/net/wireless/nxp/nxpwifi/sta_cfg.c b/drivers/net/wireless/nxp/nxpwifi/sta_cfg.c new file mode 100644 index 000000000000..b5531f9f4759 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/sta_cfg.c @@ -0,0 +1,1307 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: functions for station ioctl + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cmdevt.h" +#include "wmm.h" +#include "11n.h" +#include "cfg80211.h" + +static int disconnect_on_suspend; + +/* Copies the multicast address list from device to driver. + * + * This function does not validate the destination memory for + * size, and the calling function must ensure enough memory is + * available. + */ +int nxpwifi_copy_mcast_addr(struct nxpwifi_multicast_list *mlist, + struct net_device *dev) +{ + int i = 0; + struct netdev_hw_addr *ha; + + netdev_for_each_mc_addr(ha, dev) + memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN); + + return i; +} + +/* Wait queue completion handler. + * + * This function waits on a cmd wait queue. It also cancels the pending + * request after waking up, in case of errors. + */ +int nxpwifi_wait_queue_complete(struct nxpwifi_adapter *adapter, + struct cmd_ctrl_node *cmd_queued) +{ + int status; + + /* Wait for completion */ + status = wait_event_interruptible_timeout(adapter->cmd_wait_q.wait, + *cmd_queued->condition, + (12 * HZ)); + if (status <= 0) { + if (status == 0) + status = -ETIMEDOUT; + nxpwifi_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n", + status); + nxpwifi_cancel_all_pending_cmd(adapter); + return status; + } + + status = adapter->cmd_wait_q.status; + adapter->cmd_wait_q.status = 0; + + return status; +} + +/* This function prepares the correct firmware command and + * issues it to set the multicast list. + * + * This function can be used to enable promiscuous mode, or enable all + * multicast packets, or to enable selective multicast. + */ +int +nxpwifi_request_set_multicast_list(struct nxpwifi_private *priv, + struct nxpwifi_multicast_list *mcast_list) +{ + int ret = 0; + u16 old_pkt_filter; + + old_pkt_filter = priv->curr_pkt_filter; + + if (mcast_list->mode == NXPWIFI_PROMISC_MODE) { + nxpwifi_dbg(priv->adapter, INFO, + "info: Enable Promiscuous mode\n"); + priv->curr_pkt_filter |= HOST_ACT_MAC_PROMISCUOUS_ENABLE; + priv->curr_pkt_filter &= + ~HOST_ACT_MAC_ALL_MULTICAST_ENABLE; + } else { + /* Multicast */ + priv->curr_pkt_filter &= ~HOST_ACT_MAC_PROMISCUOUS_ENABLE; + if (mcast_list->mode == NXPWIFI_ALL_MULTI_MODE) { + nxpwifi_dbg(priv->adapter, INFO, + "info: Enabling All Multicast!\n"); + priv->curr_pkt_filter |= + HOST_ACT_MAC_ALL_MULTICAST_ENABLE; + } else { + priv->curr_pkt_filter &= + ~HOST_ACT_MAC_ALL_MULTICAST_ENABLE; + nxpwifi_dbg(priv->adapter, INFO, + "info: Set multicast list=%d\n", + mcast_list->num_multicast_addr); + /* Send multicast addresses to firmware */ + ret = nxpwifi_send_cmd(priv, + HOST_CMD_MAC_MULTICAST_ADR, + HOST_ACT_GEN_SET, 0, + mcast_list, false); + } + } + nxpwifi_dbg(priv->adapter, INFO, + "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", + old_pkt_filter, priv->curr_pkt_filter); + if (old_pkt_filter != priv->curr_pkt_filter) { + ret = nxpwifi_send_cmd(priv, HOST_CMD_MAC_CONTROL, + HOST_ACT_GEN_SET, + 0, &priv->curr_pkt_filter, false); + } + + return ret; +} + +/* This function fills bss descriptor structure using provided + * information. + * beacon_ie buffer is allocated in this function. It is caller's + * responsibility to free the memory. + */ +int nxpwifi_fill_new_bss_desc(struct nxpwifi_private *priv, + struct cfg80211_bss *bss, + struct nxpwifi_bssdescriptor *bss_desc) +{ + u8 *beacon_ie; + size_t beacon_ie_len; + struct nxpwifi_bss_priv *bss_priv = (void *)bss->priv; + const struct cfg80211_bss_ies *ies; + + rcu_read_lock(); + ies = rcu_dereference(bss->ies); + beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); + beacon_ie_len = ies->len; + bss_desc->timestamp = ies->tsf; + rcu_read_unlock(); + + if (!beacon_ie) { + nxpwifi_dbg(priv->adapter, ERROR, + " failed to alloc beacon_ie\n"); + return -ENOMEM; + } + + memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); + bss_desc->rssi = bss->signal; + /* The caller of this function will free beacon_ie */ + bss_desc->beacon_buf = beacon_ie; + bss_desc->beacon_buf_size = beacon_ie_len; + bss_desc->beacon_period = bss->beacon_interval; + bss_desc->cap_info_bitmap = bss->capability; + bss_desc->bss_band = bss_priv->band; + bss_desc->fw_tsf = bss_priv->fw_tsf; + if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { + nxpwifi_dbg(priv->adapter, INFO, + "info: InterpretIE: AP WEP enabled\n"); + bss_desc->privacy = NXPWIFI_802_11_PRIV_FILTER_8021X_WEP; + } else { + bss_desc->privacy = NXPWIFI_802_11_PRIV_FILTER_ACCEPT_ALL; + } + bss_desc->bss_mode = NL80211_IFTYPE_STATION; + + /* Disable 11ac by default. Enable it only where there + * exist VHT_CAP IE in AP beacon + */ + bss_desc->disable_11ac = true; + + if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT) + bss_desc->sensed_11h = true; + + return nxpwifi_update_bss_desc_with_ie(priv->adapter, bss_desc); +} + +void nxpwifi_dnld_txpwr_table(struct nxpwifi_private *priv) +{ + if (priv->adapter->dt_node) { + char txpwr[] = {"nxp,00_txpwrlimit"}; + + memcpy(&txpwr[8], priv->adapter->country_code, 2); + nxpwifi_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr); + } +} + +static int nxpwifi_process_country_ie(struct nxpwifi_private *priv, + struct cfg80211_bss *bss) +{ + const u8 *country_ie; + u8 country_ie_len; + struct nxpwifi_802_11d_domain_reg *domain_info = + &priv->adapter->domain_reg; + int ret; + + rcu_read_lock(); + country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); + if (!country_ie) { + rcu_read_unlock(); + return 0; + } + + country_ie_len = country_ie[1]; + if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) { + rcu_read_unlock(); + return 0; + } + + if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) { + rcu_read_unlock(); + nxpwifi_dbg(priv->adapter, INFO, + "11D: skip setting domain info in FW\n"); + return 0; + } + + if (country_ie_len > + (IEEE80211_COUNTRY_STRING_LEN + NXPWIFI_MAX_TRIPLET_802_11D)) { + rcu_read_unlock(); + nxpwifi_dbg(priv->adapter, ERROR, + "11D: country_ie_len overflow!, deauth AP\n"); + return -EINVAL; + } + + memcpy(priv->adapter->country_code, &country_ie[2], 2); + + domain_info->country_code[0] = country_ie[2]; + domain_info->country_code[1] = country_ie[3]; + domain_info->country_code[2] = ' '; + + country_ie_len -= IEEE80211_COUNTRY_STRING_LEN; + + domain_info->no_of_triplet = + country_ie_len / sizeof(struct ieee80211_country_ie_triplet); + + memcpy((u8 *)domain_info->triplet, + &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len); + + rcu_read_unlock(); + + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11D_DOMAIN_INFO, + HOST_ACT_GEN_SET, 0, NULL, false); + if (ret) + nxpwifi_dbg(priv->adapter, ERROR, + "11D: setting domain info in FW fail\n"); + else + nxpwifi_dnld_txpwr_table(priv); + + return ret; +} + +/* In infra mode, an deauthentication is performed + * first. + */ +int nxpwifi_bss_start(struct nxpwifi_private *priv, struct cfg80211_bss *bss, + struct cfg80211_ssid *req_ssid) +{ + int ret; + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_bssdescriptor *bss_desc = NULL; + u8 config_bands; + + priv->scan_block = false; + + if (adapter->region_code == 0x00 && + nxpwifi_process_country_ie(priv, bss)) + return -EINVAL; + + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(*bss_desc), GFP_KERNEL); + if (!bss_desc) + return -ENOMEM; + + ret = nxpwifi_fill_new_bss_desc(priv, bss, bss_desc); + if (ret) + goto done; + + if (nxpwifi_band_to_radio_type(bss_desc->bss_band) == + HOST_SCAN_RADIO_TYPE_BG) { + config_bands = BAND_B | BAND_G | BAND_GN; + } else { + config_bands = BAND_A | BAND_AN; + if (adapter->fw_bands & BAND_AAC) + config_bands |= BAND_AAC; + } + + if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands)) + adapter->config_bands = config_bands; + + ret = nxpwifi_check_network_compatibility(priv, bss_desc); + if (ret) + goto done; + + if (nxpwifi_11h_get_csa_closed_channel(priv) == (u8)bss_desc->channel) { + nxpwifi_dbg(adapter, ERROR, + "Attempt to reconnect on csa closed chan(%d)\n", + bss_desc->channel); + ret = -EINVAL; + goto done; + } + + nxpwifi_stop_net_dev_queue(priv->netdev, adapter); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + + /* Clear any past association response stored for + * application retrieval + */ + priv->assoc_rsp_size = 0; + ret = nxpwifi_associate(priv, bss_desc); + + /* If auth type is auto and association fails using open mode, + * try to connect using shared mode + */ + if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && + priv->sec_info.is_authtype_auto && + priv->sec_info.wep_enabled) { + priv->sec_info.authentication_mode = + NL80211_AUTHTYPE_SHARED_KEY; + ret = nxpwifi_associate(priv, bss_desc); + } + +done: + /* beacon_ie buffer was allocated in function + * nxpwifi_fill_new_bss_desc(). Free it now. + */ + if (bss_desc) + kfree(bss_desc->beacon_buf); + kfree(bss_desc); + + if (ret < 0) + priv->attempted_bss_desc = NULL; + + return ret; +} + +/* IOCTL request handler to set host sleep configuration. + * + * This function prepares the correct firmware command and + * issues it. + */ +int nxpwifi_set_hs_params(struct nxpwifi_private *priv, u16 action, + int cmd_type, struct nxpwifi_ds_hs_cfg *hs_cfg) + +{ + struct nxpwifi_adapter *adapter = priv->adapter; + int status = 0; + u32 prev_cond = 0; + + if (!hs_cfg) + return -ENOMEM; + + switch (action) { + case HOST_ACT_GEN_SET: + if (adapter->pps_uapsd_mode) { + nxpwifi_dbg(adapter, INFO, + "info: Host Sleep IOCTL\t" + "is blocked in UAPSD/PPS mode\n"); + status = -EPERM; + break; + } + if (hs_cfg->is_invoke_hostcmd) { + if (hs_cfg->conditions == HS_CFG_CANCEL) { + if (!test_bit(NXPWIFI_IS_HS_CONFIGURED, + &adapter->work_flags)) + /* Already cancelled */ + break; + /* Save previous condition */ + prev_cond = le32_to_cpu(adapter->hs_cfg + .conditions); + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + } else if (hs_cfg->conditions) { + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; + if (hs_cfg->gap) + adapter->hs_cfg.gap = (u8)hs_cfg->gap; + } else if (adapter->hs_cfg.conditions == + cpu_to_le32(HS_CFG_CANCEL)) { + /* Return failure if no parameters for HS + * enable + */ + status = -EINVAL; + break; + } + + status = nxpwifi_send_cmd(priv, + HOST_CMD_802_11_HS_CFG_ENH, + HOST_ACT_GEN_SET, 0, + &adapter->hs_cfg, + cmd_type == NXPWIFI_SYNC_CMD); + + if (hs_cfg->conditions == HS_CFG_CANCEL) + /* Restore previous condition */ + adapter->hs_cfg.conditions = + cpu_to_le32(prev_cond); + } else { + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; + adapter->hs_cfg.gap = (u8)hs_cfg->gap; + } + break; + case HOST_ACT_GEN_GET: + hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions); + hs_cfg->gpio = adapter->hs_cfg.gpio; + hs_cfg->gap = adapter->hs_cfg.gap; + break; + default: + status = -EINVAL; + break; + } + + return status; +} + +/* Sends IOCTL request to cancel the existing Host Sleep configuration. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int nxpwifi_cancel_hs(struct nxpwifi_private *priv, int cmd_type) +{ + struct nxpwifi_ds_hs_cfg hscfg; + + hscfg.conditions = HS_CFG_CANCEL; + hscfg.is_invoke_hostcmd = true; + + return nxpwifi_set_hs_params(priv, HOST_ACT_GEN_SET, + cmd_type, &hscfg); +} +EXPORT_SYMBOL_GPL(nxpwifi_cancel_hs); + +/* Sends IOCTL request to cancel the existing Host Sleep configuration. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +bool nxpwifi_enable_hs(struct nxpwifi_adapter *adapter) +{ + struct nxpwifi_ds_hs_cfg hscfg; + struct nxpwifi_private *priv; + int i; + + if (disconnect_on_suspend) { + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) + nxpwifi_deauthenticate(priv, NULL); + } + } + + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA); + + if (priv && priv->sched_scanning) { +#ifdef CONFIG_PM + if (priv->wdev.wiphy->wowlan_config && + !priv->wdev.wiphy->wowlan_config->nd_config) { +#endif + nxpwifi_dbg(adapter, CMD, "aborting bgscan!\n"); + nxpwifi_stop_bg_scan(priv); + cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0); +#ifdef CONFIG_PM + } +#endif + } + + if (adapter->hs_activated) { + nxpwifi_dbg(adapter, CMD, + "cmd: HS Already activated\n"); + return true; + } + + adapter->hs_activate_wait_q_woken = false; + + memset(&hscfg, 0, sizeof(hscfg)); + hscfg.is_invoke_hostcmd = true; + + set_bit(NXPWIFI_IS_HS_ENABLING, &adapter->work_flags); + nxpwifi_cancel_all_pending_cmd(adapter); + + if (nxpwifi_set_hs_params(nxpwifi_get_priv(adapter, + NXPWIFI_BSS_ROLE_STA), + HOST_ACT_GEN_SET, NXPWIFI_SYNC_CMD, + &hscfg)) { + nxpwifi_dbg(adapter, ERROR, + "IOCTL request HS enable failed\n"); + return false; + } + + if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q, + adapter->hs_activate_wait_q_woken, + (10 * HZ)) <= 0) { + nxpwifi_dbg(adapter, ERROR, + "hs_activate_wait_q terminated\n"); + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(nxpwifi_enable_hs); + +/* IOCTL request handler to get BSS information. + * + * This function collates the information from different driver structures + * to send to the user. + */ +int nxpwifi_get_bss_info(struct nxpwifi_private *priv, + struct nxpwifi_bss_info *info) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_bssdescriptor *bss_desc; + + if (!info) + return -EINVAL; + + bss_desc = &priv->curr_bss_params.bss_descriptor; + + info->bss_mode = priv->bss_mode; + + memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct cfg80211_ssid)); + + memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN); + + info->bss_chan = bss_desc->channel; + + memcpy(info->country_code, adapter->country_code, + IEEE80211_COUNTRY_STRING_LEN); + + info->media_connected = priv->media_connected; + + info->max_power_level = priv->max_tx_power_level; + info->min_power_level = priv->min_tx_power_level; + + info->bcn_nf_last = priv->bcn_nf_last; + + if (priv->sec_info.wep_enabled) + info->wep_status = true; + else + info->wep_status = false; + + info->is_hs_configured = test_bit(NXPWIFI_IS_HS_CONFIGURED, + &adapter->work_flags); + info->is_deep_sleep = adapter->is_deep_sleep; + + return 0; +} + +/* The function disables auto deep sleep mode. + */ +int nxpwifi_disable_auto_ds(struct nxpwifi_private *priv) +{ + struct nxpwifi_ds_auto_ds auto_ds = { + .auto_ds = DEEP_SLEEP_OFF, + }; + + return nxpwifi_send_cmd(priv, HOST_CMD_802_11_PS_MODE_ENH, + DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true); +} +EXPORT_SYMBOL_GPL(nxpwifi_disable_auto_ds); + +/* Sends IOCTL request to get the data rate. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int nxpwifi_drv_get_data_rate(struct nxpwifi_private *priv, u32 *rate) +{ + int ret; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_TX_RATE_QUERY, + HOST_ACT_GEN_GET, 0, NULL, true); + + if (!ret) { + if (priv->is_data_rate_auto) + *rate = nxpwifi_index_to_data_rate(priv, priv->tx_rate, + priv->tx_htinfo); + else + *rate = priv->data_rate; + } + + return ret; +} + +/* IOCTL request handler to set tx power configuration. + * + * This function prepares the correct firmware command and + * issues it. + * + * For non-auto power mode, all the following power groups are set - + * - Modulation class HR/DSSS + * - Modulation class OFDM + * - Modulation class HTBW20 + * - Modulation class HTBW40 + */ +int nxpwifi_set_tx_power(struct nxpwifi_private *priv, + struct nxpwifi_power_cfg *power_cfg) +{ + int ret; + struct host_cmd_ds_txpwr_cfg *txp_cfg; + struct nxpwifi_types_power_group *pg_tlv; + struct nxpwifi_power_group *pg; + u8 *buf; + u16 dbm = 0; + + if (!power_cfg->is_power_auto) { + dbm = (u16)power_cfg->power_level; + if (dbm < priv->min_tx_power_level || + dbm > priv->max_tx_power_level) { + nxpwifi_dbg(priv->adapter, ERROR, + "txpower value %d dBm\t" + "is out of range (%d dBm-%d dBm)\n", + dbm, priv->min_tx_power_level, + priv->max_tx_power_level); + return -EINVAL; + } + } + buf = kzalloc(NXPWIFI_SIZE_OF_CMD_BUFFER, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + txp_cfg = (struct host_cmd_ds_txpwr_cfg *)buf; + txp_cfg->action = cpu_to_le16(HOST_ACT_GEN_SET); + if (!power_cfg->is_power_auto) { + u16 dbm_min = power_cfg->is_power_fixed ? + dbm : priv->min_tx_power_level; + + txp_cfg->mode = cpu_to_le32(1); + pg_tlv = (struct nxpwifi_types_power_group *) + (buf + sizeof(struct host_cmd_ds_txpwr_cfg)); + pg_tlv->type = cpu_to_le16(TLV_TYPE_POWER_GROUP); + pg_tlv->length = + cpu_to_le16(4 * sizeof(struct nxpwifi_power_group)); + pg = (struct nxpwifi_power_group *) + (buf + sizeof(struct host_cmd_ds_txpwr_cfg) + + sizeof(struct nxpwifi_types_power_group)); + /* Power group for modulation class HR/DSSS */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x03; + pg->modulation_class = MOD_CLASS_HR_DSSS; + pg->power_step = 0; + pg->power_min = (s8)dbm_min; + pg->power_max = (s8)dbm; + pg++; + /* Power group for modulation class OFDM */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x07; + pg->modulation_class = MOD_CLASS_OFDM; + pg->power_step = 0; + pg->power_min = (s8)dbm_min; + pg->power_max = (s8)dbm; + pg++; + /* Power group for modulation class HTBW20 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x20; + pg->modulation_class = MOD_CLASS_HT; + pg->power_step = 0; + pg->power_min = (s8)dbm_min; + pg->power_max = (s8)dbm; + pg->ht_bandwidth = HT_BW_20; + pg++; + /* Power group for modulation class HTBW40 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x20; + pg->modulation_class = MOD_CLASS_HT; + pg->power_step = 0; + pg->power_min = (s8)dbm_min; + pg->power_max = (s8)dbm; + pg->ht_bandwidth = HT_BW_40; + } + ret = nxpwifi_send_cmd(priv, HOST_CMD_TXPWR_CFG, + HOST_ACT_GEN_SET, 0, buf, true); + + kfree(buf); + return ret; +} + +/* IOCTL request handler to get power save mode. + * + * This function prepares the correct firmware command and + * issues it. + */ +int nxpwifi_drv_set_power(struct nxpwifi_private *priv, u32 *ps_mode) +{ + int ret; + struct nxpwifi_adapter *adapter = priv->adapter; + u16 sub_cmd; + + if (*ps_mode) + adapter->ps_mode = NXPWIFI_802_11_POWER_MODE_PSP; + else + adapter->ps_mode = NXPWIFI_802_11_POWER_MODE_CAM; + sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_PS_MODE_ENH, + sub_cmd, BITMAP_STA_PS, NULL, true); + if (!ret && sub_cmd == DIS_AUTO_PS) + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_PS_MODE_ENH, + GET_PS, 0, NULL, false); + + return ret; +} + +/* IOCTL request handler to set/reset WPA IE. + * + * The supplied WPA IE is treated as a opaque buffer. Only the first field + * is checked to determine WPA version. If buffer length is zero, the existing + * WPA IE is reset. + */ +static int nxpwifi_set_wpa_ie(struct nxpwifi_private *priv, + u8 *ie_data_ptr, u16 ie_len) +{ + if (ie_len) { + if (ie_len > sizeof(priv->wpa_ie)) { + nxpwifi_dbg(priv->adapter, ERROR, + "failed to copy WPA IE, too big\n"); + return -EINVAL; + } + memcpy(priv->wpa_ie, ie_data_ptr, ie_len); + priv->wpa_ie_len = ie_len; + nxpwifi_dbg(priv->adapter, CMD, + "cmd: Set Wpa_ie_len=%d IE=%#x\n", + priv->wpa_ie_len, priv->wpa_ie[0]); + + if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) { + priv->sec_info.wpa_enabled = true; + } else if (priv->wpa_ie[0] == WLAN_EID_RSN) { + priv->sec_info.wpa2_enabled = true; + } else { + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + } + } else { + memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie)); + priv->wpa_ie_len = 0; + nxpwifi_dbg(priv->adapter, INFO, + "info: reset wpa_ie_len=%d IE=%#x\n", + priv->wpa_ie_len, priv->wpa_ie[0]); + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + } + + return 0; +} + +/* IOCTL request handler to set/reset WPS IE. + * + * The supplied WPS IE is treated as a opaque buffer. Only the first field + * is checked to internally enable WPS. If buffer length is zero, the existing + * WPS IE is reset. + */ +static int nxpwifi_set_wps_ie(struct nxpwifi_private *priv, + u8 *ie_data_ptr, u16 ie_len) +{ + if (ie_len) { + if (ie_len > NXPWIFI_MAX_VSIE_LEN) { + nxpwifi_dbg(priv->adapter, ERROR, + "info: failed to copy WPS IE, too big\n"); + return -EINVAL; + } + + priv->wps_ie = kzalloc(NXPWIFI_MAX_VSIE_LEN, GFP_KERNEL); + if (!priv->wps_ie) + return -ENOMEM; + + memcpy(priv->wps_ie, ie_data_ptr, ie_len); + priv->wps_ie_len = ie_len; + nxpwifi_dbg(priv->adapter, CMD, + "cmd: Set wps_ie_len=%d IE=%#x\n", + priv->wps_ie_len, priv->wps_ie[0]); + } else { + kfree(priv->wps_ie); + priv->wps_ie_len = ie_len; + nxpwifi_dbg(priv->adapter, INFO, + "info: Reset wps_ie_len=%d\n", priv->wps_ie_len); + } + return 0; +} + +/* IOCTL request handler to set WEP network key. + * + * This function prepares the correct firmware command and + * issues it, after validation checks. + */ +static int +nxpwifi_sec_ioctl_set_wep_key(struct nxpwifi_private *priv, + struct nxpwifi_ds_encrypt_key *encrypt_key) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + int ret; + struct nxpwifi_wep_key *wep_key; + int index; + + if (priv->wep_key_curr_index >= NUM_WEP_KEYS) + priv->wep_key_curr_index = 0; + wep_key = &priv->wep_key[priv->wep_key_curr_index]; + index = encrypt_key->key_index; + if (encrypt_key->key_disable) { + priv->sec_info.wep_enabled = 0; + } else if (!encrypt_key->key_len) { + /* Copy the required key as the current key */ + wep_key = &priv->wep_key[index]; + if (!wep_key->key_length) { + nxpwifi_dbg(adapter, ERROR, + "key not set, so cannot enable it\n"); + return -EINVAL; + } + + memcpy(encrypt_key->key_material, + wep_key->key_material, wep_key->key_length); + encrypt_key->key_len = wep_key->key_length; + + priv->wep_key_curr_index = (u16)index; + priv->sec_info.wep_enabled = 1; + } else { + wep_key = &priv->wep_key[index]; + memset(wep_key, 0, sizeof(struct nxpwifi_wep_key)); + /* Copy the key in the driver */ + memcpy(wep_key->key_material, + encrypt_key->key_material, + encrypt_key->key_len); + wep_key->key_index = index; + wep_key->key_length = encrypt_key->key_len; + priv->sec_info.wep_enabled = 1; + } + if (wep_key->key_length) { + void *enc_key; + + if (encrypt_key->key_disable) { + memset(&priv->wep_key[index], 0, + sizeof(struct nxpwifi_wep_key)); + goto done; + } + + enc_key = encrypt_key; + + /* Send request to firmware */ + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_KEY_MATERIAL, + HOST_ACT_GEN_SET, 0, enc_key, false); + if (ret) + return ret; + } + +done: + if (priv->sec_info.wep_enabled) + priv->curr_pkt_filter |= HOST_ACT_MAC_WEP_ENABLE; + else + priv->curr_pkt_filter &= ~HOST_ACT_MAC_WEP_ENABLE; + + ret = nxpwifi_send_cmd(priv, HOST_CMD_MAC_CONTROL, + HOST_ACT_GEN_SET, 0, + &priv->curr_pkt_filter, true); + + return ret; +} + +/* IOCTL request handler to set WPA key. + * + * This function prepares the correct firmware command and + * issues it, after validation checks. + * + * Current driver only supports key length of up to 32 bytes. + * + * This function can also be used to disable a currently set key. + */ +static int +nxpwifi_sec_ioctl_set_wpa_key(struct nxpwifi_private *priv, + struct nxpwifi_ds_encrypt_key *encrypt_key) +{ + int ret; + u8 remove_key = false; + + /* Current driver only supports key length of up to 32 bytes */ + if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) { + nxpwifi_dbg(priv->adapter, ERROR, + "key length too long\n"); + return -EINVAL; + } + + if (!encrypt_key->key_index) + encrypt_key->key_index = NXPWIFI_KEY_INDEX_UNICAST; + + if (remove_key) + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_KEY_MATERIAL, + HOST_ACT_GEN_SET, + !KEY_INFO_ENABLED, encrypt_key, true); + else + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_KEY_MATERIAL, + HOST_ACT_GEN_SET, + KEY_INFO_ENABLED, encrypt_key, true); + + return ret; +} + +/* IOCTL request handler to set/get network keys. + * + * This is a generic key handling function which supports WEP and WPA. + */ +static int +nxpwifi_sec_ioctl_encrypt_key(struct nxpwifi_private *priv, + struct nxpwifi_ds_encrypt_key *encrypt_key) +{ + int status; + + if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104) + status = nxpwifi_sec_ioctl_set_wpa_key(priv, encrypt_key); + else + status = nxpwifi_sec_ioctl_set_wep_key(priv, encrypt_key); + + return status; +} + +/* This function returns the driver version. + */ +int +nxpwifi_drv_get_driver_version(struct nxpwifi_adapter *adapter, char *version, + int max_len) +{ + union { + __le32 l; + u8 c[4]; + } ver; + char fw_ver[32]; + + ver.l = cpu_to_le32(adapter->fw_release_number); + sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]); + + snprintf(version, max_len, driver_version, fw_ver); + + nxpwifi_dbg(adapter, MSG, "info: NXPWIFI VERSION: %s\n", version); + + return 0; +} + +/* Sends IOCTL request to set encoding parameters. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int nxpwifi_set_encode(struct nxpwifi_private *priv, struct key_params *kp, + const u8 *key, int key_len, u8 key_index, + const u8 *mac_addr, int disable) +{ + struct nxpwifi_ds_encrypt_key encrypt_key; + + memset(&encrypt_key, 0, sizeof(encrypt_key)); + encrypt_key.key_len = key_len; + encrypt_key.key_index = key_index; + + if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC) + encrypt_key.is_igtk_key = true; + + if (!disable) { + if (key_len) + memcpy(encrypt_key.key_material, key, key_len); + else + encrypt_key.is_current_wep_key = true; + + if (mac_addr) + memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); + if (kp && kp->seq && kp->seq_len) { + memcpy(encrypt_key.pn, kp->seq, kp->seq_len); + encrypt_key.pn_len = kp->seq_len; + encrypt_key.is_rx_seq_valid = true; + } + } else { + encrypt_key.key_disable = true; + if (mac_addr) + memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); + } + + return nxpwifi_sec_ioctl_encrypt_key(priv, &encrypt_key); +} + +/* Sends IOCTL request to get extended version. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +nxpwifi_get_ver_ext(struct nxpwifi_private *priv, u32 version_str_sel) +{ + struct nxpwifi_ver_ext ver_ext; + + memset(&ver_ext, 0, sizeof(ver_ext)); + ver_ext.version_str_sel = version_str_sel; + + return nxpwifi_send_cmd(priv, HOST_CMD_VERSION_EXT, + HOST_ACT_GEN_GET, 0, &ver_ext, true); +} + +int +nxpwifi_remain_on_chan_cfg(struct nxpwifi_private *priv, u16 action, + struct ieee80211_channel *chan, + unsigned int duration) +{ + struct host_cmd_ds_remain_on_chan roc_cfg; + u8 sc; + int ret; + + memset(&roc_cfg, 0, sizeof(roc_cfg)); + roc_cfg.action = cpu_to_le16(action); + if (action == HOST_ACT_GEN_SET) { + roc_cfg.band_cfg = chan->band; + sc = nxpwifi_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT); + roc_cfg.band_cfg |= (sc << 2); + + roc_cfg.channel = + ieee80211_frequency_to_channel(chan->center_freq); + roc_cfg.duration = cpu_to_le32(duration); + } + ret = nxpwifi_send_cmd(priv, HOST_CMD_REMAIN_ON_CHAN, + action, 0, &roc_cfg, true); + if (ret) { + nxpwifi_dbg(priv->adapter, ERROR, + "failed to remain on channel\n"); + return ret; + } + + return roc_cfg.status; +} + +/* Sends IOCTL request to get statistics information. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +nxpwifi_get_stats_info(struct nxpwifi_private *priv, + struct nxpwifi_ds_get_stats *log) +{ + return nxpwifi_send_cmd(priv, HOST_CMD_802_11_GET_LOG, + HOST_ACT_GEN_GET, 0, log, true); +} + +/* IOCTL request handler to read/write register. + * + * This function prepares the correct firmware command and + * issues it. + * + * Access to the following registers are supported - + * - MAC + * - BBP + * - RF + * - PMIC + * - CAU + */ +static int nxpwifi_reg_mem_ioctl_reg_rw(struct nxpwifi_private *priv, + struct nxpwifi_ds_reg_rw *reg_rw, + u16 action) +{ + u16 cmd_no; + + switch (reg_rw->type) { + case NXPWIFI_REG_MAC: + cmd_no = HOST_CMD_MAC_REG_ACCESS; + break; + case NXPWIFI_REG_BBP: + cmd_no = HOST_CMD_BBP_REG_ACCESS; + break; + case NXPWIFI_REG_RF: + cmd_no = HOST_CMD_RF_REG_ACCESS; + break; + case NXPWIFI_REG_PMIC: + cmd_no = HOST_CMD_PMIC_REG_ACCESS; + break; + case NXPWIFI_REG_CAU: + cmd_no = HOST_CMD_CAU_REG_ACCESS; + break; + default: + return -EINVAL; + } + + return nxpwifi_send_cmd(priv, cmd_no, action, 0, reg_rw, true); +} + +/* Sends IOCTL request to write to a register. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +nxpwifi_reg_write(struct nxpwifi_private *priv, u32 reg_type, + u32 reg_offset, u32 reg_value) +{ + struct nxpwifi_ds_reg_rw reg_rw; + + reg_rw.type = reg_type; + reg_rw.offset = reg_offset; + reg_rw.value = reg_value; + + return nxpwifi_reg_mem_ioctl_reg_rw(priv, ®_rw, HOST_ACT_GEN_SET); +} + +/* Sends IOCTL request to read from a register. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +nxpwifi_reg_read(struct nxpwifi_private *priv, u32 reg_type, + u32 reg_offset, u32 *value) +{ + int ret; + struct nxpwifi_ds_reg_rw reg_rw; + + reg_rw.type = reg_type; + reg_rw.offset = reg_offset; + ret = nxpwifi_reg_mem_ioctl_reg_rw(priv, ®_rw, HOST_ACT_GEN_GET); + + if (!ret) + *value = reg_rw.value; + + return ret; +} + +/* Sends IOCTL request to read from EEPROM. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +nxpwifi_eeprom_read(struct nxpwifi_private *priv, u16 offset, u16 bytes, + u8 *value) +{ + int ret; + struct nxpwifi_ds_read_eeprom rd_eeprom; + + rd_eeprom.offset = offset; + rd_eeprom.byte_count = bytes; + + /* Send request to firmware */ + ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_EEPROM_ACCESS, + HOST_ACT_GEN_GET, 0, &rd_eeprom, true); + + if (!ret) + memcpy(value, rd_eeprom.value, + min((u16)MAX_EEPROM_DATA, rd_eeprom.byte_count)); + return ret; +} + +/* This function sets a generic IE. In addition to generic IE, it can + * also handle WPA and WPA2 IEs. + */ +static int +nxpwifi_set_gen_ie_helper(struct nxpwifi_private *priv, u8 *ie_data_ptr, + u16 ie_len) +{ + struct ieee80211_vendor_ie *pvendor_ie; + static const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; + static const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; + u16 unparsed_len = ie_len, cur_ie_len; + + /* If the passed length is zero, reset the buffer */ + if (!ie_len) { + priv->gen_ie_buf_len = 0; + priv->wps.session_enable = false; + return 0; + } else if (!ie_data_ptr || + ie_len <= sizeof(struct element)) { + return -EINVAL; + } + pvendor_ie = (struct ieee80211_vendor_ie *)ie_data_ptr; + + while (pvendor_ie) { + cur_ie_len = pvendor_ie->len + sizeof(struct element); + + if (pvendor_ie->element_id == WLAN_EID_RSN) { + /* IE is a WPA/WPA2 IE so call set_wpa function */ + nxpwifi_set_wpa_ie(priv, (u8 *)pvendor_ie, cur_ie_len); + priv->wps.session_enable = false; + goto next_ie; + } + + if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) { + /* Test to see if it is a WPA IE, if not, then + * it is a gen IE + */ + if (!memcmp(&pvendor_ie->oui, wpa_oui, + sizeof(wpa_oui))) { + /* IE is a WPA/WPA2 IE so call set_wpa function + */ + nxpwifi_set_wpa_ie(priv, (u8 *)pvendor_ie, + cur_ie_len); + priv->wps.session_enable = false; + goto next_ie; + } + + if (!memcmp(&pvendor_ie->oui, wps_oui, + sizeof(wps_oui))) { + /* Test to see if it is a WPS IE, + * if so, enable wps session flag + */ + priv->wps.session_enable = true; + nxpwifi_dbg(priv->adapter, MSG, + "WPS Session Enabled.\n"); + nxpwifi_set_wps_ie(priv, (u8 *)pvendor_ie, + cur_ie_len); + goto next_ie; + } + } + + /* Verify that the passed length is not larger than the + * available space remaining in the buffer + */ + if (cur_ie_len < + (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { + /* Append the passed data to the end + * of the genIeBuffer + */ + memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, + (u8 *)pvendor_ie, cur_ie_len); + /* Increment the stored buffer length by the + * size passed + */ + priv->gen_ie_buf_len += cur_ie_len; + } + +next_ie: + unparsed_len -= cur_ie_len; + + if (unparsed_len <= sizeof(struct element)) + pvendor_ie = NULL; + else + pvendor_ie = (struct ieee80211_vendor_ie *) + (((u8 *)pvendor_ie) + cur_ie_len); + } + + return 0; +} + +/* IOCTL request handler to set/get generic IE. + * + * In addition to various generic IEs, this function can also be + * used to set the ARP filter. + */ +static int nxpwifi_misc_ioctl_gen_ie(struct nxpwifi_private *priv, + struct nxpwifi_ds_misc_gen_ie *gen_ie, + u16 action) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + + switch (gen_ie->type) { + case NXPWIFI_IE_TYPE_GEN_IE: + if (action == HOST_ACT_GEN_GET) { + gen_ie->len = priv->wpa_ie_len; + memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len); + } else { + nxpwifi_set_gen_ie_helper(priv, gen_ie->ie_data, + (u16)gen_ie->len); + } + break; + case NXPWIFI_IE_TYPE_ARP_FILTER: + memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter)); + if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) { + adapter->arp_filter_size = 0; + nxpwifi_dbg(adapter, ERROR, + "invalid ARP filter size\n"); + return -EINVAL; + } + memcpy(adapter->arp_filter, gen_ie->ie_data, gen_ie->len); + adapter->arp_filter_size = gen_ie->len; + break; + default: + nxpwifi_dbg(adapter, ERROR, "invalid IE type\n"); + return -EINVAL; + } + return 0; +} + +/* Sends IOCTL request to set a generic IE. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +nxpwifi_set_gen_ie(struct nxpwifi_private *priv, const u8 *ie, int ie_len) +{ + struct nxpwifi_ds_misc_gen_ie gen_ie; + + if (ie_len > IEEE_MAX_IE_SIZE) + return -EFAULT; + + gen_ie.type = NXPWIFI_IE_TYPE_GEN_IE; + gen_ie.len = ie_len; + memcpy(gen_ie.ie_data, ie, ie_len); + + return nxpwifi_misc_ioctl_gen_ie(priv, &gen_ie, HOST_ACT_GEN_SET); +} + +/* This function get Host Sleep wake up reason. + */ +int nxpwifi_get_wakeup_reason(struct nxpwifi_private *priv, u16 action, + int cmd_type, + struct nxpwifi_ds_wakeup_reason *wakeup_reason) +{ + return nxpwifi_send_cmd(priv, HOST_CMD_HS_WAKEUP_REASON, + HOST_ACT_GEN_GET, 0, wakeup_reason, + cmd_type == NXPWIFI_SYNC_CMD); +} + +int nxpwifi_get_chan_info(struct nxpwifi_private *priv, + struct nxpwifi_channel_band *channel_band) +{ + return nxpwifi_send_cmd(priv, HOST_CMD_STA_CONFIGURE, + HOST_ACT_GEN_GET, 0, channel_band, + NXPWIFI_SYNC_CMD); +} From patchwork Fri Aug 9 09:45:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lin X-Patchwork-Id: 818270 Received: from DB3PR0202CU003.outbound.protection.outlook.com (mail-northeuropeazon11011015.outbound.protection.outlook.com [52.101.65.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF0D219309A; Fri, 9 Aug 2024 09:47:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.65.15 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196859; cv=fail; b=p4oIQewNFQexGxF16PRxz70r3Gt81Lt+qcIOAZJ0E15j5ao9gYzUqqec0NhK62M4+AZQi8I8yXyJDioxxN4CYdpjOdK1eZcNwr9mNmXXqmgnfkIWfrhbeiE1SYGIVtNHEVoZNbx+WWiBP0w2E18MWaImm/flxGJ1m1qiw4/Gx5M= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723196859; c=relaxed/simple; bh=q1RR66ibqaq44AVkcDwxGl47kUCoQ9rwkWGpujIF8q4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=UjawMgCbe3ffkE5iOa5txwcoD7ZBW3oLYXLaLO4yTRS0diSIlpCmGkf2zoa/gCvFiQnQLGQ+60BBC0kGM20q7ccr8FUEebZYC8kP/nbUZ1Zpp63mhgLRFKp4rVHJlrfgiNCHusxn9RKOBHmYhpKI0ZwWSxMnwp9P/ZKFRu435oQ= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=beWKt75H; arc=fail smtp.client-ip=52.101.65.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="beWKt75H" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=HK/trwY+rIeHPvTo3TpenHE24fFESK7XaGLwLdszu2TkjFvYmolJzu+92MEHDjm5kDkFOFwOORdmwZTrlWHo5kjFclu+jAu/izDswJbx4wneTiI3G6RNA0n9xf1hFSeVs7uKWmfUuljwqZOLAiovRiGanD6GLch9v3hr8R/+RY27n13LVss/m56qN5N84q3qMVY/PKI6rPPnrlhtPK6woEY+dYwpBJ96rVVe0mhx6skeBAbIOzbUrZvpWG9/GQojzgY8b2S5tQfh0bin2jG4DByQYC1iJesgwiB+Pv+TKEp5ox13ZnZ/Me4L7EuQxEk8/VQeIQzSprngBOtTvkzU4g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ZCZFlyd4yQNCcedNTkvs+kZ7RZ/SxloyQiSs+pffz/4=; b=aWmIXfdO7SU+eA7ae9yQ/5vNWqPIey/CPIRbvZRffciWdmqeDJV5GmpPVbWw/76LsE7kA40rFmKUXQhrFlivNs23e2vdjubbWcqEEBxwuW5IM7FqKTfclUr9ArJMyajbvm9KhXWqB8zuMcJV6zkqFTcWfwqAdtlVjwQqxGo7/HAXwcKzQo53CmQKJJg7NSngP9Mui0Txe9hTUpwadSkQ2rkvEimNDUZsqzLmVCz1zN7ikaa30jS3suEJV/QBlRBcuBOCv9/bQC5xNW9MOFLHkgDMPPxz9WcKOgKSrcejto7xjnWg+iFFmhZ3XPZGZIPuCgUIoY7wXuqYfD1NkyAycQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ZCZFlyd4yQNCcedNTkvs+kZ7RZ/SxloyQiSs+pffz/4=; b=beWKt75HDe3X5sXjBEFmYqzhVVcjH4MSNfXYeDMlfTduDon0AC3h6AYNfngzAqosQ2JWxcvPmNlUlOihqeNSAc1E7MDlrwurhaxKNIKn9pGxxJbSNciTx/bX/+/8dY7srFUcWjugrBAd6DhlVJAtnUkycmHqVDhZRdHXEE8Eq4xSEAWgwYyQvZhqyyqXfYChkKPm4JjWYEWD2wzgJEubyNOUJNSZuyDvhL98ZXzA2EIPvYlysliOufpC4HVvzJZPFP405pfBtYvsON/9pTj4J1vN0tTC1gWqOgn7oFRT6SEQj9Do+2apjhw74r5eaI/tB/NkWb853KBf8rj9Aok24Q== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) by GV1PR04MB9120.eurprd04.prod.outlook.com (2603:10a6:150:27::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7849.13; Fri, 9 Aug 2024 09:47:27 +0000 Received: from PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257]) by PA4PR04MB9638.eurprd04.prod.outlook.com ([fe80::f950:3bb6:6848:2257%5]) with mapi id 15.20.7828.023; Fri, 9 Aug 2024 09:47:27 +0000 From: David Lin To: linux-wireless@vger.kernel.org Cc: linux-kernel@vger.kernel.org, kvalo@kernel.org, johannes@sipsolutions.net, briannorris@chromium.org, francesco@dolcini.it, tsung-hsien.hsieh@nxp.com, David Lin Subject: [PATCH v2 29/43] wifi: nxpwifi: add sta_cmd.c Date: Fri, 9 Aug 2024 17:45:19 +0800 Message-Id: <20240809094533.1660-30-yu-hao.lin@nxp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240809094533.1660-1-yu-hao.lin@nxp.com> References: <20240809094533.1660-1-yu-hao.lin@nxp.com> X-ClientProxiedBy: TYCP286CA0178.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c6::9) To PA4PR04MB9638.eurprd04.prod.outlook.com (2603:10a6:102:273::20) Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PA4PR04MB9638:EE_|GV1PR04MB9120:EE_ X-MS-Office365-Filtering-Correlation-Id: 1ca59f42-fcfd-47d7-4283-08dcb85846e0 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|52116014|1800799024; X-Microsoft-Antispam-Message-Info: 7nH82TYOHAVaMO0O6o5LsNqtPkMGDoLNDDuIdPX4QPkeBxIr1VU/YxK0cacCw+JmUW9Dp4lx93W7RNGPWrY8EWU9hpu7skS3KJWGYsVNCH7BfQgln+Y01BC2FHZyODyEnkRC31hpcck5SmDx8eqe7nWqTdh9Kakx/q2zvfuK2rpGrV9izmjuu2Jw7lk+hJHJ73suE/Lwd0gsVVvS9DNPeuekTgujs73akr3xJ1MM/aJpmON3GYtLZiXlyhDy9T8bpuc7iK5yMwgZCnware0X9pjB5hx6VZ9Ie9+/q9uZB4xI9RSYAZhONTvLzNcdYQRkJE2uE5tA0y6NkwtCdXeD0PlEgrzddOnKvIc341AtkygVoArVtdlgxyzgzBEjQfVNal8Sk1WgDeK9KFoCCl37vN7DMZDB0j2U3xNr1TOlIC7kymw4h5VPVwGxf8YsoYV6qfU52hNlJR9Q6lurjWDYL2UYV13a12X8YjG4VH15sgvDQNwOjPLMB3KGg6c59VY7tHb0Y5lB69uKjfwpxECL4wIcxlmK3aVXr534mGgfOavfFXTTkTu5bPlAcDR8f6Cw51tDpM/4RQWhZ25AubSWRJjYyEeJ13bt0aoQQlt73ydhQDaDMX6XR0J4BAo9894v50pjpdRUgYSIdT2k/igk407j8uRns66l+VpNvRcWb0WnLdl8gV2qxSf7MrXEuDndWo0kCH9O238yvKfq0A+mp+re/F9eoFQfoBLGnagkncruXdxR2sV9kxqhGlhJmB2EBW6iStehZpzzNHg7Q4ThrvJLOZcjN5I36e52cxpMmnS7b2Nc+WsGw0Nan8X8BMfsZrZPOBpauiAdHkl2YzanWey7i66c4rBN+J5TiLKcN/pDMZ2z3Qkuzs1wVAjV4P6AhoZWXuLBOobOeHwS77HKuWOzBBKFQGmHk+6wal6m6ub9Zd0iWtXUp6O9RxKJc4w0BgmAPmVPMEC/6JqwEMtE98oVXakeK835zMtGz5eW++dpgrIJ7KFTK1Tl6dXd3i+NISUyoOHPpHCT6uiye4XVMWmVECC4K8cpFhEUVnJUSUYiUgdoyTsXuw/yag4B0/i212gtYmVqrJiJA0TvzFRsOyIAM6nVnSsJsAJ1f4s+YyXKUY+SRp8dAnhjFTTRoP4+/+wGA0XztNpVN1QTGmK9puOVOrhjHg/oFEY9M6eEI+ci//96DvbOkzNZT5erOdaO7AO9O1ajwJsG6KolA6ISR5ZeWvgmMNpgIeSApQzOQYrFNCvOPwFUBEl+ySxGoMj4xNXYngD16nmyGORWgG5AfhGp2MlgR70tyIqFJphZwTMzIvG6TsCN+MQGv3bfbouwmZRJZPrb3xUXOUDFWVG9Dw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PA4PR04MB9638.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(52116014)(1800799024); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: UwlIa0rGGPC4RuMmfKpIXy1UYEAXWEkrOe4nuwjK8saviNHlopoak9Lu4RkgL3X5EWRwtqS3Jde4XHkeVpBAFQEOLJhPbarTSKNC05C4xh/W5QPSsdK9whTZTSMOGkvdETcQYF5DjIE6Yopvajm86a/4P5abIa+CsR42BXYQIK49hN38hXzptGv+Ve9xrzlIw+TASH5FqSDoE4epzUnUcxPaQRV6qxp0KUkLUmf/bdvBoUoeJCjWCtZ6W4PsHdcZL5BtUQBjTW2eoqug8J6F296hnVimJ7YeUrfevHjxBKN4lIVfokqXIbttTyMAeuWnAVqWcoWABGYO8/2E4TSIULlG2nPoKVheR3qfpnhHSzaEHpWbI1zqkaTHS1aM+imm3Z3F6cnuN7IzHKRQs0M9JAPoTzcgCGKhGDzaQThmaho9k+SuS4gnmhIgh7X7sTQKDXEhuy7XFNv1Ds6w+3ineagCfOiDwTeTx1Lo64uPpVIkbUy9RfrpdJPNOKbn9aniO498wSUV/QpBTSrXxxvQAA04KVSlH8WmM4Z2zt8iNtHm1IskgFk43TlgsJQGXopWrOR0wKbUMQFucoesZyvGXzg2Wq8s60OqcssNaElRBLv4Qr0y5AN7vZaph7KvFYHch54NTd0c+AcwPUcPZ7BpL1ickIUY1t4toKmh7rfBfKX+TWMdlXrP6pgji4yBkkUfXgiXWT9dbzYBWypTpqpK8T8e5HjIOdNp6/dCQ358YhF8DZ3sJo0UGoYgQp5iWhEnmJZ3vYEVcoIjnXEDHS9APW0tw/+D8MmODX7MPT2lCUsJryw5hEawtDB42U8nuOutkEi7+Zbcwy5oF8LjWYIaR8ijcAMcy0kaG1rrrtEr911tqGOaNbdmQFPtJzD8g/YxqR0kWK53lCvIGyWcG8KyQmJPn61z1wq36vVP4517i3YLLy/Y+TCBujZeTcjSIysnJwRMDSAFuYPmMFO1bku4SHPpjMK1EwlphZ55v6HwnPSNYeR46UbQhdo1Tpf9/B2wNBI6HTXnYVsz58mSX1ZH/q+0Ts6Mw8WuPVsANWGd3pkqf1y7eTLSYIKMR14XqWJcwc2d55KKtxy1rDlEeLLf48g62LenbU0RKoTczV7B6oCyOG3LUONAz1weBnlj+kMNUcKGm2FSa/RnUZgBuCzpkMfURGvVN+nOHcKgLECURT1+f5Fvk/mR3qIg/mESVIaeUQ6CGEb/KrblVayEAPWPhArrZR6XlLo3D5f/hz51DgwpzanYdsJdfUi16yMha1l4+5dQTjFREyyCOmHANuL0L94ae8qPs7NDF7+8AZRwwQgk7Uv0qGfklwZYz4SozxKWYgmibe/y6Z0ZNS3g0i14z2l5v9ppM6w91bSOx/U3KGMOgJKjKoLvHuESS9oIM+BUeVgh4sfjX62nOypl03E9lydn1C71lE7xJYOcOlnZd+Nd6PGga36Y8qFEAGz/76qeqlZf40m8Rj6HGIq5iJwiJ7eM8SH3qG8VTilkW8KfLTpuay92l5Lj8O2kkhp5+Spo0Xo1okTgV69iYLwg9yT9RE2R6znVJxOqO8yCy3ugCAlZuKnVW90vRZEmy1/zVUec0xUKkTDV80O2FLM5ZuZTmB9Obfaqt9oMCvJy/s1ljKbHQosAqmp15eVwaQv7Awhj X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1ca59f42-fcfd-47d7-4283-08dcb85846e0 X-MS-Exchange-CrossTenant-AuthSource: PA4PR04MB9638.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Aug 2024 09:47:26.9843 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: twVysr0A0m1S97LhSUqDjU4Chu1kmLv6spkbDbiT77jHUvZ52TQiXg53p65rtxjhe2cxbrBeoulBX52KDBXdew== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GV1PR04MB9120 --- drivers/net/wireless/nxp/nxpwifi/sta_cmd.c | 3233 ++++++++++++++++++++ 1 file changed, 3233 insertions(+) create mode 100644 drivers/net/wireless/nxp/nxpwifi/sta_cmd.c diff --git a/drivers/net/wireless/nxp/nxpwifi/sta_cmd.c b/drivers/net/wireless/nxp/nxpwifi/sta_cmd.c new file mode 100644 index 000000000000..ef4980b48b60 --- /dev/null +++ b/drivers/net/wireless/nxp/nxpwifi/sta_cmd.c @@ -0,0 +1,3233 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NXP Wireless LAN device driver: station command handling + * + * Copyright 2011-2024 NXP + */ + +#include "decl.h" +#include "cfg.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cmdevt.h" +#include "wmm.h" +#include "11n.h" +#include "11ac.h" + +static bool disable_auto_ds; + +static int +nxpwifi_cmd_sta_get_hw_spec(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec; + + cmd->command = cpu_to_le16(HOST_CMD_GET_HW_SPEC); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + + S_DS_GEN); + memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN); + + return 0; +} + +static int +nxpwifi_ret_sta_get_hw_spec(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec; + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_ie_types_header *tlv; + struct hw_spec_api_rev *api_rev; + struct hw_spec_max_conn *max_conn; + u16 resp_size, api_id; + int i, left_len, parsed_len = 0; + + adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info); + + if (IS_SUPPORT_MULTI_BANDS(adapter)) + adapter->fw_bands = (u8)GET_FW_DEFAULT_BANDS(adapter); + else + adapter->fw_bands = BAND_B; + + adapter->config_bands = adapter->fw_bands; + + if (adapter->fw_bands & BAND_A) { + if (adapter->fw_bands & BAND_GN) { + adapter->config_bands |= BAND_AN; + adapter->fw_bands |= BAND_AN; + } + } + + adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); + adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff; + adapter->number_of_antenna = + le16_to_cpu(hw_spec->number_of_antenna) & 0xf; + + if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) { + adapter->is_hw_11ac_capable = true; + + /* Copy 11AC cap */ + adapter->hw_dot_11ac_dev_cap = + le32_to_cpu(hw_spec->dot_11ac_dev_cap); + adapter->usr_dot_11ac_dev_cap_bg = adapter->hw_dot_11ac_dev_cap + & ~NXPWIFI_DEF_11AC_CAP_BF_RESET_MASK; + adapter->usr_dot_11ac_dev_cap_a = adapter->hw_dot_11ac_dev_cap + & ~NXPWIFI_DEF_11AC_CAP_BF_RESET_MASK; + + /* Copy 11AC mcs */ + adapter->hw_dot_11ac_mcs_support = + le32_to_cpu(hw_spec->dot_11ac_mcs_support); + adapter->usr_dot_11ac_mcs_support = + adapter->hw_dot_11ac_mcs_support; + } else { + adapter->is_hw_11ac_capable = false; + } + + resp_size = le16_to_cpu(resp->size) - S_DS_GEN; + if (resp_size > sizeof(struct host_cmd_ds_get_hw_spec)) { + /* we have variable HW SPEC information */ + left_len = resp_size - sizeof(struct host_cmd_ds_get_hw_spec); + while (left_len > sizeof(struct nxpwifi_ie_types_header)) { + tlv = (void *)&hw_spec->tlvs + parsed_len; + switch (le16_to_cpu(tlv->type)) { + case TLV_TYPE_API_REV: + api_rev = (struct hw_spec_api_rev *)tlv; + api_id = le16_to_cpu(api_rev->api_id); + switch (api_id) { + case KEY_API_VER_ID: + adapter->key_api_major_ver = + api_rev->major_ver; + adapter->key_api_minor_ver = + api_rev->minor_ver; + nxpwifi_dbg(adapter, INFO, + "key_api v%d.%d\n", + adapter->key_api_major_ver, + adapter->key_api_minor_ver); + break; + case FW_API_VER_ID: + adapter->fw_api_ver = + api_rev->major_ver; + nxpwifi_dbg(adapter, INFO, + "Firmware api version %d.%d\n", + adapter->fw_api_ver, + api_rev->minor_ver); + break; + case UAP_FW_API_VER_ID: + nxpwifi_dbg(adapter, INFO, + "uAP api version %d.%d\n", + api_rev->major_ver, + api_rev->minor_ver); + break; + case CHANRPT_API_VER_ID: + nxpwifi_dbg(adapter, INFO, + "channel report api version %d.%d\n", + api_rev->major_ver, + api_rev->minor_ver); + break; + case FW_HOTFIX_VER_ID: + nxpwifi_dbg(adapter, INFO, + "Firmware hotfix version %d\n", + api_rev->major_ver); + break; + default: + nxpwifi_dbg(adapter, FATAL, + "Unknown api_id: %d\n", + api_id); + break; + } + break; + case TLV_TYPE_MAX_CONN: + max_conn = (struct hw_spec_max_conn *)tlv; + adapter->max_sta_conn = max_conn->max_sta_conn; + nxpwifi_dbg(adapter, INFO, + "max sta connections: %u\n", + adapter->max_sta_conn); + break; + default: + nxpwifi_dbg(adapter, FATAL, + "Unknown GET_HW_SPEC TLV type: %#x\n", + le16_to_cpu(tlv->type)); + break; + } + parsed_len += le16_to_cpu(tlv->len) + + sizeof(struct nxpwifi_ie_types_header); + left_len -= le16_to_cpu(tlv->len) + + sizeof(struct nxpwifi_ie_types_header); + } + } + + if (adapter->key_api_major_ver < KEY_API_VER_MAJOR_V2) + return -EOPNOTSUPP; + + nxpwifi_dbg(adapter, INFO, + "info: GET_HW_SPEC: fw_release_number- %#x\n", + adapter->fw_release_number); + nxpwifi_dbg(adapter, INFO, + "info: GET_HW_SPEC: permanent addr: %pM\n", + hw_spec->permanent_addr); + nxpwifi_dbg(adapter, INFO, + "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n", + le16_to_cpu(hw_spec->hw_if_version), + le16_to_cpu(hw_spec->version)); + + ether_addr_copy(priv->adapter->perm_addr, hw_spec->permanent_addr); + adapter->region_code = le16_to_cpu(hw_spec->region_code); + + for (i = 0; i < NXPWIFI_MAX_REGION_CODE; i++) + /* Use the region code to search for the index */ + if (adapter->region_code == region_code_index[i]) + break; + + /* If it's unidentified region code, use the default (world) */ + if (i >= NXPWIFI_MAX_REGION_CODE) { + adapter->region_code = 0x00; + nxpwifi_dbg(adapter, WARN, + "cmd: unknown region code, use default (USA)\n"); + } + + adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); + adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; + adapter->user_dev_mcs_support = adapter->hw_dev_mcs_support; + + if (adapter->if_ops.update_mp_end_port) { + u16 mp_end_port; + + mp_end_port = le16_to_cpu(hw_spec->mp_end_port); + adapter->if_ops.update_mp_end_port(adapter, mp_end_port); + } + + if (adapter->fw_api_ver == NXPWIFI_FW_V15) + adapter->scan_chan_gap_enabled = true; + + return 0; +} + +static int +nxpwifi_cmd_sta_802_11_scan(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + return nxpwifi_cmd_802_11_scan(cmd, data_buf); +} + +static int +nxpwifi_ret_sta_802_11_scan(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + int ret; + + ret = nxpwifi_ret_802_11_scan(priv, resp); + adapter->curr_cmd->wait_q_enabled = false; + + return ret; +} + +static int +nxpwifi_cmd_sta_802_11_get_log(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + cmd->command = cpu_to_le16(HOST_CMD_802_11_GET_LOG); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) + + S_DS_GEN); + + return 0; +} + +static int +nxpwifi_ret_sta_802_11_get_log(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct host_cmd_ds_802_11_get_log *get_log = + &resp->params.get_log; + struct nxpwifi_ds_get_stats *stats = + (struct nxpwifi_ds_get_stats *)data_buf; + + if (stats) { + stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame); + stats->failed = le32_to_cpu(get_log->failed); + stats->retry = le32_to_cpu(get_log->retry); + stats->multi_retry = le32_to_cpu(get_log->multi_retry); + stats->frame_dup = le32_to_cpu(get_log->frame_dup); + stats->rts_success = le32_to_cpu(get_log->rts_success); + stats->rts_failure = le32_to_cpu(get_log->rts_failure); + stats->ack_failure = le32_to_cpu(get_log->ack_failure); + stats->rx_frag = le32_to_cpu(get_log->rx_frag); + stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame); + stats->fcs_error = le32_to_cpu(get_log->fcs_error); + stats->tx_frame = le32_to_cpu(get_log->tx_frame); + stats->wep_icv_error[0] = + le32_to_cpu(get_log->wep_icv_err_cnt[0]); + stats->wep_icv_error[1] = + le32_to_cpu(get_log->wep_icv_err_cnt[1]); + stats->wep_icv_error[2] = + le32_to_cpu(get_log->wep_icv_err_cnt[2]); + stats->wep_icv_error[3] = + le32_to_cpu(get_log->wep_icv_err_cnt[3]); + stats->bcn_rcv_cnt = le32_to_cpu(get_log->bcn_rcv_cnt); + stats->bcn_miss_cnt = le32_to_cpu(get_log->bcn_miss_cnt); + } + + return 0; +} + +static int +nxpwifi_cmd_sta_mac_multicast_adr(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr; + struct nxpwifi_multicast_list *mcast_list = + (struct nxpwifi_multicast_list *)data_buf; + + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) + + S_DS_GEN); + cmd->command = cpu_to_le16(HOST_CMD_MAC_MULTICAST_ADR); + + mcast_addr->action = cpu_to_le16(cmd_action); + mcast_addr->num_of_adrs = + cpu_to_le16((u16)mcast_list->num_multicast_addr); + memcpy(mcast_addr->mac_list, mcast_list->mac_list, + mcast_list->num_multicast_addr * ETH_ALEN); + + return 0; +} + +static int +nxpwifi_cmd_sta_802_11_associate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + return nxpwifi_cmd_802_11_associate(priv, cmd, data_buf); +} + +static int +nxpwifi_ret_sta_802_11_associate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + return nxpwifi_ret_802_11_associate(priv, resp); +} + +static int +nxpwifi_cmd_sta_802_11_snmp_mib(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib; + u16 *ul_temp = (u16 *)data_buf; + + nxpwifi_dbg(priv->adapter, CMD, + "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_type); + cmd->command = cpu_to_le16(HOST_CMD_802_11_SNMP_MIB); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib) + + S_DS_GEN); + + snmp_mib->oid = cpu_to_le16((u16)cmd_type); + if (cmd_action == HOST_ACT_GEN_GET) { + snmp_mib->query_type = cpu_to_le16(HOST_ACT_GEN_GET); + snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE); + le16_unaligned_add_cpu(&cmd->size, MAX_SNMP_BUF_SIZE); + } else if (cmd_action == HOST_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HOST_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + put_unaligned_le16(*ul_temp, snmp_mib->value); + le16_unaligned_add_cpu(&cmd->size, sizeof(u16)); + } + + nxpwifi_dbg(priv->adapter, CMD, + "cmd: SNMP_CMD: Action=0x%x, OID=0x%x,\t" + "OIDSize=0x%x, Value=0x%x\n", + cmd_action, cmd_type, le16_to_cpu(snmp_mib->buf_size), + get_unaligned_le16(snmp_mib->value)); + + return 0; +} + +static int +nxpwifi_ret_sta_802_11_snmp_mib(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; + u16 oid = le16_to_cpu(smib->oid); + u16 query_type = le16_to_cpu(smib->query_type); + u32 ul_temp; + + nxpwifi_dbg(priv->adapter, INFO, + "info: SNMP_RESP: oid value = %#x,\t" + "query_type = %#x, buf size = %#x\n", + oid, query_type, le16_to_cpu(smib->buf_size)); + if (query_type == HOST_ACT_GEN_GET) { + ul_temp = get_unaligned_le16(smib->value); + if (data_buf) + *(u32 *)data_buf = ul_temp; + switch (oid) { + case FRAG_THRESH_I: + nxpwifi_dbg(priv->adapter, INFO, + "info: SNMP_RESP: FragThsd =%u\n", + ul_temp); + break; + case RTS_THRESH_I: + nxpwifi_dbg(priv->adapter, INFO, + "info: SNMP_RESP: RTSThsd =%u\n", + ul_temp); + break; + case SHORT_RETRY_LIM_I: + nxpwifi_dbg(priv->adapter, INFO, + "info: SNMP_RESP: TxRetryCount=%u\n", + ul_temp); + break; + case DTIM_PERIOD_I: + nxpwifi_dbg(priv->adapter, INFO, + "info: SNMP_RESP: DTIM period=%u\n", + ul_temp); + break; + default: + break; + } + } + + return 0; +} + +static int nxpwifi_cmd_sta_reg_access(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct nxpwifi_ds_reg_rw *reg_rw = data_buf; + + cmd->command = cpu_to_le16(cmd_no); + + switch (cmd_no) { + case HOST_CMD_MAC_REG_ACCESS: + { + struct host_cmd_ds_mac_reg_access *mac_reg; + + cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN); + mac_reg = &cmd->params.mac_reg; + mac_reg->action = cpu_to_le16(cmd_action); + mac_reg->offset = cpu_to_le16((u16)reg_rw->offset); + mac_reg->value = cpu_to_le32(reg_rw->value); + break; + } + case HOST_CMD_BBP_REG_ACCESS: + { + struct host_cmd_ds_bbp_reg_access *bbp_reg; + + cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN); + bbp_reg = &cmd->params.bbp_reg; + bbp_reg->action = cpu_to_le16(cmd_action); + bbp_reg->offset = cpu_to_le16((u16)reg_rw->offset); + bbp_reg->value = (u8)reg_rw->value; + break; + } + case HOST_CMD_RF_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *rf_reg; + + cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN); + rf_reg = &cmd->params.rf_reg; + rf_reg->action = cpu_to_le16(cmd_action); + rf_reg->offset = cpu_to_le16((u16)reg_rw->offset); + rf_reg->value = (u8)reg_rw->value; + break; + } + case HOST_CMD_PMIC_REG_ACCESS: + { + struct host_cmd_ds_pmic_reg_access *pmic_reg; + + cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN); + pmic_reg = &cmd->params.pmic_reg; + pmic_reg->action = cpu_to_le16(cmd_action); + pmic_reg->offset = cpu_to_le16((u16)reg_rw->offset); + pmic_reg->value = (u8)reg_rw->value; + break; + } + case HOST_CMD_CAU_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *cau_reg; + + cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN); + cau_reg = &cmd->params.rf_reg; + cau_reg->action = cpu_to_le16(cmd_action); + cau_reg->offset = cpu_to_le16((u16)reg_rw->offset); + cau_reg->value = (u8)reg_rw->value; + break; + } + case HOST_CMD_802_11_EEPROM_ACCESS: + { + struct nxpwifi_ds_read_eeprom *rd_eeprom = data_buf; + struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom = + &cmd->params.eeprom; + + cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN); + cmd_eeprom->action = cpu_to_le16(cmd_action); + cmd_eeprom->offset = cpu_to_le16(rd_eeprom->offset); + cmd_eeprom->byte_count = cpu_to_le16(rd_eeprom->byte_count); + cmd_eeprom->value = 0; + break; + } + default: + return -EINVAL; + } + + return 0; +} + +static int +nxpwifi_ret_sta_reg_access(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct nxpwifi_ds_reg_rw *reg_rw; + struct nxpwifi_ds_read_eeprom *eeprom; + union reg { + struct host_cmd_ds_mac_reg_access *mac; + struct host_cmd_ds_bbp_reg_access *bbp; + struct host_cmd_ds_rf_reg_access *rf; + struct host_cmd_ds_pmic_reg_access *pmic; + struct host_cmd_ds_802_11_eeprom_access *eeprom; + } r; + + if (!data_buf) + return 0; + + reg_rw = data_buf; + eeprom = data_buf; + switch (cmdresp_no) { + case HOST_CMD_MAC_REG_ACCESS: + r.mac = &resp->params.mac_reg; + reg_rw->offset = (u32)le16_to_cpu(r.mac->offset); + reg_rw->value = le32_to_cpu(r.mac->value); + break; + case HOST_CMD_BBP_REG_ACCESS: + r.bbp = &resp->params.bbp_reg; + reg_rw->offset = (u32)le16_to_cpu(r.bbp->offset); + reg_rw->value = (u32)r.bbp->value; + break; + + case HOST_CMD_RF_REG_ACCESS: + r.rf = &resp->params.rf_reg; + reg_rw->offset = (u32)le16_to_cpu(r.rf->offset); + reg_rw->value = (u32)r.bbp->value; + break; + case HOST_CMD_PMIC_REG_ACCESS: + r.pmic = &resp->params.pmic_reg; + reg_rw->offset = (u32)le16_to_cpu(r.pmic->offset); + reg_rw->value = (u32)r.pmic->value; + break; + case HOST_CMD_CAU_REG_ACCESS: + r.rf = &resp->params.rf_reg; + reg_rw->offset = (u32)le16_to_cpu(r.rf->offset); + reg_rw->value = (u32)r.rf->value; + break; + case HOST_CMD_802_11_EEPROM_ACCESS: + r.eeprom = &resp->params.eeprom; + pr_debug("info: EEPROM read len=%x\n", + le16_to_cpu(r.eeprom->byte_count)); + if (eeprom->byte_count < le16_to_cpu(r.eeprom->byte_count)) { + eeprom->byte_count = 0; + pr_debug("info: EEPROM read length is too big\n"); + return -ENOMEM; + } + eeprom->offset = le16_to_cpu(r.eeprom->offset); + eeprom->byte_count = le16_to_cpu(r.eeprom->byte_count); + if (eeprom->byte_count > 0) + memcpy(&eeprom->value, &r.eeprom->value, + min((u16)MAX_EEPROM_DATA, eeprom->byte_count)); + break; + default: + return -EINVAL; + } + return 0; +} + +static int +nxpwifi_cmd_sta_rf_tx_pwr(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct host_cmd_ds_rf_tx_pwr *txp = &cmd->params.txp; + + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_tx_pwr) + + S_DS_GEN); + cmd->command = cpu_to_le16(HOST_CMD_RF_TX_PWR); + txp->action = cpu_to_le16(cmd_action); + + return 0; +} + +static int +nxpwifi_ret_sta_rf_tx_pwr(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct host_cmd_ds_rf_tx_pwr *txp = &resp->params.txp; + u16 action = le16_to_cpu(txp->action); + + priv->tx_power_level = le16_to_cpu(txp->cur_level); + + if (action == HOST_ACT_GEN_GET) { + priv->max_tx_power_level = txp->max_power; + priv->min_tx_power_level = txp->min_power; + } + + nxpwifi_dbg(priv->adapter, INFO, + "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n", + priv->tx_power_level, priv->max_tx_power_level, + priv->min_tx_power_level); + + return 0; +} + +static int +nxpwifi_cmd_sta_rf_antenna(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct host_cmd_ds_rf_ant_mimo *ant_mimo = &cmd->params.ant_mimo; + struct host_cmd_ds_rf_ant_siso *ant_siso = &cmd->params.ant_siso; + struct nxpwifi_ds_ant_cfg *ant_cfg = + (struct nxpwifi_ds_ant_cfg *)data_buf; + + cmd->command = cpu_to_le16(HOST_CMD_RF_ANTENNA); + + switch (cmd_action) { + case HOST_ACT_GEN_SET: + if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) { + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_rf_ant_mimo) + + S_DS_GEN); + ant_mimo->action_tx = cpu_to_le16(HOST_ACT_SET_TX); + ant_mimo->tx_ant_mode = + cpu_to_le16((u16)ant_cfg->tx_ant); + ant_mimo->action_rx = cpu_to_le16(HOST_ACT_SET_RX); + ant_mimo->rx_ant_mode = + cpu_to_le16((u16)ant_cfg->rx_ant); + } else { + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_rf_ant_siso) + + S_DS_GEN); + ant_siso->action = cpu_to_le16(HOST_ACT_SET_BOTH); + ant_siso->ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); + } + break; + case HOST_ACT_GEN_GET: + if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) { + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_rf_ant_mimo) + + S_DS_GEN); + ant_mimo->action_tx = cpu_to_le16(HOST_ACT_GET_TX); + ant_mimo->action_rx = cpu_to_le16(HOST_ACT_GET_RX); + } else { + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_rf_ant_siso) + + S_DS_GEN); + ant_siso->action = cpu_to_le16(HOST_ACT_GET_BOTH); + } + break; + } + return 0; +} + +static int +nxpwifi_ret_sta_rf_antenna(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct host_cmd_ds_rf_ant_mimo *ant_mimo = &resp->params.ant_mimo; + struct host_cmd_ds_rf_ant_siso *ant_siso = &resp->params.ant_siso; + struct nxpwifi_adapter *adapter = priv->adapter; + + if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) { + priv->tx_ant = le16_to_cpu(ant_mimo->tx_ant_mode); + priv->rx_ant = le16_to_cpu(ant_mimo->rx_ant_mode); + nxpwifi_dbg(adapter, INFO, + "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x\t" + "Rx action = 0x%x, Rx Mode = 0x%04x\n", + le16_to_cpu(ant_mimo->action_tx), + le16_to_cpu(ant_mimo->tx_ant_mode), + le16_to_cpu(ant_mimo->action_rx), + le16_to_cpu(ant_mimo->rx_ant_mode)); + } else { + priv->tx_ant = le16_to_cpu(ant_siso->ant_mode); + priv->rx_ant = le16_to_cpu(ant_siso->ant_mode); + nxpwifi_dbg(adapter, INFO, + "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n", + le16_to_cpu(ant_siso->action), + le16_to_cpu(ant_siso->ant_mode)); + } + return 0; +} + +static int +nxpwifi_cmd_sta_802_11_deauthenticate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth; + u8 *mac = (u8 *)data_buf; + + cmd->command = cpu_to_le16(HOST_CMD_802_11_DEAUTHENTICATE); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate) + + S_DS_GEN); + + /* Set AP MAC address */ + memcpy(deauth->mac_addr, mac, ETH_ALEN); + + nxpwifi_dbg(priv->adapter, CMD, "cmd: Deauth: %pM\n", deauth->mac_addr); + + deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING); + + return 0; +} + +static int +nxpwifi_ret_sta_802_11_deauthenticate(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + + adapter->dbg.num_cmd_deauth++; + if (!memcmp(resp->params.deauth.mac_addr, + &priv->curr_bss_params.bss_descriptor.mac_address, + sizeof(resp->params.deauth.mac_addr))) + nxpwifi_reset_connect_state(priv, WLAN_REASON_DEAUTH_LEAVING, + false); + + return 0; +} + +static int +nxpwifi_cmd_sta_mac_control(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl; + u32 *action = (u32 *)data_buf; + + if (cmd_action != HOST_ACT_GEN_SET) { + nxpwifi_dbg(priv->adapter, ERROR, + "mac_control: only support set cmd\n"); + return -EINVAL; + } + + cmd->command = cpu_to_le16(HOST_CMD_MAC_CONTROL); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN); + mac_ctrl->action = cpu_to_le32(*action); + + return 0; +} + +static int +nxpwifi_cmd_sta_802_11_mac_address(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + cmd->command = cpu_to_le16(HOST_CMD_802_11_MAC_ADDRESS); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) + + S_DS_GEN); + cmd->result = 0; + + cmd->params.mac_addr.action = cpu_to_le16(cmd_action); + + if (cmd_action == HOST_ACT_GEN_SET) + memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr, + ETH_ALEN); + + return 0; +} + +static int +nxpwifi_ret_sta_802_11_mac_address(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct host_cmd_ds_802_11_mac_address *cmd_mac_addr; + + cmd_mac_addr = &resp->params.mac_addr; + + memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN); + + nxpwifi_dbg(priv->adapter, INFO, + "info: set mac address: %pM\n", priv->curr_addr); + + return 0; +} + +static int +nxpwifi_cmd_sta_802_11d_domain_info(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11d_domain_info *domain_info = + &cmd->params.domain_info; + struct nxpwifi_ietypes_domain_param_set *domain = + &domain_info->domain; + struct nxpwifi_ietypes_domain_code *domain_code; + u8 no_of_triplet = adapter->domain_reg.no_of_triplet; + int triplet_size; + + nxpwifi_dbg(adapter, INFO, + "info: 11D: no_of_triplet=0x%x\n", no_of_triplet); + + cmd->command = cpu_to_le16(HOST_CMD_802_11D_DOMAIN_INFO); + cmd->size = cpu_to_le16(S_DS_GEN); + domain_info->action = cpu_to_le16(cmd_action); + le16_unaligned_add_cpu(&cmd->size, sizeof(domain_info->action)); + + if (cmd_action == HOST_ACT_GEN_GET) + return 0; + + triplet_size = no_of_triplet * + sizeof(struct ieee80211_country_ie_triplet); + + domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY); + domain->header.len = + cpu_to_le16(sizeof(domain->country_code) + triplet_size); + memcpy(domain->country_code, adapter->domain_reg.country_code, + sizeof(domain->country_code)); + if (no_of_triplet) + memcpy(domain->triplet, adapter->domain_reg.triplet, + triplet_size); + le16_unaligned_add_cpu(&cmd->size, sizeof(*domain) + triplet_size); + + domain_code = (struct nxpwifi_ietypes_domain_code *)((u8 *)cmd + + le16_to_cpu(cmd->size)); + domain_code->header.type = cpu_to_le16(TLV_TYPE_REGION_DOMAIN_CODE); + domain_code->header.len = + cpu_to_le16(sizeof(*domain_code) - + sizeof(struct nxpwifi_ie_types_header)); + le16_unaligned_add_cpu(&cmd->size, sizeof(*domain_code)); + + return 0; +} + +static int +nxpwifi_ret_sta_802_11d_domain_info(struct nxpwifi_private *priv, + struct host_cmd_ds_command *resp, + u16 cmdresp_no, + void *data_buf) +{ + struct host_cmd_ds_802_11d_domain_info_rsp *domain_info = + &resp->params.domain_info_resp; + struct nxpwifi_ietypes_domain_param_set *domain = &domain_info->domain; + u16 action = le16_to_cpu(domain_info->action); + u8 no_of_triplet; + + no_of_triplet = (u8)((le16_to_cpu(domain->header.len) + - IEEE80211_COUNTRY_STRING_LEN) + / sizeof(struct ieee80211_country_ie_triplet)); + + nxpwifi_dbg(priv->adapter, INFO, + "info: 11D Domain Info Resp: no_of_triplet=%d\n", + no_of_triplet); + + if (no_of_triplet > NXPWIFI_MAX_TRIPLET_802_11D) { + nxpwifi_dbg(priv->adapter, FATAL, + "11D: invalid number of triplets %d returned\n", + no_of_triplet); + return -EINVAL; + } + + switch (action) { + case HOST_ACT_GEN_SET: /* Proc Set Action */ + break; + case HOST_ACT_GEN_GET: + break; + default: + nxpwifi_dbg(priv->adapter, ERROR, + "11D: invalid action:%d\n", domain_info->action); + return -EINVAL; + } + + return 0; +} + +static int nxpwifi_set_aes_key(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + struct nxpwifi_ds_encrypt_key *enc_key, + struct host_cmd_ds_802_11_key_material *km) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + u16 size, len = KEY_PARAMS_FIXED_LEN; + + if (enc_key->is_igtk_key) { + nxpwifi_dbg(adapter, INFO, + "%s: Set CMAC AES Key\n", __func__); + if (enc_key->is_rx_seq_valid) + memcpy(km->key_param_set.key_params.cmac_aes.ipn, + enc_key->pn, enc_key->pn_len); + km->key_param_set.key_info &= cpu_to_le16(~KEY_MCAST); + km->key_param_set.key_info |= cpu_to_le16(KEY_IGTK); + km->key_param_set.key_type = KEY_TYPE_ID_AES_CMAC; + km->key_param_set.key_params.cmac_aes.key_len = + cpu_to_le16(enc_key->key_len); + memcpy(km->key_param_set.key_params.cmac_aes.key, + enc_key->key_material, enc_key->key_len); + len += sizeof(struct nxpwifi_cmac_aes_param); + } else if (enc_key->is_igtk_def_key) { + nxpwifi_dbg(adapter, INFO, + "%s: Set CMAC default Key index\n", __func__); + km->key_param_set.key_type = KEY_TYPE_ID_AES_CMAC_DEF; + km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK; + } else { + nxpwifi_dbg(adapter, INFO, + "%s: Set AES Key\n", __func__); + if (enc_key->is_rx_seq_valid) + memcpy(km->key_param_set.key_params.aes.pn, + enc_key->pn, enc_key->pn_len); + km->key_param_set.key_type = KEY_TYPE_ID_AES; + km->key_param_set.key_params.aes.key_len = + cpu_to_le16(enc_key->key_len); + memcpy(km->key_param_set.key_params.aes.key, + enc_key->key_material, enc_key->key_len); + len += sizeof(struct nxpwifi_aes_param); + } + + km->key_param_set.len = cpu_to_le16(len); + size = len + sizeof(struct nxpwifi_ie_types_header) + + sizeof(km->action) + S_DS_GEN; + cmd->size = cpu_to_le16(size); + + return 0; +} + +static int +nxpwifi_cmd_sta_802_11_key_material(struct nxpwifi_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_no, void *data_buf, + u16 cmd_action, u32 cmd_type) +{ + struct nxpwifi_adapter *adapter = priv->adapter; + struct nxpwifi_ds_encrypt_key *enc_key = + (struct nxpwifi_ds_encrypt_key *)data_buf; + u8 *mac = enc_key->mac_addr; + u16 key_info, len = KEY_PARAMS_FIXED_LEN; + struct host_cmd_ds_802_11_key_material *km = + &cmd->params.key_material; + + cmd->command = cpu_to_le16(HOST_CMD_802_11_KEY_MATERIAL); + km->action = cpu_to_le16(cmd_action); + + if (cmd_action == HOST_ACT_GEN_GET) { + nxpwifi_dbg(adapter, INFO, "%s: Get key\n", __func__); + km->key_param_set.key_idx = + enc_key->key_index & KEY_INDEX_MASK; + km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2); + km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN); + memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN); + + if (enc_key->key_index & NXPWIFI_KEY_INDEX_UNICAST) + key_info = KEY_UNICAST; + else + key_info = KEY_MCAST; + + if (enc_key->is_igtk_key) + key_info |= KEY_IGTK; + + km->key_param_set.key_info = cpu_to_le1