From patchwork Thu Apr 17 13:51:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882861 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BB1C824EAA4 for ; Thu, 17 Apr 2025 13:52:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897971; cv=none; b=SXLWsBU0DAnpZzFp/CIU+Q/Gnc9e/JP3BS2N3tjehdx49wiwZgZuwn5mIkVkswTzsM70KbQVMuaonfkHp3ZV6ajmt9cM1iGqPLzp9ChIfD8ZHakzohc58GtscbMlW15r3bGI8n/AtfDQXsyqKJbSiQgaXNtw4rtsSh/FN8vJPTA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897971; c=relaxed/simple; bh=53IOtVgFkFYEwZwYVFct7/9NhJvm/Y9iJnBNzLZnLE0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=NefF1LttHzEDqyfKtFscIHjpMs3YdHkVL3DQAq/8v5RBZ2tFXcuL515fJt+Vr7zOLEh/DobKVY5j+DuStPf63/PRuNfEq279a8hFlkVHSIDnuXU9G9DLAOj2eyW4jWgL/mQLhY0xs4g6aIJx/i57TIKD6kNzAScsOI3eqLj47oU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: 7Kh3jNAPQjy3OKQYbJoUgw== X-CSE-MsgGUID: a7+IvEJ6Tuq6wCYFr6hoHg== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:52:48 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 175544006DE8; Thu, 17 Apr 2025 22:52:43 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 01/38] wireless: add Renesas vendor Date: Thu, 17 Apr 2025 16:51:59 +0300 Message-Id: <20250417135236.52410-2-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index c6599594dc99..7d865220cf59 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -30,6 +30,7 @@ source "drivers/net/wireless/microchip/Kconfig" source "drivers/net/wireless/purelifi/Kconfig" source "drivers/net/wireless/ralink/Kconfig" source "drivers/net/wireless/realtek/Kconfig" +source "drivers/net/wireless/renesas/Kconfig" source "drivers/net/wireless/rsi/Kconfig" source "drivers/net/wireless/silabs/Kconfig" source "drivers/net/wireless/st/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index e1c4141c6004..fcfb3ec09dee 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_WLAN_VENDOR_PURELIFI) += purelifi/ obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/ obj-$(CONFIG_WLAN_VENDOR_RALINK) += ralink/ obj-$(CONFIG_WLAN_VENDOR_REALTEK) += realtek/ +obj-$(CONFIG_WLAN_VENDOR_RENESAS) += renesas/ obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/ obj-$(CONFIG_WLAN_VENDOR_SILABS) += silabs/ obj-$(CONFIG_WLAN_VENDOR_ST) += st/ From patchwork Thu Apr 17 13:52:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882275 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8306C24EAA0 for ; Thu, 17 Apr 2025 13:52:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897977; cv=none; b=c3ry3APXiLiNwLYDJpgzEFlm5jmOZNHC7vQCkuO0C+9ln2gEKf88Cv5dKHRnxsaU/XCv7y4CHM74prfFGGToRe6zfO9FsCKQcM/9wGZfxf6gy3FxGMyT9oJKPM225G686F53n/+OgRUMa6ctTOTiisq323e/gKEry0Za25DpfTU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897977; c=relaxed/simple; bh=pDYvL20GbbhHQPz4Z0NeeVhtoq8nKSHSUt1jkOx+ieY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=U8wl+/bFrpu+ZOvXlphuYAQXpbZ3h8QHSagmGQqHboIY34ny94BNfL/T6N316UMRpr9RonOs7bQADOsHrHto/cW+RFJqMf22v2IpM7Vbr6j/dBS5zsdsRV3rszvozaLp3RNamUZ7NVIJAEWSv8hLchKfIoMVb1mQClxbPyi20WU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: /dW/BvinTO6GufxkkztNbA== X-CSE-MsgGUID: 8npkbcg3SnyEiUw827lyoA== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:52:52 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 16DB04006DE8; Thu, 17 Apr 2025 22:52:48 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 02/38] renesas: add Kconfig Date: Thu, 17 Apr 2025 16:52:00 +0300 Message-Id: <20250417135236.52410-3-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/Kconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 drivers/net/wireless/renesas/Kconfig diff --git a/drivers/net/wireless/renesas/Kconfig b/drivers/net/wireless/renesas/Kconfig new file mode 100644 index 000000000000..9607b36b3d8c --- /dev/null +++ b/drivers/net/wireless/renesas/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +config WLAN_VENDOR_RENESAS + bool "Renesas devices" + default y + help + If you have a wireless card belonging to this class, say Y. + +if WLAN_VENDOR_RENESAS + +source "drivers/net/wireless/renesas/ra6w/Kconfig" + +endif # WLAN_VENDOR_RENESAS From patchwork Thu Apr 17 13:52:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882860 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 2D01424E4CB for ; Thu, 17 Apr 2025 13:52:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897981; cv=none; b=TmLIi/c+CRulOUnj/1/tWnoikjKlCHq5KG6HKqCk4w4DJThO/bEXb3g/lb+I16gcLGsmzeTdvdirwDgRYNQ73smtHXM9/83UTEWCvhVH2apyzXRPmjQIZwY7c0xVSV/u4p1MHCcxlA5rEUGNC3IdAiz4Ah1WvxxzI+a8kPb+ZJg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897981; c=relaxed/simple; bh=BDMdGtwaLvScDAFZXwtsqejy1APdeoAS+JH5eKXTI5c=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=KUHjSS0v0KZUT7CvYkFrBmMAlUt1vbiMdhJ4znfAtSr+SF6Sr1GGZPHy6mGMSaEGgWgaRugHRxO3H4opFTpZEXxI3/pq35YM9JL0SHbh4AE2Q6tjHQvE/Rvn6pMbZ7FzLcobjo/t+j4i00YTU4xGuvnfO5tu9ncvkAk93jBQXFo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: D90U0r4uRaC0O9vdPt6PGw== X-CSE-MsgGUID: wqsJqDkaRuiUDbGWHU3FmQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:52:56 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 42F144005B3F; Thu, 17 Apr 2025 22:52:52 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 03/38] renesas: add Makefile Date: Thu, 17 Apr 2025 16:52:01 +0300 Message-Id: <20250417135236.52410-4-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/Makefile | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 drivers/net/wireless/renesas/Makefile diff --git a/drivers/net/wireless/renesas/Makefile b/drivers/net/wireless/renesas/Makefile new file mode 100644 index 000000000000..a8253bcc7d02 --- /dev/null +++ b/drivers/net/wireless/renesas/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_RA6W) += ra6w/ From patchwork Thu Apr 17 13:52:02 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882274 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A4F8224EAB6 for ; Thu, 17 Apr 2025 13:53:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897989; cv=none; b=tRs196urj2Dv82FQBXegxajzk/rSqS/06z647xtVYL/VlpVibEcAlfBpNFdQDTYSzaXgp/OP0XbwlinTdKvzWMBA1hSqhfSQce+P51g4oDhPCwRrA7V6454pnNy6jsBM+8SusxEoy2LMk7Xyov5DNcAXrmegvyN6yj7QdOD7luw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897989; c=relaxed/simple; bh=K3hbmSn2IEDrGLVS2GRWOhf3+NthrsVcfb1MyA7W6Rc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=n0I4bYSBsJUdslBb3d8hNRAKKVVqqkW+zj0I9eV5UR1DESF7Gx1a2OVabnJPiGohpVyfVbWLkpd67NfkmoN3ZBmodvKml1rTv4eFZsHS6QNdPfBLJi0XDN4Z9VZA7hp8HJ4Uj5HevZsGH0HG9AAzWQNsYRajq3MPP3Udg8cGA1Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: E2WY/yqhTPKLgbO9DKXgZw== X-CSE-MsgGUID: jwSxsgL6Tcu7MLCaKX5jyA== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:03 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 6D42B4006DE8; Thu, 17 Apr 2025 22:52:57 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 04/38] ra6w: add cfg80211.c Date: Thu, 17 Apr 2025 16:52:02 +0300 Message-Id: <20250417135236.52410-5-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/cfg80211.c | 2519 ++++++++++++++++++ 1 file changed, 2519 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/cfg80211.c diff --git a/drivers/net/wireless/renesas/ra6w/cfg80211.c b/drivers/net/wireless/renesas/ra6w/cfg80211.c new file mode 100644 index 000000000000..bbe035751bf1 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/cfg80211.c @@ -0,0 +1,2519 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains communication with cfg80211 module. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dbg.h" +#include "core.h" +#include "ctrl.h" +#include "cfg80211.h" +#include "dev.h" +#include "dbgfs.h" +#include "testmode.h" +#include "params.h" + +#define RATE(_bitrate, _hw_rate, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate), \ +} + +#define CHAN(_band, _channel, _freq) { \ + .band = (_band), \ + .hw_value = (_channel), \ + .center_freq = (_freq), \ + .flags = 0, \ + .max_antenna_gain = 0, \ + .max_power = RA6W_CFG80211_CH_MAX_POWER, \ +} + +static const u8 ra6w_ac2hwq[IEEE80211_NUM_ACS] = { + [NL80211_TXQ_Q_VO] = RA6W_CMD_AC_VO, + [NL80211_TXQ_Q_VI] = RA6W_CMD_AC_VI, + [NL80211_TXQ_Q_BE] = RA6W_CMD_AC_BE, + [NL80211_TXQ_Q_BK] = RA6W_CMD_AC_BK +}; + +static struct ieee80211_iface_limit ra6w_if_limits[] = { + { + .max = RA6W_CFG80211_VIF_MAX, + .types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) + } +}; + +static const struct ieee80211_iface_combination ra6w_if_comb[] = { + { + .limits = ra6w_if_limits, + .n_limits = ARRAY_SIZE(ra6w_if_limits), + .num_different_channels = RA6W_CFG80211_CHANINFO_MAX, + .max_interfaces = RA6W_CFG80211_VIF_MAX, + }, +}; + +static struct ieee80211_txrx_stypes ra6w_macm_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .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) + }, + [NL80211_IFTYPE_P2P_DEVICE] = { + .tx = 0xffff, + .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) + }, +}; + +static u32 ra6w_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + 0, + 0, + 0, + 0, + 0 +}; + +static struct ieee80211_rate ra6w_rate_table[] = { + RATE(10, 0x00, 0), + RATE(20, 0x01, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, 0x02, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, 0x03, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0x04, 0), + RATE(90, 0x05, 0), + RATE(120, 0x06, 0), + RATE(180, 0x07, 0), + RATE(240, 0x08, 0), + RATE(360, 0x09, 0), + RATE(480, 0x0A, 0), + RATE(540, 0x0B, 0), +}; + +static struct ieee80211_channel ra6w_chans_2g[] = { + CHAN(NL80211_BAND_2GHZ, 1, 2412), + CHAN(NL80211_BAND_2GHZ, 2, 2417), + CHAN(NL80211_BAND_2GHZ, 3, 2422), + CHAN(NL80211_BAND_2GHZ, 4, 2427), + CHAN(NL80211_BAND_2GHZ, 5, 2432), + CHAN(NL80211_BAND_2GHZ, 6, 2437), + CHAN(NL80211_BAND_2GHZ, 7, 2442), + CHAN(NL80211_BAND_2GHZ, 8, 2447), + CHAN(NL80211_BAND_2GHZ, 9, 2452), + CHAN(NL80211_BAND_2GHZ, 10, 2457), + CHAN(NL80211_BAND_2GHZ, 11, 2462), + CHAN(NL80211_BAND_2GHZ, 12, 2467), + CHAN(NL80211_BAND_2GHZ, 13, 2472), + CHAN(NL80211_BAND_2GHZ, 14, 2484), +}; + +static struct ieee80211_channel ra6w_chans_5g[] = { + CHAN(NL80211_BAND_5GHZ, 36, 5180), + CHAN(NL80211_BAND_5GHZ, 40, 5200), + CHAN(NL80211_BAND_5GHZ, 44, 5220), + CHAN(NL80211_BAND_5GHZ, 48, 5240), + CHAN(NL80211_BAND_5GHZ, 52, 5260), + CHAN(NL80211_BAND_5GHZ, 56, 5280), + CHAN(NL80211_BAND_5GHZ, 60, 5300), + CHAN(NL80211_BAND_5GHZ, 64, 5320), + CHAN(NL80211_BAND_5GHZ, 100, 5500), + CHAN(NL80211_BAND_5GHZ, 104, 5520), + CHAN(NL80211_BAND_5GHZ, 108, 5540), + CHAN(NL80211_BAND_5GHZ, 112, 5560), + CHAN(NL80211_BAND_5GHZ, 116, 5580), + CHAN(NL80211_BAND_5GHZ, 120, 5600), + CHAN(NL80211_BAND_5GHZ, 124, 5620), + CHAN(NL80211_BAND_5GHZ, 128, 5640), + CHAN(NL80211_BAND_5GHZ, 132, 5660), + CHAN(NL80211_BAND_5GHZ, 136, 5680), + CHAN(NL80211_BAND_5GHZ, 140, 5700), + CHAN(NL80211_BAND_5GHZ, 144, 5720), + CHAN(NL80211_BAND_5GHZ, 149, 5745), + CHAN(NL80211_BAND_5GHZ, 153, 5765), + CHAN(NL80211_BAND_5GHZ, 157, 5785), + CHAN(NL80211_BAND_5GHZ, 161, 5805), + CHAN(NL80211_BAND_5GHZ, 165, 5825), + CHAN(NL80211_BAND_5GHZ, 169, 5845), + CHAN(NL80211_BAND_5GHZ, 173, 5865), +}; + +static struct ieee80211_sband_iftype_data ra6w_cap_he_2g = { + .types_mask = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP), +}; + +static struct ieee80211_sband_iftype_data ra6w_cap_he_5g = { + .types_mask = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP), +}; + +static struct ieee80211_supported_band ra6w_band_2g = { + .channels = ra6w_chans_2g, + .n_channels = ARRAY_SIZE(ra6w_chans_2g), + .bitrates = ra6w_rate_table, + .n_bitrates = ARRAY_SIZE(ra6w_rate_table), + .n_iftype_data = 1, + .band = NL80211_BAND_2GHZ, +}; + +static struct ieee80211_supported_band ra6w_band_5g = { + .channels = ra6w_chans_5g, + .n_channels = ARRAY_SIZE(ra6w_chans_5g), + .bitrates = &ra6w_rate_table[4], + .n_bitrates = ARRAY_SIZE(ra6w_rate_table) - 4, + .n_iftype_data = 1, + .band = NL80211_BAND_5GHZ, +}; + +static const struct ra6w_cfg80211_legrate ra6w_legacy_rate_table[] = { + [0] = { .idx = 0, .rate = 10 }, + [1] = { .idx = 1, .rate = 20 }, + [2] = { .idx = 2, .rate = 55 }, + [3] = { .idx = 3, .rate = 110 }, + [4] = { .idx = -1, .rate = 0 }, + [5] = { .idx = -1, .rate = 0 }, + [6] = { .idx = -1, .rate = 0 }, + [7] = { .idx = -1, .rate = 0 }, + [8] = { .idx = 10, .rate = 480 }, + [9] = { .idx = 8, .rate = 240 }, + [10] = { .idx = 6, .rate = 120 }, + [11] = { .idx = 4, .rate = 60 }, + [12] = { .idx = 11, .rate = 540 }, + [13] = { .idx = 9, .rate = 360 }, + [14] = { .idx = 7, .rate = 180 }, + [15] = { .idx = 5, .rate = 90 }, +}; + +static const int ra6w_mcs_map_to_rate[] = { + [IEEE80211_VHT_MCS_SUPPORT_0_7] = 65, + [IEEE80211_VHT_MCS_SUPPORT_0_8] = 78, + [IEEE80211_VHT_MCS_SUPPORT_0_9] = 78, +}; + +static void ra6w_cfg80211_dev_init(struct net_device *ndev) +{ + ra6w_dev_init(ndev); +} + +static void ra6w_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *req) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + + ra6w_dbg("[%s] initiator=%d, alpha=%c%c\n", __func__, + req->initiator, req->alpha2[0], req->alpha2[1]); + + memcpy(priv->phy_config.country_code, req->alpha2, sizeof(req->alpha2)); + + ra6w_ctrl_chan_config(&priv->core->ctrl, wiphy); +} + +u8 *ra6w_cfg80211_create_beacon(struct ra6w_cfg80211_beacon_info *bcn, + struct cfg80211_beacon_data *new) +{ + u8 *buf = NULL; + u8 *pos = NULL; + + if (new->head) { + u8 *head = kzalloc(new->head_len, GFP_KERNEL); + + if (!head) + return NULL; + + kfree(bcn->head); + + bcn->head = head; + bcn->head_len = new->head_len; + memcpy(bcn->head, new->head, new->head_len); + } + + if (new->tail) { + u8 *tail = kzalloc(new->tail_len, GFP_KERNEL); + + if (!tail) + return NULL; + + kfree(bcn->tail); + + bcn->tail = tail; + bcn->tail_len = new->tail_len; + memcpy(bcn->tail, new->tail, new->tail_len); + } + + if (!bcn->head) + return NULL; + + bcn->tim_len = 6; + bcn->len = bcn->head_len + bcn->tail_len + bcn->ies_len + bcn->tim_len; + + buf = kzalloc(bcn->len, GFP_KERNEL); + if (!buf) + return NULL; + + pos = buf; + memcpy(pos, bcn->head, bcn->head_len); + pos += bcn->head_len; + *pos++ = WLAN_EID_TIM; + *pos++ = 4; + *pos++ = 0; + *pos++ = bcn->dtim_period; + *pos++ = 0; + *pos++ = 0; + if (bcn->tail) { + memcpy(pos, bcn->tail, bcn->tail_len); + pos += bcn->tail_len; + } + + if (bcn->ies) + memcpy(pos, bcn->ies, bcn->ies_len); + + return buf; +} + +static void ra6w_cfg80211_remove_beacon(struct ra6w_cfg80211_beacon_info *bcn) +{ + kfree(bcn->head); + bcn->head = NULL; + bcn->head_len = 0; + + kfree(bcn->tail); + bcn->tail = NULL; + bcn->tail_len = 0; + + kfree(bcn->ies); + bcn->ies = NULL; + bcn->ies_len = 0; + bcn->tim_len = 0; + bcn->dtim_period = 0; + bcn->len = 0; +} + +static void ra6w_cfg80211_csa_remove(struct ra6w_cfg80211_vif *vif) +{ + struct ra6w_cfg80211_csa_info *csa = vif->ap.csa; + + if (!csa) + return; + + ra6w_cfg80211_remove_beacon(&csa->bcn); + kfree(csa); + vif->ap.csa = NULL; +} + +struct ra6w_cfg80211_chan_info *ra6w_cfg80211_chaninfo_get(struct ra6w_cfg80211_vif *vif) +{ + struct ra6w_cfg80211_priv *priv; + + if (!vif) + return NULL; + + priv = vif->priv; + if (!priv) + return NULL; + + if (vif->ch_idx >= RA6W_CFG80211_CHANINFO_MAX || + !priv->chaninfo_table[vif->ch_idx].chan_def.chan) + return NULL; + + return &priv->chaninfo_table[vif->ch_idx]; +} + +static void ra6w_cfg80211_csa_work(struct work_struct *ws) +{ + struct ra6w_cfg80211_csa_info *csa = container_of(ws, struct ra6w_cfg80211_csa_info, + work); + struct ra6w_cfg80211_vif *vif = csa->vif; + struct ra6w_cfg80211_priv *priv = vif->priv; + + if (!priv) + goto out; + + if (csa->status) { + cfg80211_stop_iface(priv->wiphy, &vif->wdev, GFP_KERNEL); + goto out; + } + + ra6w_ctrl_change_beacon_req(&priv->core->ctrl, vif->vif_idx, + csa->buf, + csa->bcn.len, csa->bcn.head_len, + csa->bcn.tim_len, NULL); + + wiphy_lock(priv->wiphy); + ra6w_cfg80211_chaninfo_unset(vif); + ra6w_cfg80211_chaninfo_set(vif, csa->ch_idx, &csa->chandef); + cfg80211_ch_switch_notify(vif->ndev, &csa->chandef, 0); + wiphy_unlock(priv->wiphy); + +out: + ra6w_cfg80211_csa_remove(vif); +} + +static int ra6w_cfg80211_station_info_fill(struct ra6w_cfg80211_sta *sta, + struct station_info *sinfo, + struct ra6w_cfg80211_vif *vif) +{ + const struct ra6w_cfg80211_sta_stats *stats = &sta->stats; + u16 format_mod = 0; + + sinfo->generation = vif->generation; + sinfo->inactive_time = jiffies_to_msecs(jiffies - stats->last_acttive_time); + sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME); + sinfo->rx_bytes = sta->stats.rx_bytes; + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); + sinfo->rx_packets = sta->stats.rx_packets; + sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); + sinfo->tx_bytes = sta->stats.tx_bytes; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64); + sinfo->tx_packets = sta->stats.tx_packets; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); + sinfo->tx_failed = sta->stats.tx_failed; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->signal = stats->last_rx_data_ext.rssi1; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + + switch (stats->last_rx_data_ext.ch_bw) { + case 0: + sinfo->rxrate.bw = RATE_INFO_BW_20; + break; + case 1: + sinfo->rxrate.bw = RATE_INFO_BW_40; + break; + case 2: + sinfo->rxrate.bw = RATE_INFO_BW_80; + break; + case 3: + sinfo->rxrate.bw = RATE_INFO_BW_160; + break; + default: + sinfo->rxrate.bw = RATE_INFO_BW_HE_RU; + break; + } + + if (stats->last_rx_data_ext.pre_type) + format_mod = stats->last_rx_data_ext.format_mod + 1; + else + format_mod = stats->last_rx_data_ext.format_mod; + + if (stats->last_stats.format_mod > 1 && format_mod < 2) + format_mod = stats->last_stats.format_mod; + + switch (format_mod) { + case RA6W_CFG80211_FORMATMOD_NON_HT: + case RA6W_CFG80211_FORMATMOD_NON_HT_DUP_OFDM: + sinfo->rxrate.flags = 0; + sinfo->rxrate.legacy = + ra6w_legacy_rate_table[stats->last_rx_data_ext.leg_rate].rate; + break; + case RA6W_CFG80211_FORMATMOD_HT_MF: + case RA6W_CFG80211_FORMATMOD_HT_GF: + sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS; + if (stats->last_stats.ht.short_gi) + sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + sinfo->rxrate.mcs = stats->last_stats.ht.mcs; + break; + case RA6W_CFG80211_FORMATMOD_VHT: + sinfo->rxrate.flags = RATE_INFO_FLAGS_VHT_MCS; + if (stats->last_stats.vht.short_gi) + sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + sinfo->rxrate.mcs = stats->last_stats.vht.mcs; + sinfo->rxrate.nss = stats->last_stats.vht.nss + 1; + break; + case RA6W_CFG80211_FORMATMOD_HE_MU: + sinfo->rxrate.he_ru_alloc = stats->last_stats.he.ru_size; + fallthrough; + case RA6W_CFG80211_FORMATMOD_HE_SU: + case RA6W_CFG80211_FORMATMOD_HE_ER: + case RA6W_CFG80211_FORMATMOD_HE_TB: + sinfo->rxrate.flags = RATE_INFO_FLAGS_HE_MCS; + sinfo->rxrate.mcs = stats->last_stats.he.mcs; + sinfo->rxrate.nss = stats->last_stats.he.nss; + sinfo->rxrate.he_gi = stats->last_stats.he.gi_type; + sinfo->rxrate.he_dcm = stats->last_stats.he.dcm; + break; + default: + return -EINVAL; + } + + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); + + return 0; +} + +struct ra6w_cfg80211_sta *ra6w_cfg80211_sta_get(struct ra6w_cfg80211_priv *priv, u8 sta_idx) +{ + if (!priv) + return NULL; + + if (sta_idx >= RA6W_CFG80211_STA_TABLE_MAX) + return NULL; + + return &priv->sta_table[sta_idx]; +} + +void ra6w_cfg80211_sta_free(struct ra6w_cfg80211_vif *vif, u8 sta_idx) +{ + struct ra6w_cfg80211_priv *priv = vif->priv; + struct ra6w_cfg80211_sta *sta = NULL; + + if (!priv) + return; + + sta = ra6w_cfg80211_sta_get(priv, sta_idx); + if (!sta) + return; + + switch (vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + list_del(&sta->list); + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + vif->sta.ap = NULL; + default: + break; + } + + sta->valid = false; + sta->aid = RA6W_CFG80211_STA_IDX_INVALID; + sta->sta_idx = RA6W_CFG80211_STA_IDX_INVALID; + sta->vif_idx = RA6W_CFG80211_VIF_IDX_INVALID; + memset(sta->mac_addr, 0, ETH_ALEN); +} + +static struct ra6w_cfg80211_sta *ra6w_cfg80211_find_sta(struct ra6w_cfg80211_priv *priv, + const u8 *mac_addr) +{ + struct ra6w_cfg80211_sta *sta = NULL; + u8 i; + + for (i = 0; i < RA6W_CFG80211_STA_MAX; i++) { + sta = ra6w_cfg80211_sta_get(priv, i); + if (!sta) + continue; + + if (sta->valid && ether_addr_equal(sta->mac_addr, mac_addr)) + return sta; + } + + return NULL; +} + +static int _ra6w_cfg80211_del_station(struct ra6w_cfg80211_vif *vif, const u8 *mac) +{ + struct ra6w_cfg80211_priv *priv = vif->priv; + struct ra6w_ctrl *ctrl = &priv->core->ctrl; + struct ra6w_cfg80211_sta *sta = NULL; + struct ra6w_cfg80211_sta *tmp = NULL; + int ret = 0; + bool all_sta = false; + + if (!mac || is_broadcast_ether_addr(mac)) + all_sta = true; + + list_for_each_entry_safe(sta, tmp, &vif->ap.sta_list, list) { + if (all_sta || (mac && ether_addr_equal(sta->mac_addr, mac))) { + u8 sta_idx = sta->sta_idx; + + ra6w_cfg80211_sta_free(vif, sta_idx); + + ret = ra6w_ctrl_del_station_req(ctrl, sta_idx, false); + if (ret) + return ret; + + vif->generation++; + + if (!all_sta) + break; + } + } + + return 0; +} + +static int ra6w_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params) +{ + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + const u8 *mac = NULL; + + if (!vif->up) + return -EIO; + + if (params) + mac = params->mac; + + return _ra6w_cfg80211_del_station(vif, mac); +} + +static int ra6w_cfg80211_vif_assign(struct ra6w_cfg80211_priv *priv, enum nl80211_iftype type, + u8 *vif_idx, u8 *addr_idx) +{ + struct ra6w_cmd_add_if_rsp rsp = { 0 }; + int ret; + bool p2p = false; + unsigned long n; + + switch (type) { + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + p2p = true; + break; + default: + break; + } + + n = find_first_zero_bit(priv->addr_map, RA6W_CFG80211_VIF_MAX); + if (n >= RA6W_CFG80211_VIF_MAX) + return -EIO; + + ret = ra6w_ctrl_if_add(&priv->core->ctrl, priv->addresses[n].addr, (u8)type, p2p, &rsp); + if (ret) + return ret; + + *addr_idx = (u8)n; + *vif_idx = rsp.vif_idx; + + return 0; +} + +static void ra6w_cfg80211_vif_unassign(struct ra6w_cfg80211_priv *priv, u8 vif_idx, u8 addr_idx) +{ + struct ra6w_cfg80211_vif *vif = ra6w_cfg80211_vif_get(priv, vif_idx); + + if (!vif) + return; + + list_del(&vif->list); + priv->vif_table[vif_idx] = NULL; + clear_bit(addr_idx, priv->addr_map); + clear_bit(vif_idx, priv->vif_map); + + ra6w_ctrl_if_remove(&priv->core->ctrl, vif_idx); +} + +static int ra6w_cfg80211_vif_type_allowed(struct ra6w_cfg80211_priv *priv, + enum nl80211_iftype type) +{ + struct ra6w_cfg80211_vif *vif = NULL; + bool mon_presents = false; + bool data_presents = false; + + switch (type) { + case NL80211_IFTYPE_MONITOR: + mon_presents = true; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_P2P_DEVICE: + case NL80211_IFTYPE_AP: + data_presents = true; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_OCB: + case NL80211_IFTYPE_NAN: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_UNSPECIFIED: + default: + return -EOPNOTSUPP; + } + + list_for_each_entry(vif, &priv->vifs, list) { + if (vif->type == NL80211_IFTYPE_MONITOR) { + mon_presents = true; + continue; + } + + data_presents = true; + } + + if (mon_presents && data_presents) { + wiphy_err(priv->wiphy, + "Can't enable monitor and data interfaces simultaneosly\n"); + return -EPERM; + } + + return 0; +} + +static struct net_device *ra6w_cfg80211_alloc_ndev(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + u8 addr_idx, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct ra6w_cfg80211_vif *vif; + struct net_device *ndev; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct sockaddr addr = { 0 }; + int ret; + + ndev = alloc_netdev_mqs(sizeof(*vif), name, name_assign_type, + ra6w_cfg80211_dev_init, + RA6W_CFG80211_NDEV_TXQ, + RA6W_CFG80211_NDEV_RXQ); + if (!ndev) + return ERR_PTR(-ENOMEM); + + vif = netdev_priv(ndev); + ndev->ieee80211_ptr = &vif->wdev; + ndev->ieee80211_ptr->iftype = type; + SET_NETDEV_DEV(ndev, wiphy_dev(wiphy)); + ether_addr_copy(addr.sa_data, priv->addresses[addr_idx].addr); + ret = eth_mac_addr(ndev, &addr); + if (ret) + return ERR_PTR(ret); + + if (params) + ndev->ieee80211_ptr->use_4addr = params->use_4addr; + + return ndev; +} + +static struct wireless_dev *ra6w_cfg80211_add_iface(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params) +{ + int ret = -EFAULT; + struct net_device *ndev = NULL; + struct ra6w_cfg80211_vif *vif = NULL; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + u8 vif_idx = 0; + u8 addr_idx = 0; + + ret = ra6w_cfg80211_vif_type_allowed(priv, type); + if (ret) + return ERR_PTR(ret); + + ret = ra6w_cfg80211_vif_assign(priv, type, &vif_idx, &addr_idx); + if (ret) + return ERR_PTR(ret); + + ndev = ra6w_cfg80211_alloc_ndev(wiphy, name, name_assign_type, addr_idx, type, params); + if (IS_ERR(ndev)) + return ERR_PTR(-ENOMEM); + + vif = netdev_priv(ndev); + vif->wdev.wiphy = priv->wiphy; + vif->priv = priv; + vif->ndev = ndev; + vif->wdev.netdev = ndev; + vif->wdev.iftype = type; + vif->up = false; + vif->ch_idx = RA6W_CFG80211_CH_IDX_INVALID; + vif->generation = 0; + vif->vif_idx = vif_idx; + set_bit(vif_idx, priv->vif_map); + vif->addr_idx = addr_idx; + set_bit(addr_idx, priv->addr_map); + vif->type = type; + + switch (type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + INIT_LIST_HEAD(&vif->ap.sta_list); + memset(&vif->ap.bcn, 0, sizeof(vif->ap.bcn)); + vif->ap.ap_isolate = 0; + break; + case NL80211_IFTYPE_MONITOR: + ndev->type = ARPHRD_IEEE80211_RADIOTAP; + ra6w_dev_set_monitor_ops(ndev); + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_OCB: + case NL80211_IFTYPE_NAN: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MESH_POINT: + ret = -EOPNOTSUPP; + goto vif_unset; + case NL80211_IFTYPE_UNSPECIFIED: + ret = -EINVAL; + goto vif_unset; + default: + break; + } + + if (params) + vif->use_4addr = params->use_4addr; + + priv->vif_table[vif_idx] = vif; + list_add_tail(&vif->list, &priv->vifs); + set_bit(vif_idx, priv->vif_map); + + ret = cfg80211_register_netdevice(ndev); + if (ret) { + ra6w_err("[%s] %s not registered: %d\n", __func__, ndev->name, ret); + goto vif_unset; + } + + return &vif->wdev; + +vif_unset: + ra6w_cfg80211_vif_unassign(priv, vif_idx, addr_idx); + free_netdev(ndev); + + return ERR_PTR(ret); +} + +static void ra6w_cfg80211_vif_cleanup(struct ra6w_cfg80211_vif *vif) +{ + struct net_device *ndev = vif->ndev; + + if (ndev->reg_state == NETREG_REGISTERED) + unregister_netdevice(ndev); + + ndev->ieee80211_ptr = NULL; + vif->ndev = NULL; +} + +static int ra6w_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(wdev->netdev); + + ra6w_cfg80211_vif_cleanup(vif); + ra6w_cfg80211_vif_unassign(priv, vif->vif_idx, vif->addr_idx); + + return 0; +} + +static int ra6w_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, struct vif_params *params) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + int ret; + u8 vif_idx; + u8 addr_idx; + + if (vif->up) + return -EBUSY; + + ret = ra6w_cfg80211_vif_type_allowed(priv, type); + if (ret) + return ret; + + ra6w_cfg80211_vif_unassign(priv, vif->vif_idx, vif->addr_idx); + + ret = ra6w_cfg80211_vif_assign(priv, type, &vif_idx, &addr_idx); + if (ret) + return ret; + + vif->type = type; + vif->vif_idx = vif_idx; + vif->addr_idx = addr_idx; + set_bit(addr_idx, priv->addr_map); + + priv->vif_table[vif->vif_idx] = vif; + list_add_tail(&vif->list, &priv->vifs); + set_bit(vif_idx, priv->vif_map); + + ndev->type = ARPHRD_ETHER; + ra6w_dev_set_ops(ndev); + + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + vif->sta.flags = 0; + vif->sta.ap = NULL; + vif->sta.tdls_sta = NULL; + break; + case NL80211_IFTYPE_MESH_POINT: + return -EOPNOTSUPP; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + INIT_LIST_HEAD(&vif->ap.sta_list); + memset(&vif->ap.bcn, 0, sizeof(vif->ap.bcn)); + vif->ap.ap_isolate = 0; + break; + case NL80211_IFTYPE_MONITOR: + ndev->type = ARPHRD_IEEE80211_RADIOTAP; + ra6w_dev_set_monitor_ops(ndev); + break; + default: + break; + } + + vif->generation = 0; + vif->wdev.iftype = type; + + if (params->use_4addr != -1) + vif->use_4addr = params->use_4addr; + + return 0; +} + +static int ra6w_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *req) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = container_of(req->wdev, struct ra6w_cfg80211_vif, wdev); + + if (!vif->up) + return -EIO; + + if (vif->type == NL80211_IFTYPE_AP) + return -EOPNOTSUPP; + + if (priv->scan_request) + return -EAGAIN; + + ret = ra6w_ctrl_scan_start(&priv->core->ctrl, req); + if (ret) + return ret; + + priv->scan_request = req; + + return 0; +} + +static void ra6w_cfg80211_scan_abort(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = container_of(wdev, struct ra6w_cfg80211_vif, wdev); + + if (!priv->scan_request) + return; + + ra6w_ctrl_scan_cancel(&priv->core->ctrl, vif); +} + +void ra6w_cfg80211_scan_done(struct ra6w_cfg80211_priv *priv) +{ + static struct cfg80211_scan_info scan_req = { + .aborted = true, + }; + + cfg80211_scan_done(priv->scan_request, &scan_req); + priv->scan_request = NULL; +} + +static int ra6w_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + + if (!vif->up) + return -EIO; + + ra6w_stats_deinit(&vif->stats); + + return ra6w_ctrl_disconnect_req(&priv->core->ctrl, vif, reason_code); +} + +struct ra6w_cfg80211_vif *ra6w_cfg80211_vif_get(struct ra6w_cfg80211_priv *priv, u8 vif_idx) +{ + if (!priv) + return NULL; + + if (!test_bit(vif_idx, priv->vif_map)) + return NULL; + + return priv->vif_table[vif_idx]; +} + +static int ra6w_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, + int link_id, u8 key_index, bool pairwise, + const u8 *mac_addr, struct key_params *params) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_sta *sta = NULL; + struct ra6w_cfg80211_key *key = NULL; + struct ra6w_cmd_key_add_rsp rsp = { 0 }; + u8 cipher_type = 0; + u8 *tk; + + if (key_index >= RA6W_CFG80211_KEYS_MAX) { + ra6w_err("Invalid key index\n"); + return -EINVAL; + } + + if (!vif->up) + return -EIO; + + if (mac_addr) { + sta = ra6w_cfg80211_find_sta(priv, mac_addr); + if (!sta) { + ra6w_err("No STA found with MAC address\n"); + return -EINVAL; + } + key = &sta->key; + } else { + key = &vif->keys[key_index]; + } + + tk = kzalloc(params->key_len, GFP_KERNEL); + if (!tk) + return -ENOMEM; + + memcpy(tk, params->key, params->key_len); + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + cipher_type = RA6W_CIPHER_WEP40; + break; + case WLAN_CIPHER_SUITE_WEP104: + cipher_type = RA6W_CIPHER_WEP104; + break; + case WLAN_CIPHER_SUITE_TKIP: + cipher_type = RA6W_CIPHER_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + cipher_type = RA6W_CIPHER_CCMP; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + cipher_type = RA6W_CIPHER_AES_CMAC_128; + break; + case WLAN_CIPHER_SUITE_SMS4: { + u8 tmp; + int i = 0; + + cipher_type = RA6W_CIPHER_SMS4; + + for (i = 0; i < RA6W_CFG80211_WPI_SUBKEY_LEN / 2; i++) { + tmp = tk[i]; + tk[i] = tk[RA6W_CFG80211_WPI_SUBKEY_LEN - 1 - i]; + tk[RA6W_CFG80211_WPI_SUBKEY_LEN - 1 - i] = tmp; + } + + for (i = 0; i < RA6W_CFG80211_WPI_SUBKEY_LEN / 2; i++) { + tmp = tk[i + RA6W_CFG80211_WPI_SUBKEY_LEN]; + tk[i + RA6W_CFG80211_WPI_SUBKEY_LEN] = + tk[RA6W_CFG80211_WPI_KEY_LEN - 1 - i]; + tk[RA6W_CFG80211_WPI_KEY_LEN - 1 - i] = tmp; + } + break; + } + case WLAN_CIPHER_SUITE_GCMP: + cipher_type = RA6W_CIPHER_GCMP_128; + break; + case WLAN_CIPHER_SUITE_GCMP_256: + cipher_type = RA6W_CIPHER_GCMP_256; + break; + case WLAN_CIPHER_SUITE_CCMP_256: + cipher_type = RA6W_CIPHER_CCMP_256; + break; + default: + ra6w_err("[%s] Unsupported cipher %d\n", __func__, params->cipher); + ret = -EINVAL; + goto free; + } + + key->cipher_type = cipher_type; + key->pairwise = pairwise; + key->sta_idx = sta ? sta->sta_idx : RA6W_CFG80211_STA_IDX_INVALID; + key->vif_idx = vif->vif_idx; + + ret = ra6w_ctrl_add_key_req(&priv->core->ctrl, key, tk, params->key_len, key_index, &rsp); + if (ret) + goto free; + + key->key_index = rsp.hw_key_index; + memcpy(key->key, tk, params->key_len); + key->key_len = params->key_len; + memcpy(key->seq, tk, params->seq_len); + key->seq_len = params->seq_len; + +free: + kfree(tk); + + return ret; +} + +static int ra6w_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, int link_id, + u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params *)) +{ + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_key *key = NULL; + struct key_params params; + + if (!vif->up) + return -EIO; + + if (key_index > RA6W_CFG80211_KEYS_MAX) { + ra6w_err("[%s] key index %d out of bounds\n", __func__, key_index); + return -ENOENT; + } + + key = &vif->keys[key_index]; + memset(¶ms, 0, sizeof(params)); + params.cipher = key->cipher; + params.key_len = key->key_len; + params.seq_len = key->seq_len; + params.seq = key->seq; + params.key = key->key; + + callback(cookie, ¶ms); + + return key->key_len ? 0 : -ENOENT; +} + +static int ra6w_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, int link_id, + u8 key_index, bool pairwise, const u8 *mac_addr) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_sta *sta = NULL; + struct ra6w_cfg80211_key *key = NULL; + + if (!vif->up) + return -EIO; + + if (key_index >= RA6W_CFG80211_KEYS_MAX) { + ra6w_err("[%s] key index %d out of bounds\n", __func__, key_index); + return -EINVAL; + } + + if (mac_addr) { + sta = ra6w_cfg80211_find_sta(priv, mac_addr); + if (!sta) + return -EINVAL; + + key = &sta->key; + } else { + key = &vif->keys[key_index]; + } + + return ra6w_ctrl_del_key_req(&priv->core->ctrl, key->key_index); +} + +static int ra6w_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *ndev, + int link_id, u8 key_index, bool unicast, bool multicast) +{ + int ret = 0; + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + + if (!vif->up) + return -EIO; + + return ret; +} + +static int ra6w_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cmd_sm_connect_rsp rsp = { 0 }; + int ret; + + if (!vif->up) + return -EIO; + + if ((sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40 || + sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104) && + (sme->key && sme->key_len > 0)) { + struct key_params key_params; + + key_params.key = sme->key; + key_params.seq = NULL; + key_params.key_len = sme->key_len; + key_params.seq_len = 0; + key_params.cipher = sme->crypto.cipher_group; + ra6w_cfg80211_add_key(wiphy, ndev, -1, sme->key_idx, false, NULL, &key_params); + } else if ((sme->auth_type == NL80211_AUTHTYPE_SAE) && + !(sme->flags & CONNECT_REQ_EXTERNAL_AUTH_SUPPORT)) { + netdev_err(ndev, "Doesn't support SAE without external authentication\n"); + return -EINVAL; + } + + ret = ra6w_ctrl_connect(&priv->core->ctrl, ndev, sme, &rsp); + if (ret == 0) + netif_carrier_on(ndev); + + return ret; +} + +static int ra6w_cfg80211_add_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, + struct station_parameters *params) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cmd_sta_add_rsp rsp = { 0 }; + struct ra6w_cfg80211_sta *sta = NULL; + + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) + return 0; + + ret = ra6w_ctrl_add_station_req(&priv->core->ctrl, params, mac, vif->vif_idx, &rsp); + if (ret) + return ret; + + sta = ra6w_cfg80211_sta_get(priv, rsp.sta_idx); + if (!sta) + return -EINVAL; + + sta->aid = params->aid; + sta->sta_idx = rsp.sta_idx; + sta->ch_idx = vif->ch_idx; + sta->vif_idx = vif->vif_idx; + sta->qos = (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME)) != 0; + sta->ht = params->link_sta_params.ht_capa ? 1 : 0; + sta->vht = params->link_sta_params.vht_capa ? 1 : 0; + sta->he = params->link_sta_params.he_capa ? 1 : 0; + sta->listen_interval = params->listen_interval; + ether_addr_copy(sta->mac_addr, mac); + list_add_tail(&sta->list, &vif->ap.sta_list); + vif->generation++; + sta->valid = true; + + return 0; +} + +static int ra6w_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_parameters *params) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_sta *sta = NULL; + bool authorized; + + if (is_zero_ether_addr(mac)) + return 0; + + if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) + return 0; + + sta = ra6w_cfg80211_find_sta(priv, mac); + if (!sta) + return -EINVAL; + + authorized = params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED); + + return ra6w_ctrl_port_control_req(&priv->core->ctrl, authorized, sta->sta_idx); +} + +static int ra6w_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_ap_settings *settings) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_sta *sta = NULL; + struct ra6w_cmd_ap_start_rsp rsp = { 0 }; + struct ra6w_cfg80211_chan_info *chan_info = NULL; + + ret = ra6w_ctrl_ap_start_req(&priv->core->ctrl, vif, settings, &rsp); + if (ret) { + ra6w_err("Failed to start AP (%d)\n", ret); + return ret; + } + + vif->ap.bcmc_index = rsp.bcmc_idx; + vif->ap.ap_isolate = 0; + sta = ra6w_cfg80211_sta_get(priv, rsp.bcmc_idx); + if (!sta) + return -EINVAL; + + sta->valid = true; + sta->aid = 0; + sta->sta_idx = rsp.bcmc_idx; + sta->ch_idx = rsp.ch_idx; + sta->vif_idx = vif->vif_idx; + sta->qos = false; + sta->listen_interval = 5; + sta->ht = 0; + sta->vht = 0; + sta->he = 0; + + ra6w_cfg80211_chaninfo_set(vif, rsp.ch_idx, &settings->chandef); + + netif_carrier_on(ndev); + + chan_info = &priv->chaninfo_table[vif->ch_idx]; + ra6w_info("AP started: freq1 %u bcmc_idx %d\n", + chan_info->chan_def.center_freq1, vif->ap.bcmc_index); + + return 0; +} + +static int ra6w_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev, + unsigned int link_id) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + + netif_carrier_off(ndev); + _ra6w_cfg80211_del_station(vif, NULL); + ret = ra6w_ctrl_ap_stop_req(&priv->core->ctrl, vif); + ra6w_cfg80211_chaninfo_unset(vif); + + return ret; +} + +static int ra6w_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_ap_update *info) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_beacon_info *bcn = NULL; + u8 *bcn_buf; + + bcn = &vif->ap.bcn; + + bcn_buf = ra6w_cfg80211_create_beacon(bcn, &info->beacon); + if (!bcn_buf) + return -ENOMEM; + + ret = ra6w_ctrl_change_beacon_req(&priv->core->ctrl, vif->vif_idx, + bcn_buf, bcn->len, bcn->head_len, bcn->tim_len, NULL); + + kfree(bcn_buf); + + return ret; +} + +static +int ra6w_cfg80211_set_monitor_channel(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_chan_def *chandef) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = NULL; + struct ra6w_cmd_mon_mode_rsp rsp = { 0 }; + const struct ra6w_cfg80211_chan_info *chan_info = NULL; + struct cfg80211_chan_def chandef_mon; + + if (priv->mon_vif_idx == RA6W_CFG80211_VIF_IDX_INVALID) + return -EINVAL; + + vif = priv->vif_table[priv->mon_vif_idx]; + + chan_info = ra6w_cfg80211_chaninfo_get(vif); + if (chan_info && chandef && cfg80211_chandef_identical(&chan_info->chan_def, chandef)) + return 0; + + ret = ra6w_ctrl_monitor_mode_req(&priv->core->ctrl, chandef, &rsp); + if (ret) + return -EIO; + + ra6w_cfg80211_chaninfo_unset(vif); + + if (rsp.chan_index == RA6W_CFG80211_CH_IDX_INVALID) + return 0; + + if (priv->vif_started > 1) { + ra6w_cfg80211_chaninfo_set(vif, rsp.chan_index, NULL); + return -EBUSY; + } + + memset(&chandef_mon, 0, sizeof(chandef_mon)); + chandef_mon.chan = ieee80211_get_channel(wiphy, le16_to_cpu(rsp.chan.freq_prim20)); + chandef_mon.center_freq1 = le16_to_cpu(rsp.chan.freq_cen1); + chandef_mon.center_freq2 = le16_to_cpu(rsp.chan.freq_cen2); + chandef_mon.width = chnl2bw[rsp.chan.ch_bw]; + ra6w_cfg80211_chaninfo_set(vif, rsp.chan_index, &chandef_mon); + + return 0; +} + +static int ra6w_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *ndev, + const u8 *peer, u64 *cookie) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_sta *sta = NULL; + struct ra6w_cmd_probe_client_rsp rsp = { 0 }; + + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_P2P_GO) + return -EINVAL; + + list_for_each_entry(sta, &vif->ap.sta_list, list) { + if (sta->valid && ether_addr_equal(sta->mac_addr, peer)) + break; + } + + if (!sta) + return -EINVAL; + + ret = ra6w_ctrl_probe_client_req(&priv->core->ctrl, vif->vif_idx, sta->sta_idx, &rsp); + if (ret) + return ret; + + *cookie = (u64)le32_to_cpu(rsp.probe_id); + + return 0; +} + +static int ra6w_cfg80211_set_txq_params(struct wiphy *wiphy, struct net_device *ndev, + struct ieee80211_txq_params *params) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + u32 param; + u8 ac; + u8 aifs; + u8 cwmin; + u8 cwmax; + + ac = ra6w_ac2hwq[params->ac]; + aifs = params->aifs; + cwmin = (u8)fls(params->cwmin); + cwmax = (u8)fls(params->cwmax); + + param = (u32)(aifs << 0); + param |= (u32)(cwmin << 4); + param |= (u32)(cwmax << 8); + param |= (u32)(params->txop << 12); + + return ra6w_ctrl_edca_req(&priv->core->ctrl, ac, param, false, vif->vif_idx); +} + +static int ra6w_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = NULL; + struct ra6w_cfg80211_vif *tmp = NULL; + s8 tx_pwr = 0; + + switch (type) { + case NL80211_TX_POWER_AUTOMATIC: + tx_pwr = 0x7F; + break; + case NL80211_TX_POWER_LIMITED: + case NL80211_TX_POWER_FIXED: + tx_pwr = (s8)MBM_TO_DBM(mbm); + break; + default: + ra6w_err("[%s] Unsupported type %d\n", __func__, type); + return -EINVAL; + } + + if (wdev) { + vif = container_of(wdev, struct ra6w_cfg80211_vif, wdev); + if (!vif->up) + return -EIO; + + goto req; + } + + list_for_each_entry(tmp, &priv->vifs, list) { + if (!tmp->up) + continue; + + vif = tmp; + break; + } + +req: + if (!vif) + return -EIO; + + return ra6w_ctrl_set_tx_power_req(&priv->core->ctrl, vif->vif_idx, tx_pwr); +} + +static int ra6w_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, + bool enabled, int timeout) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + u8 ps_mode; + + if (!vif->up) + return -EIO; + + if (!ra6w_params_ps_supported()) + return -EOPNOTSUPP; + + ps_mode = enabled ? RA6W_CFG80211_PS_MODE_ON_DYN : RA6W_CFG80211_PS_MODE_OFF; + + return ra6w_ctrl_set_power_mgmt_req(&priv->core->ctrl, ps_mode); +} + +static int ra6w_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_info *sinfo) +{ + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_sta *sta = NULL; + + if (!vif->up) + return -EIO; + + if (vif->type == NL80211_IFTYPE_MONITOR) + return -EINVAL; + + sta = ra6w_cfg80211_find_sta(vif->priv, mac); + if (!sta) + return -ENOENT; + + return ra6w_cfg80211_station_info_fill(sta, sinfo, vif); +} + +static int ra6w_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev, int idx, + u8 *mac, struct station_info *sinfo) +{ + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_sta *sta = NULL; + struct ra6w_cfg80211_sta *tmp = NULL; + int i = 0; + + if (!vif) + return -ENOENT; + + if (vif->type == NL80211_IFTYPE_MONITOR) + return -EINVAL; + + if ((vif->type == NL80211_IFTYPE_STATION || + vif->type == NL80211_IFTYPE_P2P_CLIENT) && + !idx && vif->sta.ap && vif->sta.ap->valid) { + sta = vif->sta.ap; + goto fill; + } + + list_for_each_entry(tmp, &vif->ap.sta_list, list) { + if (i == idx) { + sta = tmp; + break; + } + + i++; + } + +fill: + if (!sta) + return -ENOENT; + + ether_addr_copy(mac, (const u8 *)&sta->mac_addr); + + return ra6w_cfg80211_station_info_fill(sta, sinfo, vif); +} + +static int ra6w_cfg80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(wdev->netdev); + struct ra6w_cfg80211_remain_on_channel *roc = NULL; + + if (!priv || !vif) + return -EIO; + + if (priv->roc) + return -EBUSY; + + roc = kzalloc(sizeof(*roc), GFP_KERNEL); + if (!roc) + return -ENOMEM; + + roc->vif = vif; + roc->chan = chan; + roc->duration = duration; + roc->internal = false; + roc->on_chan = false; + roc->tx_cnt = 0; + memset(roc->tx_cookie, 0, sizeof(roc->tx_cookie)); + + priv->roc = roc; + ret = ra6w_ctrl_remain_on_channel_req(&priv->core->ctrl, vif, chan, duration); + if (ret) { + kfree(roc); + priv->roc = NULL; + + return ret; + } + + if (cookie) + *cookie = (u64)roc; + + return ret; +} + +static int ra6w_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + + if (!priv->roc) + return 0; + + if (cookie != (u64)priv->roc) + return -EINVAL; + + return ra6w_ctrl_cancel_remain_on_channel_req(&priv->core->ctrl); +} + +static int ra6w_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_csa_settings *params) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_beacon_info *bcn; + struct ra6w_cfg80211_beacon_info *bcn_after; + struct ra6w_cfg80211_csa_info *csa; + u16 csa_oft[RA6W_CMD_BCN_MAX_CSA_CPT]; + u8 *bcn_buf; + const u8 *bcn_after_buf; + int i; + + if (vif->ap.csa) + return -EBUSY; + + if (params->n_counter_offsets_beacon > RA6W_CMD_BCN_MAX_CSA_CPT) + return -EINVAL; + + bcn = &vif->ap.bcn; + bcn_buf = ra6w_cfg80211_create_beacon(bcn, ¶ms->beacon_csa); + if (!bcn_buf) + return -ENOMEM; + + memset(csa_oft, 0, sizeof(csa_oft)); + for (i = 0; i < params->n_counter_offsets_beacon; i++) + csa_oft[i] = params->counter_offsets_beacon[i] + bcn->head_len + bcn->tim_len; + + if (params->count == 0) { + params->count = 2; + for (i = 0; i < params->n_counter_offsets_beacon; i++) + bcn_buf[csa_oft[i]] = 2; + } + + csa = kzalloc(sizeof(*csa), GFP_KERNEL); + if (!csa) { + ret = -ENOMEM; + goto free_bcn_buf; + } + + bcn_after = &csa->bcn; + bcn_after_buf = ra6w_cfg80211_create_beacon(bcn_after, ¶ms->beacon_after); + if (!bcn_after_buf) { + ret = -ENOMEM; + goto free_csa; + } + + vif->ap.csa = csa; + csa->vif = vif; + csa->chandef = params->chandef; + memcpy(csa->buf, bcn_after_buf, bcn_after->len); + kfree(bcn_after_buf); + + /* Send new Beacon. FW will extract channel and count from the beacon */ + ret = ra6w_ctrl_change_beacon_req(&priv->core->ctrl, vif->vif_idx, bcn_buf, bcn->len, + bcn->head_len, bcn->tim_len, csa_oft); + if (ret) + goto free_csa; + + INIT_WORK(&csa->work, ra6w_cfg80211_csa_work); + cfg80211_ch_switch_started_notify(ndev, &csa->chandef, params->link_id, + params->count, params->block_tx); + + kfree(bcn_buf); + + return ret; + +free_csa: + ra6w_cfg80211_csa_remove(vif); + +free_bcn_buf: + kfree(bcn_buf); + + return ret; +} + +static int ra6w_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, int idx, + struct survey_info *info) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + const struct ra6w_cfg80211_survey_info *survey_info = NULL; + struct ieee80211_supported_band *sband; + + if (idx >= ARRAY_SIZE(priv->survey_table)) + return -ENONET; + + survey_info = &priv->survey_table[idx]; + + sband = wiphy->bands[NL80211_BAND_2GHZ]; + if (!sband) + return -ENOENT; + + if (idx >= sband->n_channels) { + idx -= sband->n_channels; + sband = NULL; + } + + if (!sband) { + sband = wiphy->bands[NL80211_BAND_5GHZ]; + + if (!sband || idx >= sband->n_channels) + return -ENOENT; + } + + info->channel = &sband->channels[idx]; + info->filled = survey_info->filled; + + if (info->filled) { + info->time = (u64)survey_info->chan_dwell_ms; + info->time_busy = (u64)survey_info->chan_busy_ms; + info->noise = survey_info->chan_noise_dbm; + } + + return 0; +} + +static int ra6w_cfg80211_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, + struct cfg80211_chan_def *chandef) +{ + struct ra6w_cfg80211_vif *vif = container_of(wdev, struct ra6w_cfg80211_vif, wdev); + const struct ra6w_cfg80211_chan_info *chan_info = NULL; + + if (!vif->up) + return -ENODATA; + + chan_info = ra6w_cfg80211_chaninfo_get(vif); + if (!chan_info) + return -ENODATA; + + *chandef = chan_info->chan_def; + + return 0; +} + +static int ra6w_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, struct wireless_dev *wdev, + u64 cookie) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + int n_tx_cookie = 0; + int i; + + if (!priv->roc || !priv->roc->tx_cnt) + return 0; + + for (i = 0; i < RA6W_CFG80211_ROC_TX; i++) { + n_tx_cookie++; + + if (priv->roc->tx_cookie[i] == cookie) { + priv->roc->tx_cookie[i] = 0; + priv->roc->tx_cnt--; + break; + } + } + + if (i == RA6W_CFG80211_ROC_TX) { + if (n_tx_cookie != priv->roc->tx_cnt) + priv->roc->tx_cnt--; + else + return 0; + } + + if (!priv->roc->internal || priv->roc->tx_cnt > 0) + return 0; + + return ra6w_cfg80211_cancel_remain_on_channel(wiphy, wdev, (u64)priv->roc); +} + +static int ra6w_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *ndev, + s32 rssi_thold, u32 rssi_hyst) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_ctrl *ctrl = &priv->core->ctrl; + const struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + + return ra6w_ctrl_cqm_rssi_config_req(ctrl, vif->vif_idx, rssi_thold, rssi_hyst); +} + +static int ra6w_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *ndev, + struct bss_parameters *params) +{ + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_ctrl *ctrl = &priv->core->ctrl; + struct ra6w_cmd_ap_isolate_rsp rsp; + + if (params->ap_isolate < 0) + return -EINVAL; + + vif->ap.ap_isolate = params->ap_isolate; + + return ra6w_ctrl_set_ap_isolate_req(ctrl, vif->ap.ap_isolate, &rsp); +} + +static void ra6w_cfg80211_ht_set(struct ieee80211_sta_ht_cap *ht_cap) +{ + int i; + int nss; + + ht_cap->ht_supported = ra6w_params_ht_supported(); + if (!ht_cap->ht_supported) + return; + + if (ra6w_params_stbc_enabled()) + ht_cap->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; + + if (ra6w_params_ldpc_enabled()) + ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING; + + nss = ra6w_params_nss(); + ht_cap->mcs.rx_highest = cpu_to_le16(65 * nss); + + if (nss > 1) + ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; + + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + + if (ra6w_params_rx_amsdu_size()) + ht_cap->cap |= IEEE80211_HT_CAP_MAX_AMSDU; + + ht_cap->mcs.rx_mask[0] = 0xff; + ht_cap->mcs.rx_highest = cpu_to_le16(65); + ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + + if (ra6w_params_use_sgi()) { + ht_cap->cap |= IEEE80211_HT_CAP_SGI_20; + ht_cap->mcs.rx_highest = cpu_to_le16(72 * nss); + } + + for (i = 0; i < nss; i++) + ht_cap->mcs.rx_mask[i] = 0xFF; +} + +static void ra6w_cfg80211_vht_set(struct ieee80211_sta_vht_cap *vht_cap) +{ + u8 nss; + u32 mcs_map; + u32 mcs_map_max_2ss_rx = IEEE80211_VHT_MCS_SUPPORT_0_9; + int mcs_map_max_2ss_tx = IEEE80211_VHT_MCS_SUPPORT_0_9; + u32 i; + + vht_cap->vht_supported = ra6w_params_vht_supported(); + if (!vht_cap->vht_supported) + return; + + vht_cap->cap = 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; + + if (ra6w_params_stbc_enabled()) + vht_cap->cap |= IEEE80211_VHT_CAP_RXSTBC_1; + + if (ra6w_params_ldpc_enabled()) + vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; + + if (ra6w_params_bfmee_enabled()) { + vht_cap->cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + vht_cap->cap |= 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; + } + + nss = ra6w_params_nss(); + if (nss > 1) + vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; + + vht_cap->cap |= ra6w_params_rx_amsdu_size(); + + if (ra6w_params_bfmer_enabled()) { + vht_cap->cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + vht_cap->cap |= (nss - 1) << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; + } + + if (ra6w_params_mu_mimo_rx_enabled()) + vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + + if (ra6w_params_mu_mimo_tx_enabled()) + vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; + + mcs_map = ra6w_params_mcs_map_range(); + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(0); + + for (i = 0; i < nss; i++) { + vht_cap->vht_mcs.rx_mcs_map |= cpu_to_le16(mcs_map << (i * 2)); + vht_cap->vht_mcs.rx_highest = cpu_to_le16(ra6w_mcs_map_to_rate[mcs_map] * nss); + mcs_map = min_t(int, mcs_map, mcs_map_max_2ss_rx); + } + + for (; i < 8; i++) + vht_cap->vht_mcs.rx_mcs_map |= + cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); + + mcs_map = ra6w_params_mcs_map_range(); + vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(0); + + for (i = 0; i < nss; i++) { + vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(mcs_map << (i * 2)); + vht_cap->vht_mcs.tx_highest = cpu_to_le16(ra6w_mcs_map_to_rate[mcs_map] * nss); + mcs_map = min_t(int, mcs_map, mcs_map_max_2ss_tx); + } + + for (; i < 8; i++) + vht_cap->vht_mcs.tx_mcs_map |= + cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); + + vht_cap->cap &= ~IEEE80211_VHT_CAP_SHORT_GI_80; +} + +static void ra6w_cfg80211_threshold_set(struct ieee80211_sta_he_cap *he_cap) +{ + const u8 PPE_THRES_INFO_OFT = 7; + const u8 PPE_THRES_INFO_BIT_LEN = 6; + struct ppe_thres_info_tag { + u8 ppet16 : 3; + u8 ppet8 : 3; + } __packed; + + struct ppe_thres_field_tag { + u8 nsts : 3; + u8 ru_idx_bmp : 4; + }; + + struct ppe_thres_field_tag *ppe_thres_field; + struct ppe_thres_info_tag ppe_thres_info = { + .ppet16 = 0, // BPSK + .ppet8 = 7 // None + }; + + const u8 *ppe_thres_info_ptr = (u8 *)&ppe_thres_info; + u16 *ppe_thres_ptr = (u16 *)he_cap->ppe_thres; + u8 i; + u8 offset; + u8 nss; + + ppe_thres_field = (struct ppe_thres_field_tag *)he_cap->ppe_thres; + + ppe_thres_field->ru_idx_bmp = 1; + + nss = ra6w_params_nss(); + ppe_thres_field->nsts = nss - 1; + for (i = 0; i < nss; i++) { + offset = i * PPE_THRES_INFO_BIT_LEN + PPE_THRES_INFO_OFT; + ppe_thres_ptr = (u16 *)&he_cap->ppe_thres[offset / 8]; + *ppe_thres_ptr |= *ppe_thres_info_ptr << (offset % 8); + } +} + +static void ra6w_cfg80211_he_set(struct ra6w_cfg80211_priv *priv, + struct ieee80211_sband_iftype_data *ifdata) +{ + int i; + u8 nss; + struct ieee80211_sta_he_cap *he_cap = &ifdata->he_cap; + int mcs_map; + int mcs_map_max_2ss = IEEE80211_HE_MCS_SUPPORT_0_11; + u8 dcm_max_ru = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242; + u32 phy_vers = le32_to_cpu(priv->core->sinfo.fw_ver.phy_version); + __le16 unsup_for_ss = 0; + + he_cap->has_he = ra6w_params_he_supported(); + if (!he_cap->has_he) + return; + + if (ra6w_params_twt_enabled()) { + priv->ext_capa[9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT; + he_cap->he_cap_elem.mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ; + } + + he_cap->he_cap_elem.mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_ALL_ACK; + + ra6w_cfg80211_threshold_set(he_cap); + + if (ra6w_params_ldpc_enabled()) + he_cap->he_cap_elem.phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; + + he_cap->he_cap_elem.phy_cap_info[1] |= + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US | + IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; + he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS | + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | + IEEE80211_HE_PHY_CAP2_DOPPLER_RX; + + if (ra6w_params_stbc_enabled()) + he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; + + he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM | + IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU; + + nss = ra6w_params_nss(); + if (nss > 0) + he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2; + else + he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1; + + if (ra6w_params_bfmee_enabled()) { + he_cap->he_cap_elem.phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE; + he_cap->he_cap_elem.phy_cap_info[4] |= + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; + } + + he_cap->he_cap_elem.phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; + he_cap->he_cap_elem.phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT | + IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO; + he_cap->he_cap_elem.phy_cap_info[7] |= + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; + he_cap->he_cap_elem.phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | + dcm_max_ru; + he_cap->he_cap_elem.phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US; + + /* Starting from version v31 more HE_ER_SU modulations is supported */ + if (RA6W_PHY_VERSION(phy_vers) > 30) { + he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE; + he_cap->he_cap_elem.phy_cap_info[8] |= + IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI; + } + + mcs_map = ra6w_params_he_mcs_map_range(); + memset(&he_cap->he_mcs_nss_supp, 0, sizeof(he_cap->he_mcs_nss_supp)); + for (i = 0; i < nss; i++) { + unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); + he_cap->he_mcs_nss_supp.rx_mcs_80 |= cpu_to_le16(mcs_map << (i * 2)); + he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss; + he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss; + mcs_map = min_t(int, ra6w_params_he_mcs_map_range(), mcs_map_max_2ss); + } + + for (; i < 8; i++) { + unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); + he_cap->he_mcs_nss_supp.rx_mcs_80 |= unsup_for_ss; + he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss; + he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss; + } + + mcs_map = ra6w_params_he_mcs_map_range(); + for (i = 0; i < nss; i++) { + unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); + he_cap->he_mcs_nss_supp.tx_mcs_80 |= cpu_to_le16(mcs_map << (i * 2)); + he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss; + he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss; + mcs_map = min_t(int, ra6w_params_he_mcs_map_range(), mcs_map_max_2ss); + } + + for (; i < 8; i++) { + unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); + he_cap->he_mcs_nss_supp.tx_mcs_80 |= unsup_for_ss; + he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss; + he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss; + } +} + +static int ra6w_cfg80211_set_default_wiphy(struct ra6w_cfg80211_priv *priv, struct wiphy *wiphy) +{ + const u8 *mac_addr = priv->core->sinfo.default_mac; + int i; + + ether_addr_copy(wiphy->perm_addr, mac_addr); + for (i = 0; i < RA6W_CFG80211_VIF_MAX; i++) { + ether_addr_copy(priv->addresses[i].addr, mac_addr); + priv->addresses[i].addr[5] ^= i; + } + + wiphy->addresses = priv->addresses; + wiphy->n_addresses = RA6W_CFG80211_VIF_MAX; + + bitmap_zero(priv->addr_map, RA6W_CFG80211_VIF_MAX); + + wiphy->mgmt_stypes = ra6w_macm_stypes; + + ra6w_cfg80211_ht_set(&ra6w_band_2g.ht_cap); + if (ra6w_params_he_supported()) { + ra6w_cfg80211_he_set(priv, &ra6w_cap_he_2g); + ra6w_band_2g.iftype_data = &ra6w_cap_he_2g; + } + + wiphy->bands[NL80211_BAND_2GHZ] = &ra6w_band_2g; + + ra6w_cfg80211_ht_set(&ra6w_band_5g.ht_cap); + ra6w_cfg80211_vht_set(&ra6w_band_5g.vht_cap); + if (ra6w_params_he_supported()) { + ra6w_cfg80211_he_set(priv, &ra6w_cap_he_5g); + ra6w_band_5g.iftype_data = &ra6w_cap_he_5g; + } + + wiphy->bands[NL80211_BAND_5GHZ] = &ra6w_band_5g; + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_MONITOR); + wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_HAS_CHANNEL_SWITCH | + WIPHY_FLAG_4ADDR_STATION | + WIPHY_FLAG_4ADDR_AP | + WIPHY_FLAG_REPORTS_OBSS | + WIPHY_FLAG_OFFCHAN_TX; + + wiphy->max_scan_ssids = RA6W_CMD_SCAN_SSID_MAX; + wiphy->max_scan_ie_len = RA6W_CMD_SCAN_MAX_IE_LEN; + + wiphy->support_mbssid = 1; + + wiphy->max_num_csa_counters = RA6W_CMD_BCN_MAX_CSA_CPT; + wiphy->max_remain_on_channel_duration = 5000; + + wiphy->features |= NL80211_FEATURE_NEED_OBSS_SCAN | + NL80211_FEATURE_SK_TX_STATUS | + NL80211_FEATURE_VIF_TXPOWER | + NL80211_FEATURE_ACTIVE_MONITOR | + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + NL80211_FEATURE_SAE; + + wiphy->iface_combinations = ra6w_if_comb; + wiphy->n_iface_combinations = ARRAY_SIZE(ra6w_if_comb) - 1; + + if (ra6w_params_regd_mode_is_auto()) + wiphy->reg_notifier = ra6w_cfg80211_reg_notifier; + else + wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; + + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + wiphy->extended_capabilities = priv->ext_capa; + wiphy->extended_capabilities_mask = priv->ext_capa; + wiphy->extended_capabilities_len = ARRAY_SIZE(priv->ext_capa); + + wiphy->cipher_suites = ra6w_cipher_suites; + wiphy->n_cipher_suites = + ARRAY_SIZE(ra6w_cipher_suites) - RA6W_CFG80211_RESERVED_CIPHER_NUM; + + if (ra6w_params_wapi_supported()) + ra6w_cipher_suites[wiphy->n_cipher_suites++] = WLAN_CIPHER_SUITE_SMS4; + + if (ra6w_params_mfp_supported()) + ra6w_cipher_suites[wiphy->n_cipher_suites++] = WLAN_CIPHER_SUITE_AES_CMAC; + + if (ra6w_params_ccmp256_supported()) + ra6w_cipher_suites[wiphy->n_cipher_suites++] = WLAN_CIPHER_SUITE_CCMP_256; + + if (ra6w_params_gcmp_supported()) { + ra6w_cipher_suites[wiphy->n_cipher_suites++] = WLAN_CIPHER_SUITE_GCMP; + ra6w_cipher_suites[wiphy->n_cipher_suites++] = WLAN_CIPHER_SUITE_GCMP_256; + } + + if (ra6w_params_tdls_supported()) { + wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; + wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; + wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; + } + + if (ra6w_params_ap_uapsd_enabled()) + wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + + if (ra6w_params_ps_supported()) + wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; + + strscpy(wiphy->fw_version, priv->core->sinfo.fw_version, sizeof(wiphy->fw_version)); + + return 0; +} + +static void ra6w_cfg80211_vif_del_all(struct ra6w_cfg80211_priv *priv) +{ + struct ra6w_cfg80211_vif *vif = NULL; + struct ra6w_cfg80211_vif *tmp_vif = NULL; + + rtnl_lock(); + + list_for_each_entry_safe(vif, tmp_vif, &priv->vifs, list) { + ra6w_cfg80211_vif_cleanup(vif); + ra6w_cfg80211_vif_unassign(priv, vif->vif_idx, vif->addr_idx); + } + + rtnl_unlock(); +} + +void ra6w_cfg80211_chaninfo_set(struct ra6w_cfg80211_vif *vif, u8 ch_idx, + const struct cfg80211_chan_def *chandef) +{ + struct ra6w_cfg80211_chan_info *chan_info = NULL; + struct ra6w_cfg80211_priv *priv = vif->priv; + + if (ch_idx >= RA6W_CFG80211_CHANINFO_MAX) { + ra6w_err("Invalid channel idx %d\n", ch_idx); + return; + } + + vif->ch_idx = ch_idx; + chan_info = &priv->chaninfo_table[ch_idx]; + + /* For now chandef is NULL for STATION interface */ + if (chandef && !chan_info->chan_def.chan) { + chan_info->chan_def = *chandef; + chan_info->count++; + } +} + +void ra6w_cfg80211_chaninfo_unset(struct ra6w_cfg80211_vif *vif) +{ + struct ra6w_cfg80211_chan_info *chan_info = NULL; + struct ra6w_cfg80211_priv *priv = vif->priv; + + if (vif->ch_idx == RA6W_CFG80211_CH_IDX_INVALID) + return; + + chan_info = &priv->chaninfo_table[vif->ch_idx]; + + if (chan_info->count == 0) + ra6w_dbg("Chan info ref count is already 0\n"); + else + chan_info->count--; + + if (chan_info->count == 0) + chan_info->chan_def.chan = NULL; + + vif->ch_idx = RA6W_CFG80211_CH_IDX_INVALID; +} + +static +struct ra6w_cfg80211_sta *ra6w_cfg80211_get_sta_from_fc(struct ra6w_cfg80211_priv *priv, + struct ra6w_cfg80211_vif *vif, + const u8 *addr, __le16 fc, bool ap) +{ + bool bufferable; + struct ra6w_cfg80211_sta *sta = NULL; + + if (!ap) { + if (vif->sta.ap && vif->sta.ap->valid && + ether_addr_equal(vif->sta.ap->mac_addr, addr)) + return vif->sta.ap; + + return NULL; + } + + bufferable = ieee80211_is_deauth(fc) || + ieee80211_is_disassoc(fc) || + ieee80211_is_action(fc); + + if (!bufferable) + return NULL; + + if (is_broadcast_ether_addr(addr) || is_multicast_ether_addr(addr)) { + sta = ra6w_cfg80211_sta_get(priv, vif->ap.bcmc_index); + if (!sta || !sta->valid) + return NULL; + + return sta; + } + + list_for_each_entry(sta, &vif->ap.sta_list, list) { + if (sta->valid && ether_addr_equal(sta->mac_addr, addr)) + return sta; + } + + return NULL; +} + +static int ra6w_cfg80211_offchan_proc(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ra6w_cfg80211_priv *priv, + const struct ra6w_cfg80211_vif *vif, + struct cfg80211_mgmt_tx_params *params) +{ + struct ieee80211_channel *chan = params->chan; + int ret; + unsigned int duration = 30; + + if (!chan) + return -EINVAL; + + /* Offchannel transmission, need to start a RoC */ + if (priv->roc) { + /* Test if current RoC can be re-used */ + if (priv->roc->vif != vif || priv->roc->chan->center_freq != chan->center_freq) + return -EINVAL; + + return 0; + } + + /* Start a new ROC procedure */ + if (params->wait) + duration = params->wait; + + ret = ra6w_cfg80211_remain_on_channel(wiphy, wdev, chan, duration, NULL); + if (ret) + return ret; + + /* Internal RoC, no need to inform user space about it */ + priv->roc->internal = true; + + return 0; +} + +static int ra6w_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +{ + int ret = 0; + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_cfg80211_vif *vif = container_of(wdev, struct ra6w_cfg80211_vif, wdev); + struct ra6w_cfg80211_sta *sta = NULL; + struct ra6w_tx *tx = &priv->core->tx; + const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *)params->buf; + bool ap = false; + bool offchan = false; + const u8 *da; + __le16 fc; + + switch (vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + ap = true; + + if (!(ieee80211_is_assoc_resp(mgmt->frame_control) || + ieee80211_is_auth(mgmt->frame_control))) + break; + + cfg80211_mgmt_tx_status(wdev, *cookie, params->buf, params->len, true, GFP_ATOMIC); + + break; + default: + break; + } + + da = mgmt->da; + fc = mgmt->frame_control; + sta = ra6w_cfg80211_get_sta_from_fc(priv, vif, da, fc, ap); + + if (params->offchan) { + const struct ra6w_cfg80211_chan_info *chan_info = ra6w_cfg80211_chaninfo_get(vif); + + if (!chan_info) + return -EINVAL; + + offchan = chan_info->chan_def.chan->center_freq == params->chan->center_freq; + + ret = ra6w_cfg80211_offchan_proc(wiphy, wdev, priv, vif, params); + if (ret) + return ret; + } + + ret = ra6w_tx_mgmt(tx, vif, sta, params, cookie); + if (offchan) { + if (priv->roc->tx_cnt < RA6W_CFG80211_ROC_TX) + priv->roc->tx_cookie[priv->roc->tx_cnt] = *cookie; + else + ra6w_warn("[%s] %d frames sent within the same Roc (> RA6W_NET_ROC_TX)", + __func__, priv->roc->tx_cnt + 1); + priv->roc->tx_cnt++; + } + + return ret; +} + +static int ra6w_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_external_auth_params *params) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct ra6w_ctrl *ctrl = &priv->core->ctrl; + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + + if (!(vif->sta.flags & RA6W_CMD_STA_AUTH_EXT_BIT)) + return -EINVAL; + + vif->sta.flags &= ~RA6W_CMD_STA_AUTH_EXT_BIT; + + return ra6w_ctrl_sm_ext_auth_req_rsp(ctrl, vif->vif_idx, params->status); +} + +static struct cfg80211_ops ra6w_cfg80211_ops = { + .add_virtual_intf = ra6w_cfg80211_add_iface, + .del_virtual_intf = ra6w_cfg80211_del_iface, + .change_virtual_intf = ra6w_cfg80211_change_iface, + .scan = ra6w_cfg80211_scan, + .abort_scan = ra6w_cfg80211_scan_abort, + .connect = ra6w_cfg80211_connect, + .disconnect = ra6w_cfg80211_disconnect, + .add_key = ra6w_cfg80211_add_key, + .get_key = ra6w_cfg80211_get_key, + .del_key = ra6w_cfg80211_del_key, + .set_default_key = ra6w_cfg80211_set_default_key, + .add_station = ra6w_cfg80211_add_station, + .del_station = ra6w_cfg80211_del_station, + .change_station = ra6w_cfg80211_change_station, + .mgmt_tx = ra6w_cfg80211_mgmt_tx, + .mgmt_tx_cancel_wait = ra6w_cfg80211_mgmt_tx_cancel_wait, + .start_ap = ra6w_cfg80211_start_ap, + .change_beacon = ra6w_cfg80211_change_beacon, + .stop_ap = ra6w_cfg80211_stop_ap, + .set_monitor_channel = ra6w_cfg80211_set_monitor_channel, + .probe_client = ra6w_cfg80211_probe_client, + .set_txq_params = ra6w_cfg80211_set_txq_params, + .set_tx_power = ra6w_cfg80211_set_tx_power, + .set_power_mgmt = ra6w_cfg80211_set_power_mgmt, + .get_station = ra6w_cfg80211_get_station, + .dump_station = ra6w_cfg80211_dump_station, + .remain_on_channel = ra6w_cfg80211_remain_on_channel, + .cancel_remain_on_channel = ra6w_cfg80211_cancel_remain_on_channel, + .channel_switch = ra6w_cfg80211_channel_switch, + .dump_survey = ra6w_cfg80211_dump_survey, + .get_channel = ra6w_cfg80211_get_channel, + .set_cqm_rssi_config = ra6w_cfg80211_set_cqm_rssi_config, + .change_bss = ra6w_cfg80211_change_bss, + CFG80211_TESTMODE_CMD(ra6w_testmode_cmd) + .external_auth = ra6w_cfg80211_external_auth, +}; + +static int ra6w_cfg80211_register(struct ra6w_core *core, struct device *dev) +{ + int ret; + struct wiphy *wiphy = NULL; + struct ra6w_cfg80211_priv *priv = NULL; + + wiphy = wiphy_new(&ra6w_cfg80211_ops, sizeof(*priv)); + if (!wiphy) { + ra6w_err("Failed to create new wiphy\n"); + return -ENOENT; + } + + priv = wiphy_priv(wiphy); + priv->core = core; + + set_wiphy_dev(wiphy, dev); + priv->wiphy = wiphy; + core->priv = priv; + + priv->vif_started = 0; + priv->mon_vif_idx = RA6W_CFG80211_VIF_IDX_INVALID; + + bitmap_zero(priv->vif_map, RA6W_CFG80211_VIF_MAX); + + INIT_LIST_HEAD(&priv->vifs); + + priv->roc = NULL; + + priv->ext_capa[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING; + priv->ext_capa[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT; + priv->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF | + WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB; + priv->ext_capa[8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB; + + ret = ra6w_cfg80211_set_default_wiphy(priv, wiphy); + if (ret) + goto free_wiphy; + + ret = ra6w_ctrl_me_config(&priv->core->ctrl, wiphy); + if (ret) + goto free_wiphy; + + ret = wiphy_register(wiphy); + if (ret) { + ra6w_err("register wiphy device failed: %d\n", ret); + goto free_wiphy; + } + + ret = ra6w_params_regd_set_self(wiphy); + if (ret) + goto free_wiphy; + + ra6w_dbgfs_register(priv); + + ret = ra6w_ctrl_dev_start(&priv->core->ctrl, &priv->phy_config); + if (ret) + goto free_wiphy; + + return 0; + +free_wiphy: + wiphy_free(wiphy); + priv->wiphy = NULL; + core->priv = NULL; + + return ret; +} + +void ra6w_cfg80211_deinit(struct ra6w_core *core) +{ + struct ra6w_cfg80211_priv *priv = NULL; + struct wiphy *wiphy = NULL; + + if (!core) + return; + + priv = core->priv; + if (!priv) + return; + + ra6w_cfg80211_vif_del_all(priv); + + ra6w_dbgfs_deregister(priv); + + wiphy = priv->wiphy; + if (wiphy) { + wiphy_unregister(wiphy); + wiphy_free(wiphy); + } + + priv->wiphy = NULL; + core->priv = NULL; +} + +int ra6w_cfg80211_init(struct ra6w_core *core, struct device *dev) +{ + int ret; + struct wireless_dev *wdev = NULL; + + ret = ra6w_cfg80211_register(core, dev); + if (ret) + return ret; + + rtnl_lock(); + wdev = ra6w_cfg80211_add_iface(core->priv->wiphy, "wlan%d", NET_NAME_UNKNOWN, + NL80211_IFTYPE_STATION, NULL); + rtnl_unlock(); + if (!wdev) { + ra6w_info("Failed to instantiate a network device\n"); + ret = -ENOENT; + goto cfg80211_deinit; + } + + ra6w_info("New interface created %s\n", wdev->netdev->name); + + return 0; + +cfg80211_deinit: + ra6w_cfg80211_deinit(core); + + return ret; +} From patchwork Thu Apr 17 13:52:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882859 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E7D5524EA93 for ; Thu, 17 Apr 2025 13:53:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897991; cv=none; b=ZvOuexwUcLJAPT7zHEvuES3qPUaK2sCjuLoKJAOnDB2oULDAFCwT1Hn8e3yCVb+ox5SpLe/SX1rdNjRsoAXCWSrhszZsKprtfu1h4yH6V8n2wObBix4zmz9q6yz0suodcHh73bI6uupmf+5iGy2auhAg1EO+f0XYK+wR5AkznLQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897991; c=relaxed/simple; bh=RDYnV9R8FAUgui7wb1hoCO+RugyzO4Yxr3e6VmCpFzg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=ddMIcQnV3b8YNZf4F4yBW7qmmv0qbLOH7Xr1gYNiWz5srxkgMC4BP8pIDuA5RlQw6xhKWpoZ3DDTQlDtw8C9jv6dgxkZIWHXIiFkC/KV8HaxYIvxBojJXSkNgjGKZN+88dtmcDVBZu/CRCS32wPtud7p4fSUn8309b46hrDNyEs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: BiFWn/CNSEmuGTmSHhofGw== X-CSE-MsgGUID: I6xKYjApT/iKAsN5OeS6wg== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:07 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 752624005025; Thu, 17 Apr 2025 22:53:04 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 05/38] ra6w: add cfg80211.h Date: Thu, 17 Apr 2025 16:52:03 +0300 Message-Id: <20250417135236.52410-6-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/cfg80211.h | 266 +++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/cfg80211.h diff --git a/drivers/net/wireless/renesas/ra6w/cfg80211.h b/drivers/net/wireless/renesas/ra6w/cfg80211.h new file mode 100644 index 000000000000..e4eda5898a6a --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/cfg80211.h @@ -0,0 +1,266 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_CFG80211_H +#define RA6W_CFG80211_H + +#include + +#include "core.h" +#include "stats.h" + +#define RA6W_CFG80211_CH_MAX_POWER 30 +#define RA6W_CFG80211_EXT_CAPA_MAX 10 +#define RA6W_CFG80211_CHANINFO_MAX 3 +#define RA6W_CFG80211_ROC_TX 5 +#define RA6W_CFG80211_STA_MAX 4 +#define RA6W_CFG80211_VIF_MAX 2 +#define RA6W_CFG80211_STA_TABLE_MAX (RA6W_CFG80211_STA_MAX + RA6W_CFG80211_VIF_MAX) +#define RA6W_CFG80211_NDEV_TXQ 1 +#define RA6W_CFG80211_NDEV_RXQ 1 +#define RA6W_CFG80211_LPCA_PPM 20 +#define RA6W_CFG80211_UAPSD_TIMEOUT 300 +#define RA6W_CFG80211_KEYS_MAX 6 +#define RA6W_CFG80211_WPI_SUBKEY_LEN 16 +#define RA6W_CFG80211_WPI_KEY_LEN 32 +#define RA6W_CFG80211_KEY_LEN_MAX 32 +#define RA6W_CFG80211_KEY_SEQ_LEN_MAX 8 +#define RA6W_CFG80211_CH_IDX_INVALID 0xFF +#define RA6W_CFG80211_VIF_IDX_INVALID 0xFF +#define RA6W_CFG80211_STA_IDX_INVALID 0xFF +#define RA6W_CFG80211_TID_INVALID 0x1F +#define RA6W_CFG80211_RESERVED_CIPHER_NUM 5 + +enum ra6w_cfg80211_formatmod { + RA6W_CFG80211_FORMATMOD_NON_HT, + RA6W_CFG80211_FORMATMOD_NON_HT_DUP_OFDM, + RA6W_CFG80211_FORMATMOD_HT_MF, + RA6W_CFG80211_FORMATMOD_HT_GF, + RA6W_CFG80211_FORMATMOD_VHT, + RA6W_CFG80211_FORMATMOD_HE_SU, + RA6W_CFG80211_FORMATMOD_HE_MU, + RA6W_CFG80211_FORMATMOD_HE_ER, + RA6W_CFG80211_FORMATMOD_HE_TB, + + RA6W_CFG80211_FORMATMOD_MAX +}; + +struct ra6w_cfg80211_legrate { + s16 idx; + u16 rate; // in 100Kbps +}; + +enum ra6w_cfg80211_vif_type { + RA6W_VIF_TYPE_STA, + RA6W_VIF_TYPE_IBSS, + RA6W_VIF_TYPE_AP, + RA6W_VIF_TYPE_MESH_POINT, + RA6W_VIF_TYPE_MONITOR, + + RA6W_VIF_TYPE_MAX +}; + +enum ra6w_cfg80211_machw_support_type { + RA6W_MACHW_SUPPORT_DEFAULT = 10, + RA6W_MACHW_SUPPORT_HE = 20, + RA6W_MACHW_SUPPORT_AP_HE = 30, +}; + +enum ra6w_cfg80211_chipher_type { + RA6W_CIPHER_WEP40 = 0, + RA6W_CIPHER_TKIP = 1, + RA6W_CIPHER_CCMP = 2, + RA6W_CIPHER_WEP104 = 3, + RA6W_CIPHER_SMS4 = 4, + RA6W_CIPHER_AES_CMAC_128 = 5, + RA6W_CIPHER_GCMP_128 = 6, + RA6W_CIPHER_GCMP_256 = 7, + RA6W_CIPHER_CCMP_256 = 8, + RA6W_CIPHER_BIP_GMAC_128 = 9, + RA6W_CIPHER_BIP_GMAC_256 = 10, + RA6W_CIPHER_BIP_CMAC_256 = 11, + RA6W_CIPHER_INVALID = 0xFF, +}; + +enum ra6w_cfg80211_ps_mode { + RA6W_CFG80211_PS_MODE_OFF = 0, + RA6W_CFG80211_PS_MODE_ON = 1, + RA6W_CFG80211_PS_MODE_ON_DYN = 2 +}; + +struct ra6w_cfg80211_twt_conf_tag { + u8 flow_type; /* (0: Announced, 1: Unannounced) */ + u8 wake_int_exp; + bool wake_dur_unit; /* Unit of measurement (0:256us, 1:tu) */ + u8 min_twt_wake_dur; + u16 wake_int_mantissa; +}; + +struct ra6w_cfg80211_twt_setup_ind { + u8 resp_type; + u8 sta_idx; + struct ra6w_cfg80211_twt_conf_tag conf; +}; + +struct ra6w_cfg80211_beacon_info { + u8 *head; + u8 *tail; + u8 *ies; + u16 head_len; + u16 tail_len; + u16 ies_len; + u16 tim_len; + u16 len; + u8 dtim_period; +}; + +struct ra6w_cfg80211_csa_info { + struct ra6w_cfg80211_vif *vif; + struct ra6w_cfg80211_beacon_info bcn; + u8 buf[512]; + struct cfg80211_chan_def chandef; + int count; + u8 status; + u8 ch_idx; + struct work_struct work; +}; + +struct ra6w_cfg80211_remain_on_channel { + struct ra6w_cfg80211_vif *vif; + struct ieee80211_channel *chan; + unsigned int duration; + bool internal; + bool on_chan; + s32 tx_cnt; + u64 tx_cookie[RA6W_CFG80211_ROC_TX]; +}; + +struct ra6w_cfg80211_key { + u8 key_index; + u8 key[RA6W_CFG80211_KEY_LEN_MAX]; + u8 key_len; + u8 seq[RA6W_CFG80211_KEY_SEQ_LEN_MAX]; + u8 seq_len; + u32 cipher; + u8 cipher_type; + u8 sta_idx; + u8 vif_idx; + bool pairwise; +}; + +struct ra6w_cfg80211_sta_stats { + unsigned long last_acttive_time; + struct ra6w_rx_ext_hdr last_rx_data_ext; + struct ra6w_rx_ext_hdr last_stats; + u32 rx_packets; + u32 tx_packets; + u32 tx_failed; + u64 rx_bytes; + u64 tx_bytes; +}; + +struct ra6w_cfg80211_chan_info { + struct cfg80211_chan_def chan_def; + u8 count; +}; + +struct ra6w_cfg80211_survey_info { + u32 filled; + u32 chan_dwell_ms; + u32 chan_busy_ms; + s8 chan_noise_dbm; +}; + +struct ra6w_cfg80211_sta { + struct list_head list; + bool valid; + u8 mac_addr[ETH_ALEN]; + u16 aid; + u8 sta_idx; + u8 vif_idx; + enum nl80211_band band; + enum nl80211_chan_width width; + u16 center_freq; + u32 center_freq1; + u32 center_freq2; + u8 ch_idx; + bool qos; + struct ra6w_cfg80211_key key; + bool ht; + bool vht; + bool he; + struct ra6w_cfg80211_sta_stats stats; + int listen_interval; + struct ra6w_cfg80211_twt_setup_ind twt_ind; +}; + +struct ra6w_cfg80211_vif { + struct list_head list; + u8 vif_idx; + u8 addr_idx; + enum nl80211_iftype type; + struct wireless_dev wdev; + struct net_device *ndev; + void *priv; + bool roc_tdls; + u8 tdls_status; + bool tdls_chsw_prohibited; + struct ra6w_cfg80211_key keys[RA6W_CFG80211_KEYS_MAX]; + u8 ch_idx; + bool up; + bool use_4addr; + s32 generation; + struct ra6w_stats stats; + union { + struct { + u32 flags; + struct ra6w_cfg80211_sta *ap; + struct ra6w_cfg80211_sta *tdls_sta; + } sta; + struct { + u8 ap_isolate; + struct list_head sta_list; + struct ra6w_cfg80211_beacon_info bcn; + u8 bcmc_index; + struct ra6w_cfg80211_csa_info *csa; + } ap; + }; +}; + +struct ra6w_cfg80211_priv { + struct ra6w_core *core; + struct wiphy *wiphy; + struct dentry *root; + u8 ext_capa[RA6W_CFG80211_EXT_CAPA_MAX]; + struct list_head vifs; + struct ra6w_cmd_phy_cfg phy_config; + struct ra6w_cfg80211_sta sta_table[RA6W_CFG80211_STA_TABLE_MAX]; + struct ra6w_cfg80211_vif *vif_table[RA6W_CFG80211_VIF_MAX]; + DECLARE_BITMAP(vif_map, RA6W_CFG80211_VIF_MAX); + struct mac_address addresses[RA6W_CFG80211_VIF_MAX]; + DECLARE_BITMAP(addr_map, RA6W_CFG80211_VIF_MAX); + s32 vif_started; + s8 mon_vif_idx; + struct ra6w_cfg80211_chan_info chaninfo_table[RA6W_CFG80211_CHANINFO_MAX]; + u8 chaninfo_index; + struct ra6w_cfg80211_remain_on_channel *roc; + struct cfg80211_scan_request *scan_request; + struct ra6w_cfg80211_survey_info survey_table[RA6W_CMD_SCAN_CHANNEL_MAX]; +}; + +int ra6w_cfg80211_init(struct ra6w_core *core, struct device *dev); +void ra6w_cfg80211_deinit(struct ra6w_core *core); +void ra6w_cfg80211_chaninfo_set(struct ra6w_cfg80211_vif *vif, u8 ch_idx, + const struct cfg80211_chan_def *chandef); +struct ra6w_cfg80211_chan_info *ra6w_cfg80211_chaninfo_get(struct ra6w_cfg80211_vif *vif); +void ra6w_cfg80211_chaninfo_unset(struct ra6w_cfg80211_vif *vif); +u8 *ra6w_cfg80211_create_beacon(struct ra6w_cfg80211_beacon_info *bcn, + struct cfg80211_beacon_data *new); +struct ra6w_cfg80211_sta *ra6w_cfg80211_sta_get(struct ra6w_cfg80211_priv *priv, u8 sta_idx); +void ra6w_cfg80211_sta_free(struct ra6w_cfg80211_vif *vif, u8 sta_idx); +struct ra6w_cfg80211_vif *ra6w_cfg80211_vif_get(struct ra6w_cfg80211_priv *priv, u8 vif_idx); +void ra6w_cfg80211_scan_done(struct ra6w_cfg80211_priv *priv); + +#endif /* RA6W_CFG80211_H */ From patchwork Thu Apr 17 13:52:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882273 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A7B2A24EA93 for ; Thu, 17 Apr 2025 13:53:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897996; cv=none; b=JJsCyh1kZUDxTjQlSiL7CndoPpWA61QxWU/n0ZzQQtuUtUcXlPccFU/XkzKnnjEMeMoDIkvwsb9cwrK/uiOibITNZX2twFXfHHWONWd/sCZgk4EQkDyC500rpYZTqnDSGkLi4hS5/zEnaYaiS6vep+HEoR+BxGxyMvgO8B6RkaI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897996; c=relaxed/simple; bh=x8ZX/qobYB6KdqWRChx5iTU+X7UCaBsbY/nJC0T3Cws=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=j1mqxzn6CZPlo9eKPXjSaWCngKynlqeP7n8QgFeggjRA80Uy6gE6CkIcrRu0aPRpK4vXqLIyV1ckH/Do5KxIrwhn8bxntsaxIFxW3l4jW9M7lNFDIuHe9mBi2eAQg8ExUxp25gP6pEaLrSNq2sIJy2CQEV/m2LT/eje7L8tQYHY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: FIdAisRdT2y1XXL5Klqatg== X-CSE-MsgGUID: lnVUS/ylQS+ItSfF30LHNg== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:12 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 9D5734006DE8; Thu, 17 Apr 2025 22:53:08 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 06/38] ra6w: add cmd.h Date: Thu, 17 Apr 2025 16:52:04 +0300 Message-Id: <20250417135236.52410-7-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/cmd.h | 978 ++++++++++++++++++++++++ 1 file changed, 978 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/cmd.h diff --git a/drivers/net/wireless/renesas/ra6w/cmd.h b/drivers/net/wireless/renesas/ra6w/cmd.h new file mode 100644 index 000000000000..635709d05af0 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/cmd.h @@ -0,0 +1,978 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_CMD_H +#define RA6W_CMD_H + +#include + +#define RA6W_CMD_MAX_Q 4 +#define RA6W_CMD_DATA_SIZE 1700 +#define RA6W_CMD_MAX_MCS_LEN 16 + +#define RA6W_CMD_MAC_HE_MAC_CAPA_LEN 6 +#define RA6W_CMD_MAC_HE_PHY_CAPA_LEN 11 +#define RA6W_CMD_MAC_HE_PPE_THRES_MAX_LEN 25 + +#define RA6W_CMD_SCAN_SSID_MAX 2 +#define RA6W_CMD_SCAN_MAX_IE_LEN 200 +#define RA6W_CMD_SSID_LEN 32 + +#define RA6W_CMD_TX_LIFETIME_MS 100 + +#define RA6W_CMD_BT_COEX_MAX 3 +#define RA6W_CMD_BCN_MAX_CSA_CPT 2 +#define RA6W_CMD_BCN_SIZE 512 +#define RA6W_CMD_SECURY_KEY_LEN 32 + +#define RA6W_CMD_SCAN_CHANNEL_24G 14 +#define RA6W_CMD_SCAN_CHANNEL_5G 28 +#define RA6W_CMD_SCAN_CHANNEL_MAX (RA6W_CMD_SCAN_CHANNEL_24G + RA6W_CMD_SCAN_CHANNEL_5G) + +enum ra6w_cmd_data { + RA6W_CMD_DATA_START = 0, + RA6W_CMD_DATA_RX = 1, + RA6W_CMD_DATA_STATUS_RX = 2, + RA6W_CMD_DATA_TX = 5, + + RA6W_CMD_DATA_MAX, + RA6W_CMD_DATA_LAST = RA6W_CMD_DATA_MAX - 1 +}; + +enum ra6w_cmd_common { + RA6W_CMD_COMMON_START = 10, + RA6W_CMD_COMMON_RESET = 11, + RA6W_CMD_COMMON_GET_MAC_ADDR = 12, + + RA6W_CMD_COMMON_MAX, + RA6W_CMD_COMMON_LAST = RA6W_CMD_COMMON_MAX - 1 +}; + +enum ra6w_cmd_ctrl { + RA6W_CMD_FULLMAC_START = 100, + + RA6W_CMD_MM_RESET = 101, + RA6W_CMD_MM_START = 102, + RA6W_CMD_MM_GET_VER = 103, + RA6W_CMD_MM_ADD_IF = 104, + RA6W_CMD_MM_RM_IF = 105, + RA6W_CMD_MM_ADD_KEY = 106, + RA6W_CMD_MM_DEL_KEY = 107, + RA6W_CMD_MM_SET_POWER = 108, + RA6W_CMD_MM_GET_RSSI = 109, + RA6W_CMD_MM_REMAIN_ON_CHANNEL = 110, + RA6W_CMD_MM_SET_EDCA = 111, + + RA6W_CMD_ME_CONFIG = 113, + RA6W_CMD_ME_CHAN_CONFIG = 114, + RA6W_CMD_ME_SET_CONTROL_PORT = 115, + RA6W_CMD_ME_ADD_STA = 116, + RA6W_CMD_ME_DEL_STA = 117, + RA6W_CMD_ME_SET_MON_CFG = 121, + RA6W_CMD_ME_SET_PS_MODE = 122, + + RA6W_CMD_SC_START = 123, + RA6W_CMD_SC_CANCEL_CMD = 126, + + RA6W_CMD_SM_CONNECT = 127, + RA6W_CMD_SM_DISCONNECT = 128, + RA6W_CMD_SM_EXTERNAL_AUTH_REQUIRED_RSP = 129, + + RA6W_CMD_AM_START = 133, + RA6W_CMD_AM_STOP = 134, + RA6W_CMD_AM_START_CHAN_AVAIL = 135, + RA6W_CMD_AM_STOP_CHAN_AVAIL = 136, + RA6W_CMD_AM_PROBE_CLIENT = 137, + RA6W_CMD_AM_BCN_CHANGE = 138, + RA6W_CMD_AM_ISOLATE = 139, + + RA6W_CMD_FULLMAC_MAX, + RA6W_CMD_FULLMAC_LAST = RA6W_CMD_FULLMAC_MAX - 1 +}; + +enum ra6w_cmd_ind { + RA6W_CMD_IND_FULLMAC_START = 180, + + RA6W_CMD_ME_TKIP_MIC_FAILURE_IND = 181, + + RA6W_CMD_SC_RESULT_IND = 183, + RA6W_CMD_SC_COMPLETE_IND = 184, + RA6W_CMD_SC_CHANNEL_SURVEY_IND = 185, + + RA6W_CMD_SM_CONNECT_IND = 186, + RA6W_CMD_SM_DISCONNECT_IND = 187, + RA6W_CMD_SM_EXTERNAL_AUTH_REQUIRED_IND = 189, + + RA6W_CMD_TWT_SETUP_IND = 190, + + RA6W_CMD_AM_PROBE_CLIENT_IND = 191, + + RA6W_CMD_MM_CHANNEL_SWITCH_IND = 192, + RA6W_CMD_MM_CHANNEL_PRE_SWITCH_IND = 193, + RA6W_CMD_MM_REMAIN_ON_CHANNEL_EXP_IND = 194, + RA6W_CMD_MM_PS_CHANGE_IND = 195, + RA6W_CMD_MM_TRAFFIC_REQ_IND = 196, + RA6W_CMD_MM_CSA_COUNTER_IND = 198, + RA6W_CMD_MM_RSSI_STATUS_IND = 200, + RA6W_CMD_MM_CSA_FINISH_IND = 201, + RA6W_CMD_MM_CSA_TRAFFIC_IND = 202, + RA6W_CMD_MM_PACKET_LOSS_IND = 203, + + RA6W_CMD_TD_CHAN_SWITCH_IND = 204, + + RA6W_CMD_DBG_ERROR_IND = 207, + + RA6W_CMD_IND_FULLMAC_MAX, + RA6W_CMD_IND_FULLMAC_LAST = RA6W_CMD_IND_FULLMAC_MAX - 1 +}; + +enum ra6w_cmd_dbg { + RA6W_CMD_DBG_START = 220, + + RA6W_CMD_DBG_MEM_READ = 221, + RA6W_CMD_DBG_MEM_WRITE = 222, + RA6W_CMD_DBG_SET_MOD_FILTER = 223, + RA6W_CMD_DBG_SET_SEV_FILTER = 224, + RA6W_CMD_DBG_RF_TX = 227, + RA6W_CMD_DBG_RF_CW = 228, + RA6W_CMD_DBG_RF_CONT = 229, + RA6W_CMD_DBG_RF_CH = 230, + RA6W_CMD_DBG_RF_PER = 231, + RA6W_CMD_DBG_STATS_TX = 232, + + RA6W_CMD_DBG_MAX, + RA6W_CMD_DBG_LAST = RA6W_CMD_DBG_MAX - 1 +}; + +enum ra6w_cmd_ac { + RA6W_CMD_AC_BK, + RA6W_CMD_AC_BE, + RA6W_CMD_AC_VI, + RA6W_CMD_AC_VO, + + RA6W_CMD_AC_MAX, +}; + +enum ra6w_cmd_mac_chan_bandwidth { + RA6W_CMD_PHY_CHNL_BW_20, + RA6W_CMD_PHY_CHNL_BW_40, + RA6W_CMD_PHY_CHNL_BW_80, + RA6W_CMD_PHY_CHNL_BW_160, + RA6W_CMD_PHY_CHNL_BW_80P80, + + RA6W_CMD_PHY_CHNL_BW_OTHER, +}; + +enum ra6w_cmd_chan_bits { + RA6W_CMD_CHAN_NO_IR_BIT = BIT(0), + RA6W_CMD_CHAN_DISABLED_BIT = BIT(1), + RA6W_CMD_CHAN_RADAR_BIT = BIT(2), + RA6W_CMD_CHAN_HT40M_BIT = BIT(3), + RA6W_CMD_CHAN_HT40P_BIT = BIT(4), + RA6W_CMD_CHAN_VHT80_10_70_BIT = BIT(5), + RA6W_CMD_CHAN_VHT80_30_50_BIT = BIT(6), + RA6W_CMD_CHAN_VHT80_50_30_BIT = BIT(7), + RA6W_CMD_CHAN_VHT80_70_10_BIT = BIT(8) +}; + +enum ra6w_cmd_machw_version { + RA6W_CMD_MACHW_DEFAULT = 10, + RA6W_CMD_MACHW_HE = 20, + RA6W_CMD_MACHW_HE_AP = 30, +}; + +enum ra6w_cmd_connection_bits { + RA6W_CMD_CONN_CONTROL_PORT_HOST_BIT = BIT(0), + RA6W_CMD_CONN_CONTROL_PORT_NO_ENC_BIT = BIT(1), + RA6W_CMD_CONN_DISABLE_HT_BIT = BIT(2), + RA6W_CMD_CONN_USE_PAIRWISE_KEY_BIT = BIT(3), + RA6W_CMD_CONN_MFP_IN_USE_BIT = BIT(4), + RA6W_CMD_CONN_REASSOCIATION_BIT = BIT(5), + RA6W_CMD_CONN_USE_PRIVACY_BIT = BIT(7), + RA6W_CMD_CONN_REQUIRE_SPP_AMSDU_BIT = BIT(8), +}; + +enum ra6w_cmd_sm_auth_status_bits { + RA6W_CMD_STA_AUTH_EXT_BIT = BIT(0), +}; + +enum ra6w_cmd_sta_cap_bits { + RA6W_CMD_STA_CAP_QOS_BIT = BIT(0), + RA6W_CMD_STA_CAP_HT_BIT = BIT(1), + RA6W_CMD_STA_CAP_VHT_BIT = BIT(2), + RA6W_CMD_STA_CAP_MFP_BIT = BIT(3), + RA6W_CMD_STA_OP_NOT_IE_BIT = BIT(4), + RA6W_CMD_STA_CAP_HE_BIT = BIT(5), + RA6W_CMD_STA_CAP_SHORT_PREAMBLE_BIT = BIT(6), +}; + +enum ra6w_cmd_tdls_state { + RA6W_CMD_TDLS_STATE_LINK_IDLE, + RA6W_CMD_TDLS_STATE_TX_REQ, + RA6W_CMD_TDLS_STATE_TX_RSP, + RA6W_CMD_TDLS_STATE_LINK_ACTIVE, + + RA6W_CMD_TDLS_STATE_MAX +}; + +enum ra6w_cmd_roc_op_code { + RA6W_CMD_ROC_OP_CODE_START, + RA6W_CMD_ROC_OP_CODE_STOP, + + RA6W_CMD_ROC_OP_CODE_MAX +}; + +struct ra6w_cmd_hdr { + u8 cmd; + u8 ext_len; + __le16 data_len; +}; + +struct ra6w_cmd_reset_data { + __le64 time_usec; + __le32 bt_coex; +}; + +struct ra6w_cmd_reset_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_reset_data data; +} __packed; + +struct ra6w_cmd_phy_cfg { + u8 boot_mode; + u8 band; + u8 country_code[4]; +}; + +struct ra6w_cmd_mm_start_data { + struct ra6w_cmd_phy_cfg phy_cfg; + __le32 uapsd_timeout; + __le16 lp_clk_accuracy; + __le16 tx_timeout[RA6W_CMD_MAX_Q]; + __le16 rx_hostbuf_size; +}; + +struct ra6w_cmd_mm_start_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_mm_start_data data; +} __packed; + +struct ra6w_cmd_mm_common_get_mac_req { + struct ra6w_cmd_hdr hdr; +}; + +struct ra6w_cmd_fw_ver_rsp { + __le32 fw_version; + __le32 machw_features; + __le32 machw_version; + __le32 phy_feature; + __le32 phy_version; + __le32 features; + __le16 max_sta_nb; + u8 max_vif_nb; +}; + +struct ra6w_cmd_mac_addr { + u16 addr[ETH_ALEN / 2]; +}; + +struct ra6w_cmd_add_if_data { + u8 iftype; + struct ra6w_cmd_mac_addr addr; + bool p2p; + bool uf; +}; + +struct ra6w_cmd_add_if_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_add_if_data data; +} __packed; + +struct ra6w_cmd_add_if_rsp { + u8 status; + u8 vif_idx; +}; + +struct ra6w_cmd_del_if_data { + u8 vif_idx; +}; + +struct ra6w_cmd_del_if_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_del_if_data data; +} __packed; + +struct ra6w_cmd_oper_ch_info { + u8 ch_band; + u8 ch_bw; + __le16 freq_prim20; + __le16 freq_cen1; + __le16 freq_cen2; + __le16 ch_flags; + s8 tx_max_pwr; +}; + +struct ra6w_cmd_mac_htcapability { + __le16 ht_capa_info; + u8 a_mpdu_param; + u8 mcs_rate[RA6W_CMD_MAX_MCS_LEN]; + __le16 ht_extended_capa; + __le32 tx_beamforming_capa; + u8 asel_capa; +}; + +struct ra6w_cmd_mac_vhtcapability { + __le32 vht_capa_info; + __le16 rx_mcs_map; + __le16 rx_highest; + __le16 tx_mcs_map; + __le16 tx_highest; +}; + +struct ra6w_cmd_mac_he_mcs_nss_supp { + __le16 rx_mcs_80; + __le16 tx_mcs_80; + __le16 rx_mcs_160; + __le16 tx_mcs_160; + __le16 rx_mcs_80p80; + __le16 tx_mcs_80p80; +}; + +struct ra6w_cmd_mac_hecapability { + u8 mac_cap_info[RA6W_CMD_MAC_HE_MAC_CAPA_LEN]; + u8 phy_cap_info[RA6W_CMD_MAC_HE_PHY_CAPA_LEN]; + struct ra6w_cmd_mac_he_mcs_nss_supp mcs_supp; + u8 ppe_thres[RA6W_CMD_MAC_HE_PPE_THRES_MAX_LEN]; +}; + +struct ra6w_cmd_me_config_data { + struct ra6w_cmd_mac_htcapability ht_cap; + struct ra6w_cmd_mac_vhtcapability vht_cap; + struct ra6w_cmd_mac_hecapability he_cap; + __le16 tx_lft; + u8 phy_bw_max; + u8 ht_supp; + u8 vht_supp; + u8 he_supp; + u8 he_ul_on; + u8 ps_on; + u8 ant_div_on; + u8 dpsm; + u8 amsdu_tx; +}; + +struct ra6w_cmd_me_config_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_me_config_data data; +} __packed; + +struct ra6w_cmd_prim_ch_def { + __le16 ch_freq; + u8 ch_band; + s8 tx_max_pwr; + __le16 ch_flags; +}; + +struct ra6w_cmd_mac_ssid { + u8 ssid_len; + u8 ssid[RA6W_CMD_SSID_LEN]; +}; + +struct ra6w_cmd_me_chan_config_data { + struct ra6w_cmd_prim_ch_def chan24G[RA6W_CMD_SCAN_CHANNEL_24G]; + struct ra6w_cmd_prim_ch_def chan5G[RA6W_CMD_SCAN_CHANNEL_5G]; + u8 chan24G_cnt; + u8 chan5G_cnt; +}; + +struct ra6w_cmd_me_chan_config_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_me_chan_config_data data; +} __packed; + +struct ra6w_cmd_sc_start_data { + struct ra6w_cmd_prim_ch_def chan[RA6W_CMD_SCAN_CHANNEL_MAX]; + struct ra6w_cmd_mac_ssid ssid[RA6W_CMD_SCAN_SSID_MAX]; + u8 bssid[ETH_ALEN]; + __le32 ie_addr; + __le16 ie_len; + u8 vif_idx; + u8 n_channels; + u8 n_ssids; + u8 no_cck; + __le32 duration; + u8 ie[RA6W_CMD_SCAN_MAX_IE_LEN]; +}; + +struct ra6w_cmd_sc_start_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_sc_start_data data; +} __packed; + +struct ra6w_cmd_sc_cancel_data { + u8 vif_idx; +}; + +struct ra6w_cmd_sc_cancel_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_sc_cancel_data data; +} __packed; + +struct ra6w_cmd_sm_connect_data { + struct ra6w_cmd_mac_ssid ssid; + struct ra6w_cmd_mac_addr bssid; + struct ra6w_cmd_prim_ch_def chan; + __le32 flags; + __be16 ctrl_port_ethertype; + __le16 listen_interval; + u8 dont_wait_bcmc; + u8 auth_type; + u8 uapsd_queues; + u8 vif_idx; + __le16 ie_len; + u32 ie_buf[]; +}; + +struct ra6w_cmd_sm_connect_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_sm_connect_data data; +} __packed; + +struct ra6w_cmd_sm_connect_rsp { + u8 status; +}; + +struct ra6w_cmd_change_bcn_data { + u8 bcn_ptr[RA6W_CMD_BCN_SIZE]; + __le16 bcn_len; + __le16 tim_oft; + u8 tim_len; + u8 vif_id; + u8 csa_oft[RA6W_CMD_BCN_MAX_CSA_CPT]; +}; + +struct ra6w_cmd_change_bcn_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_change_bcn_data data; +} __packed; + +#define RA6W_CMD_MAC_RATESET_LEN 12 + +struct ra6w_cmd_mac_rateset { + u8 length; + u8 array[RA6W_CMD_MAC_RATESET_LEN]; +}; + +struct ra6w_cmd_sta_add_data { + struct ra6w_cmd_mac_addr mac_addr; + struct ra6w_cmd_mac_rateset rate_set; + struct ra6w_cmd_mac_htcapability ht_cap; + struct ra6w_cmd_mac_vhtcapability vht_cap; + struct ra6w_cmd_mac_hecapability he_cap; + __le32 flags; + __le16 aid; + u8 uapsd_queues; + u8 max_sp_len; + u8 opmode_notif; + u8 vif_idx; + u8 tdls_sta; + u8 tdls_sta_initiator; + u8 tdls_chsw_allowed; +}; + +struct ra6w_cmd_sta_add_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_sta_add_data data; +} __packed; + +struct ra6w_cmd_sta_del_data { + u8 sta_idx; + u8 is_tdls_sta; +}; + +struct ra6w_cmd_sta_del_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_sta_del_data data; +} __packed; + +struct ra6w_cmd_key_add_rsp { + u8 status; + u8 hw_key_index; +}; + +struct ra6w_cmd_sta_add_rsp { + u8 sta_idx; + u8 status; + u8 pm_state; +}; + +struct ra6w_cmd_ap_start_rsp { + u8 status; + u8 vif_idx; + u8 ch_idx; + u8 bcmc_idx; +}; + +struct ra6w_cmd_mon_mode_rsp { + u8 chan_index; + struct ra6w_cmd_oper_ch_info chan; +}; + +struct ra6w_cmd_probe_client_rsp { + u8 status; + __le32 probe_id; +}; + +struct ra6w_cmd_mem_read_rsp { + __le32 memaddr; + __le32 memdata; +}; + +struct ra6w_cmd_rf_per_rsp { + __le32 pass; + __le32 fcs; + __le32 phy; + __le32 overflow; +}; + +enum ra6w_cmd_stats_tx_bits { + RA6W_STATS_TX_STOP_BIT = BIT(0), + RA6W_STATS_TX_START_BIT = BIT(1), + RA6W_STATS_TX_REQ_BIT = BIT(2) +}; + +struct ra6w_cmd_stats_tx_data { + u8 req_type; +}; + +struct ra6w_cmd_stats_tx_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_stats_tx_data data; +} __packed; + +#define RA6W_CMD_CCK_OFDM_MCS_CNT 15 +#define RA6W_CMD_HT_GI_CNT 2 +#define RA6W_CMD_HT_MCS_CNT 8 +#define RA6W_CMD_VHT_GI_CNT 2 +#define RA6W_CMD_VHT_MCS_CNT 10 +#define RA6W_CMD_HE_GI_CNT 3 +#define RA6W_CMD_HE_MCS_CNT 10 + +struct ra6w_cmd_stats_tx_rsp { + u8 status; + __le64 t_success_cnt[4]; + __le64 t_fail_cnt[4]; + __le32 epr[2]; + u8 format_mod; + union { + struct { + __le64 success[RA6W_CMD_CCK_OFDM_MCS_CNT]; + __le64 fail[RA6W_CMD_CCK_OFDM_MCS_CNT]; + } non_ht; + struct { + __le64 success[RA6W_CMD_HT_GI_CNT][RA6W_CMD_HT_MCS_CNT]; + __le64 fail[RA6W_CMD_HT_GI_CNT][RA6W_CMD_HT_MCS_CNT]; + } ht; + struct { + __le64 success[RA6W_CMD_VHT_GI_CNT][RA6W_CMD_VHT_MCS_CNT]; + __le64 fail[RA6W_CMD_VHT_GI_CNT][RA6W_CMD_VHT_MCS_CNT]; + } vht; + struct { + __le64 success[RA6W_CMD_HE_GI_CNT][RA6W_CMD_HE_MCS_CNT]; + __le64 fail[RA6W_CMD_HE_GI_CNT][RA6W_CMD_HE_MCS_CNT]; + } he; + }; +}; + +struct ra6w_cmd_sc_survey_info { + __le16 freq; + s8 chan_noise_dbm; + __le32 chan_dwell_ms; + __le32 chan_busy_ms; +}; + +struct ra6w_cmd_legacy_info { + u32 format_mod : 4; + u32 ch_bw : 3; + u32 pre_type : 1; + u32 leg_length : 12; + u32 leg_rate : 4; +} __packed; + +struct ra6w_cmd_sc_result_ind { + __le16 length; + __le16 framectrl; + __le16 center_freq; + u8 band; + u8 sta_idx; + u8 inst_nbr; + s8 rssi; + struct ra6w_cmd_legacy_info legacy_info; + u32 payload[]; +}; + +#define RA6W_CMD_ASSOC_IE_SIZE 256 + +struct ra6w_cmd_sm_connect_ind { + __le16 conn_status; + struct ra6w_cmd_mac_addr bssid; + u8 is_roam; + u8 vif_idx; + u8 ap_idx; + u8 ch_idx; + u8 flag_qos; + u8 acm_bits; + __le16 assoc_req_ie_len; + __le16 assoc_rsp_ie_len; + __le16 assoc_id; + struct ra6w_cmd_oper_ch_info oper_chan; + __le32 edca_param[RA6W_CMD_AC_MAX]; + u8 assoc_ie_buf[RA6W_CMD_ASSOC_IE_SIZE]; +}; + +struct ra6w_cmd_disconnect_data { + __le16 deauth_reason; + u8 vif_idx; +}; + +struct ra6w_cmd_disconnect_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_disconnect_data data; +} __packed; + +struct ra6w_cmd_sm_disconnect_ind { + __le16 reason_code; + u8 vif_idx; + u8 reassoc; +}; + +struct ra6w_cmd_secury_key_info { + u8 length; + u32 array[RA6W_CMD_SECURY_KEY_LEN / 4]; +}; + +struct ra6w_cmd_key_add_data { + u8 key_idx; + u8 sta_id; + struct ra6w_cmd_secury_key_info key; + u8 cipher_suite; + u8 vif_idx; + u8 spp; + u8 pairwise; +}; + +struct ra6w_cmd_key_add_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_key_add_data data; +} __packed; + +struct ra6w_cmd_key_del_data { + u8 key_index; +}; + +struct ra6w_cmd_key_del_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_key_del_data data; +} __packed; + +struct ra6w_cmd_port_control_data { + u8 sta_idx; + u8 port_control_state; +}; + +struct ra6w_cmd_port_control_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_port_control_data data; +} __packed; + +struct ra6w_cmd_roc_data { + u8 op_code; + u8 vif_idx; + struct ra6w_cmd_oper_ch_info chan; + __le32 duration_ms; +}; + +struct ra6w_cmd_roc_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_roc_data data; +} __packed; + +struct ra6w_cmd_ap_start_data { + struct ra6w_cmd_mac_rateset basic_rates; + struct ra6w_cmd_oper_ch_info chan; + __le16 tim_oft; + __le16 bcn_int; + __le32 flags; + __be16 ctrl_port_ethertype; + u8 tim_len; + u8 vif_idx; + u8 beacon[RA6W_CMD_BCN_SIZE]; + __le16 bcn_len; +}; + +struct ra6w_cmd_ap_start_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_ap_start_data data; +} __packed; + +struct ra6w_cmd_ap_stop_data { + u8 vif_idx; +}; + +struct ra6w_cmd_ap_stop_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_ap_stop_data data; +} __packed; + +struct ra6w_cmd_mon_mode_data { + struct ra6w_cmd_oper_ch_info chan; + u8 ch_valid; + u8 uf_enable; +}; + +struct ra6w_cmd_mon_mode_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_mon_mode_data data; +} __packed; + +struct ra6w_cmd_probe_client_data { + u8 vif_idx; + u8 sta_idx; +}; + +struct ra6w_cmd_probe_client_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_probe_client_data data; +} __packed; + +struct ra6w_cmd_ap_isolate_data { + u8 ap_isolate; +}; + +struct ra6w_cmd_ap_isolate_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_ap_isolate_data data; +} __packed; + +struct ra6w_cmd_ap_isolate_rsp { + u8 ap_isolate; +}; + +struct ra6w_cmd_set_tx_power_data { + u8 vif_idx; + s8 tx_power; +}; + +struct ra6w_cmd_set_tx_power_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_set_tx_power_data data; +} __packed; + +struct ra6w_cmd_edca_data { + __le32 edca_param; + u8 uapsd_enabled; + u8 ac; + u8 vif_idx; +}; + +struct ra6w_cmd_edca_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_edca_data data; +} __packed; + +struct ra6w_cmd_set_power_mgmt_data { + u8 ps_mode; +}; + +struct ra6w_cmd_set_power_mgmt_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_set_power_mgmt_data data; +} __packed; + +struct ra6w_cmd_cqm_rssi_config_data { + u8 vif_idx; + s8 rssi_thold; + u8 rssi_hyst; +}; + +struct ra6w_cmd_cqm_rssi_config_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_cqm_rssi_config_data data; +} __packed; + +struct ra6w_cmd_me_mic_failure_ind { + struct ra6w_cmd_mac_addr mac_addr; + __le64 tsc; + u8 group; + u8 keyid; + u8 vif_idx; +}; + +struct ra6w_cmd_rssi_status_ind { + u8 vif_idx; + u8 rssi_status; + s8 rssi; +}; + +struct ra6w_cmd_dbg_mem_read_data { + __le32 mem_addr; +}; + +struct ra6w_cmd_dbg_mem_read_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_dbg_mem_read_data data; +} __packed; + +struct ra6w_cmd_dbg_mem_write_data { + __le32 mem_addr; + __le32 mem_value; +}; + +struct ra6w_cmd_dbg_mem_write_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_dbg_mem_write_data data; +} __packed; + +struct ra6w_cmd_dbg_mode_filter_data { + __le32 mode_filter; +}; + +struct ra6w_cmd_dbg_mode_filter_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_dbg_mode_filter_data data; +} __packed; + +struct ra6w_cmd_dbg_level_filter_data { + __le32 level_filter; +}; + +struct ra6w_cmd_dbg_level_filter_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_dbg_level_filter_data data; +} __packed; + +struct ra6w_cmd_rf_tx_data { + __le64 bssid; + __le64 dest_addr; + __le16 frequency; + __le16 num_frames; + __le16 frame_len; + u8 start; + __le32 tx_rate; + __le32 tx_power; + u8 gi; + u8 green_field; + u8 preamble_type; + u8 qos_enable; + u8 ack_policy; + u8 aifsn_val; +}; + +struct ra6w_cmd_rf_tx_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_rf_tx_data data; +} __packed; + +struct ra6w_cmd_rf_cw_data { + u8 start; + __le32 tx_power; + __le16 frequency; +}; + +struct ra6w_cmd_rf_cw_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_rf_cw_data data; +} __packed; + +struct ra6w_cmd_rf_cont_data { + __le16 frequency; + u8 start; + __le32 tx_rate; + __le32 tx_power; +}; + +struct ra6w_cmd_rf_cont_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_rf_cont_data data; +} __packed; + +struct ra6w_cmd_rf_ch_data { + __le16 frequency; +}; + +struct ra6w_cmd_rf_ch_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_rf_ch_data data; +} __packed; + +struct ra6w_cmd_rf_per_data { + u8 start; +}; + +struct ra6w_cmd_rf_per_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_rf_per_data data; +} __packed; + +struct ra6w_cmd_sm_ext_auth_req_ind { + u8 vif_idx; + struct ra6w_cmd_mac_ssid ssid; + struct ra6w_cmd_mac_addr bssid; + __le32 key_mgmt_suite; +}; + +struct ra6w_cmd_sm_ext_auth_req_rsp_data { + u8 vif_idx; + __le16 status; +}; + +struct ra6w_cmd_sm_ext_auth_req_rsp_req { + struct ra6w_cmd_hdr hdr; + struct ra6w_cmd_sm_ext_auth_req_rsp_data data; +} __packed; + +struct ra6w_cmd_channel_switch_ind { + u8 chan_index; + u8 roc_req; + u8 vif_idx; + u8 roc_tdls; + __le32 duration_us; + __le16 freq; +}; + +struct ra6w_cmd_channel_pre_switch_ind { + u8 chan_index; +}; + +struct ra6w_cmd_ap_probe_client_ind { + u8 vif_idx; + u8 sta_idx; + u8 client_present; + __le32 probe_id; +}; + +struct ra6w_cmd_pktloss_ind { + u8 vif_idx; + struct ra6w_cmd_mac_addr mac_addr; + __le32 num_packets; +}; + +struct ra6w_cmd_csa_counter_ind { + u8 vif_idx; + u8 csa_count; +}; + +struct ra6w_cmd_csa_finish_ind { + u8 vif_idx; + u8 status; + u8 chan_idx; +}; + +struct ra6w_cmd_csa_traffic_ind { + u8 vif_idx; + u8 enable; +}; + +#endif /* RA6W_CMD_H */ From patchwork Thu Apr 17 13:52:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882858 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 2E83424EAB6 for ; Thu, 17 Apr 2025 13:53:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897999; cv=none; b=m2GvTzRI+kXVboMFsOXmkBcXidhexLndKq2YgkrVwX40v7gwrCPJKGK9wMiO6czV7LRdY/vyJXv1LOqTGinfqNqqBGSFoUK1l9uA7VJm95h8l8ZxVxo1K5p/Ck33Vl1ydsBnyowqOmJwzt/YjtBSnH9XP3cGvgM7Bxpu7DAfx3c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744897999; c=relaxed/simple; bh=Dza1K45MMLZYCFpwctrzjwbv7OY5hIgEfE5LTKsNoLo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=TH1z47aMf+gqIAG6b8jcOazad9S50NFDPY2rqLL0UwLYDXJelHenqpj+gGAVT+kGmoCgBInOlkBbZqQgIz2mIHDDsq0zc6k09CrzqQkFrMzleBTIHq3+rpgq898xeCd3Vp2tdFWw8HGWtnfL8CmoK8j++oJdTbWfz9bvxklDvxM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: sr7G5/7RR8SX3adOhu32Tg== X-CSE-MsgGUID: eLnd9bb+RBmjmDhti6GxOQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:16 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 2E6C64006DE8; Thu, 17 Apr 2025 22:53:12 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 07/38] ra6w: add core.c Date: Thu, 17 Apr 2025 16:52:05 +0300 Message-Id: <20250417135236.52410-8-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/core.c | 286 +++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/core.c diff --git a/drivers/net/wireless/renesas/ra6w/core.c b/drivers/net/wireless/renesas/ra6w/core.c new file mode 100644 index 000000000000..5691ec6d07f9 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/core.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains the main events processing thread. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include + +#include "core.h" +#include "if.h" +#include "params.h" +#include "dbg.h" + +#define RA6W_CORE_THREAD_NAME "ra6w_core_thread" + +static inline u8 ra6w_core_cmd_to_hndl_type(u8 cmd) +{ + if (cmd == RA6W_CMD_DATA_RX) + return RA6W_CORE_HNDL_RX; + + if (cmd == RA6W_CMD_DATA_STATUS_RX) + return RA6W_CORE_HNDL_STATUS; + + if (cmd >= RA6W_CMD_COMMON_START && cmd < RA6W_CMD_COMMON_MAX) + return RA6W_CORE_HNDL_CTRL; + + if (cmd >= RA6W_CMD_FULLMAC_START && cmd < RA6W_CMD_FULLMAC_MAX) + return RA6W_CORE_HNDL_CTRL; + + if (cmd >= RA6W_CMD_DBG_START && cmd < RA6W_CMD_DBG_MAX) + return RA6W_CORE_HNDL_CTRL; + + if (cmd >= RA6W_CMD_IND_FULLMAC_START && cmd < RA6W_CMD_IND_FULLMAC_MAX) + return RA6W_CORE_HNDL_INDI; + + return RA6W_CORE_HNDL_MAX; +} + +static void ra6w_core_event_handler(struct ra6w_core *core) +{ + struct ra6w_if *ifp = container_of(core, struct ra6w_if, core); + struct ra6w_status *status = &core->status; + struct ra6w_indi *indi = &core->indi; + struct ra6w_rx *rx = &core->rx; + int ret; + union ra6w_core_data *data = NULL; + struct sk_buff *skb = NULL; + u8 cmd; + + do { + if (!skb) { + skb = dev_alloc_skb(sizeof(*data)); + if (!skb) + return; + + skb_put(skb, sizeof(*data)); + } + + ret = ra6w_if_read(ifp, skb->data, sizeof(*data)); + if (ret) + break; + + data = (union ra6w_core_data *)skb->data; + cmd = ra6w_core_cmd_to_hndl_type(data->rx.cmd); + switch (cmd) { + case RA6W_CORE_HNDL_RX: + ret = ra6w_rx_event_post(rx, skb); + if (ret == 0) + skb = NULL; + break; + case RA6W_CORE_HNDL_CTRL: + ra6w_ctrl_event_post(&core->ctrl, skb); + break; + case RA6W_CORE_HNDL_INDI: + ret = ra6w_indi_event_post(indi, skb); + if (ret == 0) + skb = NULL; + break; + case RA6W_CORE_HNDL_STATUS: + ra6w_status_event_post(&core->status, skb); + break; + default: + ret = -EINVAL; + break; + } + } while (!kthread_should_stop() && !ret && !ra6w_status_rx_get(status)); + + dev_kfree_skb(skb); +} + +static int core_thread_handler(void *arg) +{ + struct ra6w_core *core = arg; + int event = 0; + + while (!kthread_should_stop()) { + event = ra6w_q_wait(&core->event, RA6W_CORE_EVENT_MASK); + if (event & BIT(RA6W_CORE_EVENT_DATA)) + ra6w_core_event_handler(core); + + if (event & BIT(RA6W_CORE_EVENT_RESET)) + break; + + atomic_set(&core->event.condition, 0); + } + + return 0; +} + +static int ra6w_core_event_init(struct ra6w_core *core) +{ + atomic_set(&core->event.condition, 0); + init_waitqueue_head(&core->event.wait_queue); + core->task = kthread_run(core_thread_handler, core, RA6W_CORE_THREAD_NAME); + if (!core->task) { + ra6w_err("[%s] kthread_run %s failed\n", __func__, RA6W_CORE_THREAD_NAME); + return -ENOENT; + } + + return 0; +} + +static void ra6w_core_event_deinit(struct ra6w_core *core) +{ + if (!core->task) + return; + + atomic_set(&core->event.condition, BIT(RA6W_CORE_EVENT_RESET)); + kthread_stop(core->task); + core->task = NULL; +} + +int ra6w_core_init(struct ra6w_core *core) +{ + int ret; + + ret = ra6w_tx_init(&core->tx); + if (ret) + return ret; + + ra6w_ctrl_init(&core->ctrl); + + ret = ra6w_indi_init(&core->indi); + if (ret) + goto ctrl_deinit; + + ret = ra6w_rx_init(&core->rx); + if (ret) + goto indi_deinit; + + ra6w_status_init(&core->status); + + ret = ra6w_core_event_init(core); + if (ret) + goto rx_deinit; + + return 0; + +rx_deinit: + ra6w_rx_deinit(&core->rx); + +indi_deinit: + ra6w_indi_deinit(&core->indi); + +ctrl_deinit: + ra6w_tx_deinit(&core->tx); + + return ret; +} + +static u8 RENESAS_OUI[] = { 0xd4, 0x3d, 0x39 }; + +static void ra6w_core_rand_mac_addr_gen(u8 *mac) +{ + memcpy(mac, RENESAS_OUI, 3); + get_random_bytes(&mac[3], 3); +} + +static const u8 *ra6w_core_find_tag(const u8 *file_data, const u8 *tag_name, u32 tag_name_len) +{ + const char *tag_data = NULL; + + if (!tag_name || tag_name_len == 0) + return NULL; + + tag_data = strnstr(file_data, tag_name, tag_name_len); + if (!tag_data) + return NULL; + + return tag_data + tag_name_len; +} + +#define RA6W_CORE_DEFAULT_MAC_NAME "default_mac.ini" +#define RA6W_CORE_MAC_TAG "MAC_ADDR=" +#define RA6W_CORE_MAC_TAG_LEN strlen(RA6W_CORE_MAC_TAG) + +static int ra6w_core_fw_mac_addr_get(struct ra6w_core *core, u8 *mac) +{ + struct ra6w_if *ifp = container_of(core, struct ra6w_if, core); + const struct firmware *fw = NULL; + const u8 *fw_mac = NULL; + char path[100] = { 0 }; + int ret; + int n; + + snprintf(path, sizeof(path), "%s/%s", KBUILD_MODNAME, RA6W_CORE_DEFAULT_MAC_NAME); + + ret = request_firmware(&fw, path, &ifp->dev.func->dev); + if (ret) { + ra6w_warn("request_firmware %s failed: %d\n", path, ret); + return -ENOENT; + } + + if (RA6W_CORE_MAC_TAG_LEN + RA6W_MAC_ADDR_STR_LEN > fw->size) { + ret = -ENOENT; + goto free_fw; + } + + fw_mac = ra6w_core_find_tag(fw->data, RA6W_CORE_MAC_TAG, RA6W_CORE_MAC_TAG_LEN); + if (!fw_mac) { + ra6w_warn("Tag %s not found in %s\n", RA6W_CORE_MAC_TAG, path); + ret = -ENOENT; + goto free_fw; + } + + n = sscanf(fw_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + mac + 0, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5); + if (n != ETH_ALEN || !is_valid_ether_addr(mac)) + ret = -ENOENT; + +free_fw: + release_firmware(fw); + + return ret; +} + +static int ra6w_core_mac_addr_init(struct ra6w_core *core) +{ + u8 mac[ETH_ALEN] = { 0 }; + int ret; + + ret = ra6w_ctrl_otp_mac_addr_get(&core->ctrl, mac); + if (ret == 0) { + ra6w_info("OTP MAC Address : %pM\n", mac); + goto set; + } + + ret = ra6w_core_fw_mac_addr_get(core, mac); + if (ret == 0) { + ra6w_info("FW MAC Address %pM\n", mac); + goto set; + } + + ra6w_core_rand_mac_addr_gen(mac); + ra6w_info("Random MAC Address %pM\n", mac); + +set: + ether_addr_copy(core->sinfo.default_mac, mac); + + return 0; +} + +int ra6w_core_post_init(struct ra6w_core *core) +{ + int ret; + struct ra6w_ctrl *ctrl = &core->ctrl; + + ret = ra6w_ctrl_dev_reset(ctrl); + if (ret) + return ret; + + ret = ra6w_ctrl_update_fw_ver(ctrl); + if (ret) + return ret; + + return ra6w_core_mac_addr_init(core); +} + +void ra6w_core_deinit(struct ra6w_core *core) +{ + ra6w_core_event_deinit(core); + ra6w_rx_deinit(&core->rx); + ra6w_indi_deinit(&core->indi); + ra6w_tx_deinit(&core->tx); +} From patchwork Thu Apr 17 13:52:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882272 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A7F7B24E4B2 for ; Thu, 17 Apr 2025 13:53:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898003; cv=none; b=FP/rmB8Ybw15Te9VmBoAr55BAxUx3pTd3/vajRZj+fdWcGGFC18+jBuQ2hUosur4kDuKkiHih0xlvY/6r+zqz5DYt0MJVGYyX85N4nqDcL/zrqSB8uFQS9ygjNEVUOu//5gcGGgjSHWdz2RbiJ6VM5rua1fo9lJbwlrgi1IhpRg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898003; c=relaxed/simple; bh=tJ07C6YZyODuHeOLhuwjyJ8CF5t/NnWhjqQ5uX/6Y5A=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=AWswLau2K6aRaB357ATyzTqSQjDjkfGyyJlrBq6KyFqLsoy1Fzug+oDH3scvWFrY9+jEZpfrHQ/+hiyZNLfD5omOPk/c3JV4NlTrmWsWozZ6j2cHGlIb2GzsOBMGxl085bYKrN6hs+Lf19k1itouZ1WYn0Dzf2ofSkyGcL2uaAY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: n1TXYwYmRSiWdujinXtaYQ== X-CSE-MsgGUID: pqrHJYwKQiC1IIlqoXToLA== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:20 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 5262D4006DE8; Thu, 17 Apr 2025 22:53:16 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 08/38] ra6w: add core.h Date: Thu, 17 Apr 2025 16:52:06 +0300 Message-Id: <20250417135236.52410-9-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/core.h | 99 ++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/core.h diff --git a/drivers/net/wireless/renesas/ra6w/core.h b/drivers/net/wireless/renesas/ra6w/core.h new file mode 100644 index 000000000000..78f7102e15f6 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/core.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_CORE_H +#define RA6W_CORE_H + +#include +#include +#include +#include +#include + +#include "status.h" +#include "cmd.h" +#include "rx.h" +#include "tx.h" +#include "indi.h" +#include "ctrl.h" +#include "sdio.h" +#include "recovery.h" + +#define RA6W_BASE_HDR_SIZE (sizeof(u8) + sizeof(u8) + sizeof(u16)) +#define RA6W_GET_DATA_SIZE(ext_len, data_len) (RA6W_BASE_HDR_SIZE + (ext_len) + (data_len)) + +struct ra6w_core_stat { + u32 packets; + u32 err; +}; + +struct ra6w_core_stats { + struct ra6w_core_stat tx; + struct ra6w_core_stat rx; +}; + +struct ra6w_sys_info { + struct ra6w_cmd_fw_ver_rsp fw_ver; + char fw_version[32]; + u8 machw_support_type; + u8 default_mac[ETH_ALEN]; +}; + +enum ra6w_core_data_event { + RA6W_CORE_EVENT_DATA, + + RA6W_CORE_EVENT_DATA_MAX, +}; + +#define RA6W_CORE_EVENT_RESET RA6W_CORE_EVENT_DATA_MAX +#define RA6W_CORE_EVENT_MASK (BIT(RA6W_CORE_EVENT_DATA) | BIT(RA6W_CORE_EVENT_RESET)) + +enum ra6w_core_handler_id { + RA6W_CORE_HNDL_RX, + RA6W_CORE_HNDL_CTRL, + RA6W_CORE_HNDL_INDI, + RA6W_CORE_HNDL_STATUS, + + RA6W_CORE_HNDL_MAX, +}; + +/* + * @priv: private cfg80211 data + * @task: main kthread task + * @event: main kthread event data + * @status: status of Tx, Rx, ctrl fw routines + * @ctrl: synchronous fw routine data + * @indi: asynchronous fw routine data + * @rx: Rx routine data + * @tx: Tx routine data + * @stats: Rx, Tx statistics + * @sinfo: fw version information + * @recovery: recovery data + */ +struct ra6w_core { + struct ra6w_cfg80211_priv *priv; + struct task_struct *task; + struct ra6w_q_event event; + struct ra6w_status status; + struct ra6w_ctrl ctrl; + struct ra6w_indi indi; + struct ra6w_rx rx; + struct ra6w_tx tx; + struct ra6w_core_stats stats; + struct ra6w_sys_info sinfo; + struct ra6w_recovery recovery; +}; + +union ra6w_core_data { + struct ra6w_rx_buf rx; + struct ra6w_indi_buf indi; + struct ra6w_ctrl_rsp ctrl; +}; + +int ra6w_core_init(struct ra6w_core *core); +void ra6w_core_deinit(struct ra6w_core *core); +int ra6w_core_post_init(struct ra6w_core *core); + +#endif /* RA6W_CORE_H */ From patchwork Thu Apr 17 13:52:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882857 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6FE0724EF61 for ; Thu, 17 Apr 2025 13:53:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898008; cv=none; b=jDNDZmAyJfUmZHkej6RoXXAhEZHgsnuUNQCNcjP5U4nnGpJj8lEkxb8EKGh9AYP2quM5SpRG0/jcLlhkhCuFMEYWfrkJdYwrsvbgIFCxenytmB7uM1Zx+pq3VfzRpiwFZnk4o9b/mO6WftKccOK6GXxCfAD/DQgQVgnIWw1bKSc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898008; c=relaxed/simple; bh=uNuI8hNdpIS37N6iXXkpOO3ANxlUDfUwmFQ0fpBjdMc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=gG2Y1kRwIftI4SgIYl/nyjnP/070ZUTA/+9EgMCqV31MXQW65CX5qSN+CRrLRPlPdhd5GazYMk+DhrXKcJQmpy6EzBwVkKekpGRsXMmcqOccECqujNPYh1qGzqUVTUZou+ze8ymuGfnXK5v9rVUVwJiPxfTp7ltPPvQNxNxR34w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: hbwGHSvsTuW/pNivB0Nutw== X-CSE-MsgGUID: nJLL4fhbT1+r3V0Ap44gEQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:25 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 74AF7400502F; Thu, 17 Apr 2025 22:53:21 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 09/38] ra6w: add ctrl.c Date: Thu, 17 Apr 2025 16:52:07 +0300 Message-Id: <20250417135236.52410-10-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/ctrl.c | 1649 ++++++++++++++++++++++ 1 file changed, 1649 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/ctrl.c diff --git a/drivers/net/wireless/renesas/ra6w/ctrl.c b/drivers/net/wireless/renesas/ra6w/ctrl.c new file mode 100644 index 000000000000..5d8efc9e3bc7 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/ctrl.c @@ -0,0 +1,1649 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains synchronous fw routine. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include +#include + +#include "dbg.h" +#include "cmd.h" +#include "core.h" +#include "ctrl.h" +#include "if.h" +#include "cfg80211.h" +#include "params.h" + +#define RA6W_CTRL_EVENT_WAIT_DEFAULT_TIME_MS 2000 + +static int ra6w_ctrl_wait(struct ra6w_ctrl *ctrl, u8 cmd) +{ + int ret_event = 0; + struct ra6w_q_event *event = &ctrl->event; + + wait_event_interruptible_timeout(event->wait_queue, + ra6w_q_event_condition(event, cmd, &ret_event), + msecs_to_jiffies(RA6W_CTRL_EVENT_WAIT_DEFAULT_TIME_MS)); + + atomic_set(&event->condition, RA6W_CTRL_EVENT_RESET); + + if (ret_event != cmd) { + ra6w_err("[%s] received %d event. Expected %u event\n", __func__, ret_event, cmd); + return -EIO; + } + + return 0; +} + +static int ra6w_ctrl_set(struct ra6w_ctrl *ctrl, u8 cmd, void *req, u16 req_len) +{ + struct ra6w_cmd_hdr *hdr; + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + struct ra6w_if *ifp = container_of(core, struct ra6w_if, core); + + if (!req) + return -ENOENT; + + hdr = req; + hdr->cmd = cmd; + hdr->data_len = cpu_to_le16(req_len); + + return ra6w_if_write(ifp, req, req_len + sizeof(*hdr)); +} + +static int ra6w_ctrl_set_wait(struct ra6w_ctrl *ctrl, u8 cmd, void *req, u16 req_len) +{ + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + struct ra6w_if *ifp = container_of(core, struct ra6w_if, core); + int ret; + + ret = ra6w_if_write(ifp, req, req_len); + if (ret) + return ret; + + return ra6w_ctrl_wait(ctrl, cmd); +} + +static int ra6w_ctrl_set_and_wait(struct ra6w_ctrl *ctrl, u8 cmd, void *req, u16 req_len) +{ + struct ra6w_cmd_hdr *hdr; + int ret; + + if (!req) + return -ENOENT; + + hdr = req; + hdr->cmd = cmd; + hdr->data_len = cpu_to_le16(req_len); + + ret = ra6w_ctrl_set_wait(ctrl, cmd, req, req_len + sizeof(*hdr)); + if (ret) { + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + + ra6w_recovery_event_post(&core->recovery); + } + + return ret; +} + +static int ra6w_ctrl_rsp_sync(struct ra6w_ctrl *ctrl, u8 cmd, u16 rsp_len) +{ + if (ctrl->cmd != cmd) + return -EINVAL; + + if (ctrl->rsp_len != rsp_len) + return -EINVAL; + + ctrl->rsp = NULL; + ctrl->rsp_len = 0; + + return 0; +} + +static int ra6w_ctrl_set_and_wait_rsp(struct ra6w_ctrl *ctrl, u8 cmd, void *req, u16 req_len, + void *rsp, u16 rsp_len) +{ + struct ra6w_cmd_hdr *hdr; + int ret; + + if (!req || !rsp) + return -ENOENT; + + hdr = req; + hdr->cmd = cmd; + hdr->data_len = cpu_to_le16(req_len); + + ctrl->rsp = rsp; + ctrl->rsp_len = rsp_len; + + ret = ra6w_ctrl_set_wait(ctrl, cmd, req, req_len + sizeof(*hdr)); + if (ret) + return ret; + + return ra6w_ctrl_rsp_sync(ctrl, cmd, rsp_len); +} + +void ra6w_ctrl_event_post(struct ra6w_ctrl *ctrl, const struct sk_buff *skb) +{ + struct ra6w_ctrl_rsp *rsp = (struct ra6w_ctrl_rsp *)skb->data; + + if (rsp->ext_len == RA6W_CTRL_RSP_EXT_LEN) { + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + + ra6w_status_set(&core->status, rsp->ext_hdr.status); + } + + ctrl->cmd = rsp->cmd; + + if (ctrl->rsp) { + ctrl->rsp_len = le16_to_cpu(rsp->data_len); + memcpy(ctrl->rsp, rsp->data, le16_to_cpu(rsp->data_len)); + } + + ra6w_q_event_set(&ctrl->event, rsp->cmd); +} + +/* Assume that rate higher that 54 Mbps are BSS membership */ +#define RA6W_IS_BASIC_RATE(r) (((r) & 0x80) && (((r) & ~0x80) <= (54 * 2))) + +static const s32 bw2chnl[] = { + [NL80211_CHAN_WIDTH_20_NOHT] = RA6W_CMD_PHY_CHNL_BW_20, + [NL80211_CHAN_WIDTH_20] = RA6W_CMD_PHY_CHNL_BW_20, + [NL80211_CHAN_WIDTH_40] = RA6W_CMD_PHY_CHNL_BW_40, + [NL80211_CHAN_WIDTH_80] = RA6W_CMD_PHY_CHNL_BW_80, + [NL80211_CHAN_WIDTH_160] = RA6W_CMD_PHY_CHNL_BW_160, + [NL80211_CHAN_WIDTH_80P80] = RA6W_CMD_PHY_CHNL_BW_80P80, +}; + +const s32 chnl2bw[] = { + [RA6W_CMD_PHY_CHNL_BW_20] = NL80211_CHAN_WIDTH_20, + [RA6W_CMD_PHY_CHNL_BW_40] = NL80211_CHAN_WIDTH_40, + [RA6W_CMD_PHY_CHNL_BW_80] = NL80211_CHAN_WIDTH_80, + [RA6W_CMD_PHY_CHNL_BW_160] = NL80211_CHAN_WIDTH_160, + [RA6W_CMD_PHY_CHNL_BW_80P80] = NL80211_CHAN_WIDTH_80P80, +}; + +static inline u16 ra6w_ctrl_get_chan_flags(u32 flags) +{ + u16 chan_flags = 0; + + if (flags & IEEE80211_CHAN_DISABLED) + chan_flags |= RA6W_CMD_CHAN_DISABLED_BIT; + + if (flags & IEEE80211_CHAN_NO_IR) + chan_flags |= RA6W_CMD_CHAN_NO_IR_BIT; + + if (flags & IEEE80211_CHAN_RADAR) + chan_flags |= RA6W_CMD_CHAN_RADAR_BIT; + + return chan_flags; +} + +int ra6w_ctrl_dev_hw_reset(struct ra6w_ctrl *ctrl) +{ + int ret; + u8 cmd = RA6W_CMD_COMMON_RESET; + struct ra6w_cmd_reset_req *req = NULL; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + ret = ra6w_ctrl_set(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_dev_reset(struct ra6w_ctrl *ctrl) +{ + struct ra6w_cmd_reset_req *req = NULL; + u8 cmd = RA6W_CMD_MM_RESET; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.time_usec = cpu_to_le64(local_clock() / NSEC_PER_USEC); + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_dev_start(struct ra6w_ctrl *ctrl, const struct ra6w_cmd_phy_cfg *phy_config) +{ + struct ra6w_cmd_mm_start_req *req = NULL; + u8 cmd = RA6W_CMD_MM_START; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + memcpy(&req->data.phy_cfg, phy_config, sizeof(*phy_config)); + req->data.uapsd_timeout = cpu_to_le32(ra6w_params_uapsd_threshold()); + req->data.lp_clk_accuracy = cpu_to_le16(RA6W_CFG80211_LPCA_PPM); + req->data.rx_hostbuf_size = cpu_to_le16(RA6W_CMD_DATA_SIZE); + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_otp_mac_addr_get(struct ra6w_ctrl *ctrl, u8 *mac) +{ + struct ra6w_cmd_hdr *req = NULL; + u8 cmd = RA6W_CMD_COMMON_GET_MAC_ADDR; + int ret; + + if (!mac) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, 0, mac, ETH_ALEN); + if (ret) + goto req_free; + + if (!is_valid_ether_addr(mac)) + ret = -ENOENT; + +req_free: + kfree(req); + + return ret; +} + +static int ra6w_ctrl_get_fw_ver(struct ra6w_ctrl *ctrl, struct ra6w_cmd_fw_ver_rsp *rsp) +{ + struct ra6w_cmd_hdr *req = NULL; + u8 cmd = RA6W_CMD_MM_GET_VER; + int ret; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, 0, rsp, sizeof(*rsp)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_update_fw_ver(struct ra6w_ctrl *ctrl) +{ +#define UNPACK_FW_VERSION(str, fw_version) \ +do { \ + u8 *p = (u8 *)fw_version; \ + snprintf(str, sizeof(str), \ + "%hhu.%hhu.%hhu.%hhu.%hhu", \ + (p[3] >> 4) & 0x0f, p[3] & 0x0f, p[2], p[1], p[0]); \ +} while (0) + + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + struct ra6w_cmd_fw_ver_rsp *fw_ver = &core->sinfo.fw_ver; + int ret; + + ret = ra6w_ctrl_get_fw_ver(ctrl, fw_ver); + if (ret) + return ret; + + UNPACK_FW_VERSION(core->sinfo.fw_version, &fw_ver->fw_version); + ra6w_info("fw_version : %s", core->sinfo.fw_version); + ra6w_dbg("machw_features : 0x%X", fw_ver->machw_features); + ra6w_dbg("machw_version : 0x%X", fw_ver->machw_version); + ra6w_dbg("phy_feature : 0x%X", fw_ver->phy_feature); + ra6w_dbg("phy_version : 0x%X", fw_ver->phy_version); + ra6w_dbg("features : 0x%X", fw_ver->features); + ra6w_dbg("max_sta_nb : %d", fw_ver->max_sta_nb); + ra6w_dbg("max_vif_nb : %d", fw_ver->max_vif_nb); + + core->sinfo.machw_support_type = RA6W_MACHW_SUPPORT_HE; + + return 0; +} + +int ra6w_ctrl_if_add(struct ra6w_ctrl *ctrl, const u8 *mac, u8 iftype, bool p2p, + struct ra6w_cmd_add_if_rsp *rsp) +{ + int ret; + struct ra6w_cmd_add_if_req *req = NULL; + struct ra6w_cmd_add_if_data *req_data = NULL; + u8 cmd = RA6W_CMD_MM_ADD_IF; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req_data = &req->data; + + ether_addr_copy((u8 *)&req_data->addr.addr, mac); + + switch (iftype) { + case NL80211_IFTYPE_P2P_CLIENT: + p2p = true; + req_data->iftype = RA6W_VIF_TYPE_STA; + break; + case NL80211_IFTYPE_STATION: + req_data->iftype = RA6W_VIF_TYPE_STA; + break; + case NL80211_IFTYPE_ADHOC: + req_data->iftype = RA6W_VIF_TYPE_IBSS; + break; + case NL80211_IFTYPE_P2P_GO: + p2p = true; + req_data->iftype = RA6W_VIF_TYPE_AP; + break; + case NL80211_IFTYPE_AP: + req_data->iftype = RA6W_VIF_TYPE_AP; + break; + case NL80211_IFTYPE_MESH_POINT: + req_data->iftype = RA6W_VIF_TYPE_MESH_POINT; + break; + case NL80211_IFTYPE_AP_VLAN: + ret = -EINVAL; + goto free; + case NL80211_IFTYPE_MONITOR: + req_data->iftype = RA6W_VIF_TYPE_MONITOR; + req_data->uf = false; + break; + default: + req_data->iftype = RA6W_VIF_TYPE_STA; + break; + } + + req_data->p2p = p2p; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(req->data), rsp, sizeof(*rsp)); + if (!ret) + ret = ra6w_status_err_code_to_errno(rsp->status); + +free: + kfree(req); + + return ret; +} + +int ra6w_ctrl_if_remove(struct ra6w_ctrl *ctrl, u8 vif_idx) +{ + struct ra6w_cmd_del_if_req *req = NULL; + u8 cmd = RA6W_CMD_MM_RM_IF; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.vif_idx = vif_idx; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +static int ra6w_ctrl_req_ht_cap_set(struct ra6w_cmd_me_config_data *req_data, + struct ieee80211_sta_ht_cap *ht_cap) +{ + struct ra6w_cmd_mac_htcapability *ht = &req_data->ht_cap; + const u8 *ht_mcs = NULL; + int i = 0; + + if (!ht_cap->ht_supported) { + ra6w_err("[%s] HT not supported. Abort.\n", __func__); + return -ENOENT; + } + + req_data->ht_supp = ht_cap->ht_supported; + ht->ht_capa_info = cpu_to_le16(ht_cap->cap); + ht->a_mpdu_param = ht_cap->ampdu_factor | + (ht_cap->ampdu_density << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); + + ht_mcs = (u8 *)&ht_cap->mcs; + for (i = 0; i < sizeof(ht_cap->mcs); i++) + ht->mcs_rate[i] = ht_mcs[i]; + + ht->ht_extended_capa = 0; + ht->tx_beamforming_capa = 0; + ht->asel_capa = 0; + + return 0; +} + +static void ra6w_ctrl_req_vht_cap_set(struct ra6w_cmd_me_config_data *req_data, + const struct ieee80211_sta_vht_cap *vht_cap) +{ + struct ra6w_cmd_mac_vhtcapability *vht = &req_data->vht_cap; + + req_data->vht_supp = vht_cap->vht_supported; + if (!vht_cap->vht_supported) + return; + + vht->vht_capa_info = cpu_to_le32(vht_cap->cap); + vht->rx_highest = vht_cap->vht_mcs.rx_highest; + vht->rx_mcs_map = vht_cap->vht_mcs.rx_mcs_map; + vht->tx_highest = vht_cap->vht_mcs.tx_highest; + vht->tx_mcs_map = vht_cap->vht_mcs.tx_mcs_map; +} + +static void ra6w_ctrl_req_he_cap_set(struct ra6w_cmd_me_config_data *req_data, + const struct ieee80211_sta_he_cap *he_cap) +{ + struct ra6w_cmd_mac_hecapability *he = &req_data->he_cap; + const struct ieee80211_he_cap_elem *cap_elem; + + req_data->he_supp = he_cap->has_he; + if (!he_cap->has_he) + return; + + cap_elem = &he_cap->he_cap_elem; + memcpy(he->mac_cap_info, cap_elem->mac_cap_info, ARRAY_SIZE(cap_elem->mac_cap_info)); + memcpy(he->phy_cap_info, cap_elem->phy_cap_info, ARRAY_SIZE(cap_elem->phy_cap_info)); + + he->mcs_supp.rx_mcs_80 = he_cap->he_mcs_nss_supp.rx_mcs_80; + he->mcs_supp.tx_mcs_80 = he_cap->he_mcs_nss_supp.tx_mcs_80; + he->mcs_supp.rx_mcs_160 = he_cap->he_mcs_nss_supp.rx_mcs_160; + he->mcs_supp.tx_mcs_160 = he_cap->he_mcs_nss_supp.tx_mcs_160; + he->mcs_supp.rx_mcs_80p80 = he_cap->he_mcs_nss_supp.rx_mcs_80p80; + he->mcs_supp.tx_mcs_80p80 = he_cap->he_mcs_nss_supp.tx_mcs_80p80; + + memcpy(he->ppe_thres, he_cap->ppe_thres, RA6W_CMD_MAC_HE_PPE_THRES_MAX_LEN); + + req_data->he_ul_on = ra6w_params_he_ul_on(); +} + +static int ra6w_ctrl_cmd_me_config_set(struct ra6w_cmd_me_config_data *req_data, + const struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband = NULL; + struct ieee80211_sta_ht_cap *ht_cap = NULL; + struct ieee80211_sta_vht_cap *vht_cap = NULL; + struct ieee80211_sta_he_cap const *he_cap = NULL; + int ret; + + if (wiphy->bands[NL80211_BAND_5GHZ]) { + sband = wiphy->bands[NL80211_BAND_5GHZ]; + ht_cap = &sband->ht_cap; + vht_cap = &sband->vht_cap; + if (sband->iftype_data) + he_cap = &sband->iftype_data->he_cap; + } else if (wiphy->bands[NL80211_BAND_2GHZ]) { + sband = wiphy->bands[NL80211_BAND_2GHZ]; + ht_cap = &sband->ht_cap; + if (sband->iftype_data) + he_cap = &sband->iftype_data->he_cap; + vht_cap = NULL; + } + + if (!ht_cap) { + ra6w_err("[%s] HT not found. Abort.\n", __func__); + return -ENOENT; + } + + ret = ra6w_ctrl_req_ht_cap_set(req_data, ht_cap); + if (ret) + return ret; + + if (vht_cap) + ra6w_ctrl_req_vht_cap_set(req_data, vht_cap); + + if (he_cap) + ra6w_ctrl_req_he_cap_set(req_data, he_cap); + + req_data->ps_on = ra6w_params_ps_supported(); + req_data->dpsm = ra6w_params_dpsm_enabled(); + req_data->tx_lft = cpu_to_le16(RA6W_CMD_TX_LIFETIME_MS); + req_data->amsdu_tx = 0; + req_data->ant_div_on = ra6w_params_ant_div(); + req_data->phy_bw_max = ra6w_params_bw_max_get(); + + return 0; +} + +int ra6w_ctrl_me_config(struct ra6w_ctrl *ctrl, struct wiphy *wiphy) +{ + int ret; + u8 cmd = RA6W_CMD_ME_CONFIG; + struct ra6w_cmd_me_config_req *req = NULL; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + ret = ra6w_ctrl_cmd_me_config_set(&req->data, wiphy); + if (ret) + goto req_free; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + if (ret) + goto req_free; + + ra6w_info("HT supp %d, VHT supp %d, HE supp %d\n", + req->data.ht_supp, req->data.vht_supp, req->data.he_supp); + +req_free: + kfree(req); + + return ret; +} + +int ra6w_ctrl_chan_config(struct ra6w_ctrl *ctrl, struct wiphy *wiphy) +{ + int ret; + const struct ieee80211_supported_band *band = NULL; + int i = 0; + struct ra6w_cmd_me_chan_config_req *req = NULL; + u8 cmd = RA6W_CMD_ME_CHAN_CONFIG; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + if (wiphy->bands[NL80211_BAND_2GHZ]) { + band = wiphy->bands[NL80211_BAND_2GHZ]; + for (i = 0; i < band->n_channels; i++) { + const struct ieee80211_channel *channel = &band->channels[i]; + struct ra6w_cmd_prim_ch_def *ch_def = &req->data.chan24G[i]; + + ch_def->ch_flags |= cpu_to_le16(ra6w_ctrl_get_chan_flags(channel->flags)); + ch_def->ch_band = NL80211_BAND_2GHZ; + ch_def->ch_freq = cpu_to_le16(channel->center_freq); + ch_def->tx_max_pwr = min_t(int, channel->max_power, channel->max_reg_power); + req->data.chan24G_cnt++; + if (req->data.chan24G_cnt == RA6W_CMD_SCAN_CHANNEL_24G) + break; + } + } + + if (wiphy->bands[NL80211_BAND_5GHZ]) { + band = wiphy->bands[NL80211_BAND_5GHZ]; + for (i = 0; i < band->n_channels; i++) { + const struct ieee80211_channel *channel = &band->channels[i]; + struct ra6w_cmd_prim_ch_def *ch_def = &req->data.chan5G[i]; + + ch_def->ch_flags |= cpu_to_le16(ra6w_ctrl_get_chan_flags(channel->flags)); + ch_def->ch_band = NL80211_BAND_5GHZ; + ch_def->ch_freq = cpu_to_le16(channel->center_freq); + ch_def->tx_max_pwr = min_t(int, channel->max_power, channel->max_reg_power); + req->data.chan5G_cnt++; + if (req->data.chan5G_cnt == RA6W_CMD_SCAN_CHANNEL_5G) + break; + } + } + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_scan_start(struct ra6w_ctrl *ctrl, struct cfg80211_scan_request *param) +{ + int ret; + const struct ra6w_cfg80211_vif *vif = NULL; + struct ra6w_cmd_sc_start_req *req = NULL; + u16 req_len = 0; + __le16 chan_flags = 0; + u16 i; + u16 j; + u8 cmd = RA6W_CMD_SC_START; + + if (!param->wdev) + return -EINVAL; + + req_len = sizeof(req->data) + param->ie_len; + req = kzalloc(req_len, GFP_KERNEL); + if (!req) + return -ENOMEM; + + eth_broadcast_addr((u8 *)&req->data.bssid); + + vif = container_of(param->wdev, struct ra6w_cfg80211_vif, wdev); + req->data.vif_idx = vif->vif_idx; + req->data.n_channels = (u8)min_t(int, RA6W_CMD_SCAN_CHANNEL_MAX, param->n_channels); + req->data.n_ssids = (u8)min_t(int, RA6W_CMD_SCAN_SSID_MAX, param->n_ssids); + req->data.no_cck = param->no_cck; + if (param->duration_mandatory) + req->data.duration = cpu_to_le32(ieee80211_tu_to_usec(param->duration)); + + if (req->data.n_ssids == 0) + chan_flags |= cpu_to_le16(RA6W_CMD_CHAN_NO_IR_BIT); + + for (i = 0; i < req->data.n_ssids; i++) { + for (j = 0; j < param->ssids[i].ssid_len; j++) + req->data.ssid[i].ssid[j] = param->ssids[i].ssid[j]; + + req->data.ssid[i].ssid_len = param->ssids[i].ssid_len; + } + + if (param->ie && param->ie_len > 0) { + req->data.ie_len = cpu_to_le16(param->ie_len); + req->data.ie_addr = 0; + memcpy(req->data.ie, param->ie, param->ie_len); + } + + for (i = 0; i < req->data.n_channels; i++) { + const struct ieee80211_channel *channel = param->channels[i]; + struct ra6w_cmd_prim_ch_def *ch_def = &req->data.chan[i]; + + ch_def->ch_band = channel->band; + ch_def->ch_freq = cpu_to_le16(channel->center_freq); + ch_def->ch_flags = chan_flags | + cpu_to_le16(ra6w_ctrl_get_chan_flags(channel->flags)); + ch_def->tx_max_pwr = min_t(int, channel->max_power, channel->max_reg_power); + } + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, req_len); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_scan_cancel(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_vif *vif) +{ + int ret; + struct ra6w_cmd_sc_cancel_req *req = NULL; + u8 cmd = RA6W_CMD_SC_CANCEL_CMD; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.vif_idx = vif->vif_idx; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_connect(struct ra6w_ctrl *ctrl, const struct net_device *ndev, + struct cfg80211_connect_params *sme, + struct ra6w_cmd_sm_connect_rsp *rsp) +{ + int ret; + struct ra6w_cfg80211_vif *vif = NULL; + struct ra6w_cmd_sm_connect_req *req = NULL; + struct ra6w_cmd_sm_connect_data *req_data = NULL; + u8 cmd = RA6W_CMD_SM_CONNECT; + int i; + u32 req_len; + + if (!rsp) + return -ENOENT; + + vif = netdev_priv(ndev); + if (!vif) + return -ENOENT; + + req_len = sizeof(req->data) + sme->ie_len; + req = kzalloc(req_len, GFP_KERNEL); + if (!req) + return -ENOMEM; + + req_data = &req->data; + + if (sme->crypto.n_ciphers_pairwise && + (sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP40 || + sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_TKIP || + sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP104)) + req_data->flags |= cpu_to_le32(RA6W_CMD_CONN_DISABLE_HT_BIT); + + if (sme->crypto.cipher_group) + req_data->flags |= cpu_to_le32(RA6W_CMD_CONN_USE_PRIVACY_BIT); + + if (sme->crypto.control_port) + req_data->flags |= cpu_to_le32(RA6W_CMD_CONN_CONTROL_PORT_HOST_BIT); + + if (sme->crypto.control_port_no_encrypt) + req_data->flags |= cpu_to_le32(RA6W_CMD_CONN_CONTROL_PORT_NO_ENC_BIT); + + if (sme->crypto.cipher_group && + sme->crypto.cipher_group != WLAN_CIPHER_SUITE_WEP40 && + sme->crypto.cipher_group != WLAN_CIPHER_SUITE_WEP104) + req_data->flags |= cpu_to_le32(RA6W_CMD_CONN_USE_PAIRWISE_KEY_BIT); + + if (sme->mfp == NL80211_MFP_REQUIRED) + req_data->flags |= cpu_to_le32(RA6W_CMD_CONN_MFP_IN_USE_BIT); + + if (ra6w_params_amsdu_require_spp()) + req_data->flags |= cpu_to_le32(RA6W_CMD_CONN_REQUIRE_SPP_AMSDU_BIT); + + req_data->ctrl_port_ethertype = sme->crypto.control_port_ethertype; + + if (sme->bssid) + ether_addr_copy((u8 *)&req_data->bssid, sme->bssid); + else + eth_broadcast_addr((u8 *)&req_data->bssid); + + if (sme->prev_bssid) + req_data->flags |= cpu_to_le32(RA6W_CMD_CONN_REASSOCIATION_BIT); + + req_data->vif_idx = vif->vif_idx; + req_data->chan.ch_freq = cpu_to_le16(0xFFFF); + if (sme->channel) { + req_data->chan.ch_band = sme->channel->band; + req_data->chan.ch_freq = cpu_to_le16(sme->channel->center_freq); + req_data->chan.ch_flags = + cpu_to_le16(ra6w_ctrl_get_chan_flags(sme->channel->flags)); + } + + for (i = 0; i < sme->ssid_len; i++) + req_data->ssid.ssid[i] = sme->ssid[i]; + + req_data->ssid.ssid_len = sme->ssid_len; + req_data->listen_interval = 0; + req_data->dont_wait_bcmc = false; + + switch (sme->auth_type) { + case NL80211_AUTHTYPE_AUTOMATIC: + req_data->auth_type = WLAN_AUTH_OPEN; + break; + case NL80211_AUTHTYPE_OPEN_SYSTEM: + req_data->auth_type = WLAN_AUTH_OPEN; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + req_data->auth_type = WLAN_AUTH_SHARED_KEY; + break; + case NL80211_AUTHTYPE_FT: + ret = -EOPNOTSUPP; + goto req_free; + case NL80211_AUTHTYPE_SAE: + req_data->auth_type = WLAN_AUTH_SAE; + break; + default: + ret = -EINVAL; + goto req_free; + } + + memcpy(req_data->ie_buf, sme->ie, sme->ie_len); + req_data->ie_len = cpu_to_le16(sme->ie_len); + + req_data->uapsd_queues = IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, req_len, rsp, sizeof(*rsp)); + if (!ret) + ret = ra6w_status_err_code_to_errno(rsp->status); + +req_free: + kfree(req); + + return ret; +} + +int ra6w_ctrl_disconnect_req(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_vif *vif, + u16 reason) +{ + struct ra6w_cmd_disconnect_req *req = NULL; + u8 cmd = RA6W_CMD_SM_DISCONNECT; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.vif_idx = vif->vif_idx; + req->data.deauth_reason = cpu_to_le16(reason); + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_add_key_req(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_key *key, + const u8 *key_data, u32 key_len, u8 key_index, + struct ra6w_cmd_key_add_rsp *rsp) +{ + int ret; + struct ra6w_cmd_key_add_req *req = NULL; + struct ra6w_cmd_key_add_data *req_data = NULL; + u8 cmd = RA6W_CMD_MM_ADD_KEY; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req_data = &req->data; + req_data->sta_id = key->sta_idx; + req_data->key_idx = key_index; + req_data->pairwise = key->pairwise; + req_data->vif_idx = key->vif_idx; + req_data->key.length = key_len; + req_data->cipher_suite = key->cipher_type; + + memcpy(req_data->key.array, key_data, key_len); + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(req->data), rsp, sizeof(*rsp)); + if (!ret) + ret = ra6w_status_err_code_to_errno(rsp->status); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_del_key_req(struct ra6w_ctrl *ctrl, u8 key_index) +{ + struct ra6w_cmd_key_del_req *req = NULL; + u8 cmd = RA6W_CMD_MM_DEL_KEY; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.key_index = key_index; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_add_station_req(struct ra6w_ctrl *ctrl, struct station_parameters *params, + const u8 *mac, u8 vif_idx, struct ra6w_cmd_sta_add_rsp *rsp) +{ + struct ra6w_cmd_sta_add_req *req = NULL; + struct ra6w_cmd_sta_add_data *req_data = NULL; + const struct link_station_parameters *link = NULL; + u8 cmd = RA6W_CMD_ME_ADD_STA; + int ret; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req_data = &req->data; + ether_addr_copy((u8 *)&req_data->mac_addr.addr[0], mac); + + link = ¶ms->link_sta_params; + req_data->rate_set.length = min_t(u8, sizeof(req_data->rate_set.array), + link->supported_rates_len); + + memcpy(req_data->rate_set.array, link->supported_rates, req_data->rate_set.length); + + if (params->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + req_data->flags |= cpu_to_le32(RA6W_CMD_STA_CAP_SHORT_PREAMBLE_BIT); + + if (link->ht_capa) { + const struct ieee80211_ht_cap *ht_cap = link->ht_capa; + + req_data->flags |= cpu_to_le32(RA6W_CMD_STA_CAP_HT_BIT); + req_data->ht_cap.ht_capa_info = ht_cap->cap_info; + req_data->ht_cap.a_mpdu_param = ht_cap->ampdu_params_info; + memcpy(req_data->ht_cap.mcs_rate, &ht_cap->mcs, sizeof(req_data->ht_cap.mcs_rate)); + req_data->ht_cap.ht_extended_capa = ht_cap->extended_ht_cap_info; + req_data->ht_cap.tx_beamforming_capa = ht_cap->tx_BF_cap_info; + req_data->ht_cap.asel_capa = ht_cap->antenna_selection_info; + } + + if (link->vht_capa) { + const struct ieee80211_vht_cap *vht_cap = link->vht_capa; + + req_data->flags |= cpu_to_le32(RA6W_CMD_STA_CAP_VHT_BIT); + req_data->vht_cap.vht_capa_info = vht_cap->vht_cap_info; + req_data->vht_cap.rx_highest = vht_cap->supp_mcs.rx_highest; + req_data->vht_cap.rx_mcs_map = vht_cap->supp_mcs.rx_mcs_map; + req_data->vht_cap.tx_highest = vht_cap->supp_mcs.tx_highest; + req_data->vht_cap.tx_mcs_map = vht_cap->supp_mcs.tx_mcs_map; + } + + if (link->he_capa) { + const struct ieee80211_he_cap_elem *he_cap = link->he_capa; + + req_data->flags |= cpu_to_le32(RA6W_CMD_STA_CAP_HE_BIT); + memcpy(req_data->he_cap.mac_cap_info, he_cap->mac_cap_info, + sizeof(he_cap->mac_cap_info)); + memcpy(req_data->he_cap.phy_cap_info, he_cap->phy_cap_info, + sizeof(he_cap->phy_cap_info)); + } + + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME)) + req_data->flags |= cpu_to_le32(RA6W_CMD_STA_CAP_QOS_BIT); + + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_MFP)) + req_data->flags |= cpu_to_le32(RA6W_CMD_STA_CAP_MFP_BIT); + + if (link->opmode_notif_used) { + req_data->flags |= cpu_to_le32(RA6W_CMD_STA_OP_NOT_IE_BIT); + req_data->opmode_notif = link->opmode_notif; + } + + req_data->aid = cpu_to_le16(params->aid); + req_data->uapsd_queues = params->uapsd_queues; + req_data->max_sp_len = params->max_sp * 2; + req_data->vif_idx = vif_idx; + + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + const struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + const struct ra6w_cfg80211_priv *priv = core->priv; + const struct ra6w_cfg80211_vif *vif = priv->vif_table[vif_idx]; + + req_data->tdls_sta = true; + if ((params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) && + !vif->tdls_chsw_prohibited) + req_data->tdls_chsw_allowed = true; + if (vif->tdls_status == RA6W_CMD_TDLS_STATE_TX_RSP) + req_data->tdls_sta_initiator = true; + } + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(req->data), rsp, sizeof(*rsp)); + if (!ret) + ret = ra6w_status_err_code_to_errno(rsp->status); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_del_station_req(struct ra6w_ctrl *ctrl, u8 sta_idx, bool is_tdls_sta) +{ + struct ra6w_cmd_sta_del_req *req = NULL; + u8 cmd = RA6W_CMD_ME_DEL_STA; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.sta_idx = sta_idx; + req->data.is_tdls_sta = is_tdls_sta; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_port_control_req(struct ra6w_ctrl *ctrl, bool authorized, u8 sta_idx) +{ + struct ra6w_cmd_port_control_req *req = NULL; + u8 cmd = RA6W_CMD_ME_SET_CONTROL_PORT; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.port_control_state = authorized; + req->data.sta_idx = sta_idx; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +static void ra6w_ctrl_channel_set(struct ra6w_cmd_oper_ch_info *chan, + const struct cfg80211_chan_def *chandef) +{ + const struct ieee80211_channel *channel = chandef->chan; + + chan->ch_band = channel->band; + chan->ch_bw = bw2chnl[chandef->width]; + chan->freq_prim20 = cpu_to_le16(channel->center_freq); + chan->freq_cen1 = cpu_to_le16(chandef->center_freq1); + chan->freq_cen2 = cpu_to_le16(chandef->center_freq2); + chan->ch_flags = cpu_to_le16(ra6w_ctrl_get_chan_flags(channel->flags)); + chan->tx_max_pwr = min_t(int, channel->max_power, channel->max_reg_power); +} + +int ra6w_ctrl_remain_on_channel_req(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_vif *vif, + struct ieee80211_channel *chan, int duration) +{ + struct ra6w_cmd_roc_req *req = NULL; + struct ra6w_cmd_roc_data *req_data = NULL; + struct cfg80211_chan_def chandef; + u8 cmd = RA6W_CMD_MM_REMAIN_ON_CHANNEL; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); + + req_data = &req->data; + req_data->op_code = RA6W_CMD_ROC_OP_CODE_START; + req_data->vif_idx = vif->vif_idx; + req_data->duration_ms = cpu_to_le32(duration); + ra6w_ctrl_channel_set(&req_data->chan, &chandef); + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_cancel_remain_on_channel_req(struct ra6w_ctrl *ctrl) +{ + struct ra6w_cmd_roc_req *req = NULL; + u8 cmd = RA6W_CMD_MM_REMAIN_ON_CHANNEL; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.op_code = RA6W_CMD_ROC_OP_CODE_STOP; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_ap_start_req(struct ra6w_ctrl *ctrl, struct ra6w_cfg80211_vif *vif, + struct cfg80211_ap_settings *settings, + struct ra6w_cmd_ap_start_rsp *rsp) +{ + int ret = -ENOENT; + struct ra6w_cmd_ap_start_req *req = NULL; + struct ra6w_cmd_ap_start_data *req_data = NULL; + struct ra6w_cfg80211_beacon_info *beacon_info = NULL; + int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + u8 cmd = RA6W_CMD_AM_START; + int len = 0; + int i; + const u8 *var_pos = NULL; + u8 *beacon_buf = NULL; + const u8 *rate_ie = NULL; + u8 rate_len = 0; + u32 flags = 0; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + beacon_info = &vif->ap.bcn; + beacon_info->dtim_period = settings->dtim_period; + beacon_buf = ra6w_cfg80211_create_beacon(beacon_info, &settings->beacon); + if (!beacon_buf) { + ret = -ENOMEM; + goto req_free; + } + + req_data = &req->data; + + len = beacon_info->len - var_offset; + var_pos = beacon_buf + var_offset; + + rate_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len); + if (rate_ie) { + const u8 *rates = rate_ie + 2; + + for (i = 0; (i < rate_ie[1]) && (rate_len < RA6W_CMD_MAC_RATESET_LEN); i++) { + if (RA6W_IS_BASIC_RATE(rates[i])) + req_data->basic_rates.array[rate_len++] = rates[i]; + } + } + + rate_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, var_pos, len); + if (rate_ie) { + const u8 *rates = rate_ie + 2; + + for (i = 0; (i < rate_ie[1]) && (rate_len < RA6W_CMD_MAC_RATESET_LEN); i++) { + if (RA6W_IS_BASIC_RATE(rates[i])) + req_data->basic_rates.array[rate_len++] = rates[i]; + } + } + + req_data->basic_rates.length = rate_len; + req_data->vif_idx = vif->vif_idx; + memcpy(req_data->beacon, beacon_buf, beacon_info->len); + req_data->bcn_len = cpu_to_le16(beacon_info->len); + req_data->tim_oft = cpu_to_le16(beacon_info->head_len); + req_data->tim_len = beacon_info->tim_len; + ra6w_ctrl_channel_set(&req_data->chan, &settings->chandef); + req_data->bcn_int = cpu_to_le16(settings->beacon_interval); + + if (settings->crypto.cipher_group) { + flags |= RA6W_CMD_CONN_USE_PRIVACY_BIT; + + if (settings->crypto.cipher_group != WLAN_CIPHER_SUITE_WEP40 && + settings->crypto.cipher_group != WLAN_CIPHER_SUITE_WEP104) + flags |= RA6W_CMD_CONN_USE_PAIRWISE_KEY_BIT; + } + + if (settings->crypto.control_port) + flags |= RA6W_CMD_CONN_CONTROL_PORT_HOST_BIT; + + if (settings->crypto.control_port_no_encrypt) + flags |= RA6W_CMD_CONN_CONTROL_PORT_NO_ENC_BIT; + + req_data->flags = cpu_to_le32(flags); + + req_data->ctrl_port_ethertype = cpu_to_be16(ETH_P_PAE); + if (settings->crypto.control_port_ethertype) + req_data->ctrl_port_ethertype = settings->crypto.control_port_ethertype; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(req->data), rsp, sizeof(*rsp)); + if (!ret) + ret = ra6w_status_err_code_to_errno(rsp->status); + + kfree(beacon_buf); + +req_free: + kfree(req); + + return ret; +} + +int ra6w_ctrl_ap_stop_req(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_vif *vif) +{ + struct ra6w_cmd_ap_stop_req *req = NULL; + u8 cmd = RA6W_CMD_AM_STOP; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.vif_idx = vif->vif_idx; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_change_beacon_req(struct ra6w_ctrl *ctrl, u8 vif_idx, const u8 *bcn, + u16 bcn_len, u16 tim_oft, u16 tim_len, const u16 *csa_oft) +{ + struct ra6w_cmd_change_bcn_req *req = NULL; + struct ra6w_cmd_change_bcn_data *req_data = NULL; + u8 cmd = RA6W_CMD_AM_BCN_CHANGE; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req_data = &req->data; + req_data->bcn_len = cpu_to_le16(bcn_len); + req_data->tim_oft = cpu_to_le16(tim_oft); + req_data->tim_len = tim_len; + req_data->vif_id = vif_idx; + memcpy(req_data->bcn_ptr, bcn, bcn_len); + + if (csa_oft) { + int i; + + for (i = 0; i < RA6W_CMD_BCN_MAX_CSA_CPT; i++) + req_data->csa_oft[i] = (u8)csa_oft[i]; + } + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_monitor_mode_req(struct ra6w_ctrl *ctrl, const struct cfg80211_chan_def *chandef, + struct ra6w_cmd_mon_mode_rsp *rsp) +{ + int ret; + struct ra6w_cmd_mon_mode_req *req = NULL; + struct ra6w_cmd_mon_mode_data *req_data = NULL; + u8 cmd = RA6W_CMD_ME_SET_MON_CFG; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req_data = &req->data; + + if (chandef) { + req_data->ch_valid = true; + ra6w_ctrl_channel_set(&req_data->chan, chandef); + } + + req_data->uf_enable = true; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(req->data), rsp, sizeof(*rsp)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_probe_client_req(struct ra6w_ctrl *ctrl, u8 vif_idx, u8 sta_idx, + struct ra6w_cmd_probe_client_rsp *rsp) +{ + int ret; + struct ra6w_cmd_probe_client_req *req = NULL; + u8 cmd = RA6W_CMD_AM_PROBE_CLIENT; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.vif_idx = vif_idx; + req->data.sta_idx = sta_idx; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(req->data), rsp, sizeof(*rsp)); + if (!ret) + ret = ra6w_status_err_code_to_errno(rsp->status); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_set_ap_isolate_req(struct ra6w_ctrl *ctrl, u8 ap_isolate, + struct ra6w_cmd_ap_isolate_rsp *rsp) +{ + int ret; + struct ra6w_cmd_ap_isolate_req *req = NULL; + u8 cmd = RA6W_CMD_AM_ISOLATE; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.ap_isolate = ap_isolate; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(req->data), rsp, sizeof(*rsp)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_edca_req(struct ra6w_ctrl *ctrl, u8 ac, u32 param, bool uapsd, u8 vif_idx) +{ + struct ra6w_cmd_edca_req *req = NULL; + struct ra6w_cmd_edca_data *req_data = NULL; + u8 cmd = RA6W_CMD_MM_SET_EDCA; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req_data = &req->data; + req_data->ac = ac; + req_data->edca_param = cpu_to_le32(param); + req_data->uapsd_enabled = uapsd; + req_data->vif_idx = vif_idx; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_set_tx_power_req(struct ra6w_ctrl *ctrl, u8 vif_idx, s8 tx_power) +{ + struct ra6w_cmd_set_tx_power_req *req = NULL; + u8 cmd = RA6W_CMD_MM_SET_POWER; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.vif_idx = vif_idx; + req->data.tx_power = tx_power; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_set_power_mgmt_req(struct ra6w_ctrl *ctrl, u8 ps_mode) +{ + struct ra6w_cmd_set_power_mgmt_req *req = NULL; + u8 cmd = RA6W_CMD_ME_SET_PS_MODE; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.ps_mode = ps_mode; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_cqm_rssi_config_req(struct ra6w_ctrl *ctrl, u8 vif_idx, + s32 rssi_thold, u32 rssi_hyst) +{ + struct ra6w_cmd_cqm_rssi_config_req *req = NULL; + u8 cmd = RA6W_CMD_MM_GET_RSSI; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.vif_idx = vif_idx; + req->data.rssi_thold = rssi_thold; + req->data.rssi_hyst = rssi_hyst; + + ret = ra6w_ctrl_set(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_sm_ext_auth_req_rsp(struct ra6w_ctrl *ctrl, u8 vif_idx, u16 status) +{ + struct ra6w_cmd_sm_ext_auth_req_rsp_req *req = NULL; + u8 cmd = RA6W_CMD_SM_EXTERNAL_AUTH_REQUIRED_RSP; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.vif_idx = vif_idx; + req->data.status = cpu_to_le16(status); + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_mem_read_req(struct ra6w_ctrl *ctrl, u32 addr, + struct ra6w_cmd_mem_read_rsp *rsp) +{ + struct ra6w_cmd_dbg_mem_read_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_MEM_READ; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.mem_addr = cpu_to_le32(addr); + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(req->data), rsp, sizeof(*rsp)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_mem_write_req(struct ra6w_ctrl *ctrl, u32 addr, u32 value) +{ + struct ra6w_cmd_dbg_mem_write_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_MEM_WRITE; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.mem_addr = cpu_to_le32(addr); + req->data.mem_value = cpu_to_le32(value); + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_dbg_mode_filter_req(struct ra6w_ctrl *ctrl, u32 mode) +{ + struct ra6w_cmd_dbg_mode_filter_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_SET_MOD_FILTER; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.mode_filter = cpu_to_le32(mode); + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_dbg_level_filter_req(struct ra6w_ctrl *ctrl, u32 level) +{ + struct ra6w_cmd_dbg_level_filter_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_SET_SEV_FILTER; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.level_filter = cpu_to_le32(level); + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_rf_tx_req(struct ra6w_ctrl *ctrl, struct ra6w_cmd_rf_tx_data *data) +{ + struct ra6w_cmd_rf_tx_req *req = NULL; + struct ra6w_cmd_rf_tx_data *req_data = NULL; + u8 cmd = RA6W_CMD_DBG_RF_TX; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req_data = &req->data; + req_data->start = data->start; + req_data->frequency = data->frequency; + req_data->num_frames = data->num_frames; + req_data->frame_len = data->frame_len; + req_data->tx_rate = data->tx_rate; + req_data->tx_power = data->tx_power; + req_data->dest_addr = data->dest_addr; + req_data->bssid = data->bssid; + req_data->gi = data->gi; + req_data->green_field = data->green_field; + req_data->preamble_type = data->preamble_type; + req_data->qos_enable = data->qos_enable; + req_data->ack_policy = data->ack_policy; + req_data->aifsn_val = data->aifsn_val; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(req->data)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_rf_cw_req(struct ra6w_ctrl *ctrl, const struct ra6w_cmd_rf_cw_data *data) +{ + struct ra6w_cmd_rf_cw_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_RF_CW; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.start = data->start; + req->data.frequency = data->frequency; + req->data.tx_power = data->tx_power; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(*req)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_rf_cont_req(struct ra6w_ctrl *ctrl, const struct ra6w_cmd_rf_cont_data *data) +{ + struct ra6w_cmd_rf_cont_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_RF_CONT; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.start = data->start; + req->data.frequency = data->frequency; + req->data.tx_power = data->tx_power; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(*req)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_rf_ch_req(struct ra6w_ctrl *ctrl, u16 frequency) +{ + struct ra6w_cmd_rf_ch_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_RF_CH; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.frequency = cpu_to_le16(frequency); + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(*req)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_rf_per_req(struct ra6w_ctrl *ctrl, u8 start, struct ra6w_cmd_rf_per_rsp *rsp) +{ + int ret; + struct ra6w_cmd_rf_per_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_RF_PER; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.start = start; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(*req), rsp, sizeof(*rsp)); + + kfree(req); + + return ret; +} + +int ra6w_ctrl_stats_tx_req(struct ra6w_ctrl *ctrl, u8 req_type, struct ra6w_cmd_stats_tx_rsp *rsp) +{ + int ret; + struct ra6w_cmd_stats_tx_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_STATS_TX; + + if (!rsp) + return -ENOENT; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.req_type = req_type; + + ret = ra6w_ctrl_set_and_wait_rsp(ctrl, cmd, req, sizeof(*req), rsp, sizeof(*rsp)); + if (!ret && rsp->status != RA6W_STATS_STATUS_ENABLED) + ret = -EPERM; + + kfree(req); + + return ret; +} + +int ra6w_ctrl_stats_tx_start_req(struct ra6w_ctrl *ctrl, u8 req_type) +{ + int ret; + struct ra6w_cmd_stats_tx_req *req = NULL; + u8 cmd = RA6W_CMD_DBG_STATS_TX; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->data.req_type = req_type; + + ret = ra6w_ctrl_set_and_wait(ctrl, cmd, req, sizeof(*req)); + + kfree(req); + + return ret; +} + +void ra6w_ctrl_init(struct ra6w_ctrl *ctrl) +{ + atomic_set(&ctrl->event.condition, RA6W_CTRL_EVENT_RESET); + init_waitqueue_head(&ctrl->event.wait_queue); +} From patchwork Thu Apr 17 13:52:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882271 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5A34024EAA4 for ; Thu, 17 Apr 2025 13:53:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898012; cv=none; b=AVHeLq6s5gmDjc5Ru8E4D9Gu2+3U7lwMbVVDnG1wOjkcDJjtLv8dQb3MflugxsEt1iIbA34n1JWSTy6+3BL4rkU+PLQ7/eRUbwaBCci8YNURounly4rLlVMmClrN6ZbnGKCq0Yfp3wnXSZmGIS06auaOwTyPcJs9V+5zymKVynw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898012; c=relaxed/simple; bh=U8E1qiaNsTXurFNMRo6kztTdOlLLEvAcaFMg0dAzIs0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=gJQOB3VrEnc2Oe8KiGXoVQt1aj8i3hK+9wNfRLkVsSlhf100mea9BudOkhLAuleD81nzZJToDknzc8smrvFw+x05dHr0Al8YWii74KqY6Xrgw4bx0FZI5jxcgMTBKh2Q1BbMxdEP3YQmJRWHZceAyZ4xOrcnbTAn+4eQ7BopAZw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: y8DCk4F4SNSPQ4drtqwDrw== X-CSE-MsgGUID: bJV5BIm0SiyeK8usPmo6sg== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:29 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 0556E4006DE8; Thu, 17 Apr 2025 22:53:25 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 10/38] ra6w: add ctrl.h Date: Thu, 17 Apr 2025 16:52:08 +0300 Message-Id: <20250417135236.52410-11-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/ctrl.h | 100 +++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/ctrl.h diff --git a/drivers/net/wireless/renesas/ra6w/ctrl.h b/drivers/net/wireless/renesas/ra6w/ctrl.h new file mode 100644 index 000000000000..7d98251d81ae --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/ctrl.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_CTRL_H +#define RA6W_CTRL_H + +#include + +#define RA6W_CTRL_DATA_LEN 980 +#define RA6W_CTRL_RSP_EXT_LEN (sizeof(struct ra6w_ctrl_rsp_ext_hdr)) +#define RA6W_CTRL_EVENT_RESET 0 + +struct ra6w_ctrl_rsp_ext_hdr { + u32 status : 32; +}; + +struct ra6w_ctrl_rsp { + u8 cmd; + u8 ext_len; + __le16 data_len; + struct ra6w_ctrl_rsp_ext_hdr ext_hdr; + u8 data[RA6W_CTRL_DATA_LEN]; +}; + +struct ra6w_ctrl { + struct ra6w_q_event event; + u8 cmd; + void *rsp; + u16 rsp_len; +}; + +extern const int chnl2bw[]; + +struct ra6w_cfg80211_vif; +struct ra6w_cfg80211_key; + +void ra6w_ctrl_init(struct ra6w_ctrl *ctrl); +void ra6w_ctrl_event_post(struct ra6w_ctrl *ctrl, const struct sk_buff *skb); +int ra6w_ctrl_dev_hw_reset(struct ra6w_ctrl *ctrl); +int ra6w_ctrl_dev_reset(struct ra6w_ctrl *ctrl); +int ra6w_ctrl_dev_start(struct ra6w_ctrl *ctrl, const struct ra6w_cmd_phy_cfg *phy_config); +int ra6w_ctrl_otp_mac_addr_get(struct ra6w_ctrl *ctrl, u8 *mac); +int ra6w_ctrl_if_add(struct ra6w_ctrl *ctrl, const u8 *mac, u8 iftype, bool p2p, + struct ra6w_cmd_add_if_rsp *rsp); +int ra6w_ctrl_if_remove(struct ra6w_ctrl *ctrl, u8 vif_idx); +int ra6w_ctrl_me_config(struct ra6w_ctrl *ctrl, struct wiphy *wiphy); +int ra6w_ctrl_chan_config(struct ra6w_ctrl *ctrl, struct wiphy *wiphy); +int ra6w_ctrl_scan_start(struct ra6w_ctrl *ctrl, struct cfg80211_scan_request *param); +int ra6w_ctrl_scan_cancel(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_vif *vif); +int ra6w_ctrl_connect(struct ra6w_ctrl *ctrl, const struct net_device *ndev, + struct cfg80211_connect_params *sme, + struct ra6w_cmd_sm_connect_rsp *rsp); +int ra6w_ctrl_disconnect_req(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_vif *vif, + u16 reason); +int ra6w_ctrl_add_key_req(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_key *key, + const u8 *key_data, u32 key_len, u8 key_index, + struct ra6w_cmd_key_add_rsp *rsp); +int ra6w_ctrl_del_key_req(struct ra6w_ctrl *ctrl, u8 key_index); +int ra6w_ctrl_add_station_req(struct ra6w_ctrl *ctrl, struct station_parameters *params, + const u8 *mac, u8 vif_idx, struct ra6w_cmd_sta_add_rsp *rsp); +int ra6w_ctrl_del_station_req(struct ra6w_ctrl *ctrl, u8 sta_idx, bool is_tdls_sta); +int ra6w_ctrl_port_control_req(struct ra6w_ctrl *ctrl, bool authorized, u8 sta_idx); +int ra6w_ctrl_remain_on_channel_req(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_vif *vif, + struct ieee80211_channel *chan, int duration); +int ra6w_ctrl_cancel_remain_on_channel_req(struct ra6w_ctrl *ctrl); +int ra6w_ctrl_ap_start_req(struct ra6w_ctrl *ctrl, struct ra6w_cfg80211_vif *vif, + struct cfg80211_ap_settings *settings, + struct ra6w_cmd_ap_start_rsp *rsp); +int ra6w_ctrl_ap_stop_req(struct ra6w_ctrl *ctrl, const struct ra6w_cfg80211_vif *vif); +int ra6w_ctrl_change_beacon_req(struct ra6w_ctrl *ctrl, u8 vif_idx, const u8 *bcn, u16 bcn_len, + u16 tim_oft, u16 tim_len, const u16 *csa_oft); +int ra6w_ctrl_monitor_mode_req(struct ra6w_ctrl *ctrl, const struct cfg80211_chan_def *chandef, + struct ra6w_cmd_mon_mode_rsp *rsp); +int ra6w_ctrl_probe_client_req(struct ra6w_ctrl *ctrl, u8 vif_idx, u8 sta_idx, + struct ra6w_cmd_probe_client_rsp *rsp); +int ra6w_ctrl_set_ap_isolate_req(struct ra6w_ctrl *ctrl, u8 ap_isolate, + struct ra6w_cmd_ap_isolate_rsp *rsp); +int ra6w_ctrl_edca_req(struct ra6w_ctrl *ctrl, u8 ac, u32 param, bool uapsd, u8 vif_idx); +int ra6w_ctrl_set_tx_power_req(struct ra6w_ctrl *ctrl, u8 vif_idx, s8 tx_power); +int ra6w_ctrl_set_power_mgmt_req(struct ra6w_ctrl *ctrl, u8 ps_mode); +int ra6w_ctrl_cqm_rssi_config_req(struct ra6w_ctrl *ctrl, u8 vif_idx, + s32 rssi_thold, u32 rssi_hyst); +int ra6w_ctrl_mem_read_req(struct ra6w_ctrl *ctrl, u32 addr, + struct ra6w_cmd_mem_read_rsp *rsp); +int ra6w_ctrl_mem_write_req(struct ra6w_ctrl *ctrl, u32 addr, u32 value); +int ra6w_ctrl_dbg_mode_filter_req(struct ra6w_ctrl *ctrl, u32 mode); +int ra6w_ctrl_dbg_level_filter_req(struct ra6w_ctrl *ctrl, u32 level); +int ra6w_ctrl_rf_tx_req(struct ra6w_ctrl *ctrl, struct ra6w_cmd_rf_tx_data *data); +int ra6w_ctrl_rf_cw_req(struct ra6w_ctrl *ctrl, const struct ra6w_cmd_rf_cw_data *data); +int ra6w_ctrl_rf_cont_req(struct ra6w_ctrl *ctrl, const struct ra6w_cmd_rf_cont_data *data); +int ra6w_ctrl_rf_ch_req(struct ra6w_ctrl *ctrl, u16 frequency); +int ra6w_ctrl_rf_per_req(struct ra6w_ctrl *ctrl, u8 start, struct ra6w_cmd_rf_per_rsp *rsp); +int ra6w_ctrl_sm_ext_auth_req_rsp(struct ra6w_ctrl *ctrl, u8 vif_idx, u16 status); +int ra6w_ctrl_update_fw_ver(struct ra6w_ctrl *ctrl); +int ra6w_ctrl_stats_tx_req(struct ra6w_ctrl *ctrl, u8 req_type, struct ra6w_cmd_stats_tx_rsp *rsp); +int ra6w_ctrl_stats_tx_start_req(struct ra6w_ctrl *ctrl, u8 req_type); + +#endif /* RA6W_CTRL_H */ From patchwork Thu Apr 17 13:52:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882856 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id B27E524EAB2 for ; Thu, 17 Apr 2025 13:53:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898015; cv=none; b=F1Gnq1o2O5FOaQUEFvC57xPKUKsUkIrMQ+m0hEdgyLigXDx0FGkH4vEh/NHlirenSbqAvfy0+QLJBsWBhzD+G6qxSnWk1TacSsav+JcxnW5I+exMmCf5pygPadW00tlH73B2A+hnkn8upYcOgc79t7xzEL1jWYFJmY/DRd2Uwv0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898015; c=relaxed/simple; bh=Hhqbf6WuIpUwwc9U0dK/HrZDmRqQNDISvk4adE+ma+8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=dNH8BpGRiZZk5dy2gZT9II9TG4Txbm4X4FkXOsSGpbPQRmOFd4WxcZl2TbYqiZEmp4UDnw82d2eNXF8YpP3WmdQvigfgRa+mJjGtkalO4rRp9gKJjxpoHFKJ3uHie9vULSa5mNxBefFvHdzJlnrL1WwiWkH8+0vP2fo/xIZHeZw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: oSW8//BFSCuL00gYsDfu6A== X-CSE-MsgGUID: hq/bHy+rQbuTY11BwnsuAA== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:33 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 275384006DE8; Thu, 17 Apr 2025 22:53:29 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 11/38] ra6w: add dbg.h Date: Thu, 17 Apr 2025 16:52:09 +0300 Message-Id: <20250417135236.52410-12-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/dbg.h | 47 +++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/dbg.h diff --git a/drivers/net/wireless/renesas/ra6w/dbg.h b/drivers/net/wireless/renesas/ra6w/dbg.h new file mode 100644 index 000000000000..2609f4d4003d --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/dbg.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_DBG_H +#define RA6W_DBG_H + +#include +#include + +enum ra6w_dbg_level { + RA6W_DBG_LVL_OFF, + RA6W_DBG_LVL_ERROR, + RA6W_DBG_LVL_WARN, + RA6W_DBG_LVL_INFO, + RA6W_DBG_LVL_DEBUG, + RA6W_DBG_LVL_TRACE, + RA6W_DBG_LVL_VERBOSE, + + RA6W_DBG_LVL_MAX, + RA6W_DBG_LVL_LAST = RA6W_DBG_LVL_MAX - 1 +}; + +#define RA6W_DEFAULT_LOG_LVL RA6W_DBG_LVL_INFO + +#define RA6W_PRINT(level, type, fmt, arg...) \ +do { \ + if ((level) <= ra6w_params_log_level()) \ + pr_##type("%s" fmt, THIS_MODULE->name, ##arg); \ +} while (0) + +#define ra6w_err(fmt, arg...) RA6W_PRINT(RA6W_DBG_LVL_ERROR, err, " E: " fmt, ##arg) +#define ra6w_warn(fmt, arg...) RA6W_PRINT(RA6W_DBG_LVL_WARN, warn, " W: " fmt, ##arg) +#define ra6w_info(fmt, arg...) RA6W_PRINT(RA6W_DBG_LVL_INFO, info, " I: " fmt, ##arg) +#define ra6w_trace(fmt, arg...) RA6W_PRINT(RA6W_DBG_LVL_TRACE, debug, " T: " fmt, ##arg) +#define ra6w_dbg(fmt, arg...) RA6W_PRINT(RA6W_DBG_LVL_DEBUG, debug, " D: " fmt, ##arg) + +#define RA6W_SET_DBG_LEVEL(level) \ +do { \ + if ((level) >= RA6W_DBG_LVL_OFF && level <= RA6W_DBG_LVL_LAST) \ + ra6w_params_log_level_set(level); \ +} while (0) + +#define RA6W_MAC_ADDR_STR_LEN sizeof("xx:xx:xx:xx:xx:xx") + +#endif /* RA6W_DBG_H */ From patchwork Thu Apr 17 13:52:10 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882270 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D31D224EA9C for ; Thu, 17 Apr 2025 13:53:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898020; cv=none; b=KS8MLTzOcntCoKULohH10Ig3uWpkeEfwqKZHYTNs8aBiKVvNScUjCwtsXLWYONjzr+DvN1HrhTPABRTApL7+JxTWFBLN6NNz46mJpOMyo/Dqfdk3x2eBzL+fmhZT6pgF1QXs5gcDfvhXuIHMJgvVdPfHmhcP09FCLnv36Z+OuCk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898020; c=relaxed/simple; bh=seVdcN2f9FLehHM8iyNX8zksgZhOD1X2/Bgj52pP+ao=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=t5kCS4XcbGg7svG+9D7rJo1Ml261CyjHi47lAOvR9k/09PdPy7t14tMAQSffwp9g50MEkkCj1vShu3s+9Dpj9OUApeBrK2GMPmbqLP9DY0i/W+YxmfqKa8wFIfg/zaMBjMTixfSEQSqESuqEDpDrwcSy2Xn8a5whLyIRgxp0wXg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: CE6Z+OnnRYioRbDWXPLDzQ== X-CSE-MsgGUID: x46zBHQWTdewixjEtYfEWw== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:37 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 496684006DE8; Thu, 17 Apr 2025 22:53:33 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 12/38] ra6w: add dbgfs.c Date: Thu, 17 Apr 2025 16:52:10 +0300 Message-Id: <20250417135236.52410-13-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/dbgfs.c | 201 ++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/dbgfs.c diff --git a/drivers/net/wireless/renesas/ra6w/dbgfs.c b/drivers/net/wireless/renesas/ra6w/dbgfs.c new file mode 100644 index 000000000000..9c764feebe6d --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/dbgfs.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains debugfs handlers. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include +#include +#include + +#include "core.h" +#include "cfg80211.h" +#include "params.h" +#include "dbg.h" +#include "dbgfs.h" + +static ssize_t ra6w_dbgfs_stats_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + const struct ra6w_cfg80211_priv *priv = file->private_data; + const struct ra6w_core_stat *tx = &priv->core->stats.tx; + const struct ra6w_core_stat *rx = &priv->core->stats.rx; + char *buf; + size_t n = 0; + size_t len = 256; + ssize_t ret = 0; + + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + n += scnprintf(&buf[n], len - n, "tx packets: %u\n", tx->packets); + n += scnprintf(&buf[n], len - n, "tx errors : %u\n", tx->err); + n += scnprintf(&buf[n], len - n, "rx packets: %u\n", rx->packets); + n += scnprintf(&buf[n], len - n, "rx errors : %u\n", rx->err); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, n); + + kfree(buf); + + return ret; +} + +static const struct file_operations ra6w_dbgfs_stats_ops = { + .read = ra6w_dbgfs_stats_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static ssize_t ra6w_dbgfs_dev_info_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ +#define FSCNPRINTF(n, len, buf, NBIT, str) \ +do { \ + bool set = test_bit(NBIT, &features); \ + (n) += scnprintf(&(buf)[n], (len) - (n), "%s : %d\n", str, set); \ +} while (0) + + struct ra6w_cfg80211_priv *priv = file->private_data; + struct ra6w_core *core = priv->core; + const struct ra6w_cmd_fw_ver_rsp *fw_ver = &core->sinfo.fw_ver; + unsigned long features; + char *buf; + size_t n = 0; + size_t len = count; + ssize_t ret = 0; + + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + n += scnprintf(&buf[n], len - n, "fw_version : %s\n", core->sinfo.fw_version); + n += scnprintf(&buf[n], len - n, "machw_features : 0x%X\n", + le32_to_cpu(fw_ver->machw_features)); + n += scnprintf(&buf[n], len - n, "machw_version : 0x%X\n", + le32_to_cpu(fw_ver->machw_version)); + n += scnprintf(&buf[n], len - n, "phy_feature : 0x%X\n", + le32_to_cpu(fw_ver->phy_feature)); + n += scnprintf(&buf[n], len - n, "phy_version : 0x%X\n", + le32_to_cpu(fw_ver->phy_version)); + n += scnprintf(&buf[n], len - n, "dev features : 0x%X:\n", fw_ver->features); + + features = (unsigned long)le32_to_cpu(fw_ver->features); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_BCN_BIT, " BCN "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_RADAR_BIT, " RADAR "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_PS_BIT, " PS "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_UAPSD_BIT, " UAPSD "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_AMPDU_BIT, " AMPDU "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_AMSDU_BIT, " AMSDU "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_P2P_BIT, " P2P "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_P2P_GO_BIT, " P2P_GO "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_UMAC_BIT, " UMAC "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_VHT_BIT, " VHT "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_BFMEE_BIT, " BFMEE "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_BFMER_BIT, " BFMER "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_WAPI_BIT, " WAPI "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_MFP_BIT, " MFP "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_MU_MIMO_RX_BIT, " MU_MIMO_RX "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_MU_MIMO_TX_BIT, " MU_MIMO_TX "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_MESH_BIT, " MESH "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_TDLS_BIT, " TDLS "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_ANT_DIV_BIT, " ANT_DIV "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_UF_BIT, " UF "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_AMSDU_MAX_SIZE_0_BIT, " AMSDU_MAX_SIZE_0"); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_AMSDU_MAX_SIZE_1_BIT, " AMSDU_MAX_SIZE_1"); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_HE_BIT, " HE "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_TWT_BIT, " TWT "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_FTM_INIT_BIT, " FTM_INIT "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_FAKE_FTM_RSP_BIT, " FAKE_FTM_RSP "); + FSCNPRINTF(n, len, buf, RA6W_DEV_FEAT_HW_LLCSNAP_INS_BIT, " HW_LLCSNAP_INS "); + + n += scnprintf(&buf[n], len - n, "max sta : %u\n", le16_to_cpu(fw_ver->max_sta_nb)); + n += scnprintf(&buf[n], len - n, "max vif : %u\n", fw_ver->max_vif_nb); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, n); + + kfree(buf); + + return ret; +} + +static const struct file_operations ra6w_dbgfs_dev_info_ops = { + .read = ra6w_dbgfs_dev_info_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static ssize_t ra6w_dbgfs_mac_info_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ +#define FSCNPRINTF(n, len, buf, NBIT, str) \ +do { \ + bool set = test_bit(NBIT, &features); \ + (n) += scnprintf(&(buf)[n], (len) - (n), "%s : %d\n", str, set); \ +} while (0) + + struct ra6w_cfg80211_priv *priv = file->private_data; + struct ra6w_core *core = priv->core; + struct ra6w_sys_info *sinfo = &core->sinfo; + u32 mac_feat = le32_to_cpu(sinfo->fw_ver.machw_features); + unsigned long features = (unsigned long)mac_feat; + char *buf; + size_t n = 0; + size_t len = count; + ssize_t ret = 0; + + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + n += scnprintf(&buf[n], len - n, "mac features: 0x%X:\n", mac_feat); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_QOS_BIT, " QOS "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_EDCA_BIT, " EDCA "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_SME_BIT, " SME "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_SECURITY_BIT, " SECURITY "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_TKIP_BIT, " TKIP "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_CCMP_BIT, " CCMP "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_RCE_BIT, " RCE "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_GCMP_BIT, " GCMP "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_HT_BIT, " HT "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_VHT_BIT, " VHT "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_TPC_BIT, " TPC "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_WAPI_BIT, " WAPI "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_COEX_BIT, " COEX "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_HE_BIT, " HE "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_BFMEE_BIT, " BFMEE "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_BFMER_BIT, " BFMER "); + FSCNPRINTF(n, len, buf, RA6W_MAC_FEAT_MU_MIMO_TX_BIT, " MU_MIMO_TX"); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, n); + + kfree(buf); + + return ret; +} + +static const struct file_operations ra6w_dbgfs_mac_info_ops = { + .read = ra6w_dbgfs_mac_info_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +void ra6w_dbgfs_register(struct ra6w_cfg80211_priv *priv) +{ + struct dentry *root; + + root = debugfs_create_dir(KBUILD_MODNAME, priv->wiphy->debugfsdir); + priv->root = root; + + debugfs_create_file("stats", 0600, root, priv, &ra6w_dbgfs_stats_ops); + debugfs_create_file("dev_info", 0600, root, priv, &ra6w_dbgfs_dev_info_ops); + debugfs_create_file("mac_info", 0600, root, priv, &ra6w_dbgfs_mac_info_ops); + debugfs_create_u32("log_level", 0600, root, &ra6w_params_list.module_params.log_level); +} + +void ra6w_dbgfs_deregister(struct ra6w_cfg80211_priv *priv) +{ + debugfs_remove_recursive(priv->root); + priv->root = NULL; +} From patchwork Thu Apr 17 13:52:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882855 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3421B24E4B2 for ; Thu, 17 Apr 2025 13:53:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898025; cv=none; b=Jdt4LsIQZIevCIT53lwt5vjau9P6f5tRF6iDXr1i53B/h9G3hiMw1kKZ0vY2Ke8OzO45EDg6U4kAI+kTg+Dy2lLZt5aQCb3KDC9rshWnPVywTStRfc2412pX7pLJhBQigRL2fexcy8vwjlBbQohxBhQilY2bswbDZLjOibuL3ok= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898025; c=relaxed/simple; bh=Opz41BGZewPIpVabg+NF9R5vbdf8F5RfrOqzj06Vwh4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=DaVy1CQoE4nXLFa9a3VVMPlG4moI2SpFR5FRgI0SeMfRMdsVVT9xm4GiWo1tNh0bXiopKZgdXNaTzpE0GSZn4jgWvpzYz/QWAHFa44Kw+KMiufY4CMjFMCTS/KWAK+WngOOq7ZEGqjYbEO6BQEGshjjRfScpsAECVW3Dzq/OZys= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: 81XVeJjmQ4idgdhakHUmOA== X-CSE-MsgGUID: iJg//Z0AS4uXqwERfG1Vpw== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:41 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 6B0394006DE8; Thu, 17 Apr 2025 22:53:38 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 13/38] ra6w: add dbgfs.h Date: Thu, 17 Apr 2025 16:52:11 +0300 Message-Id: <20250417135236.52410-14-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/dbgfs.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/dbgfs.h diff --git a/drivers/net/wireless/renesas/ra6w/dbgfs.h b/drivers/net/wireless/renesas/ra6w/dbgfs.h new file mode 100644 index 000000000000..50e11ac3c8c9 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/dbgfs.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_DBGFS_H +#define RA6W_DBGFS_H + +#ifdef CONFIG_DEBUG_FS +void ra6w_dbgfs_register(struct ra6w_cfg80211_priv *priv); +void ra6w_dbgfs_deregister(struct ra6w_cfg80211_priv *priv); +#else +static inline void ra6w_dbgfs_register(struct ra6w_cfg80211_priv *priv) +{ +} + +static inline void ra6w_dbgfs_deregister(struct ra6w_cfg80211_priv *priv) +{ +} +#endif /* CONFIG_DEBUG_FS */ + +#endif /* RA6W_DBGFS_H */ From patchwork Thu Apr 17 13:52:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882269 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 20C0E24EF65 for ; Thu, 17 Apr 2025 13:53:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898027; cv=none; b=kIFFmWNadjdklA1Hv7GXb7uIQFmYkntGD/ajc5GYEPhqvT2W2q11zQQqvwNAY7kbZZY+8qYQsJxMIeca0RhNM3nnIHavwt4h1u1NIzzdtYVo3Ds09Qii81bzSqV/grflk2xez32WMlZNIag1gM3QHdALz6tbSITCmArynGcJjBQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898027; c=relaxed/simple; bh=3+eUbsLPpjSU0tCw99VJHJrXkdBt2ZW/dgX5V02MF7g=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=XLqyrbqs8yIFAxuuxCeZNEKyed9ORtGGhT4DDKZXD6PjhgQLJ5D5SaRwstRr5gf6pg3RwjqMx7YBgL3wOwG8mr/idZPymg9jOD9uZKmEoQPaLJ5QRxi3GZaBMULTG+oArpWhVklxQ6dsdRKLnlLYVqQVJXC9eF2vSP8kt6hbSrI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: ox6e45XQSEezBZv5GAAzOw== X-CSE-MsgGUID: S08UMYjHT3yGHZ0HyyfHyA== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:45 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 8B96F4006DE8; Thu, 17 Apr 2025 22:53:42 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 14/38] ra6w: add dev.c Date: Thu, 17 Apr 2025 16:52:12 +0300 Message-Id: <20250417135236.52410-15-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/dev.c | 233 ++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/dev.c diff --git a/drivers/net/wireless/renesas/ra6w/dev.c b/drivers/net/wireless/renesas/ra6w/dev.c new file mode 100644 index 000000000000..16716fb4fdd7 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/dev.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains netdevice communication. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include +#include +#include +#include + +#include "core.h" +#include "cfg80211.h" +#include "dev.h" +#include "params.h" +#include "dbg.h" + +static int ra6w_dev_ndo_open(struct net_device *ndev) +{ + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_priv *priv = vif->priv; + + vif->up = true; + priv->vif_started++; + + if (ra6w_recovery_reprobe_get()) { + ra6w_recovery_reprobe_set(false); + return 0; + } + + netif_carrier_off(ndev); + + return 0; +} + +static int ra6w_dev_ndo_close(struct net_device *ndev) +{ + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_cfg80211_priv *priv = NULL; + + if (!vif) + return 0; + + priv = vif->priv; + if (!priv) + return 0; + + if (priv->scan_request) { + ra6w_ctrl_scan_cancel(&priv->core->ctrl, vif); + ra6w_cfg80211_scan_done(priv); + } + + vif->up = false; + if (netif_carrier_ok(ndev)) { + if (vif->type == NL80211_IFTYPE_STATION || + vif->type == NL80211_IFTYPE_P2P_CLIENT) + cfg80211_disconnected(ndev, WLAN_REASON_DEAUTH_LEAVING, + NULL, 0, true, GFP_ATOMIC); + + netif_carrier_off(ndev); + } + + if (vif->type == NL80211_IFTYPE_MONITOR) + priv->mon_vif_idx = RA6W_CFG80211_VIF_IDX_INVALID; + + priv->vif_started--; + + return 0; +} + +static struct ra6w_cfg80211_sta *ra6w_dev_get_sta(struct ra6w_cfg80211_vif *vif, + struct sk_buff *skb) +{ + struct ra6w_cfg80211_sta *sta = NULL; + + if (!vif) + return NULL; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + sta = vif->sta.ap; + if (sta && sta->valid) + return sta; + + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: { + const struct ethhdr *eth = (struct ethhdr *)skb->data; + + if (is_multicast_ether_addr(eth->h_dest)) { + sta = ra6w_cfg80211_sta_get(vif->priv, vif->ap.bcmc_index); + if (sta && sta->valid) + return sta; + + break; + } + + list_for_each_entry(sta, &vif->ap.sta_list, list) { + if (sta->valid && ether_addr_equal(sta->mac_addr, eth->h_dest)) + return sta; + } + } + break; + default: + break; + } + + return NULL; +} + +static netdev_tx_t ra6w_dev_tx(struct ra6w_cfg80211_vif *vif, struct sk_buff *skb) +{ + struct ra6w_cfg80211_priv *priv = vif->priv; + struct ra6w_tx *tx = &priv->core->tx; + struct ra6w_tx_buf *tx_buf = NULL; + const struct ra6w_cfg80211_sta *sta = NULL; + u8 hdr_size = RA6W_GET_DATA_SIZE(RA6W_TX_EXT_LEN, 0); + u8 tx_buf_ac = RA6W_TX_DATA_AC; + u8 sta_idx = RA6W_CFG80211_STA_IDX_INVALID; + u8 prio = skb->priority; + + if (skb->len - hdr_size > RA6W_CMD_DATA_SIZE) + return -EINVAL; + + sta = ra6w_dev_get_sta(vif, skb); + if (sta) + sta_idx = sta->sta_idx; + + if (sta_idx == RA6W_CFG80211_STA_IDX_INVALID) + return -ENXIO; + + if (skb_headroom(skb) < hdr_size) { + int ret; + + ret = pskb_expand_head(skb, hdr_size, 0, GFP_ATOMIC); + if (ret < 0) { + ra6w_err("[%s] SKB resize failed: hdr_size %u (reserved %u) ret %d\n", + __func__, hdr_size, skb_headroom(skb), ret); + + return -EFAULT; + } + } + + if (skb->priority == 0 || skb->priority > IEEE80211_QOS_CTL_TAG1D_MASK) + prio = cfg80211_classify8021d(skb, NULL); + + tx_buf = (struct ra6w_tx_buf *)skb_push(skb, hdr_size); + tx_buf->cmd = RA6W_CMD_DATA_TX; + tx_buf->ext_len = RA6W_TX_EXT_LEN; + tx_buf->ext_hdr.buf_idx = tx_buf_ac; + tx_buf->ext_hdr.tid = prio; + tx_buf->ext_hdr.vif_idx = vif->vif_idx; + tx_buf->ext_hdr.sta_idx = sta_idx; + tx_buf->ext_hdr.flags = 0; + tx_buf->ext_hdr.sn = 0; + tx_buf->data_len = cpu_to_le16(skb->len - hdr_size); + + return ra6w_tx_event_post(tx, tx_buf_ac, skb); +} + +static netdev_tx_t ra6w_dev_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int ret; + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + + ret = ra6w_dev_tx(vif, skb); + if (ret) { + dev_kfree_skb(skb); + ndev->stats.tx_errors++; + ndev->stats.tx_dropped++; + + return NETDEV_TX_OK; + } + + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; + + return NETDEV_TX_OK; +} + +static const struct net_device_ops ra6w_dev_ops = { + .ndo_open = ra6w_dev_ndo_open, + .ndo_stop = ra6w_dev_ndo_close, + .ndo_start_xmit = ra6w_dev_ndo_start_xmit, + .ndo_set_mac_address = eth_mac_addr, +}; + +static const struct net_device_ops ra6w_dev_monitor_ops = { + .ndo_open = ra6w_dev_ndo_open, + .ndo_stop = ra6w_dev_ndo_close, + .ndo_set_mac_address = eth_mac_addr, +}; + +static u32 ra6w_dev_ethtool_get_link(struct net_device *ndev) +{ + return netif_carrier_ok(ndev); +} + +static const struct ethtool_ops ra6w_ethtool_ops = { + .get_link = ra6w_dev_ethtool_get_link, + .get_drvinfo = cfg80211_get_drvinfo, +}; + +void ra6w_dev_init(struct net_device *ndev) +{ + if (!ndev) + return; + + ether_setup(ndev); + + ndev->priv_flags &= ~IFF_TX_SKB_SHARING; + + ra6w_dev_set_ops(ndev); + ndev->ethtool_ops = &ra6w_ethtool_ops; + + ndev->needs_free_netdev = true; + ndev->watchdog_timeo = RA6W_CMD_TX_LIFETIME_MS; + ndev->needed_headroom += RA6W_GET_DATA_SIZE(RA6W_TX_EXT_LEN, 0); + ndev->hw_features = 0; +} + +void ra6w_dev_set_ops(struct net_device *ndev) +{ + ndev->netdev_ops = &ra6w_dev_ops; + ndev->tx_queue_len = RA6W_TX_BUF_Q_MAX; +} + +void ra6w_dev_set_monitor_ops(struct net_device *ndev) +{ + ndev->netdev_ops = &ra6w_dev_monitor_ops; +} From patchwork Thu Apr 17 13:52:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882854 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5210E24EF6A for ; Thu, 17 Apr 2025 13:53:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898031; cv=none; b=NikFBH76aeFPjPw6Vxeyht4DTa2kzkU52FM5gzpHqU0oJHnKzjJE/wtZUydazTAVgeP1IsEefoXaRzVzDylI5jKO3so0wSMjoJP+DbxZ90VpMrkf4tdWE4R5vnk8YXkQE3iMm8djRSvNh5SagSdK9qCF6Hpao63TyPMGIu5c55U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898031; c=relaxed/simple; bh=yoStUonIwss4GitjHnZNS3wYTfDdCHe67D6TnWuBz0g=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=qZn6arPUOgMo+x8yG2pKBw/+4U9IykiU0eyMoBvpL5qxUhkwp6y2rOrPtBNVvZHKaL7drjnKIXNoJmoEgQuhXxsn+cEJBF3WrB2uALvb/htfKOeB1MQ5S4yGzx9ykLy6Cxb6dUQo1/GsgfQqMqBxI+jTLbDdobPhGU45rC274j0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: HLyQN8KxS/OiqgXykdUyhQ== X-CSE-MsgGUID: DrDJ/mU7QOCj6n7L+WlGFA== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:50 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id AD8A44005025; Thu, 17 Apr 2025 22:53:46 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 15/38] ra6w: add dev.h Date: Thu, 17 Apr 2025 16:52:13 +0300 Message-Id: <20250417135236.52410-16-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/dev.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/dev.h diff --git a/drivers/net/wireless/renesas/ra6w/dev.h b/drivers/net/wireless/renesas/ra6w/dev.h new file mode 100644 index 000000000000..792f0193fe59 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/dev.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_DEV_H +#define RA6W_DEV_H + +#include +#include + +void ra6w_dev_init(struct net_device *ndev); +void ra6w_dev_set_ops(struct net_device *ndev); +void ra6w_dev_set_monitor_ops(struct net_device *ndev); + +#endif /* RA6W_DEV_H */ From patchwork Thu Apr 17 13:52:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882268 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7B73324EF6A for ; Thu, 17 Apr 2025 13:53:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898036; cv=none; b=QLr68YvCMMyIMhZcpaSHvGnQT7iPbBPKyGRgxetbh9pBQXdoFuz5M1Xe5E09ULuntz7x81l2/y6ye+sRMoHuhty0ILxRijVKfGCOYrHL8pEM+PasTdvapMGEtdaGF97mHJbNypwSjI5rirV1Ndytkl2tdhl0Fsk0iOKHS63XWvU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898036; c=relaxed/simple; bh=4O/s4m3lOto2Ap8nDH6mV+g/IQN9iN+/H0DrV2Wtjw8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=VkRwvFScImwktFeWr+Gsei2L07XxWKFawa+UX3V1KEvgwHNrAyww1AIFgq9lsZnEtSJMxm5QnE9IihKrDgsuZ8y6bLBatSzd3rEFLLyKT2bIXUTnqihZOSa2NfRt5DbM4aOJhSBrtOTDXSt2JtCVJJwPI9BL/BOiR2sKiqoba4E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: xclw8bDpSvaLGOpvB4nFMg== X-CSE-MsgGUID: 8lYi64GtQHyvQC3pUW3ICA== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:54 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id D80464005025; Thu, 17 Apr 2025 22:53:50 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 16/38] ra6w: add if.h Date: Thu, 17 Apr 2025 16:52:14 +0300 Message-Id: <20250417135236.52410-17-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/if.h | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/if.h diff --git a/drivers/net/wireless/renesas/ra6w/if.h b/drivers/net/wireless/renesas/ra6w/if.h new file mode 100644 index 000000000000..35fc7d2865d4 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/if.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_IF_H +#define RA6W_IF_H + +struct ra6w_if_ops { + int (*read)(struct sdio_func *func, void *data, int len); + int (*write)(struct sdio_func *func, void *data, int len); +}; + +struct ra6w_if_dev { + struct sdio_func *func; + bool dev_on_resume; +}; + +struct ra6w_if { + struct ra6w_core core; + struct ra6w_if_dev dev; + const struct ra6w_if_ops *ops; +}; + +static inline int ra6w_if_read(struct ra6w_if *ifp, void *buf, int len) +{ + if (ifp->core.recovery.in_recovery) + return -EINPROGRESS; + + return ifp->ops->read(ifp->dev.func, buf, len); +} + +static inline int ra6w_if_write(struct ra6w_if *ifp, void *buf, int len) +{ + if (ifp->core.recovery.in_recovery) + return -EINPROGRESS; + + return ifp->ops->write(ifp->dev.func, buf, len); +} + +#endif /* RA6W_IF_H */ From patchwork Thu Apr 17 13:52:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882853 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 53C6F24EABC for ; Thu, 17 Apr 2025 13:53:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898041; cv=none; b=kHfY3c60kfSyEH53j1yKRkhfDI1ZytPc9p86HOY6PcTnm/oD7Q3gUlgG2hjyN0goTsNMoirspluZydNsN9Db60F3kBr3CMk4f/aTUUHs7tSZx8YNr43wIPRezBw1hDOc2XSouTZHa/STcDeu2tzOaniYmZGWKdEzBZ9OOOSWxIM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898041; c=relaxed/simple; bh=BkDoe8XVR2ejyHRZmyDrvnnk9LAxn8o5UiglRFSQYxk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=QP3MtSWCkUeFVpiNfdq77L8z19LDidxz9wTaoLOIB5fLYAPD1T6lAQE/blFLMs/Ha1XEVm2fona0rgcP+TcxKk2dzkVckECKcZSH/8ddGZxWWb+VRL5Czkci0AN7vSWRGrNwFFML463PjVs6fEixWisf0lfo0TC6C+65JW76naY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: Vk00mgHURQekxaQ5sXq5Qg== X-CSE-MsgGUID: poQOgpHHQTiIDrV4lJ5pew== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:53:58 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 0FDED4006DE8; Thu, 17 Apr 2025 22:53:54 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 17/38] ra6w: add indi.c Date: Thu, 17 Apr 2025 16:52:15 +0300 Message-Id: <20250417135236.52410-18-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/indi.c | 581 +++++++++++++++++++++++ 1 file changed, 581 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/indi.c diff --git a/drivers/net/wireless/renesas/ra6w/indi.c b/drivers/net/wireless/renesas/ra6w/indi.c new file mode 100644 index 000000000000..b31e588c3e48 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/indi.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains asynchronous fw routine. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include "core.h" +#include "cfg80211.h" +#include "dev.h" +#include "params.h" +#include "dbg.h" +#include "indi.h" + +#define RA6W_INDI_THREAD_NAME "ra6w_indi_thread" + +static int ra6w_indi_freq_to_idx(const struct ra6w_cfg80211_priv *priv, u16 freq, u16 *idx_res) +{ + const struct ieee80211_supported_band *sband; + u16 ch; + u16 band; + u16 idx = 0; + int ret = -ENOENT; + + for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { + sband = priv->wiphy->bands[band]; + if (!sband) + continue; + + for (ch = 0; ch < sband->n_channels; ch++, idx++) { + if (sband->channels[ch].center_freq != freq) + continue; + + *idx_res = idx; + ret = 0; + + break; + } + } + + return ret; +} + +static void ra6w_indi_channel_survey(struct ra6w_cfg80211_priv *priv, const void *data) +{ + struct ra6w_cfg80211_survey_info *survey = NULL; + const struct ra6w_cmd_sc_survey_info *ind = data; + u16 idx = 0; + int ret; + + ret = ra6w_indi_freq_to_idx(priv, le16_to_cpu(ind->freq), &idx); + if (ret) + return; + + survey = &priv->survey_table[idx]; + + survey->chan_dwell_ms = le32_to_cpu(ind->chan_dwell_ms); + survey->filled |= SURVEY_INFO_TIME; + survey->chan_busy_ms = le32_to_cpu(ind->chan_busy_ms); + survey->filled |= SURVEY_INFO_TIME_BUSY; + + if (ind->chan_noise_dbm) { + survey->chan_noise_dbm = ind->chan_noise_dbm; + survey->filled |= SURVEY_INFO_NOISE_DBM; + } +} + +static void ra6w_indi_scan_result(struct ra6w_cfg80211_priv *priv, void *data) +{ + struct cfg80211_bss *bss = NULL; + struct ieee80211_channel *chan = NULL; + struct ra6w_cmd_sc_result_ind *ind = data; + + chan = ieee80211_get_channel(priv->wiphy, le16_to_cpu(ind->center_freq)); + if (!chan) + return; + + /* + * Since we are using CFG80211_SIGNAL_TYPE_MBM signal_type, + * we have to multiply rssi by 100 + */ + bss = cfg80211_inform_bss_frame(priv->wiphy, chan, + (struct ieee80211_mgmt *)ind->payload, + le16_to_cpu(ind->length), (s32)ind->rssi * 100, + GFP_ATOMIC); + if (!bss) + return; + + cfg80211_put_bss(priv->wiphy, bss); +} + +static void ra6w_indi_scan_complete(struct ra6w_cfg80211_priv *priv) +{ + struct cfg80211_scan_info info = { + .aborted = false, + }; + + if (!priv->scan_request) + return; + + cfg80211_scan_done(priv->scan_request, &info); + priv->scan_request = NULL; +} + +static void ra6w_indi_sm_connect(struct ra6w_cfg80211_priv *priv, void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + struct net_device *ndev = NULL; + struct ra6w_cmd_sm_connect_ind *ind = data; + const u8 *req_ie; + const u8 *rsp_ie; + + vif = ra6w_cfg80211_vif_get(priv, ind->vif_idx); + if (!vif || !vif->up) + return; + + ndev = vif->ndev; + if (!ndev) + return; + + if (ind->conn_status == 0) { + struct ra6w_cfg80211_sta *sta = ra6w_cfg80211_sta_get(priv, ind->ap_idx); + struct ieee80211_channel *chan; + struct cfg80211_chan_def chandef; + + sta->valid = true; + sta->sta_idx = ind->ap_idx; + sta->ch_idx = ind->ch_idx; + sta->vif_idx = ind->vif_idx; + sta->qos = ind->flag_qos; + sta->aid = le16_to_cpu(ind->assoc_id); + sta->band = ind->oper_chan.ch_band; + sta->width = ind->oper_chan.ch_bw; + sta->center_freq = le16_to_cpu(ind->oper_chan.freq_prim20); + sta->center_freq1 = le16_to_cpu(ind->oper_chan.freq_cen1); + sta->center_freq2 = le16_to_cpu(ind->oper_chan.freq_cen2); + vif->sta.ap = sta; + vif->generation++; + chan = ieee80211_get_channel(priv->wiphy, le16_to_cpu(ind->oper_chan.freq_prim20)); + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); + if (!ra6w_params_ht_supported()) + chandef.width = NL80211_CHAN_WIDTH_20_NOHT; + else + chandef.width = chnl2bw[ind->oper_chan.ch_bw]; + chandef.center_freq1 = le16_to_cpu(ind->oper_chan.freq_cen1); + chandef.center_freq2 = le16_to_cpu(ind->oper_chan.freq_cen2); + ra6w_cfg80211_chaninfo_set(vif, ind->ch_idx, &chandef); + ether_addr_copy(sta->mac_addr, (u8 *)&ind->bssid.addr); + } + + req_ie = (const u8 *)ind->assoc_ie_buf; + rsp_ie = req_ie + le16_to_cpu(ind->assoc_req_ie_len); + + cfg80211_connect_result(ndev, (const u8 *)ind->bssid.addr, + req_ie, le16_to_cpu(ind->assoc_req_ie_len), + rsp_ie, le16_to_cpu(ind->assoc_rsp_ie_len), + le16_to_cpu(ind->conn_status), GFP_ATOMIC); +} + +static const char *ra6w_indi_reason_to_str(int reason_code) +{ + switch (reason_code) { + case RA6W_INDI_DIS_RSN_BEACON_MISS: return "BEACON_MISS"; + case RA6W_INDI_DIS_RSN_PS_TX_MAX_ERR: return "PS_TX_MAX_ERR"; + case RA6W_INDI_DIS_RSN_CHAN_SWITCH_FAIL: return "CHAN_SWITCH_FAIL"; + default: return "UNKNOWN"; + } +} + +static void ra6w_indi_sm_disconnect(struct ra6w_cfg80211_priv *priv, const void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + const struct ra6w_cmd_sm_disconnect_ind *ind = data; + struct net_device *ndev = NULL; + + vif = ra6w_cfg80211_vif_get(priv, ind->vif_idx); + if (!vif || !vif->up) + return; + + ndev = vif->ndev; + + if (!ind->reassoc) { + u16 reason_code = le16_to_cpu(ind->reason_code); + bool locally_generated = false; + + if (reason_code > RA6W_INDI_DIS_RSN_MIN && + reason_code < RA6W_INDI_DIS_RSN_MAX) { + ra6w_info("[%s] disconnect reason is %s\n", + __func__, ra6w_indi_reason_to_str(reason_code)); + reason_code = WLAN_REASON_UNSPECIFIED; + locally_generated = true; + } + + ra6w_stats_deinit(&vif->stats); + + cfg80211_disconnected(ndev, reason_code, NULL, 0, locally_generated, GFP_ATOMIC); + } + + netif_carrier_off(ndev); + + if (vif->sta.ap) + ra6w_cfg80211_sta_free(vif, vif->sta.ap->sta_idx); + + vif->generation++; + + ra6w_cfg80211_chaninfo_unset(vif); +} + +static void ra6w_indi_me_mic_failure(struct ra6w_cfg80211_priv *priv, void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + struct net_device *ndev = NULL; + struct ra6w_cmd_me_mic_failure_ind *ind = data; + + vif = ra6w_cfg80211_vif_get(priv, ind->vif_idx); + if (!vif || !vif->up) + return; + + ndev = vif->ndev; + if (!ndev) + return; + + cfg80211_michael_mic_failure(ndev, (u8 *)&ind->mac_addr, + (ind->group ? NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE), + ind->keyid, (u8 *)&ind->tsc, GFP_ATOMIC); +} + +static void ra6w_indi_twt_setup(struct ra6w_cfg80211_priv *priv, const void *data) +{ + struct ra6w_cfg80211_sta *sta = NULL; + const struct ra6w_cfg80211_twt_setup_ind *ind = data; + + sta = ra6w_cfg80211_sta_get(priv, ind->sta_idx); + if (!sta) + return; + + memcpy(&sta->twt_ind, ind, sizeof(*ind)); +} + +static void ra6w_indi_rssi_status(struct ra6w_cfg80211_priv *priv, const void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + struct net_device *ndev = NULL; + const struct ra6w_cmd_rssi_status_ind *ind = data; + + vif = ra6w_cfg80211_vif_get(priv, ind->vif_idx); + if (!vif || !vif->up) + return; + + ndev = vif->ndev; + if (!ndev) + return; + + cfg80211_cqm_rssi_notify(ndev, (ind->rssi_status ? NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW : + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH), + ind->rssi, GFP_ATOMIC); +} + +static void ra6w_indi_sm_ext_auth_req(struct ra6w_cfg80211_priv *priv, void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + struct cfg80211_external_auth_params params; + struct ra6w_cmd_sm_ext_auth_req_ind *ind = data; + + vif = ra6w_cfg80211_vif_get(priv, ind->vif_idx); + if (!vif || !vif->up) + return; + + params.action = NL80211_EXTERNAL_AUTH_START; + ether_addr_copy(params.bssid, (u8 *)&ind->bssid.addr); + params.ssid.ssid_len = ind->ssid.ssid_len; + memcpy(params.ssid.ssid, ind->ssid.ssid, + min_t(size_t, ind->ssid.ssid_len, sizeof(params.ssid.ssid))); + params.key_mgmt_suite = le32_to_cpu(ind->key_mgmt_suite); + + if (vif->type != NL80211_IFTYPE_STATION || + cfg80211_external_auth_request(vif->ndev, ¶ms, GFP_ATOMIC)) { + struct ra6w_ctrl *ctrl = &priv->core->ctrl; + + wiphy_err(priv->wiphy, "Failed to start external auth on vif %d", ind->vif_idx); + ra6w_ctrl_sm_ext_auth_req_rsp(ctrl, ind->vif_idx, WLAN_STATUS_UNSPECIFIED_FAILURE); + + return; + } + + vif->sta.flags |= RA6W_CMD_STA_AUTH_EXT_BIT; +} + +static void ra6w_indi_rx_chan_switch(struct ra6w_cfg80211_priv *priv, const void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + const struct ra6w_cmd_channel_switch_ind *ind = data; + + if (ind->roc_tdls) { + u8 vif_idx = ind->vif_idx; + + list_for_each_entry(vif, &priv->vifs, list) { + if (vif->vif_idx == vif_idx) + vif->roc_tdls = true; + } + } else if (ind->roc_req) { + struct ra6w_cfg80211_remain_on_channel *roc = priv->roc; + + if (!roc) + return; + + vif = roc->vif; + if (!vif) + return; + + if (!roc->internal) + cfg80211_ready_on_channel(&vif->wdev, (u64)(roc), roc->chan, + roc->duration, GFP_ATOMIC); + + roc->on_chan = true; + } + + priv->chaninfo_index = ind->chan_index; +} + +static void ra6w_indi_ap_probe_client(struct ra6w_cfg80211_priv *priv, const void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + struct ra6w_cfg80211_sta *sta = NULL; + const struct ra6w_cmd_ap_probe_client_ind *ind = data; + + vif = ra6w_cfg80211_vif_get(priv, ind->vif_idx); + if (!vif || !vif->up) + return; + + sta = ra6w_cfg80211_sta_get(priv, ind->sta_idx); + if (!sta) + return; + + sta->stats.last_acttive_time = jiffies; + cfg80211_probe_status(vif->ndev, sta->mac_addr, (u64)le32_to_cpu(ind->probe_id), + ind->client_present, 0, false, GFP_ATOMIC); +} + +static void ra6w_indi_roc_exp(struct ra6w_cfg80211_priv *priv) +{ + struct ra6w_cfg80211_remain_on_channel *roc = NULL; + struct ra6w_cfg80211_vif *vif = NULL; + + roc = priv->roc; + if (!roc) + return; + + vif = roc->vif; + if (!vif) + return; + + if (!roc->internal && roc->on_chan) + cfg80211_remain_on_channel_expired(&vif->wdev, (u64)(roc), roc->chan, GFP_ATOMIC); + + kfree(roc); + priv->roc = NULL; +} + +static void ra6w_indi_pktloss_notify(struct ra6w_cfg80211_priv *priv, const void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + const struct ra6w_cmd_pktloss_ind *ind = data; + + vif = ra6w_cfg80211_vif_get(priv, ind->vif_idx); + if (!vif || !vif->up) + return; + + cfg80211_cqm_pktloss_notify(vif->ndev, (const u8 *)ind->mac_addr.addr, + le32_to_cpu(ind->num_packets), GFP_ATOMIC); +} + +static void ra6w_indi_csa_counter(struct ra6w_cfg80211_priv *priv, const void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + const struct ra6w_cmd_csa_counter_ind *ind = data; + + vif = ra6w_cfg80211_vif_get(priv, ind->vif_idx); + if (!vif || !vif->up) + return; + + if (!vif->ap.csa) { + netdev_err(vif->ndev, "CSA counter update but no active CSA"); + return; + } + + vif->ap.csa->count = ind->csa_count; +} + +static void ra6w_indi_csa_finish(struct ra6w_cfg80211_priv *priv, const void *data) +{ + struct ra6w_cfg80211_vif *vif = NULL; + const struct ra6w_cmd_csa_finish_ind *ind = data; + + vif = ra6w_cfg80211_vif_get(priv, ind->vif_idx); + if (!vif || !vif->up) + return; + + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_P2P_GO) { + if (!vif->ap.csa) { + netdev_err(vif->ndev, "CSA finish indication but no active CSA"); + return; + } + + vif->ap.csa->status = ind->status; + vif->ap.csa->ch_idx = ind->chan_idx; + schedule_work(&vif->ap.csa->work); + + return; + } + + if (ind->status == 0) { + ra6w_cfg80211_chaninfo_unset(vif); + ra6w_cfg80211_chaninfo_set(vif, ind->chan_idx, NULL); + } +} + +static void ra6w_indi_rx(struct ra6w_indi *indi, struct sk_buff *skb) +{ + struct ra6w_core *core = container_of(indi, struct ra6w_core, indi); + struct ra6w_cfg80211_priv *priv = core->priv; + struct ra6w_indi_buf *indi_data = (struct ra6w_indi_buf *)skb->data; + + if (!priv || !indi_data || indi_data->data_len == 0) + return; + + switch (indi_data->cmd) { + case RA6W_CMD_ME_TKIP_MIC_FAILURE_IND: + ra6w_indi_me_mic_failure(priv, indi_data->data); + break; + case RA6W_CMD_SC_RESULT_IND: + ra6w_indi_scan_result(priv, indi_data->data); + break; + case RA6W_CMD_SC_COMPLETE_IND: + ra6w_indi_scan_complete(priv); + break; + case RA6W_CMD_SC_CHANNEL_SURVEY_IND: + ra6w_indi_channel_survey(priv, indi_data->data); + break; + case RA6W_CMD_SM_CONNECT_IND: + ra6w_indi_sm_connect(priv, indi_data->data); + break; + case RA6W_CMD_SM_DISCONNECT_IND: + ra6w_indi_sm_disconnect(priv, indi_data->data); + break; + case RA6W_CMD_SM_EXTERNAL_AUTH_REQUIRED_IND: + ra6w_indi_sm_ext_auth_req(priv, indi_data->data); + break; + case RA6W_CMD_TWT_SETUP_IND: + ra6w_indi_twt_setup(priv, indi_data->data); + break; + case RA6W_CMD_AM_PROBE_CLIENT_IND: + ra6w_indi_ap_probe_client(priv, indi_data->data); + break; + case RA6W_CMD_MM_CHANNEL_SWITCH_IND: + ra6w_indi_rx_chan_switch(priv, indi_data->data); + break; + case RA6W_CMD_MM_CHANNEL_PRE_SWITCH_IND: + break; + case RA6W_CMD_MM_REMAIN_ON_CHANNEL_EXP_IND: + ra6w_indi_roc_exp(priv); + break; + case RA6W_CMD_MM_PS_CHANGE_IND: + break; + case RA6W_CMD_MM_TRAFFIC_REQ_IND: + break; + case RA6W_CMD_MM_RSSI_STATUS_IND: + ra6w_indi_rssi_status(priv, indi_data->data); + break; + case RA6W_CMD_MM_CSA_COUNTER_IND: + ra6w_indi_csa_counter(priv, indi_data->data); + break; + case RA6W_CMD_MM_CSA_FINISH_IND: + ra6w_indi_csa_finish(priv, indi_data->data); + break; + case RA6W_CMD_MM_CSA_TRAFFIC_IND: + break; + case RA6W_CMD_MM_PACKET_LOSS_IND: + ra6w_indi_pktloss_notify(priv, indi_data->data); + break; + case RA6W_CMD_DBG_ERROR_IND: + ra6w_recovery_event_post(&core->recovery); + break; + default: + ra6w_err("[%s] unknown indi cmd[%d]\n", __func__, indi_data->cmd); + break; + } +} + +static void ra6w_indi_worker(struct ra6w_indi *indi) +{ + struct sk_buff *skb = NULL; + + while (!kthread_should_stop() && + (skb = ra6w_q_pop(&indi->q))) { + ra6w_indi_rx(indi, skb); + dev_kfree_skb(skb); + } +} + +static int indi_thread_handler(void *arg) +{ + struct ra6w_indi *indi = arg; + int event = 0; + + do { + event = ra6w_q_wait(&indi->event, RA6W_INDI_EVENT_MASK); + if (event & BIT(RA6W_INDI_EVENT)) + ra6w_indi_worker(indi); + + if (event & BIT(RA6W_INDI_EVENT_RESET)) + break; + + atomic_set(&indi->event.condition, 0); + } while (!kthread_should_stop()); + + return 0; +} + +static int _ra6w_indi_init(struct ra6w_indi *indi, size_t indi_buf_num) +{ + int ret; + + if (indi_buf_num == 0) { + ra6w_err("[%s] indication queue size must be greater then zero\n", __func__); + return -EINVAL; + } + + ret = ra6w_q_init(&indi->q, indi_buf_num, sizeof(struct ra6w_indi_buf *)); + if (ret) + return ret; + + atomic_set(&indi->event.condition, 0); + init_waitqueue_head(&indi->event.wait_queue); + + indi->task = kthread_run(indi_thread_handler, indi, RA6W_INDI_THREAD_NAME); + if (!indi->task) { + ra6w_err("[%s] kthread_run %s failed\n", __func__, RA6W_INDI_THREAD_NAME); + goto indi_buf_free; + } + + return 0; + +indi_buf_free: + ra6w_q_deinit(&indi->q); + + return ret; +} + +int ra6w_indi_init(struct ra6w_indi *indi) +{ + return _ra6w_indi_init(indi, RA6W_INDI_BUF_Q_MAX); +} + +void ra6w_indi_deinit(struct ra6w_indi *indi) +{ + if (indi->task) { + atomic_set(&indi->event.condition, BIT(RA6W_INDI_EVENT_RESET)); + kthread_stop(indi->task); + } + + ra6w_q_deinit(&indi->q); +} + +int ra6w_indi_event_post(struct ra6w_indi *indi, struct sk_buff *skb) +{ + struct ra6w_core *core = container_of(indi, struct ra6w_core, indi); + struct ra6w_indi_buf *indi_data = (struct ra6w_indi_buf *)skb->data; + int ret; + + if (indi_data->ext_len == RA6W_INDI_EXT_LEN) + ra6w_status_set(&core->status, indi_data->ext_hdr.status); + + ret = ra6w_q_push(&indi->q, skb); + if (!ret || !ra6w_q_empty(&indi->q)) + ra6w_q_event_set(&indi->event, BIT(RA6W_INDI_EVENT)); + + return ret; +} From patchwork Thu Apr 17 13:52:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882267 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 217A124EAA4 for ; Thu, 17 Apr 2025 13:54:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898044; cv=none; b=AGxbKvvFeQNUvtK01RmB5PB6Nt0/bKGRlmnzo94ILdrqjhWiwaDQEI6nnrmj1o72z13Pw78+MX8iKV2YYM7XvhS4eXchcAi5hqDjaUpiabiJMqPiL8D7vVtw6f8XZJWZG4ww3wM8Q3MYEleTRxLyohjyy3Nz7okdcAqAqlHLjJU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898044; c=relaxed/simple; bh=YMaLRV2UlDXx+u6uIXARxUODfFPonUWr4uQX3CuKn9s=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=Lvcp5Vj+2LILS0PROIJS+aftkOD9sY+CtxtyVDFgwkG5O/X+94J8f10Pd5Pj7d7R0FoiFQdqqN00MVfHyo129KGJitx1toT9djwMYLICCTyK//HMjD9evtL8yafIrv8RbatPkUJZmefVpIt7IfLk3Drnqw0aTd89oYn3mHSUE9s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: j4gk3zGeSY2TI4sC62KPmw== X-CSE-MsgGUID: COwuOctmSH6MAWcWPdtPwg== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:02 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 2F75F4006DE8; Thu, 17 Apr 2025 22:53:58 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 18/38] ra6w: add indi.h Date: Thu, 17 Apr 2025 16:52:16 +0300 Message-Id: <20250417135236.52410-19-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/indi.h | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/indi.h diff --git a/drivers/net/wireless/renesas/ra6w/indi.h b/drivers/net/wireless/renesas/ra6w/indi.h new file mode 100644 index 000000000000..ee050d086f52 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/indi.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_INDI_H +#define RA6W_INDI_H + +#include +#include + +#include "q.h" + +#define RA6W_INDI_DATA_LEN 980 +#define RA6W_INDI_EXT_LEN (sizeof(struct ra6w_indi_ext_hdr)) +#define RA6W_INDI_BUF_Q_MAX 64 + +enum ra6w_indi_disconnect_reason { + RA6W_INDI_DIS_RSN_MIN = 100, + RA6W_INDI_DIS_RSN_BEACON_MISS = RA6W_INDI_DIS_RSN_MIN, + RA6W_INDI_DIS_RSN_PS_TX_MAX_ERR, + RA6W_INDI_DIS_RSN_CHAN_SWITCH_FAIL, + + RA6W_INDI_DIS_RSN_MAX, + RA6W_INDI_DIS_RSN_LAST = RA6W_INDI_DIS_RSN_MAX - 1, +}; + +struct ra6w_indi_ext_hdr { + u32 status : 32; +}; + +struct ra6w_indi_buf { + u8 cmd; + u8 ext_len; + __le16 data_len; + struct ra6w_indi_ext_hdr ext_hdr; + u8 data[RA6W_INDI_DATA_LEN]; +}; + +enum ra6w_indi_data_event { + RA6W_INDI_EVENT, + RA6W_INDI_EVENT_RESET, + + RA6W_INDI_EVENT_MAX, +}; + +#define RA6W_INDI_EVENT_MASK (BIT(RA6W_INDI_EVENT) | BIT(RA6W_INDI_EVENT_RESET)) + +struct ra6w_indi { + struct task_struct *task; + struct ra6w_q_event event; + struct ra6w_q q; +}; + +int ra6w_indi_init(struct ra6w_indi *indi); +void ra6w_indi_deinit(struct ra6w_indi *indi); +int ra6w_indi_event_post(struct ra6w_indi *indi, struct sk_buff *skb); + +#endif /* RA6W_INDI_H */ From patchwork Thu Apr 17 13:52:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882852 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id DFE0324EAA4 for ; Thu, 17 Apr 2025 13:54:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898049; cv=none; b=ubX9Sg0PhLoQTLgqZxGdEWbEJOpKBAECjsvPjQKVsKYEh8BuL0x2DytmkyNeWDWOkc7+yscelGvws2NHaGgo2uCZIjXYcpzjNyzuH/sD/ynaMiuWDGcRBnZXxWUF320j1hpg53ddRubUwpAiGnfG2j3m5lpAcv0abirod2/0UKI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898049; c=relaxed/simple; bh=TYqN0s/p4DPh6CuF9kfN0ED80d4CB9cr5uNaZng0yac=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=P/9o65MruxWDvPyQqAbTsCHlIQiZ5QtgLfz/Z1ZzXPJmW2GgsoB9LRIRI72Oau5/hPNcyuYrb5+WhJf+N743XdxCJ9LbcPJM2/zQsSftELHwdWbWeJSwp5nxXukolgWKqgtPeeEqgk8YrJasKHgR+4EJzNwTXUlRYG0/GkXXJcE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: UZpbQ4hRSOun4MpRpSPpEA== X-CSE-MsgGUID: uOilWCS4QFCrx5ViG5/oeQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:06 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 5131E4005B3F; Thu, 17 Apr 2025 22:54:02 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 19/38] ra6w: add params.c Date: Thu, 17 Apr 2025 16:52:17 +0300 Message-Id: <20250417135236.52410-20-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/params.c | 387 +++++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/params.c diff --git a/drivers/net/wireless/renesas/ra6w/params.c b/drivers/net/wireless/renesas/ra6w/params.c new file mode 100644 index 000000000000..c428fe7b648b --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/params.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains driver parameters operations. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include +#include +#include +#include + +#include "dbg.h" +#include "core.h" +#include "cfg80211.h" +#include "params.h" + +#define RA6W_PHY_FEAT_CHBW_MASK 0x03000000 +#define RA6W_PHY_FEAT_CHBW_LSB 24 +#define RA6W_PHY_FEAT_NSS_MASK 0x00000F00 +#define RA6W_PHY_FEAT_NSS_LSB 8 + +struct ra6w_params ra6w_params_list = { + .module_params = { + .stbc_enabled = true, + .ldpc_enabled = true, + .dpsm_enabled = true, + .ht_supported = true, + .rx_amsdu_size = 2, + .mcs_map_range = IEEE80211_VHT_MCS_SUPPORT_0_8, + .use_sgi = true, + .bfmer_enabled = true, + .he_mcs_map_range = IEEE80211_HE_MCS_SUPPORT_0_9, + .ap_uapsd_enabled = true, + .regdom_mode = "auto", + .log_level = RA6W_DEFAULT_LOG_LVL, + }, + .features = { + .uapsd_threshold = RA6W_CFG80211_UAPSD_TIMEOUT, + } +}; + +static struct ieee80211_regdomain ra6w_regdom = { + .n_reg_rules = 2, + .alpha2 = "99", + .reg_rules = { + REG_RULE(2390 - 10, 2510 + 10, 20, 0, 20, 0), + REG_RULE(5150 - 10, 5970 + 10, 20, 0, 20, 0), + } +}; + +module_param_named(stbc_enabled, ra6w_params_list.module_params.stbc_enabled, bool, 0444); +MODULE_PARM_DESC(stbc_enabled, "Enable STBC (Default: 1)"); + +module_param_named(ldpc_enabled, ra6w_params_list.module_params.ldpc_enabled, bool, 0444); +MODULE_PARM_DESC(ldpc_enabled, "Enable LDPC (Default: 1)"); + +module_param_named(ant_div, ra6w_params_list.module_params.ant_div, bool, 0444); +MODULE_PARM_DESC(ant_div, "Enable Antenna Diversity (Default: 0)"); + +module_param_named(ht_supported, ra6w_params_list.module_params.ht_supported, bool, 0444); +MODULE_PARM_DESC(ht_supported, "HT Enabled (Default: 1)"); + +module_param_named(amsdu_require_spp, + ra6w_params_list.module_params.amsdu_require_spp, bool, 0444); +MODULE_PARM_DESC(amsdu_require_spp, "Require usage of SPP A-MSDU (Default: 0)"); + +module_param_named(bfmer_enabled, ra6w_params_list.module_params.bfmer_enabled, bool, 0444); +MODULE_PARM_DESC(bfmer_enabled, "Beem Former Enabled. (Default: 1)"); + +module_param_named(dpsm_enabled, ra6w_params_list.module_params.dpsm_enabled, bool, 0444); +MODULE_PARM_DESC(dpsm_enabled, "Dynamic Power Save Mode Enabled (Default: 1)"); + +module_param_named(ap_uapsd_enabled, ra6w_params_list.module_params.ap_uapsd_enabled, bool, 0444); +MODULE_PARM_DESC(ap_uapsd_enabled, "AP UAPSD Enabled. (Default: 1)"); + +module_param_named(use_sgi, ra6w_params_list.module_params.use_sgi, bool, 0444); +MODULE_PARM_DESC(use_sgi, "SGI. (Default: 1: on)"); + +module_param_named(ccmp256_supported, + ra6w_params_list.module_params.ccmp256_supported, bool, 0444); +MODULE_PARM_DESC(ccmp256_supported, "CCMP256 Supported. (Default: 0)"); + +module_param_named(regdom_mode, ra6w_params_list.module_params.regdom_mode, charp, 0444); +MODULE_PARM_DESC(regdom_mode, "Regulatory mode (auto/self). default: auto"); + +module_param_named(rx_amsdu_size, ra6w_params_list.module_params.rx_amsdu_size, byte, 0444); +MODULE_PARM_DESC(rx_amsdu_size, "RX AMSDU SIZE. (Default: 2)"); + +module_param_named(mcs_map_range, ra6w_params_list.module_params.mcs_map_range, byte, 0444); +MODULE_PARM_DESC(mcs_map_range, "MCS MAP. (Default: 1"); + +module_param_named(he_mcs_map_range, ra6w_params_list.module_params.he_mcs_map_range, byte, 0444); +MODULE_PARM_DESC(he_mcs_map_range, "HE MCS MAP. (Default: 1)"); + +module_param_named(log_level, ra6w_params_list.module_params.log_level, int, 0644); +MODULE_PARM_DESC(log_level, "log_level (Default: 3: info)"); + +static u8 ra6w_params_phy_bw_get(const struct ra6w_sys_info *sinfo) +{ + u32 phy_feat = le32_to_cpu(sinfo->fw_ver.phy_feature); + + return (phy_feat & RA6W_PHY_FEAT_CHBW_MASK) >> RA6W_PHY_FEAT_CHBW_LSB; +} + +static u8 ra6w_params_phy_nss_get(const struct ra6w_sys_info *sinfo) +{ + u32 phy_feat = le32_to_cpu(sinfo->fw_ver.phy_feature); + + return (phy_feat & RA6W_PHY_FEAT_NSS_MASK) >> RA6W_PHY_FEAT_NSS_LSB; +} + +static bool ra6w_params_mac_gcmp_get(const struct ra6w_sys_info *sinfo) +{ + u32 mac_feat = le32_to_cpu(sinfo->fw_ver.machw_features); + + return mac_feat & BIT(RA6W_MAC_FEAT_GCMP_BIT); +} + +static u8 ra6w_params_rx_amsdu_size_get(const struct ra6w_sys_info *sinfo) +{ + u32 feat = le32_to_cpu(sinfo->fw_ver.features); + + return (feat >> RA6W_DEV_FEAT_AMSDU_MAX_SIZE_0_BIT) & 0x03; +} + +static bool ra6w_params_feat(u32 dev_feat, enum ra6w_params_dev_feat id) +{ + return dev_feat & BIT(id); +} + +static int ra6w_params_features_set(struct ra6w_core *core) +{ + int ret = 0; + u32 feat; + u32 phy_vers; + u16 max_sta_nb; + u8 max_vif_nb; + u8 amsdu_rx = 0; + struct ra6w_sys_info *sinfo = &core->sinfo; + struct ra6w_params_module_params *module_params = &ra6w_params_list.module_params; + struct ra6w_params_dev_features *features = &ra6w_params_list.features; + + feat = le32_to_cpu(sinfo->fw_ver.features); + if (!ra6w_params_feat(feat, RA6W_DEV_FEAT_UMAC_BIT)) { + ra6w_err("UMAC is not supported\n"); + return -ENOENT; + } + + features->vht_supported = ra6w_params_feat(feat, RA6W_DEV_FEAT_VHT_BIT); + features->he_supported = ra6w_params_feat(feat, RA6W_DEV_FEAT_HE_BIT); + features->he_ul_on = ra6w_params_feat(feat, RA6W_DEV_FEAT_HE_BIT); + features->ps_supported = ra6w_params_feat(feat, RA6W_DEV_FEAT_PS_BIT); + features->amsdu_supported = ra6w_params_feat(feat, RA6W_DEV_FEAT_AMSDU_BIT); + features->bfmee_enabled = ra6w_params_feat(feat, RA6W_DEV_FEAT_BFMEE_BIT); + features->tdls_supported = ra6w_params_feat(feat, RA6W_DEV_FEAT_TDLS_BIT); + features->wapi_supported = ra6w_params_feat(feat, RA6W_DEV_FEAT_WAPI_BIT); + features->mfp_supported = ra6w_params_feat(feat, RA6W_DEV_FEAT_MFP_BIT); + features->radar_supported = ra6w_params_feat(feat, RA6W_DEV_FEAT_RADAR_BIT); + features->mu_mimo_rx_enabled = ra6w_params_feat(feat, RA6W_DEV_FEAT_MU_MIMO_RX_BIT); + features->mu_mimo_tx_enabled = ra6w_params_feat(feat, RA6W_DEV_FEAT_MU_MIMO_TX_BIT); + features->twt_enabled = ra6w_params_feat(feat, RA6W_DEV_FEAT_TWT_BIT); + + amsdu_rx = ra6w_params_rx_amsdu_size_get(sinfo); + module_params->rx_amsdu_size = min(amsdu_rx, module_params->rx_amsdu_size); + + if (!ra6w_params_feat(feat, RA6W_DEV_FEAT_UAPSD_BIT)) + features->uapsd_threshold = 0; + + features->bw_max = ra6w_params_phy_bw_get(sinfo); + + if (!module_params->ht_supported) { + features->vht_supported = false; + features->he_supported = false; + } + + if (features->he_supported && !module_params->ldpc_enabled) + module_params->he_mcs_map_range = min_t(u8, module_params->he_mcs_map_range, + IEEE80211_HE_MCS_SUPPORT_0_9); + + phy_vers = le32_to_cpu(sinfo->fw_ver.phy_version); + + if (!features->mu_mimo_rx_enabled || !features->bfmee_enabled) + features->mu_mimo_rx_enabled = false; + + features->gcmp_supported = ra6w_params_mac_gcmp_get(sinfo); + + if (core->sinfo.machw_support_type >= RA6W_MACHW_SUPPORT_HE) + module_params->ccmp256_supported = true; + + features->nss = ra6w_params_phy_nss_get(sinfo); + + max_sta_nb = le16_to_cpu(sinfo->fw_ver.max_sta_nb); + if (max_sta_nb != RA6W_CFG80211_STA_MAX) { + ra6w_err("Number of supported stations by driver not fit to FW (%d != %d)\n", + RA6W_CFG80211_STA_MAX, max_sta_nb); + ret = -ENOENT; + } + + max_vif_nb = sinfo->fw_ver.max_vif_nb; + if (max_vif_nb != RA6W_CFG80211_VIF_MAX) { + ra6w_err("Number of virtual interfaces in driver not fit to FW (%d != %d)\n", + RA6W_CFG80211_VIF_MAX, max_vif_nb); + ret = -ENOENT; + } + + return ret; +} + +int ra6w_params_init(struct ra6w_core *core) +{ + return ra6w_params_features_set(core); +} + +bool ra6w_params_regd_mode_is_auto(void) +{ + return !strcmp(ra6w_params_list.module_params.regdom_mode, "auto"); +} + +int ra6w_params_regd_set_self(struct wiphy *wiphy) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + int ret; + + if (!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)) + return 0; + + ret = regulatory_set_wiphy_regd(wiphy, &ra6w_regdom); + if (ret) + return ret; + + ra6w_info("regdom mode: self\n"); + + memcpy(priv->phy_config.country_code, ra6w_regdom.alpha2, sizeof(ra6w_regdom.alpha2)); + + return ra6w_ctrl_chan_config(&priv->core->ctrl, wiphy); +} + +bool ra6w_params_ps_supported(void) +{ + return ra6w_params_list.features.ps_supported; +} + +bool ra6w_params_dpsm_enabled(void) +{ + return ra6w_params_list.module_params.dpsm_enabled; +} + +bool ra6w_params_amsdu_require_spp(void) +{ + return ra6w_params_list.module_params.amsdu_require_spp; +} + +bool ra6w_params_ht_supported(void) +{ + return ra6w_params_list.module_params.ht_supported; +} + +bool ra6w_params_vht_supported(void) +{ + return ra6w_params_list.features.vht_supported; +} + +bool ra6w_params_he_supported(void) +{ + return ra6w_params_list.features.he_supported; +} + +bool ra6w_params_he_ul_on(void) +{ + return ra6w_params_list.features.he_ul_on; +} + +bool ra6w_params_wapi_supported(void) +{ + return ra6w_params_list.features.wapi_supported; +} + +bool ra6w_params_mfp_supported(void) +{ + return ra6w_params_list.features.mfp_supported; +} + +bool ra6w_params_ap_uapsd_enabled(void) +{ + return ra6w_params_list.module_params.ap_uapsd_enabled; +} + +bool ra6w_params_tdls_supported(void) +{ + return ra6w_params_list.features.tdls_supported; +} + +bool ra6w_params_gcmp_supported(void) +{ + return ra6w_params_list.features.gcmp_supported; +} + +bool ra6w_params_ccmp256_supported(void) +{ + return ra6w_params_list.module_params.ccmp256_supported; +} + +bool ra6w_params_bfmee_enabled(void) +{ + return ra6w_params_list.features.bfmee_enabled; +} + +bool ra6w_params_bfmer_enabled(void) +{ + return ra6w_params_list.module_params.bfmer_enabled; +} + +bool ra6w_params_ldpc_enabled(void) +{ + return ra6w_params_list.module_params.ldpc_enabled; +} + +bool ra6w_params_stbc_enabled(void) +{ + return ra6w_params_list.module_params.stbc_enabled; +} + +u8 ra6w_params_bw_max_get(void) +{ + return ra6w_params_list.features.bw_max; +} + +bool ra6w_params_use_sgi(void) +{ + return ra6w_params_list.module_params.use_sgi; +} + +bool ra6w_params_mu_mimo_rx_enabled(void) +{ + return ra6w_params_list.features.mu_mimo_rx_enabled; +} + +bool ra6w_params_mu_mimo_tx_enabled(void) +{ + return ra6w_params_list.features.mu_mimo_tx_enabled; +} + +bool ra6w_params_twt_enabled(void) +{ + return ra6w_params_list.features.twt_enabled; +} + +u32 ra6w_params_uapsd_threshold(void) +{ + return ra6w_params_list.features.uapsd_threshold; +} + +bool ra6w_params_ant_div(void) +{ + return ra6w_params_list.module_params.ant_div; +} + +u32 ra6w_params_log_level(void) +{ + return ra6w_params_list.module_params.log_level; +} + +void ra6w_params_log_level_set(u32 log_level) +{ + ra6w_params_list.module_params.log_level = log_level; +} + +u8 ra6w_params_nss(void) +{ + return ra6w_params_list.features.nss; +} + +u8 ra6w_params_rx_amsdu_size(void) +{ + return ra6w_params_list.module_params.rx_amsdu_size; +} + +u8 ra6w_params_mcs_map_range(void) +{ + return ra6w_params_list.module_params.mcs_map_range; +} + +u8 ra6w_params_he_mcs_map_range(void) +{ + return ra6w_params_list.module_params.he_mcs_map_range; +} From patchwork Thu Apr 17 13:52:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882266 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6583724EF78 for ; Thu, 17 Apr 2025 13:54:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898053; cv=none; b=jQVGhhhb/fRv4TDls2Bngk+QbNFd5vvV+u9dfJ51EKzFKh0RnrusSifjyqjVOm05FAASvOza19V4mcQ4BKcS+fGIZn6Bd6jCcZSfU0s/iQQ6ZpvClyR7bFoOumzoK4JJT2il4R/66GHg9W1psPdqsql93Y2qf+mDr50t1zUT5NY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898053; c=relaxed/simple; bh=8ZXIn7Cz7U+JCirf0fapXNBrCEverddBPeV7oVQQkTM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=SRpd14bKVk12tB1dh074q2a9pJ1aN8LKN2dOf3m+pyf27sXQaLoE7asFUHiq/E7Qa6/rNEYv22GuB5UWnNVRJHRssU6m5wxnA4NlNvCFPYBo7j361N9wrKMqaUMIlhrg6g0OX6zxnlfU6zdeI3ZccLNHr051+4+LskzcXy+KbzY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: P2vtGiINRuqwwzMWiClDLQ== X-CSE-MsgGUID: FFRJN6QkQZS3d0YiOLPp3A== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:10 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 722D7400502F; Thu, 17 Apr 2025 22:54:07 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 20/38] ra6w: add params.h Date: Thu, 17 Apr 2025 16:52:18 +0300 Message-Id: <20250417135236.52410-21-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/params.h | 149 +++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/params.h diff --git a/drivers/net/wireless/renesas/ra6w/params.h b/drivers/net/wireless/renesas/ra6w/params.h new file mode 100644 index 000000000000..c67b157e5113 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/params.h @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_PARAMS_H +#define RA6W_PARAMS_H + +#define RA6W_PHY_MINOR_VERSION(v) (((v) & 0x00FF0000) >> 16) +#define RA6W_PHY_MAJOR_VERSION(v) (((v) & 0xFF000000) >> 24) +#define RA6W_PHY_VERSION(v) \ + ((RA6W_PHY_MAJOR_VERSION(v) + 2) * 10 + RA6W_PHY_MINOR_VERSION(v)) + +enum ra6w_params_dev_feat { + RA6W_DEV_FEAT_BCN_BIT, + RA6W_DEV_FEAT_RADAR_BIT, + RA6W_DEV_FEAT_PS_BIT, + RA6W_DEV_FEAT_UAPSD_BIT, + RA6W_DEV_FEAT_AMPDU_BIT, + RA6W_DEV_FEAT_AMSDU_BIT, + RA6W_DEV_FEAT_P2P_BIT, + RA6W_DEV_FEAT_P2P_GO_BIT, + RA6W_DEV_FEAT_UMAC_BIT, + RA6W_DEV_FEAT_VHT_BIT, + RA6W_DEV_FEAT_BFMEE_BIT, + RA6W_DEV_FEAT_BFMER_BIT, + RA6W_DEV_FEAT_WAPI_BIT, + RA6W_DEV_FEAT_MFP_BIT, + RA6W_DEV_FEAT_MU_MIMO_RX_BIT, + RA6W_DEV_FEAT_MU_MIMO_TX_BIT, + RA6W_DEV_FEAT_MESH_BIT, + RA6W_DEV_FEAT_TDLS_BIT, + RA6W_DEV_FEAT_ANT_DIV_BIT, + RA6W_DEV_FEAT_UF_BIT, + RA6W_DEV_FEAT_AMSDU_MAX_SIZE_0_BIT, + RA6W_DEV_FEAT_AMSDU_MAX_SIZE_1_BIT, + RA6W_DEV_FEAT_MON_DATA_BIT, + RA6W_DEV_FEAT_HE_BIT, + RA6W_DEV_FEAT_TWT_BIT, + RA6W_DEV_FEAT_FTM_INIT_BIT, + RA6W_DEV_FEAT_FAKE_FTM_RSP_BIT, + RA6W_DEV_FEAT_HW_LLCSNAP_INS_BIT, + RA6W_DEV_FEAT_MAX +}; + +enum ra6w_params_mac_feat { + RA6W_MAC_FEAT_QOS_BIT, + RA6W_MAC_FEAT_EDCA_BIT, + RA6W_MAC_FEAT_SME_BIT, + RA6W_MAC_FEAT_SECURITY_BIT, + RA6W_MAC_FEAT_WEP_BIT, + RA6W_MAC_FEAT_TKIP_BIT, + RA6W_MAC_FEAT_CCMP_BIT, + RA6W_MAC_FEAT_RCE_BIT, + RA6W_MAC_FEAT_GCMP_BIT, + RA6W_MAC_FEAT_HT_BIT, + RA6W_MAC_FEAT_VHT_BIT, + RA6W_MAC_FEAT_TPC_BIT, + RA6W_MAC_FEAT_WAPI_BIT, + RA6W_MAC_FEAT_COEX_BIT, + RA6W_MAC_FEAT_HE_BIT, + RA6W_MAC_FEAT_RESERVED_BIT, + RA6W_MAC_FEAT_BFMEE_BIT, + RA6W_MAC_FEAT_BFMER_BIT, + RA6W_MAC_FEAT_MU_MIMO_TX_BIT, + + RA6W_MAC_FEAT_MAX, +}; + +struct ra6w_params_dev_features { + bool tdls_supported; + bool amsdu_supported; + bool vht_supported; + bool he_supported; + bool he_ul_on; + bool bfmee_enabled; + bool ps_supported; + bool wapi_supported; + bool mfp_supported; + bool gcmp_supported; + bool radar_supported; + bool mu_mimo_rx_enabled; + bool mu_mimo_tx_enabled; + bool twt_enabled; + u8 nss; + u32 uapsd_threshold; + u8 bw_max; +}; + +struct ra6w_params_module_params { + bool stbc_enabled; + bool ldpc_enabled; + bool ant_div; + bool ht_supported; + bool amsdu_require_spp; + bool bfmer_enabled; + bool dpsm_enabled; + bool ap_uapsd_enabled; + bool use_sgi; + bool ccmp256_supported; + char *regdom_mode; + u8 mcs_map_range; + u8 he_mcs_map_range; + u8 rx_amsdu_size; + u32 log_level; +}; + +struct ra6w_params { + struct ra6w_params_dev_features features; + struct ra6w_params_module_params module_params; +}; + +extern struct ra6w_params ra6w_params_list; + +int ra6w_params_init(struct ra6w_core *core); +bool ra6w_params_regd_mode_is_auto(void); +int ra6w_params_regd_set_self(struct wiphy *wiphy); +bool ra6w_params_ps_supported(void); +bool ra6w_params_dpsm_enabled(void); +bool ra6w_params_amsdu_require_spp(void); +bool ra6w_params_ht_supported(void); +bool ra6w_params_vht_supported(void); +bool ra6w_params_he_supported(void); +bool ra6w_params_he_ul_on(void); +bool ra6w_params_wapi_supported(void); +bool ra6w_params_mfp_supported(void); +bool ra6w_params_ap_uapsd_enabled(void); +bool ra6w_params_tdls_supported(void); +bool ra6w_params_gcmp_supported(void); +bool ra6w_params_ccmp256_supported(void); +bool ra6w_params_bfmee_enabled(void); +bool ra6w_params_bfmer_enabled(void); +bool ra6w_params_ldpc_enabled(void); +bool ra6w_params_stbc_enabled(void); +u8 ra6w_params_bw_max_get(void); +bool ra6w_params_use_sgi(void); +bool ra6w_params_mu_mimo_rx_enabled(void); +bool ra6w_params_mu_mimo_tx_enabled(void); +bool ra6w_params_twt_enabled(void); +bool ra6w_params_ant_div(void); +u32 ra6w_params_log_level(void); +void ra6w_params_log_level_set(u32 log_level); +u8 ra6w_params_nss(void); +u8 ra6w_params_rx_amsdu_size(void); +u8 ra6w_params_mcs_map_range(void); +u8 ra6w_params_he_mcs_map_range(void); +u32 ra6w_params_uapsd_threshold(void); + +#endif /* RA6W_PARAMS_H */ From patchwork Thu Apr 17 13:52:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882851 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3744D24EF6A for ; Thu, 17 Apr 2025 13:54:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898057; cv=none; b=Zr4ZsZmlekCRcWgy3qZNOkzNXsSBq0lgWBDzxVx8j3I5ln2Oi5hT4bM3LOC8JKhdNsD/kd96kelbRa5vTlTXGgnhGqgToQhp7dsooBsL6xEErqUk8PG24a8rTCBx9Rr1gyJoBMHTY7O3ZQ1P7nHTZ1ZFAFdtbjoAP7HskNlLOwg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898057; c=relaxed/simple; bh=ZGE2x5odtT5fIcXumSEK7h+Mjw/eESosf6vPg8T/BvQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=qgZ/u/9qu5FTaPx6w8xMbV56xg/ywhXo+n+1jS81CwIIH4wlHllmsobmbyYPXG5q5yqMat24hDSIHGwDP+DRrJct6LNYyY7ebbFemDykdG973bv8gl61ZBiR7eUQjZwIXiNYysS3FOy21IDrHTz8Ns3qrPFpQv4fO26gwlw9mVs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: 8+joch4rQaeVqVWOL7SO/Q== X-CSE-MsgGUID: w1XTj++sSoWoU9JFW6+5Pg== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:15 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 9BDBB400E4E9; Thu, 17 Apr 2025 22:54:11 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 21/38] ra6w: add q.c Date: Thu, 17 Apr 2025 16:52:19 +0300 Message-Id: <20250417135236.52410-22-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/q.c | 134 ++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/q.c diff --git a/drivers/net/wireless/renesas/ra6w/q.c b/drivers/net/wireless/renesas/ra6w/q.c new file mode 100644 index 000000000000..74f1c3a8421b --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/q.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains queue API. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include +#include + +#include "q.h" + +bool ra6w_q_empty(struct ra6w_q *q) +{ + unsigned long flags = 0; + bool empty = 0; + + spin_lock_irqsave(&q->lock, flags); + empty = (CIRC_CNT(q->head, q->tail, q->max_count) == 0); + spin_unlock_irqrestore(&q->lock, flags); + + return empty; +} + +int ra6w_q_push(struct ra6w_q *q, void *buf) +{ + int ret = -ENOENT; + unsigned long head; + unsigned long tail; + unsigned long flags = 0; + + spin_lock_irqsave(&q->lock, flags); + + head = q->head; + tail = READ_ONCE(q->tail); + + if (CIRC_SPACE(head, tail, q->max_count) >= 1) { + q->buf[head] = buf; + WRITE_ONCE(q->head, (head + 1) & (q->max_count - 1)); + ret = 0; + } + + spin_unlock_irqrestore(&q->lock, flags); + + return ret; +} + +void *ra6w_q_pop(struct ra6w_q *q) +{ + void *buf = NULL; + unsigned long head; + unsigned long tail; + unsigned long flags = 0; + + spin_lock_irqsave(&q->lock, flags); + + head = READ_ONCE(q->head); + tail = q->tail; + + if (CIRC_CNT(head, tail, q->max_count) >= 1) { + buf = q->buf[tail]; + WRITE_ONCE(q->tail, (tail + 1) & (q->max_count - 1)); + } + + spin_unlock_irqrestore(&q->lock, flags); + + return buf; +} + +bool ra6w_q_event_condition(const struct ra6w_q_event *event, int event_mask, int *ret_event) +{ + *ret_event = atomic_read(&event->condition); + + return *ret_event & event_mask; +} + +void ra6w_q_event_set(struct ra6w_q_event *event, int event_val) +{ + atomic_or(event_val, &event->condition); + wake_up_interruptible(&event->wait_queue); +} + +int ra6w_q_wait(struct ra6w_q_event *event, int event_mask) +{ + int ret_event = 0; + + wait_event_interruptible(event->wait_queue, + ra6w_q_event_condition(event, event_mask, &ret_event)); + + return ret_event; +} + +int ra6w_q_wait_timeout(struct ra6w_q_event *event, int event_mask) +{ + int ret_event = 0; + + wait_event_interruptible_timeout(event->wait_queue, + ra6w_q_event_condition(event, event_mask, &ret_event), + msecs_to_jiffies(event->timeout)); + + return ret_event; +} + +int ra6w_q_init(struct ra6w_q *q, size_t max_count, size_t buf_size) +{ + q->head = 0; + q->tail = 0; + q->max_count = max_count; + spin_lock_init(&q->lock); + + q->buf = kcalloc(max_count, buf_size, GFP_KERNEL); + if (!q->buf) + return -ENOMEM; + + return 0; +} + +static void ra6w_q_free(struct ra6w_q *q) +{ + void *buf = NULL; + + while ((buf = ra6w_q_pop(q))) + kfree(buf); +} + +void ra6w_q_deinit(struct ra6w_q *q) +{ + ra6w_q_free(q); + kfree(q->buf); + q->head = 0; + q->tail = 0; + q->max_count = 0; + q->buf = NULL; +} From patchwork Thu Apr 17 13:52:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882265 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 536B624EAAE for ; Thu, 17 Apr 2025 13:54:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898061; cv=none; b=h8ddBqDzyuVY5WeToLJeHonn/MAxziujmxw17Nk1qOVskEepAo5suPNKV6+Ux7l7c8KddcU9ulJWQZOnJa2qYpGGlUsW57fWxCHEefU3DpLHlfuDZsI05ZPe1RF4VOlfcKinklGobo2EWDLJf//Za3iH4EHWAi4NIyFjBHawzZY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898061; c=relaxed/simple; bh=NSOjeTQzrSHltDuz0G3J6cqJ6L1wwx55nF/bgrlu4EU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=BgL/1KQH4Vcsx81oxsv8rOSxlFGFCUKQvfHugu7/Uz34cFxFe1XnZYBA7s/dWMeCioQBVB0a8P3lI1u9+Dkc3S7AEukuaeJs/dtH7c7SPsLvGDnURxMhJDUaUdg22Io75MXdwm9OKeNh27HYvQ1u7OH5Kj2LvauvrnXO3Ti9nXg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: m35NB3JERCK0sq45yyLlqg== X-CSE-MsgGUID: DMu9qfs7Si6kkMXp1EJs6g== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:19 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id BB54D400E4E9; Thu, 17 Apr 2025 22:54:15 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 22/38] ra6w: add q.h Date: Thu, 17 Apr 2025 16:52:20 +0300 Message-Id: <20250417135236.52410-23-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/q.h | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/q.h diff --git a/drivers/net/wireless/renesas/ra6w/q.h b/drivers/net/wireless/renesas/ra6w/q.h new file mode 100644 index 000000000000..5f8a165ae84d --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/q.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_Q_H +#define RA6W_Q_H + +#include +#include +#include +#include +#include + +struct ra6w_q { + size_t max_count; + unsigned long head; + unsigned long tail; + spinlock_t lock; + void **buf; +}; + +struct ra6w_q_event { + atomic_t condition; + wait_queue_head_t wait_queue; + u32 timeout; +}; + +int ra6w_q_init(struct ra6w_q *q, size_t max_count, size_t buf_size); +bool ra6w_q_empty(struct ra6w_q *q); +int ra6w_q_push(struct ra6w_q *q, void *buf); +void *ra6w_q_pop(struct ra6w_q *q); +void ra6w_q_event_set(struct ra6w_q_event *event, int event_val); +bool ra6w_q_event_condition(const struct ra6w_q_event *event, int event_mask, int *ret_event); +int ra6w_q_wait(struct ra6w_q_event *event, int event_mask); +int ra6w_q_wait_timeout(struct ra6w_q_event *event, int event_mask); +void ra6w_q_deinit(struct ra6w_q *q); + +#endif /* RA6W_Q_H */ From patchwork Thu Apr 17 13:52:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882850 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 02D0F24EF74 for ; Thu, 17 Apr 2025 13:54:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898065; cv=none; b=tPVVU+VbPt7LAmIggA6t/ODDr2Vz8tHw1jEgmWbMnAHjwuFjYmaLJBtPaNKD5EpYgd1KkJf2PfLEix/RW4tF0U3/SamusH8dXcvVAweKbkmHmv+xEyj6/5g7WlWFgpuxgqtDOkf6B2vSqntV3cV9tFVlK640h01YkhX0xQxGRpM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898065; c=relaxed/simple; bh=UMDOtzRzvuu7j3V3b7dl0F732n48pj5aVluYqrOoE+Y=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=GqAib15MkfRFvgXiOO3gwUj21/oO8vi6XqTJWSYwnZI7EmUp/tZaAGB2Y8OjGuQyH1QCx0Acg9rPnzhx+QONcfpTfncZviFwqxksFy7iQRNQFNCF+TUEkRuuCdZ8VX7J8tA4zePLP39iLt2stXTOFVmqyqkEDT80bUH19ATxBG4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: PY9MFCUORWa718VErTQ2fw== X-CSE-MsgGUID: Lh8+n+eETMCrbDzYc6ItHQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:23 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id DD160400E4E9; Thu, 17 Apr 2025 22:54:19 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 23/38] ra6w: add recovery.c Date: Thu, 17 Apr 2025 16:52:21 +0300 Message-Id: <20250417135236.52410-24-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/recovery.c | 87 ++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/recovery.c diff --git a/drivers/net/wireless/renesas/ra6w/recovery.c b/drivers/net/wireless/renesas/ra6w/recovery.c new file mode 100644 index 000000000000..5fc9a8cf42e5 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/recovery.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains recovery handler. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include "core.h" +#include "if.h" +#include "params.h" +#include "dbg.h" +#include "recovery.h" + +#define RA6W_RECOVERY_WQ_NAME "ra6w_recovery_wq" + +static bool ra6w_recovery_reprobe; + +void ra6w_recovery_reprobe_set(bool set) +{ + ra6w_recovery_reprobe = set; +} + +bool ra6w_recovery_reprobe_get(void) +{ + return ra6w_recovery_reprobe; +} + +void ra6w_recovery_event_post(struct ra6w_recovery *recovery) +{ + struct ra6w_core *core = container_of(recovery, struct ra6w_core, recovery); + + if (!recovery->wq) + return; + + if (recovery->in_recovery) + return; + + ra6w_ctrl_dev_hw_reset(&core->ctrl); + recovery->in_recovery = true; + + queue_work(recovery->wq, &recovery->work); +} + +static void ra6w_recovery_process(struct ra6w_recovery *recovery) +{ + struct ra6w_core *core = container_of(recovery, struct ra6w_core, recovery); + struct ra6w_if *ifp = container_of(core, struct ra6w_if, core); + + ra6w_info("recovery start\n"); + + ra6w_sdio_reprobe(ifp->dev.func); + + ra6w_recovery_reprobe_set(true); +} + +static void ra6w_recovery_handler(struct work_struct *work) +{ + struct ra6w_recovery *recovery = container_of(work, struct ra6w_recovery, work); + + ra6w_recovery_process(recovery); +} + +int ra6w_recovery_init(struct ra6w_recovery *recovery) +{ + struct workqueue_struct *wq; + + wq = create_singlethread_workqueue(RA6W_RECOVERY_WQ_NAME); + if (!wq) { + ra6w_err("[%s] create workqueue %s failed\n", __func__, RA6W_RECOVERY_WQ_NAME); + return -ENOENT; + } + + INIT_WORK(&recovery->work, ra6w_recovery_handler); + recovery->wq = wq; + + return 0; +} + +void ra6w_recovery_deinit(struct ra6w_recovery *recovery) +{ + cancel_work_sync(&recovery->work); + + if (recovery->wq) + destroy_workqueue(recovery->wq); + + recovery->wq = NULL; +} From patchwork Thu Apr 17 13:52:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882264 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 687D724EAA4 for ; Thu, 17 Apr 2025 13:54:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898069; cv=none; b=LMkbhl3FTXjlg6atsO8/6KQ4qZPir4vwxL9sYsyiqeO7gDnWYsQEfPk7podpzQrw11XxzfndKFaUaq+TDu8K4YmOsDq3j2pkqOsved1ktzLf6Ao6Cv/oi0AkUJqK3YNRIxdmsMBqphG1y9x9FPNZi4elmlJFTh+vw7MhJYtZwJk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898069; c=relaxed/simple; bh=jh8/0RPh0B4eDJn5iKI1DI3xPFh4teWxL6+cEnSCIRY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=N6nmHpIa1wcVxWOaw4nKwHovoX/bYmzrkwylQI7HTjFlA7/kmQFLNYJfgXMURQ+xWkwJduvshxeb/SpcV9XzZm9bHHAspuQ6yGVz3npCNKnZIARYoQe1OcloYqC1wO1Iz8+6TnjUCH40w5Vp43tQ2UDXEx91xxJBFPTihbY971E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: 76p1aJRtTVaq9MpVra/QAw== X-CSE-MsgGUID: w2X5boaPSzSO2pRuY1rWGQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:27 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 0986B400502F; Thu, 17 Apr 2025 22:54:23 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 24/38] ra6w: add recovery.h Date: Thu, 17 Apr 2025 16:52:22 +0300 Message-Id: <20250417135236.52410-25-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/recovery.h | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/recovery.h diff --git a/drivers/net/wireless/renesas/ra6w/recovery.h b/drivers/net/wireless/renesas/ra6w/recovery.h new file mode 100644 index 000000000000..bffe16d6e919 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/recovery.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_RECOVERY_H +#define RA6W_RECOVERY_H + +struct ra6w_recovery { + struct workqueue_struct *wq; + struct work_struct work; + bool in_recovery; +}; + +int ra6w_recovery_init(struct ra6w_recovery *recovery); +void ra6w_recovery_deinit(struct ra6w_recovery *recovery); +void ra6w_recovery_event_post(struct ra6w_recovery *recovery); +void ra6w_recovery_reprobe_set(bool set); +bool ra6w_recovery_reprobe_get(void); + +#endif /* RA6W_RECOVERY_H */ From patchwork Thu Apr 17 13:52:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882849 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id C15B524EF68 for ; Thu, 17 Apr 2025 13:54:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898073; cv=none; b=Bofre5JC16zfdZOAcJwMB1neGQqSk1SCLlkp2ywFc6czfB0I1xr6nw8Vdcp7zm2WB+G6I3xWByMWLd6blByq4Nn28W1S5bMw2AV3aM186cW0zsocYtJ+SKJcK7JtgnlDJVDWF0thTLiSstE1ftwx/KYdUxWR3jQ6Nvnn+HJ+RB8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898073; c=relaxed/simple; bh=9KB6aECXPbMLZqUEChtYKuv9mj2jKVbCMPNdcmPhoV0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=j/7lNNN18Sv6NW26BD/DeuY7Y6TollcKajVqXGLwOHbyUoOJIwtyyKqouFlxiGKYfimD2gQKK10wb78/x8DAqVM1/5bjcfLlswD0rs0xCnH7OPQEsSM8Pqvwb6EbjO7DtW1uokxHlKSbE2x3J0OqCFIGg5jUjbalOQxWbKaNFio= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: FiYkDQIwRuqT+DRSZmxHVQ== X-CSE-MsgGUID: i5uLOj4EQ+im9wfLBHk82w== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:31 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 30E2E400E4E9; Thu, 17 Apr 2025 22:54:27 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 25/38] ra6w: add rx.c Date: Thu, 17 Apr 2025 16:52:23 +0300 Message-Id: <20250417135236.52410-26-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/rx.c | 274 +++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/rx.c diff --git a/drivers/net/wireless/renesas/ra6w/rx.c b/drivers/net/wireless/renesas/ra6w/rx.c new file mode 100644 index 000000000000..9e2570938c88 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/rx.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains Rx routine. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include "core.h" +#include "dev.h" +#include "params.h" +#include "dbg.h" +#include "cfg80211.h" +#include "rx.h" + +#define RA6W_RX_THREAD_NAME "ra6w_rx_thread" + +static void ra6w_rx_update_stats(struct ra6w_cfg80211_vif *vif, const struct ra6w_rx_buf *rx_buf) +{ + struct ra6w_cfg80211_sta *sta = NULL; + struct ra6w_cfg80211_sta_stats *stats = NULL; + + sta = ra6w_cfg80211_sta_get(vif->priv, rx_buf->ext_hdr.sta_idx); + if (!sta) + return; + + stats = &sta->stats; + + sta->stats.last_acttive_time = jiffies; + stats->rx_packets++; + stats->rx_bytes += le16_to_cpu(rx_buf->data_len); + stats->last_rx_data_ext = rx_buf->ext_hdr; + + if (stats->last_rx_data_ext.format_mod > 1) + stats->last_stats = rx_buf->ext_hdr; + + ra6w_stats_rx_update(&vif->stats, stats); +} + +static int ra6w_rx_mgmt_set(struct ra6w_cfg80211_vif *vif, struct sk_buff *skb) +{ + struct net_device *ndev = vif->ndev; + struct ra6w_rx_buf *rx_buf = (struct ra6w_rx_buf *)skb->data; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx_buf->data; + + switch (vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + if (ieee80211_is_beacon(mgmt->frame_control)) { + struct wiphy *wiphy = vif->wdev.wiphy; + + if (!wiphy) + return -ENOENT; + + cfg80211_report_obss_beacon(wiphy, rx_buf->data, + le16_to_cpu(rx_buf->data_len), + rx_buf->ext_hdr.prim20_freq, + rx_buf->ext_hdr.rssi1); + + return 0; + } + + if (!ieee80211_is_deauth(mgmt->frame_control) && + !ieee80211_is_disassoc(mgmt->frame_control)) + break; + + if (mgmt->u.deauth.reason_code == + cpu_to_le16(WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA) || + mgmt->u.deauth.reason_code == + cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA)) { + cfg80211_rx_unprot_mlme_mgmt(ndev, rx_buf->data, + le16_to_cpu(rx_buf->data_len)); + + return 0; + } + break; + default: + break; + } + + cfg80211_rx_mgmt(&vif->wdev, rx_buf->ext_hdr.prim20_freq, rx_buf->ext_hdr.rssi1, + rx_buf->data, le16_to_cpu(rx_buf->data_len), 0); + + return 0; +} + +static void ra6w_rx_mgmt(struct ra6w_cfg80211_priv *priv, struct sk_buff *skb) +{ + struct ra6w_cfg80211_vif *vif = NULL; + struct net_device *ndev = NULL; + struct ra6w_rx_buf *rx_buf = (struct ra6w_rx_buf *)skb->data; + u8 vif_idx = rx_buf->ext_hdr.vif_idx; + int ret; + int len; + + if (vif_idx == RA6W_CFG80211_VIF_IDX_INVALID) { + u8 n = 0; + + n = find_first_bit(priv->vif_map, RA6W_CFG80211_VIF_MAX); + if (n >= RA6W_CFG80211_VIF_MAX) + return; + + vif_idx = n; + } + + vif = ra6w_cfg80211_vif_get(priv, vif_idx); + if (!vif) + return; + + ndev = vif->ndev; + + ra6w_rx_update_stats(vif, rx_buf); + + len = le16_to_cpu(rx_buf->data_len); + ret = ra6w_rx_mgmt_set(vif, skb); + if (ret) { + ndev->stats.rx_errors++; + ndev->stats.rx_dropped++; + } else { + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; + } +} + +static void ra6w_rx_sta(struct ra6w_cfg80211_priv *priv, struct sk_buff *skb) +{ + struct ra6w_cfg80211_vif *vif = NULL; + struct net_device *ndev = NULL; + struct ra6w_rx_buf *rx_buf = (struct ra6w_rx_buf *)skb->data; + int ret; + int len; + + vif = ra6w_cfg80211_vif_get(priv, rx_buf->ext_hdr.vif_idx); + if (!vif) { + dev_kfree_skb(skb); + return; + } + + ndev = vif->ndev; + + skb->len = RA6W_GET_DATA_SIZE(rx_buf->ext_len, le16_to_cpu(rx_buf->data_len)); + skb_pull(skb, rx_buf->ext_len + RA6W_BASE_HDR_SIZE); + skb->dev = ndev; + skb->priority = rx_buf->ext_hdr.priority; + skb->protocol = eth_type_trans(skb, skb->dev); + + ra6w_rx_update_stats(vif, rx_buf); + + len = skb->len; + ret = netif_rx(skb); + if (ret) { + ndev->stats.rx_errors++; + ndev->stats.rx_dropped++; + } else { + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; + } +} + +static void ra6w_rx_skb(struct ra6w_rx *rx, struct sk_buff *skb) +{ + struct ra6w_core *core = container_of(rx, struct ra6w_core, rx); + struct ra6w_cfg80211_priv *priv = core->priv; + struct ra6w_rx_buf *rx_buf = (struct ra6w_rx_buf *)skb->data; + + core->stats.rx.packets++; + + if (rx_buf->ext_hdr.mpdu == 0) { + ra6w_rx_sta(priv, skb); + return; + } + + ra6w_rx_mgmt(priv, skb); + dev_kfree_skb(skb); +} + +static void ra6w_rx_worker(struct ra6w_rx *rx) +{ + struct sk_buff *skb = NULL; + + while (!kthread_should_stop() && (skb = ra6w_q_pop(&rx->q))) + ra6w_rx_skb(rx, skb); +} + +static int ra6w_rx_thread_handler(void *arg) +{ + struct ra6w_rx *rx = arg; + int event = 0; + + while (!kthread_should_stop()) { + event = ra6w_q_wait(&rx->event, RA6W_RX_EVENT_MASK); + if (event & BIT(RA6W_RX_DATA_EVENT)) + ra6w_rx_worker(rx); + + if (event & BIT(RA6W_RX_EVENT_RESET)) + break; + + atomic_set(&rx->event.condition, 0); + } + + return 0; +} + +static int _ra6w_rx_init(struct ra6w_rx *rx, size_t rx_buf_num) +{ + int ret = -ENOENT; + + if (rx_buf_num == 0) { + ra6w_err("[%s] rx queue size must be greater then zero\n", __func__); + return -EINVAL; + } + + ret = ra6w_q_init(&rx->q, rx_buf_num, sizeof(struct ra6w_rx_buf *)); + if (ret) + return ret; + + atomic_set(&rx->event.condition, 0); + init_waitqueue_head(&rx->event.wait_queue); + + rx->task = kthread_run(ra6w_rx_thread_handler, rx, RA6W_RX_THREAD_NAME); + if (!rx->task) { + ra6w_err("[%s] kthread_run %s failed\n", __func__, RA6W_RX_THREAD_NAME); + ret = -ENOENT; + + goto rx_buf_free; + } + + return 0; + +rx_buf_free: + ra6w_q_deinit(&rx->q); + + return ret; +} + +int ra6w_rx_init(struct ra6w_rx *rx) +{ + return _ra6w_rx_init(rx, RA6W_RX_BUF_Q_MAX); +} + +int ra6w_rx_event_post(struct ra6w_rx *rx, struct sk_buff *skb) +{ + struct ra6w_core *core = container_of(rx, struct ra6w_core, rx); + struct ra6w_rx_buf *rx_buf = (struct ra6w_rx_buf *)skb->data; + int ret; + + if (rx_buf->ext_len != RA6W_RX_EXT_LEN) { + core->stats.rx.err++; + return -EINVAL; + } + + ra6w_status_set(&core->status, rx_buf->ext_hdr.status); + + if (rx_buf->data_len == 0) { + core->stats.rx.err++; + return -EINVAL; + } + + ret = ra6w_q_push(&rx->q, skb); + if (!ret || !ra6w_q_empty(&rx->q)) + ra6w_q_event_set(&rx->event, BIT(RA6W_RX_DATA_EVENT)); + + return ret; +} + +void ra6w_rx_deinit(struct ra6w_rx *rx) +{ + if (rx->task) { + atomic_set(&rx->event.condition, BIT(RA6W_RX_EVENT_RESET)); + kthread_stop(rx->task); + } + + ra6w_q_deinit(&rx->q); +} From patchwork Thu Apr 17 13:52:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882263 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6B64324EF68 for ; Thu, 17 Apr 2025 13:54:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898078; cv=none; b=NCTIz01JIO5Al4zbHnTb7Ekh+GNLAZXFh0acAYnEWgpqhbGuOCA/hg5Q2od/cIf88R2MawoBgehi/RD5WR8AS+khdO0D1uSK+o9EQKG7Z+fDaS9F0CZ4CjHe6zSMNhYqClSqHCZImjGQcmWj/e84JPkEnWFmrMqXFojr+ikExck= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898078; c=relaxed/simple; bh=0XKVgpu8jNkoQSoN0pPT9F308cU1ywVApeYhChk4NDs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=k9/Mc4itLF0CwExXY9qCXZT/+h53Fc3cNhhq+ohaGivWN/mDqrt3/5GN6gCCXIUN8R+VKTE3mVrIKAq00XAWelIvtV974AlaArKch52fez4mr4q0jVi10WjBPFj9YZD+O5MIp4U67b/r8RI9XoBzAP5JUndX9oQ7YFNrIiCgcAA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: 0AoczfFCSd6x9Z/aVSHsBg== X-CSE-MsgGUID: IM3ez+KcQM6SO6j3zVWP1A== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:35 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 521AC401009B; Thu, 17 Apr 2025 22:54:31 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 26/38] ra6w: add rx.h Date: Thu, 17 Apr 2025 16:52:24 +0300 Message-Id: <20250417135236.52410-27-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/rx.h | 105 +++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/rx.h diff --git a/drivers/net/wireless/renesas/ra6w/rx.h b/drivers/net/wireless/renesas/ra6w/rx.h new file mode 100644 index 000000000000..10ee61b3ed6f --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/rx.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_RX_H +#define RA6W_RX_H + +#include + +#include "q.h" + +#define RA6W_RX_EXT_LEN (sizeof(struct ra6w_rx_ext_hdr)) +#define RA6W_RX_BUF_Q_MAX 64 + +enum ra6w_rx_ext_hdr_flags { + RA6W_EXT_FLAGS_MGMT_BIT = BIT(1), + RA6W_EXT_FLAGS_MGMT_NO_CCK_BIT = BIT(2), + RA6W_EXT_FLAGS_AMSDU_BIT = BIT(3), + RA6W_EXT_FLAGS_MGMT_ROBUST_BIT = BIT(4), + RA6W_EXT_FLAGS_4ADDR_BIT = BIT(5), + RA6W_EXT_FLAGS_EOSP_BIT = BIT(6), + RA6W_EXT_FLAGS_MESH_FWD_BIT = BIT(7), + RA6W_EXT_FLAGS_TDLS_BIT = BIT(8), + RA6W_EXT_FLAGS_SN_BIT = BIT(9) +}; + +struct ra6w_rx_ext_ht { + u16 short_gi : 1; + u16 mcs : 7; + u16 num_extn_ss : 2; + u16 reserved : 6; +}; + +struct ra6w_rx_ext_vht { + u16 short_gi : 1; + u16 mcs : 7; + u16 nss : 3; + u16 reserved : 5; +}; + +struct ra6w_rx_ext_he { + u16 ru_size : 3; + u16 mcs : 7; + u16 nss : 3; + u16 gi_type : 2; + u16 dcm : 1; +}; + +struct ra6w_rx_ext_hdr { + u32 status : 32; + u32 amsdu : 1; + u32 mpdu : 1; + u32 addr_4 : 1; + u32 mesh_peer_new : 1; + u32 priority : 3; + u32 vif_idx : 8; + u32 sta_idx : 8; + u32 dest_sta_idx : 8; + u32 ch_bw : 2; + u32 rssi1 : 8; + u32 band : 4; + u32 channel_type : 8; + u32 prim20_freq : 16; + u32 center1_freq : 16; + u32 center2_freq : 16; + u32 format_mod : 4; + u32 pre_type : 1; + u32 leg_rate : 4; + + union { + struct ra6w_rx_ext_ht ht; + struct ra6w_rx_ext_vht vht; + struct ra6w_rx_ext_he he; + }; +}; + +struct ra6w_rx_buf { + u8 cmd; + u8 ext_len; + __le16 data_len; + struct ra6w_rx_ext_hdr ext_hdr; + u8 data[RA6W_CMD_DATA_SIZE]; +}; + +enum ra6w_rx_data_event { + RA6W_RX_DATA_EVENT, + + RA6W_RX_DATA_EVENT_MAX, +}; + +#define RA6W_RX_EVENT_RESET RA6W_RX_DATA_EVENT_MAX +#define RA6W_RX_EVENT_MASK (BIT(RA6W_RX_DATA_EVENT) | BIT(RA6W_RX_EVENT_RESET)) + +struct ra6w_rx { + struct task_struct *task; + struct ra6w_q_event event; + struct ra6w_q q; +}; + +int ra6w_rx_init(struct ra6w_rx *rx); +void ra6w_rx_deinit(struct ra6w_rx *rx); +int ra6w_rx_event_post(struct ra6w_rx *rx, struct sk_buff *skb); + +#endif /* RA6W_RX_H */ From patchwork Thu Apr 17 13:52:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882848 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E647124EAB2 for ; Thu, 17 Apr 2025 13:54:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898083; cv=none; b=C61veI1t73zN7zYFX50GggnwPp9pNMFqne+WhJg1/Z0gam2WwwCx+G2fnVP67uKmRy7m8Ba2Ol6+SZ2SYSDUtU9OLaCAHDjeXpmv86HufloAni4EiyjGRm5yypp8n3fRecWpHLDBsUi3v9WiUu6fmZ+V5ixeoAxAuFhXpobbyIA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898083; c=relaxed/simple; bh=/78LeKjIAwQnUbprAiO7aIoBuBnoLYS8SJx6Ep2wwgI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=b00jqy1MCV16jee05a81QPOv3Fa5C0bQ4bX/tl/pVJ6NJ+EN7QThGRGXD/VFc3jSuMLhV5M0GzoER7Sd5NWt9y0NDU/NOnOkjkXM0r2ABem7iJsWDMkWRuk4dyOG3krC6tndqd2SAjsg9po8tr6I/I0f9ViN84ohQBC5XNgtBI4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: fHV8+fpkRtufsJT7wSFvrQ== X-CSE-MsgGUID: BfPx31IRR/OvmmWdBYQiTQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:39 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 74C6A400E4E9; Thu, 17 Apr 2025 22:54:36 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 27/38] ra6w: add sdio.c Date: Thu, 17 Apr 2025 16:52:25 +0300 Message-Id: <20250417135236.52410-28-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/sdio.c | 505 +++++++++++++++++++++++ 1 file changed, 505 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/sdio.c diff --git a/drivers/net/wireless/renesas/ra6w/sdio.c b/drivers/net/wireless/renesas/ra6w/sdio.c new file mode 100644 index 000000000000..b2f31a4019f2 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/sdio.c @@ -0,0 +1,505 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains SDIO operations. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include +#include +#include +#include +#include + +#include "core.h" +#include "if.h" +#include "cfg80211.h" +#include "params.h" +#include "dbg.h" + +void ra6w_sdio_reprobe(struct sdio_func *func) +{ + func->card->host->rescan_disable = 0; + + mmc_detect_change(func->card->host, msecs_to_jiffies(100)); +} + +static void ra6w_sdio_irq_handler(struct sdio_func *func) +{ + struct ra6w_if *ifp = sdio_get_drvdata(func); + struct ra6w_core *core = &ifp->core; + int ret = 0; + u8 reg = 0; + + reg = sdio_readb(func, SDIO_CCCR_CAPS, &ret); + if (ret) { + ra6w_err("SDIO_CCCR_CAP read failed: %d\n", ret); + return; + } + + sdio_writeb(func, reg, SDIO_CCCR_CAPS, &ret); + if (ret) { + ra6w_err("SDIO_CCCR_CAPS write failed: %d\n", ret); + return; + } + + ra6w_q_event_set(&core->event, BIT(RA6W_CORE_EVENT_DATA)); +} + +static int ra6w_sdio_enable_irq(struct sdio_func *func) +{ + int ret = 0; + u8 reg = 0; + + sdio_claim_host(func); + + reg = sdio_f0_readb(func, SDIO_CCCR_IENx, &ret); + if (ret) { + ra6w_err("SDIO_CCCR_IENx read failed: %d\n", ret); + goto release_host; + } + + func->num = 0; + reg |= BIT(func->num); + sdio_writeb(func, reg, SDIO_CCCR_IENx, &ret); + if (ret) { + ra6w_err("SDIO_CCCR_IENx write failed: reg=0x%x ret=%d\n", reg, ret); + goto release_host; + } + + sdio_writeb(func, SDIO_CCCR_CAP_E4MI, SDIO_CCCR_CAPS, &ret); + if (ret) { + ra6w_err("SDIO_CCCR_CAPS write failed: SDIO_CCCR_CAP_E4MI ret=%d\n", ret); + goto release_host; + } + + func->num = 1; + sdio_writeb(func, SDIO_CCCR_CAP_SRW, SDIO_CCCR_CIS, &ret); + if (ret) { + ra6w_err("SDIO_CCCR_CIS write failed: SDIO_CCCR_CAP_SRW ret=%d\n", ret); + goto release_host; + } + + ret = sdio_claim_irq(func, ra6w_sdio_irq_handler); + if (ret) + ra6w_err("sdio_claim_irq failed: %d\n", ret); + +release_host: + sdio_release_host(func); + + return ret; +} + +static void ra6w_sdio_disable_irq(struct sdio_func *func) +{ + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); +} + +static int ra6w_sdio_init(struct sdio_func *func) +{ + int ret = 0; + u8 reg = 0; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) { + ra6w_err("sdio func enable failed: %d\n", ret); + goto release_host; + } + + ret = sdio_set_block_size(func, RA6W_SDIO_BLOCK_SIZE); + if (ret) { + ra6w_err("sdio func set block size failed: %d\n", ret); + goto release_host; + } + + reg = sdio_f0_readb(func, SDIO_CCCR_CAPS, &ret); + if (ret) { + ra6w_err("SDIO_CCCR_CAPS read failed: %d\n", ret); + goto release_host; + } + + reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); + if (ret) { + ra6w_err("SDIO_CCCR_IF read failed: %d\n", ret); + goto release_host; + } + + reg = SDIO_BUS_WIDTH_4BIT | SDIO_BUS_CD_DISABLE; + func->num = 0; + sdio_writeb(func, reg, SDIO_CCCR_IF, &ret); + +release_host: + sdio_release_host(func); + + return ret; +} + +static int ra6w_sdio_read(struct sdio_func *func, void *data, int len) +{ + int ret; + int chunk; + + sdio_claim_host(func); + + chunk = sdio_align_size(func, len); + ret = sdio_readsb(func, data, RA6W_SDIO_ADDR_READ, chunk); + + sdio_release_host(func); + + return ret; +} + +static int ra6w_sdio_write(struct sdio_func *func, void *data, int len) +{ + int ret; + int chunk; + + sdio_claim_host(func); + + chunk = sdio_align_size(func, len); + ret = sdio_writesb(func, RA6W_SDIO_ADDR_WRITE, data, chunk); + + sdio_release_host(func); + + return ret; +} + +static int ra6w_sdio_write_crc32(struct sdio_func *func, const struct firmware *fw) +{ + u32 img_crc; + u32 msg_data; + int i; + int ret = 0; + + /* send CRC */ + img_crc = crc32_le(~0U, fw->data, fw->size); + img_crc ^= ~0U; + ra6w_dbg("wifi FW CRC is %08x\n", img_crc); + + sdio_writel(func, img_crc, RA6W_SDIO_HOST_GP_REG, &ret); + if (ret) { + ra6w_err("CRC32 write failed: %d\n", ret); + return ret; + } + + /* Check CRC */ + for (i = 0; i < RA6W_SDIO_CRC_CHECK_RETRY_MAX; i++) { + msg_data = sdio_readl(func, RA6W_SDIO_CHIP_GP_REG, &ret); + if (ret) + return ret; + + if (msg_data == RA6W_SDIO_CODE_CRC_CHECKING) { + usleep_range(RA6W_SDIO_CRC_CHECK_SLEEP_MIN_US, + RA6W_SDIO_CRC_CHECK_SLEEP_MAX_US); + continue; + } + + if (msg_data == RA6W_SDIO_CODE_SUCCESS) + return 0; + + if (msg_data == RA6W_SDIO_CODE_BOOT_NG) { + ra6w_info("CRC32 write failed: 0x%x\n", RA6W_SDIO_CODE_BOOT_NG); + return -ENOENT; + } + } + + return 0; +} + +static int ra6w_sdio_fw_ack(struct sdio_func *func) +{ + u32 msg_data; + int i; + int ret; + + for (i = 0; i < RA6W_SDIO_ACK_CNT_MAX; i++) { + msg_data = sdio_readl(func, RA6W_SDIO_CHIP_GP_REG, &ret); + if (ret) + return ret; + + if (msg_data == RA6W_SDIO_CODE_SUCCESS) + break; + } + + return 0; +} + +static int ra6w_sdio_fw_wait_sync(struct sdio_func *func) +{ + u16 blk_size; + u8 reg; + int i; + int ret; + + for (i = 0; i < RA6W_SDIO_WAIT_SYNC_CNT_MAX; i++) { + reg = sdio_f0_readb(func, 0x110, &ret); + if (ret) + return ret; + + blk_size = reg; + reg = sdio_f0_readb(func, 0x111, &ret); + if (ret) + return ret; + + blk_size |= reg << 8; + msleep(50); + if (blk_size == RA6W_SDIO_BLOCK_SIZE) + break; + } + + return 0; +} + +static int _ra6w_sdio_fw_upload(struct sdio_func *func, const struct firmware *fw) +{ + u32 iteration; + u32 remain_len; + u8 *fw_buf = NULL; + int i; + int ret = 0; + + fw_buf = devm_kmalloc(&func->dev, RA6W_SDIO_BLOCK_SIZE, GFP_KERNEL); + if (!fw_buf) + return -ENOMEM; + + func->num = 1; + sdio_claim_host(func); + + sdio_writel(func, fw->size, RA6W_SDIO_HOST_GP_REG, &ret); + if (ret) { + ra6w_err("Write fw size failed: %d\n", ret); + goto release_host; + } + + ret = ra6w_sdio_fw_ack(func); + if (ret) + goto release_host; + + iteration = RA6W_SDIO_GET_CNT(fw->size, RA6W_SDIO_BLOCK_SIZE); + for (i = 0; i < iteration; i++) { + memcpy(fw_buf, &fw->data[i * RA6W_SDIO_BLOCK_SIZE], RA6W_SDIO_BLOCK_SIZE); + ret = sdio_writesb(func, 0, fw_buf, RA6W_SDIO_BLOCK_SIZE); + if (ret) + goto release_host; + } + + remain_len = RA6W_SDIO_GET_REMAIN(fw->size, RA6W_SDIO_BLOCK_SIZE); + memcpy(fw_buf, &fw->data[i * RA6W_SDIO_BLOCK_SIZE], remain_len); + ret = sdio_writesb(func, 0, fw_buf, remain_len); + if (ret) + goto release_host; + + ret = ra6w_sdio_write_crc32(func, fw); + if (ret) + goto release_host; + + func->num = 0; + + ra6w_sdio_fw_wait_sync(func); + +release_host: + sdio_release_host(func); + devm_kfree(&func->dev, fw_buf); + + return ret; +} + +static int ra6w_sdio_fw_upload(struct sdio_func *func) +{ + int ret; + char path[100] = { 0 }; + const struct firmware *fw = NULL; + + snprintf(path, sizeof(path), "%s/%s", KBUILD_MODNAME, RA6W_SDIO_FW_NAME); + + ra6w_info("F/W uploading...\n"); + + ret = request_firmware(&fw, path, &func->dev); + if (ret) { + ra6w_err("[%s] request_firmware %s failed: %d\n", __func__, path, ret); + return ret; + } + + ret = _ra6w_sdio_fw_upload(func, fw); + + ra6w_info("F/W uploading %s\n", ret ? "failed" : "done"); + + release_firmware(fw); + + return ret; +} + +static void ra6w_sdio_host_reset(struct sdio_func *func) +{ + int err = 0; + + sdio_claim_host(func); + sdio_writel(func, RA6W_SDIO_ADDR_RESET, RA6W_SDIO_HOST_GP_REG, &err); + sdio_release_host(func); +} + +static const struct ra6w_if_ops ra6w_if_sdio_ops = { + .read = ra6w_sdio_read, + .write = ra6w_sdio_write, +}; + +static int ra6w_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret; + struct ra6w_if *ifp = NULL; + struct ra6w_core *core = NULL; + + ifp = kzalloc(sizeof(*ifp), GFP_KERNEL); + if (!ifp) + return -ENOMEM; + + ifp->dev.func = func; + + ifp->ops = &ra6w_if_sdio_ops; + + sdio_set_drvdata(func, ifp); + + ret = ra6w_sdio_init(func); + if (ret) + goto free_ifp; + + sdio_claim_host(func); + func->card->host->rescan_disable = 1; + sdio_release_host(func); + + ret = ra6w_sdio_fw_upload(func); + if (ret) + goto free_ifp; + + core = &ifp->core; + + ret = ra6w_core_init(core); + if (ret) + goto free_ifp; + + ret = ra6w_sdio_enable_irq(func); + if (ret) + goto core_deinit; + + ret = ra6w_core_post_init(core); + if (ret) + goto core_deinit; + + ret = ra6w_params_init(core); + if (ret) + goto core_deinit; + + ret = ra6w_cfg80211_init(core, &func->dev); + if (ret) + goto core_deinit; + + ret = ra6w_recovery_init(&core->recovery); + if (ret) + goto cfg80211_deinit; + + return 0; + +cfg80211_deinit: + ra6w_cfg80211_deinit(core); + +core_deinit: + ra6w_core_deinit(core); + ra6w_sdio_host_reset(func); + ra6w_sdio_disable_irq(func); + +free_ifp: + kfree(ifp); + + return ret; +} + +static void ra6w_sdio_remove(struct sdio_func *func) +{ + struct ra6w_if *ifp = sdio_get_drvdata(func); + struct ra6w_core *core = &ifp->core; + + ra6w_recovery_deinit(&core->recovery); + + ra6w_cfg80211_deinit(core); + ra6w_sdio_disable_irq(func); + ra6w_core_deinit(core); + ra6w_sdio_host_reset(func); + + sdio_claim_host(func); + func->card->host->rescan_disable = 0; + sdio_disable_func(func); + sdio_release_host(func); + + mmc_detect_change(func->card->host, msecs_to_jiffies(100)); + + ifp->dev.func = NULL; + + kfree(ifp); +} + +static struct sdio_device_id ra6w_sdio_device_id[] = { + { SDIO_DEVICE(RA6W_SDIO_VENDOR_ID_RENESAS, RA6W_SDIO_DEVICE_ID_RA6W) }, + {}, +}; + +MODULE_DEVICE_TABLE(sdio, ra6w_sdio_device_id); + +#ifdef CONFIG_PM +static int ra6w_sdio_suspend(struct device *device) +{ + struct sdio_func *func = dev_to_sdio_func(device); + struct ra6w_if *ifp = sdio_get_drvdata(func); + mmc_pm_flag_t flags; + s32 ret = 0; + + ifp->dev.dev_on_resume = false; + + flags = sdio_get_host_pm_caps(func); + if (!(flags & MMC_PM_KEEP_POWER)) { + dev_err(device, "%s: cannot remain alive while host is suspended\n", + sdio_func_id(func)); + return -EINVAL; + } + + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (ret) + return ret; + + return sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); +} + +static int ra6w_sdio_resume(struct device *device) +{ + const struct sdio_func *func = dev_to_sdio_func(device); + struct ra6w_if *ifp = sdio_get_drvdata(func); + + ifp->dev.dev_on_resume = true; + + return 0; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops ra6w_sdio_pm_ops = { + SYSTEM_SLEEP_PM_OPS(ra6w_sdio_suspend, ra6w_sdio_resume) +}; + +static struct sdio_driver ra6w_sdio_driver = { + .name = KBUILD_MODNAME, + .id_table = ra6w_sdio_device_id, + .probe = ra6w_sdio_probe, + .remove = ra6w_sdio_remove, + .drv = { + .owner = THIS_MODULE, + .pm = &ra6w_sdio_pm_ops + } +}; + +module_sdio_driver(ra6w_sdio_driver); + +MODULE_DESCRIPTION("Renesas 11ax driver for Linux"); +MODULE_AUTHOR("Alexander Savchenko "); +MODULE_LICENSE("GPL"); From patchwork Thu Apr 17 13:52:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882262 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9D6B824EABF for ; Thu, 17 Apr 2025 13:54:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898086; cv=none; b=BhWSuAADSEq1GrTfTqcWNamD0vK4TSo+8zxFqiP7aZnV+K26AhUBFGBV65OfSdz7CDAnaNxt3LxbiwNvnRldCRbHQfzDQasvdG3fBsbyJLVrttCbbVKXExGf9dGPbLOIfwGdOv88c5+jR20TnifvHQy0CNLNuxO/Ip7x+AmdLzQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898086; c=relaxed/simple; bh=CSv+Y7Ei5d0ps/8dtEgtZloQ+D8G/rpyNduaZ4hDX0Y=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=dslbqLKogncMnjapB2fXsW8GE1Ld9KkQ0/PWpveH37Avx2PgzY4xsX3mH5M6ExyYuL8p3h4GxdAstLHSA+1E+EJQS6HBIz/iLufAXrj9Zk0LfNeYC+ecBxkeaWCjD7nsWRKcgW6yHqXDY7/ZsdcOvIMyDSnMQ+No+2h0aehzeWA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: iG2QPO3NQYiM1oKaC5dFWw== X-CSE-MsgGUID: WbAol+0DSPaG4HCLU8t37Q== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:44 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 9F61F401009B; Thu, 17 Apr 2025 22:54:40 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 28/38] ra6w: add sdio.h Date: Thu, 17 Apr 2025 16:52:26 +0300 Message-Id: <20250417135236.52410-29-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/sdio.h | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/sdio.h diff --git a/drivers/net/wireless/renesas/ra6w/sdio.h b/drivers/net/wireless/renesas/ra6w/sdio.h new file mode 100644 index 000000000000..6b7d0c7d7bbc --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/sdio.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_SDIO_H +#define RA6W_SDIO_H + +#include + +#define RA6W_SDIO_VENDOR_ID_RENESAS 0x5245 +#define RA6W_SDIO_DEVICE_ID_RA6W 0x4154 +#define RA6W_SDIO_MAX_BLOCK_CNT 5 +#define RA6W_SDIO_BLOCK_SIZE 512 +#define RA6W_SDIO_HOST_GP_REG 0x24 +#define RA6W_SDIO_CHIP_GP_REG 0x28 +#define RA6W_SDIO_CODE_SUCCESS 0x00022000 +#define RA6W_SDIO_CODE_CRC_CHECKING 0xf0f0f0f0 +#define RA6W_SDIO_CODE_BOOT_NG 0x20000002 +#define RA6W_SDIO_ADDR_RESET 0xdeadffff +#define RA6W_SDIO_ADDR_READ 0x0001 +#define RA6W_SDIO_ADDR_WRITE 0x0002 +#define RA6W_SDIO_ADDR_STATUS 0x0010 + +#define RA6W_SDIO_FW_NAME "fmacfw_sdio.bin" + +#define RA6W_SDIO_GET_CNT(len, blk_size) (((u32)(len)) / (blk_size)) +#define RA6W_SDIO_GET_REMAIN(len, blk_size) (((u32)(len)) % (blk_size)) + +#define RA6W_SDIO_ACK_CNT_MAX 10 +#define RA6W_SDIO_WAIT_SYNC_CNT_MAX 20 +#define RA6W_SDIO_CRC_CHECK_RETRY_MAX 20 +#define RA6W_SDIO_CRC_CHECK_SLEEP_MIN_US 10000 +#define RA6W_SDIO_CRC_CHECK_SLEEP_MAX_US 11000 + +void ra6w_sdio_reprobe(struct sdio_func *func); + +#endif /* RA6W_SDIO_H */ From patchwork Thu Apr 17 13:52:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882847 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 517A724EF65 for ; Thu, 17 Apr 2025 13:54:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898090; cv=none; b=F4PW5Nf2fEF16hN60JHPQU97tMzIZZuakrMQlVt3Xb1gwr6QMaFwDW1E1HXSfKaNnDSst0ONyjYeQ5L7MziKEPgivKhP9lloiw+S17FHMMM2lbEFBZKzwhkj3PJAxkJssRS4QOASQD/hgM269TNA15Ub8kK3o17nijEDXiOD4ds= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898090; c=relaxed/simple; bh=xsGy+CsTNezAQ4ZpyUr/x2RHI7fB+scq/QNYJxp4cAI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=WzF5SRx103HtbVtIz3rShyuYPvDPwR6dEWrOfFx4lTKUaTej/TaQEjkw+5QpNNi3zaIVnQPb6VrNeqgLGYkKVJoM/MBOwIRBnWE8ZSCDD7w1HaX5SYaWQWhDjGCZDpnVcMsYYMrCO1f8woU4/eopCrNEUaE3p9i1k1DEib1NxIk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: arPeOXFyRF6Qqppt3yjC3Q== X-CSE-MsgGUID: l3S3cntbSWeNWeqDKTGQLw== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:48 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id BF38940103A8; Thu, 17 Apr 2025 22:54:44 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 29/38] ra6w: add stats.c Date: Thu, 17 Apr 2025 16:52:27 +0300 Message-Id: <20250417135236.52410-30-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/stats.c | 94 +++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/stats.c diff --git a/drivers/net/wireless/renesas/ra6w/stats.c b/drivers/net/wireless/renesas/ra6w/stats.c new file mode 100644 index 000000000000..59f431b3f158 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/stats.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains statistics routine. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include "cfg80211.h" +#include "stats.h" + +void ra6w_stats_rx_update(struct ra6w_stats *stats, + const struct ra6w_cfg80211_sta_stats *sta_stats) +{ + struct ra6w_stats_rx *rx_stats = stats->rx_stats; + const struct ra6w_rx_ext_hdr *last_rx = &sta_stats->last_rx_data_ext; + + if (!stats->stats_enabled || !rx_stats) + return; + + rx_stats->format_mode = last_rx->format_mod; + + switch (last_rx->format_mod) { + case RA6W_CFG80211_FORMATMOD_NON_HT: + rx_stats->flags |= RA6W_STATS_RX_OFDM_BIT; + rx_stats->non_ht.ofdm++; + fallthrough; + case RA6W_CFG80211_FORMATMOD_NON_HT_DUP_OFDM: + rx_stats->flags |= RA6W_STATS_RX_CCK_BIT; + rx_stats->non_ht.cck++; + rx_stats->non_ht.bw = last_rx->ch_bw; + break; + case RA6W_CFG80211_FORMATMOD_HT_MF: + case RA6W_CFG80211_FORMATMOD_HT_GF: + rx_stats->flags |= RA6W_STATS_RX_HT_BIT; + rx_stats->ht.bw = last_rx->ch_bw & 0x1; + rx_stats->ht.nss = last_rx->ht.num_extn_ss & 0x3; + rx_stats->ht.mcs = last_rx->ht.mcs & 0x7; + rx_stats->ht.gi = last_rx->ht.short_gi & 0x1; + rx_stats->ht.ht[rx_stats->ht.gi][rx_stats->ht.mcs]++; + break; + case RA6W_CFG80211_FORMATMOD_VHT: + rx_stats->flags |= RA6W_STATS_RX_VHT_BIT; + rx_stats->vht.bw = last_rx->ch_bw; + rx_stats->vht.nss = last_rx->vht.nss; + rx_stats->vht.mcs = last_rx->vht.mcs; + rx_stats->vht.gi = last_rx->vht.short_gi & 0x1; + rx_stats->vht.vht[rx_stats->vht.gi][rx_stats->vht.mcs]++; + break; + case RA6W_CFG80211_FORMATMOD_HE_MU: + case RA6W_CFG80211_FORMATMOD_HE_SU: + case RA6W_CFG80211_FORMATMOD_HE_ER: + case RA6W_CFG80211_FORMATMOD_HE_TB: + rx_stats->flags |= RA6W_STATS_RX_HE_SU_BIT; + rx_stats->he_su.mcs = last_rx->he.mcs; + rx_stats->he_su.nss = last_rx->he.nss; + rx_stats->he_su.gi = last_rx->he.gi_type; + rx_stats->he_su.he[rx_stats->he_su.gi][rx_stats->he_su.mcs]++; + break; + default: + break; + } +} + +int ra6w_stats_init(struct ra6w_stats *stats) +{ + struct ra6w_stats_rx *rx_stats = NULL; + + if (stats->stats_enabled) + return 0; + + rx_stats = kzalloc(sizeof(*rx_stats), GFP_KERNEL); + if (!rx_stats) + return -ENOMEM; + + stats->rx_stats = rx_stats; + stats->stats_enabled = true; + + return 0; +} + +void ra6w_stats_deinit(struct ra6w_stats *stats) +{ + struct ra6w_cfg80211_vif *vif = container_of(stats, struct ra6w_cfg80211_vif, stats); + struct ra6w_cfg80211_priv *priv = vif->priv; + + if (!stats->stats_enabled) + return; + + ra6w_ctrl_stats_tx_start_req(&priv->core->ctrl, RA6W_STATS_TX_STOP_BIT); + + stats->stats_enabled = false; + kfree(stats->rx_stats); + stats->rx_stats = NULL; +} From patchwork Thu Apr 17 13:52:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882261 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8097624EA9C for ; Thu, 17 Apr 2025 13:54:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898094; cv=none; b=bmdRdSSrA9Ung9U8UStrJu6UnKyjGdI9aWTU15xuWmdU7tTcHVzCdJmFOTWkFBhYMrbUMCB4js1oemLHAS19cBxzJmB+gFITrLnhGkx1J8D2+HVeeSMvhaeuOc+C2rzrRj8AeCYcxke80/aGpSb12UDj/MdSHFACFhfYosv+iEY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898094; c=relaxed/simple; bh=Z91kGV9gdbQ/5EAiACcYSnbvvRe9vnRkY0c8b91p5aM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=XOlpitXWYiOb2apWJ2+Vvj75o7DVmjYYy3rQRCa/BqV7G9OWCsk/rKNRIfTh3wZEtwmbp3x4JGadmaUyGibCsnT8d6/X/UobT0KP1sD3ipopTfTBFAybSophl1KoDTCBsPqZ7PdOMkG6JGg/gEKQ9xiVq5a/EXrzO02sTRmoSAA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: PwBmrmkyRpiTD8CChsf7EA== X-CSE-MsgGUID: 34EwP5IjQXaOfn0nWY6xig== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:52 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id E09AD40103D5; Thu, 17 Apr 2025 22:54:48 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 30/38] ra6w: add stats.h Date: Thu, 17 Apr 2025 16:52:28 +0300 Message-Id: <20250417135236.52410-31-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/stats.h | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/stats.h diff --git a/drivers/net/wireless/renesas/ra6w/stats.h b/drivers/net/wireless/renesas/ra6w/stats.h new file mode 100644 index 000000000000..06e870f6ae0f --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/stats.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_STATS_H +#define RA6W_STATS_H + +#define RA6W_MCS_MAX_HT 8 +#define RA6W_MCS_MAX_VHT 9 +#define RA6W_MCS_MAX_HE 12 +#define RA6W_GI_MAX_HT 2 +#define RA6W_GI_MAX_VHT 2 +#define RA6W_GI_MAX_HE 3 + +enum ra6w_stats_bits { + RA6W_STATS_RX_CCK_BIT = BIT(0), + RA6W_STATS_RX_OFDM_BIT = BIT(1), + RA6W_STATS_RX_HT_BIT = BIT(2), + RA6W_STATS_RX_VHT_BIT = BIT(3), + RA6W_STATS_RX_HE_SU_BIT = BIT(4), + RA6W_STATS_RX_HE_MU_BIT = BIT(5), + RA6W_STATS_RX_HE_EXT_BIT = BIT(6), + RA6W_STATS_RX_HE_TRIGFLAG_LONG_BIT = BIT(7) +}; + +enum ra6w_stats_status { + RA6W_STATS_STATUS_DISABLED, + RA6W_STATS_STATUS_ENABLED, + + RA6W_STATS_STATUS_MAX +}; + +struct ra6w_stats_non_ht { + u8 bw; + u64 ofdm; + u64 cck; +}; + +struct ra6w_stats_rx { + u8 format_mode; + u8 flags; + struct ra6w_stats_non_ht non_ht; + struct { + u8 bw; + u8 mcs; + u8 gi; + u8 nss; + u64 ht[RA6W_GI_MAX_HT][RA6W_MCS_MAX_HT]; + } ht; + struct { + u8 bw; + u8 mcs; + u8 gi; + u8 nss; + u64 vht[RA6W_GI_MAX_VHT][RA6W_MCS_MAX_VHT]; + } vht; + struct { + u8 bw; + u8 mcs; + u8 gi; + u8 nss; + u64 he[RA6W_GI_MAX_HE][RA6W_MCS_MAX_HE]; + } he_su; +}; + +struct ra6w_stats { + struct ra6w_stats_rx *rx_stats; + bool stats_enabled; +}; + +struct ra6w_cfg80211_sta_stats; + +#ifdef CONFIG_NL80211_TESTMODE + +int ra6w_stats_init(struct ra6w_stats *stats); +void ra6w_stats_deinit(struct ra6w_stats *stats); +void ra6w_stats_rx_update(struct ra6w_stats *stats, + const struct ra6w_cfg80211_sta_stats *sta_stats); + +#else + +static inline int ra6w_stats_init(struct ra6w_stats *stats) +{ + return 0; +} + +static inline void ra6w_stats_deinit(struct ra6w_stats *stats) +{ +} + +static inline +void ra6w_stats_rx_update(struct ra6w_stats *stats, + const struct ra6w_cfg80211_sta_stats *sta_stats) +{ +} + +#endif /* CONFIG_NL80211_TESTMODE */ + +#endif /* RA6W_STATS_H */ From patchwork Thu Apr 17 13:52:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882846 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 32A2824EF74 for ; Thu, 17 Apr 2025 13:54:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898098; cv=none; b=uXjOM4oPArL7gM1OPSYGakQIWPZ6mHpGADjSsndu3Rv+bpiurA4Z0Wt9aIKjU2B0FPCDE5cpvnhf4qZmkBMP5gj5sQOs0e4otkOWKUAOouGoGYNSeU5CYZAB3Pzsk8ezvVtDr+TTZwxcgyMz+xsDbM23PpWL+QmhdTeDPENFWF0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898098; c=relaxed/simple; bh=+YyPqBC/ODomYOQ6LT83kCF0k8cSDRF6vlYjNdCO0Pk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=Xt4hZuSOplzhMPhphwVVdCaD4vJK342ocB/ovfhbb4sL/ZwKGEGPmVTvsIPvWDi5OuiXR99HNR99eDyu/9X4dN23JhoYYfG5+D2vmACLwJvzAqpwX3Rc7hwjZ7351c/kBBRCPvLbUrTQzNuyoUiqbwL4s+jhXNmbXUZifEN6Fa0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: DKcktOK7SJeP2MjQgKS3IQ== X-CSE-MsgGUID: 74tP3qWbTxetLNKZ1lH5Jw== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:54:56 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 2BC0A401009B; Thu, 17 Apr 2025 22:54:52 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 31/38] ra6w: add status.c Date: Thu, 17 Apr 2025 16:52:29 +0300 Message-Id: <20250417135236.52410-32-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/status.c | 117 +++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/status.c diff --git a/drivers/net/wireless/renesas/ra6w/status.c b/drivers/net/wireless/renesas/ra6w/status.c new file mode 100644 index 000000000000..86427b2be610 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/status.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains driver status operations. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include + +#include "core.h" +#include "if.h" +#include "params.h" +#include "dbg.h" +#include "status.h" + +void ra6w_status_init(struct ra6w_status *status) +{ + spin_lock_init(&status->lock); +} + +void ra6w_status_set(struct ra6w_status *status, u32 value) +{ + unsigned long flags = 0; + + spin_lock_irqsave(&status->lock, flags); + *(u32 *)&status->value[0] = value; + spin_unlock_irqrestore(&status->lock, flags); +} + +void ra6w_status_event_post(struct ra6w_status *status, const struct sk_buff *skb) +{ + struct ra6w_status_buf *rsp = (struct ra6w_status_buf *)skb->data; + + if (rsp->ext_len == RA6W_STATUS_EXT_LEN) + ra6w_status_set(status, rsp->ext_hdr.status); +} + +u8 ra6w_status_rx_get(struct ra6w_status *status) +{ + u8 ret = 0; + unsigned long flags = 0; + + spin_lock_irqsave(&status->lock, flags); + ret = status->value[RA6W_STATUS_BYTE_STATUS] & BIT(RA6W_STATUS_BIT_RX_EMPTY); + spin_unlock_irqrestore(&status->lock, flags); + + return ret; +} + +u8 ra6w_status_tx_get(struct ra6w_status *status, u8 ac) +{ + u8 ret = 0; + u8 value = 0; + unsigned long flags = 0; + + spin_lock_irqsave(&status->lock, flags); + + value = status->value[RA6W_STATUS_BYTE_STATUS]; + + switch (ac) { + case RA6W_TX_DATA_AC: + ret = value & BIT(RA6W_STATUS_BIT_TX_AC_FULL); + break; + case RA6W_TX_DATA_AC_POWER: + ret = value & BIT(RA6W_STATUS_BIT_TX_POWER_FULL); + break; + default: + break; + } + + spin_unlock_irqrestore(&status->lock, flags); + + return ret; +} + +u8 ra6w_status_tx_avail_cnt_get(struct ra6w_status *status, u8 ac) +{ + u8 cnt = 0; + unsigned long flags = 0; + + spin_lock_irqsave(&status->lock, flags); + + switch (ac) { + case RA6W_TX_DATA_AC: + cnt = status->value[RA6W_STATUS_BYTE_TX_AVAIL_CNT]; + break; + case RA6W_TX_DATA_AC_POWER: + cnt = status->value[RA6W_STATUS_BYTE_TX_POWER_AVAIL_CNT]; + break; + default: + break; + } + + spin_unlock_irqrestore(&status->lock, flags); + + return cnt; +} + +int ra6w_status_err_code_to_errno(u8 err) +{ + switch (err) { + case RA6W_STATUS_CODE_SUCCESS: return 0; + case RA6W_STATUS_CODE_FAIL: return -ENOENT; + case RA6W_STATUS_CODE_EMPTY: return -ENODATA; + case RA6W_STATUS_CODE_FULL: return -EXFULL; + case RA6W_STATUS_CODE_INVALID_PARAM: return -EINVAL; + case RA6W_STATUS_CODE_NOT_FOUND: return -ENXIO; + case RA6W_STATUS_CODE_NO_MORE: return -ENOSPC; + case RA6W_STATUS_CODE_NOT_IN_USE: return -ESPIPE; + case RA6W_STATUS_CODE_BUSY: return -EBUSY; + case RA6W_STATUS_CODE_IN_PROGRESS: return -EINPROGRESS; + case RA6W_STATUS_CODE_MEMORY_FAIL: return -ENOMEM; + case RA6W_STATUS_CODE_NOT_SUPPORT: return -EOPNOTSUPP; + case RA6W_STATUS_CODE_EXIST: return -EEXIST; + default: return -EIO; + } +} From patchwork Thu Apr 17 13:52:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882260 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9C82C24EF6B for ; Thu, 17 Apr 2025 13:55:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898103; cv=none; b=Rt54ChP6kZzRvWGprrQdZqWaKoc51pEgT3VUhy2Zi0EwXz86OvZOj+HCgOO0gt7KWH5rEAHibB3QjDGonCtBruVUAenFiXi/pJl0pcUo17mVr2s2fgRapX4FJpMIz+6XDdo2doheMPewts+M1yOx06YqWcJRs4p01TnK25i42/U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898103; c=relaxed/simple; bh=RMviJYm8lGQtJAHfpndeBCfJuNWB5H4Utvn2Inw5vkc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=tlUQjGoNVxVM2xBF6ef8gAT6eLA1yMRcqmNtuenW5z9KeY/P1LAavCnmiV40ZYDGMw/Qo3BGjysYz4Mt2F0OTW4xBLKk7kQmAs9HElGVLVwgLvzqLipNydvisoTvUqMp4s4+xcvlrpAwzRtiLTg1Eg3BZNZYT3CSRPlTTLoHH/Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: +SUrNCTBRTWk3uAG3RDIRA== X-CSE-MsgGUID: 21RCBnHSQBCpoOa5dJqa9g== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:55:00 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 4F7E8401009B; Thu, 17 Apr 2025 22:54:56 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 32/38] ra6w: add status.h Date: Thu, 17 Apr 2025 16:52:30 +0300 Message-Id: <20250417135236.52410-33-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/status.h | 73 ++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/status.h diff --git a/drivers/net/wireless/renesas/ra6w/status.h b/drivers/net/wireless/renesas/ra6w/status.h new file mode 100644 index 000000000000..3736e2a2fdb7 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/status.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_STATUS_H +#define RA6W_STATUS_H + +#include +#include + +enum ra6w_status_code { + RA6W_STATUS_CODE_SUCCESS = 0, + RA6W_STATUS_CODE_FAIL, + RA6W_STATUS_CODE_EMPTY, + RA6W_STATUS_CODE_FULL, + RA6W_STATUS_CODE_INVALID_PARAM, + RA6W_STATUS_CODE_NOT_FOUND, + RA6W_STATUS_CODE_NO_MORE, + RA6W_STATUS_CODE_NOT_IN_USE, + RA6W_STATUS_CODE_BUSY, + RA6W_STATUS_CODE_IN_PROGRESS, + RA6W_STATUS_CODE_MEMORY_FAIL, + RA6W_STATUS_CODE_NOT_SUPPORT, + RA6W_STATUS_CODE_EXIST, + + RA6W_STATUS_CODE_MAX +}; + +enum ra6w_status_byte { + RA6W_STATUS_BYTE_STATUS, + RA6W_STATUS_BYTE_TX_AVAIL_CNT, + RA6W_STATUS_BYTE_TX_POWER_AVAIL_CNT, + RA6W_STATUS_BYTE_RESERVED, + + RA6W_STATUS_BYTE_MAX +}; + +enum ra6w_status_byte_bits { + RA6W_STATUS_BIT_RX_EMPTY, + RA6W_STATUS_BIT_TX_AC_FULL, + RA6W_STATUS_BIT_TX_POWER_FULL, + + RA6W_STATUS_BITS_MAX +}; + +struct ra6w_status { + u8 value[RA6W_STATUS_BYTE_MAX]; + spinlock_t lock; +}; + +struct ra6w_status_ext_hdr { + u32 status : 32; +}; + +struct ra6w_status_buf { + u8 cmd; + u8 ext_len; + __le16 data_len; + struct ra6w_status_ext_hdr ext_hdr; +}; + +#define RA6W_STATUS_EXT_LEN (sizeof(struct ra6w_status_ext_hdr)) + +void ra6w_status_init(struct ra6w_status *status); +void ra6w_status_set(struct ra6w_status *status, u32 value); +u8 ra6w_status_rx_get(struct ra6w_status *status); +u8 ra6w_status_tx_get(struct ra6w_status *status, u8 ac); +u8 ra6w_status_tx_avail_cnt_get(struct ra6w_status *status, u8 ac); +int ra6w_status_err_code_to_errno(u8 err); +void ra6w_status_event_post(struct ra6w_status *status, const struct sk_buff *skb); + +#endif /* RA6W_STATUS_H */ From patchwork Thu Apr 17 13:52:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882845 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9F28724EF9B for ; Thu, 17 Apr 2025 13:55:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898108; cv=none; b=V8mZn36wuCtigJCuQjOH5uAri6tucpmizDNY7fTEER+T/Ky4sQOP/Ne6xlvJGaa08meQL9OtYfbs10r556oRSSp6aAEWhKGhubGfh8EmPuFFny6f6X4HaFCJ4qtgUJNoGQg7kVAuZOIOL8PNi2bnHTTGG+KKj3UkllK7McFO7Gc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898108; c=relaxed/simple; bh=qT2sMESs+2ygTerY281vS6yb/yByNuTXqeH+WEgEnu4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=dTwVJHaI49NfIZGj5F8FhoCp59gusT3ULiYY9csD8fQVX1YtYu1grFto7sNd6NLI4YBWe/3OQD7Kn5JO0Bc97Ter5M0LE5aQnk/qeLIoMuubsu7nfg+J4no6nNOhlNRAQCaJc9EptEMKnBpDMKG4pyo/1cRTnvSSTf7EWp8O72g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: 5jslJKBSSvCDd5JqaMjC0w== X-CSE-MsgGUID: JimpIodiQ3eKMILUS0rOiA== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:55:05 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 12FE240103D5; Thu, 17 Apr 2025 22:55:01 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 33/38] ra6w: add testmode.c Date: Thu, 17 Apr 2025 16:52:31 +0300 Message-Id: <20250417135236.52410-34-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/testmode.c | 649 +++++++++++++++++++ 1 file changed, 649 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/testmode.c diff --git a/drivers/net/wireless/renesas/ra6w/testmode.c b/drivers/net/wireless/renesas/ra6w/testmode.c new file mode 100644 index 000000000000..ea67183b3c41 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/testmode.c @@ -0,0 +1,649 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains cfg80211 tetsmode routine. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include +#include + +#include "core.h" +#include "params.h" +#include "dbg.h" +#include "testmode.h" +#include "cfg80211.h" + +#define TESTMODE_SIZE 1024 + +static int ra6w_testmode_reg(struct ra6w_ctrl *ctrl, struct nlattr **tb) +{ + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + struct ra6w_cfg80211_priv *priv = core->priv; + struct sk_buff *skb; + u32 memaddr; + u32 val32; + int ret = 0; + + if (!tb[RA6W_TESTMODE_ATTR_REG_OFFSET]) { + ra6w_err("Error finding register offset\n"); + return -ENOMSG; + } + + memaddr = nla_get_u32(tb[RA6W_TESTMODE_ATTR_REG_OFFSET]); + + switch (nla_get_u32(tb[RA6W_TESTMODE_ATTR_CMD])) { + case RA6W_TESTMODE_CMD_READ_REG: { + struct ra6w_cmd_mem_read_rsp mem_read_rsp; + + ret = ra6w_ctrl_mem_read_req(ctrl, memaddr, &mem_read_rsp); + if (ret) + return ret; + + skb = cfg80211_testmode_alloc_reply_skb(priv->wiphy, TESTMODE_SIZE); + if (!skb) { + ra6w_err("Error allocating memory\n"); + return -ENOMEM; + } + + val32 = le32_to_cpu(mem_read_rsp.memdata); + if (nla_put_u32(skb, RA6W_TESTMODE_ATTR_REG_VALUE32, val32)) + goto nla_put_failure; + + ret = cfg80211_testmode_reply(skb); + } + break; + case RA6W_TESTMODE_CMD_WRITE_REG: + if (!tb[RA6W_TESTMODE_ATTR_REG_VALUE32]) { + ra6w_err("Error finding value to write\n"); + return -ENOMSG; + } + + val32 = nla_get_u32(tb[RA6W_TESTMODE_ATTR_REG_VALUE32]); + ret = ra6w_ctrl_mem_write_req(ctrl, memaddr, val32); + break; + default: + ra6w_err("Unknown TM reg cmd ID\n"); + return -EINVAL; + } + + return ret; + +nla_put_failure: + kfree_skb(skb); + + return -EMSGSIZE; +} + +static int ra6w_testmode_dbg_filter(struct ra6w_ctrl *ctrl, struct nlattr **tb) +{ + u32 filter; + int ret = 0; + + if (!tb[RA6W_TESTMODE_ATTR_REG_FILTER]) { + ra6w_err("Error finding filter value\n"); + return -ENOMSG; + } + + filter = nla_get_u32(tb[RA6W_TESTMODE_ATTR_REG_FILTER]); + ra6w_dbg("TM DBG filter, setting: 0x%x\n", filter); + + switch (nla_get_u32(tb[RA6W_TESTMODE_ATTR_CMD])) { + case RA6W_TESTMODE_CMD_LOGMODEFILTER_SET: + ret = ra6w_ctrl_dbg_mode_filter_req(ctrl, filter); + break; + case RA6W_TESTMODE_CMD_DBGLEVELFILTER_SET: + ret = ra6w_ctrl_dbg_level_filter_req(ctrl, filter); + break; + default: + ra6w_err("Unknown testmode register command ID\n"); + return -EINVAL; + } + + return ret; +} + +static int ra6w_testmode_rf_tx(struct ra6w_ctrl *ctrl, struct nlattr **tb) +{ + struct ra6w_cmd_rf_tx_data data; + + if (!tb[RA6W_TESTMODE_ATTR_START]) { + ra6w_err("Error finding RF TX parameters\n"); + return -ENOMSG; + } + + data.start = nla_get_u8(tb[RA6W_TESTMODE_ATTR_START]); + if (data.start == RA6W_TESTMODE_VALUE_START) { + if (!tb[RA6W_TESTMODE_ATTR_RATE] || + !tb[RA6W_TESTMODE_ATTR_POWER] || + !tb[RA6W_TESTMODE_ATTR_GI] || + !tb[RA6W_TESTMODE_ATTR_GREEN] || + !tb[RA6W_TESTMODE_ATTR_PREAMBLE] || + !tb[RA6W_TESTMODE_ATTR_QOS] || + !tb[RA6W_TESTMODE_ATTR_ACK] || + !tb[RA6W_TESTMODE_ATTR_AIFSN] || + !tb[RA6W_TESTMODE_ATTR_CH] || + !tb[RA6W_TESTMODE_ATTR_FRAMES_NUM] || + !tb[RA6W_TESTMODE_ATTR_ADDR_DEST] || + !tb[RA6W_TESTMODE_ATTR_BSSID]) + return -EINVAL; + + data.tx_rate = cpu_to_le32(nla_get_u32(tb[RA6W_TESTMODE_ATTR_RATE])); + data.tx_power = cpu_to_le32(nla_get_u32(tb[RA6W_TESTMODE_ATTR_POWER])); + data.gi = nla_get_u8(tb[RA6W_TESTMODE_ATTR_GI]); + data.green_field = nla_get_u8(tb[RA6W_TESTMODE_ATTR_GREEN]); + data.preamble_type = nla_get_u8(tb[RA6W_TESTMODE_ATTR_PREAMBLE]); + data.qos_enable = nla_get_u8(tb[RA6W_TESTMODE_ATTR_QOS]); + data.ack_policy = nla_get_u8(tb[RA6W_TESTMODE_ATTR_ACK]); + data.aifsn_val = nla_get_u8(tb[RA6W_TESTMODE_ATTR_AIFSN]); + data.frequency = cpu_to_le16(nla_get_u16(tb[RA6W_TESTMODE_ATTR_CH])); + data.num_frames = cpu_to_le16(nla_get_u16(tb[RA6W_TESTMODE_ATTR_FRAMES_NUM])); + data.frame_len = cpu_to_le16(nla_get_u16(tb[RA6W_TESTMODE_ATTR_FRAMES_LEN])); + data.dest_addr = cpu_to_le64(nla_get_u64(tb[RA6W_TESTMODE_ATTR_ADDR_DEST])); + data.bssid = cpu_to_le64(nla_get_u64(tb[RA6W_TESTMODE_ATTR_BSSID])); + } + + return ra6w_ctrl_rf_tx_req(ctrl, &data); +} + +static int ra6w_testmode_rf_cw(struct ra6w_ctrl *ctrl, struct nlattr **tb) +{ + struct ra6w_cmd_rf_cw_data data = { 0 }; + + if (!tb[RA6W_TESTMODE_ATTR_START]) { + ra6w_err("Error finding RF CW parameters\n"); + return -ENOMSG; + } + + data.start = nla_get_u8(tb[RA6W_TESTMODE_ATTR_START]); + if (data.start == RA6W_TESTMODE_VALUE_START) { + if (!tb[RA6W_TESTMODE_ATTR_POWER]) + return -EINVAL; + + data.tx_power = cpu_to_le32(nla_get_u32(tb[RA6W_TESTMODE_ATTR_POWER])); + if (!tb[RA6W_TESTMODE_ATTR_CH]) + return -EINVAL; + + data.frequency = cpu_to_le16(nla_get_u16(tb[RA6W_TESTMODE_ATTR_CH])); + } + + return ra6w_ctrl_rf_cw_req(ctrl, &data); +} + +static int ra6w_testmode_rf_cont(struct ra6w_ctrl *ctrl, struct nlattr **tb) +{ + struct ra6w_cmd_rf_cont_data data = { 0 }; + + if (!tb[RA6W_TESTMODE_ATTR_START]) { + ra6w_err("Error finding RF CONT parameters\n"); + return -ENOMSG; + } + + data.start = nla_get_u8(tb[RA6W_TESTMODE_ATTR_START]); + if (data.start == RA6W_TESTMODE_VALUE_START) { + if (!tb[RA6W_TESTMODE_ATTR_POWER]) + return -EINVAL; + + data.tx_power = cpu_to_le32(nla_get_u32(tb[RA6W_TESTMODE_ATTR_POWER])); + if (!tb[RA6W_TESTMODE_ATTR_CH]) + return -EINVAL; + + data.frequency = cpu_to_le16(nla_get_u16(tb[RA6W_TESTMODE_ATTR_CH])); + if (!tb[RA6W_TESTMODE_ATTR_RATE]) + return -EINVAL; + + data.tx_rate = cpu_to_le32(nla_get_u32(tb[RA6W_TESTMODE_ATTR_RATE])); + } + + return ra6w_ctrl_rf_cont_req(ctrl, &data); +} + +static int ra6w_testmode_rf_ch(struct ra6w_ctrl *ctrl, struct nlattr **tb) +{ + u16 frequency = 0; + + if (!tb[RA6W_TESTMODE_ATTR_CH]) { + ra6w_err("Error finding RF CH parameters\n"); + return -ENOMSG; + } + + frequency = nla_get_u16(tb[RA6W_TESTMODE_ATTR_CH]); + + return ra6w_ctrl_rf_ch_req(ctrl, frequency); +} + +static int ra6w_testmode_rf_per(struct ra6w_ctrl *ctrl, struct nlattr **tb) +{ + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + struct ra6w_cfg80211_priv *priv = core->priv; + struct ra6w_cmd_rf_per_rsp rsp = { 0 }; + struct sk_buff *skb = NULL; + int ret = 0; + u8 start = 0; + + if (!tb[RA6W_TESTMODE_ATTR_START]) { + ra6w_err("Error finding RF PER parameters\n"); + return -ENOMSG; + } + + start = nla_get_u8(tb[RA6W_TESTMODE_ATTR_START]); + if (start != RA6W_TESTMODE_VALUE_PER_GET) + return 0; + + ret = ra6w_ctrl_rf_per_req(ctrl, start, &rsp); + if (ret) + return ret; + + skb = cfg80211_testmode_alloc_reply_skb(priv->wiphy, TESTMODE_SIZE); + if (!skb) { + ra6w_err("Error allocating memory\n"); + return -ENOMEM; + } + + if (nla_put_u32(skb, RA6W_TESTMODE_ATTR_PER_PASS, le32_to_cpu(rsp.pass))) + goto nla_put_failure; + + if (nla_put_u32(skb, RA6W_TESTMODE_ATTR_PER_FCS, le32_to_cpu(rsp.fcs))) + goto nla_put_failure; + + if (nla_put_u32(skb, RA6W_TESTMODE_ATTR_PER_PHY, le32_to_cpu(rsp.phy))) + goto nla_put_failure; + + if (nla_put_u32(skb, RA6W_TESTMODE_ATTR_PER_OVERFLOW, le32_to_cpu(rsp.overflow))) + goto nla_put_failure; + + return cfg80211_testmode_reply(skb); + +nla_put_failure: + if (skb) + kfree_skb(skb); + + return -EMSGSIZE; +} + +static int ra6w_testmode_host_log_level(struct nlattr **tb) +{ + u8 level = 0; + + if (!tb[RA6W_TESTMODE_ATTR_HOST_LOG_LEVEL]) { + ra6w_err("Error finding level attribute\n"); + return -ENOMSG; + } + + level = nla_get_u8(tb[RA6W_TESTMODE_ATTR_HOST_LOG_LEVEL]); + + RA6W_SET_DBG_LEVEL(level); + + return 0; +} + +static int ra6w_testmode_tx_power(struct ra6w_ctrl *ctrl, struct nlattr **tb, + const struct ra6w_cfg80211_vif *vif) +{ + u32 tx_power = 0; + + if (!tb[RA6W_TESTMODE_ATTR_POWER]) { + ra6w_err("Error finding tx power attribute\n"); + return -ENOMSG; + } + + tx_power = nla_get_u32(tb[RA6W_TESTMODE_ATTR_POWER]); + + return ra6w_ctrl_set_tx_power_req(ctrl, vif->vif_idx, tx_power); +} + +static struct ra6w_cfg80211_sta *ra6w_testmode_sta_get(struct ra6w_cfg80211_vif *vif) +{ + struct ra6w_cfg80211_sta *sta = NULL; + + if (vif->type == NL80211_IFTYPE_STATION || + vif->type == NL80211_IFTYPE_P2P_CLIENT) + return vif->sta.ap; + + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_P2P_GO) { + list_for_each_entry(sta, &vif->ap.sta_list, list) { + if (sta->valid) + return sta; + } + } + + return NULL; +} + +static int ra6w_testmode_stats_start(struct ra6w_ctrl *ctrl, struct nlattr **tb, + struct ra6w_cfg80211_vif *vif) +{ + int ret = 0; + + ret = ra6w_stats_init(&vif->stats); + if (ret) + return ret; + + return ra6w_ctrl_stats_tx_start_req(ctrl, RA6W_STATS_TX_START_BIT); +} + +static int ra6w_testmode_stats_stop(struct ra6w_cfg80211_vif *vif) +{ + ra6w_stats_deinit(&vif->stats); + + return 0; +} + +static int ra6w_testmode_stats_tx(struct ra6w_ctrl *ctrl, struct nlattr **tb, + struct ra6w_cfg80211_vif *vif) +{ + int ret = 0; + struct ra6w_cmd_stats_tx_rsp rsp = { 0 }; + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + struct ra6w_cfg80211_priv *priv = core->priv; + struct ra6w_cfg80211_sta *sta = NULL; + struct wiphy *wiphy = priv->wiphy; + struct sk_buff *skb = NULL; + char bssid[RA6W_MAC_ADDR_STR_LEN] = { 0 }; + char mac_address[RA6W_MAC_ADDR_STR_LEN] = { 0 }; + + if (!vif->stats.stats_enabled) + return -EINVAL; + + sta = ra6w_testmode_sta_get(vif); + if (!sta) + return -EINVAL; + + ret = ra6w_ctrl_stats_tx_req(ctrl, RA6W_STATS_TX_REQ_BIT, &rsp); + if (ret) + return ret; + + skb = cfg80211_testmode_alloc_reply_skb(wiphy, TESTMODE_SIZE); + if (!skb) + return -ENOMEM; + + snprintf(bssid, sizeof(bssid), "%pM", sta->mac_addr); + snprintf(mac_address, sizeof(mac_address), "%pM", wiphy->perm_addr); + + if (nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_FLAGS, rsp.format_mod) || + nla_put(skb, RA6W_TESTMODE_ATTR_STATS_TX_EPR, sizeof(rsp.epr), rsp.epr) || + nla_put_string(skb, RA6W_TESTMODE_ATTR_STATS_BSSID, bssid) || + nla_put_string(skb, RA6W_TESTMODE_ATTR_STATS_OWN_MAC, mac_address) || + nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_STAIDX, sta->sta_idx)) + goto nla_put_failure; + + switch (rsp.format_mod) { + case RA6W_CFG80211_FORMATMOD_NON_HT: + case RA6W_CFG80211_FORMATMOD_NON_HT_DUP_OFDM: + if (nla_put(skb, RA6W_TESTMODE_ATTR_STATS_TX_CCK, sizeof(rsp.non_ht.success), + rsp.non_ht.success) || + nla_put(skb, RA6W_TESTMODE_ATTR_STATS_TX_CCK_FAIL, sizeof(rsp.non_ht.fail), + rsp.non_ht.fail)) + goto nla_put_failure; + break; + case RA6W_CFG80211_FORMATMOD_HT_MF: + case RA6W_CFG80211_FORMATMOD_HT_GF: + if (nla_put(skb, RA6W_TESTMODE_ATTR_STATS_TX_HT, sizeof(rsp.ht.success), + rsp.ht.success) || + nla_put(skb, RA6W_TESTMODE_ATTR_STATS_TX_HT_FAIL, sizeof(rsp.ht.fail), + rsp.ht.fail)) + goto nla_put_failure; + break; + case RA6W_CFG80211_FORMATMOD_VHT: + if (nla_put(skb, RA6W_TESTMODE_ATTR_STATS_TX_VHT, sizeof(rsp.vht.success), + rsp.vht.success) || + nla_put(skb, RA6W_TESTMODE_ATTR_STATS_TX_VHT_FAIL, sizeof(rsp.vht.fail), + rsp.vht.fail)) + goto nla_put_failure; + break; + case RA6W_CFG80211_FORMATMOD_HE_SU: + case RA6W_CFG80211_FORMATMOD_HE_ER: + case RA6W_CFG80211_FORMATMOD_HE_MU: + case RA6W_CFG80211_FORMATMOD_HE_TB: + if (nla_put(skb, RA6W_TESTMODE_ATTR_STATS_TX_HE, sizeof(rsp.he.success), + rsp.he.success) || + nla_put(skb, RA6W_TESTMODE_ATTR_STATS_TX_HE_FAIL, sizeof(rsp.he.fail), + rsp.he.fail)) + goto nla_put_failure; + break; + }; + + return cfg80211_testmode_reply(skb); + +nla_put_failure: + kfree_skb(skb); + + return -EMSGSIZE; +} + +static int ra6w_testmode_stats_rx(struct ra6w_ctrl *ctrl, struct nlattr **tb, + struct ra6w_cfg80211_vif *vif) +{ + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + struct ra6w_cfg80211_priv *priv = core->priv; + struct ra6w_cfg80211_sta *sta = NULL; + struct wiphy *wiphy = priv->wiphy; + struct sk_buff *skb = NULL; + struct ra6w_stats *stats = &vif->stats; + struct ra6w_stats_rx *rx_stats = stats->rx_stats; + char bssid[RA6W_MAC_ADDR_STR_LEN] = { 0 }; + char mac_address[RA6W_MAC_ADDR_STR_LEN] = { 0 }; + + if (!stats->stats_enabled || !rx_stats) + return -EINVAL; + + sta = ra6w_testmode_sta_get(vif); + if (!sta) + return -EINVAL; + + skb = cfg80211_testmode_alloc_reply_skb(wiphy, TESTMODE_SIZE); + if (!skb) + return -ENOMEM; + + if (nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_READY, vif->stats.stats_enabled)) + goto nla_put_failure; + + snprintf(bssid, sizeof(bssid), "%pM", sta->mac_addr); + snprintf(mac_address, sizeof(mac_address), "%pM", wiphy->perm_addr); + + if (nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_FLAGS, rx_stats->flags) || + nla_put_string(skb, RA6W_TESTMODE_ATTR_STATS_BSSID, bssid) || + nla_put_string(skb, RA6W_TESTMODE_ATTR_STATS_OWN_MAC, mac_address) || + nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_STAIDX, sta->sta_idx)) + goto nla_put_failure; + + if (rx_stats->flags & RA6W_STATS_RX_OFDM_BIT || + rx_stats->flags & RA6W_STATS_RX_CCK_BIT) { + if (nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_BW, rx_stats->non_ht.bw) || + nla_put_u64_64bit(skb, RA6W_TESTMODE_ATTR_STATS_RX_CCK, rx_stats->non_ht.cck, + NL80211_ATTR_PAD) || + nla_put_u64_64bit(skb, RA6W_TESTMODE_ATTR_STATS_RX_OFDM, + rx_stats->non_ht.ofdm, NL80211_ATTR_PAD)) + goto nla_put_failure; + } + + if (rx_stats->flags & RA6W_STATS_RX_HT_BIT) { + if (nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_BW, rx_stats->ht.bw) || + nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_NSS, rx_stats->ht.nss) || + nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_GI, rx_stats->ht.gi) || + nla_put(skb, RA6W_TESTMODE_ATTR_STATS_RX_HT, sizeof(rx_stats->ht.ht), + rx_stats->ht.ht)) + goto nla_put_failure; + } + + if (rx_stats->flags & RA6W_STATS_RX_VHT_BIT) { + if (nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_BW, rx_stats->vht.bw) || + nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_NSS, rx_stats->vht.nss) || + nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_GI, rx_stats->vht.gi) || + nla_put(skb, RA6W_TESTMODE_ATTR_STATS_RX_VHT, sizeof(rx_stats->vht.vht), + rx_stats->vht.vht)) + goto nla_put_failure; + } + + if (rx_stats->flags & RA6W_STATS_RX_HE_SU_BIT) { + if (nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_BW, rx_stats->he_su.bw) || + nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_NSS, rx_stats->he_su.nss) || + nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_RX_GI, rx_stats->he_su.gi) || + nla_put(skb, RA6W_TESTMODE_ATTR_STATS_RX_HE_SU, sizeof(rx_stats->he_su.he), + rx_stats->he_su.he)) + goto nla_put_failure; + } + + return cfg80211_testmode_reply(skb); + +nla_put_failure: + kfree_skb(skb); + + return -EMSGSIZE; +} + +static int ra6w_testmode_stats_rssi(struct ra6w_ctrl *ctrl, struct nlattr **tb, + struct ra6w_cfg80211_vif *vif) +{ + struct ra6w_core *core = container_of(ctrl, struct ra6w_core, ctrl); + struct ra6w_cfg80211_priv *priv = core->priv; + struct ra6w_cfg80211_sta *sta = vif->sta.ap; + struct wiphy *wiphy = priv->wiphy; + struct sk_buff *skb = NULL; + struct ra6w_stats *stats = &vif->stats; + char bssid[RA6W_MAC_ADDR_STR_LEN] = { 0 }; + char mac_address[RA6W_MAC_ADDR_STR_LEN] = { 0 }; + + if (!stats->stats_enabled) + return -EINVAL; + + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_P2P_GO) + return -EINVAL; + + if (!sta) + return -EINVAL; + + skb = cfg80211_testmode_alloc_reply_skb(wiphy, TESTMODE_SIZE); + if (!skb) + return -ENOMEM; + + snprintf(bssid, sizeof(bssid), "%pM", sta->mac_addr); + snprintf(mac_address, sizeof(mac_address), "%pM", wiphy->perm_addr); + + if (nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_READY, stats->stats_enabled) || + nla_put_u32(skb, RA6W_TESTMODE_ATTR_STATS_RSSI, sta->stats.last_rx_data_ext.rssi1) || + nla_put_string(skb, RA6W_TESTMODE_ATTR_STATS_BSSID, bssid) || + nla_put_string(skb, RA6W_TESTMODE_ATTR_STATS_OWN_MAC, mac_address) || + nla_put_u8(skb, RA6W_TESTMODE_ATTR_STATS_STAIDX, sta->sta_idx)) + goto nla_put_failure; + + return cfg80211_testmode_reply(skb); + +nla_put_failure: + kfree_skb(skb); + + return -EMSGSIZE; +} + +static const struct nla_policy ra6w_testmode_attr_policy[RA6W_TESTMODE_ATTR_MAX] = { + [RA6W_TESTMODE_ATTR_CMD] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_REG_OFFSET] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_REG_VALUE32] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_REG_FILTER] = { .type = NLA_U32 }, + + /* RF commands */ + [RA6W_TESTMODE_ATTR_START] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_CH] = { .type = NLA_U16 }, + [RA6W_TESTMODE_ATTR_FRAMES_NUM] = { .type = NLA_U16 }, + [RA6W_TESTMODE_ATTR_FRAMES_LEN] = { .type = NLA_U16 }, + [RA6W_TESTMODE_ATTR_RATE] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_POWER] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_ADDR_DEST] = { .type = NLA_U64 }, + [RA6W_TESTMODE_ATTR_BSSID] = { .type = NLA_U64 }, + [RA6W_TESTMODE_ATTR_GI] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_GREEN] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_PREAMBLE] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_QOS] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_ACK] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_AIFSN] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_PER_PASS] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_PER_FCS] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_PER_PHY] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_PER_OVERFLOW] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_HOST_LOG_LEVEL] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_STATS_RSSI] = { .type = NLA_U32 }, + [RA6W_TESTMODE_ATTR_STATS_BSSID] = { .type = NLA_STRING }, + [RA6W_TESTMODE_ATTR_STATS_STAIDX] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_STATS_OWN_MAC] = { .type = NLA_STRING }, + [RA6W_TESTMODE_ATTR_STATS_FLAGS] = { .type = NLA_U8 }, + [RA6W_TESTMODE_ATTR_STATS_RX_OFDM] = { .type = NLA_U32, .len = 8 }, + [RA6W_TESTMODE_ATTR_STATS_READY] = { .type = NLA_U8 }, +}; + +int ra6w_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len) +{ + struct ra6w_cfg80211_priv *priv = wiphy_priv(wiphy); + struct nlattr *tb[RA6W_TESTMODE_ATTR_MAX]; + int ret = -ENOENT; + const struct net_device *ndev = wdev->netdev; + struct ra6w_cfg80211_vif *vif = netdev_priv(ndev); + struct ra6w_ctrl *ctrl = &priv->core->ctrl; + u32 cmd; + + ret = nla_parse_deprecated(tb, RA6W_TESTMODE_ATTR_MAX, data, len, + ra6w_testmode_attr_policy, NULL); + if (ret) + return ret; + + if (!tb[RA6W_TESTMODE_ATTR_CMD]) { + ra6w_err("Error finding testmode command type\n"); + return -ENOMSG; + } + + cmd = nla_get_u32(tb[RA6W_TESTMODE_ATTR_CMD]); + + switch (cmd) { + case RA6W_TESTMODE_CMD_READ_REG: + case RA6W_TESTMODE_CMD_WRITE_REG: + ret = ra6w_testmode_reg(ctrl, tb); + break; + case RA6W_TESTMODE_CMD_LOGMODEFILTER_SET: + case RA6W_TESTMODE_CMD_DBGLEVELFILTER_SET: + ret = ra6w_testmode_dbg_filter(ctrl, tb); + break; + case RA6W_TESTMODE_CMD_TX: + ret = ra6w_testmode_rf_tx(ctrl, tb); + break; + case RA6W_TESTMODE_CMD_CW: + ret = ra6w_testmode_rf_cw(ctrl, tb); + break; + case RA6W_TESTMODE_CMD_CONT: + ret = ra6w_testmode_rf_cont(ctrl, tb); + break; + case RA6W_TESTMODE_CMD_CHANNEL: + ret = ra6w_testmode_rf_ch(ctrl, tb); + break; + case RA6W_TESTMODE_CMD_PER: + ret = ra6w_testmode_rf_per(ctrl, tb); + break; + case RA6W_TESTMODE_CMD_HOST_LOG_LEVEL: + ret = ra6w_testmode_host_log_level(tb); + break; + case RA6W_TESTMODE_CMD_TX_POWER: + ret = ra6w_testmode_tx_power(ctrl, tb, vif); + break; + case RA6W_TESTMODE_CMD_STATS_START: + ret = ra6w_testmode_stats_start(ctrl, tb, vif); + break; + case RA6W_TESTMODE_CMD_STATS_STOP: + ret = ra6w_testmode_stats_stop(vif); + break; + case RA6W_TESTMODE_CMD_STATS_TX: + ret = ra6w_testmode_stats_tx(ctrl, tb, vif); + break; + case RA6W_TESTMODE_CMD_STATS_RX: + ret = ra6w_testmode_stats_rx(ctrl, tb, vif); + break; + case RA6W_TESTMODE_CMD_STATS_RSSI: + ret = ra6w_testmode_stats_rssi(ctrl, tb, vif); + break; + default: + ra6w_err("Unknown testmode command: %u\n", cmd); + ret = -EOPNOTSUPP; + break; + } + + return ret; +} From patchwork Thu Apr 17 13:52:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882259 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BF7B024EA9C for ; Thu, 17 Apr 2025 13:55:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898111; cv=none; b=QhZ2ly+KBY+dioVTnNVuHuEjDO/pwsp78aYBxXkRXWV1LVIq7ZeHzY8jQt4lr8a9V7f3SRTAaApPk9Y9+L4Sb4Ft37k7q77D59fbPa0L+yHZHweYa9p3LA5Gk88Ae57y823vFKkAsvUmcH5RbiuS+dXutjcnSj/G2UFfuSeMoVQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898111; c=relaxed/simple; bh=amMD0tJarLEqIXW32riiTY3aTRG7oz5LqE4fSq3LO4k=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=lKX+PEgS0S6XKCWeX/Rq9qVwCpei2gGIIKHjtAuhwjwrLgoSjmyVqp0mzpADUXgjaK8+XJlOqL+IdjAt7w8CySsMuxAh/OEX8zNam6h5YKCrXUWYYEM7d5vvlqTfOXAYI+Nb7AT5lbWwKGL7XNEG0Yj+FgMt7WdfJX2mpR5uRMg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: Q1SvfPQ2QzmJVAb/2tnSBg== X-CSE-MsgGUID: Pj1qgTh4QeWhjw0jtIFbVQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:55:09 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 34470401009B; Thu, 17 Apr 2025 22:55:05 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 34/38] ra6w: add testmode.h Date: Thu, 17 Apr 2025 16:52:32 +0300 Message-Id: <20250417135236.52410-35-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/testmode.h | 150 +++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/testmode.h diff --git a/drivers/net/wireless/renesas/ra6w/testmode.h b/drivers/net/wireless/renesas/ra6w/testmode.h new file mode 100644 index 000000000000..eb4907137761 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/testmode.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ +#ifndef RA6W_TESTMODE_H +#define RA6W_TESTMODE_H + +#ifdef CONFIG_NL80211_TESTMODE + +enum ra6w_testmode_cmd { + RA6W_TESTMODE_CMD_READ_REG = 1, + RA6W_TESTMODE_CMD_WRITE_REG, + RA6W_TESTMODE_CMD_LOGMODEFILTER_SET, + RA6W_TESTMODE_CMD_DBGLEVELFILTER_SET, + RA6W_TESTMODE_CMD_TX, + RA6W_TESTMODE_CMD_CW, + RA6W_TESTMODE_CMD_CONT, + RA6W_TESTMODE_CMD_CHANNEL, + RA6W_TESTMODE_CMD_PER, + RA6W_TESTMODE_CMD_RESET_HW, + RA6W_TESTMODE_CMD_HOST_LOG_LEVEL, + RA6W_TESTMODE_CMD_DBGOUTDIR_SET, + RA6W_TESTMODE_CMD_TX_POWER, + RA6W_TESTMODE_CMD_STATS_START, + RA6W_TESTMODE_CMD_STATS_STOP, + RA6W_TESTMODE_CMD_STATS_TX, + RA6W_TESTMODE_CMD_STATS_RX, + RA6W_TESTMODE_CMD_STATS_RSSI, + RA6W_TESTMODE_CMD_MAX, +}; + +enum ra6w_testmode_attr { + RA6W_TESTMODE_ATTR_NOT_APPLICABLE = 0, + RA6W_TESTMODE_ATTR_CMD, + RA6W_TESTMODE_ATTR_REG_OFFSET, + RA6W_TESTMODE_ATTR_REG_VALUE32, + RA6W_TESTMODE_ATTR_REG_FILTER, + RA6W_TESTMODE_ATTR_START, + RA6W_TESTMODE_ATTR_CH, + RA6W_TESTMODE_ATTR_FRAMES_NUM, + RA6W_TESTMODE_ATTR_FRAMES_LEN, + RA6W_TESTMODE_ATTR_RATE, + RA6W_TESTMODE_ATTR_POWER, + RA6W_TESTMODE_ATTR_ADDR_DEST, + RA6W_TESTMODE_ATTR_BSSID, + RA6W_TESTMODE_ATTR_GI, + RA6W_TESTMODE_ATTR_GREEN, + RA6W_TESTMODE_ATTR_PREAMBLE, + RA6W_TESTMODE_ATTR_QOS, + RA6W_TESTMODE_ATTR_ACK, + RA6W_TESTMODE_ATTR_AIFSN, + RA6W_TESTMODE_ATTR_PER_PASS, + RA6W_TESTMODE_ATTR_PER_FCS, + RA6W_TESTMODE_ATTR_PER_PHY, + RA6W_TESTMODE_ATTR_PER_OVERFLOW, + RA6W_TESTMODE_ATTR_HOST_LOG_LEVEL, + RA6W_TESTMODE_ATTR_STATS_READY, + RA6W_TESTMODE_ATTR_STATS_RSSI, + RA6W_TESTMODE_ATTR_STATS_BSSID, + RA6W_TESTMODE_ATTR_STATS_STAIDX, + RA6W_TESTMODE_ATTR_STATS_OWN_MAC, + RA6W_TESTMODE_ATTR_STATS_FLAGS, + RA6W_TESTMODE_ATTR_STATS_RX_BW, + RA6W_TESTMODE_ATTR_STATS_RX_MCS, + RA6W_TESTMODE_ATTR_STATS_RX_GI, + RA6W_TESTMODE_ATTR_STATS_RX_NSS, + RA6W_TESTMODE_ATTR_STATS_RX_CCK, + RA6W_TESTMODE_ATTR_STATS_RX_OFDM, + RA6W_TESTMODE_ATTR_STATS_RX_HT, + RA6W_TESTMODE_ATTR_STATS_RX_VHT, + RA6W_TESTMODE_ATTR_STATS_RX_HE_SU, + RA6W_TESTMODE_ATTR_STATS_RX_HE_MU, + RA6W_TESTMODE_ATTR_STATS_RX_HE_EXT, + RA6W_TESTMODE_ATTR_STATS_RX_HE_TRIG, + RA6W_TESTMODE_ATTR_STATS_TX_CCK, + RA6W_TESTMODE_ATTR_STATS_TX_CCK_FAIL, + RA6W_TESTMODE_ATTR_STATS_TX_OFDM, + RA6W_TESTMODE_ATTR_STATS_TX_OFDM_FAIL, + RA6W_TESTMODE_ATTR_STATS_TX_HT, + RA6W_TESTMODE_ATTR_STATS_TX_HT_FAIL, + RA6W_TESTMODE_ATTR_STATS_TX_VHT, + RA6W_TESTMODE_ATTR_STATS_TX_VHT_FAIL, + RA6W_TESTMODE_ATTR_STATS_TX_HE, + RA6W_TESTMODE_ATTR_STATS_TX_HE_FAIL, + RA6W_TESTMODE_ATTR_STATS_TX_EPR, + RA6W_TESTMODE_ATTR_MAX, +}; + +enum { + RA6W_TESTMODE_VALUE_STOP = 0, + RA6W_TESTMODE_VALUE_START, +}; + +enum ra6w_testmode_value_per { + RA6W_TESTMODE_VALUE_PER_STOP = 0, + RA6W_TESTMODE_VALUE_PER_START, + RA6W_TESTMODE_VALUE_PER_GET, + RA6W_TESTMODE_VALUE_PER_RESET, +}; + +enum ra6w_testmode_rate { + RA6W_TESTMODE_RATE_B1 = 0, + RA6W_TESTMODE_RATE_B2, + RA6W_TESTMODE_RATE_B5_5, + RA6W_TESTMODE_RATE_B11, + RA6W_TESTMODE_RATE_G6, + RA6W_TESTMODE_RATE_G9, + RA6W_TESTMODE_RATE_G12, + RA6W_TESTMODE_RATE_G18, + RA6W_TESTMODE_RATE_G24, + RA6W_TESTMODE_RATE_G36, + RA6W_TESTMODE_RATE_G48, + RA6W_TESTMODE_RATE_G54, + RA6W_TESTMODE_RATE_N6_5, + RA6W_TESTMODE_RATE_N13, + RA6W_TESTMODE_RATE_N19_5, + RA6W_TESTMODE_RATE_N26, + RA6W_TESTMODE_RATE_N39, + RA6W_TESTMODE_RATE_N52, + RA6W_TESTMODE_RATE_N58_5, + RA6W_TESTMODE_RATE_N65, +}; + +enum { + RA6W_TESTMODE_VALUE_SHORT = 0, + RA6W_TESTMODE_VALUE_LONG, +}; + +enum { + RA6W_TESTMODE_VALUE_OFF = 0, + RA6W_TESTMODE_VALUE_ON, +}; + +enum { + RA6W_TESTMODE_VALUE_NO = 0, + RA6W_TESTMODE_VALUE_NORM, + RA6W_TESTMODE_VALUE_BA, + RA6W_TESTMODE_VALUE_CBA, +}; + +int ra6w_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len); +#else +static inline int ra6w_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, + void *data, int len) +{ + return 0; +} +#endif /* CONFIG_NL80211_TESTMODE */ + +#endif // RA6W_TESTMODE_H From patchwork Thu Apr 17 13:52:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882844 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id CD61624EF72 for ; Thu, 17 Apr 2025 13:55:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898117; cv=none; b=CZjM5EtZtznNANdFi9kDaf7VnLv4MaIqXdJdRiMs+kgZpCRe+5UVMYulyqtYjqK+ELPweo02UW3JMUFcpoeIqjtEYCabURecv8dxbvanjdZL5LR7udlteek2Q69bGl2xQXfUvs5hGCPxFaUkTuKCtZyWpnhU9mSAdDlHwb7lmqU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898117; c=relaxed/simple; bh=qGkgTIuGh+zFjckOp/sW+fx67jShVhIKCo33yThluCw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=blJkBdE/lmB4g3YlDfSKQTcYsqI79cv8NKalO49x2UK7dqIhTnkeLWDiE4mmifzvB/5s0gqchKNB5Fp3M08g8Msl0p2N6+krY9REEOzvKH/yJfSHRnoZGd0iksCk3mNxfsHUeWtJrs2QL5ZNoriaDufmt7Jcgq3UKqISHiihAw8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: 6uUPsCpaSRKaVeYd2JnChg== X-CSE-MsgGUID: 7P/uwJymSmGubLvzoREnDA== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:55:13 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 55B61401009B; Thu, 17 Apr 2025 22:55:09 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 35/38] ra6w: add tx.c Date: Thu, 17 Apr 2025 16:52:33 +0300 Message-Id: <20250417135236.52410-36-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/tx.c | 254 +++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/tx.c diff --git a/drivers/net/wireless/renesas/ra6w/tx.c b/drivers/net/wireless/renesas/ra6w/tx.c new file mode 100644 index 000000000000..1023fab47a95 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/tx.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains Tx routine. + * + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#include "core.h" +#include "if.h" +#include "cfg80211.h" +#include "params.h" +#include "dbg.h" +#include "tx.h" + +#define RA6W_TX_THREAD_NAME "ra6w_tx_thread" +#define RA6W_TX_BUFFER_THRESHOLD 4 + +static int ra6w_tx_send(struct ra6w_tx *tx, struct sk_buff *skb) +{ + struct ra6w_core *core = container_of(tx, struct ra6w_core, tx); + struct ra6w_if *ifp = container_of(core, struct ra6w_if, core); + struct ra6w_cfg80211_priv *priv = core->priv; + struct ra6w_cfg80211_sta *sta = NULL; + struct ra6w_tx_buf *tx_buf = (struct ra6w_tx_buf *)skb->data; + int ret; + u32 len = 0; + u8 sta_idx; + + sta_idx = tx_buf->ext_hdr.sta_idx; + if (sta_idx != RA6W_CFG80211_STA_IDX_INVALID) + sta = ra6w_cfg80211_sta_get(priv, sta_idx); + + len = RA6W_GET_DATA_SIZE(tx_buf->ext_len, le16_to_cpu(tx_buf->data_len)); + ret = ra6w_if_write(ifp, tx_buf, len); + if (ret) { + core->stats.tx.err++; + if (sta) + sta->stats.tx_failed++; + + return ret; + } + + core->stats.tx.packets++; + if (sta) { + sta->stats.tx_packets++; + sta->stats.tx_bytes += len; + } + + return 0; +} + +static void ra6w_tx_send_ac(struct ra6w_tx *tx, u8 ac) +{ + struct ra6w_core *core = container_of(tx, struct ra6w_core, tx); + struct ra6w_status *status = &core->status; + struct ra6w_q *q = &tx->q_ac[ac].q; + struct sk_buff *skb = NULL; + u8 tx_cnt = 0; + u8 tx_avail_cnt = 0; + u8 tx_cnt_max = 0; + + tx_avail_cnt = ra6w_status_tx_avail_cnt_get(status, ac); + tx_cnt_max = min_t(u8, tx_avail_cnt, RA6W_TX_BUFFER_THRESHOLD); + + while (!kthread_should_stop() && + !ra6w_status_tx_get(status, ac) && + tx_cnt < tx_cnt_max && + (skb = ra6w_q_pop(q))) { + ra6w_tx_send(tx, skb); + dev_kfree_skb(skb); + skb = NULL; + tx_cnt++; + } +} + +static void ra6w_tx_reschedule(struct ra6w_tx *tx) +{ + struct ra6w_core *core = container_of(tx, struct ra6w_core, tx); + struct ra6w_status *status = &core->status; + int event_mask = 0; + u8 ac; + + for (ac = RA6W_TX_DATA_AC; ac < RA6W_TX_DATA_AC_MAX; ac++) { + if (ra6w_q_empty(&tx->q_ac[ac].q)) + continue; + + if (ra6w_status_tx_get(status, ac)) + continue; + + event_mask |= BIT(ac); + } + + if (event_mask) + ra6w_q_event_set(&tx->event, event_mask); +} + +static int ra6w_tx_thread_handler(void *arg) +{ + struct ra6w_tx *tx = arg; + int event = 0; + u8 ac; + + while (!kthread_should_stop()) { + event = ra6w_q_wait_timeout(&tx->event, RA6W_TX_EVENT_MASK); + atomic_set(&tx->event.condition, 0); + + for (ac = RA6W_TX_DATA_AC; ac < RA6W_TX_DATA_AC_MAX; ac++) { + if (!(event & BIT(ac))) + continue; + + ra6w_tx_send_ac(tx, ac); + } + + if (event & BIT(RA6W_TX_EVENT_RESET)) + break; + + if (!atomic_read(&tx->event.condition)) + ra6w_tx_reschedule(tx); + } + + return 0; +} + +int ra6w_tx_mgmt(struct ra6w_tx *tx, const struct ra6w_cfg80211_vif *vif, + const struct ra6w_cfg80211_sta *sta, + const struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + struct sk_buff *skb = NULL; + struct ra6w_tx_buf *tx_buf = NULL; + unsigned int len; + + if (!params || params->len == 0 || params->len > RA6W_CMD_DATA_SIZE || !params->buf) + return -EINVAL; + + len = RA6W_GET_DATA_SIZE(RA6W_TX_EXT_LEN, params->len); + + skb = dev_alloc_skb(len); + if (!skb) + return -ENOMEM; + + skb_put(skb, len); + skb->priority = RA6W_CMD_AC_BK; + + *cookie = (unsigned long)skb; + + tx_buf = (struct ra6w_tx_buf *)skb->data; + memcpy(tx_buf->data, params->buf, params->len); + + if (unlikely(params->n_csa_offsets > 0) && + vif->type == NL80211_IFTYPE_AP && + vif->ap.csa) { + int i; + + for (i = 0; i < params->n_csa_offsets; i++) + tx_buf->data[params->csa_offsets[i]] = vif->ap.csa->count; + } + + tx_buf->cmd = RA6W_CMD_DATA_TX; + tx_buf->ext_len = RA6W_TX_EXT_LEN; + tx_buf->ext_hdr.buf_idx = RA6W_TX_DATA_AC_POWER; + tx_buf->ext_hdr.tid = RA6W_CFG80211_TID_INVALID; + tx_buf->ext_hdr.vif_idx = vif->vif_idx; + tx_buf->ext_hdr.sta_idx = sta ? sta->sta_idx : RA6W_CFG80211_STA_IDX_INVALID; + + tx_buf->ext_hdr.flags = RA6W_EXT_FLAGS_MGMT_BIT; + + if (ieee80211_is_robust_mgmt_frame(skb)) + tx_buf->ext_hdr.flags |= RA6W_EXT_FLAGS_MGMT_ROBUST_BIT; + + if (params->no_cck) + tx_buf->ext_hdr.flags |= RA6W_EXT_FLAGS_MGMT_NO_CCK_BIT; + + tx_buf->ext_hdr.sn = 0; + tx_buf->data_len = cpu_to_le16(params->len); + + return ra6w_tx_event_post(tx, RA6W_TX_DATA_AC_POWER, skb); +} + +int ra6w_tx_event_post(struct ra6w_tx *tx, u8 ac, struct sk_buff *skb) +{ + int ret; + struct ra6w_q *q; + + if (!skb || ac >= RA6W_TX_DATA_AC_MAX) + return -EINVAL; + + q = &tx->q_ac[ac].q; + ret = ra6w_q_push(q, skb); + ra6w_q_event_set(&tx->event, BIT(ac)); + + return ret; +} + +static int ra6w_tx_init_ac(struct ra6w_tx_q_ac *q_ac, size_t tx_buf_num) +{ + if (tx_buf_num == 0) { + ra6w_err("[%s] AC tx queue size must be greater then zero\n", __func__); + return -EINVAL; + } + + return ra6w_q_init(&q_ac->q, tx_buf_num, sizeof(struct sk_buff *)); +} + +static int _ra6w_tx_init(struct ra6w_tx *tx, size_t tx_buf_num, size_t tx_buf_power_num) +{ + int ret; + + ret = ra6w_tx_init_ac(&tx->q_ac[RA6W_TX_DATA_AC], tx_buf_num); + if (ret) + return ret; + + ret = ra6w_tx_init_ac(&tx->q_ac[RA6W_TX_DATA_AC_POWER], tx_buf_power_num); + if (ret) + goto tx_buf_free; + + tx->event.timeout = RA6W_TX_EVENT_TIMEOUT_MS; + atomic_set(&tx->event.condition, 0); + init_waitqueue_head(&tx->event.wait_queue); + + tx->task = kthread_run(ra6w_tx_thread_handler, tx, RA6W_TX_THREAD_NAME); + if (!tx->task) { + ra6w_err("[%s] kthread_run %s failed\n", __func__, RA6W_TX_THREAD_NAME); + goto tx_buf_power_free; + } + + return 0; + +tx_buf_power_free: + ra6w_q_deinit(&tx->q_ac[RA6W_TX_DATA_AC_POWER].q); + +tx_buf_free: + ra6w_q_deinit(&tx->q_ac[RA6W_TX_DATA_AC].q); + + return ret; +} + +int ra6w_tx_init(struct ra6w_tx *tx) +{ + return _ra6w_tx_init(tx, RA6W_TX_BUF_Q_MAX, RA6W_TX_POWER_BUF_Q_MAX); +} + +void ra6w_tx_deinit(struct ra6w_tx *tx) +{ + int ac; + + if (tx->task) { + atomic_set(&tx->event.condition, BIT(RA6W_TX_EVENT_RESET)); + kthread_stop(tx->task); + } + + for (ac = RA6W_TX_DATA_AC; ac < RA6W_TX_DATA_AC_MAX; ac++) + ra6w_q_deinit(&tx->q_ac[ac].q); +} From patchwork Thu Apr 17 13:52:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882258 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1FFC5250BF1 for ; Thu, 17 Apr 2025 13:55:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898119; cv=none; b=XaNfmdsseToF9woTz19KEUXVpV3WUDqstxdrqyrOh2OjlrF73F7WpYCIAUmJvZD+yKsODlZTcC+OQ6s7TCPYcw/Ed0I9kXqNbDvKePEXujl7kYEvxMagkssdGFeo/+y1U5DPjtJPYxkjPisLYFvlK0O2Xktef9MsmFDj6gWkCHg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898119; c=relaxed/simple; bh=31NH0et9RAe2gDQ31TIsRvUnTSYSaDHQ/G8scXU+RUE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=EZw5BDqR2vvunNjlbtyYz7x/wN2Ed5Jjmjk8OgqHztTbdIreNjNWSPcKYaDM3IGNr15r1+Rtzp4Mps06cBCi5Ri8KO+rqsunE4ryPTt4HsD5kt8CECXYsvxIbnjGOmagYaNkAhZP47GgiSArE5vNq4NVQC3sRHNTEF0QI57HdJo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: ZJEW6XKmQWOfqIPPs03Z4A== X-CSE-MsgGUID: ugTnYJXpTfyPPSCKaolA4Q== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 17 Apr 2025 22:55:17 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 76CD240103A8; Thu, 17 Apr 2025 22:55:14 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 36/38] ra6w: add tx.h Date: Thu, 17 Apr 2025 16:52:34 +0300 Message-Id: <20250417135236.52410-37-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/tx.h | 69 ++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/tx.h diff --git a/drivers/net/wireless/renesas/ra6w/tx.h b/drivers/net/wireless/renesas/ra6w/tx.h new file mode 100644 index 000000000000..3020946468af --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/tx.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) [2022-2025] Renesas Electronics Corporation and/or its affiliates. + */ + +#ifndef RA6W_TX_H +#define RA6W_TX_H + +#include + +#include "q.h" + +#define RA6W_TX_EXT_LEN (sizeof(struct ra6w_tx_ext_hdr)) +#define RA6W_TX_BUF_Q_MAX 128 +#define RA6W_TX_POWER_BUF_Q_MAX 32 + +enum ra6w_tx_data_ac { + RA6W_TX_DATA_AC, + RA6W_TX_DATA_AC_POWER, + + RA6W_TX_DATA_AC_MAX, +}; + +#define RA6W_TX_EVENT_RESET RA6W_TX_DATA_AC_MAX +#define RA6W_TX_EVENT_MASK (BIT(RA6W_TX_DATA_AC) | \ + BIT(RA6W_TX_DATA_AC_POWER) | \ + BIT(RA6W_TX_EVENT_RESET)) + +#define RA6W_TX_EVENT_TIMEOUT_MS 100 + +struct ra6w_tx_ext_hdr { + u32 buf_idx : 3; + u32 tid : 5; + u32 vif_idx : 8; + u32 sta_idx : 8; + u32 flags : 10; + u32 sn : 24; +}; + +struct ra6w_tx_buf { + u8 cmd; + u8 ext_len; + __le16 data_len; + struct ra6w_tx_ext_hdr ext_hdr; + u8 data[RA6W_CMD_DATA_SIZE]; +}; + +struct ra6w_tx_q_ac { + struct ra6w_q q; +}; + +struct ra6w_tx { + struct task_struct *task; + struct ra6w_q_event event; + struct ra6w_tx_q_ac q_ac[RA6W_TX_DATA_AC_MAX]; +}; + +struct ra6w_cfg80211_vif; +struct ra6w_cfg80211_sta; + +int ra6w_tx_init(struct ra6w_tx *tx); +void ra6w_tx_deinit(struct ra6w_tx *tx); +int ra6w_tx_event_post(struct ra6w_tx *tx, u8 ac, struct sk_buff *skb); +int ra6w_tx_mgmt(struct ra6w_tx *tx, const struct ra6w_cfg80211_vif *vif, + const struct ra6w_cfg80211_sta *sta, + const struct cfg80211_mgmt_tx_params *params, + u64 *cookie); + +#endif /* RA6W_TX_H */ From patchwork Thu Apr 17 13:52:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882843 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 2AFB2250C01 for ; Thu, 17 Apr 2025 13:55:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898124; cv=none; b=ViKKgh/l68OR/3siy+KiegvB+A7je8OAXs//Yn/D92LwctrDyHQBHty/75so7kMCTlE9XY4XSETxC07sgY08Ujp5Q9e0aNo2XwplLnjcL3XpMU+bxuKID3SKfA+eknSkBoo9zH0OeSQapVUuBnE06H2Ua2EUvfPKv5gnYMZRQJ4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898124; c=relaxed/simple; bh=5LE+16tyjI3K+ZRflMyYLEWaYGNlNvylTcnaqaOZsnk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=LPsAOw3A5lSfVRHhZ9HRNFgNQUt8FeXPA4TgTw4+jzwemk2sTRS5UfHQCz55PXRmx46k09J1AYY5coG5kKmj78t0BGDkp7HoCdF1caSgLCFmIdKWCkza7I7OQFf741BuIrXD/5HJ0TrPMqbpl64csCZ41fpgHOTc2IPY2XW6k54= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: /FIV1lTiSGe5RJehBmcZaA== X-CSE-MsgGUID: XRhT6G9BSTyrmNHQkHBKsQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:55:22 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id A4F5740103A8; Thu, 17 Apr 2025 22:55:18 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 37/38] ra6w: add Makefile Date: Thu, 17 Apr 2025 16:52:35 +0300 Message-Id: <20250417135236.52410-38-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/Makefile diff --git a/drivers/net/wireless/renesas/ra6w/Makefile b/drivers/net/wireless/renesas/ra6w/Makefile new file mode 100644 index 000000000000..e828a8ca1c95 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +ra6w-$(CONFIG_RA6W) += sdio.o cfg80211.o dev.o params.o \ + core.o q.o ctrl.o indi.o rx.o tx.o \ + status.o recovery.o + +ra6w-$(CONFIG_DEBUG_FS) += dbgfs.o +ra6w-$(CONFIG_NL80211_TESTMODE) += stats.o +ra6w-$(CONFIG_NL80211_TESTMODE) += testmode.o +obj-$(CONFIG_RA6W) += ra6w.o From patchwork Thu Apr 17 13:52:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Savchenko X-Patchwork-Id: 882257 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7596024EF6D for ; Thu, 17 Apr 2025 13:55:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.160.252.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898127; cv=none; b=iyn4jV2F1VPK5n2R6c5bCoHOarDlJStR0YGQjvQCPEUDokZQrxUL6/TyyIgkv6/b3VNvDl/Ei5MK5hbK92xF9BqT4QN1+bW28o+f0IGm2B1Y5hNsskzILbYRzLqQCVW3gAn7i0nUcZsufVW4OhH2l4TRoCM9xx7Bu7L5aTQh0BY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744898127; c=relaxed/simple; bh=IPo7jDqI6XbpqGyVrtjredTl/bL6IIEv1D0mztFgZOI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=a1IR/pbXv/U4VOX2kC9tzy8XWZWzG+QOO7kh+fqAPqcn10Xr/wAqRwxRH3awFS0MZ6OeGOlE9PSonoP00YXCCh/xMfm/bQofO7Sf8euBIxh1/57GUEWXfz8caZFUTSegr5I7fFMUTlMZSeTgue6a1X+JVBlisZ2w/h75GYFai4U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com; spf=pass smtp.mailfrom=bp.renesas.com; arc=none smtp.client-ip=210.160.252.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=bp.renesas.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bp.renesas.com X-CSE-ConnectionGUID: 7kv0lfjQSROFsR9aD23CmQ== X-CSE-MsgGUID: 1CYehWLCSqO28JZlqpNDXQ== Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 17 Apr 2025 22:55:26 +0900 Received: from localhost.localdomain (unknown [10.14.100.3]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id D814D401009B; Thu, 17 Apr 2025 22:55:22 +0900 (JST) From: Alexander Savchenko To: linux-wireless@vger.kernel.org, Johannes Berg Cc: Sergiy Petrov , Viktor Barna , Gal Gur , Alexander Savchenko Subject: [PATCH 38/38] ra6w: add Kconfig Date: Thu, 17 Apr 2025 16:52:36 +0300 Message-Id: <20250417135236.52410-39-oleksandr.savchenko.dn@bp.renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> References: <20250417135236.52410-1-oleksandr.savchenko.dn@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Part of the split. Please, take a look at the cover letter for more details Reviewed-by: Viktor Barna Reviewed-by: Gal Gur Signed-off-by: Alexander Savchenko --- drivers/net/wireless/renesas/ra6w/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 drivers/net/wireless/renesas/ra6w/Kconfig diff --git a/drivers/net/wireless/renesas/ra6w/Kconfig b/drivers/net/wireless/renesas/ra6w/Kconfig new file mode 100644 index 000000000000..d23b5a5ef469 --- /dev/null +++ b/drivers/net/wireless/renesas/ra6w/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only +config RA6W + tristate "Renesas 802.11ax wireless chips support" + depends on CFG80211 && MMC + help + This module adds support for wireless adapters based on + Renesas RA6W IEEE 802.11ax (Dual-band Wi-Fi6) family of chipsets. + Select M (recommended), if you have a wireless module.