From nobody Fri Dec 19 12:29:08 2025 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B9B93314CC for ; Tue, 4 Nov 2025 16:26:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762273602; cv=none; b=MBgOfjBmUL798J3YahWDjISInzfu7c9P3zxEibAGkqi6nIEDxoFqt4kb6EhLsR0sizfDMrrCvPso31VntLYTcSkNxdShOEPGtFEe7QsqYKQgH5ijl2wPBiVSFkv2YS8ywUy0mZT+AshARmLYt4dVnngbfTJ1Svr/k5iGGUfiWyU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762273602; c=relaxed/simple; bh=f2htvx12bw7SMDZ3aiHnRioMCGgqy+3MUAmu4uzS49s=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iUpK5t8d+7YvNGWRgZ374s/GlFeflOzATEwxpXc8yv9O0y2Vc3TnXGVZZtqhmQM6mdUwfmmIT8HrqOGg4j6S85ivtVb5LJCbIQpxWPVsSCr9KvFVMDwD0q2Mhz8qgiyFVXcyjXFqKGNLG7XwbCN6rgkWzdzz6g86mT6z26EpOaw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=KBAwVRXD; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=QKajZkyv; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="KBAwVRXD"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="QKajZkyv" Received: from pps.filterd (m0279870.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 5A4Cfuga2056906 for ; Tue, 4 Nov 2025 16:26:39 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=qcppdkim1; bh=JIURF+d3FTA 1RHybdKd5zcpig3gEVPwtAKcIXddrJkM=; b=KBAwVRXDYGhfixJGmYh29QKuq+K IlWBDnDdFaOKtbj+uoaqhcZXLVwH4ohzqXuwQJR/mZAmtfrFD8wjmUXk98i+ygCx av71WpyXicu0cCkyreG56t8tLJp6p3IWrOSaf1xncEL+XcVSMQn2rw3r2cVaTnqq w3Fzuu3oyXlwivrL6KvfPA6SaL3uMCle/1puP5jNYOSJoDLW79I86xGCXRyfT6bz g6+L/R8ldrP4nKnFddC32Gbkjd4IngbXOjXh0zWxnZ4Fxth+p6kTDqyvJfSDUK5s /y9r21WCLEG+GxzIEbPk5vxB4Q+FJd4LhlI5JVrtKMWrP7J25OOxCXk4jqQ== Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4a78eqt8ns-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 04 Nov 2025 16:26:39 +0000 (GMT) Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-295093f614cso68631985ad.0 for ; Tue, 04 Nov 2025 08:26:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1762273598; x=1762878398; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=JIURF+d3FTA1RHybdKd5zcpig3gEVPwtAKcIXddrJkM=; b=QKajZkyv8VM33CCDTeaFQ+uqLWVFwFCZZXaN+VjylUzAPrJGx0ZN4DLt3Vm+adRzpF nmGR2OoBcr06b29KlbU+qMXs1Nsrqhx8mSJ+P4ZByg3hPFAdBZPU3RF+PnjM9y39Zq9c Y1HnRt91i0kZ0f2y3t5Awla1+jxO6WXHUUc6gMbq8g+NJ15rZtYIYLw0RkMXTmaHhXld d+u/QF8SeyuPQXvin8FG3QFXZwtPWp2t+k1b7XoJqhqvifobj+n4+c1cGb6AQZNcLMz8 Lu5HRPiy3IhmmtMUwIrdO67/RtJQKS5piKCtl5aLfUw1UrWEgPJuoJpBZnfX2Smlr2lW cTwA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762273598; x=1762878398; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JIURF+d3FTA1RHybdKd5zcpig3gEVPwtAKcIXddrJkM=; b=djOsMmTGTlNCMWZeFFMdeGO4qQfKoOi4rE+DqsXinqco40+eCTNDbHFhHGFUgEoG2F XK/2Uzzrdp3KfOuADyUjjSV4K4YEcMwrwQojN8ShKd/L5zWVVol3TB33WIrDveXQm0Z3 ECm6nZMNvO4dvc0Q2aUZJtL2BwD0FLs1jknEtBA6IIse9FLUIJnvrJ4jwBemN6PcIaMy YAbTdHpjcJ5RNUcoxi7h7QiIO37DvGvGdUPnGNiIpToegcJycTHKvPi/CZYOZg4ZzRxw 2bbn10Tu8Wq2LYNBMrxfhyrcc4CHJcbbSaZke5RHJomhvI8hYA/B/XJ4tpmDSeuVOdt2 nuzg== X-Forwarded-Encrypted: i=1; AJvYcCUH80i/dBSodbulCRN9c87qNjR/RCwcb03E0C+C6ixwIjPcsEHju2siz3oh6AfM0aWVl6SaF3XwVfl1bd0=@vger.kernel.org X-Gm-Message-State: AOJu0YxxLtDLluHZ8v66fx5ys9tpkEHCQRGI8cYdt3Og24ntgmPvCXPe hpCE/gZAqVJAuOa02z53uXlrEWTnG5TFH43+ht4gFe9ekZM8svuunYCrYav2mRt3S0A3zVKrU2Q IUS5gtvZwkdLbLbf1ONZdIl/YmdXSSh+GngfEoVabJ2thzBmf6ZvFhpMMKsxlnZ/cREM= X-Gm-Gg: ASbGncslY6N2DIOACrEIabtUp/qt+cmR0oKr3B6dZTGp0FJhD2Tovl0YW8pczUj0Dsv muo+xLcCVoJWGc5BhZfonioc/659qI8Lui3PaL4cLCX+2276hcd6dx4uRdG4o5ZJWd/6XGTrAGh 5Vsk016CJooHSYG3uRQECuN0szOEgL4EF4T1kqm55OA+F5EbzvfEfAUGk4lp0ApLBSU+G4WhQLF xKAUZbuXZweJIRVQLhSGCB0iTExuZpq+WbbkRUjxsGt8qZdNnzb1aapJIXZZT7e1fclc+gdncgn 8RFuluM/IYlbCf29VCYJ1re1Cf3tP9RP7CN2yZEfRqmH3xtH9Hg9LeQ6P6SsEwpSKTOoBwKJKR6 JjrYSuvI2VPRhMBbwWnwnmvKGQWFJLZcLok67iRPBnD0+ X-Received: by 2002:a17:903:1a0b:b0:294:fc77:f041 with SMTP id d9443c01a7336-2962addfa05mr2003405ad.25.1762273597648; Tue, 04 Nov 2025 08:26:37 -0800 (PST) X-Google-Smtp-Source: AGHT+IHbdiDnsXgvZTVNG6+LON5+jxK58b43NI5g7Z4kf30StwJ7aLWWyCSfl02b3WA7qBy6rR4K7w== X-Received: by 2002:a17:903:1a0b:b0:294:fc77:f041 with SMTP id d9443c01a7336-2962addfa05mr2002945ad.25.1762273596980; Tue, 04 Nov 2025 08:26:36 -0800 (PST) Received: from hu-yuzha-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-29601a7a8a9sm31508435ad.107.2025.11.04.08.26.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Nov 2025 08:26:36 -0800 (PST) From: "Yu Zhang(Yuriy)" To: jjohnson@kernel.org Cc: baochen.qiang@oss.qualcomm.com, linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org, ath11k@lists.infradead.org, Yu Zhang , Vasanthakumar Thiagarajan Subject: [PATCH ath-next v2 2/6] wifi: ath11k: Register debugfs for CFR configuration Date: Tue, 4 Nov 2025 08:26:29 -0800 Message-Id: <20251104162633.3007874-3-yu.zhang@oss.qualcomm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251104162633.3007874-1-yu.zhang@oss.qualcomm.com> References: <20251104162633.3007874-1-yu.zhang@oss.qualcomm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMTA0MDEzNyBTYWx0ZWRfX3nZ5M2aKJdvr u+vRvfzdBk/vGSuwJxZDFwNpfgIEP6OxVA8BJh932tCt6TTdVCGgpgsOzaLry8mnzpibtdEWBr0 PA6u15QehYVMpFY/u9PntsU6+HB5s4JC09p4d9yolmgYbtrni7B/eJnrz5H0OdXjCz/hjwTills pUnVK4VGmM3DjBoi8OIlSChrxWMvHEuQYvNOJEUoAFoBbCv0YzlsPw9oKwdqbPcqTvXxqabB0xK DOLWhmyog8QQRG7fX5zWEe7x4w60miudyfnEJ2Xkrouf80av5VJWFwyEsteOWBgksIBkBA6pufV O2O/aoUfJ/K8SGkosT1UA1CFi3lnizM4ymDH1bx4xc33kYrmZI0pvDBhN8luaMGshmY/a+U1tl5 NCNQ+e0RzHloGfereL5QtMX/rm13bA== X-Authority-Analysis: v=2.4 cv=fofRpV4f c=1 sm=1 tr=0 ts=690a293f cx=c_pps a=JL+w9abYAAE89/QcEU+0QA==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=6UeiqGixMTsA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=COk6AnOGAAAA:8 a=EUspDBNiAAAA:8 a=dJ9JZWBW9j4LC2dvM44A:9 a=324X-CrmTo6CU4MGRt3R:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-ORIG-GUID: Blr50rU33_2rvFIK1PGPdvUohGnBUD-m X-Proofpoint-GUID: Blr50rU33_2rvFIK1PGPdvUohGnBUD-m X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2025-11-04_02,2025-11-03_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 suspectscore=0 clxscore=1015 adultscore=0 priorityscore=1501 malwarescore=0 impostorscore=0 lowpriorityscore=0 phishscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2510240001 definitions=main-2511040137 Content-Type: text/plain; charset="utf-8" From: Venkateswara Naralasetty Provide debugfs interfaces support to config CFR from the user space. To enable/disable cfr feature use command, echo > /sys/kernel/debug/ieee80211/phyX/ath11k/enable_cfr where, val: 0 to disable CFR and 1 to enable CFR. To enable CFR capture for associated peers, echo " " > /sys/kernel/debug/ieee80211/phyX/netdev\:wlanx/stations//cfr_capture val: 0 - stop CFR capture 1 - start CFR capture bw: CFR capture bandwidth 0 - 20MHZ 1 - 40MHZ 2 - 80MHZ Periodicity: Periodicity at which hardware is expected to collect CFR dump. 0 - single shot capture. non zero - for Periodic captures (value must be multiple of 10 ms) method: Method used by hardware to collect the CFR dump. 0 - from the ACKs of QOS NULL packets. Also, send the required WMI commands to the firmware based on the CFR configurations. Tested-on: IPQ8074 hw2.0 PCI IPQ8074 WLAN.HK.2.5.0.1-00991-QCAHKSWPL_SILICO= NZ-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_I= OE-1 Signed-off-by: Venkateswara Naralasetty Co-developed-by: Yu Zhang (Yuriy) Signed-off-by: Yu Zhang (Yuriy) Reviewed-by: Vasanthakumar Thiagarajan --- drivers/net/wireless/ath/ath11k/cfr.c | 191 ++++++++++++++++++ drivers/net/wireless/ath/ath11k/cfr.h | 41 ++++ drivers/net/wireless/ath/ath11k/core.h | 11 + drivers/net/wireless/ath/ath11k/debugfs_sta.c | 143 ++++++++++++- drivers/net/wireless/ath/ath11k/mac.c | 2 + drivers/net/wireless/ath/ath11k/wmi.c | 41 ++++ drivers/net/wireless/ath/ath11k/wmi.h | 50 ++++- 7 files changed, 476 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/a= th/ath11k/cfr.c index 73ffe3510ffe..5d634d1ef5f5 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.c +++ b/drivers/net/wireless/ath/ath11k/cfr.c @@ -14,6 +14,193 @@ static int ath11k_cfr_process_data(struct ath11k *ar, return 0; } =20 +void ath11k_cfr_decrement_peer_count(struct ath11k *ar, + struct ath11k_sta *arsta) +{ + struct ath11k_cfr *cfr =3D &ar->cfr; + + spin_lock_bh(&cfr->lock); + + if (arsta->cfr_capture.cfr_enable) + cfr->cfr_enabled_peer_cnt--; + + spin_unlock_bh(&cfr->lock); +} + +static enum ath11k_wmi_cfr_capture_bw +ath11k_cfr_bw_to_fw_cfr_bw(enum ath11k_cfr_capture_bw bw) +{ + switch (bw) { + case ATH11K_CFR_CAPTURE_BW_20: + return WMI_PEER_CFR_CAPTURE_BW_20; + case ATH11K_CFR_CAPTURE_BW_40: + return WMI_PEER_CFR_CAPTURE_BW_40; + case ATH11K_CFR_CAPTURE_BW_80: + return WMI_PEER_CFR_CAPTURE_BW_80; + default: + return WMI_PEER_CFR_CAPTURE_BW_MAX; + } +} + +static enum ath11k_wmi_cfr_capture_method +ath11k_cfr_method_to_fw_cfr_method(enum ath11k_cfr_capture_method method) +{ + switch (method) { + case ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME: + return WMI_CFR_CAPTURE_METHOD_NULL_FRAME; + case ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE: + return WMI_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE; + case ATH11K_CFR_CAPTURE_METHOD_PROBE_RESP: + return WMI_CFR_CAPTURE_METHOD_PROBE_RESP; + default: + return WMI_CFR_CAPTURE_METHOD_MAX; + } +} + +int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, + struct ath11k_sta *arsta, + struct ath11k_per_peer_cfr_capture *params, + const u8 *peer_mac) +{ + struct ath11k_cfr *cfr =3D &ar->cfr; + struct wmi_peer_cfr_capture_conf_arg arg; + enum ath11k_wmi_cfr_capture_bw bw; + enum ath11k_wmi_cfr_capture_method method; + int ret =3D 0; + + if (cfr->cfr_enabled_peer_cnt >=3D ATH11K_MAX_CFR_ENABLED_CLIENTS && + !arsta->cfr_capture.cfr_enable) { + ath11k_err(ar->ab, "CFR enable peer threshold reached %u\n", + cfr->cfr_enabled_peer_cnt); + return -ENOSPC; + } + + if (params->cfr_enable =3D=3D arsta->cfr_capture.cfr_enable && + params->cfr_period =3D=3D arsta->cfr_capture.cfr_period && + params->cfr_method =3D=3D arsta->cfr_capture.cfr_method && + params->cfr_bw =3D=3D arsta->cfr_capture.cfr_bw) + return ret; + + if (!params->cfr_enable && !arsta->cfr_capture.cfr_enable) + return ret; + + bw =3D ath11k_cfr_bw_to_fw_cfr_bw(params->cfr_bw); + if (bw >=3D WMI_PEER_CFR_CAPTURE_BW_MAX) { + ath11k_warn(ar->ab, "FW doesn't support configured bw %d\n", + params->cfr_bw); + return -EINVAL; + } + + method =3D ath11k_cfr_method_to_fw_cfr_method(params->cfr_method); + if (method >=3D WMI_CFR_CAPTURE_METHOD_MAX) { + ath11k_warn(ar->ab, "FW doesn't support configured method %d\n", + params->cfr_method); + return -EINVAL; + } + + arg.request =3D params->cfr_enable; + arg.periodicity =3D params->cfr_period; + arg.bw =3D bw; + arg.method =3D method; + + ret =3D ath11k_wmi_peer_set_cfr_capture_conf(ar, arsta->arvif->vdev_id, + peer_mac, &arg); + if (ret) { + ath11k_warn(ar->ab, + "failed to send cfr capture info: vdev_id %u peer %pM: %d\n", + arsta->arvif->vdev_id, peer_mac, ret); + return ret; + } + + spin_lock_bh(&cfr->lock); + + if (params->cfr_enable && + params->cfr_enable !=3D arsta->cfr_capture.cfr_enable) + cfr->cfr_enabled_peer_cnt++; + else if (!params->cfr_enable) + cfr->cfr_enabled_peer_cnt--; + + spin_unlock_bh(&cfr->lock); + + arsta->cfr_capture.cfr_enable =3D params->cfr_enable; + arsta->cfr_capture.cfr_period =3D params->cfr_period; + arsta->cfr_capture.cfr_method =3D params->cfr_method; + arsta->cfr_capture.cfr_bw =3D params->cfr_bw; + + return ret; +} + +static ssize_t ath11k_read_file_enable_cfr(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar =3D file->private_data; + char buf[32] =3D {}; + size_t len; + + mutex_lock(&ar->conf_mutex); + len =3D scnprintf(buf, sizeof(buf), "%d\n", ar->cfr_enabled); + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath11k_write_file_enable_cfr(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar =3D file->private_data; + u32 enable_cfr; + int ret; + + if (kstrtouint_from_user(ubuf, count, 0, &enable_cfr)) + return -EINVAL; + + guard(mutex)(&ar->conf_mutex); + + if (ar->state !=3D ATH11K_STATE_ON) + return -ENETDOWN; + + if (enable_cfr > 1) + return -EINVAL; + + if (ar->cfr_enabled =3D=3D enable_cfr) + return count; + + ret =3D ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PER_PEER_CFR_ENABLE, + enable_cfr, ar->pdev->pdev_id); + if (ret) { + ath11k_warn(ar->ab, + "Failed to enable/disable per peer cfr %d\n", ret); + return ret; + } + + ar->cfr_enabled =3D enable_cfr; + + return count; +} + +static const struct file_operations fops_enable_cfr =3D { + .read =3D ath11k_read_file_enable_cfr, + .write =3D ath11k_write_file_enable_cfr, + .open =3D simple_open, + .owner =3D THIS_MODULE, + .llseek =3D default_llseek, +}; + +static void ath11k_cfr_debug_unregister(struct ath11k *ar) +{ + debugfs_remove(ar->cfr.enable_cfr); + ar->cfr.enable_cfr =3D NULL; +} + +static void ath11k_cfr_debug_register(struct ath11k *ar) +{ + ar->cfr.enable_cfr =3D debugfs_create_file("enable_cfr", 0600, + ar->debug.debugfs_pdev, ar, + &fops_enable_cfr); +} + void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, u32 buf_id) { @@ -85,6 +272,7 @@ void ath11k_cfr_deinit(struct ath11k_base *ab) ar =3D ab->pdevs[i].ar; cfr =3D &ar->cfr; =20 + ath11k_cfr_debug_unregister(ar); ath11k_cfr_ring_free(ar); =20 spin_lock_bh(&cfr->lut_lock); @@ -140,6 +328,8 @@ int ath11k_cfr_init(struct ath11k_base *ab) } =20 cfr->lut_num =3D num_lut_entries; + + ath11k_cfr_debug_register(ar); } =20 return 0; @@ -149,6 +339,7 @@ int ath11k_cfr_init(struct ath11k_base *ab) ar =3D ab->pdevs[i].ar; cfr =3D &ar->cfr; =20 + ath11k_cfr_debug_unregister(ar); ath11k_cfr_ring_free(ar); =20 spin_lock_bh(&cfr->lut_lock); diff --git a/drivers/net/wireless/ath/ath11k/cfr.h b/drivers/net/wireless/a= th/ath11k/cfr.h index 65b87d759329..054962f6cfb3 100644 --- a/drivers/net/wireless/ath/ath11k/cfr.h +++ b/drivers/net/wireless/ath/ath11k/cfr.h @@ -14,10 +14,14 @@ #define ATH11K_CFR_EVENT_TIMEOUT_MS 1 #define ATH11K_CFR_NUM_RING_ENTRIES 1 =20 +#define ATH11K_MAX_CFR_ENABLED_CLIENTS 10 #define CFR_MAX_LUT_ENTRIES 136 =20 #define HOST_MAX_CHAINS 8 =20 +struct ath11k_sta; +struct ath11k_per_peer_cfr_capture; + struct ath11k_cfr_dma_hdr { u16 info0; u16 info1; @@ -48,6 +52,8 @@ struct ath11k_cfr { /* Protect for lut entries */ spinlock_t lut_lock; struct ath11k_look_up_table *lut; + struct dentry *enable_cfr; + u8 cfr_enabled_peer_cnt; u32 lut_num; u64 tx_evt_cnt; u64 dbr_evt_cnt; @@ -61,11 +67,32 @@ struct ath11k_cfr { u64 cfr_dma_aborts; }; =20 +enum ath11k_cfr_capture_method { + ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME, + ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE, + ATH11K_CFR_CAPTURE_METHOD_PROBE_RESP, + ATH11K_CFR_CAPTURE_METHOD_MAX, +}; + +enum ath11k_cfr_capture_bw { + ATH11K_CFR_CAPTURE_BW_20, + ATH11K_CFR_CAPTURE_BW_40, + ATH11K_CFR_CAPTURE_BW_80, + ATH11K_CFR_CAPTURE_BW_MAX, +}; + #ifdef CONFIG_ATH11K_CFR int ath11k_cfr_init(struct ath11k_base *ab); void ath11k_cfr_deinit(struct ath11k_base *ab); void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, u32 buf_id); +void ath11k_cfr_decrement_peer_count(struct ath11k *ar, + struct ath11k_sta *arsta); +int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, + struct ath11k_sta *arsta, + struct ath11k_per_peer_cfr_capture *params, + const u8 *peer_mac); + #else static inline int ath11k_cfr_init(struct ath11k_base *ab) { @@ -80,5 +107,19 @@ static inline void ath11k_cfr_lut_update_paddr(struct a= th11k *ar, dma_addr_t paddr, u32 buf_id) { } + +static inline void ath11k_cfr_decrement_peer_count(struct ath11k *ar, + struct ath11k_sta *arsta) +{ +} + +static inline int +ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, + struct ath11k_sta *arsta, + struct ath11k_per_peer_cfr_capture *params, + const u8 *peer_mac) +{ + return 0; +} #endif /* CONFIG_ATH11K_CFR */ #endif /* ATH11K_CFR_H */ diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/= ath/ath11k/core.h index 40fb7cee3e43..3f41e6569a78 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -532,6 +532,13 @@ struct ath11k_per_ppdu_tx_stats { =20 DECLARE_EWMA(avg_rssi, 10, 8) =20 +struct ath11k_per_peer_cfr_capture { + enum ath11k_cfr_capture_method cfr_method; + enum ath11k_cfr_capture_bw cfr_bw; + u32 cfr_enable; + u32 cfr_period; +}; + struct ath11k_sta { struct ath11k_vif *arvif; =20 @@ -572,6 +579,10 @@ struct ath11k_sta { bool peer_current_ps_valid; =20 u32 bw_prev; + +#ifdef CONFIG_ATH11K_CFR + struct ath11k_per_peer_cfr_capture cfr_capture; +#endif }; =20 #define ATH11K_MIN_5G_FREQ 4150 diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wi= reless/ath/ath11k/debugfs_sta.c index d89d0f28d890..dfb9d877d28a 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights res= erved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ =20 @@ -240,6 +239,141 @@ static const struct file_operations fops_tx_stats =3D= { .llseek =3D default_llseek, }; =20 +#ifdef CONFIG_ATH11K_CFR +static ssize_t ath11k_dbg_sta_write_cfr_capture(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta =3D file->private_data; + struct ath11k_sta *arsta =3D ath11k_sta_to_arsta(sta); + struct ath11k *ar =3D arsta->arvif->ar; + struct ath11k_cfr *cfr =3D &ar->cfr; + struct wmi_peer_cfr_capture_conf_arg arg; + u32 cfr_capture_enable =3D 0, cfr_capture_bw =3D 0; + u32 cfr_capture_method =3D 0, cfr_capture_period =3D 0; + char buf[64] =3D {}; + int ret; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + guard(mutex)(&ar->conf_mutex); + + if (ar->state !=3D ATH11K_STATE_ON) + return -ENETDOWN; + + if (!ar->cfr_enabled) + return -EINVAL; + + ret =3D sscanf(buf, "%u %u %u %u", &cfr_capture_enable, &cfr_capture_bw, + &cfr_capture_period, &cfr_capture_method); + + if (ret < 1 || (cfr_capture_enable && ret !=3D 4)) + return -EINVAL; + + if (cfr_capture_enable =3D=3D arsta->cfr_capture.cfr_enable && + (cfr_capture_period && + cfr_capture_period =3D=3D arsta->cfr_capture.cfr_period) && + cfr_capture_bw =3D=3D arsta->cfr_capture.cfr_bw && + cfr_capture_method =3D=3D arsta->cfr_capture.cfr_method) + return count; + + if (!cfr_capture_enable && + cfr_capture_enable =3D=3D arsta->cfr_capture.cfr_enable) + return count; + + if (cfr_capture_enable > WMI_PEER_CFR_CAPTURE_ENABLE || + cfr_capture_bw > arsta->bw || + cfr_capture_bw > WMI_PEER_CFR_CAPTURE_BW_80 || + cfr_capture_method > ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE = || + cfr_capture_period > WMI_PEER_CFR_PERIODICITY_MAX) + return -EINVAL; + + /* Target expects cfr period in multiple of 10 */ + if (cfr_capture_period % 10) { + ath11k_err(ar->ab, "periodicity should be 10x\n"); + return -EINVAL; + } + + if (ar->cfr.cfr_enabled_peer_cnt >=3D ATH11K_MAX_CFR_ENABLED_CLIENTS && + !arsta->cfr_capture.cfr_enable) { + ath11k_err(ar->ab, "CFR enable peer threshold reached %u\n", + ar->cfr.cfr_enabled_peer_cnt); + return -EINVAL; + } + + if (!cfr_capture_enable) { + cfr_capture_bw =3D arsta->cfr_capture.cfr_bw; + cfr_capture_period =3D arsta->cfr_capture.cfr_period; + cfr_capture_method =3D arsta->cfr_capture.cfr_method; + } + + arg.request =3D cfr_capture_enable; + arg.periodicity =3D cfr_capture_period; + arg.bw =3D cfr_capture_bw; + arg.method =3D cfr_capture_method; + + ret =3D ath11k_wmi_peer_set_cfr_capture_conf(ar, arsta->arvif->vdev_id, + sta->addr, &arg); + if (ret) { + ath11k_warn(ar->ab, + "failed to send cfr capture info: vdev_id %u peer %pM: %d\n", + arsta->arvif->vdev_id, sta->addr, ret); + return ret; + } + + spin_lock_bh(&ar->cfr.lock); + + if (cfr_capture_enable && + cfr_capture_enable !=3D arsta->cfr_capture.cfr_enable) + cfr->cfr_enabled_peer_cnt++; + else if (!cfr_capture_enable) + cfr->cfr_enabled_peer_cnt--; + + spin_unlock_bh(&ar->cfr.lock); + + arsta->cfr_capture.cfr_enable =3D cfr_capture_enable; + arsta->cfr_capture.cfr_period =3D cfr_capture_period; + arsta->cfr_capture.cfr_bw =3D cfr_capture_bw; + arsta->cfr_capture.cfr_method =3D cfr_capture_method; + + return count; +} + +static ssize_t ath11k_dbg_sta_read_cfr_capture(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta =3D file->private_data; + struct ath11k_sta *arsta =3D ath11k_sta_to_arsta(sta); + struct ath11k *ar =3D arsta->arvif->ar; + char buf[512] =3D {}; + int len =3D 0; + + mutex_lock(&ar->conf_mutex); + + len +=3D scnprintf(buf + len, sizeof(buf) - len, "cfr_enabled =3D %d\n", + arsta->cfr_capture.cfr_enable); + len +=3D scnprintf(buf + len, sizeof(buf) - len, "bandwidth =3D %d\n", + arsta->cfr_capture.cfr_bw); + len +=3D scnprintf(buf + len, sizeof(buf) - len, "period =3D %d\n", + arsta->cfr_capture.cfr_period); + len +=3D scnprintf(buf + len, sizeof(buf) - len, "cfr_method =3D %d\n", + arsta->cfr_capture.cfr_method); + + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_peer_cfr_capture =3D { + .write =3D ath11k_dbg_sta_write_cfr_capture, + .read =3D ath11k_dbg_sta_read_cfr_capture, + .open =3D simple_open, + .owner =3D THIS_MODULE, + .llseek =3D default_llseek, +}; +#endif /* CONFIG_ATH11K_CFR */ + static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -877,6 +1011,13 @@ void ath11k_debugfs_sta_op_add(struct ieee80211_hw *h= w, struct ieee80211_vif *vi debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta, &fops_htt_peer_stats_reset); =20 +#ifdef CONFIG_ATH11K_CFR + if (test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT, + ar->ab->wmi_ab.svc_map)) + debugfs_create_file("cfr_capture", 0600, dir, sta, + &fops_peer_cfr_capture); +#endif/* CONFIG_ATH11K_CFR */ + debugfs_create_file("peer_ps_state", 0400, dir, sta, &fops_peer_ps_state); =20 diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/a= th/ath11k/mac.c index c6360d6a72bd..965c377cd8dc 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9979,6 +9979,8 @@ static int ath11k_mac_op_sta_state(struct ieee80211_h= w *hw, } spin_unlock_bh(&ar->ab->base_lock); mutex_unlock(&ar->ab->tbl_mtx_lock); + + ath11k_cfr_decrement_peer_count(ar, arsta); } else if (old_state =3D=3D IEEE80211_STA_AUTH && new_state =3D=3D IEEE80211_STA_ASSOC && (vif->type =3D=3D NL80211_IFTYPE_AP || diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/a= th/ath11k/wmi.c index edff6fb61344..846c9946a084 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -3941,6 +3941,47 @@ int ath11k_wmi_fils_discovery_tmpl(struct ath11k *ar= , u32 vdev_id, return 0; } =20 +int ath11k_wmi_peer_set_cfr_capture_conf(struct ath11k *ar, + u32 vdev_id, const u8 *mac_addr, + struct wmi_peer_cfr_capture_conf_arg *arg) +{ + struct ath11k_pdev_wmi *wmi =3D ar->wmi; + struct wmi_peer_cfr_capture_cmd_fixed_param *cmd; + struct sk_buff *skb; + int ret; + + skb =3D ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd =3D (struct wmi_peer_cfr_capture_cmd_fixed_param *)skb->data; + cmd->tlv_header =3D FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_PEER_CFR_CAPTURE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + memcpy(&cmd->mac_addr, mac_addr, ETH_ALEN); + cmd->request =3D arg->request; + cmd->vdev_id =3D vdev_id; + cmd->periodicity =3D arg->periodicity; + cmd->bandwidth =3D arg->bw; + cmd->capture_method =3D arg->method; + + ret =3D ath11k_wmi_cmd_send(ar->wmi, skb, WMI_PEER_CFR_CAPTURE_CMDID); + if (ret) { + ath11k_warn(ar->ab, + "WMI vdev %d failed to send peer cfr capture cmd: %d\n", + vdev_id, ret); + dev_kfree_skb(skb); + } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI peer CFR capture cmd req %u id %u period %u bw %u mode %u\n", + arg->request, vdev_id, arg->periodicity, + arg->bw, arg->method); + + return ret; +} + int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id, struct sk_buff *tmpl) { diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/a= th/ath11k/wmi.h index 7a55fe0879c0..1562d169ba9a 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -362,6 +362,10 @@ enum wmi_tlv_cmd_id { WMI_PEER_REORDER_QUEUE_REMOVE_CMDID, WMI_PEER_SET_RX_BLOCKSIZE_CMDID, WMI_PEER_ANTDIV_INFO_REQ_CMDID, + WMI_PEER_RESERVED0_CMDID, + WMI_PEER_TID_MSDUQ_QDEPTH_THRESH_UPDATE_CMDID, + WMI_PEER_TID_CONFIGURATIONS_CMDID, + WMI_PEER_CFR_CAPTURE_CMDID, WMI_BCN_TX_CMDID =3D WMI_TLV_CMD(WMI_GRP_MGMT), WMI_PDEV_SEND_BCN_CMDID, WMI_BCN_TMPL_CMDID, @@ -3833,7 +3837,8 @@ struct wmi_scan_prob_req_oui_cmd { #define WMI_TX_PARAMS_DWORD1_BW_MASK GENMASK(14, 8) #define WMI_TX_PARAMS_DWORD1_PREAMBLE_TYPE GENMASK(19, 15) #define WMI_TX_PARAMS_DWORD1_FRAME_TYPE BIT(20) -#define WMI_TX_PARAMS_DWORD1_RSVD GENMASK(31, 21) +#define WMI_TX_PARAMS_DWORD1_CFR_CAPTURE BIT(21) +#define WMI_TX_PARAMS_DWORD1_RSVD GENMASK(31, 22) =20 struct wmi_mgmt_send_params { u32 tlv_header; @@ -4218,6 +4223,45 @@ enum cc_setting_code { */ }; =20 +enum ath11k_wmi_cfr_capture_bw { + WMI_PEER_CFR_CAPTURE_BW_20, + WMI_PEER_CFR_CAPTURE_BW_40, + WMI_PEER_CFR_CAPTURE_BW_80, + WMI_PEER_CFR_CAPTURE_BW_MAX, +}; + +enum ath11k_wmi_cfr_capture_method { + WMI_CFR_CAPTURE_METHOD_NULL_FRAME, + WMI_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE, + WMI_CFR_CAPTURE_METHOD_PROBE_RESP, + WMI_CFR_CAPTURE_METHOD_MAX, +}; + +struct wmi_peer_cfr_capture_conf_arg { + enum ath11k_wmi_cfr_capture_bw bw; + enum ath11k_wmi_cfr_capture_method method; + u32 request; + u32 periodicity; +}; + +struct wmi_peer_cfr_capture_cmd_fixed_param { + u32 tlv_header; + u32 request; + struct wmi_mac_addr mac_addr; + u32 vdev_id; + u32 periodicity; + /* BW of measurement - of type enum ath11k_wmi_cfr_capture_bw */ + u32 bandwidth; + /* Method used to capture CFR - of type enum ath11k_wmi_cfr_capture_metho= d */ + u32 capture_method; +} __packed; + +#define WMI_PEER_CFR_CAPTURE_ENABLE 1 +#define WMI_PEER_CFR_CAPTURE_DISABLE 0 + +/*periodicity in ms */ +#define WMI_PEER_CFR_PERIODICITY_MAX 600000 + static inline enum cc_setting_code ath11k_wmi_cc_setting_code_to_reg(enum wmi_reg_cc_setting_code status_code) { @@ -6532,5 +6576,7 @@ bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *a= r); int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar, u32 vdev_id, struct ath11k_reg_tpc_power_info *param); - +int ath11k_wmi_peer_set_cfr_capture_conf(struct ath11k *ar, + u32 vdev_id, const u8 *mac, + struct wmi_peer_cfr_capture_conf_arg *arg); #endif --=20 2.34.1