From patchwork Fri Apr 24 19:32:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508937 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 50C8713B2 for ; Fri, 24 Apr 2020 19:43:14 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 290D52173E for ; Fri, 24 Apr 2020 19:43:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="TekCsrys"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="CKbfVjkV" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 290D52173E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Hww7puxfeJNXtuv75kJ9Q0B1SBF/e+gYgdavS4f4YTg=; b=TekCsrysqb92r9 W4/Cy7vWed4fZucg+yydWJjOM9Cy9W0/CLd0JCf7A+7livBI7wpEHK6ZhKni0mW6OSzREjWhh5ERr TEBWGEEDVZGsSd57XvQIGpemBLYF7Ey2+vFO0xhmm5rzO5SHxAry3dYXOFYDNId2+iVDgN2u8o9Ra 1lX4jkfeGCWtU4pOxUIcFFkXXxeMXZoDzFnahiGLb5YF1PTV8n5/k54nGnJGzgBStnVyLGDapIhC/ 9PuSjv3jwKAjd2ODs19EwXlwR+Vtb+/rkJackTjaxB0x4CRLjlVCAkRxRgreXeWwWO4LIl/UQilE6 7D9IexbTQizSb86yWXQw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EB-00063H-Ll; Fri, 24 Apr 2020 19:43:11 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4E8-00061n-Vn for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:10 +0000 X-UUID: 8dc05d36f21d4a089099ff5cabe9cc83-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=I+YRhVrLNgwRO1l9UFDd9D9zLrcTC4/loe2w8YLs6NE=; b=CKbfVjkVUwUgfB8LbKRIVhfZyMvsgdNwvMEGh4a62yQ0VkdBjgY3djgYNRoVO37NeuDk0VxUtzhCR4Kjb8ztSTqPfX8xoK8txrbzpmrERk3BtI1k/xhcho/K2cIxhp1z+gqFl4zbdME67d9echKww5v0XpWBaOblfTgRuI5wHwo=; X-UUID: 8dc05d36f21d4a089099ff5cabe9cc83-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1093415165; Fri, 24 Apr 2020 11:43:06 -0800 Received: from mtkmbs08n2.mediatek.inc (172.21.101.56) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:00 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:45 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:48 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 01/18] mt76: avoid rx reorder buffer overflow Date: Sat, 25 Apr 2020 03:32:22 +0800 Message-ID: <8ec4dbd2b0254cd16ac9bdae6666141872c6858c.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-TM-SNTS-SMTP: 841B23960D011988730A4DE0BB38752B0586DEF0F023820815934341FB2751F32000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124309_030578_5AB634B9 X-CRM114-Status: UNSURE ( 6.75 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org Enlarge slot to support 11ax 256 BA (256 MPDUs in an AMPDU) Signed-off-by: Chih-Min Chen Signed-off-by: Ryder Lee --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index f77f03530259..acdbe6f8248d 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -152,8 +152,8 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) struct ieee80211_sta *sta; struct mt76_rx_tid *tid; bool sn_less; - u16 seqno, head, size; - u8 ackp, idx; + u16 seqno, head, size, idx; + u8 ackp; __skb_queue_tail(frames, skb); @@ -239,7 +239,7 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) } int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno, - u16 ssn, u8 size) + u16 ssn, u16 size) { struct mt76_rx_tid *tid; @@ -264,7 +264,7 @@ EXPORT_SYMBOL_GPL(mt76_rx_aggr_start); static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) { - u8 size = tid->size; + u16 size = tid->size; int i; spin_lock_bh(&tid->lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 6106dc4fea44..6e1dae718602 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -244,8 +244,8 @@ struct mt76_rx_tid { struct delayed_work reorder_work; u16 head; - u8 size; - u8 nframes; + u16 size; + u16 nframes; u8 num; @@ -796,7 +796,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, void mt76_set_stream_caps(struct mt76_dev *dev, bool vht); int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid, - u16 ssn, u8 size); + u16 ssn, u16 size); void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid); void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, From patchwork Fri Apr 24 19:32:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508927 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1C20813B2 for ; Fri, 24 Apr 2020 19:33:16 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EE3BB2075A for ; Fri, 24 Apr 2020 19:33:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="RAhquABu"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="g70uUygv" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EE3BB2075A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=GbmbN0/VWSPpaQ0Hy8moE/6qJYO+5MIX0OPRyvoYeEo=; b=RAhquABuGeqjF+ NvhVSq5cKcbw8cYw0bMa+5OFUCjEM5FFJt0IyN8oUedxAY1VZ0D2CuapM+Di3Pi21aQUR7cCpOyDb siSQV/jMHubbH8OqdNtAMK8Q6z8uQd4+77WerNdsqvjYeFVPXIPls7nA2775G6luLdZXBnnFKe/hl 9wRqQxUwKtVChjf6g+cXfjKQqY86+hz3pyFxdbPgVw87c1JdY6ENlq7XRWp2jr35bqg/a1GSY8zdG 76k/UepjhXGVQjqNNjaQUfxAcFTsAi0lZU1Rfyj+K5rz2wRM8BfUjtIe0Q7z3bQ/fUphtG2t25sSF 1zc2FH1q14uiXeLZYs9Q==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44Y-0007rO-4v; Fri, 24 Apr 2020 19:33:14 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44R-0007ks-26 for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:33:08 +0000 X-UUID: 7af1b89d297d4b7b83e53801707f7f14-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=yEW8X2NnaYwRxQbxBF03TWaDWQpug/aAmvpFQkebjBg=; b=g70uUygvnnPEycQxlKQxqu9RPuRLWgMryzfCP/vMcoAe5zLHh9ECuwWFdj6h6CkLustSjYOnlnEDMe58hzGFp6cJk4bUXSIvnp+l2HTli5h+9oaawd7K2HcdG893uUHx2L590tpYoZqI93fxAuRpojO3VxDKzfda8SHKV8l5tPA=; X-UUID: 7af1b89d297d4b7b83e53801707f7f14-20200424 Received: from mtkcas67.mediatek.inc [(172.29.193.45)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 2016957675; Fri, 24 Apr 2020 11:33:04 -0800 Received: from mtkmbs08n1.mediatek.inc (172.21.101.55) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:00 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n1.mediatek.inc (172.21.101.55) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:46 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:49 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 02/18] mt76: add support for HE RX rate reporting Date: Sat, 25 Apr 2020 03:32:23 +0800 Message-ID: <4de594b915945eef1e98c856391f25568f415fcd.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_123307_109563_DBC26A67 X-CRM114-Status: UNSURE ( 8.37 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org Add support for encoding and reporting HE RX rates. Signed-off-by: Ryder Lee --- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 +++- drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 176c22a5319a..f13114b07b6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -676,7 +676,6 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_hw **hw, struct ieee80211_sta **sta) { - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct mt76_rx_status mstat; @@ -688,6 +687,9 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, status->enc_flags = mstat.enc_flags; status->encoding = mstat.encoding; status->bw = mstat.bw; + status->he_ru = mstat.he_ru; + status->he_gi = mstat.he_gi; + status->he_dcm = mstat.he_dcm; status->rate_idx = mstat.rate_idx; status->nss = mstat.nss; status->band = mstat.band; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 6e1dae718602..cebef52fb685 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -460,7 +460,8 @@ struct mt76_rx_status { u16 freq; u32 flag; u8 enc_flags; - u8 encoding:2, bw:3; + u8 encoding:2, bw:3, he_ru:3; + u8 he_gi:2, he_dcm:1; u8 rate_idx; u8 nss; u8 band; From patchwork Fri Apr 24 19:32:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508949 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C2EEC13B2 for ; Fri, 24 Apr 2020 19:43:29 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9B1222173E for ; Fri, 24 Apr 2020 19:43:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="s3giS1hv"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="Syt9uRre" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9B1222173E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=r+6WjxUNkPFikrVE/Z9FaQK+BcCcs90D/q9PnZAGGnA=; b=s3giS1hvuYSnoS RFfEfZVPferwzIWQ5cqVognZY+A12eKxNOr8HVx8npABZ1qWcbk/5S6ntfPoa5i4rZaxW0fVcsePF X5X20nHo/zBU7sAosEL8qlFPawfXkdYQA8bDycktDPy3r17W2wnCSQvKUUYsamMZ3uqUiAQs6S3Vz z3hr3xA3TMcf8/yWhjvgvg0cDb5JMBPWNHVbuJXk+nf0kpTO6f3lO5OgX/kdDw5F7AArqr5O0VnG9 WeFgGnfj9JnRWAWl3O1o7nipFC+AiJcEi4FvjBYSlCtjxR40LWA2IWBWsvlToiwj+D3JZDdoE22M3 P494wzBPy1L/LL5rTLVg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4ER-0006Tk-CO; Fri, 24 Apr 2020 19:43:27 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4ED-00061n-JZ for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:15 +0000 X-UUID: 814d14e13d2d480f8ef5aba9adc6ed5b-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=28kyiWh+DJyUahYzVncxWTlfyCRoL0b/vSUBaKQXca8=; b=Syt9uRrej5CuUgWGAjl9w7X/Rt/ITzY9KX/bf7x6GKLOIza6F15cuAaqMmAjZSkdZdvFVGhRg+6eZpa5ddAsgnc78k0sCRt/JBvZunf7qhLGVva3IKmkF4JG6r/03o7oEWG0iVwBe043D7GtBNaH2e6nGJFg/oNARXvueuERR98=; X-UUID: 814d14e13d2d480f8ef5aba9adc6ed5b-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 410285144; Fri, 24 Apr 2020 11:43:06 -0800 Received: from mtkmbs08n2.mediatek.inc (172.21.101.56) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:01 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:46 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:49 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 03/18] mt76: add Rx stats support for radiotap Date: Sat, 25 Apr 2020 03:32:24 +0800 Message-ID: X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-TM-SNTS-SMTP: 2FE1901E1305162641D7C11B72595574A4AF624437F882A3DDE5620F69FCF0D02000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124313_662698_A61E1896 X-CRM114-Status: UNSURE ( 9.28 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org HE deivces need to add Rx radiotap header. Signed-off-by: Ryder Lee --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mac80211.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76.h | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index acdbe6f8248d..df25c00d9e06 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -119,7 +119,7 @@ static void mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; + struct ieee80211_bar *bar = mt76_skb_get_hdr(skb); struct mt76_wcid *wcid = status->wcid; struct mt76_rx_tid *tid; u16 seqno; @@ -147,7 +147,7 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); struct mt76_wcid *wcid = status->wcid; struct ieee80211_sta *sta; struct mt76_rx_tid *tid; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index f13114b07b6e..f65e1b3e8f7a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -726,7 +726,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb) * Validate the first fragment both here and in mac80211 * All further fragments will be validated by mac80211 only. */ - hdr = (struct ieee80211_hdr *)skb->data; + hdr = mt76_skb_get_hdr(skb); if (ieee80211_is_frag(hdr) && !ieee80211_is_first_frag(hdr->frame_control)) return 0; @@ -799,7 +799,7 @@ mt76_airtime_flush_ampdu(struct mt76_dev *dev) static void mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_wcid *wcid = status->wcid; @@ -836,7 +836,7 @@ static void mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); struct ieee80211_sta *sta; struct ieee80211_hw *hw; struct mt76_wcid *wcid = status->wcid; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index cebef52fb685..b2e619bab0e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -744,6 +744,25 @@ static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb) return ((void *)IEEE80211_SKB_CB(skb)->status.status_driver_data); } +static inline void *mt76_skb_get_hdr(struct sk_buff *skb) +{ + struct mt76_rx_status mstat; + u8 *data = skb->data; + + /* Alignment concerns */ + BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) % 4); + BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) % 4); + + mstat = *((struct mt76_rx_status *)skb->cb); + + if (mstat.flag & RX_FLAG_RADIOTAP_HE) + data += sizeof(struct ieee80211_radiotap_he); + if (mstat.flag & RX_FLAG_RADIOTAP_HE_MU) + data += sizeof(struct ieee80211_radiotap_he_mu); + + return data; +} + static inline void mt76_insert_hdr_pad(struct sk_buff *skb) { int len = ieee80211_get_hdrlen_from_skb(skb); From patchwork Fri Apr 24 19:32:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508925 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3D1F413B2 for ; Fri, 24 Apr 2020 19:33:15 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1C0532075A for ; Fri, 24 Apr 2020 19:33:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="rwyr+J9v"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="Ohk+d/gL" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1C0532075A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=3APgifMB888iMUxNPEFwgETzNV1ZOfkgse4vtYAKsIM=; b=rwyr+J9vPM+tPC YiERkAm4FbnglqbwZ3wv3B0l7dRAFS+7oO9cfJ7POTYwF2E+CgIs1Y4t+uTcYmU67JLeemwT+OoFO A626NMKQrgj+l39Xl/SBTFcmm6PxqjtwMrKSBtdsC2FIq5cblQdqv616gwLhMRuwaAHGZ2UgfEJZ5 I16r37hRzK6TfzRtQVc0txXbYDH1VdSx83j2Jb0H5sUR6nDIIMCROt7whEYUbiwISwFnHmgWVVupz brA79dY+JHZ1ncxpD4dKxIMV5B9FWdpBsW0/YmTOQU1YWPOk6muNPGOaqzuzZ5dUHGtzlEy9RLphh RXkD96NAeMH8uolO4gMQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44X-0007qG-71; Fri, 24 Apr 2020 19:33:13 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44Q-0007k2-1c for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:33:07 +0000 X-UUID: f494c41b834d482cb6cf29dc5a836600-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=XDktOf2vniFyQDGqyF7ynyGfsNnKETf+PHxTBonDFBg=; b=Ohk+d/gL0eT1O4vtwQy1hnZaKOl+CotOV6Sm2SuQr8ckm/cRdZW0rftFHdufmwzBjdbLdtoteEQFPUshpKCGdgYjvk9vBcRKVLDQn2Yz0/6rrjuQL22/svSkZ2bwbHIxq4z37AWIGItO7g5+wyI4uMsqe4iLNXoKKQCSggJrMak=; X-UUID: f494c41b834d482cb6cf29dc5a836600-20200424 Received: from mtkcas67.mediatek.inc [(172.29.193.45)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1240431480; Fri, 24 Apr 2020 11:33:04 -0800 Received: from mtkmbs08n1.mediatek.inc (172.21.101.55) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:00 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n1.mediatek.inc (172.21.101.55) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:46 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:50 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 04/18] mt76: adjust wcid size to support new 802.11ax generation Date: Sat, 25 Apr 2020 03:32:25 +0800 Message-ID: <352573a70a544487e82aff10c20859bc6b44d6a0.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_123306_089176_35512276 X-CRM114-Status: UNSURE ( 8.50 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org The newer 802.11ax devices (i.e. MT7915E) can connect to much more peers than previous generations. Signed-off-by: Ryder Lee --- drivers/net/wireless/mediatek/mt76/mt76.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b2e619bab0e9..2d0fb57f050b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -181,7 +181,7 @@ enum mt76_wcid_flags { MT_WCID_FLAG_PS, }; -#define MT76_N_WCIDS 128 +#define MT76_N_WCIDS 288 /* stored in ieee80211_tx_info::hw_queue */ #define MT_TX_HW_QUEUE_EXT_PHY BIT(3) @@ -201,7 +201,7 @@ struct mt76_wcid { struct ewma_signal rssi; int inactive_count; - u8 idx; + u16 idx; u8 hw_key_idx; u8 sta:1; @@ -268,7 +268,7 @@ struct mt76_rx_tid { struct mt76_tx_cb { unsigned long jiffies; - u8 wcid; + u16 wcid; u8 pktid; u8 flags; }; @@ -443,7 +443,7 @@ struct mt76_mmio { struct mt76_rx_status { union { struct mt76_wcid *wcid; - u8 wcid_idx; + u16 wcid_idx; }; unsigned long reorder_time; @@ -620,7 +620,7 @@ enum mt76_phy_type { #define mt76_hw(dev) (dev)->mphy.hw static inline struct ieee80211_hw * -mt76_wcid_hw(struct mt76_dev *dev, u8 wcid) +mt76_wcid_hw(struct mt76_dev *dev, u16 wcid) { if (wcid <= MT76_N_WCIDS && mt76_wcid_mask_test(dev->wcid_phy_mask, wcid)) From patchwork Fri Apr 24 19:32:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508919 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0D42313B2 for ; Fri, 24 Apr 2020 19:33:12 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E06242075A for ; Fri, 24 Apr 2020 19:33:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="TmPA9COf"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="rSZieFD4" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E06242075A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=eoVGK+hQcTqprV5fu26O0LCUp8hbR+P75oMvLgVZPgg=; b=TmPA9COfBub1B5 yDzI0g2rm7sM9f4c3XEBwlBjuWlRzKOdlCBI6laHgvzXdBYV8LIowm3640x0HnNsLZo9Opn4oEDy7 zhZh3TeN7l3RIXM7A9DkYPa+gK79sLK1LMhB5Iwld/hqGWtcsqF2EPvqvWsDouchvlQUuRpa9f252 qxyCm+iZYcQyvZWnqNLLSCNcQv0opT/UJsyiRJUd9Xv4vGaJoyf6hmM2y+AroloDbbJSVOuMV5kz7 RrnvlV4SHNYPrN3z1Ko6wmaVgDbgnQmRvxw27rdaP3qCLZ2OdXn/9p+DsUp3jcOmNkwlbue6BnYHU QckefGPuhNfUjRyX7RIA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44U-0007my-10; Fri, 24 Apr 2020 19:33:10 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44O-0007iz-Oq for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:33:05 +0000 X-UUID: 78074ef2ab1c4969bc433c415a7622b4-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=333UAHMqqUfl/oqO1oNmHQeRS6Hf48FRzVK5RbsxFDg=; b=rSZieFD4rmu6Nvnhips9wGHPy6kKX+BeDzQqpf+EBU0RydesTJ6v6w3nDhfHSA48bGLPFPuEkSpn5JlSH0gT9Z5Rn3ijDkD9TFbS400hto6sOL0KD3KxYapSQBRnfw7ZG6Zcv34GN+pEEntSOjavhpLDIPRvV6yIqlLYPBEik7I=; X-UUID: 78074ef2ab1c4969bc433c415a7622b4-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 105296040; Fri, 24 Apr 2020 11:32:54 -0800 Received: from MTKMBS06N1.mediatek.inc (172.21.101.129) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:32:49 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs06n1.mediatek.inc (172.21.101.129) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:51 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:50 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 05/18] mt76: add HE phy modes and hardware queue Date: Sat, 25 Apr 2020 03:32:26 +0800 Message-ID: X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_123304_806380_651FCF91 X-CRM114-Status: UNSURE ( 6.60 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org This is a preliminary patch to support 11ax deivces. Signed-off-by: Ryder Lee --- drivers/net/wireless/mediatek/mt76/mt76.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 2d0fb57f050b..254fbf5d094a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -60,6 +60,7 @@ enum mt76_txq_id { MT_TXQ_BK = IEEE80211_AC_BK, MT_TXQ_PSD, MT_TXQ_MCU, + MT_TXQ_MCU_WA, MT_TXQ_BEACON, MT_TXQ_CAB, MT_TXQ_FWDL, @@ -69,6 +70,7 @@ enum mt76_txq_id { enum mt76_rxq_id { MT_RXQ_MAIN, MT_RXQ_MCU, + MT_RXQ_MCU_WA, __MT_RXQ_MAX }; @@ -579,6 +581,10 @@ enum mt76_phy_type { MT_PHY_TYPE_HT, MT_PHY_TYPE_HT_GF, MT_PHY_TYPE_VHT, + MT_PHY_TYPE_HE_SU = 8, + MT_PHY_TYPE_HE_EXT_SU, + MT_PHY_TYPE_HE_TB, + MT_PHY_TYPE_HE_MU, }; #define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) From patchwork Fri Apr 24 19:32:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508961 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C9ECC13B2 for ; Fri, 24 Apr 2020 19:43:38 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7F61D2098B for ; Fri, 24 Apr 2020 19:43:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="dtIAfkOd"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="CFXSMMw2" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7F61D2098B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=1hzGweNCq8QTostAeVhhphqENJWWKNOyprHmd+6qjtY=; b=dtIAfkOd+1SDqO EWyliDI5r1Ghu/KEcG5KYURxrtctv8Vu2fxEjunGqt1N5Tc0MCwgMWGVHmJbC2ipqCrkISIQU+KUQ JpUgscjyNjy7/JsFbxscNy1e7egSYeH9vLxRCj7eUSWOh5pqlCdKiOH2DLma6uzFz5bLJD+t0RbQo mgyRTrD+EziYVbNb924IBNKHkdgeWxGGdH71VIQw6BIUzklWn/u9eSqkZKlfeNzVzeSTGvFepfF13 f3ZzbPtYu9T+mXTx4l03m0zRGT9H8DS4aMrfBwTI84VXJNf3E6RPc0hTw9O8LcWjfE5k20xcqIM0l hrFDcbd60dPnGQmZb1Ew==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4Ea-0006lT-1x; Fri, 24 Apr 2020 19:43:36 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EI-00067A-AK for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:23 +0000 X-UUID: e8b3dc0eb724400e9ea4dd6965cdd494-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=+/c+8SN/L67vPoOb+KDR67/tx96PI5Rxb9oTR1rx9YA=; b=CFXSMMw2+qEMWrCpEP8LtZCZ8l9BcVDq+Zf7gvHSxpoiU+62mwDTaFRN+YiaH0sKwO87093OPUz+hhKB/9xBUoM2DtKWcxpP2+dpANnCfjFSC+pfA3VDWtNVwOEaeV8cjsPgdbPtsv8hpDnQEJmtv18ySFjEZvlqE26AYDeFK/I=; X-UUID: e8b3dc0eb724400e9ea4dd6965cdd494-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1222416372; Fri, 24 Apr 2020 11:43:10 -0800 Received: from MTKMBS02N2.mediatek.inc (172.21.101.101) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:03 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs02n2.mediatek.inc (172.21.101.101) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:47 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:50 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 06/18] mt76: add mac80211 driver for MT7915 PCIe-based chipsets Date: Sat, 25 Apr 2020 03:32:27 +0800 Message-ID: X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-TM-SNTS-SMTP: D2EEFB2375008A58FF51AC11397C0814BC27061C69FBC4BC9C52FD04539653F72000:8 X-MTK: N X-Spam-Note: CRM114 run bypassed due to message size (288306 bytes) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org Add support for the MediaTek latest generation IEEE 802.11ax 4x4 device MT7915E, which supports concurrent dual-band operation at both 5GHz and 2.4GHz. Note that this patch just add basic part and will add more HE capabilities support in the further patches. The driver supports AP, Station, Mesh and monitor mode. Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen Signed-off-by: Chih-Min Chen Suggested-by: Shihwei Lin Tested-by: Evelyn Tsai Acked-by: Yiwei Chung Acked-by: YF Luo --- drivers/net/wireless/mediatek/mt76/Kconfig | 1 + drivers/net/wireless/mediatek/mt76/Makefile | 1 + .../net/wireless/mediatek/mt76/mt7915/Kconfig | 13 + .../wireless/mediatek/mt76/mt7915/Makefile | 6 + .../wireless/mediatek/mt76/mt7915/debugfs.c | 245 ++ .../net/wireless/mediatek/mt76/mt7915/dma.c | 285 ++ .../wireless/mediatek/mt76/mt7915/eeprom.c | 125 + .../wireless/mediatek/mt76/mt7915/eeprom.h | 78 + .../net/wireless/mediatek/mt76/mt7915/init.c | 395 +++ .../net/wireless/mediatek/mt76/mt7915/mac.c | 1298 +++++++++ .../net/wireless/mediatek/mt76/mt7915/mac.h | 328 +++ .../net/wireless/mediatek/mt76/mt7915/main.c | 741 ++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.c | 2313 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.h | 837 ++++++ .../wireless/mediatek/mt76/mt7915/mt7915.h | 441 ++++ .../net/wireless/mediatek/mt76/mt7915/pci.c | 166 ++ .../net/wireless/mediatek/mt76/mt7915/regs.h | 343 +++ 17 files changed, 7616 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/Kconfig create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/Makefile create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/dma.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mac.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mac.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/main.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mcu.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mcu.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/pci.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/regs.h diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index cbc2d8a5d354..41533a0e1720 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -24,3 +24,4 @@ source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig" +source "drivers/net/wireless/mediatek/mt76/mt7915/Kconfig" diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index a1dfafec431b..ef663b873b0b 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ obj-$(CONFIG_MT7603E) += mt7603/ obj-$(CONFIG_MT7615_COMMON) += mt7615/ +obj-$(CONFIG_MT7915E) += mt7915/ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig new file mode 100644 index 000000000000..d98225da694c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: ISC +config MT7915E + tristate "MediaTek MT7915E (PCIe) support" + select MT76_CORE + depends on MAC80211 + depends on PCI + help + This adds support for MT7915-based wireless PCIe devices, + which support concurrent dual-band operation at both 5GHz + and 2.4GHz IEEE 802.11ax 4x4:4SS 1024-QAM, 160MHz channels, + OFDMA, spatial reuse and dual carrier modulation. + + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile new file mode 100644 index 000000000000..57fe726cc38b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile @@ -0,0 +1,6 @@ +#SPDX-License-Identifier: ISC + +obj-$(CONFIG_MT7915E) += mt7915e.o + +mt7915e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \ + debugfs.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c new file mode 100644 index 000000000000..152ae0617f3d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7915.h" +#include "eeprom.h" + +/** global debugfs **/ + +/* test knob of system layer 1/2 error recovery */ +static int mt7915_ser_trigger_set(void *data, u64 val) +{ + enum { + SER_SET_RECOVER_L1 = 1, + SER_SET_RECOVER_L2, + SER_ENABLE = 2, + SER_RECOVER + }; + struct mt7915_dev *dev = data; + int ret = 0; + + switch (val) { + case SER_SET_RECOVER_L1: + case SER_SET_RECOVER_L2: + /* fall through */ + ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0); + if (ret) + return ret; + + return mt7915_mcu_set_ser(dev, SER_RECOVER, val, 0); + default: + break; + } + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_ser_trigger, NULL, + mt7915_ser_trigger_set, "%lld\n"); + +static int +mt7915_radar_trigger(void *data, u64 val) +{ + struct mt7915_dev *dev = data; + + return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, 1, 0, 0); +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL, + mt7915_radar_trigger, "%lld\n"); + +static int +mt7915_dbdc_set(void *data, u64 val) +{ + struct mt7915_dev *dev = data; + + if (val) + mt7915_register_ext_phy(dev); + else + mt7915_unregister_ext_phy(dev); + + return 0; +} + +static int +mt7915_dbdc_get(void *data, u64 *val) +{ + struct mt7915_dev *dev = data; + + *val = !!mt7915_ext_phy(dev); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_dbdc, mt7915_dbdc_get, + mt7915_dbdc_set, "%lld\n"); + +static void +mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, + struct seq_file *file) +{ + struct mt7915_dev *dev = file->private; + bool ext_phy = phy != &dev->phy; + int bound[15], range[4], i, n; + + if (!phy) + return; + + /* Tx ampdu stat */ + for (i = 0; i < ARRAY_SIZE(range); i++) + range[i] = mt76_rr(dev, MT_MIB_ARNG(ext_phy, i)); + + for (i = 0; i < ARRAY_SIZE(bound); i++) + bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i) + 1; + + seq_printf(file, "\nPhy %d\n", ext_phy); + + seq_printf(file, "Length: %8d | ", bound[0]); + for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) + seq_printf(file, "%3d -%3d | ", + bound[i] + 1, bound[i + 1]); + + seq_puts(file, "\nCount: "); + n = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; + for (i = 0; i < ARRAY_SIZE(bound); i++) + seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]); + seq_puts(file, "\n"); + + seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); +} + +static int +mt7915_tx_stats_read(struct seq_file *file, void *data) +{ + struct mt7915_dev *dev = file->private; + int stat[8], i, n; + + mt7915_ampdu_stat_read_phy(&dev->phy, file); + mt7915_ampdu_stat_read_phy(mt7915_ext_phy(dev), file); + + /* Tx amsdu info */ + seq_puts(file, "Tx MSDU stat:\n"); + for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) { + stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); + n += stat[i]; + } + + for (i = 0; i < ARRAY_SIZE(stat); i++) { + seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ", + i + 1, stat[i]); + if (n != 0) + seq_printf(file, "(%d%%)\n", stat[i] * 100 / n); + else + seq_puts(file, "\n"); + } + + return 0; +} + +static int +mt7915_tx_stats_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7915_tx_stats_read, inode->i_private); +} + +static const struct file_operations fops_tx_stats = { + .open = mt7915_tx_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int mt7915_read_temperature(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + int temp; + + /* cpu */ + temp = mt7915_mcu_get_temperature(dev, 0); + seq_printf(s, "Temperature: %d\n", temp); + + return 0; +} + +static int +mt7915_queues_acq(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + int i; + + for (i = 0; i < 16; i++) { + int j, acs = i / 4, index = i % 4; + u32 ctrl, val, qlen = 0; + + val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); + ctrl = BIT(31) | BIT(15) | (acs << 8); + + for (j = 0; j < 32; j++) { + if (val & BIT(j)) + continue; + + mt76_wr(dev, MT_PLE_FL_Q0_CTRL, + ctrl | (j + (index << 5))); + qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, + GENMASK(11, 0)); + } + seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); + } + + return 0; +} + +static int +mt7915_queues_read(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + static const struct { + char *queue; + int id; + } queue_map[] = { + { "WFDMA0", MT_TXQ_BE }, + { "MCUWM", MT_TXQ_MCU }, + { "MCUWA", MT_TXQ_MCU_WA }, + { "MCUFWQ", MT_TXQ_FWDL }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(queue_map); i++) { + struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id]; + + if (!q->q) + continue; + + seq_printf(s, + "%s: queued=%d head=%d tail=%d\n", + queue_map[i].queue, q->q->queued, q->q->head, + q->q->tail); + } + + return 0; +} + +int mt7915_init_debugfs(struct mt7915_dev *dev) +{ + struct dentry *dir; + + dir = mt76_register_debugfs(&dev->mt76); + if (!dir) + return -ENOMEM; + + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt7915_queues_read); + debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, + mt7915_queues_acq); + debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats); + debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc); + debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); + /* test knobs */ + debugfs_create_file("radar_trigger", 0200, dir, dev, + &fops_radar_trigger); + debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger); + debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, + mt7915_read_temperature); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c new file mode 100644 index 000000000000..766185d1aa21 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7915.h" +#include "../dma.h" +#include "mac.h" + +static int +mt7915_init_tx_queues(struct mt7915_dev *dev, int n_desc) +{ + struct mt76_sw_queue *q; + struct mt76_queue *hwq; + int err, i; + + hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL); + if (!hwq) + return -ENOMEM; + + err = mt76_queue_alloc(dev, hwq, MT7915_TXQ_BAND0, n_desc, 0, + MT_TX_RING_BASE); + if (err < 0) + return err; + + for (i = 0; i < MT_TXQ_MCU; i++) { + q = &dev->mt76.q_tx[i]; + INIT_LIST_HEAD(&q->swq); + q->q = hwq; + } + + return 0; +} + +static int +mt7915_init_mcu_queue(struct mt7915_dev *dev, struct mt76_sw_queue *q, + int idx, int n_desc) +{ + struct mt76_queue *hwq; + int err; + + hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL); + if (!hwq) + return -ENOMEM; + + err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE); + if (err < 0) + return err; + + INIT_LIST_HEAD(&q->swq); + q->q = hwq; + + return 0; +} + +void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + __le32 *rxd = (__le32 *)skb->data; + enum rx_pkt_type type; + + type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: + mt7915_mac_tx_free(dev, skb); + break; + case PKT_TYPE_RX_EVENT: + mt7915_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_NORMAL: + if (!mt7915_mac_fill_rx(dev, skb)) { + mt76_rx(&dev->mt76, q, skb); + return; + } + /* fall through */ + default: + dev_kfree_skb(skb); + break; + } +} + +static int mt7915_poll_tx(struct napi_struct *napi, int budget) +{ + static const u8 queue_map[] = { + MT_TXQ_MCU, + MT_TXQ_MCU_WA, + MT_TXQ_BE + }; + struct mt7915_dev *dev; + int i; + + dev = container_of(napi, struct mt7915_dev, mt76.tx_napi); + + for (i = 0; i < ARRAY_SIZE(queue_map); i++) + mt76_queue_tx_cleanup(dev, queue_map[i], false); + + if (napi_complete_done(napi, 0)) + mt7915_irq_enable(dev, MT_INT_TX_DONE_ALL); + + for (i = 0; i < ARRAY_SIZE(queue_map); i++) + mt76_queue_tx_cleanup(dev, queue_map[i], false); + + mt7915_mac_sta_poll(dev); + + tasklet_schedule(&dev->mt76.tx_tasklet); + + return 0; +} + +void mt7915_dma_prefetch(struct mt7915_dev *dev) +{ +#define PREFETCH(base, depth) ((base) << 16 | (depth)) + + mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x40, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x80, 0x0)); + + mt76_wr(dev, MT_WFDMA1_TX_RING0_EXT_CTRL, PREFETCH(0x80, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING1_EXT_CTRL, PREFETCH(0xc0, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING2_EXT_CTRL, PREFETCH(0x100, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING3_EXT_CTRL, PREFETCH(0x140, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING4_EXT_CTRL, PREFETCH(0x180, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING5_EXT_CTRL, PREFETCH(0x1c0, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING6_EXT_CTRL, PREFETCH(0x200, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING7_EXT_CTRL, PREFETCH(0x240, 0x4)); + + mt76_wr(dev, MT_WFDMA1_TX_RING16_EXT_CTRL, PREFETCH(0x280, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING17_EXT_CTRL, PREFETCH(0x2c0, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING18_EXT_CTRL, PREFETCH(0x300, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING19_EXT_CTRL, PREFETCH(0x340, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING20_EXT_CTRL, PREFETCH(0x380, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING21_EXT_CTRL, PREFETCH(0x3c0, 0x0)); + + mt76_wr(dev, MT_WFDMA1_RX_RING0_EXT_CTRL, PREFETCH(0x3c0, 0x4)); + mt76_wr(dev, MT_WFDMA1_RX_RING1_EXT_CTRL, PREFETCH(0x400, 0x4)); + mt76_wr(dev, MT_WFDMA1_RX_RING2_EXT_CTRL, PREFETCH(0x440, 0x4)); + mt76_wr(dev, MT_WFDMA1_RX_RING3_EXT_CTRL, PREFETCH(0x480, 0x0)); +} + +int mt7915_dma_init(struct mt7915_dev *dev) +{ + /* Increase buffer size to receive large VHT/HE MPDUs */ + int rx_buf_size = MT_RX_BUF_SIZE * 2; + int ret; + + mt76_dma_attach(&dev->mt76); + + /* configure global setting */ + mt76_set(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); + + /* configure perfetch settings */ + mt7915_dma_prefetch(dev); + + /* reset dma idx */ + mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); + mt76_wr(dev, MT_WFDMA1_RST_DTX_PTR, ~0); + + /* configure delay interrupt */ + mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); + mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0, 0); + + /* init tx queue */ + ret = mt7915_init_tx_queues(dev, MT7915_TX_RING_SIZE); + if (ret) + return ret; + + /* command to WM */ + ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU], + MT7915_TXQ_MCU_WM, + MT7915_TX_MCU_RING_SIZE); + if (ret) + return ret; + + /* command to WA */ + ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU_WA], + MT7915_TXQ_MCU_WA, + MT7915_TX_MCU_RING_SIZE); + if (ret) + return ret; + + /* firmware download */ + ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_FWDL], + MT7915_TXQ_FWDL, + MT7915_TX_FWDL_RING_SIZE); + if (ret) + return ret; + + /* event from WM */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], + MT7915_RXQ_MCU_WM, MT7915_RX_MCU_RING_SIZE, + rx_buf_size, MT_RX_EVENT_RING_BASE); + if (ret) + return ret; + + /* event from WA */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], + MT7915_RXQ_MCU_WA, MT7915_RX_MCU_RING_SIZE, + rx_buf_size, MT_RX_EVENT_RING_BASE); + if (ret) + return ret; + + /* rx data */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0, + MT7915_RX_RING_SIZE, rx_buf_size, + MT_RX_DATA_RING_BASE); + if (ret) + return ret; + + ret = mt76_init_queues(dev); + if (ret < 0) + return ret; + + netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi, + mt7915_poll_tx, NAPI_POLL_WEIGHT); + napi_enable(&dev->mt76.tx_napi); + + /* hif wait WFDMA idle */ + mt76_set(dev, MT_WFDMA0_BUSY_ENA, + MT_WFDMA0_BUSY_ENA_TX_FIFO0 | + MT_WFDMA0_BUSY_ENA_TX_FIFO1 | + MT_WFDMA0_BUSY_ENA_RX_FIFO); + + mt76_set(dev, MT_WFDMA1_BUSY_ENA, + MT_WFDMA1_BUSY_ENA_TX_FIFO0 | + MT_WFDMA1_BUSY_ENA_TX_FIFO1 | + MT_WFDMA1_BUSY_ENA_RX_FIFO); + + mt76_set(dev, MT_WFDMA0_PCIE1_BUSY_ENA, + MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 | + MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 | + MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO); + + mt76_set(dev, MT_WFDMA1_PCIE1_BUSY_ENA, + MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO0 | + MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO1 | + MT_WFDMA1_PCIE1_BUSY_ENA_RX_FIFO); + + mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC, + MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000); + + /* set WFDMA Tx/Rx */ + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + mt76_set(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); + + /* enable interrupts for TX/RX rings */ + mt7915_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_MCU_CMD); + + return 0; +} + +void mt7915_dma_cleanup(struct mt7915_dev *dev) +{ + /* disable */ + mt76_clear(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN); + mt76_clear(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_TX_DMA_EN | + MT_WFDMA1_GLO_CFG_RX_DMA_EN); + + /* reset */ + mt76_clear(dev, MT_WFDMA1_RST, + MT_WFDMA1_RST_DMASHDL_ALL_RST | + MT_WFDMA1_RST_LOGIC_RST); + + mt76_set(dev, MT_WFDMA1_RST, + MT_WFDMA1_RST_DMASHDL_ALL_RST | + MT_WFDMA1_RST_LOGIC_RST); + + mt76_clear(dev, MT_WFDMA0_RST, + MT_WFDMA0_RST_DMASHDL_ALL_RST | + MT_WFDMA0_RST_LOGIC_RST); + + mt76_set(dev, MT_WFDMA0_RST, + MT_WFDMA0_RST_DMASHDL_ALL_RST | + MT_WFDMA0_RST_LOGIC_RST); + + tasklet_kill(&dev->mt76.tx_tasklet); + mt76_dma_cleanup(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c new file mode 100644 index 000000000000..2099dd40530f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7915.h" +#include "eeprom.h" + +static inline bool mt7915_efuse_valid(u8 val) +{ + return !(val == 0xff); +} + +u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset) +{ + u8 *data = dev->mt76.eeprom.data; + + if (!mt7915_efuse_valid(data[offset])) + mt7915_mcu_get_eeprom(dev, offset); + + return data[offset]; +} + +static int mt7915_eeprom_load(struct mt7915_dev *dev) +{ + int ret; + + ret = mt76_eeprom_init(&dev->mt76, MT7915_EEPROM_SIZE); + if (ret < 0) + return ret; + + memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE); + + return 0; +} + +static int mt7915_check_eeprom(struct mt7915_dev *dev) +{ + u16 val; + u8 *eeprom = dev->mt76.eeprom.data; + + mt7915_eeprom_read(dev, 0); + val = get_unaligned_le16(eeprom); + + switch (val) { + case 0x7915: + return 0; + default: + return -EINVAL; + } +} + +static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev) +{ + u8 *eeprom = dev->mt76.eeprom.data; + u8 tx_mask, max_nss = 4; + u32 val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF); + + val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val); + switch (val) { + case MT_EE_5GHZ: + dev->mt76.cap.has_5ghz = true; + break; + case MT_EE_2GHZ: + dev->mt76.cap.has_2ghz = true; + break; + default: + dev->mt76.cap.has_2ghz = true; + dev->mt76.cap.has_5ghz = true; + break; + } + + /* read tx mask from eeprom */ + tx_mask = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK, + eeprom[MT_EE_WIFI_CONF]); + if (!tx_mask || tx_mask > max_nss) + tx_mask = max_nss; + + dev->chainmask = BIT(tx_mask) - 1; + dev->mphy.antenna_mask = dev->chainmask; + dev->phy.chainmask = dev->chainmask; +} + +int mt7915_eeprom_init(struct mt7915_dev *dev) +{ + int ret; + + ret = mt7915_eeprom_load(dev); + if (ret < 0) + return ret; + + ret = mt7915_check_eeprom(dev); + if (ret) + return ret; + + mt7915_eeprom_parse_hw_cap(dev); + memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, + ETH_ALEN); + + mt76_eeprom_override(&dev->mt76); + + return 0; +} + +int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, + struct ieee80211_channel *chan, + u8 chain_idx) +{ + int index; + bool tssi_on; + + if (chain_idx > 3) + return -EINVAL; + + tssi_on = mt7915_tssi_enabled(dev, chan->band); + + if (chan->band == NL80211_BAND_2GHZ) { + index = MT_EE_TX0_POWER_2G + chain_idx * 3 + !tssi_on; + } else { + int group = tssi_on ? + mt7915_get_channel_group(chan->hw_value) : 8; + + index = MT_EE_TX0_POWER_5G + chain_idx * 12 + group; + } + + return mt7915_eeprom_read(dev, index); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h new file mode 100644 index 000000000000..30fc607e466d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_EEPROM_H +#define __MT7915_EEPROM_H + +#include "mt7915.h" + +struct cal_data { + u8 count; + u16 offset[60]; +}; + +enum mt7915_eeprom_field { + MT_EE_CHIP_ID = 0x000, + MT_EE_VERSION = 0x002, + MT_EE_MAC_ADDR = 0x004, + MT_EE_DDIE_FT_VERSION = 0x050, + MT_EE_WIFI_CONF = 0x190, + MT_EE_TX0_POWER_2G = 0x2fc, + MT_EE_TX0_POWER_5G = 0x34b, + MT_EE_ADIE_FT_VERSION = 0x9a0, + + __MT_EE_MAX = 0xe00 +}; + +#define MT_EE_WIFI_CONF_TX_MASK GENMASK(2, 0) +#define MT_EE_WIFI_CONF_BAND_SEL GENMASK(7, 6) +#define MT_EE_WIFI_CONF_TSSI0_2G BIT(0) +#define MT_EE_WIFI_CONF_TSSI0_5G BIT(2) +#define MT_EE_WIFI_CONF_TSSI1_5G BIT(4) + +enum mt7915_eeprom_band { + MT_EE_DUAL_BAND, + MT_EE_5GHZ, + MT_EE_2GHZ, + MT_EE_DBDC, +}; + +struct sku_group { + u8 len; + u16 offset[2]; + const u8 *delta_map; +}; + +static inline int +mt7915_get_channel_group(int channel) +{ + if (channel >= 184 && channel <= 196) + return 0; + if (channel <= 48) + return 1; + if (channel <= 64) + return 2; + if (channel <= 96) + return 3; + if (channel <= 112) + return 4; + if (channel <= 128) + return 5; + if (channel <= 144) + return 6; + return 7; +} + +static inline bool +mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) +{ + u8 *eep = dev->mt76.eeprom.data; + + /* TODO: DBDC */ + if (band == NL80211_BAND_5GHZ) + return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_5G; + else + return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_2G; +} + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c new file mode 100644 index 000000000000..fb596afdf0be --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include +#include "mt7915.h" +#include "mac.h" +#include "eeprom.h" + +static void +mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) +{ + u32 mask, set; + + mt76_rmw_field(dev, MT_TMAC_CTCR0(band), + MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); + mt76_set(dev, MT_TMAC_CTCR0(band), + MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | + MT_TMAC_CTCR0_INS_DDLMT_EN); + + mask = MT_MDP_RCFR0_MCU_RX_MGMT | + MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR | + MT_MDP_RCFR0_MCU_RX_CTL_BAR; + set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF); + mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set); + + mask = MT_MDP_RCFR1_MCU_RX_BYPASS | + MT_MDP_RCFR1_RX_DROPPED_UCAST | + MT_MDP_RCFR1_RX_DROPPED_MCAST; + set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); + mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); + + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); +} + +static void mt7915_mac_init(struct mt7915_dev *dev) +{ + int i; + + mt76_rmw_field(dev, MT_DMA_DCR0, MT_DMA_DCR0_MAX_RX_LEN, 1536); + mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); + /* disable hardware de-agg */ + mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); + + for (i = 0; i < MT7915_WTBL_SIZE; i++) + mt7915_mac_wtbl_update(dev, i, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + mt7915_mac_init_band(dev, 0); + mt7915_mac_init_band(dev, 1); + mt7915_mcu_set_rts_thresh(&dev->phy, 0x92b); +} + +static void +mt7915_init_txpower_band(struct mt7915_dev *dev, + struct ieee80211_supported_band *sband) +{ + int i, n_chains = hweight8(dev->mphy.antenna_mask); + + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; + u32 target_power = 0; + int j; + + for (j = 0; j < n_chains; j++) { + u32 val; + + val = mt7915_eeprom_get_target_power(dev, chan, j); + target_power = max(target_power, val); + } + + chan->max_power = min_t(int, chan->max_reg_power, + target_power / 2); + chan->orig_mpwr = target_power / 2; + } +} + +static void mt7915_init_txpower(struct mt7915_dev *dev) +{ + mt7915_init_txpower_band(dev, &dev->mphy.sband_2g.sband); + mt7915_init_txpower_band(dev, &dev->mphy.sband_5g.sband); +} + +static void mt7915_init_work(struct work_struct *work) +{ + struct mt7915_dev *dev = container_of(work, struct mt7915_dev, + init_work); + + mt7915_mcu_set_eeprom(dev); + mt7915_mac_init(dev); + mt7915_init_txpower(dev); +} + +static int mt7915_init_hardware(struct mt7915_dev *dev) +{ + int ret, idx; + + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + + INIT_WORK(&dev->init_work, mt7915_init_work); + spin_lock_init(&dev->token_lock); + idr_init(&dev->token); + + ret = mt7915_dma_init(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + + ret = mt7915_mcu_init(dev); + if (ret) + return ret; + + ret = mt7915_eeprom_init(dev); + if (ret < 0) + return ret; + + /* Beacon and mgmt frames should occupy wcid 0 */ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1); + if (idx) + return -ENOSPC; + + dev->mt76.global_wcid.idx = idx; + dev->mt76.global_wcid.hw_key_idx = -1; + dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; + rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); + + return 0; +} + +#define CCK_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ +} + +#define OFDM_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ +} + +static struct ieee80211_rate mt7915_rates[] = { + CCK_RATE(0, 10), + CCK_RATE(1, 20), + CCK_RATE(2, 55), + CCK_RATE(3, 110), + OFDM_RATE(11, 60), + OFDM_RATE(15, 90), + OFDM_RATE(10, 120), + OFDM_RATE(14, 180), + OFDM_RATE(9, 240), + OFDM_RATE(13, 360), + OFDM_RATE(8, 480), + OFDM_RATE(12, 540), +}; + +static const struct ieee80211_iface_limit if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC) + }, { + .max = MT7915_MAX_INTERFACES, + .types = BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_STATION) + } +}; + +static const struct ieee80211_iface_combination if_comb[] = { + { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 4, + .num_different_channels = 1, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160) | + BIT(NL80211_CHAN_WIDTH_80P80), + } +}; + +static void +mt7915_regd_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + struct mt7915_phy *phy = mphy->priv; + struct cfg80211_chan_def *chandef = &mphy->chandef; + + dev->mt76.region = request->dfs_region; + + if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) + return; + + mt7915_dfs_init_radar_detector(phy); +} + +static void +mt7915_init_wiphy(struct ieee80211_hw *hw) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct wiphy *wiphy = hw->wiphy; + + hw->queues = 4; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + + phy->slottime = 9; + + hw->sta_data_size = sizeof(struct mt7915_sta); + hw->vif_data_size = sizeof(struct mt7915_vif); + + wiphy->iface_combinations = if_comb; + wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + wiphy->reg_notifier = mt7915_regd_notifier; + wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + + ieee80211_hw_set(hw, HAS_RATE_CONTROL); + + hw->max_tx_fragments = 4; +} + +static void +mt7915_cap_dbdc_enable(struct mt7915_dev *dev) +{ + dev->mphy.sband_5g.sband.vht_cap.cap &= + ~(IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); + + if (dev->chainmask == 0xf) + dev->mphy.antenna_mask = dev->chainmask >> 2; + else + dev->mphy.antenna_mask = dev->chainmask >> 1; + + dev->phy.chainmask = dev->mphy.antenna_mask; + dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask; + dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; + + mt76_set_stream_caps(&dev->mt76, true); +} + +static void +mt7915_cap_dbdc_disable(struct mt7915_dev *dev) +{ + dev->mphy.sband_5g.sband.vht_cap.cap |= + IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + + dev->mphy.antenna_mask = dev->chainmask; + dev->phy.chainmask = dev->chainmask; + dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask; + dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; + + mt76_set_stream_caps(&dev->mt76, true); +} + +int mt7915_register_ext_phy(struct mt7915_dev *dev) +{ + struct mt7915_phy *phy = mt7915_ext_phy(dev); + struct mt76_phy *mphy; + int ret; + bool bound; + + /* TODO: enble DBDC */ + bound = mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5); + if (!bound) + return -EINVAL; + + if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) + return -EINVAL; + + if (phy) + return 0; + + mt7915_cap_dbdc_enable(dev); + mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops); + if (!mphy) + return -ENOMEM; + + phy = mphy->priv; + phy->dev = dev; + phy->mt76 = mphy; + phy->chainmask = dev->chainmask & ~dev->phy.chainmask; + mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1; + mt7915_init_wiphy(mphy->hw); + + /* + * Make the secondary PHY MAC address local without overlapping with + * the usual MAC address allocation scheme on multiple virtual interfaces + */ + mphy->hw->wiphy->perm_addr[0] |= 2; + mphy->hw->wiphy->perm_addr[0] ^= BIT(7); + + /* The second interface does not get any packets unless it has a vif */ + ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF); + + ret = mt76_register_phy(mphy); + if (ret) + ieee80211_free_hw(mphy->hw); + + return ret; +} + +void mt7915_unregister_ext_phy(struct mt7915_dev *dev) +{ + struct mt7915_phy *phy = mt7915_ext_phy(dev); + struct mt76_phy *mphy = dev->mt76.phy2; + + if (!phy) + return; + + mt7915_cap_dbdc_disable(dev); + mt76_unregister_phy(mphy); + ieee80211_free_hw(mphy->hw); +} + +int mt7915_register_device(struct mt7915_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + int ret; + + dev->phy.dev = dev; + dev->phy.mt76 = &dev->mt76.phy; + dev->mt76.phy.priv = &dev->phy; + INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7915_mac_work); + INIT_LIST_HEAD(&dev->sta_poll_list); + spin_lock_init(&dev->sta_poll_lock); + + init_waitqueue_head(&dev->reset_wait); + INIT_WORK(&dev->reset_work, mt7915_mac_reset_work); + + ret = mt7915_init_hardware(dev); + if (ret) + return ret; + + mt7915_init_wiphy(hw); + dev->mphy.sband_2g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + dev->mphy.sband_5g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + dev->mphy.sband_5g.sband.vht_cap.cap |= + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; + mt7915_cap_dbdc_disable(dev); + dev->phy.dfs_state = -1; + + ret = mt76_register_device(&dev->mt76, true, mt7915_rates, + ARRAY_SIZE(mt7915_rates)); + if (ret) + return ret; + + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); + + return mt7915_init_debugfs(dev); +} + +void mt7915_unregister_device(struct mt7915_dev *dev) +{ + struct mt76_txwi_cache *txwi; + int id; + + mt7915_unregister_ext_phy(dev); + mt76_unregister_device(&dev->mt76); + mt7915_mcu_exit(dev); + mt7915_dma_cleanup(dev); + + spin_lock_bh(&dev->token_lock); + idr_for_each_entry(&dev->token, txwi, id) { + mt7915_txp_skb_unmap(&dev->mt76, txwi); + if (txwi->skb) + dev_kfree_skb_any(txwi->skb); + mt76_put_txwi(&dev->mt76, txwi); + } + spin_unlock_bh(&dev->token_lock); + idr_destroy(&dev->token); + + mt76_free_device(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c new file mode 100644 index 000000000000..ddba360046c3 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -0,0 +1,1298 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include +#include +#include "mt7915.h" +#include "../dma.h" +#include "mac.h" + +#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) + +static const struct mt7915_dfs_radar_spec etsi_radar_specs = { + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, + .radar_pattern = { + [5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 }, + [6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 }, + [7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 }, + [8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 }, + [9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 }, + [10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 }, + [11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 }, + [12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 }, + }, +}; + +static const struct mt7915_dfs_radar_spec fcc_radar_specs = { + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, + .radar_pattern = { + [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, + [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, + [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, + [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, + [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, + }, +}; + +static const struct mt7915_dfs_radar_spec jp_radar_specs = { + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, + .radar_pattern = { + [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, + [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, + [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, + [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, + [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, + [13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 }, + [14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 }, + [15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 }, + }, +}; + +static struct mt76_wcid *mt7915_rx_get_wcid(struct mt7915_dev *dev, + u16 idx, bool unicast) +{ + struct mt7915_sta *sta; + struct mt76_wcid *wcid; + + if (idx >= ARRAY_SIZE(dev->mt76.wcid)) + return NULL; + + wcid = rcu_dereference(dev->mt76.wcid[idx]); + if (unicast || !wcid) + return wcid; + + if (!wcid->sta) + return NULL; + + sta = container_of(wcid, struct mt7915_sta, wcid); + if (!sta->vif) + return NULL; + + return &sta->vif->sta.wcid; +} + +void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) +{ +} + +bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask) +{ + mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); + + return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, + 0, 5000); +} + +static u32 mt7915_mac_wtbl_lmac_read(struct mt7915_dev *dev, u16 wcid, + u16 addr) +{ + mt76_wr(dev, MT_WTBLON_TOP_WDUCR, + FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7))); + + return mt76_rr(dev, MT_WTBL_LMAC_OFFS(wcid, addr)); +} + +/* TODO: use txfree airtime info to avoid runtime accessing in the long run */ +void mt7915_mac_sta_poll(struct mt7915_dev *dev) +{ + static const u8 ac_to_tid[] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; + static const u8 hw_queue_map[] = { + [IEEE80211_AC_BK] = 0, + [IEEE80211_AC_BE] = 1, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_VO] = 3, + }; + struct ieee80211_sta *sta; + struct mt7915_sta *msta; + u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; + int i; + + rcu_read_lock(); + + while (true) { + bool clear = false; + u16 idx; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&dev->sta_poll_list)) { + spin_unlock_bh(&dev->sta_poll_lock); + break; + } + msta = list_first_entry(&dev->sta_poll_list, + struct mt7915_sta, poll_list); + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + for (i = 0, idx = msta->wcid.idx; i < IEEE80211_NUM_ACS; i++) { + u32 tx_last = msta->airtime_ac[i]; + u32 rx_last = msta->airtime_ac[i + IEEE80211_NUM_ACS]; + + msta->airtime_ac[i] = + mt7915_mac_wtbl_lmac_read(dev, idx, 20 + i); + msta->airtime_ac[i + IEEE80211_NUM_ACS] = + mt7915_mac_wtbl_lmac_read(dev, idx, 21 + i); + tx_time[i] = msta->airtime_ac[i] - tx_last; + rx_time[i] = msta->airtime_ac[i + IEEE80211_NUM_ACS] - + rx_last; + + if ((tx_last | rx_last) & BIT(30)) + clear = true; + } + + if (clear) { + mt7915_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + } + + if (!msta->wcid.sta) + continue; + + sta = container_of((void *)msta, struct ieee80211_sta, + drv_priv); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + u32 tx_cur = tx_time[i]; + u32 rx_cur = rx_time[hw_queue_map[i]]; + u8 tid = ac_to_tid[i]; + + if (!tx_cur && !rx_cur) + continue; + + ieee80211_sta_register_airtime(sta, tid, tx_cur, + rx_cur); + } + } + + rcu_read_unlock(); +} + +int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7915_phy *phy = &dev->phy; + struct ieee80211_supported_band *sband; + struct ieee80211_hdr *hdr; + struct mt7915_rxv rxv = {}; + __le32 *rxd = (__le32 *)skb->data; + u32 rxd1 = le32_to_cpu(rxd[1]); + u32 rxd2 = le32_to_cpu(rxd[2]); + u32 rxd3 = le32_to_cpu(rxd[3]); + bool unicast, insert_ccmp_hdr = false; + u8 remove_pad; + int i, idx; + + memset(status, 0, sizeof(*status)); + + if (rxd1 & MT_RXD1_NORMAL_BAND_IDX) { + mphy = dev->mt76.phy2; + if (!mphy) + return -EINVAL; + + phy = mphy->priv; + status->ext_phy = true; + } + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) + return -EINVAL; + + unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; + idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); + status->wcid = mt7915_rx_get_wcid(dev, idx, unicast); + + if (status->wcid) { + struct mt7915_sta *msta; + + msta = container_of(status->wcid, struct mt7915_sta, wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + } + + status->freq = mphy->chandef.chan->center_freq; + status->band = mphy->chandef.chan->band; + if (status->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else + sband = &mphy->sband_2g.sband; + + if (!sband->channels) + return -EINVAL; + + if (rxd1 & MT_RXD1_NORMAL_FCS_ERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) + status->flag |= RX_FLAG_MMIC_ERROR; + + if (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1) != 0 && + !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_IV_STRIPPED; + status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; + } + + if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + + /* all subframes of an A-MPDU have the same timestamp */ + if (phy->rx_ampdu_ts != rxd[14]) { + if (!++phy->ampdu_ref) + phy->ampdu_ref++; + } + phy->rx_ampdu_ts = rxd[14]; + + status->ampdu_ref = phy->ampdu_ref; + } + + remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2); + + if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) + return -EINVAL; + + rxd += 6; + if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { + u8 *data = (u8 *)rxd; + + if (status->flag & RX_FLAG_DECRYPTED) { + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + + insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + } + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { + rxd += 2; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + /* RXD Group 3 - P-RXV */ + if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { + memcpy(rxv.v, rxd, sizeof(rxv.v)); + + rxd += 2; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + + if (rxv.v[0] & MT_PRXV_HT_AD_CODE) + status->enc_flags |= RX_ENC_FLAG_LDPC; + + status->chains = mphy->antenna_mask; + status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, rxv.v[1]); + status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, rxv.v[1]); + status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, rxv.v[1]); + status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, rxv.v[1]); + status->signal = status->chain_signal[0]; + + for (i = 1; i < hweight8(mphy->antenna_mask); i++) { + if (!(status->chains & BIT(i))) + continue; + + status->signal = max(status->signal, + status->chain_signal[i]); + } + + /* RXD Group 5 - C-RXV */ + if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { + u8 stbc = FIELD_GET(MT_CRXV_HT_STBC, rxv.v[2]); + u8 gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, rxv.v[2]); + bool cck = false; + + rxd += 18; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + + idx = i = FIELD_GET(MT_PRXV_TX_RATE, rxv.v[0]); + rxv.phy = FIELD_GET(MT_CRXV_TX_MODE, rxv.v[2]); + + switch (rxv.phy) { + case MT_PHY_TYPE_CCK: + cck = true; + /* fall through */ + case MT_PHY_TYPE_OFDM: + i = mt76_get_rate(&dev->mt76, sband, i, cck); + break; + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_HT: + status->encoding = RX_ENC_HT; + if (i > 31) + return -EINVAL; + break; + case MT_PHY_TYPE_VHT: + status->nss = + FIELD_GET(MT_PRXV_NSTS, rxv.v[0]) + 1; + status->encoding = RX_ENC_VHT; + if (i > 9) + return -EINVAL; + break; + default: + return -EINVAL; + } + status->rate_idx = i; + + switch (FIELD_GET(MT_CRXV_FRAME_MODE, rxv.v[2])) { + case IEEE80211_STA_RX_BW_20: + break; + case IEEE80211_STA_RX_BW_40: + status->bw = RATE_INFO_BW_40; + break; + case IEEE80211_STA_RX_BW_80: + status->bw = RATE_INFO_BW_80; + break; + case IEEE80211_STA_RX_BW_160: + status->bw = RATE_INFO_BW_160; + break; + default: + return -EINVAL; + } + + status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; + if (gi) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + } + } + + skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad); + + if (insert_ccmp_hdr) { + u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); + + mt76_insert_ccmp_hdr(skb, key_id); + } + + hdr = mt76_skb_get_hdr(skb); + if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) + return 0; + + status->aggr = unicast && + !ieee80211_is_qos_nullfunc(hdr->frame_control); + status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + + return 0; +} + +void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, bool beacon) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + bool multicast = is_multicast_ether_addr(hdr->addr1); + struct ieee80211_vif *vif = info->control.vif; + struct mt76_phy *mphy = &dev->mphy; + bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; + u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; + __le16 fc = hdr->frame_control; + u16 tx_count = 4, seqno = 0; + u32 val; + + if (vif) { + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + + omac_idx = mvif->omac_idx; + wmm_idx = mvif->wmm_idx; + } + + if (ext_phy && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; + fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; + + if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) { + q_idx = wmm_idx * MT7915_MAX_WMM_SETS + + skb_get_queue_mapping(skb); + p_fmt = MT_TX_TYPE_CT; + } else if (beacon) { + q_idx = MT_LMAC_BCN0; + p_fmt = MT_TX_TYPE_FW; + } else { + q_idx = MT_LMAC_ALTX0; + p_fmt = MT_TX_TYPE_CT; + } + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | + FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | + FIELD_PREP(MT_TXD0_Q_IDX, q_idx); + txwi[0] = cpu_to_le32(val); + + val = MT_TXD1_LONG_FORMAT | + FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | + FIELD_PREP(MT_TXD1_HDR_INFO, + ieee80211_get_hdrlen_from_skb(skb) / 2) | + FIELD_PREP(MT_TXD1_TID, + skb->priority & IEEE80211_QOS_CTL_TID_MASK) | + FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); + if (ext_phy && q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0) + val |= cpu_to_le32(MT_TXD1_TGID); + + txwi[1] = cpu_to_le32(val); + + val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | + FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | + FIELD_PREP(MT_TXD2_MULTICAST, multicast); + if (key) { + if (multicast && ieee80211_is_robust_mgmt_frame(skb) && + key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + val |= MT_TXD2_BIP; + txwi[3] = 0; + } else { + txwi[3] = cpu_to_le32(MT_TXD3_PROTECT_FRAME); + } + } else { + txwi[3] = 0; + } + txwi[2] = cpu_to_le32(val); + + txwi[4] = 0; + txwi[5] = 0; + txwi[6] = 0; + + if (!ieee80211_is_data(fc) || multicast) { + u16 rate; + + /* hardware won't add HTC for mgmt/ctrl frame */ + txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE | MT_TXD2_HTC_VLD); + + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + rate = MT7915_5G_RATE_DEFAULT; + else + rate = MT7915_2G_RATE_DEFAULT; + + val = MT_TXD6_FIXED_BW | + FIELD_PREP(MT_TXD6_TX_RATE, rate); + txwi[6] |= cpu_to_le32(val); + txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); + } + + if (!ieee80211_is_beacon(fc)) + txwi[3] |= cpu_to_le32(MT_TXD3_SW_POWER_MGMT); + else + tx_count = 0x1f; + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK); + + val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | + FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + txwi[7] = cpu_to_le32(val); + + val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); + if (ieee80211_is_data_qos(fc)) { + seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + val |= MT_TXD3_SN_VALID; + } else if (ieee80211_is_back_req(fc)) { + struct ieee80211_bar *bar; + + bar = (struct ieee80211_bar *)skb->data; + seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num)); + val |= MT_TXD3_SN_VALID; + } + val |= FIELD_PREP(MT_TXD3_SEQ, seqno); + txwi[3] |= cpu_to_le32(val); +} + +int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct ieee80211_key_conf *key = info->control.hw_key; + struct ieee80211_vif *vif = info->control.vif; + struct mt76_tx_cb *cb = mt76_tx_skb_cb(tx_info->skb); + struct mt76_txwi_cache *t; + struct mt7915_txp *txp; + int id, i, nbuf = tx_info->nbuf - 1; + u8 *txwi = (u8 *)txwi_ptr; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + cb->wcid = wcid->idx; + + mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, + false); + + txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE); + for (i = 0; i < nbuf; i++) { + txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); + txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len); + } + txp->nbuf = nbuf; + + /* pass partial skb header to fw */ + tx_info->buf[1].len = MT_CT_PARSE_LEN; + tx_info->nbuf = MT_CT_DMA_BUF_NUM; + + txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD); + + if (!key) + txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); + + if (ieee80211_is_mgmt(hdr->frame_control)) + txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); + + if (vif) { + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + + txp->bss_idx = mvif->idx; + } + + t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); + t->skb = tx_info->skb; + + spin_lock_bh(&dev->token_lock); + id = idr_alloc(&dev->token, t, 0, MT7915_TOKEN_SIZE, GFP_ATOMIC); + spin_unlock_bh(&dev->token_lock); + if (id < 0) + return id; + + txp->token = cpu_to_le16(id); + txp->rept_wds_wcid = 0xff; + tx_info->skb = DMA_DUMMY_DATA; + + return 0; +} + +static inline bool +mt7915_tx_check_aggr_tid(struct mt7915_sta *msta, u8 tid) +{ + bool ret = false; + + spin_lock_bh(&msta->ampdu_lock); + if (msta->ampdu_state[tid] == MT7915_AGGR_STOP) + ret = true; + spin_unlock_bh(&msta->ampdu_lock); + + return ret; +} + +static void +mt7915_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct mt7915_sta *msta; + u16 tid; + + if (!sta->ht_cap.ht_supported) + return; + + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + + if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) + return; + + if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) + return; + + msta = (struct mt7915_sta *)sta->drv_priv; + tid = ieee80211_get_tid(hdr); + + if (mt7915_tx_check_aggr_tid(msta, tid)) { + ieee80211_start_tx_ba_session(sta, tid, 0); + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_PROGRESS); + } +} + +static inline void +mt7915_tx_status(struct ieee80211_sta *sta, struct ieee80211_hw *hw, + struct ieee80211_tx_info *info, struct sk_buff *skb) +{ + struct ieee80211_tx_status status = { + .sta = sta, + .info = info, + }; + + if (skb) + status.skb = skb; + + if (sta) { + struct mt7915_sta *msta; + + msta = (struct mt7915_sta *)sta->drv_priv; + status.rate = &msta->stats.tx_rate; + } + + /* use status_ext to report HE rate */ + ieee80211_tx_status_ext(hw, &status); +} + +static void +mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, + struct ieee80211_sta *sta, u8 stat) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw; + + hw = mt76_tx_status_get_hw(mdev, skb); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) + info->flags |= IEEE80211_TX_STAT_AMPDU; + else if (sta) + mt7915_tx_check_aggr(sta, skb); + + if (stat) + ieee80211_tx_info_clear_status(info); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.tx_time = 0; + + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { + mt7915_tx_status(sta, hw, info, skb); + return; + } + + if (sta || !(info->flags & IEEE80211_TX_CTL_NO_ACK)) + mt7915_tx_status(sta, hw, info, NULL); + + dev_kfree_skb(skb); +} + +void mt7915_txp_skb_unmap(struct mt76_dev *dev, + struct mt76_txwi_cache *t) +{ + struct mt7915_txp *txp; + int i; + + txp = mt7915_txwi_to_txp(dev, t); + for (i = 1; i < txp->nbuf; i++) + dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]), + le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); +} + +void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_tx_free *free = (struct mt7915_tx_free *)skb->data; + struct mt76_dev *mdev = &dev->mt76; + struct mt76_txwi_cache *txwi; + struct ieee80211_sta *sta = NULL; + u8 i, count; + + /* + * TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE, + * to the time ack is received or dropped by hw (air + hw queue time). + * Should avoid accessing WTBL to get Tx airtime, and use it instead. + */ + count = FIELD_GET(MT_TX_FREE_MSDU_CNT, le16_to_cpu(free->ctrl)); + for (i = 0; i < count; i++) { + u32 msdu, info = le32_to_cpu(free->info[i]); + u8 stat; + + /* + * 1'b1: new wcid pair. + * 1'b0: msdu_id with the same 'wcid pair' as above. + */ + if (info & MT_TX_FREE_PAIR) { + struct mt7915_sta *msta; + struct mt76_wcid *wcid; + u16 idx; + + count++; + idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info); + wcid = rcu_dereference(dev->mt76.wcid[idx]); + sta = wcid_to_sta(wcid); + if (!sta) + continue; + + msta = container_of(wcid, struct mt7915_sta, wcid); + ieee80211_queue_work(mt76_hw(dev), &msta->stats_work); + continue; + } + + msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); + stat = FIELD_GET(MT_TX_FREE_STATUS, info); + + spin_lock_bh(&dev->token_lock); + txwi = idr_remove(&dev->token, msdu); + spin_unlock_bh(&dev->token_lock); + + if (!txwi) + continue; + + mt7915_txp_skb_unmap(mdev, txwi); + if (txwi->skb) { + mt7915_tx_complete_status(mdev, txwi->skb, sta, stat); + txwi->skb = NULL; + } + + mt76_put_txwi(mdev, txwi); + } + dev_kfree_skb(skb); +} + +void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, + struct mt76_queue_entry *e) +{ + struct mt7915_dev *dev; + + if (!e->txwi) { + dev_kfree_skb_any(e->skb); + return; + } + + dev = container_of(mdev, struct mt7915_dev, mt76); + + /* error path */ + if (e->skb == DMA_DUMMY_DATA) { + struct mt76_txwi_cache *t; + struct mt7915_txp *txp; + + txp = mt7915_txwi_to_txp(mdev, e->txwi); + + spin_lock_bh(&dev->token_lock); + t = idr_remove(&dev->token, le16_to_cpu(txp->token)); + spin_unlock_bh(&dev->token_lock); + e->skb = t ? t->skb : NULL; + } + + if (e->skb) { + struct mt76_tx_cb *cb = mt76_tx_skb_cb(e->skb); + struct mt76_wcid *wcid; + + wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]); + + mt7915_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0); + } +} + +void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + u32 reg = MT_WF_PHY_RX_CTRL1(ext_phy); + + mt7915_l2_clear(dev, reg, MT_WF_PHY_RX_CTRL1_STSCNT_EN); + mt7915_l2_set(dev, reg, BIT(11) | BIT(9)); +} + +void mt7915_mac_reset_counters(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + int i; + + for (i = 0; i < 4; i++) { + mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i)); + mt76_rr(dev, MT_TX_AGG_CNT2(ext_phy, i)); + } + + if (ext_phy) { + dev->mt76.phy2->survey_time = ktime_get_boottime(); + i = ARRAY_SIZE(dev->mt76.aggr_stats) / 2; + } else { + dev->mt76.phy.survey_time = ktime_get_boottime(); + i = 0; + } + memset(&dev->mt76.aggr_stats[i], 0, sizeof(dev->mt76.aggr_stats) / 2); + + /* reset airtime counters */ + mt76_rr(dev, MT_MIB_SDR9(ext_phy)); + mt76_rr(dev, MT_MIB_SDR36(ext_phy)); + mt76_rr(dev, MT_MIB_SDR37(ext_phy)); + + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(ext_phy), + MT_WF_RMAC_MIB_RXTIME_CLR); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(ext_phy), + MT_WF_RMAC_MIB_RXTIME_CLR); +} + +void mt7915_mac_set_timing(struct mt7915_phy *phy) +{ + s16 coverage_class = phy->coverage_class; + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + u32 val, reg_offset; + u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); + u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); + int sifs, offset; + bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ; + + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + return; + + if (is_5ghz) + sifs = 16; + else + sifs = 10; + + if (ext_phy) { + coverage_class = max_t(s16, dev->phy.coverage_class, + coverage_class); + } else { + struct mt7915_phy *phy_ext = mt7915_ext_phy(dev); + + if (phy_ext) + coverage_class = max_t(s16, phy_ext->coverage_class, + coverage_class); + } + mt76_set(dev, MT_ARB_SCR(ext_phy), + MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); + udelay(1); + + offset = 3 * coverage_class; + reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); + + mt76_wr(dev, MT_TMAC_CDTR(ext_phy), cck + reg_offset); + mt76_wr(dev, MT_TMAC_ODTR(ext_phy), ofdm + reg_offset); + mt76_wr(dev, MT_TMAC_ICR0(ext_phy), + FIELD_PREP(MT_IFS_EIFS, 360) | + FIELD_PREP(MT_IFS_RIFS, 2) | + FIELD_PREP(MT_IFS_SIFS, sifs) | + FIELD_PREP(MT_IFS_SLOT, phy->slottime)); + + if (phy->slottime < 20 || is_5ghz) + val = MT7915_CFEND_RATE_DEFAULT; + else + val = MT7915_CFEND_RATE_11B; + + mt76_rmw_field(dev, MT_AGG_ACR0(ext_phy), MT_AGG_ACR_CFEND_RATE, val); + mt76_clear(dev, MT_ARB_SCR(ext_phy), + MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); +} + +/* + * TODO: mib counters are read-clear and there're many HE functionalities need + * such info, hence firmware prepares a task to read the fields out to a shared + * structure. User should switch to use event format to avoid race condition. + */ +static void +mt7915_phy_update_channel(struct mt76_phy *mphy, int idx) +{ + struct mt7915_dev *dev = container_of(mphy->dev, struct mt7915_dev, mt76); + struct mt76_channel_state *state; + u64 busy_time, tx_time, rx_time, obss_time; + + busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx), + MT_MIB_SDR9_BUSY_MASK); + tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx), + MT_MIB_SDR36_TXTIME_MASK); + rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx), + MT_MIB_SDR37_RXTIME_MASK); + obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx), + MT_MIB_OBSSTIME_MASK); + + /* TODO: state->noise */ + state = mphy->chan_state; + state->cc_busy += busy_time; + state->cc_tx += tx_time; + state->cc_rx += rx_time + obss_time; + state->cc_bss_rx += rx_time; +} + +void mt7915_update_channel(struct mt76_dev *mdev) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + + mt7915_phy_update_channel(&mdev->phy, 0); + if (mdev->phy2) + mt7915_phy_update_channel(mdev->phy2, 1); + + /* reset obss airtime */ + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); + if (mdev->phy2) + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(1), + MT_WF_RMAC_MIB_RXTIME_CLR); +} + +static bool +mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) +{ + bool ret; + + ret = wait_event_timeout(dev->reset_wait, + (READ_ONCE(dev->reset_state) & state), + MT7915_RESET_TIMEOUT); + + WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); + return ret; +} + +static void +mt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct ieee80211_hw *hw = priv; + + mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon); +} + +static void +mt7915_update_beacons(struct mt7915_dev *dev) +{ + ieee80211_iterate_active_interfaces(dev->mt76.hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7915_update_vif_beacon, dev->mt76.hw); + + if (!dev->mt76.phy2) + return; + + ieee80211_iterate_active_interfaces(dev->mt76.phy2->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7915_update_vif_beacon, dev->mt76.phy2->hw); +} + +static void +mt7915_dma_reset(struct mt7915_dev *dev) +{ + int i; + + mt76_clear(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + mt76_clear(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); + usleep_range(1000, 2000); + + for (i = 0; i < __MT_TXQ_MAX; i++) + mt76_queue_tx_cleanup(dev, i, true); + + for (i = 0; i < ARRAY_SIZE(dev->mt76.q_rx); i++) + mt76_queue_rx_reset(dev, i); + + /* re-init prefetch settings after reset */ + mt7915_dma_prefetch(dev); + + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + mt76_set(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); +} + +/* system error recovery */ +void mt7915_mac_reset_work(struct work_struct *work) +{ + struct mt7915_dev *dev; + + dev = container_of(work, struct mt7915_dev, reset_work); + + if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA)) + return; + + ieee80211_stop_queues(mt76_hw(dev)); + if (dev->mt76.phy2) + ieee80211_stop_queues(dev->mt76.phy2->hw); + + set_bit(MT76_RESET, &dev->mphy.state); + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + cancel_delayed_work_sync(&dev->mt76.mac_work); + + /* lock/unlock all queues to ensure that no tx is pending */ + mt76_txq_schedule_all(&dev->mphy); + if (dev->mt76.phy2) + mt76_txq_schedule_all(dev->mt76.phy2); + + tasklet_disable(&dev->mt76.tx_tasklet); + napi_disable(&dev->mt76.napi[0]); + napi_disable(&dev->mt76.napi[1]); + napi_disable(&dev->mt76.napi[2]); + napi_disable(&dev->mt76.tx_napi); + + mutex_lock(&dev->mt76.mutex); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); + + if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { + mt7915_dma_reset(dev); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT); + mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); + } + + clear_bit(MT76_MCU_RESET, &dev->mphy.state); + clear_bit(MT76_RESET, &dev->mphy.state); + + tasklet_enable(&dev->mt76.tx_tasklet); + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); + + napi_enable(&dev->mt76.napi[0]); + napi_schedule(&dev->mt76.napi[0]); + + napi_enable(&dev->mt76.napi[1]); + napi_schedule(&dev->mt76.napi[1]); + + napi_enable(&dev->mt76.napi[2]); + napi_schedule(&dev->mt76.napi[2]); + + ieee80211_wake_queues(mt76_hw(dev)); + if (dev->mt76.phy2) + ieee80211_wake_queues(dev->mt76.phy2->hw); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); + mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); + + mutex_unlock(&dev->mt76.mutex); + + mt7915_update_beacons(dev); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + MT7915_WATCHDOG_TIME); +} + +static void +mt7915_mac_update_mib_stats(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + struct mib_stats *mib = &phy->mib; + bool ext_phy = phy != &dev->phy; + int i, aggr0, aggr1; + + memset(mib, 0, sizeof(*mib)); + + mib->fcs_err_cnt = mt76_get_field(dev, MT_MIB_SDR3(ext_phy), + MT_MIB_SDR3_FCS_ERR_MASK); + + aggr0 = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; + for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) { + u32 val, val2; + + val = mt76_rr(dev, MT_MIB_MB_SDR1(ext_phy, i)); + + val2 = FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val); + if (val2 > mib->ack_fail_cnt) + mib->ack_fail_cnt = val2; + + val2 = FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); + if (val2 > mib->ba_miss_cnt) + mib->ba_miss_cnt = val2; + + val = mt76_rr(dev, MT_MIB_MB_SDR0(ext_phy, i)); + val2 = FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); + if (val2 > mib->rts_retries_cnt) { + mib->rts_cnt = FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); + mib->rts_retries_cnt = val2; + } + + val = mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i)); + val2 = mt76_rr(dev, MT_TX_AGG_CNT2(ext_phy, i)); + + dev->mt76.aggr_stats[aggr0++] += val & 0xffff; + dev->mt76.aggr_stats[aggr0++] += val >> 16; + dev->mt76.aggr_stats[aggr1++] += val2 & 0xffff; + dev->mt76.aggr_stats[aggr1++] += val2 >> 16; + } +} + +void mt7915_mac_sta_stats_work(struct work_struct *work) +{ + struct ieee80211_sta *sta; + struct ieee80211_vif *vif; + struct mt7915_sta_stats *stats; + struct mt7915_sta *msta; + struct mt7915_dev *dev; + + msta = container_of(work, struct mt7915_sta, stats_work); + sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); + vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); + dev = msta->vif->dev; + stats = &msta->stats; + + /* use MT_TX_FREE_RATE to report Tx rate for further devices */ + if (time_after(jiffies, stats->jiffies + HZ)) { + mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO, + msta->wcid.idx); + + stats->jiffies = jiffies; + } + + if (test_and_clear_bit(IEEE80211_RC_SUPP_RATES_CHANGED | + IEEE80211_RC_NSS_CHANGED | + IEEE80211_RC_BW_CHANGED, &stats->changed)) + mt7915_mcu_add_rate_ctrl(dev, vif, sta); + + if (test_and_clear_bit(IEEE80211_RC_SMPS_CHANGED, &stats->changed)) + mt7915_mcu_add_smps(dev, vif, sta); + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); +} + +void mt7915_mac_work(struct work_struct *work) +{ + struct mt7915_dev *dev; + + dev = (struct mt7915_dev *)container_of(work, struct mt76_dev, + mac_work.work); + + mutex_lock(&dev->mt76.mutex); + mt76_update_survey(&dev->mt76); + if (++dev->mac_work_count == 5) { + struct mt7915_phy *ext_phy = mt7915_ext_phy(dev); + + mt7915_mac_update_mib_stats(&dev->phy); + if (ext_phy) + mt7915_mac_update_mib_stats(ext_phy); + + dev->mac_work_count = 0; + } + mutex_unlock(&dev->mt76.mutex); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + MT7915_WATCHDOG_TIME); +} + +static void mt7915_dfs_stop_radar_detector(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + + if (phy->rdd_state & BIT(0)) + mt7915_mcu_rdd_cmd(dev, RDD_STOP, 0, MT_RX_SEL0, 0); + if (phy->rdd_state & BIT(1)) + mt7915_mcu_rdd_cmd(dev, RDD_STOP, 1, MT_RX_SEL0, 0); +} + +static int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int chain) +{ + int err; + + err = mt7915_mcu_rdd_cmd(dev, RDD_START, chain, MT_RX_SEL0, 0); + if (err < 0) + return err; + + return mt7915_mcu_rdd_cmd(dev, RDD_DET_MODE, chain, MT_RX_SEL0, 1); +} + +static int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy) +{ + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + int err; + + /* start CAC */ + err = mt7915_mcu_rdd_cmd(dev, RDD_CAC_START, ext_phy, MT_RX_SEL0, 0); + if (err < 0) + return err; + + err = mt7915_dfs_start_rdd(dev, ext_phy); + if (err < 0) + return err; + + phy->rdd_state |= BIT(ext_phy); + + if (chandef->width == NL80211_CHAN_WIDTH_160 || + chandef->width == NL80211_CHAN_WIDTH_80P80) { + err = mt7915_dfs_start_rdd(dev, 1); + if (err < 0) + return err; + + phy->rdd_state |= BIT(1); + } + + return 0; +} + +static int +mt7915_dfs_init_radar_specs(struct mt7915_phy *phy) +{ + const struct mt7915_dfs_radar_spec *radar_specs; + struct mt7915_dev *dev = phy->dev; + int err, i; + + switch (dev->mt76.region) { + case NL80211_DFS_FCC: + radar_specs = &fcc_radar_specs; + err = mt7915_mcu_set_fcc5_lpn(dev, 8); + if (err < 0) + return err; + break; + case NL80211_DFS_ETSI: + radar_specs = &etsi_radar_specs; + break; + case NL80211_DFS_JP: + radar_specs = &jp_radar_specs; + break; + default: + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { + err = mt7915_mcu_set_radar_th(dev, i, + &radar_specs->radar_pattern[i]); + if (err < 0) + return err; + } + + return mt7915_mcu_set_pulse_th(dev, &radar_specs->pulse_th); +} + +int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) +{ + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + int err; + + if (dev->mt76.region == NL80211_DFS_UNSET) { + phy->dfs_state = -1; + if (phy->rdd_state) + goto stop; + + return 0; + } + + if (test_bit(MT76_SCANNING, &phy->mt76->state)) + return 0; + + if (phy->dfs_state == chandef->chan->dfs_state) + return 0; + + err = mt7915_dfs_init_radar_specs(phy); + if (err < 0) { + phy->dfs_state = -1; + goto stop; + } + + phy->dfs_state = chandef->chan->dfs_state; + + if (chandef->chan->flags & IEEE80211_CHAN_RADAR) { + if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) + return mt7915_dfs_start_radar_detector(phy); + + return mt7915_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy, + MT_RX_SEL0, 0); + } + +stop: + err = mt7915_mcu_rdd_cmd(dev, RDD_NORMAL_START, ext_phy, + MT_RX_SEL0, 0); + if (err < 0) + return err; + + mt7915_dfs_stop_radar_detector(phy); + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h new file mode 100644 index 000000000000..7da7551f98e4 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_MAC_H +#define __MT7915_MAC_H + +#define MT_CT_PARSE_LEN 72 +#define MT_CT_DMA_BUF_NUM 2 + +#define MT_RXD0_LENGTH GENMASK(15, 0) +#define MT_RXD0_PKT_TYPE GENMASK(31, 27) + +#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16) +#define MT_RXD0_NORMAL_IP_SUM BIT(23) +#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24) + +enum rx_pkt_type { + PKT_TYPE_TXS, + PKT_TYPE_TXRXV, + PKT_TYPE_NORMAL, + PKT_TYPE_RX_DUP_RFB, + PKT_TYPE_RX_TMR, + PKT_TYPE_RETRIEVE, + PKT_TYPE_TXRX_NOTIFY, + PKT_TYPE_RX_EVENT, +}; + +/* RXD DW1 */ +#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0) +#define MT_RXD1_NORMAL_GROUP_1 BIT(11) +#define MT_RXD1_NORMAL_GROUP_2 BIT(12) +#define MT_RXD1_NORMAL_GROUP_3 BIT(13) +#define MT_RXD1_NORMAL_GROUP_4 BIT(14) +#define MT_RXD1_NORMAL_GROUP_5 BIT(15) +#define MT_RXD1_NORMAL_SEC_MODE GENMASK(20, 16) +#define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21) +#define MT_RXD1_NORMAL_CM BIT(23) +#define MT_RXD1_NORMAL_CLM BIT(24) +#define MT_RXD1_NORMAL_ICV_ERR BIT(25) +#define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26) +#define MT_RXD1_NORMAL_FCS_ERR BIT(27) +#define MT_RXD1_NORMAL_BAND_IDX BIT(28) +#define MT_RXD1_NORMAL_SPP_EN BIT(29) +#define MT_RXD1_NORMAL_ADD_OM BIT(30) +#define MT_RXD1_NORMAL_SEC_DONE BIT(31) + +/* RXD DW2 */ +#define MT_RXD2_NORMAL_BSSID GENMASK(5, 0) +#define MT_RXD2_NORMAL_CO_ANT BIT(6) +#define MT_RXD2_NORMAL_BF_CQI BIT(7) +#define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8) +#define MT_RXD2_NORMAL_HDR_TRANS BIT(13) +#define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 14) +#define MT_RXD2_NORMAL_TID GENMASK(19, 16) +#define MT_RXD2_NORMAL_MU_BAR BIT(21) +#define MT_RXD2_NORMAL_SW_BIT BIT(22) +#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23) +#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24) +#define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25) +#define MT_RXD2_NORMAL_INT_FRAME BIT(26) +#define MT_RXD2_NORMAL_FRAG BIT(27) +#define MT_RXD2_NORMAL_NULL_FRAME BIT(28) +#define MT_RXD2_NORMAL_NDATA BIT(29) +#define MT_RXD2_NORMAL_NON_AMPDU BIT(30) +#define MT_RXD2_NORMAL_BF_REPORT BIT(31) + +/* RXD DW3 */ +#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0) +#define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8) +#define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16) +#define MT_RXD3_NORMAL_U2M BIT(0) +#define MT_RXD3_NORMAL_HTC_VLD BIT(0) +#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(19) +#define MT_RXD3_NORMAL_BEACON_MC BIT(20) +#define MT_RXD3_NORMAL_BEACON_UC BIT(21) +#define MT_RXD3_NORMAL_AMSDU BIT(22) +#define MT_RXD3_NORMAL_MESH BIT(23) +#define MT_RXD3_NORMAL_MHCP BIT(24) +#define MT_RXD3_NORMAL_NO_INFO_WB BIT(25) +#define MT_RXD3_NORMAL_DISABLE_RX_HDR_TRANS BIT(26) +#define MT_RXD3_NORMAL_POWER_SAVE_STAT BIT(27) +#define MT_RXD3_NORMAL_MORE BIT(28) +#define MT_RXD3_NORMAL_UNWANT BIT(29) +#define MT_RXD3_NORMAL_RX_DROP BIT(30) +#define MT_RXD3_NORMAL_VLAN2ETH BIT(31) + +/* RXD DW4 */ +#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) +#define MT_RXD4_NORMAL_PATTERN_DROP BIT(9) +#define MT_RXD4_NORMAL_CLS BIT(10) +#define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) +#define MT_RXD4_NORMAL_MAGIC_PKT BIT(13) +#define MT_RXD4_NORMAL_WOL GENMASK(18, 14) +#define MT_RXD4_NORMAL_CLS_BITMAP GENMASK(28, 19) +#define MT_RXD3_NORMAL_PF_MODE BIT(29) +#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) + +/* P-RXV */ +#define MT_PRXV_TX_RATE GENMASK(6, 0) +#define MT_PRXV_NSTS GENMASK(9, 7) +#define MT_PRXV_HT_AD_CODE BIT(11) +#define MT_PRXV_RCPI3 GENMASK(31, 24) +#define MT_PRXV_RCPI2 GENMASK(23, 16) +#define MT_PRXV_RCPI1 GENMASK(15, 8) +#define MT_PRXV_RCPI0 GENMASK(7, 0) + +/* C-RXV */ +#define MT_CRXV_HT_STBC GENMASK(1, 0) +#define MT_CRXV_TX_MODE GENMASK(7, 4) +#define MT_CRXV_FRAME_MODE GENMASK(10, 8) +#define MT_CRXV_HT_SHORT_GI GENMASK(14, 13) + +struct mt7915_rxv { + u32 phy; + + /* P-RXV: bit 0~1, C-RXV: bit 2~19 */ + __le32 v[20]; +}; + +enum tx_header_format { + MT_HDR_FORMAT_802_3, + MT_HDR_FORMAT_CMD, + MT_HDR_FORMAT_802_11, + MT_HDR_FORMAT_802_11_EXT, +}; + +enum tx_pkt_type { + MT_TX_TYPE_CT, + MT_TX_TYPE_SF, + MT_TX_TYPE_CMD, + MT_TX_TYPE_FW, +}; + +enum tx_pkt_queue_idx { + MT_LMAC_AC00, + MT_LMAC_AC01, + MT_LMAC_AC02, + MT_LMAC_AC03, + MT_LMAC_ALTX0 = 0x10, + MT_LMAC_BMC0 = 0x10, + MT_LMAC_BCN0 = 0x12, +}; + +enum tx_port_idx { + MT_TX_PORT_IDX_LMAC, + MT_TX_PORT_IDX_MCU +}; + +enum tx_mcu_port_q_idx { + MT_TX_MCU_PORT_RX_Q0 = 0x20, + MT_TX_MCU_PORT_RX_Q1, + MT_TX_MCU_PORT_RX_Q2, + MT_TX_MCU_PORT_RX_Q3, + MT_TX_MCU_PORT_RX_FWDL = 0x3e +}; + +#define MT_CT_INFO_APPLY_TXD BIT(0) +#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1) +#define MT_CT_INFO_MGMT_FRAME BIT(2) +#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) +#define MT_CT_INFO_HSR2_TX BIT(4) + +#define MT_TXD_SIZE (8 * 4) + +#define MT_TXD0_Q_IDX GENMASK(31, 25) +#define MT_TXD0_PKT_FMT GENMASK(24, 23) +#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16) +#define MT_TXD0_TX_BYTES GENMASK(15, 0) + +#define MT_TXD1_LONG_FORMAT BIT(31) +#define MT_TXD1_TGID BIT(30) +#define MT_TXD1_OWN_MAC GENMASK(29, 24) +#define MT_TXD1_AMSDU BIT(23) +#define MT_TXD1_TID GENMASK(22, 20) +#define MT_TXD1_HDR_PAD GENMASK(19, 18) +#define MT_TXD1_HDR_FORMAT GENMASK(17, 16) +#define MT_TXD1_HDR_INFO GENMASK(15, 11) +#define MT_TXD1_VTA BIT(10) +#define MT_TXD1_WLAN_IDX GENMASK(9, 0) + +#define MT_TXD2_FIX_RATE BIT(31) +#define MT_TXD2_FIXED_RATE BIT(30) +#define MT_TXD2_POWER_OFFSET GENMASK(29, 24) +#define MT_TXD2_MAX_TX_TIME GENMASK(23, 16) +#define MT_TXD2_FRAG GENMASK(15, 14) +#define MT_TXD2_HTC_VLD BIT(13) +#define MT_TXD2_DURATION BIT(12) +#define MT_TXD2_BIP BIT(11) +#define MT_TXD2_MULTICAST BIT(10) +#define MT_TXD2_RTS BIT(9) +#define MT_TXD2_SOUNDING BIT(8) +#define MT_TXD2_NDPA BIT(7) +#define MT_TXD2_NDP BIT(6) +#define MT_TXD2_FRAME_TYPE GENMASK(5, 4) +#define MT_TXD2_SUB_TYPE GENMASK(3, 0) + +#define MT_TXD3_SN_VALID BIT(31) +#define MT_TXD3_PN_VALID BIT(30) +#define MT_TXD3_SW_POWER_MGMT BIT(29) +#define MT_TXD3_BA_DISABLE BIT(28) +#define MT_TXD3_SEQ GENMASK(27, 16) +#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11) +#define MT_TXD3_TX_COUNT GENMASK(10, 6) +#define MT_TXD3_TIMING_MEASURE BIT(5) +#define MT_TXD3_DAS BIT(4) +#define MT_TXD3_EEOSP BIT(3) +#define MT_TXD3_EMRD BIT(2) +#define MT_TXD3_PROTECT_FRAME BIT(1) +#define MT_TXD3_NO_ACK BIT(0) + +#define MT_TXD4_PN_LOW GENMASK(31, 0) + +#define MT_TXD5_PN_HIGH GENMASK(31, 16) +#define MT_TXD5_MD BIT(15) +#define MT_TXD5_ADD_BA BIT(14) +#define MT_TXD5_TX_STATUS_HOST BIT(10) +#define MT_TXD5_TX_STATUS_MCU BIT(9) +#define MT_TXD5_TX_STATUS_FMT BIT(8) +#define MT_TXD5_PID GENMASK(7, 0) + +#define MT_TXD6_TX_IBF BIT(31) +#define MT_TXD6_TX_EBF BIT(30) +#define MT_TXD6_TX_RATE GENMASK(29, 16) +#define MT_TXD6_SGI GENMASK(15, 14) +#define MT_TXD6_HELTF GENMASK(13, 12) +#define MT_TXD6_LDPC BIT(11) +#define MT_TXD6_SPE_ID_IDX BIT(10) +#define MT_TXD6_ANT_ID GENMASK(7, 4) +#define MT_TXD6_DYN_BW BIT(3) +#define MT_TXD6_FIXED_BW BIT(2) +#define MT_TXD6_BW GENMASK(2, 0) + +#define MT_TXD7_TXD_LEN GENMASK(31, 30) +#define MT_TXD7_UDP_TCP_SUM BIT(29) +#define MT_TXD7_IP_SUM BIT(28) + +#define MT_TXD7_TYPE GENMASK(21, 20) +#define MT_TXD7_SUB_TYPE GENMASK(19, 16) + +#define MT_TXD7_PSE_FID GENMASK(27, 16) +#define MT_TXD7_SPE_IDX GENMASK(15, 11) +#define MT_TXD7_HW_AMSDU BIT(10) +#define MT_TXD7_TX_TIME GENMASK(9, 0) + +#define MT_TX_RATE_STBC BIT(13) +#define MT_TX_RATE_NSS GENMASK(12, 10) +#define MT_TX_RATE_MODE GENMASK(9, 6) +#define MT_TX_RATE_IDX GENMASK(5, 0) + +#define MT_TXP_MAX_BUF_NUM 6 + +struct mt7915_txp { + __le16 flags; + __le16 token; + u8 bss_idx; + u8 rept_wds_wcid; + u8 rsv; + u8 nbuf; + __le32 buf[MT_TXP_MAX_BUF_NUM]; + __le16 len[MT_TXP_MAX_BUF_NUM]; +} __packed __aligned(4); + +struct mt7915_tx_free { + __le16 rx_byte_cnt; + __le16 ctrl; + u8 txd_cnt; + u8 rsv[3]; + __le32 info[]; +} __packed __aligned(4); + +#define MT_TX_FREE_MSDU_CNT GENMASK(9, 0) +#define MT_TX_FREE_WLAN_ID GENMASK(23, 14) +#define MT_TX_FREE_LATENCY GENMASK(12, 0) +/* 0: success, others: dropped */ +#define MT_TX_FREE_STATUS GENMASK(14, 13) +#define MT_TX_FREE_MSDU_ID GENMASK(30, 16) +#define MT_TX_FREE_PAIR BIT(31) +/* will support this field in further revision */ +#define MT_TX_FREE_RATE GENMASK(13, 0) + +struct mt7915_dfs_pulse { + u32 max_width; /* us */ + int max_pwr; /* dbm */ + int min_pwr; /* dbm */ + u32 min_stgr_pri; /* us */ + u32 max_stgr_pri; /* us */ + u32 min_cr_pri; /* us */ + u32 max_cr_pri; /* us */ +}; + +struct mt7915_dfs_pattern { + u8 enb; + u8 stgr; + u8 min_crpn; + u8 max_crpn; + u8 min_crpr; + u8 min_pw; + u32 min_pri; + u32 max_pri; + u8 max_pw; + u8 min_crbn; + u8 max_crbn; + u8 min_stgpn; + u8 max_stgpn; + u8 min_stgpr; + u8 rsv[2]; + u32 min_stgpr_diff; +} __packed; + +struct mt7915_dfs_radar_spec { + struct mt7915_dfs_pulse pulse_th; + struct mt7915_dfs_pattern radar_pattern[16]; +}; + +static inline struct mt7915_txp * +mt7915_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) +{ + u8 *txwi; + + if (!t) + return NULL; + + txwi = mt76_get_txwi_ptr(dev, t); + + return (struct mt7915_txp *)(txwi + MT_TXD_SIZE); +} + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c new file mode 100644 index 000000000000..ae5ed41d337b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -0,0 +1,741 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include +#include +#include +#include +#include "mt7915.h" +#include "mcu.h" + +static bool mt7915_dev_running(struct mt7915_dev *dev) +{ + struct mt7915_phy *phy; + + if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) + return true; + + phy = mt7915_ext_phy(dev); + + return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); +} + +static int mt7915_start(struct ieee80211_hw *hw) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool running; + + mutex_lock(&dev->mt76.mutex); + + running = mt7915_dev_running(dev); + + if (!running) { + mt7915_mcu_set_pm(dev, 0, 0); + mt7915_mcu_set_mac(dev, 0, true, false); + mt7915_mcu_set_scs(dev, 0, true); + } + + if (phy != &dev->phy) { + mt7915_mcu_set_pm(dev, 1, 0); + mt7915_mcu_set_mac(dev, 1, true, false); + mt7915_mcu_set_scs(dev, 1, true); + } + + mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); + + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); + + if (running) + goto out; + + mt7915_mac_reset_counters(phy); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + MT7915_WATCHDOG_TIME); +out: + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static void mt7915_stop(struct ieee80211_hw *hw) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + + mutex_lock(&dev->mt76.mutex); + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); + + if (phy != &dev->phy) { + mt7915_mcu_set_pm(dev, 1, 1); + mt7915_mcu_set_mac(dev, 1, false, false); + } + + if (!mt7915_dev_running(dev)) { + cancel_delayed_work_sync(&dev->mt76.mac_work); + + mt7915_mcu_set_pm(dev, 0, 1); + mt7915_mcu_set_mac(dev, 0, false, false); + } + + mutex_unlock(&dev->mt76.mutex); +} + +static int get_omac_idx(enum nl80211_iftype type, u32 mask) +{ + int i; + + switch (type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP: + /* ap uses hw bssid 0 and ext bssid */ + if (~mask & BIT(HW_BSSID_0)) + return HW_BSSID_0; + + for (i = EXT_BSSID_1; i < EXT_BSSID_END; i++) + if (~mask & BIT(i)) + return i; + break; + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + /* station uses hw bssid other than 0 */ + for (i = HW_BSSID_1; i < HW_BSSID_MAX; i++) + if (~mask & BIT(i)) + return i; + break; + default: + WARN_ON(1); + break; + } + + return -1; +} + +static int mt7915_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt76_txq *mtxq; + bool ext_phy = phy != &dev->phy; + int idx, ret = 0; + + mutex_lock(&dev->mt76.mutex); + + mvif->idx = ffs(~phy->vif_mask) - 1; + if (mvif->idx >= MT7915_MAX_INTERFACES) { + ret = -ENOSPC; + goto out; + } + + idx = get_omac_idx(vif->type, phy->omac_mask); + if (idx < 0) { + ret = -ENOSPC; + goto out; + } + mvif->omac_idx = idx; + mvif->dev = dev; + mvif->band_idx = ext_phy; + + if (ext_phy) + mvif->wmm_idx = ext_phy * (MT7915_MAX_WMM_SETS / 2) + + mvif->idx % (MT7915_MAX_WMM_SETS / 2); + else + mvif->wmm_idx = mvif->idx % MT7915_MAX_WMM_SETS; + + ret = mt7915_mcu_add_dev_info(dev, vif, true); + if (ret) + goto out; + + phy->vif_mask |= BIT(mvif->idx); + phy->omac_mask |= BIT(mvif->omac_idx); + + idx = MT7915_WTBL_RESERVED - mvif->idx; + + INIT_LIST_HEAD(&mvif->sta.poll_list); + mvif->sta.wcid.idx = idx; + mvif->sta.wcid.ext_phy = mvif->band_idx; + mvif->sta.wcid.hw_key_idx = -1; + mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt7915_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); + if (vif->txq) { + mtxq = (struct mt76_txq *)vif->txq->drv_priv; + mtxq->wcid = &mvif->sta.wcid; + mt76_txq_init(&dev->mt76, vif->txq); + } + +out: + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + +static void mt7915_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = &mvif->sta; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + int idx = msta->wcid.idx; + + /* TODO: disable beacon for the bss */ + + mt7915_mcu_add_dev_info(dev, vif, false); + + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + if (vif->txq) + mt76_txq_remove(&dev->mt76, vif->txq); + + mutex_lock(&dev->mt76.mutex); + phy->vif_mask &= ~BIT(mvif->idx); + phy->omac_mask &= ~BIT(mvif->omac_idx); + mutex_unlock(&dev->mt76.mutex); + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); +} + +static void mt7915_init_dfs_state(struct mt7915_phy *phy) +{ + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct cfg80211_chan_def *chandef = &hw->conf.chandef; + + if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + return; + + if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) + return; + + if (mphy->chandef.chan->center_freq == chandef->chan->center_freq && + mphy->chandef.width == chandef->width) + return; + + phy->dfs_state = -1; +} + +static int mt7915_set_channel(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + int ret; + + cancel_delayed_work_sync(&dev->mt76.mac_work); + + mutex_lock(&dev->mt76.mutex); + set_bit(MT76_RESET, &phy->mt76->state); + + mt7915_init_dfs_state(phy); + mt76_set_channel(phy->mt76); + + ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH); + if (ret) + goto out; + + mt7915_mac_set_timing(phy); + ret = mt7915_dfs_init_radar_detector(phy); + mt7915_mac_cca_stats_reset(phy); + + mt7915_mac_reset_counters(phy); + phy->noise = 0; + +out: + clear_bit(MT76_RESET, &phy->mt76->state); + mutex_unlock(&dev->mt76.mutex); + + mt76_txq_schedule_all(phy->mt76); + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + MT7915_WATCHDOG_TIME); + + return ret; +} + +static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = sta ? (struct mt7915_sta *)sta->drv_priv : + &mvif->sta; + struct mt76_wcid *wcid = &msta->wcid; + int idx = key->keyidx; + + /* The hardware does not support per-STA RX GTK, fallback + * to software mode for these. + */ + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + + /* fall back to sw encryption for unsupported ciphers */ + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + case WLAN_CIPHER_SUITE_SMS4: + break; + default: + return -EOPNOTSUPP; + } + + if (cmd == SET_KEY) { + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; + } else if (idx == wcid->hw_key_idx) { + wcid->hw_key_idx = -1; + } + mt76_wcid_key_setup(&dev->mt76, wcid, + cmd == SET_KEY ? key : NULL); + + return mt7915_mcu_add_key(dev, vif, msta, key, cmd); +} + +static int mt7915_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + int ret; + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ieee80211_stop_queues(hw); + ret = mt7915_set_channel(phy); + if (ret) + return ret; + ieee80211_wake_queues(hw); + } + + mutex_lock(&dev->mt76.mutex); + + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) + phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; + else + phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; + + mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); + } + + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static int +mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + + /* no need to update right away, we'll get BSS_CHANGED_QOS */ + mvif->wmm[queue].cw_min = params->cw_min; + mvif->wmm[queue].cw_max = params->cw_max; + mvif->wmm[queue].aifs = params->aifs; + mvif->wmm[queue].txop = params->txop; + + return 0; +} + +static void mt7915_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + + u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | + MT_WF_RFCR1_DROP_BF_POLL | + MT_WF_RFCR1_DROP_BA | + MT_WF_RFCR1_DROP_CFEND | + MT_WF_RFCR1_DROP_CFACK; + u32 flags = 0; + +#define MT76_FILTER(_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + phy->rxfilter &= ~(_hw); \ + phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + } while (0) + + phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | + MT_WF_RFCR_DROP_OTHER_BEACON | + MT_WF_RFCR_DROP_FRAME_REPORT | + MT_WF_RFCR_DROP_PROBEREQ | + MT_WF_RFCR_DROP_MCAST_FILTERED | + MT_WF_RFCR_DROP_MCAST | + MT_WF_RFCR_DROP_BCAST | + MT_WF_RFCR_DROP_DUPLICATE | + MT_WF_RFCR_DROP_A2_BSSID | + MT_WF_RFCR_DROP_UNWANTED_CTL | + MT_WF_RFCR_DROP_STBC_MULTI); + + MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | + MT_WF_RFCR_DROP_A3_MAC | + MT_WF_RFCR_DROP_A3_BSSID); + + MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); + + MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | + MT_WF_RFCR_DROP_RTS | + MT_WF_RFCR_DROP_CTL_RSV | + MT_WF_RFCR_DROP_NDPA); + + *total_flags = flags; + mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); + + if (*total_flags & FIF_CONTROL) + mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags); + else + mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); +} + +static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt7915_dev *dev = mt7915_hw_dev(hw); + + mutex_lock(&dev->mt76.mutex); + + /* + * station mode uses BSSID to map the wlan entry to a peer, + * and then peer references bss_info_rfch to set bandwidth cap. + */ + if (changed & BSS_CHANGED_BSSID && + vif->type == NL80211_IFTYPE_STATION) { + bool join = !is_zero_ether_addr(info->bssid); + + mt7915_mcu_add_bss_info(phy, vif, join); + mt7915_mcu_add_sta(dev, vif, NULL, join); + } + + if (changed & BSS_CHANGED_ASSOC) + mt7915_mcu_add_bss_info(phy, vif, info->assoc); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; + + if (slottime != phy->slottime) { + phy->slottime = slottime; + mt7915_mac_set_timing(phy); + } + } + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + mt7915_mcu_add_bss_info(phy, vif, info->enable_beacon); + mt7915_mcu_add_sta(dev, vif, NULL, info->enable_beacon); + } + + /* ensure that enable txcmd_mode after bss_info */ + if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) + mt7915_mcu_set_tx(dev, vif); + + if (changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED)) + mt7915_mcu_add_beacon(hw, vif, info->enable_beacon); + + mutex_unlock(&dev->mt76.mutex); +} + +static void +mt7915_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + + mutex_lock(&dev->mt76.mutex); + mt7915_mcu_add_beacon(hw, vif, true); + mutex_unlock(&dev->mt76.mutex); +} + +int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + int idx; + + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1); + if (idx < 0) + return -ENOSPC; + + INIT_LIST_HEAD(&msta->poll_list); + INIT_WORK(&msta->stats_work, mt7915_mac_sta_stats_work); + spin_lock_init(&msta->ampdu_lock); + msta->vif = mvif; + msta->wcid.sta = 1; + msta->wcid.idx = idx; + msta->wcid.ext_phy = mvif->band_idx; + msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + msta->stats.jiffies = jiffies; + + mt7915_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + mt7915_mcu_add_sta(dev, vif, sta, true); + + return 0; +} + +void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + + mt7915_mcu_add_sta(dev, vif, sta, false); + + mt7915_mac_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); +} + +static void mt7915_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct mt76_wcid *wcid = &dev->mt76.global_wcid; + + if (control->sta) { + struct mt7915_sta *sta; + + sta = (struct mt7915_sta *)control->sta->drv_priv; + wcid = &sta->wcid; + } + + if (vif && !control->sta) { + struct mt7915_vif *mvif; + + mvif = (struct mt7915_vif *)vif->drv_priv; + wcid = &mvif->sta.wcid; + } + + mt76_tx(mphy, control->sta, wcid, skb); +} + +static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + + mutex_lock(&dev->mt76.mutex); + mt7915_mcu_set_rts_thresh(phy, val); + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static int +mt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + enum ieee80211_ampdu_mlme_action action = params->action; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct ieee80211_sta *sta = params->sta; + struct ieee80211_txq *txq = sta->txq[params->tid]; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + u16 tid = params->tid; + u16 ssn = params->ssn; + struct mt76_txq *mtxq; + int ret = 0; + + if (!txq) + return -EINVAL; + + mtxq = (struct mt76_txq *)txq->drv_priv; + + mutex_lock(&dev->mt76.mutex); + switch (action) { + case IEEE80211_AMPDU_RX_START: + mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, + params->buf_size); + mt7915_mcu_add_rx_ba(dev, params, true); + break; + case IEEE80211_AMPDU_RX_STOP: + mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); + mt7915_mcu_add_rx_ba(dev, params, false); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + mtxq->aggr = true; + mtxq->send_bar = false; + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_OPERATIONAL); + mt7915_mcu_add_tx_ba(dev, params, true); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + mtxq->aggr = false; + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP); + mt7915_mcu_add_tx_ba(dev, params, false); + break; + case IEEE80211_AMPDU_TX_START: + mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_START); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; + break; + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP); + mt7915_mcu_add_tx_ba(dev, params, false); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + +static int +mt7915_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, + IEEE80211_STA_NONE); +} + +static int +mt7915_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, + IEEE80211_STA_NOTEXIST); +} + +static int +mt7915_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mib_stats *mib = &phy->mib; + + stats->dot11RTSSuccessCount = mib->rts_cnt; + stats->dot11RTSFailureCount = mib->rts_retries_cnt; + stats->dot11FCSErrorCount = mib->fcs_err_cnt; + stats->dot11ACKFailureCount = mib->ack_fail_cnt; + + return 0; +} + +static void +mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + + phy->coverage_class = max_t(s16, coverage_class, 0); + mt7915_mac_set_timing(phy); +} + +static int +mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + int max_nss = hweight8(hw->wiphy->available_antennas_tx); + bool ext_phy = phy != &dev->phy; + + if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) + return -EINVAL; + + if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) + tx_ant = BIT(ffs(tx_ant) - 1) - 1; + + mutex_lock(&dev->mt76.mutex); + + phy->mt76->antenna_mask = tx_ant; + + if (ext_phy) { + if (dev->chainmask == 0xf) + tx_ant <<= 2; + else + tx_ant <<= 1; + } + phy->chainmask = tx_ant; + + mt76_set_stream_caps(&dev->mt76, true); + + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static void +mt7915_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u32 changed) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, sta->addr); + if (!sta) { + rcu_read_unlock(); + return; + } + rcu_read_lock(); + + set_bit(changed, &msta->stats.changed); + ieee80211_queue_work(hw, &msta->stats_work); +} + +const struct ieee80211_ops mt7915_ops = { + .tx = mt7915_tx, + .start = mt7915_start, + .stop = mt7915_stop, + .add_interface = mt7915_add_interface, + .remove_interface = mt7915_remove_interface, + .config = mt7915_config, + .conf_tx = mt7915_conf_tx, + .configure_filter = mt7915_configure_filter, + .bss_info_changed = mt7915_bss_info_changed, + .sta_add = mt7915_sta_add, + .sta_remove = mt7915_sta_remove, + .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, + .sta_rc_update = mt7915_sta_rc_update, + .set_key = mt7915_set_key, + .ampdu_action = mt7915_ampdu_action, + .set_rts_threshold = mt7915_set_rts_threshold, + .wake_tx_queue = mt76_wake_tx_queue, + .sw_scan_start = mt76_sw_scan, + .sw_scan_complete = mt76_sw_scan_complete, + .release_buffered_frames = mt76_release_buffered_frames, + .get_txpower = mt76_get_txpower, + .channel_switch_beacon = mt7915_channel_switch_beacon, + .get_stats = mt7915_get_stats, + .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, + .set_antenna = mt7915_set_antenna, + .set_coverage_class = mt7915_set_coverage_class, +}; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c new file mode 100644 index 000000000000..dad2c300d0f2 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -0,0 +1,2313 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include +#include +#include "mt7915.h" +#include "mcu.h" +#include "mac.h" +#include "eeprom.h" + +struct mt7915_patch_hdr { + char build_date[16]; + char platform[4]; + __be32 hw_sw_ver; + __be32 patch_ver; + __be16 checksum; + u16 reserved; + struct { + __be32 patch_ver; + __be32 subsys; + __be32 feature; + __be32 n_region; + __be32 crc; + u32 reserved[11]; + } desc; +} __packed; + +struct mt7915_patch_sec { + __be32 type; + __be32 offs; + __be32 size; + union { + __be32 spec[13]; + struct { + __be32 addr; + __be32 len; + __be32 sec_key_idx; + __be32 align_len; + u32 reserved[9]; + } info; + }; +} __packed; + +struct mt7915_fw_trailer { + u8 chip_id; + u8 eco_code; + u8 n_region; + u8 format_ver; + u8 format_flag; + u8 reserved[2]; + char fw_ver[10]; + char build_date[15]; + u32 crc; +} __packed; + +struct mt7915_fw_region { + __le32 decomp_crc; + __le32 decomp_len; + __le32 decomp_blk_sz; + u8 reserved[4]; + __le32 addr; + __le32 len; + u8 feature_set; + u8 reserved1[15]; +} __packed; + +#define MCU_PATCH_ADDRESS 0x200000 + +#define FW_FEATURE_SET_ENCRYPT BIT(0) +#define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) +#define FW_FEATURE_OVERRIDE_ADDR BIT(5) + +#define DL_MODE_ENCRYPT BIT(0) +#define DL_MODE_KEY_IDX GENMASK(2, 1) +#define DL_MODE_RESET_SEC_IV BIT(3) +#define DL_MODE_WORKING_PDA_CR4 BIT(4) +#define DL_MODE_NEED_RSP BIT(31) + +#define FW_START_OVERRIDE BIT(0) +#define FW_START_WORKING_PDA_CR4 BIT(2) + +#define PATCH_SEC_TYPE_MASK GENMASK(15, 0) +#define PATCH_SEC_TYPE_INFO 0x2 + +#define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) +#define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) + +static enum mt7915_cipher_type +mt7915_mcu_get_cipher(int cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_AES_CMAC: + return MT_CIPHER_BIP_CMAC_128; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + case WLAN_CIPHER_SUITE_CCMP_256: + return MT_CIPHER_CCMP_256; + case WLAN_CIPHER_SUITE_GCMP: + return MT_CIPHER_GCMP; + case WLAN_CIPHER_SUITE_GCMP_256: + return MT_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_SMS4: + return MT_CIPHER_WAPI; + default: + return MT_CIPHER_NONE; + } +} + +static u8 mt7915_mcu_chan_bw(struct cfg80211_chan_def *chandef) +{ + static const u8 width_to_bw[] = { + [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, + [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, + [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, + [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, + [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, + [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, + [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, + [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, + }; + + if (chandef->width >= ARRAY_SIZE(width_to_bw)) + return 0; + + return width_to_bw[chandef->width]; +} + +static u8 +mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, + enum nl80211_band band, struct ieee80211_sta *sta) +{ + struct ieee80211_sta_ht_cap *ht_cap; + struct ieee80211_sta_vht_cap *vht_cap; + u8 mode = 0; + + if (sta) { + ht_cap = &sta->ht_cap; + vht_cap = &sta->vht_cap; + } else { + struct ieee80211_supported_band *sband; + + if (band == NL80211_BAND_2GHZ) + sband = &dev->mphy.sband_2g.sband; + else + sband = &dev->mphy.sband_5g.sband; + + ht_cap = &sband->ht_cap; + vht_cap = &sband->vht_cap; + } + + if (band == NL80211_BAND_2GHZ) { + mode |= PHY_MODE_B | PHY_MODE_G; + + if (ht_cap->ht_supported) + mode |= PHY_MODE_GN; + } else if (band == NL80211_BAND_5GHZ) { + mode |= PHY_MODE_A; + + if (ht_cap->ht_supported) + mode |= PHY_MODE_AN; + + if (vht_cap->vht_supported) + mode |= PHY_MODE_AC; + } + + return mode; +} + +static int __mt7915_mcu_msg_send(struct mt7915_dev *dev, struct sk_buff *skb, + int cmd, int *wait_seq) +{ + struct mt7915_mcu_txd *mcu_txd; + u8 seq, pkt_fmt, qidx; + enum mt7915_txq_id txq; + __le32 *txd; + u32 val; + + seq = ++dev->mt76.mcu.msg_seq & 0xf; + if (!seq) + seq = ++dev->mt76.mcu.msg_seq & 0xf; + + if (cmd == -MCU_CMD_FW_SCATTER) { + txq = MT_TXQ_FWDL; + goto exit; + } + + mcu_txd = (struct mt7915_mcu_txd *)skb_push(skb, sizeof(*mcu_txd)); + + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) { + txq = MT_TXQ_MCU_WA; + qidx = MT_TX_MCU_PORT_RX_Q0; + pkt_fmt = MT_TX_TYPE_CMD; + } else { + txq = MT_TXQ_MCU; + qidx = MT_TX_MCU_PORT_RX_Q0; + pkt_fmt = MT_TX_TYPE_CMD; + } + + txd = mcu_txd->txd; + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | + FIELD_PREP(MT_TXD0_PKT_FMT, pkt_fmt) | + FIELD_PREP(MT_TXD0_Q_IDX, qidx); + txd[0] = cpu_to_le32(val); + + val = MT_TXD1_LONG_FORMAT | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); + txd[1] = cpu_to_le32(val); + + mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); + mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, qidx)); + mcu_txd->pkt_type = MCU_PKT_ID; + mcu_txd->seq = seq; + + if (cmd < 0) { + mcu_txd->set_query = MCU_Q_NA; + mcu_txd->cid = -cmd; + } else { + mcu_txd->cid = MCU_CMD_EXT_CID; + mcu_txd->ext_cid = cmd; + mcu_txd->ext_cid_ack = 1; + + /* do not use Q_SET for efuse */ + if (cmd == MCU_EXT_CMD_EFUSE_ACCESS) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; + } + + mcu_txd->s2d_index = MCU_S2D_H2N; + BUILD_BUG_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && + mcu_txd->set_query != MCU_Q_QUERY); + +exit: + if (wait_seq) + *wait_seq = seq; + + return mt76_tx_queue_skb_raw(dev, txq, skb, 0); +} + +static int +mt7915_mcu_parse_eeprom(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_eeprom_info *res; + u8 *buf; + + if (!skb) + return -EINVAL; + + skb_pull(skb, sizeof(struct mt7915_mcu_rxd)); + + res = (struct mt7915_mcu_eeprom_info *)skb->data; + buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); + memcpy(buf, res->data, 16); + + return 0; +} + +static int +mt7915_mcu_parse_response(struct mt7915_dev *dev, int cmd, + struct sk_buff *skb, int seq) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + int ret = 0; + + if (seq != rxd->seq) + return -EAGAIN; + + switch (cmd) { + case -MCU_CMD_PATCH_SEM_CONTROL: + skb_pull(skb, sizeof(*rxd) - 4); + ret = *skb->data; + break; + case MCU_EXT_CMD_THERMAL_CTRL: + skb_pull(skb, sizeof(*rxd) + 4); + ret = le32_to_cpu(*(__le32 *)skb->data); + break; + case MCU_EXT_CMD_EFUSE_ACCESS: + ret = mt7915_mcu_parse_eeprom(dev, skb); + break; + default: + break; + } + dev_kfree_skb(skb); + + return ret; +} + +static int +mt7915_mcu_wait_response(struct mt7915_dev *dev, int cmd, int seq) +{ + unsigned long expires = jiffies + 20 * HZ; + struct sk_buff *skb; + int ret = 0; + + while (true) { + skb = mt76_mcu_get_response(&dev->mt76, expires); + if (!skb) { + dev_err(dev->mt76.dev, "Message %d (seq %d) timeout\n", + cmd, seq); + return -ETIMEDOUT; + } + + ret = mt7915_mcu_parse_response(dev, cmd, skb, seq); + if (ret != -EAGAIN) + break; + } + + return ret; +} + +static int +mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, bool wait_resp) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + int ret, seq; + + mutex_lock(&mdev->mcu.mutex); + + ret = __mt7915_mcu_msg_send(dev, skb, cmd, &seq); + if (ret) + goto out; + + if (wait_resp) + ret = mt7915_mcu_wait_response(dev, cmd, seq); + +out: + mutex_unlock(&mdev->mcu.mutex); + + return ret; +} + +static int +mt7915_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, + int len, bool wait_resp) +{ + struct sk_buff *skb; + + skb = mt76_mcu_msg_alloc(mdev, data, len); + if (!skb) + return -ENOMEM; + + return __mt76_mcu_skb_send_msg(mdev, skb, cmd, wait_resp); +} + +static void +mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + if (vif->csa_active) + ieee80211_csa_finish(vif); +} + +static void +mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7915_mcu_rdd_report *r; + + r = (struct mt7915_mcu_rdd_report *)skb->data; + + if (r->idx && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + ieee80211_radar_detected(mphy->hw); + dev->hw_pattern++; +} + +static void +mt7915_mcu_tx_rate_cal(struct mt76_phy *mphy, struct mt7915_mcu_ra_info *ra, + struct rate_info *rate, u16 r) +{ + struct ieee80211_supported_band *sband; + u16 ru_idx = le16_to_cpu(ra->ru_idx); + u16 flags = 0; + + rate->mcs = FIELD_GET(MT_RA_RATE_MCS, r); + rate->nss = FIELD_GET(MT_RA_RATE_NSS, r) + 1; + + switch (FIELD_GET(MT_RA_RATE_TX_MODE, r)) { + case MT_PHY_TYPE_CCK: + case MT_PHY_TYPE_OFDM: + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else + sband = &mphy->sband_2g.sband; + + rate->legacy = sband->bitrates[rate->mcs].bitrate; + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + rate->mcs += (rate->nss - 1) * 8; + flags |= RATE_INFO_FLAGS_MCS; + + if (ra->gi) + flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_VHT: + flags |= RATE_INFO_FLAGS_VHT_MCS; + + if (ra->gi) + flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + rate->he_gi = ra->gi; + rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r); + + flags |= RATE_INFO_FLAGS_HE_MCS; + break; + default: + break; + } + rate->flags = flags; + + if (ru_idx) { + switch (ru_idx) { + case 1 ... 2: + rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + case 3 ... 6: + rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_484; + break; + case 7 ... 14: + rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_242; + break; + default: + rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_106; + break; + } + rate->bw = RATE_INFO_BW_HE_RU; + } else { + u8 bw = mt7915_mcu_chan_bw(&mphy->chandef) - + FIELD_GET(MT_RA_RATE_BW, r); + + switch (bw) { + case IEEE80211_STA_RX_BW_160: + rate->bw = RATE_INFO_BW_160; + break; + case IEEE80211_STA_RX_BW_80: + rate->bw = RATE_INFO_BW_80; + break; + case IEEE80211_STA_RX_BW_40: + rate->bw = RATE_INFO_BW_40; + break; + default: + rate->bw = RATE_INFO_BW_20; + break; + } + } +} + +static void +mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_ra_info *ra = (struct mt7915_mcu_ra_info *)skb->data; + u16 wcidx = le16_to_cpu(ra->wlan_idx); + struct mt76_wcid *wcid = rcu_dereference(dev->mt76.wcid[wcidx]); + struct mt7915_sta *msta = container_of(wcid, struct mt7915_sta, wcid); + struct mt7915_sta_stats *stats = &msta->stats; + struct mt76_phy *mphy = &dev->mphy; + struct rate_info rate = {}, prob_rate = {}; + u16 attempts = le16_to_cpu(ra->attempts); + u16 curr = le16_to_cpu(ra->curr_rate); + u16 probe = le16_to_cpu(ra->prob_up_rate); + + if (msta->wcid.ext_phy && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + /* current rate */ + mt7915_mcu_tx_rate_cal(mphy, ra, &rate, curr); + stats->tx_rate = rate; + + /* probing rate */ + mt7915_mcu_tx_rate_cal(mphy, ra, &prob_rate, probe); + stats->prob_rate = prob_rate; + + if (attempts) { + u16 success = le16_to_cpu(ra->success); + + stats->per = 1000 * (attempts - success) / attempts; + } +} + +static void +mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + + switch (rxd->ext_eid) { + case MCU_EXT_EVENT_RDD_REPORT: + mt7915_mcu_rx_radar_detected(dev, skb); + break; + case MCU_EXT_EVENT_CSA_NOTIFY: + ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7915_mcu_csa_finish, dev); + break; + case MCU_EXT_EVENT_RATE_REPORT: + mt7915_mcu_tx_rate_report(dev, skb); + break; + default: + break; + } +} + +static void +mt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + + switch (rxd->eid) { + case MCU_EVENT_EXT: + mt7915_mcu_rx_ext_event(dev, skb); + break; + default: + break; + } + dev_kfree_skb(skb); +} + +void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + + if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || + rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || + rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || + rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || + !rxd->seq) + mt7915_mcu_rx_unsolicited_event(dev, skb); + else + mt76_mcu_rx_event(&dev->mt76, skb); +} + +static struct sk_buff * +mt7915_mcu_alloc_sta_req(struct mt7915_dev *dev, struct mt7915_vif *mvif, + struct mt7915_sta *msta, int len) +{ + struct sta_req_hdr hdr = { + .bss_idx = mvif->idx, + .wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : 0, + .wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : 0, + .muar_idx = msta ? mvif->omac_idx : 0, + .is_tlv_append = 1, + }; + struct sk_buff *skb; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + skb_put_data(skb, &hdr, sizeof(hdr)); + + return skb; +} + +static struct wtbl_req_hdr * +mt7915_mcu_alloc_wtbl_req(struct mt7915_dev *dev, struct mt7915_sta *msta, + int cmd, void *sta_wtbl, struct sk_buff **skb) +{ + struct tlv *sta_hdr = sta_wtbl; + struct wtbl_req_hdr hdr = { + .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), + .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), + .operation = cmd, + }; + struct sk_buff *nskb = *skb; + + if (!nskb) { + nskb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + MT7915_WTBL_UPDATE_BA_SIZE); + if (!nskb) + return ERR_PTR(-ENOMEM); + + *skb = nskb; + } + + if (sta_hdr) + sta_hdr->len = cpu_to_le16(sizeof(hdr)); + + return skb_put_data(nskb, &hdr, sizeof(hdr)); +} + +static struct tlv * +mt7915_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len, + void *sta_ntlv, void *sta_wtbl) +{ + struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv; + struct tlv *sta_hdr = sta_wtbl; + struct tlv *ptlv, tlv = { + .tag = cpu_to_le16(tag), + .len = cpu_to_le16(len), + }; + u16 ntlv; + + ptlv = skb_put(skb, len); + memcpy(ptlv, &tlv, sizeof(tlv)); + + ntlv = le16_to_cpu(ntlv_hdr->tlv_num); + ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1); + + if (sta_hdr) { + u16 size = le16_to_cpu(sta_hdr->len); + + sta_hdr->len = cpu_to_le16(size + len); + } + + return ptlv; +} + +static struct tlv * +mt7915_mcu_add_tlv(struct sk_buff *skb, int tag, int len) +{ + return mt7915_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL); +} + +static struct tlv * +mt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len, + __le16 *sub_ntlv, __le16 *len) +{ + struct tlv *ptlv, tlv = { + .tag = cpu_to_le16(sub_tag), + .len = cpu_to_le16(sub_len), + }; + + ptlv = skb_put(skb, sub_len); + memcpy(ptlv, &tlv, sizeof(tlv)); + + *sub_ntlv = cpu_to_le16(le16_to_cpu(*sub_ntlv) + 1); + *len = cpu_to_le16(le16_to_cpu(*len) + sub_len); + + return ptlv; +} + +/** bss info **/ +static int +mt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct mt7915_phy *phy, bool enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + enum nl80211_band band = chandef->chan->band; + struct bss_info_basic *bss; + u16 wlan_idx = mvif->sta.wcid.idx; + u32 type = NETWORK_INFRA; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss)); + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + break; + case NL80211_IFTYPE_STATION: + /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ + if (enable) { + struct ieee80211_sta *sta; + struct mt7915_sta *msta; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (!sta) { + rcu_read_unlock(); + return -EINVAL; + } + + msta = (struct mt7915_sta *)sta->drv_priv; + wlan_idx = msta->wcid.idx; + rcu_read_unlock(); + } + break; + case NL80211_IFTYPE_ADHOC: + type = NETWORK_IBSS; + break; + default: + WARN_ON(1); + break; + } + + bss = (struct bss_info_basic *)tlv; + memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); + bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); + bss->network_type = cpu_to_le32(type); + bss->dtim_period = vif->bss_conf.dtim_period; + bss->bmc_wcid_lo = to_wcid_lo(wlan_idx); + bss->bmc_wcid_hi = to_wcid_hi(wlan_idx); + bss->phy_mode = mt7915_get_phy_mode(phy->dev, vif, band, NULL); + bss->wmm_idx = mvif->wmm_idx; + bss->active = enable; + + return 0; +} + +static void +mt7915_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct bss_info_omac *omac; + struct tlv *tlv; + u32 type = 0; + u8 idx; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac)); + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + type = CONNECTION_INFRA_AP; + break; + case NL80211_IFTYPE_STATION: + type = CONNECTION_INFRA_STA; + break; + case NL80211_IFTYPE_ADHOC: + type = CONNECTION_IBSS_ADHOC; + break; + default: + WARN_ON(1); + break; + } + + omac = (struct bss_info_omac *)tlv; + idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; + omac->conn_type = cpu_to_le32(type); + omac->omac_idx = mvif->omac_idx; + omac->band_idx = mvif->band_idx; + omac->hw_bss_idx = idx; +} + +static void +mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct mt7915_phy *phy) +{ + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + struct bss_info_rf_ch *ch; + struct tlv *tlv; + int freq1 = chandef->center_freq1; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch)); + + ch = (struct bss_info_rf_ch *)tlv; + ch->pri_ch = chandef->chan->hw_value; + ch->center_ch0 = ieee80211_frequency_to_channel(freq1); + ch->bw = mt7915_mcu_chan_bw(chandef); + + if (chandef->width == NL80211_CHAN_WIDTH_80P80) { + int freq2 = chandef->center_freq2; + + ch->center_ch1 = ieee80211_frequency_to_channel(freq2); + } + + ch->he_all_disable = true; +} + +static void +mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct mt7915_phy *phy) +{ + struct bss_info_ra *ra; + struct tlv *tlv; + int max_nss = hweight8(phy->chainmask); + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra)); + + ra = (struct bss_info_ra *)tlv; + ra->op_mode = vif->type == NL80211_IFTYPE_AP; + ra->adhoc_en = vif->type == NL80211_IFTYPE_ADHOC; + ra->short_preamble = true; + ra->tx_streams = max_nss; + ra->rx_streams = max_nss; + ra->algo = 4; + ra->train_up_rule = 2; + ra->train_up_high_thres = 110; + ra->train_up_rule_rssi = -70; + ra->low_traffic_thres = 2; + ra->phy_cap = cpu_to_le32(0xfdf); + ra->interval = cpu_to_le32(500); + ra->fast_interval = cpu_to_le32(100); +} + +static void +mt7915_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7915_vif *mvif) +{ +/* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */ +#define BCN_TX_ESTIMATE_TIME (4096 + 20) + struct bss_info_ext_bss *ext; + int ext_bss_idx, tsf_offset; + struct tlv *tlv; + + ext_bss_idx = mvif->omac_idx - EXT_BSSID_START; + if (ext_bss_idx < 0) + return; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext)); + + ext = (struct bss_info_ext_bss *)tlv; + tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME; + ext->mbss_tsf_offset = cpu_to_le32(tsf_offset); +} + +static void +mt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy) +{ + struct bss_info_bmc_rate *bmc; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + enum nl80211_band band = chandef->chan->band; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc)); + + bmc = (struct bss_info_bmc_rate *)tlv; + if (band == NL80211_BAND_2GHZ) { + bmc->short_preamble = true; + } else { + bmc->bc_trans = cpu_to_le16(0x2000); + bmc->mc_trans = cpu_to_le16(0x2080); + } +} + +static void +mt7915_mcu_bss_sync_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +{ + struct bss_info_sync_mode *sync; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_SYNC_MODE, sizeof(*sync)); + + sync = (struct bss_info_sync_mode *)tlv; + sync->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); + sync->dtim_period = vif->bss_conf.dtim_period; + sync->enable = true; +} + +int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, + struct ieee80211_vif *vif, int enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct sk_buff *skb; + + skb = mt7915_mcu_alloc_sta_req(phy->dev, mvif, NULL, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + /* bss_omac must be first */ + if (enable) + mt7915_mcu_bss_omac_tlv(skb, vif); + + mt7915_mcu_bss_basic_tlv(skb, vif, phy, enable); + + if (enable) { + mt7915_mcu_bss_rfch_tlv(skb, vif, phy); + mt7915_mcu_bss_bmc_tlv(skb, phy); + mt7915_mcu_bss_ra_tlv(skb, vif, phy); + + if (mvif->omac_idx > HW_BSSID_MAX) + mt7915_mcu_bss_ext_tlv(skb, mvif); + else + mt7915_mcu_bss_sync_tlv(skb, vif); + } + + return __mt76_mcu_skb_send_msg(&phy->dev->mt76, skb, + MCU_EXT_CMD_BSS_INFO_UPDATE, true); +} + +/** starec & wtbl **/ +static int +mt7915_mcu_sta_key_tlv(struct sk_buff *skb, struct ieee80211_key_conf *key, + enum set_key_cmd cmd) +{ + struct sta_rec_sec *sec; + struct tlv *tlv; + u32 len = sizeof(*sec); + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); + + sec = (struct sta_rec_sec *)tlv; + sec->add = cmd; + + if (cmd == SET_KEY) { + struct sec_key *sec_key; + u8 cipher; + + cipher = mt7915_mcu_get_cipher(key->cipher); + if (cipher == MT_CIPHER_NONE) + return -EOPNOTSUPP; + + sec_key = &sec->key[0]; + sec_key->cipher_len = sizeof(*sec_key); + sec_key->key_id = key->keyidx; + + if (cipher == MT_CIPHER_BIP_CMAC_128) { + sec_key->cipher_id = MT_CIPHER_AES_CCMP; + sec_key->key_len = 16; + memcpy(sec_key->key, key->key, 16); + + sec_key = &sec->key[1]; + sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; + sec_key->cipher_len = sizeof(*sec_key); + sec_key->key_len = 16; + memcpy(sec_key->key, key->key + 16, 16); + + sec->n_cipher = 2; + } else { + sec_key->cipher_id = cipher; + sec_key->key_len = key->keylen; + memcpy(sec_key->key, key->key, key->keylen); + + if (cipher == MT_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(sec_key->key + 16, key->key + 24, 8); + memcpy(sec_key->key + 24, key->key + 16, 8); + } + + len -= sizeof(*sec_key); + sec->n_cipher = 1; + } + } else { + len -= sizeof(sec->key); + sec->n_cipher = 0; + } + sec->len = cpu_to_le16(len); + + return 0; +} + +int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct mt7915_sta *msta, struct ieee80211_key_conf *key, + enum set_key_cmd cmd) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct sk_buff *skb; + int ret; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = mt7915_mcu_sta_key_tlv(skb, key, cmd); + if (ret) + return ret; + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + +static void +mt7915_mcu_sta_ba_tlv(struct sk_buff *skb, + struct ieee80211_ampdu_params *params, + bool enable, bool tx) +{ + struct sta_rec_ba *ba; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); + + ba = (struct sta_rec_ba *)tlv; + ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT, + ba->winsize = cpu_to_le16(params->buf_size); + ba->ssn = cpu_to_le16(params->ssn); + ba->ba_en = enable << params->tid; + ba->amsdu = params->amsdu; + ba->tid = params->tid; +} + +static void +mt7915_mcu_wtbl_ba_tlv(struct sk_buff *skb, + struct ieee80211_ampdu_params *params, + bool enable, bool tx, void *sta_wtbl, + void *wtbl_tlv) +{ + struct wtbl_ba *ba; + struct tlv *tlv; + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba), + wtbl_tlv, sta_wtbl); + + ba = (struct wtbl_ba *)tlv; + ba->tid = params->tid; + + if (tx) { + ba->ba_type = MT_BA_TYPE_ORIGINATOR; + ba->sn = enable ? cpu_to_le16(params->ssn) : 0; + ba->ba_en = enable; + } else { + memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN); + ba->ba_type = MT_BA_TYPE_RECIPIENT; + ba->rst_ba_tid = params->tid; + ba->rst_ba_sel = RST_BA_MAC_TID_MATCH; + ba->rst_ba_sb = 1; + } + + if (enable && tx) + ba->ba_winsize = cpu_to_le16(params->buf_size); +} + +static int +mt7915_mcu_sta_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable, bool tx) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv; + struct mt7915_vif *mvif = msta->vif; + struct wtbl_req_hdr *wtbl_hdr; + struct tlv *sta_wtbl; + struct sk_buff *skb; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_ba_tlv(skb, params, enable, tx); + sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + + wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, + &skb); + mt7915_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + +int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable) +{ + return mt7915_mcu_sta_ba(dev, params, enable, true); +} + +int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable) +{ + return mt7915_mcu_sta_ba(dev, params, enable, false); +} + +static void +mt7915_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *sta_wtbl, + void *wtbl_tlv) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct wtbl_generic *generic; + struct wtbl_rx *rx; + struct tlv *tlv; + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic), + wtbl_tlv, sta_wtbl); + + generic = (struct wtbl_generic *)tlv; + + if (sta) { + memcpy(generic->peer_addr, sta->addr, ETH_ALEN); + generic->partial_aid = cpu_to_le16(sta->aid); + generic->muar_idx = mvif->omac_idx; + generic->qos = sta->wme; + } else { + /* use BSSID in station mode */ + if (vif->type == NL80211_IFTYPE_STATION) + memcpy(generic->peer_addr, vif->bss_conf.bssid, + ETH_ALEN); + else + eth_broadcast_addr(generic->peer_addr); + + generic->muar_idx = 0xe; + } + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx), + wtbl_tlv, sta_wtbl); + + rx = (struct wtbl_rx *)tlv; + rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1; + rx->rca2 = 1; + rx->rv = 1; +} + +static void +mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) +{ +#define EXTRA_INFO_VER BIT(0) +#define EXTRA_INFO_NEW BIT(1) + struct sta_rec_basic *basic; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic)); + + basic = (struct sta_rec_basic *)tlv; + basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); + + if (enable) { + basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); + basic->conn_state = CONN_STATE_PORT_SECURE; + } else { + basic->conn_state = CONN_STATE_DISCONNECT; + } + + if (!sta) { + basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); + eth_broadcast_addr(basic->peer_addr); + return; + } + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + basic->conn_type = cpu_to_le32(CONNECTION_INFRA_STA); + break; + case NL80211_IFTYPE_STATION: + basic->conn_type = cpu_to_le32(CONNECTION_INFRA_AP); + break; + case NL80211_IFTYPE_ADHOC: + basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + break; + default: + WARN_ON(1); + break; + } + + memcpy(basic->peer_addr, sta->addr, ETH_ALEN); + basic->aid = cpu_to_le16(sta->aid); + basic->qos = sta->wme; +} + +static void +mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + struct ieee80211_sta *sta) +{ + struct tlv *tlv; + + if (sta->ht_cap.ht_supported) { + struct sta_rec_ht *ht; + + /* starec ht */ + tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); + ht = (struct sta_rec_ht *)tlv; + ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); + } + + /* starec vht */ + if (sta->vht_cap.vht_supported) { + struct sta_rec_vht *vht; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); + vht = (struct sta_rec_vht *)tlv; + vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); + vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; + vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; + } +} + +static void +mt7915_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + void *sta_wtbl, void *wtbl_tlv) +{ + struct wtbl_smps *smps; + struct tlv *tlv; + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps), + wtbl_tlv, sta_wtbl); + smps = (struct wtbl_smps *)tlv; + + if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) + smps->smps = true; +} + +static void +mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + void *sta_wtbl, void *wtbl_tlv) +{ + struct wtbl_ht *ht = NULL; + struct tlv *tlv; + + /* wtbl ht */ + if (sta->ht_cap.ht_supported) { + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), + wtbl_tlv, sta_wtbl); + ht = (struct wtbl_ht *)tlv; + ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING; + ht->af = sta->ht_cap.ampdu_factor; + ht->mm = sta->ht_cap.ampdu_density; + ht->ht = true; + } + + /* wtbl vht */ + if (sta->vht_cap.vht_supported) { + struct wtbl_vht *vht; + u8 af; + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht), + wtbl_tlv, sta_wtbl); + vht = (struct wtbl_vht *)tlv; + vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC, + vht->vht = true; + + af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, + sta->vht_cap.cap); + if (ht) + ht->af = max_t(u8, ht->af, af); + } + + mt7915_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_tlv); +} + +int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct wtbl_req_hdr *wtbl_hdr; + struct tlv *sta_wtbl; + struct sk_buff *skb; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + + wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, + &skb); + mt7915_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr); + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + +static void +mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct cfg80211_chan_def *chandef = &dev->mphy.chandef; + struct sta_rec_ra *ra; + struct tlv *tlv; + enum nl80211_band band = chandef->chan->band; + u32 supp_rate = sta->supp_rates[band]; + int n_rates = hweight32(supp_rate); + u32 cap = sta->wme ? STA_CAP_WMM : 0; + u8 i, nss = sta->rx_nss, mcs = 0; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); + + ra = (struct sta_rec_ra *)tlv; + ra->valid = true; + ra->auto_rate = true; + ra->phy_mode = mt7915_get_phy_mode(dev, vif, band, sta); + ra->channel = chandef->chan->hw_value; + ra->bw = sta->bandwidth; + ra->rate_len = n_rates; + ra->phy.bw = sta->bandwidth; + + if (n_rates) { + if (band == NL80211_BAND_2GHZ) { + ra->supp_mode = MODE_CCK; + ra->supp_cck_rate = supp_rate & GENMASK(3, 0); + ra->phy.type = MT_PHY_TYPE_CCK; + + if (n_rates > 4) { + ra->supp_mode |= MODE_OFDM; + ra->supp_ofdm_rate = supp_rate >> 4; + ra->phy.type = MT_PHY_TYPE_OFDM; + } + } else { + ra->supp_mode = MODE_OFDM; + ra->supp_ofdm_rate = supp_rate; + ra->phy.type = MT_PHY_TYPE_OFDM; + } + } + + if (sta->ht_cap.ht_supported) { + for (i = 0; i < nss; i++) + ra->ht_mcs[i] = sta->ht_cap.mcs.rx_mask[i]; + + ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; + ra->supp_mode |= MODE_HT; + mcs = hweight32(ra->supp_ht_mcs) - 1; + ra->af = sta->ht_cap.ampdu_factor; + ra->ht_gf = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); + + cap |= STA_CAP_HT; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) + cap |= STA_CAP_SGI_20; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) + cap |= STA_CAP_SGI_40; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC) + cap |= STA_CAP_TX_STBC; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) + cap |= STA_CAP_RX_STBC; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) + cap |= STA_CAP_LDPC; + } + + if (sta->vht_cap.vht_supported) { + __le16 mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; + u16 vht_mcs; + u8 af, mcs_prev; + + af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, + sta->vht_cap.cap); + ra->af = max_t(u8, ra->af, af); + + cap |= STA_CAP_VHT; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) + cap |= STA_CAP_VHT_SGI_80; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) + cap |= STA_CAP_VHT_SGI_160; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC) + cap |= STA_CAP_VHT_TX_STBC; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) + cap |= STA_CAP_VHT_RX_STBC; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) + cap |= STA_CAP_VHT_LDPC; + + ra->supp_mode |= MODE_VHT; + for (mcs = 0, i = 0; i < nss; i++, mcs_map >>= 2) { + switch (mcs_map & 0x3) { + case IEEE80211_VHT_MCS_SUPPORT_0_9: + vht_mcs = GENMASK(9, 0); + break; + case IEEE80211_VHT_MCS_SUPPORT_0_8: + vht_mcs = GENMASK(8, 0); + break; + case IEEE80211_VHT_MCS_SUPPORT_0_7: + vht_mcs = GENMASK(7, 0); + break; + default: + vht_mcs = 0; + } + + ra->supp_vht_mcs[i] = cpu_to_le16(vht_mcs); + + mcs_prev = hweight16(vht_mcs) - 1; + if (mcs_prev > mcs) + mcs = mcs_prev; + + /* only support 2ss on 160MHz */ + if (i > 1 && (ra->bw == CMD_CBW_160MHZ || + ra->bw == CMD_CBW_8080MHZ)) + break; + } + } + + ra->sta_status = cpu_to_le32(cap); + + switch (BIT(fls(ra->supp_mode) - 1)) { + case MODE_VHT: + ra->phy.type = MT_PHY_TYPE_VHT; + ra->phy.mcs = mcs; + ra->phy.nss = nss; + ra->phy.stbc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC); + ra->phy.ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); + ra->phy.sgi = + !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); + break; + case MODE_HT: + ra->phy.type = MT_PHY_TYPE_HT; + ra->phy.mcs = mcs; + ra->phy.ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING; + ra->phy.stbc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC); + ra->phy.sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); + break; + default: + break; + } +} + +int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct sk_buff *skb; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta); + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + +int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct wtbl_req_hdr *wtbl_hdr; + struct mt7915_sta *msta; + struct tlv *sta_wtbl; + struct sk_buff *skb; + int ret; + + msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_basic_tlv(skb, vif, sta, enable); + if (enable && sta) + mt7915_mcu_sta_tlv(dev, skb, sta); + + sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + + wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, + sta_wtbl, &skb); + if (enable) { + mt7915_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); + if (sta) + mt7915_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr); + } + + ret = __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); + if (ret) + return ret; + + if (enable && sta) + return mt7915_mcu_add_rate_ctrl(dev, vif, sta); + + return 0; +} + +int mt7915_mcu_add_dev_info(struct mt7915_dev *dev, + struct ieee80211_vif *vif, bool enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct { + struct req_hdr { + u8 omac_idx; + u8 dbdc_idx; + __le16 tlv_num; + u8 is_tlv_append; + u8 rsv[3]; + } __packed hdr; + struct req_tlv { + __le16 tag; + __le16 len; + u8 active; + u8 dbdc_idx; + u8 omac_addr[ETH_ALEN]; + } __packed tlv; + } data = { + .hdr = { + .omac_idx = mvif->omac_idx, + .dbdc_idx = mvif->band_idx, + .tlv_num = cpu_to_le16(1), + .is_tlv_append = 1, + }, + .tlv = { + .tag = cpu_to_le16(DEV_INFO_ACTIVE), + .len = cpu_to_le16(sizeof(struct req_tlv)), + .active = enable, + .dbdc_idx = mvif->band_idx, + }, + }; + + memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE, + &data, sizeof(data), true); +} + +static void +mt7915_mcu_beacon_csa(struct sk_buff *rskb, struct sk_buff *skb, + struct bss_info_bcn *bcn, + struct ieee80211_mutable_offsets *offs) +{ + if (offs->csa_counter_offs[0]) { + struct tlv *tlv; + struct bss_info_bcn_csa *csa; + + tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CSA, + sizeof(*csa), &bcn->sub_ntlv, + &bcn->len); + csa = (struct bss_info_bcn_csa *)tlv; + csa->cnt = skb->data[offs->csa_counter_offs[0]]; + } +} + +static void +mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb, + struct sk_buff *skb, struct bss_info_bcn *bcn, + struct ieee80211_mutable_offsets *offs) +{ + struct mt76_wcid *wcid = &dev->mt76.global_wcid; + struct bss_info_bcn_cont *cont; + struct tlv *tlv; + u8 *buf; + int len = sizeof(*cont) + MT_TXD_SIZE + skb->len; + + tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT, + len, &bcn->sub_ntlv, &bcn->len); + + cont = (struct bss_info_bcn_cont *)tlv; + cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); + cont->tim_ofs = cpu_to_le16(offs->tim_offset); + + if (offs->csa_counter_offs[0]) + cont->csa_ofs = cpu_to_le16(offs->csa_counter_offs[0] - 4); + + buf = (u8 *)tlv + sizeof(*cont); + mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, + true); + memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); +} + +int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int en) +{ +#define MAX_BEACON_SIZE 512 + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct ieee80211_mutable_offsets offs; + struct ieee80211_tx_info *info; + struct sk_buff *skb, *rskb; + struct tlv *tlv; + struct bss_info_bcn *bcn; + int len = MT7915_BEACON_UPDATE_SIZE + MAX_BEACON_SIZE; + + rskb = mt7915_mcu_alloc_sta_req(dev, mvif, NULL, len); + if (IS_ERR(rskb)) + return PTR_ERR(rskb); + + tlv = mt7915_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn)); + bcn = (struct bss_info_bcn *)tlv; + bcn->enable = en; + + skb = ieee80211_beacon_get_template(hw, vif, &offs); + if (!skb) + return -EINVAL; + + if (skb->len > MAX_BEACON_SIZE - MT_TXD_SIZE) { + dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); + dev_kfree_skb(skb); + return -EINVAL; + } + + if (mvif->band_idx) { + info = IEEE80211_SKB_CB(skb); + info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; + } + + /* TODO: subtag - bss color count & 11v MBSSID */ + mt7915_mcu_beacon_csa(rskb, skb, bcn, &offs); + mt7915_mcu_beacon_cont(dev, rskb, skb, bcn, &offs); + dev_kfree_skb(skb); + + return __mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, + MCU_EXT_CMD_BSS_INFO_UPDATE, true); +} + +static int mt7915_mcu_send_firmware(struct mt7915_dev *dev, const void *data, + int len) +{ + int ret = 0, cur_len; + + while (len > 0) { + cur_len = min_t(int, 4096 - sizeof(struct mt7915_mcu_txd), + len); + + ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER, + data, cur_len, false); + if (ret) + break; + + data += cur_len; + len -= cur_len; + mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); + } + + return ret; +} + +static int mt7915_mcu_start_firmware(struct mt7915_dev *dev, u32 addr, + u32 option) +{ + struct { + __le32 option; + __le32 addr; + } req = { + .option = cpu_to_le32(option), + .addr = cpu_to_le32(addr), + }; + + return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, + &req, sizeof(req), true); +} + +static int mt7915_mcu_restart(struct mt76_dev *dev) +{ + struct { + u8 power_mode; + u8 rsv[3]; + } req = { + .power_mode = 1, + }; + + return __mt76_mcu_send_msg(dev, -MCU_CMD_NIC_POWER_CTRL, &req, + sizeof(req), false); +} + +static int mt7915_mcu_patch_sem_ctrl(struct mt7915_dev *dev, bool get) +{ + struct { + __le32 op; + } req = { + .op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE), + }; + + return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_SEM_CONTROL, + &req, sizeof(req), true); +} + +static int mt7915_mcu_start_patch(struct mt7915_dev *dev) +{ + struct { + u8 check_crc; + u8 reserved[3]; + } req = { + .check_crc = 0, + }; + + return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_FINISH_REQ, + &req, sizeof(req), true); +} + +static int mt7915_driver_own(struct mt7915_dev *dev) +{ + u32 reg = mt7915_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); + + mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); + if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, + 0, 500)) { + dev_err(dev->mt76.dev, "Timeout for driver own\n"); + return -EIO; + } + + return 0; +} + +static int mt7915_mcu_init_download(struct mt7915_dev *dev, u32 addr, + u32 len, u32 mode) +{ + struct { + __le32 addr; + __le32 len; + __le32 mode; + } req = { + .addr = cpu_to_le32(addr), + .len = cpu_to_le32(len), + .mode = cpu_to_le32(mode), + }; + int attr; + + if (req.addr == MCU_PATCH_ADDRESS) + attr = -MCU_CMD_PATCH_START_REQ; + else + attr = -MCU_CMD_TARGET_ADDRESS_LEN_REQ; + + return __mt76_mcu_send_msg(&dev->mt76, attr, &req, sizeof(req), true); +} + +static int mt7915_load_patch(struct mt7915_dev *dev) +{ + const struct mt7915_patch_hdr *hdr; + const struct firmware *fw = NULL; + int i, ret, sem; + + sem = mt7915_mcu_patch_sem_ctrl(dev, 1); + switch (sem) { + case PATCH_IS_DL: + return 0; + case PATCH_NOT_DL_SEM_SUCCESS: + break; + default: + dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); + return -EAGAIN; + } + + ret = request_firmware(&fw, MT7915_ROM_PATCH, dev->mt76.dev); + if (ret) + goto out; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const struct mt7915_patch_hdr *)(fw->data); + + dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", + be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); + + for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { + struct mt7915_patch_sec *sec; + const u8 *dl; + u32 len, addr; + + sec = (struct mt7915_patch_sec *)(fw->data + sizeof(*hdr) + + i * sizeof(*sec)); + if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != + PATCH_SEC_TYPE_INFO) { + ret = -EINVAL; + goto out; + } + + addr = be32_to_cpu(sec->info.addr); + len = be32_to_cpu(sec->info.len); + dl = fw->data + be32_to_cpu(sec->offs); + + ret = mt7915_mcu_init_download(dev, addr, len, + DL_MODE_NEED_RSP); + if (ret) { + dev_err(dev->mt76.dev, "Download request failed\n"); + goto out; + } + + ret = mt7915_mcu_send_firmware(dev, dl, len); + if (ret) { + dev_err(dev->mt76.dev, "Failed to send patch\n"); + goto out; + } + } + + ret = mt7915_mcu_start_patch(dev); + if (ret) + dev_err(dev->mt76.dev, "Failed to start patch\n"); + +out: + sem = mt7915_mcu_patch_sem_ctrl(dev, 0); + switch (sem) { + case PATCH_REL_SEM_SUCCESS: + break; + default: + ret = -EAGAIN; + dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); + goto out; + } + release_firmware(fw); + + return ret; +} + +static u32 mt7915_mcu_gen_dl_mode(u8 feature_set, bool is_wa) +{ + u32 ret = 0; + + ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? + (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; + ret |= FIELD_PREP(DL_MODE_KEY_IDX, + FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); + ret |= DL_MODE_NEED_RSP; + ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; + + return ret; +} + +static int +mt7915_mcu_send_ram_firmware(struct mt7915_dev *dev, + const struct mt7915_fw_trailer *hdr, + const u8 *data, bool is_wa) +{ + int i, offset = 0; + u32 override = 0, option = 0; + + for (i = 0; i < hdr->n_region; i++) { + const struct mt7915_fw_region *region; + int err; + u32 len, addr, mode; + + region = (const struct mt7915_fw_region *)((const u8 *)hdr - + (hdr->n_region - i) * sizeof(*region)); + mode = mt7915_mcu_gen_dl_mode(region->feature_set, is_wa); + len = le32_to_cpu(region->len); + addr = le32_to_cpu(region->addr); + + if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) + override = addr; + + err = mt7915_mcu_init_download(dev, addr, len, mode); + if (err) { + dev_err(dev->mt76.dev, "Download request failed\n"); + return err; + } + + err = mt7915_mcu_send_firmware(dev, data + offset, len); + if (err) { + dev_err(dev->mt76.dev, "Failed to send firmware.\n"); + return err; + } + + offset += len; + } + + if (override) + option |= FW_START_OVERRIDE; + + if (is_wa) + option |= FW_START_WORKING_PDA_CR4; + + return mt7915_mcu_start_firmware(dev, override, option); +} + +static int mt7915_load_ram(struct mt7915_dev *dev) +{ + const struct mt7915_fw_trailer *hdr; + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, MT7915_FIRMWARE_WM, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const struct mt7915_fw_trailer *)(fw->data + fw->size - + sizeof(*hdr)); + + dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", + hdr->fw_ver, hdr->build_date); + + ret = mt7915_mcu_send_ram_firmware(dev, hdr, fw->data, false); + if (ret) { + dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); + goto out; + } + + release_firmware(fw); + + ret = request_firmware(&fw, MT7915_FIRMWARE_WA, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const struct mt7915_fw_trailer *)(fw->data + fw->size - + sizeof(*hdr)); + + dev_info(dev->mt76.dev, "WA Firmware Version: %.10s, Build Time: %.15s\n", + hdr->fw_ver, hdr->build_date); + + ret = mt7915_mcu_send_ram_firmware(dev, hdr, fw->data, true); + if (ret) { + dev_err(dev->mt76.dev, "Failed to start WA firmware\n"); + goto out; + } + + snprintf(dev->mt76.hw->wiphy->fw_version, + sizeof(dev->mt76.hw->wiphy->fw_version), + "%.10s-%.15s", hdr->fw_ver, hdr->build_date); + +out: + release_firmware(fw); + + return ret; +} + +static int mt7915_load_firmware(struct mt7915_dev *dev) +{ + int ret; + u32 val, reg = mt7915_reg_map_l1(dev, MT_TOP_MISC); + + val = FIELD_PREP(MT_TOP_MISC_FW_STATE, FW_STATE_FW_DOWNLOAD); + + if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, val, 1000)) { + /* restart firmware once */ + __mt76_mcu_restart(&dev->mt76); + if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, + val, 1000)) { + dev_err(dev->mt76.dev, + "Firmware is not ready for download\n"); + return -EIO; + } + } + + ret = mt7915_load_patch(dev); + if (ret) + return ret; + + ret = mt7915_load_ram(dev); + if (ret) + return ret; + + if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, + FIELD_PREP(MT_TOP_MISC_FW_STATE, + FW_STATE_WACPU_RDY), 1000)) { + dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); + return -EIO; + } + + mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); + + dev_dbg(dev->mt76.dev, "Firmware init done\n"); + + return 0; +} + +int mt7915_mcu_init(struct mt7915_dev *dev) +{ + static const struct mt76_mcu_ops mt7915_mcu_ops = { + .headroom = sizeof(struct mt7915_mcu_txd), + .mcu_skb_send_msg = mt7915_mcu_send_message, + .mcu_send_msg = mt7915_mcu_msg_send, + .mcu_restart = mt7915_mcu_restart, + }; + int ret; + + dev->mt76.mcu_ops = &mt7915_mcu_ops, + + ret = mt7915_driver_own(dev); + if (ret) + return ret; + + ret = mt7915_load_firmware(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + + return 0; +} + +void mt7915_mcu_exit(struct mt7915_dev *dev) +{ + u32 reg = mt7915_reg_map_l1(dev, MT_TOP_MISC); + + __mt76_mcu_restart(&dev->mt76); + if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, + FIELD_PREP(MT_TOP_MISC_FW_STATE, + FW_STATE_FW_DOWNLOAD), 1000)) { + dev_err(dev->mt76.dev, "Failed to exit mcu\n"); + return; + } + + reg = mt7915_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); + mt76_wr(dev, reg, MT_TOP_LPCR_HOST_FW_OWN); + skb_queue_purge(&dev->mt76.mcu.res_q); +} + +int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, + bool enable, bool hdr_trans) +{ + struct { + u8 operation; + u8 enable; + u8 check_bssid; + u8 insert_vlan; + u8 remove_vlan; + u8 tid; + u8 mode; + u8 rsv; + } __packed req_trans = { + .enable = hdr_trans, + }; + struct { + u8 enable; + u8 band; + u8 rsv[2]; + } __packed req_mac = { + .enable = enable, + .band = band, + }; + int ret; + + ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RX_HDR_TRANS, + &req_trans, sizeof(req_trans), false); + if (ret) + return ret; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL, + &req_mac, sizeof(req_mac), true); +} + +int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable) +{ + struct { + __le32 cmd; + u8 band; + u8 enable; + } __packed req = { + .cmd = cpu_to_le32(SCS_ENABLE), + .band = band, + .enable = enable + 1, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SCS_CTRL, &req, + sizeof(req), false); +} + +int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val) +{ + struct mt7915_dev *dev = phy->dev; + struct { + u8 prot_idx; + u8 band; + u8 rsv[2]; + __le32 len_thresh; + __le32 pkt_thresh; + } __packed req = { + .prot_idx = 1, + .band = phy != &dev->phy, + .len_thresh = cpu_to_le32(val), + .pkt_thresh = cpu_to_le32(0x2), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) +{ +#define WMM_AIFS_SET BIT(0) +#define WMM_CW_MIN_SET BIT(1) +#define WMM_CW_MAX_SET BIT(2) +#define WMM_TXOP_SET BIT(3) +#define WMM_PARAM_SET GENMASK(3, 0) +#define TX_CMD_MODE 1 + struct edca { + u8 queue; + u8 set; + u8 aifs; + u8 cw_min; + __le16 cw_max; + __le16 txop; + }; + struct mt7915_mcu_tx { + u8 total; + u8 action; + u8 valid; + u8 mode; + + struct edca edca[IEEE80211_NUM_ACS]; + } __packed req = { + .valid = true, + .mode = TX_CMD_MODE, + .total = IEEE80211_NUM_ACS, + }; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + int ac; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + struct edca *e = &req.edca[ac]; + + e->queue = ac + mvif->wmm_idx * MT7915_MAX_WMM_SETS; + e->aifs = mvif->wmm[ac].aifs; + e->txop = cpu_to_le16(mvif->wmm[ac].txop); + + if (mvif->wmm[ac].cw_min) + e->cw_min = fls(mvif->wmm[ac].cw_max); + else + e->cw_min = 5; + + if (mvif->wmm[ac].cw_max) + e->cw_max = cpu_to_le16(fls(mvif->wmm[ac].cw_max)); + else + e->cw_max = cpu_to_le16(10); + } + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter) +{ +#define ENTER_PM_STATE 1 +#define EXIT_PM_STATE 2 + struct { + u8 pm_number; + u8 pm_state; + u8 bssid[ETH_ALEN]; + u8 dtim_period; + u8 wlan_idx_lo; + __le16 bcn_interval; + __le32 aid; + __le32 rx_filter; + u8 band_idx; + u8 wlan_idx_hi; + u8 rsv[2]; + __le32 feature; + u8 omac_idx; + u8 wmm_idx; + u8 bcn_loss_cnt; + u8 bcn_sp_duration; + } __packed req = { + .pm_number = 5, + .pm_state = (enter) ? ENTER_PM_STATE : EXIT_PM_STATE, + .band_idx = band, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL, + &req, sizeof(req), true); +} + +int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, + enum mt7915_rdd_cmd cmd, u8 index, + u8 rx_sel, u8 val) +{ + struct { + u8 ctrl; + u8 rdd_idx; + u8 rdd_rx_sel; + u8 val; + u8 rsv[4]; + } __packed req = { + .ctrl = cmd, + .rdd_idx = index, + .rdd_rx_sel = rx_sel, + .val = val, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val) +{ + struct { + u32 tag; + u16 min_lpn; + u8 rsv[2]; + } __packed req = { + .tag = 0x1, + .min_lpn = val, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, + const struct mt7915_dfs_pulse *pulse) +{ + struct { + u32 tag; + struct mt7915_dfs_pulse pulse; + } __packed req = { + .tag = 0x3, + }; + + memcpy(&req.pulse, pulse, sizeof(*pulse)); + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, + const struct mt7915_dfs_pattern *pattern) +{ + struct { + u32 tag; + u16 radar_type; + struct mt7915_dfs_pattern pattern; + } __packed req = { + .tag = 0x2, + .radar_type = index, + }; + + memcpy(&req.pattern, pattern, sizeof(*pattern)); + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) +{ + struct mt7915_dev *dev = phy->dev; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + int freq1 = chandef->center_freq1; + struct { + u8 control_ch; + u8 center_ch; + u8 bw; + u8 tx_streams_num; + u8 rx_streams; /* mask or num */ + u8 switch_reason; + u8 band_idx; + u8 center_ch2; /* for 80+80 only */ + __le16 cac_case; + u8 channel_band; + u8 rsv0; + __le32 outband_freq; + u8 txpower_drop; + u8 ap_bw; + u8 ap_center_ch; + u8 rsv1[57]; + } __packed req = { + .control_ch = chandef->chan->hw_value, + .center_ch = ieee80211_frequency_to_channel(freq1), + .bw = mt7915_mcu_chan_bw(chandef), + .tx_streams_num = hweight8(phy->mt76->antenna_mask), + .rx_streams = phy->chainmask, + .band_idx = phy != &dev->phy, + .channel_band = chandef->chan->band, + }; + + if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && + chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) + req.switch_reason = CH_SWITCH_DFS; + else + req.switch_reason = CH_SWITCH_NORMAL; + + if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) + req.rx_streams = hweight8(req.rx_streams); + + if (chandef->width == NL80211_CHAN_WIDTH_80P80) { + int freq2 = chandef->center_freq2; + + req.center_ch2 = ieee80211_frequency_to_channel(freq2); + } + + return __mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); +} + +int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) +{ + struct req_hdr { + u8 buffer_mode; + u8 format; + __le16 len; + } __packed req = { + .buffer_mode = EE_MODE_EFUSE, + .format = EE_FORMAT_WHOLE, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, + &req, sizeof(req), true); +} + +int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) +{ + struct mt7915_mcu_eeprom_info req = { + .addr = cpu_to_le32(round_down(offset, 16)), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req, + sizeof(req), true); +} + +int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index) +{ + struct { + u8 ctrl_id; + u8 action; + u8 band; + u8 rsv[5]; + } req = { + .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, + .action = index, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_THERMAL_CTRL, &req, + sizeof(req), true); +} + +int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) +{ + struct { + __le32 cmd; + __le16 wlan_idx; + __le16 ru_idx; + __le16 direction; + __le16 dump_group; + } req = { + .cmd = cpu_to_le32(cmd), + .wlan_idx = cpu_to_le16(wlan_idx), + .dump_group = cpu_to_le16(1), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RATE_CTRL, &req, + sizeof(req), false); +} + +int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) +{ + struct { + u8 action; + u8 set; + u8 band; + u8 rsv; + } req = { + .action = action, + .set = set, + .band = band, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SER_TRIGGER, + &req, sizeof(req), false); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h new file mode 100644 index 000000000000..5e4708861ede --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -0,0 +1,837 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_MCU_H +#define __MT7915_MCU_H + +struct mt7915_mcu_txd { + __le32 txd[8]; + + __le16 len; + __le16 pq_id; + + u8 cid; + u8 pkt_type; + u8 set_query; /* FW don't care */ + u8 seq; + + u8 uc_d2b0_rev; + u8 ext_cid; + u8 s2d_index; + u8 ext_cid_ack; + + u32 reserved[5]; +} __packed __aligned(4); + +/* event table */ +enum { + MCU_EVENT_TARGET_ADDRESS_LEN = 0x01, + MCU_EVENT_FW_START = 0x01, + MCU_EVENT_GENERIC = 0x01, + MCU_EVENT_ACCESS_REG = 0x02, + MCU_EVENT_MT_PATCH_SEM = 0x04, + MCU_EVENT_CH_PRIVILEGE = 0x18, + MCU_EVENT_EXT = 0xed, + MCU_EVENT_RESTART_DL = 0xef, +}; + +/* ext event table */ +enum { + MCU_EXT_EVENT_PS_SYNC = 0x5, + MCU_EXT_EVENT_THERMAL_PROTECT = 0x22, + MCU_EXT_EVENT_ASSERT_DUMP = 0x23, + MCU_EXT_EVENT_RDD_REPORT = 0x3a, + MCU_EXT_EVENT_CSA_NOTIFY = 0x4f, + MCU_EXT_EVENT_RATE_REPORT = 0x87, +}; + +struct mt7915_mcu_rxd { + __le32 rxd[6]; + + __le16 len; + __le16 pkt_type_id; + + u8 eid; + u8 seq; + __le16 __rsv; + + u8 ext_eid; + u8 __rsv1[2]; + u8 s2d_index; +}; + +struct mt7915_mcu_rdd_report { + struct mt7915_mcu_rxd rxd; + + u8 idx; + u8 long_detected; + u8 constant_prf_detected; + u8 staggered_prf_detected; + u8 radar_type_idx; + u8 periodic_pulse_num; + u8 long_pulse_num; + u8 hw_pulse_num; + + u8 out_lpn; + u8 out_spn; + u8 out_crpn; + u8 out_crpw; + u8 out_crbn; + u8 out_stgpn; + u8 out_stgpw; + + u8 rsv; + + __le32 out_pri_const; + __le32 out_pri_stg[3]; + + struct { + __le32 start; + __le16 pulse_width; + __le16 pulse_power; + u8 mdrdy_flag; + u8 rsv[3]; + } long_pulse[32]; + + struct { + __le32 start; + __le16 pulse_width; + __le16 pulse_power; + u8 mdrdy_flag; + u8 rsv[3]; + } periodic_pulse[32]; + + struct { + __le32 start; + __le16 pulse_width; + __le16 pulse_power; + u8 sc_pass; + u8 sw_reset; + u8 mdrdy_flag; + u8 tx_active; + } hw_pulse[32]; +} __packed; + +struct mt7915_mcu_eeprom_info { + __le32 addr; + __le32 valid; + u8 data[16]; +} __packed; + +struct mt7915_mcu_ra_info { + struct mt7915_mcu_rxd rxd; + + __le32 event_id; + __le16 wlan_idx; + __le16 ru_idx; + __le16 direction; + __le16 dump_group; + + __le32 suggest_rate; + __le32 min_rate; /* for dynamic sounding */ + __le32 max_rate; /* for dynamic sounding */ + __le32 init_rate_down_rate; + + __le16 curr_rate; + __le16 init_rate_down_total; + __le16 init_rate_down_succ; + __le16 success; + __le16 attempts; + + __le16 prev_rate; + __le16 prob_up_rate; + u8 no_rate_up_cnt; + u8 ppdu_cnt; + u8 gi; + + u8 try_up_fail; + u8 try_up_total; + u8 suggest_wf; + u8 try_up_check; + u8 prob_up_period; + u8 prob_down_pending; +} __packed; + +#define MT_RA_RATE_NSS GENMASK(8, 6) +#define MT_RA_RATE_MCS GENMASK(3, 0) +#define MT_RA_RATE_TX_MODE GENMASK(12, 9) +#define MT_RA_RATE_DCM_EN BIT(4) +#define MT_RA_RATE_BW GENMASK(14, 13) + +#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) +#define MCU_PKT_ID 0xa0 + +enum { + MCU_Q_QUERY, + MCU_Q_SET, + MCU_Q_RESERVED, + MCU_Q_NA +}; + +enum { + MCU_S2D_H2N, + MCU_S2D_C2N, + MCU_S2D_H2C, + MCU_S2D_H2CN +}; + +enum { + MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01, + MCU_CMD_FW_START_REQ = 0x02, + MCU_CMD_INIT_ACCESS_REG = 0x3, + MCU_CMD_NIC_POWER_CTRL = 0x4, + MCU_CMD_PATCH_START_REQ = 0x05, + MCU_CMD_PATCH_FINISH_REQ = 0x07, + MCU_CMD_PATCH_SEM_CONTROL = 0x10, + MCU_CMD_EXT_CID = 0xED, + MCU_CMD_FW_SCATTER = 0xEE, + MCU_CMD_RESTART_DL_REQ = 0xEF, +}; + +enum { + MCU_EXT_CMD_EFUSE_ACCESS = 0x01, + MCU_EXT_CMD_PM_STATE_CTRL = 0x07, + MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, + MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, + MCU_EXT_CMD_STA_REC_UPDATE = 0x25, + MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, + MCU_EXT_CMD_EDCA_UPDATE = 0x27, + MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A, + MCU_EXT_CMD_THERMAL_CTRL = 0x2c, + MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, + MCU_EXT_CMD_PROTECT_CTRL = 0x3e, + MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, + MCU_EXT_CMD_RX_HDR_TRANS = 0x47, + MCU_EXT_CMD_SET_RX_PATH = 0x4e, + MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, + MCU_EXT_CMD_SCS_CTRL = 0x82, + MCU_EXT_CMD_RATE_CTRL = 0x87, + MCU_EXT_CMD_SET_RDD_TH = 0x9d, +}; + +enum { + PATCH_SEM_RELEASE, + PATCH_SEM_GET +}; + +enum { + PATCH_NOT_DL_SEM_FAIL, + PATCH_IS_DL, + PATCH_NOT_DL_SEM_SUCCESS, + PATCH_REL_SEM_SUCCESS +}; + +enum { + FW_STATE_INITIAL, + FW_STATE_FW_DOWNLOAD, + FW_STATE_NORMAL_OPERATION, + FW_STATE_NORMAL_TRX, + FW_STATE_WACPU_RDY = 7 +}; + +enum { + EE_MODE_EFUSE, + EE_MODE_BUFFER, +}; + +enum { + EE_FORMAT_BIN, + EE_FORMAT_WHOLE, + EE_FORMAT_MULTIPLE, +}; + +#define STA_TYPE_STA BIT(0) +#define STA_TYPE_AP BIT(1) +#define STA_TYPE_ADHOC BIT(2) +#define STA_TYPE_WDS BIT(4) +#define STA_TYPE_BC BIT(5) + +#define NETWORK_INFRA BIT(16) +#define NETWORK_P2P BIT(17) +#define NETWORK_IBSS BIT(18) +#define NETWORK_WDS BIT(21) + +#define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA) +#define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA) +#define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P) +#define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P) +#define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS) +#define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS) +#define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA) + +#define CONN_STATE_DISCONNECT 0 +#define CONN_STATE_CONNECT 1 +#define CONN_STATE_PORT_SECURE 2 + +enum { + DEV_INFO_ACTIVE, + DEV_INFO_MAX_NUM +}; + +enum { + SCS_SEND_DATA, + SCS_SET_MANUAL_PD_TH, + SCS_CONFIG, + SCS_ENABLE, + SCS_SHOW_INFO, + SCS_GET_GLO_ADDR, + SCS_GET_GLO_ADDR_EVENT, +}; + +enum { + CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, + CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40, + CMD_CBW_80MHZ = IEEE80211_STA_RX_BW_80, + CMD_CBW_160MHZ = IEEE80211_STA_RX_BW_160, + CMD_CBW_10MHZ, + CMD_CBW_5MHZ, + CMD_CBW_8080MHZ, + + CMD_HE_MCS_BW80 = 0, + CMD_HE_MCS_BW160, + CMD_HE_MCS_BW8080, + CMD_HE_MCS_BW_NUM +}; + +struct tlv { + __le16 tag; + __le16 len; +} __packed; + +struct bss_info_omac { + __le16 tag; + __le16 len; + u8 hw_bss_idx; + u8 omac_idx; + u8 band_idx; + u8 rsv0; + __le32 conn_type; + u32 rsv1; +} __packed; + +struct bss_info_basic { + __le16 tag; + __le16 len; + __le32 network_type; + u8 active; + u8 rsv0; + __le16 bcn_interval; + u8 bssid[ETH_ALEN]; + u8 wmm_idx; + u8 dtim_period; + u8 bmc_wcid_lo; + u8 cipher; + u8 phy_mode; + u8 max_bssid; /* max BSSID. range: 1 ~ 8, 0: MBSSID disabled */ + u8 non_tx_bssid;/* non-transmitted BSSID, 0: transmitted BSSID */ + u8 bmc_wcid_hi; /* high Byte and version */ + u8 rsv[2]; +} __packed; + +struct bss_info_rf_ch { + __le16 tag; + __le16 len; + u8 pri_ch; + u8 center_ch0; + u8 center_ch1; + u8 bw; + u8 he_ru26_block; /* 1: don't send HETB in RU26, 0: allow */ + u8 he_all_disable; /* 1: disallow all HETB, 0: allow */ + u8 rsv[2]; +} __packed; + +struct bss_info_ext_bss { + __le16 tag; + __le16 len; + __le32 mbss_tsf_offset; /* in unit of us */ + u8 rsv[8]; +} __packed; + +struct bss_info_sync_mode { + __le16 tag; + __le16 len; + __le16 bcn_interval; + u8 enable; + u8 dtim_period; + u8 rsv[8]; +} __packed; + +struct bss_info_bmc_rate { + __le16 tag; + __le16 len; + __le16 bc_trans; + __le16 mc_trans; + u8 short_preamble; + u8 rsv[7]; +} __packed; + +struct bss_info_ra { + __le16 tag; + __le16 len; + u8 op_mode; + u8 adhoc_en; + u8 short_preamble; + u8 tx_streams; + u8 rx_streams; + u8 algo; + u8 force_sgi; + u8 force_gf; + u8 ht_mode; + u8 has_20_sta; /* Check if any sta support GF. */ + u8 bss_width_trigger_events; + u8 vht_nss_cap; + u8 vht_bw_signal; /* not use */ + u8 vht_force_sgi; /* not use */ + u8 se_off; + u8 antenna_idx; + u8 train_up_rule; + u8 rsv[3]; + unsigned short train_up_high_thres; + short train_up_rule_rssi; + unsigned short low_traffic_thres; + __le16 max_phyrate; + __le32 phy_cap; + __le32 interval; + __le32 fast_interval; +} __packed; + +struct bss_info_bcn { + __le16 tag; + __le16 len; + u8 ver; + u8 enable; + __le16 sub_ntlv; +} __packed __aligned(4); + +struct bss_info_bcn_csa { + __le16 tag; + __le16 len; + u8 cnt; + u8 rsv[3]; +} __packed __aligned(4); + +struct bss_info_bcn_bcc { + __le16 tag; + __le16 len; + u8 cnt; + u8 rsv[3]; +} __packed __aligned(4); + +struct bss_info_bcn_mbss { +#define MAX_BEACON_NUM 32 + __le16 tag; + __le16 len; + __le32 bitmap; + __le16 offset[MAX_BEACON_NUM]; + u8 rsv[8]; +} __packed __aligned(4); + +struct bss_info_bcn_cont { + __le16 tag; + __le16 len; + __le16 tim_ofs; + __le16 csa_ofs; + __le16 bcc_ofs; + __le16 pkt_len; +} __packed __aligned(4); + +enum { + BSS_INFO_BCN_CSA, + BSS_INFO_BCN_BCC, + BSS_INFO_BCN_MBSSID, + BSS_INFO_BCN_CONTENT, + BSS_INFO_BCN_MAX +}; + +enum { + BSS_INFO_OMAC, + BSS_INFO_BASIC, + BSS_INFO_RF_CH, /* optional, for BT/LTE coex */ + BSS_INFO_PM, /* sta only */ + BSS_INFO_UAPSD, /* sta only */ + BSS_INFO_ROAM_DETECT, /* obsoleted */ + BSS_INFO_LQ_RM, /* obsoleted */ + BSS_INFO_EXT_BSS, + BSS_INFO_BMC_RATE, /* for bmc rate control in CR4 */ + BSS_INFO_SYNC_MODE, + BSS_INFO_RA, + BSS_INFO_HW_AMSDU, + BSS_INFO_BSS_COLOR, + BSS_INFO_HE_BASIC, + BSS_INFO_PROTECT_INFO, + BSS_INFO_OFFLOAD, + BSS_INFO_11V_MBSSID, + BSS_INFO_MAX_NUM +}; + +enum { + WTBL_RESET_AND_SET = 1, + WTBL_SET, + WTBL_QUERY, + WTBL_RESET_ALL +}; + +struct wtbl_req_hdr { + u8 wlan_idx_lo; + u8 operation; + __le16 tlv_num; + u8 wlan_idx_hi; + u8 rsv[3]; +} __packed; + +struct wtbl_generic { + __le16 tag; + __le16 len; + u8 peer_addr[ETH_ALEN]; + u8 muar_idx; + u8 skip_tx; + u8 cf_ack; + u8 qos; + u8 mesh; + u8 adm; + __le16 partial_aid; + u8 baf_en; + u8 aad_om; +} __packed; + +struct wtbl_rx { + __le16 tag; + __le16 len; + u8 rcid; + u8 rca1; + u8 rca2; + u8 rv; + u8 rsv[4]; +} __packed; + +struct wtbl_ht { + __le16 tag; + __le16 len; + u8 ht; + u8 ldpc; + u8 af; + u8 mm; + u8 rsv[4]; +} __packed; + +struct wtbl_vht { + __le16 tag; + __le16 len; + u8 ldpc; + u8 dyn_bw; + u8 vht; + u8 txop_ps; + u8 rsv[4]; +} __packed; + +enum { + MT_BA_TYPE_INVALID, + MT_BA_TYPE_ORIGINATOR, + MT_BA_TYPE_RECIPIENT +}; + +enum { + RST_BA_MAC_TID_MATCH, + RST_BA_MAC_MATCH, + RST_BA_NO_MATCH +}; + +struct wtbl_ba { + __le16 tag; + __le16 len; + /* common */ + u8 tid; + u8 ba_type; + u8 rsv0[2]; + /* originator only */ + __le16 sn; + u8 ba_en; + u8 ba_winsize_idx; + __le16 ba_winsize; + /* recipient only */ + u8 peer_addr[ETH_ALEN]; + u8 rst_ba_tid; + u8 rst_ba_sel; + u8 rst_ba_sb; + u8 band_idx; + u8 rsv1[4]; +} __packed; + +struct wtbl_bf { + __le16 tag; + __le16 len; + u8 ibf; + u8 ebf; + u8 ibf_vht; + u8 ebf_vht; + u8 gid; + u8 pfmu_idx; + u8 rsv[2]; +} __packed; + +struct wtbl_smps { + __le16 tag; + __le16 len; + u8 smps; + u8 rsv[3]; +} __packed; + +struct wtbl_spe { + __le16 tag; + __le16 len; + u8 spe_idx; + u8 rsv[3]; +} __packed; + +enum { + WTBL_GENERIC, + WTBL_RX, + WTBL_HT, + WTBL_VHT, + WTBL_PEER_PS, /* not used */ + WTBL_TX_PS, + WTBL_HDR_TRANS, + WTBL_SEC_KEY, + WTBL_BA, + WTBL_RDG, /* obsoleted */ + WTBL_PROTECT, /* not used */ + WTBL_CLEAR, /* not used */ + WTBL_BF, + WTBL_SMPS, + WTBL_RAW_DATA, /* debug only */ + WTBL_PN, + WTBL_SPE, + WTBL_MAX_NUM +}; + +struct sta_ntlv_hdr { + u8 rsv[2]; + __le16 tlv_num; +} __packed; + +struct sta_req_hdr { + u8 bss_idx; + u8 wlan_idx_lo; + __le16 tlv_num; + u8 is_tlv_append; + u8 muar_idx; + u8 wlan_idx_hi; + u8 rsv; +} __packed; + +struct sta_rec_basic { + __le16 tag; + __le16 len; + __le32 conn_type; + u8 conn_state; + u8 qos; + __le16 aid; + u8 peer_addr[ETH_ALEN]; + __le16 extra_info; +} __packed; + +struct sta_rec_ht { + __le16 tag; + __le16 len; + __le16 ht_cap; + u16 rsv; +} __packed; + +struct sta_rec_vht { + __le16 tag; + __le16 len; + __le32 vht_cap; + __le16 vht_rx_mcs_map; + __le16 vht_tx_mcs_map; + u8 rts_bw_sig; + u8 rsv[3]; +} __packed; + +struct sta_rec_ba { + __le16 tag; + __le16 len; + u8 tid; + u8 ba_type; + u8 amsdu; + u8 ba_en; + __le16 ssn; + __le16 winsize; +} __packed; + +struct sec_key { + u8 cipher_id; + u8 cipher_len; + u8 key_id; + u8 key_len; + u8 key[32]; +} __packed; + +struct sta_rec_sec { + __le16 tag; + __le16 len; + u8 add; + u8 n_cipher; + u8 rsv[2]; + + struct sec_key key[2]; +} __packed; + +struct ra_phy { + u8 type; + u8 flag; + u8 stbc; + u8 sgi; + u8 bw; + u8 ldpc; + u8 mcs; + u8 nss; + u8 he_ltf; +}; + +struct sta_rec_ra { + __le16 tag; + __le16 len; + + u8 valid; + u8 auto_rate; + u8 phy_mode; + u8 channel; + u8 bw; + u8 disable_cck; + u8 ht_mcs32; + u8 ht_gf; + u8 ht_mcs[4]; + u8 mmps_mode; + u8 gband_256; + u8 af; + u8 auth_wapi_mode; + u8 rate_len; + + u8 supp_mode; + u8 supp_cck_rate; + u8 supp_ofdm_rate; + __le32 supp_ht_mcs; + __le16 supp_vht_mcs[4]; + + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + __le32 sta_status; + + struct ra_phy phy; +} __packed; + +enum { + STA_REC_BASIC, + STA_REC_RA, + STA_REC_RA_CMM_INFO, + STA_REC_RA_UPDATE, + STA_REC_BF, + STA_REC_AMSDU, + STA_REC_BA, + STA_REC_RED, /* not used */ + STA_REC_TX_PROC, /* for hdr trans and CSO in CR4 */ + STA_REC_HT, + STA_REC_VHT, + STA_REC_APPS, + STA_REC_KEY, + STA_REC_WTBL, + STA_REC_HE, + STA_REC_HW_AMSDU, + STA_REC_WTBL_AADOM, + STA_REC_KEY_V2, + STA_REC_MURU, + STA_REC_MUEDCA, + STA_REC_MAX_NUM +}; + +enum mt7915_cipher_type { + MT_CIPHER_NONE, + MT_CIPHER_WEP40, + MT_CIPHER_WEP104, + MT_CIPHER_WEP128, + MT_CIPHER_TKIP, + MT_CIPHER_AES_CCMP, + MT_CIPHER_CCMP_256, + MT_CIPHER_GCMP, + MT_CIPHER_GCMP_256, + MT_CIPHER_WAPI, + MT_CIPHER_BIP_CMAC_128, +}; + +enum { + CH_SWITCH_NORMAL = 0, + CH_SWITCH_SCAN = 3, + CH_SWITCH_MCC = 4, + CH_SWITCH_DFS = 5, + CH_SWITCH_BACKGROUND_SCAN_START = 6, + CH_SWITCH_BACKGROUND_SCAN_RUNNING = 7, + CH_SWITCH_BACKGROUND_SCAN_STOP = 8, + CH_SWITCH_SCAN_BYPASS_DPD = 9 +}; + +enum { + THERMAL_SENSOR_TEMP_QUERY, + THERMAL_SENSOR_MANUAL_CTRL, + THERMAL_SENSOR_INFO_QUERY, + THERMAL_SENSOR_TASK_CTRL, +}; + +#define MT7915_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ + sizeof(struct wtbl_generic) + \ + sizeof(struct wtbl_rx) + \ + sizeof(struct wtbl_ht) + \ + sizeof(struct wtbl_vht) + \ + sizeof(struct wtbl_ba) + \ + sizeof(struct wtbl_bf) + \ + sizeof(struct wtbl_smps) + \ + sizeof(struct wtbl_spe)) + +#define MT7915_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ + sizeof(struct sta_rec_basic) + \ + sizeof(struct sta_rec_ht) + \ + sizeof(struct sta_rec_ba) + \ + sizeof(struct sta_rec_vht) + \ + sizeof(struct tlv) + \ + sizeof(struct sta_rec_sec) + \ + sizeof(struct sta_rec_ra) + \ + MT7915_WTBL_UPDATE_MAX_SIZE) + +#define MT7915_WTBL_UPDATE_BA_SIZE (sizeof(struct wtbl_req_hdr) + \ + sizeof(struct wtbl_ba)) + +#define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \ + sizeof(struct bss_info_bcn_csa) + \ + sizeof(struct bss_info_bcn_bcc) + \ + sizeof(struct bss_info_bcn_mbss) + \ + sizeof(struct bss_info_bcn_cont)) + +#define PHY_MODE_A BIT(0) +#define PHY_MODE_B BIT(1) +#define PHY_MODE_G BIT(2) +#define PHY_MODE_GN BIT(3) +#define PHY_MODE_AN BIT(4) +#define PHY_MODE_AC BIT(5) + +#define MODE_CCK BIT(0) +#define MODE_OFDM BIT(1) +#define MODE_HT BIT(2) +#define MODE_VHT BIT(3) + +#define STA_CAP_WMM BIT(0) +#define STA_CAP_SGI_20 BIT(4) +#define STA_CAP_SGI_40 BIT(5) +#define STA_CAP_TX_STBC BIT(6) +#define STA_CAP_RX_STBC BIT(7) +#define STA_CAP_VHT_SGI_80 BIT(16) +#define STA_CAP_VHT_SGI_160 BIT(17) +#define STA_CAP_VHT_TX_STBC BIT(18) +#define STA_CAP_VHT_RX_STBC BIT(19) +#define STA_CAP_VHT_LDPC BIT(23) +#define STA_CAP_LDPC BIT(24) +#define STA_CAP_HT BIT(26) +#define STA_CAP_VHT BIT(27) + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h new file mode 100644 index 000000000000..b23ab3f215e0 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -0,0 +1,441 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_H +#define __MT7915_H + +#include +#include +#include "../mt76.h" +#include "regs.h" + +#define MT7915_MAX_INTERFACES 4 +#define MT7915_MAX_WMM_SETS 4 +#define MT7915_WTBL_SIZE 288 +#define MT7915_WTBL_RESERVED (MT7915_WTBL_SIZE - 1) +#define MT7915_WTBL_STA (MT7915_WTBL_RESERVED - \ + MT7915_MAX_INTERFACES) + +#define MT7915_WATCHDOG_TIME (HZ / 10) +#define MT7915_RESET_TIMEOUT (30 * HZ) + +#define MT7915_TX_RING_SIZE 2048 +#define MT7915_TX_MCU_RING_SIZE 256 +#define MT7915_TX_FWDL_RING_SIZE 128 + +#define MT7915_RX_RING_SIZE 1536 +#define MT7915_RX_MCU_RING_SIZE 512 + +#define MT7915_FIRMWARE_WA "mediatek/mt7915_wa.bin" +#define MT7915_FIRMWARE_WM "mediatek/mt7915_wm.bin" +#define MT7915_ROM_PATCH "mediatek/mt7915_rom_patch.bin" + +#define MT7915_EEPROM_SIZE 3584 +#define MT7915_TOKEN_SIZE 8192 + +#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ +#define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ +#define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */ +#define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */ + + +struct mt7915_vif; +struct mt7915_sta; +struct mt7915_dfs_pulse; +struct mt7915_dfs_pattern; + +enum mt7915_txq_id { + MT7915_TXQ_FWDL = 16, + MT7915_TXQ_MCU_WM, + MT7915_TXQ_BAND0, + MT7915_TXQ_BAND1, + MT7915_TXQ_MCU_WA, +}; + +enum mt7915_rxq_id { + MT7915_RXQ_BAND0 = 0, + MT7915_RXQ_BAND1, + MT7915_RXQ_MCU_WM = 0, + MT7915_RXQ_MCU_WA, +}; + +enum mt7915_ampdu_state { + MT7915_AGGR_STOP, + MT7915_AGGR_PROGRESS, + MT7915_AGGR_START, + MT7915_AGGR_OPERATIONAL +}; + +struct mt7915_sta_stats { + struct rate_info prob_rate; + struct rate_info tx_rate; + + unsigned long per; + unsigned long changed; + unsigned long jiffies; +}; + +struct mt7915_sta { + struct mt76_wcid wcid; /* must be first */ + + struct mt7915_vif *vif; + + struct list_head poll_list; + u32 airtime_ac[8]; + + struct mt7915_sta_stats stats; + struct work_struct stats_work; + + spinlock_t ampdu_lock; + enum mt7915_ampdu_state ampdu_state[IEEE80211_NUM_TIDS]; +}; + +struct mt7915_vif { + u16 idx; + u8 omac_idx; + u8 band_idx; + u8 wmm_idx; + + struct { + u16 cw_min; + u16 cw_max; + u16 txop; + u8 aifs; + } wmm[IEEE80211_NUM_ACS]; + + struct mt7915_sta sta; + struct mt7915_dev *dev; +}; + +struct mib_stats { + u16 ack_fail_cnt; + u16 fcs_err_cnt; + u16 rts_cnt; + u16 rts_retries_cnt; + u16 ba_miss_cnt; +}; + +struct mt7915_phy { + struct mt76_phy *mt76; + struct mt7915_dev *dev; + + u32 rxfilter; + u32 vif_mask; + u32 omac_mask; + + u16 noise; + u16 chainmask; + + s16 coverage_class; + u8 slottime; + + u8 rdd_state; + int dfs_state; + + __le32 rx_ampdu_ts; + u32 ampdu_ref; + + struct mib_stats mib; +}; + +struct mt7915_dev { + union { /* must be first */ + struct mt76_dev mt76; + struct mt76_phy mphy; + }; + + struct mt7915_phy phy; + + u16 chainmask; + + struct work_struct init_work; + struct work_struct reset_work; + wait_queue_head_t reset_wait; + u32 reset_state; + + struct list_head sta_poll_list; + spinlock_t sta_poll_lock; + + u32 hw_pattern; + + spinlock_t token_lock; + struct idr token; + + u8 mac_work_count; + bool fw_debug; +}; + +enum { + HW_BSSID_0 = 0x0, + HW_BSSID_1, + HW_BSSID_2, + HW_BSSID_3, + HW_BSSID_MAX, + EXT_BSSID_START = 0x10, + EXT_BSSID_1, + EXT_BSSID_2, + EXT_BSSID_3, + EXT_BSSID_4, + EXT_BSSID_5, + EXT_BSSID_6, + EXT_BSSID_7, + EXT_BSSID_8, + EXT_BSSID_9, + EXT_BSSID_10, + EXT_BSSID_11, + EXT_BSSID_12, + EXT_BSSID_13, + EXT_BSSID_14, + EXT_BSSID_15, + EXT_BSSID_END +}; + +enum { + MT_RX_SEL0, + MT_RX_SEL1, +}; + +enum mt7915_rdd_cmd { + RDD_STOP, + RDD_START, + RDD_DET_MODE, + RDD_RADAR_EMULATE, + RDD_START_TXQ = 20, + RDD_CAC_START = 50, + RDD_CAC_END, + RDD_NORMAL_START, + RDD_DISABLE_DFS_CAL, + RDD_PULSE_DBG, + RDD_READ_PULSE, + RDD_RESUME_BF, + RDD_IRQ_OFF, +}; + +enum { + RATE_CTRL_RU_INFO, + RATE_CTRL_FIXED_RATE_INFO, + RATE_CTRL_DUMP_INFO, + RATE_CTRL_MU_INFO, +}; + +static inline struct mt7915_phy * +mt7915_hw_phy(struct ieee80211_hw *hw) +{ + struct mt76_phy *phy = hw->priv; + + return phy->priv; +} + +static inline struct mt7915_dev * +mt7915_hw_dev(struct ieee80211_hw *hw) +{ + struct mt76_phy *phy = hw->priv; + + return container_of(phy->dev, struct mt7915_dev, mt76); +} + +static inline struct mt7915_phy * +mt7915_ext_phy(struct mt7915_dev *dev) +{ + struct mt76_phy *phy = dev->mt76.phy2; + + if (!phy) + return NULL; + + return phy->priv; +} + +static inline void +mt7915_set_aggr_state(struct mt7915_sta *msta, u8 tid, + enum mt7915_ampdu_state state) +{ + spin_lock_bh(&msta->ampdu_lock); + msta->ampdu_state[tid] = state; + spin_unlock_bh(&msta->ampdu_lock); +} + +extern const struct ieee80211_ops mt7915_ops; +extern struct pci_driver mt7915_pci_driver; + +u32 mt7915_reg_map(struct mt7915_dev *dev, u32 addr); + +int mt7915_register_device(struct mt7915_dev *dev); +void mt7915_unregister_device(struct mt7915_dev *dev); +int mt7915_register_ext_phy(struct mt7915_dev *dev); +void mt7915_unregister_ext_phy(struct mt7915_dev *dev); +int mt7915_eeprom_init(struct mt7915_dev *dev); +u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset); +int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, + struct ieee80211_channel *chan, + u8 chain_idx); +int mt7915_dma_init(struct mt7915_dev *dev); +void mt7915_dma_prefetch(struct mt7915_dev *dev); +void mt7915_dma_cleanup(struct mt7915_dev *dev); +int mt7915_mcu_init(struct mt7915_dev *dev); +int mt7915_mcu_add_dev_info(struct mt7915_dev *dev, + struct ieee80211_vif *vif, bool enable); +int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, + struct ieee80211_vif *vif, int enable); +int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable); +int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool add); +int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool add); +int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct mt7915_sta *msta, struct ieee80211_key_conf *key, + enum set_key_cmd cmd); +int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int enable); +int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd); +int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif); +int mt7915_mcu_set_eeprom(struct mt7915_dev *dev); +int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset); +int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable, + bool hdr_trans); +int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable); +int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band); +int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val); +int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter); +int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); +int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, + const struct mt7915_dfs_pulse *pulse); +int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, + const struct mt7915_dfs_pattern *pattern); +int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx); +int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index); +int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd, + u8 index, u8 rx_sel, u8 val); +void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb); +void mt7915_mcu_exit(struct mt7915_dev *dev); + +static inline bool is_mt7915(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7915; +} + +static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask) +{ + mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask); +} + +static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) +{ + mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); +} + +static inline u32 +mt7915_reg_map_l1(struct mt7915_dev *dev, u32 addr) +{ + u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); + u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); + + mt76_rmw_field(dev, MT_HIF_REMAP_L1, MT_HIF_REMAP_L1_MASK, base); + /* use read to push write */ + mt76_rr(dev, MT_HIF_REMAP_L1); + + return MT_HIF_REMAP_BASE_L1 + offset; +} + +static inline u32 +mt7915_l1_rr(struct mt7915_dev *dev, u32 addr) +{ + return mt76_rr(dev, mt7915_reg_map_l1(dev, addr)); +} + +static inline void +mt7915_l1_wr(struct mt7915_dev *dev, u32 addr, u32 val) +{ + mt76_wr(dev, mt7915_reg_map_l1(dev, addr), val); +} + +static inline u32 +mt7915_l1_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val) +{ + val |= mt7915_l1_rr(dev, addr) & ~mask; + mt7915_l1_wr(dev, addr, val); + + return val; +} + +#define mt7915_l1_set(dev, addr, val) mt7915_l1_rmw(dev, addr, 0, val) +#define mt7915_l1_clear(dev, addr, val) mt7915_l1_rmw(dev, addr, val, 0) + +static inline u32 +mt7915_reg_map_l2(struct mt7915_dev *dev, u32 addr) +{ + u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); + u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); + + mt76_rmw_field(dev, MT_HIF_REMAP_L2, MT_HIF_REMAP_L2_MASK, base); + /* use read to push write */ + mt76_rr(dev, MT_HIF_REMAP_L2); + + return MT_HIF_REMAP_BASE_L2 + offset; +} + +static inline u32 +mt7915_l2_rr(struct mt7915_dev *dev, u32 addr) +{ + return mt76_rr(dev, mt7915_reg_map_l2(dev, addr)); +} + +static inline void +mt7915_l2_wr(struct mt7915_dev *dev, u32 addr, u32 val) +{ + mt76_wr(dev, mt7915_reg_map_l2(dev, addr), val); +} + +static inline u32 +mt7915_l2_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val) +{ + val |= mt7915_l2_rr(dev, addr) & ~mask; + mt7915_l2_wr(dev, addr, val); + + return val; +} + +#define mt7915_l2_set(dev, addr, val) mt7915_l2_rmw(dev, addr, 0, val) +#define mt7915_l2_clear(dev, addr, val) mt7915_l2_rmw(dev, addr, val, 0) + +bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask); +void mt7915_mac_reset_counters(struct mt7915_phy *phy); +void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy); +void mt7915_mac_sta_poll(struct mt7915_dev *dev); +void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, bool beacon); +void mt7915_mac_set_timing(struct mt7915_phy *phy); +int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb); +void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb); +int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void mt7915_mac_work(struct work_struct *work); +void mt7915_mac_reset_work(struct work_struct *work); +void mt7915_mac_sta_stats_work(struct work_struct *work); +int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info); +void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, + struct mt76_queue_entry *e); +void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb); +void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); +void mt7915_stats_work(struct work_struct *work); +void mt7915_txp_skb_unmap(struct mt76_dev *dev, + struct mt76_txwi_cache *txwi); +int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force); +int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); +void mt7915_update_channel(struct mt76_dev *mdev); +int mt7915_init_debugfs(struct mt7915_dev *dev); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c new file mode 100644 index 000000000000..b79b5060cd77 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Ryder Lee + */ + +#include +#include +#include + +#include "mt7915.h" +#include "mac.h" +#include "../trace.h" + +static const struct pci_device_id mt7915_pci_device_table[] = { + { PCI_DEVICE(0x14c3, 0x7915) }, + { }, +}; + +static void +mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + + mt7915_irq_enable(dev, MT_INT_RX_DONE(q)); +} + +/* TODO: support 2/4/6/8 MSI-X vectors */ +static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) +{ + struct mt7915_dev *dev = dev_instance; + u32 intr; + + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) + return IRQ_NONE; + + trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); + + intr &= dev->mt76.mmio.irqmask; + + if (intr & MT_INT_TX_DONE_ALL) { + mt7915_irq_disable(dev, MT_INT_TX_DONE_ALL); + napi_schedule(&dev->mt76.tx_napi); + } + + if (intr & MT_INT_RX_DONE_DATA) { + mt7915_irq_disable(dev, MT_INT_RX_DONE_DATA); + napi_schedule(&dev->mt76.napi[0]); + } + + if (intr & MT_INT_RX_DONE_WM) { + mt7915_irq_disable(dev, MT_INT_RX_DONE_WM); + napi_schedule(&dev->mt76.napi[1]); + } + + if (intr & MT_INT_RX_DONE_WA) { + mt7915_irq_disable(dev, MT_INT_RX_DONE_WA); + napi_schedule(&dev->mt76.napi[2]); + } + + if (intr & MT_INT_MCU_CMD) { + u32 val = mt76_rr(dev, MT_MCU_CMD); + + mt76_wr(dev, MT_MCU_CMD, val); + if (val & MT_MCU_CMD_ERROR_MASK) { + dev->reset_state = val; + ieee80211_queue_work(mt76_hw(dev), &dev->reset_work); + wake_up(&dev->reset_wait); + } + } + + return IRQ_HANDLED; +} + +static int mt7915_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + static const struct mt76_driver_ops drv_ops = { + /* txwi_size = txd size + txp size */ + .txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp), + .drv_flags = MT_DRV_TXWI_NO_FREE, + .survey_flags = SURVEY_INFO_TIME_TX | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_BSS_RX, + .tx_prepare_skb = mt7915_tx_prepare_skb, + .tx_complete_skb = mt7915_tx_complete_skb, + .rx_skb = mt7915_queue_rx_skb, + .rx_poll_complete = mt7915_rx_poll_complete, + .sta_ps = mt7915_sta_ps, + .sta_add = mt7915_mac_sta_add, + .sta_remove = mt7915_mac_sta_remove, + .update_survey = mt7915_update_channel, + }; + struct mt7915_dev *dev; + struct mt76_dev *mdev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7915_ops, + &drv_ops); + if (!mdev) + return -ENOMEM; + + dev = container_of(mdev, struct mt7915_dev, mt76); + + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) | + (mt7915_l1_rr(dev, MT_HW_REV) & 0xff); + dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + + /* master switch of PCIe tnterrupt enable */ + mt7915_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + + ret = devm_request_irq(mdev->dev, pdev->irq, mt7915_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) + goto error; + + ret = mt7915_register_device(dev); + if (ret) + goto error; + + return 0; +error: + ieee80211_free_hw(mt76_hw(dev)); + return ret; +} + +static void mt7915_pci_remove(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + + mt7915_unregister_device(dev); +} + +struct pci_driver mt7915_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mt7915_pci_device_table, + .probe = mt7915_pci_probe, + .remove = mt7915_pci_remove, +}; + +module_pci_driver(mt7915_pci_driver); + +MODULE_DEVICE_TABLE(pci, mt7915_pci_device_table); +MODULE_FIRMWARE(MT7915_FIRMWARE_WA); +MODULE_FIRMWARE(MT7915_FIRMWARE_WM); +MODULE_FIRMWARE(MT7915_ROM_PATCH); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h new file mode 100644 index 000000000000..ef87579056fe --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -0,0 +1,343 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_REGS_H +#define __MT7915_REGS_H + +/* MCU WFDMA1 */ +#define MT_MCU_WFDMA1_BASE 0x3000 +#define MT_MCU_WFDMA1(ofs) (MT_MCU_WFDMA1_BASE + (ofs)) + +#define MT_MCU_INT_EVENT MT_MCU_WFDMA1(0x108) +#define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) +#define MT_MCU_INT_EVENT_DMA_INIT BIT(1) +#define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2) +#define MT_MCU_INT_EVENT_RESET_DONE BIT(3) + +#define MT_PLE_BASE 0x8000 +#define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) + +#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) +#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) +#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8) +#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc) + +#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \ + ((n) << 2)) +#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) + +#define MT_MDP_BASE 0xf000 +#define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) + +#define MT_MDP_DCR0 MT_MDP(0x000) +#define MT_MDP_DCR0_DAMSDU_EN BIT(15) + +#define MT_MDP_DCR1 MT_MDP(0x004) +#define MT_MDP_DCR1_MAX_RX_LEN GENMASK(15, 3) + +#define MT_MDP_BNRCFR0(_band) MT_MDP(0x070 + ((_band) << 8)) +#define MT_MDP_RCFR0_MCU_RX_MGMT GENMASK(5, 4) +#define MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR GENMASK(7, 6) +#define MT_MDP_RCFR0_MCU_RX_CTL_BAR GENMASK(9, 8) + +#define MT_MDP_BNRCFR1(_band) MT_MDP(0x074 + ((_band) << 8)) +#define MT_MDP_RCFR1_MCU_RX_BYPASS GENMASK(23, 22) +#define MT_MDP_RCFR1_RX_DROPPED_UCAST GENMASK(28, 27) +#define MT_MDP_RCFR1_RX_DROPPED_MCAST GENMASK(30, 29) +#define MT_MDP_TO_HIF 0 +#define MT_MDP_TO_WM 1 + +/* TMAC: band 0(0x21000), band 1(0xa1000) */ +#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000) +#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) + +#define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090) +#define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x094) +#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) +#define MT_TIMEOUT_VAL_CCA GENMASK(31, 16) + +#define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4) +#define MT_IFS_EIFS GENMASK(8, 0) +#define MT_IFS_RIFS GENMASK(14, 10) +#define MT_IFS_SIFS GENMASK(22, 16) +#define MT_IFS_SLOT GENMASK(30, 24) + +#define MT_TMAC_CTCR0(_band) MT_WF_TMAC(_band, 0x0f4) +#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0) +#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17) +#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18) + +/* DMA Band 0 */ +#define MT_WF_DMA_BASE 0x21e00 +#define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs)) + +#define MT_DMA_DCR0 MT_WF_DMA(0x000) +#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) + +/* MIB: band 0(0x24800), band 1(0xa4800) */ +#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) +#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) + +#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014) +#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0) + +#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c) +#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) + +#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048) +#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) + +#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098) +#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) +#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c) +#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) + +#define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4)) +#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) +#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) + +#define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(_band, 0x104 + ((n) << 4)) +#define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0) +#define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) + +#define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4)) +#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0) + +#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x0a8 + ((n) << 2)) +#define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x164 + ((n) << 2)) +#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x4b8 + ((n) << 2)) +#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0)) + +#define MT_WTBLON_TOP_BASE 0x34000 +#define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs)) +#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x0) +#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0) + +#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x030) +#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(9, 0) +#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) +#define MT_WTBL_UPDATE_BUSY BIT(31) + +#define MT_WTBL_BASE 0x38000 +#define MT_WTBL_LMAC_ID GENMASK(14, 8) +#define MT_WTBL_LMAC_DW GENMASK(7, 2) +#define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \ + FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \ + FIELD_PREP(MT_WTBL_LMAC_DW, _dw)) + +/* AGG: band 0(0x20800), band 1(0xa0800) */ +#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800) +#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs)) + +#define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x084) +#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0) +#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16) + +/* ARB: band 0(0x20c00), band 1(0xa0c00) */ +#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00) +#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs)) + +#define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080) +#define MT_ARB_SCR_TX_DISABLE BIT(8) +#define MT_ARB_SCR_RX_DISABLE BIT(9) + +/* RMAC: band 0(0x21400), band 1(0xa1400) */ +#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400) +#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs)) + +#define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000) +#define MT_WF_RFCR_DROP_STBC_MULTI BIT(0) +#define MT_WF_RFCR_DROP_FCSFAIL BIT(1) +#define MT_WF_RFCR_DROP_VERSION BIT(3) +#define MT_WF_RFCR_DROP_PROBEREQ BIT(4) +#define MT_WF_RFCR_DROP_MCAST BIT(5) +#define MT_WF_RFCR_DROP_BCAST BIT(6) +#define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7) +#define MT_WF_RFCR_DROP_A3_MAC BIT(8) +#define MT_WF_RFCR_DROP_A3_BSSID BIT(9) +#define MT_WF_RFCR_DROP_A2_BSSID BIT(10) +#define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11) +#define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12) +#define MT_WF_RFCR_DROP_CTL_RSV BIT(13) +#define MT_WF_RFCR_DROP_CTS BIT(14) +#define MT_WF_RFCR_DROP_RTS BIT(15) +#define MT_WF_RFCR_DROP_DUPLICATE BIT(16) +#define MT_WF_RFCR_DROP_OTHER_BSS BIT(17) +#define MT_WF_RFCR_DROP_OTHER_UC BIT(18) +#define MT_WF_RFCR_DROP_OTHER_TIM BIT(19) +#define MT_WF_RFCR_DROP_NDPA BIT(20) +#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) + +#define MT_WF_RFCR1(_band) MT_WF_RMAC(_band, 0x004) +#define MT_WF_RFCR1_DROP_ACK BIT(4) +#define MT_WF_RFCR1_DROP_BF_POLL BIT(5) +#define MT_WF_RFCR1_DROP_BA BIT(6) +#define MT_WF_RFCR1_DROP_CFEND BIT(7) +#define MT_WF_RFCR1_DROP_CFACK BIT(8) + +#define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4) +#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) +#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) + +#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8) +#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) +#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) + +/* WFDMA0 */ +#define MT_WFDMA0_BASE 0xd4000 +#define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs)) + +#define MT_WFDMA0_RST MT_WFDMA0(0x100) +#define MT_WFDMA0_RST_LOGIC_RST BIT(4) +#define MT_WFDMA0_RST_DMASHDL_ALL_RST BIT(5) + +#define MT_WFDMA0_BUSY_ENA MT_WFDMA0(0x13c) +#define MT_WFDMA0_BUSY_ENA_TX_FIFO0 BIT(0) +#define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) +#define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2) + +#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) +#define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) +#define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) + +#define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) +#define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) + +#define MT_RX_DATA_RING_BASE MT_WFDMA0(0x500) + +#define MT_WFDMA0_RX_RING0_EXT_CTRL MT_WFDMA0(0x680) +#define MT_WFDMA0_RX_RING1_EXT_CTRL MT_WFDMA0(0x684) +#define MT_WFDMA0_RX_RING2_EXT_CTRL MT_WFDMA0(0x688) + +/* WFDMA1 */ +#define MT_WFDMA1_BASE 0xd5000 +#define MT_WFDMA1(ofs) (MT_WFDMA1_BASE + (ofs)) + +#define MT_WFDMA1_RST MT_WFDMA1(0x100) +#define MT_WFDMA1_RST_LOGIC_RST BIT(4) +#define MT_WFDMA1_RST_DMASHDL_ALL_RST BIT(5) + +#define MT_WFDMA1_BUSY_ENA MT_WFDMA1(0x13c) +#define MT_WFDMA1_BUSY_ENA_TX_FIFO0 BIT(0) +#define MT_WFDMA1_BUSY_ENA_TX_FIFO1 BIT(1) +#define MT_WFDMA1_BUSY_ENA_RX_FIFO BIT(2) + +#define MT_MCU_CMD MT_WFDMA1(0x1f0) +#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1) +#define MT_MCU_CMD_STOP_DMA BIT(2) +#define MT_MCU_CMD_RESET_DONE BIT(3) +#define MT_MCU_CMD_RECOVERY_DONE BIT(4) +#define MT_MCU_CMD_NORMAL_STATE BIT(5) +#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) + +#define MT_WFDMA1_GLO_CFG MT_WFDMA1(0x208) +#define MT_WFDMA1_GLO_CFG_TX_DMA_EN BIT(0) +#define MT_WFDMA1_GLO_CFG_RX_DMA_EN BIT(2) +#define MT_WFDMA1_GLO_CFG_OMIT_TX_INFO BIT(28) +#define MT_WFDMA1_GLO_CFG_OMIT_RX_INFO BIT(27) + +#define MT_WFDMA1_RST_DTX_PTR MT_WFDMA1(0x20c) +#define MT_WFDMA1_PRI_DLY_INT_CFG0 MT_WFDMA1(0x2f0) + +#define MT_TX_RING_BASE MT_WFDMA1(0x300) +#define MT_RX_EVENT_RING_BASE MT_WFDMA1(0x500) + +#define MT_WFDMA1_TX_RING0_EXT_CTRL MT_WFDMA1(0x600) +#define MT_WFDMA1_TX_RING1_EXT_CTRL MT_WFDMA1(0x604) +#define MT_WFDMA1_TX_RING2_EXT_CTRL MT_WFDMA1(0x608) +#define MT_WFDMA1_TX_RING3_EXT_CTRL MT_WFDMA1(0x60c) +#define MT_WFDMA1_TX_RING4_EXT_CTRL MT_WFDMA1(0x610) +#define MT_WFDMA1_TX_RING5_EXT_CTRL MT_WFDMA1(0x614) +#define MT_WFDMA1_TX_RING6_EXT_CTRL MT_WFDMA1(0x618) +#define MT_WFDMA1_TX_RING7_EXT_CTRL MT_WFDMA1(0x61c) + +#define MT_WFDMA1_TX_RING16_EXT_CTRL MT_WFDMA1(0x640) +#define MT_WFDMA1_TX_RING17_EXT_CTRL MT_WFDMA1(0x644) +#define MT_WFDMA1_TX_RING18_EXT_CTRL MT_WFDMA1(0x648) +#define MT_WFDMA1_TX_RING19_EXT_CTRL MT_WFDMA1(0x64c) +#define MT_WFDMA1_TX_RING20_EXT_CTRL MT_WFDMA1(0x650) +#define MT_WFDMA1_TX_RING21_EXT_CTRL MT_WFDMA1(0x654) +#define MT_WFDMA1_TX_RING22_EXT_CTRL MT_WFDMA1(0x658) +#define MT_WFDMA1_TX_RING23_EXT_CTRL MT_WFDMA1(0x65c) + +#define MT_WFDMA1_RX_RING0_EXT_CTRL MT_WFDMA1(0x680) +#define MT_WFDMA1_RX_RING1_EXT_CTRL MT_WFDMA1(0x684) +#define MT_WFDMA1_RX_RING2_EXT_CTRL MT_WFDMA1(0x688) +#define MT_WFDMA1_RX_RING3_EXT_CTRL MT_WFDMA1(0x68c) + +/* WFDMA CSR */ +#define MT_WFDMA_EXT_CSR_BASE 0xd7000 +#define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs)) + +#define MT_INT_SOURCE_CSR MT_WFDMA_EXT_CSR(0x10) +#define MT_INT_MASK_CSR MT_WFDMA_EXT_CSR(0x14) +#define MT_INT_RX_DONE_DATA BIT(16) +#define MT_INT_RX_DONE_WM BIT(0) +#define MT_INT_RX_DONE_WA BIT(1) +#define MT_INT_RX_DONE(_n) ((_n) ? BIT((_n) - 1) : BIT(16)) +#define MT_INT_RX_DONE_ALL (BIT(0) | BIT(1) | BIT(16)) +#define MT_INT_TX_DONE_ALL (BIT(15) | GENMASK(27, 26) | BIT(30)) +#define MT_INT_MCU_CMD BIT(29) + +#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) +#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) + +/* WFDMA0 PCIE1 */ +#define MT_WFDMA0_PCIE1_BASE 0xd8000 +#define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) + +#define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c) +#define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) +#define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) +#define MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO BIT(2) + +/* WFDMA1 PCIE1 */ +#define MT_WFDMA1_PCIE1_BASE 0xd9000 +#define MT_WFDMA1_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) + +#define MT_WFDMA1_PCIE1_BUSY_ENA MT_WFDMA1_PCIE1(0x13c) +#define MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) +#define MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) +#define MT_WFDMA1_PCIE1_BUSY_ENA_RX_FIFO BIT(2) + +#define MT_INFRA_CFG_BASE 0xf1000 +#define MT_INFRA(ofs) (MT_INFRA_CFG_BASE + (ofs)) + +#define MT_HIF_REMAP_L1 MT_INFRA(0x1ac) +#define MT_HIF_REMAP_L1_MASK GENMASK(15, 0) +#define MT_HIF_REMAP_L1_OFFSET GENMASK(15, 0) +#define MT_HIF_REMAP_L1_BASE GENMASK(31, 16) +#define MT_HIF_REMAP_BASE_L1 0xe0000 + +#define MT_HIF_REMAP_L2 MT_INFRA(0x1b0) +#define MT_HIF_REMAP_L2_MASK GENMASK(19, 0) +#define MT_HIF_REMAP_L2_OFFSET GENMASK(11, 0) +#define MT_HIF_REMAP_L2_BASE GENMASK(31, 12) +#define MT_HIF_REMAP_BASE_L2 0x00000 + +#define MT_TOP_BASE 0x18060000 +#define MT_TOP(ofs) (MT_TOP_BASE + (ofs)) + +#define MT_TOP_LPCR_HOST_BAND0 MT_TOP(0x10) +#define MT_TOP_LPCR_HOST_FW_OWN BIT(0) +#define MT_TOP_LPCR_HOST_DRV_OWN BIT(1) + +#define MT_TOP_MISC MT_TOP(0xf0) +#define MT_TOP_MISC_FW_STATE GENMASK(2, 0) + +#define MT_HW_BOUND 0x70010020 +#define MT_HW_CHIPID 0x70010200 +#define MT_HW_REV 0x70010204 + +#define MT_PCIE_MAC_BASE 0x74030000 +#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) +#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) + +/* PHY: band 0(0x83080000), band 1(0x83090000) */ +#define MT_WF_PHY_BASE 0x83080000 +#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) + +#define MT_WF_PHY_RX_CTRL1(_phy) MT_WF_PHY(0x2004 + ((_phy) << 16)) +#define MT_WF_PHY_RX_CTRL1_STSCNT_EN GENMASK(11, 9) + +#endif From patchwork Fri Apr 24 19:32:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508947 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 063CA14DD for ; Fri, 24 Apr 2020 19:43:28 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D8BF42176D for ; Fri, 24 Apr 2020 19:43:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="kNR3O8bi"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="j9bZVnSu" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D8BF42176D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=WRlV7Ix75o4XosyEQAh257o5qP1O0kaRT83DBXJ929g=; b=kNR3O8biIg/fYi VEZmS6gsZ3ERvmr1y4JDqYUE8orKbdSiOUWrFdbYq1x9/6SWPDVIBCDkm4GNlIvsiF7BbZUn8otAV Snnm0hKT/2YVpUnRMkiWMlrrkysedQg0venD+hD/KDmjEs5ByiSlSWKxvJJRBukZApSEikJrJOpd9 8uc6NFRyJnLT8171/aR7Zh0ZFrNrHXrcL+TUvaMWIQTC78djlGUWs05KGTMWE6qcepj3CbtJu3bjM XjMuV4S70Ph7e7LoHz9m+XJ5q0aoKzxX9Yuatf4ZQSPs8f0dV3miWPfVSDERnhpnxOJTIs6SdMI2v 96eF4eTfjXuD0+hGGAyQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EP-0006Mn-Fz; Fri, 24 Apr 2020 19:43:25 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EC-000625-SI for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:14 +0000 X-UUID: 1760b9b7ecf14222b782cafea2c8ea30-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=6x+oFqiIGQnnKYYcf2KhwLTXjjhGL/WPlXmNOrOE1gI=; b=j9bZVnSuzfVueZcpZ3rJANPJT4I6adN0adQOPAbOC77mgpL58r8Q8JWD9pJZoIaTpDL96RVxmGbr2E6rV3GMgzvSlYpokIFUDyz3en5uNRXfLkPPXzEDCkLCCbK+K9ZOHwkRpLoq9l4KJsoHJ4ewYVAg4UBrbm0KQqSW37s0pb8=; X-UUID: 1760b9b7ecf14222b782cafea2c8ea30-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1921811953; Fri, 24 Apr 2020 11:43:06 -0800 Received: from mtkmbs08n2.mediatek.inc (172.21.101.56) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:01 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:48 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:51 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 07/18] mt76: mt7915: enable Rx HE rate reporting Date: Sat, 25 Apr 2020 03:32:28 +0800 Message-ID: <2dcb775842199f2e4de1c823f2d8e048b352eebb.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-TM-SNTS-SMTP: BE577BE27BEE5889C9CBD23C81B0B930AFEFB468DC7B58C355744931D24A6B592000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124312_925256_5DE3E091 X-CRM114-Status: GOOD ( 10.27 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org Enable HE rate reporting in Rx path Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen --- .../net/wireless/mediatek/mt76/mt7915/init.c | 2 ++ .../net/wireless/mediatek/mt76/mt7915/mac.c | 27 +++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7915/mac.h | 2 ++ .../net/wireless/mediatek/mt76/mt7915/regs.h | 1 + 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index fb596afdf0be..f9384e1dab74 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -43,6 +43,8 @@ static void mt7915_mac_init(struct mt7915_dev *dev) mt76_rmw_field(dev, MT_DMA_DCR0, MT_DMA_DCR0_MAX_RX_LEN, 1536); mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); + /* enable rx rate report */ + mt76_set(dev, MT_DMA_DCR0, MT_DMA_DCR0_RXD_G5_EN); /* disable hardware de-agg */ mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index ddba360046c3..dd5b30a066b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -347,6 +347,22 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) if (i > 9) return -EINVAL; break; + case MT_PHY_TYPE_HE_MU: + /* fall through */ + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + status->nss = + FIELD_GET(MT_PRXV_NSTS, rxv.v[0]) + 1; + status->encoding = RX_ENC_HE; + i &= GENMASK(3, 0); + + if (gi <= NL80211_RATE_INFO_HE_GI_3_2) + status->he_gi = gi; + + if (idx & MT_PRXV_TX_DCM) + status->he_dcm = true; + break; default: return -EINVAL; } @@ -356,7 +372,14 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) case IEEE80211_STA_RX_BW_20: break; case IEEE80211_STA_RX_BW_40: - status->bw = RATE_INFO_BW_40; + if (rxv.phy & MT_PHY_TYPE_HE_EXT_SU && + (idx & MT_PRXV_TX_ER_SU_106T)) { + status->bw = RATE_INFO_BW_HE_RU; + status->he_ru = + NL80211_RATE_INFO_HE_RU_ALLOC_106; + } else { + status->bw = RATE_INFO_BW_40; + } break; case IEEE80211_STA_RX_BW_80: status->bw = RATE_INFO_BW_80; @@ -369,7 +392,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) } status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; - if (gi) + if (rxv.phy < MT_PHY_TYPE_HE_SU && gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 7da7551f98e4..712753484aee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -97,6 +97,8 @@ enum rx_pkt_type { /* P-RXV */ #define MT_PRXV_TX_RATE GENMASK(6, 0) +#define MT_PRXV_TX_DCM BIT(4) +#define MT_PRXV_TX_ER_SU_106T BIT(5) #define MT_PRXV_NSTS GENMASK(9, 7) #define MT_PRXV_HT_AD_CODE BIT(11) #define MT_PRXV_RCPI3 GENMASK(31, 24) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index ef87579056fe..572bdc16fb2d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -73,6 +73,7 @@ #define MT_DMA_DCR0 MT_WF_DMA(0x000) #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) +#define MT_DMA_DCR0_RXD_G5_EN BIT(23) /* MIB: band 0(0x24800), band 1(0xa4800) */ #define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) From patchwork Fri Apr 24 19:32:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508959 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CA4F113B2 for ; Fri, 24 Apr 2020 19:43:36 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A5881216FD for ; Fri, 24 Apr 2020 19:43:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="hzGCUaUB"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="n+Ig1+YL" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A5881216FD Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=ZJVc86O29XGZmsOSMHJMbUmaRP6eQSkJmAQKox2YHbI=; b=hzGCUaUBW8RCSk eoTSl/I+Y/HJvLatGEXAg1si51O5zkbpKM1qSz0Pvp14PJW9yhLq6DDxS1VZXV8fF0nQM2Qva2UxO avybpk/AhmzaKvCkgn2Vml4cEmml1fX2q9mJIshYiVT889ZOdCg8qN5yDSYWy1dZ7AZNQOVDiDpAk 8vYlicmmsH+CT15pe0WQy83TYu3BED6UyJ7gLEVnRP6AlHZSWpRKM2SoxVCqz4WCnfDl8DX+YvkfT IK+I+iCNHJ0Ky7r9NsJX73S9IlKm2PBSWEvLo9Nb4QV1FscF1F+buhdo1+OMIrHjdf/EPUxYti5Lk sbh8gchDCpeu4G7K5yTg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EY-0006iH-KS; Fri, 24 Apr 2020 19:43:34 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EE-000625-CB for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:19 +0000 X-UUID: 6ca717521ce946f6b4c476e8792ede62-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=OQgHXdY9xupntxysaSQvzP6LHb2R936k7c8Ji5vDl54=; b=n+Ig1+YLbxk7/XU3UveuRJKiPTtK8bIM8s5xvJ8D3oE7wbBXtGim5bwWbRiZoPIMsYHXX0R65jTnqrXojMh6q4wU2m4Hn8XkgWRrV1imz31FaqIrvyxf99I8u671pEFevvYdML9qReSxxVFP6LE4plPnMKskuwyG37Jop6kdgfI=; X-UUID: 6ca717521ce946f6b4c476e8792ede62-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1471549966; Fri, 24 Apr 2020 11:43:06 -0800 Received: from mtkmbs08n1.mediatek.inc (172.21.101.55) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:01 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n1.mediatek.inc (172.21.101.55) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:48 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:51 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 08/18] mt76: mt7915: implement HE per-rate tx power support Date: Sat, 25 Apr 2020 03:32:29 +0800 Message-ID: <69efab22c1fb4fbb1eb16cb378d944897ce24cd2.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124314_440722_C64BEF32 X-CRM114-Status: GOOD ( 12.60 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org Use firmware support for applying per-rate limit and power offsets. This can support all HE RU types. Signed-off-by: Shayne Chen Signed-off-by: Ryder Lee Tested-by: Chih-Min Chen Tested-by: Evelyn Tsai Acked-by: Yiwei Chung Acked-by: YF Luo --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 59 +++++++++ .../wireless/mediatek/mt76/mt7915/eeprom.c | 118 ++++++++++++++++++ .../wireless/mediatek/mt76/mt7915/eeprom.h | 47 +++++++ .../net/wireless/mediatek/mt76/mt7915/init.c | 2 + .../net/wireless/mediatek/mt76/mt7915/main.c | 7 ++ .../net/wireless/mediatek/mt76/mt7915/mcu.c | 48 +++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.h | 1 + .../wireless/mediatek/mt76/mt7915/mt7915.h | 8 ++ .../net/wireless/mediatek/mt76/mt7915/pci.c | 25 ++++ 9 files changed, 315 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 152ae0617f3d..2e3f05f73697 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -219,6 +219,63 @@ mt7915_queues_read(struct seq_file *s, void *data) return 0; } +static void +mt7915_puts_rate_txpower(struct seq_file *s, s8 *delta, + s8 txpower_cur, int band) +{ + static const char * const sku_group_name[] = { + "CCK", "OFDM", "HT20", "HT40", + "VHT20", "VHT40", "VHT80", "VHT160", + "RU26", "RU52", "RU106", "RU242/SU20", + "RU484/SU40", "RU996/SU80", "RU2x996/SU160" + }; + s8 txpower[MT7915_SKU_RATE_NUM]; + int i, idx = 0; + + for (i = 0; i < MT7915_SKU_RATE_NUM; i++) + txpower[i] = DIV_ROUND_UP(txpower_cur + delta[i], 2); + + for (i = 0; i < MAX_SKU_RATE_GROUP_NUM; i++) { + const struct sku_group *sku = &mt7915_sku_groups[i]; + u32 offset = sku->offset[band]; + + if (!offset) { + idx += sku->len; + continue; + } + + mt76_seq_puts_array(s, sku_group_name[i], + txpower + idx, sku->len); + idx += sku->len; + } +} + +static int +mt7915_read_rate_txpower(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + struct mt76_phy *mphy = &dev->mphy; + enum nl80211_band band = mphy->chandef.chan->band; + s8 *delta = dev->rate_power[band]; + s8 txpower_base = mphy->txpower_cur - delta[MT7915_SKU_MAX_DELTA_IDX]; + + seq_puts(s, "Band 0:\n"); + mt7915_puts_rate_txpower(s, delta, txpower_base, band); + + if (dev->mt76.phy2) { + mphy = dev->mt76.phy2; + band = mphy->chandef.chan->band; + delta = dev->rate_power[band]; + txpower_base = mphy->txpower_cur - + delta[MT7915_SKU_MAX_DELTA_IDX]; + + seq_puts(s, "Band 1:\n"); + mt7915_puts_rate_txpower(s, delta, txpower_base, band); + } + + return 0; +} + int mt7915_init_debugfs(struct mt7915_dev *dev) { struct dentry *dir; @@ -240,6 +297,8 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger); debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, mt7915_read_temperature); + debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir, + mt7915_read_rate_txpower); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 2099dd40530f..7deba7ebd68a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -123,3 +123,121 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, return mt7915_eeprom_read(dev, index); } + +static const u8 sku_cck_delta_map[] = { + SKU_CCK_GROUP0, + SKU_CCK_GROUP0, + SKU_CCK_GROUP1, + SKU_CCK_GROUP1, +}; + +static const u8 sku_ofdm_delta_map[] = { + SKU_OFDM_GROUP0, + SKU_OFDM_GROUP0, + SKU_OFDM_GROUP1, + SKU_OFDM_GROUP1, + SKU_OFDM_GROUP2, + SKU_OFDM_GROUP2, + SKU_OFDM_GROUP3, + SKU_OFDM_GROUP4, +}; + +static const u8 sku_mcs_delta_map[] = { + SKU_MCS_GROUP0, + SKU_MCS_GROUP1, + SKU_MCS_GROUP1, + SKU_MCS_GROUP2, + SKU_MCS_GROUP2, + SKU_MCS_GROUP3, + SKU_MCS_GROUP4, + SKU_MCS_GROUP5, + SKU_MCS_GROUP6, + SKU_MCS_GROUP7, + SKU_MCS_GROUP8, + SKU_MCS_GROUP9, +}; + +#define SKU_GROUP(_mode, _len, _ofs_2g, _ofs_5g, _map) \ + [_mode] = { \ + .len = _len, \ + .offset = { \ + _ofs_2g, \ + _ofs_5g, \ + }, \ + .delta_map = _map \ +} + +const struct sku_group mt7915_sku_groups[] = { + SKU_GROUP(SKU_CCK, 4, 0x252, 0, sku_cck_delta_map), + SKU_GROUP(SKU_OFDM, 8, 0x254, 0x29d, sku_ofdm_delta_map), + + SKU_GROUP(SKU_HT_BW20, 8, 0x259, 0x2a2, sku_mcs_delta_map), + SKU_GROUP(SKU_HT_BW40, 9, 0x262, 0x2ab, sku_mcs_delta_map), + SKU_GROUP(SKU_VHT_BW20, 12, 0x259, 0x2a2, sku_mcs_delta_map), + SKU_GROUP(SKU_VHT_BW40, 12, 0x262, 0x2ab, sku_mcs_delta_map), + SKU_GROUP(SKU_VHT_BW80, 12, 0, 0x2b4, sku_mcs_delta_map), + SKU_GROUP(SKU_VHT_BW160, 12, 0, 0, sku_mcs_delta_map), + + SKU_GROUP(SKU_HE_RU26, 12, 0x27f, 0x2dd, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU52, 12, 0x289, 0x2e7, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU106, 12, 0x293, 0x2f1, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU242, 12, 0x26b, 0x2bf, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU484, 12, 0x275, 0x2c9, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU996, 12, 0, 0x2d3, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU2x996, 12, 0, 0, sku_mcs_delta_map), +}; + +static s8 +mt7915_get_sku_delta(struct mt7915_dev *dev, u32 addr) +{ + u32 val = mt7915_eeprom_read(dev, addr); + s8 delta = FIELD_GET(SKU_DELTA_VAL, val); + + if (!(val & SKU_DELTA_EN)) + return 0; + + return val & SKU_DELTA_ADD ? delta : -delta; +} + +static void +mt7915_eeprom_init_sku_band(struct mt7915_dev *dev, + struct ieee80211_supported_band *sband) +{ + int i, band = sband->band; + s8 *rate_power = dev->rate_power[band], max_delta = 0; + u8 idx = 0; + + for (i = 0; i < ARRAY_SIZE(mt7915_sku_groups); i++) { + const struct sku_group *sku = &mt7915_sku_groups[i]; + u32 offset = sku->offset[band]; + int j; + + if (!offset) { + idx += sku->len; + continue; + } + + rate_power[idx++] = mt7915_get_sku_delta(dev, offset); + if (rate_power[idx - 1] > max_delta) + max_delta = rate_power[idx - 1]; + + if (i == SKU_HT_BW20 || i == SKU_VHT_BW20) + offset += 1; + + for (j = 1; j < sku->len; j++) { + u32 addr = offset + sku->delta_map[j]; + + rate_power[idx++] = mt7915_get_sku_delta(dev, addr); + if (rate_power[idx - 1] > max_delta) + max_delta = rate_power[idx - 1]; + } + } + + rate_power[idx] = max_delta; +} + +void mt7915_eeprom_init_sku(struct mt7915_dev *dev) +{ + mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_2g.sband); + mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_5g.sband); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index 30fc607e466d..4e31d6ab4fa6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -37,6 +37,51 @@ enum mt7915_eeprom_band { MT_EE_DBDC, }; +#define SKU_DELTA_VAL GENMASK(5, 0) +#define SKU_DELTA_ADD BIT(6) +#define SKU_DELTA_EN BIT(7) + +enum mt7915_sku_delta_group { + SKU_CCK_GROUP0, + SKU_CCK_GROUP1, + + SKU_OFDM_GROUP0 = 0, + SKU_OFDM_GROUP1, + SKU_OFDM_GROUP2, + SKU_OFDM_GROUP3, + SKU_OFDM_GROUP4, + + SKU_MCS_GROUP0 = 0, + SKU_MCS_GROUP1, + SKU_MCS_GROUP2, + SKU_MCS_GROUP3, + SKU_MCS_GROUP4, + SKU_MCS_GROUP5, + SKU_MCS_GROUP6, + SKU_MCS_GROUP7, + SKU_MCS_GROUP8, + SKU_MCS_GROUP9, +}; + +enum mt7915_sku_rate_group { + SKU_CCK, + SKU_OFDM, + SKU_HT_BW20, + SKU_HT_BW40, + SKU_VHT_BW20, + SKU_VHT_BW40, + SKU_VHT_BW80, + SKU_VHT_BW160, + SKU_HE_RU26, + SKU_HE_RU52, + SKU_HE_RU106, + SKU_HE_RU242, + SKU_HE_RU484, + SKU_HE_RU996, + SKU_HE_RU2x996, + MAX_SKU_RATE_GROUP_NUM, +}; + struct sku_group { u8 len; u16 offset[2]; @@ -75,4 +120,6 @@ mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_2G; } +extern const struct sku_group mt7915_sku_groups[]; + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index f9384e1dab74..abce37ca9252 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -85,6 +85,8 @@ static void mt7915_init_txpower(struct mt7915_dev *dev) { mt7915_init_txpower_band(dev, &dev->mphy.sband_2g.sband); mt7915_init_txpower_band(dev, &dev->mphy.sband_5g.sband); + + mt7915_eeprom_init_sku(dev); } static void mt7915_init_work(struct work_struct *work) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index ae5ed41d337b..231bae4184ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -42,6 +42,7 @@ static int mt7915_start(struct ieee80211_hw *hw) mt7915_mcu_set_scs(dev, 1, true); } + mt7915_mcu_set_sku_en(phy, true); mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); @@ -325,6 +326,12 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed) ieee80211_wake_queues(hw); } + if (changed & IEEE80211_CONF_CHANGE_POWER) { + ret = mt7915_mcu_set_sku(phy); + if (ret) + return ret; + } + mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index dad2c300d0f2..b275d18e5d9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2295,6 +2295,54 @@ int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) sizeof(req), false); } +int mt7915_mcu_set_sku(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct mt7915_sku_val { + u8 format_id; + u8 limit_type; + u8 dbdc_idx; + s8 val[MT7915_SKU_RATE_NUM]; + } __packed req = { + .format_id = 4, + .dbdc_idx = phy != &dev->phy, + }; + int i; + s8 *delta; + + delta = dev->rate_power[mphy->chandef.chan->band]; + mphy->txpower_cur = hw->conf.power_level * 2 + + delta[MT7915_SKU_MAX_DELTA_IDX]; + + for (i = 0; i < MT7915_SKU_RATE_NUM; i++) + req.val[i] = hw->conf.power_level * 2 + delta[i]; + + return __mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable) +{ + struct mt7915_dev *dev = phy->dev; + struct mt7915_sku { + u8 format_id; + u8 sku_enable; + u8 dbdc_idx; + u8 rsv; + } __packed req = { + .format_id = 0, + .dbdc_idx = phy != &dev->phy, + .sku_enable = enable, + }; + + return __mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, + &req, sizeof(req), true); +} + int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) { struct { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 5e4708861ede..d9c9aab7e6dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -203,6 +203,7 @@ enum { MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, MCU_EXT_CMD_RX_HDR_TRANS = 0x47, MCU_EXT_CMD_SET_RX_PATH = 0x4e, + MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_SCS_CTRL = 0x82, MCU_EXT_CMD_RATE_CTRL = 0x87, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index b23ab3f215e0..6d3fde7f635a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -38,6 +38,9 @@ #define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */ #define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */ +#define MT7915_SKU_RATE_NUM 161 +#define MT7915_SKU_MAX_DELTA_IDX MT7915_SKU_RATE_NUM +#define MT7915_SKU_TABLE_SIZE (MT7915_SKU_RATE_NUM + 1) struct mt7915_vif; struct mt7915_sta; @@ -161,6 +164,8 @@ struct mt7915_dev { spinlock_t token_lock; struct idr token; + s8 **rate_power; /* TODO: use mt76_rate_power */ + u8 mac_work_count; bool fw_debug; }; @@ -268,6 +273,7 @@ u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset); int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, struct ieee80211_channel *chan, u8 chain_idx); +void mt7915_eeprom_init_sku(struct mt7915_dev *dev); int mt7915_dma_init(struct mt7915_dev *dev); void mt7915_dma_prefetch(struct mt7915_dev *dev); void mt7915_dma_cleanup(struct mt7915_dev *dev); @@ -303,6 +309,8 @@ int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable); int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band); int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val); int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter); +int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable); +int mt7915_mcu_set_sku(struct mt7915_phy *phy); int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, const struct mt7915_dfs_pulse *pulse); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index b79b5060cd77..7937c6965f59 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -75,6 +75,28 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) return IRQ_HANDLED; } +static int +mt7915_alloc_device(struct pci_dev *pdev, struct mt7915_dev *dev) +{ +#define NUM_BANDS 2 + int i; + s8 **sku; + + sku = devm_kzalloc(&pdev->dev, NUM_BANDS * sizeof(*sku), GFP_KERNEL); + if (!sku) + return -ENOMEM; + + for (i = 0; i < NUM_BANDS; i++) { + sku[i] = devm_kzalloc(&pdev->dev, MT7915_SKU_TABLE_SIZE * + sizeof(**sku), GFP_KERNEL); + if (!sku[i]) + return -ENOMEM; + } + dev->rate_power = sku; + + return 0; +} + static int mt7915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -118,6 +140,9 @@ static int mt7915_pci_probe(struct pci_dev *pdev, return -ENOMEM; dev = container_of(mdev, struct mt7915_dev, mt76); + ret = mt7915_alloc_device(pdev, dev); + if (ret) + return ret; mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) | From patchwork Fri Apr 24 19:32:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508955 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 678DF13B2 for ; Fri, 24 Apr 2020 19:43:34 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 442D92098B for ; Fri, 24 Apr 2020 19:43:34 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="cmYAj59r"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="c4fZSCA+" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 442D92098B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=ByHd6+HOZjeNW3QBUd38UnSJJVuUKliFydqYwHInUQw=; b=cmYAj59rW/l31x JaZcOHjRcE5nCPujLXs96mzPh+hnvOuTwIJBtw1YY8KA/OYxAdxl+8oZM/x7hLJ2tDEJQ4+OZuXzQ xD2WD5pQYFPSFc8XyDiNn+F13B/Nt4U/IrR48IY60+4Sqdy5AVESim8MPNUKQkjYAoNhmxg6rXx6C vLkJ/hMr8eRk24qGsbAvoWagWG8RryQ4rwpHsV91I5HqYS1ruohOdd5mWGzExx75dGN0Jyol8bD2g HUUsnzb0SMSJKpUCfokaSyU+Ph/ZHbQeDqQWSzdUMNS1EU3YxVHbW1EEgdvyBSJDnyxM11SeesQ3g cJDQJXi06UvuD+BFkYCA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EW-0006ds-8x; Fri, 24 Apr 2020 19:43:32 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EF-00061n-3X for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:19 +0000 X-UUID: edc7654416314b1990c55f9d9e8de185-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=i5/82YhnH3aELYgpcl6Y5zf/y9ZrirZKk1uprIaulSk=; b=c4fZSCA+0I/ic/zdfE54bqvgFAKHITxgC7plzhmkPxQUyK/emrE1TxZuXv84MPwbHMqqRYBB8C7EgEJB6X8/UGB1EHLfypuH6hVNygLAHtOKH5E7imFJlVQ5/X5YXYD1QRMvs12t5D+KAWVXUQNeV7hUAAAQCyVOwAs7ZV8AteE=; X-UUID: edc7654416314b1990c55f9d9e8de185-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1542248454; Fri, 24 Apr 2020 11:43:06 -0800 Received: from mtkmbs08n2.mediatek.inc (172.21.101.56) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:02 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:48 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:51 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 09/18] mt76: mt7915: register per-phy HE capabilities for each interface Date: Sat, 25 Apr 2020 03:32:30 +0800 Message-ID: <60ee4fb41774936e7eea3c36630062ea81108889.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-TM-SNTS-SMTP: 312FAC97239FB54FF3B8C3F6771A492F44D9CDB54E3248AAC24A778989CEDD7C2000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124315_196000_4D2C8915 X-CRM114-Status: GOOD ( 12.29 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org The capabilities for the HE interfaces are generated from the capabilities reported by the firmware. This should move to common file once we got other HE devices support. Signed-off-by: Ryder Lee --- .../net/wireless/mediatek/mt76/mt7915/init.c | 190 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/main.c | 1 + .../net/wireless/mediatek/mt76/mt7915/mcu.c | 9 + .../net/wireless/mediatek/mt76/mt7915/mcu.h | 3 + .../wireless/mediatek/mt76/mt7915/mt7915.h | 3 + 5 files changed, 206 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index abce37ca9252..bb8325e2edbd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -239,6 +239,194 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) hw->max_tx_fragments = 4; } +static void +mt7915_gen_ppe_thresh(u8 *he_ppet) +{ + int ru, nss, max_nss = 1, max_ru = 3; + u8 bit = 7, ru_bit_mask = 0x7; + u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71}; + + he_ppet[0] = max_nss & IEEE80211_PPE_THRES_NSS_MASK; + he_ppet[0] |= (ru_bit_mask << + IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS) & + IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK; + + for (nss = 0; nss <= max_nss; nss++) { + for (ru = 0; ru < max_ru; ru++) { + u8 val; + int i; + + if (!(ru_bit_mask & BIT(ru))) + continue; + + val = (ppet16_ppet8_ru3_ru0[nss] >> (ru * 6)) & + 0x3f; + val = ((val >> 3) & 0x7) | ((val & 0x7) << 3); + for (i = 5; i >= 0; i--) { + he_ppet[bit / 8] |= + ((val >> i) & 0x1) << ((bit % 8)); + bit++; + } + } + } +} + +static int +mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, + struct ieee80211_sband_iftype_data *data) +{ + int i, idx = 0; + int nss = hweight8(phy->chainmask); + u16 mcs_map = 0; + + for (i = 0; i < 8; i++) { + if (i < nss) + mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2)); + else + mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); + } + + for (i = 0; i < NUM_NL80211_IFTYPES; i++) { + struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap; + struct ieee80211_he_cap_elem *he_cap_elem = + &he_cap->he_cap_elem; + struct ieee80211_he_mcs_nss_supp *he_mcs = + &he_cap->he_mcs_nss_supp; + + switch (i) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_AP: +#ifdef CONFIG_MAC80211_MESH + case NL80211_IFTYPE_MESH_POINT: +#endif + break; + default: + continue; + } + + data[idx].types_mask = BIT(i); + he_cap->has_he = true; + + he_cap_elem->mac_cap_info[0] = + IEEE80211_HE_MAC_CAP0_HTC_HE; + he_cap_elem->mac_cap_info[1] = + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US | + IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1; + he_cap_elem->mac_cap_info[2] = + IEEE80211_HE_MAC_CAP2_BSR; + he_cap_elem->mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED; + he_cap_elem->mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU; + + if (band == NL80211_BAND_2GHZ) + he_cap_elem->phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; + else if (band == NL80211_BAND_5GHZ) + he_cap_elem->phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; + + he_cap_elem->phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; + he_cap_elem->phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; + + /* TODO: TxBF & MU & MESH */ + + switch (i) { + case NL80211_IFTYPE_AP: + he_cap_elem->mac_cap_info[0] |= + IEEE80211_HE_MAC_CAP0_TWT_RES; + he_cap_elem->mac_cap_info[4] |= + IEEE80211_HE_MAC_CAP4_BQR; + he_cap_elem->phy_cap_info[3] |= + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; + he_cap_elem->phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; + break; + case NL80211_IFTYPE_STATION: + he_cap_elem->mac_cap_info[0] |= + IEEE80211_HE_MAC_CAP0_TWT_REQ; + he_cap_elem->mac_cap_info[3] |= + IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED; + + if (band == NL80211_BAND_2GHZ) + he_cap_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G; + else if (band == NL80211_BAND_5GHZ) + he_cap_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; + + he_cap_elem->phy_cap_info[1] |= + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A; + he_cap_elem->phy_cap_info[8] |= + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; + break; +#ifdef CONFIG_MAC80211_MESH + case NL80211_IFTYPE_MESH_POINT: + break; +#endif + } + + he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map); + he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map); + he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map); + he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map); + he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map); + he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map); + + memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); + if (he_cap_elem->phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { + mt7915_gen_ppe_thresh(he_cap->ppe_thres); + } else { + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US; + } + idx++; + } + + return idx; +} + +void mt7915_set_stream_he_caps(struct mt7915_phy *phy) +{ + struct ieee80211_sband_iftype_data *data; + struct ieee80211_supported_band *band; + struct mt76_dev *mdev = &phy->dev->mt76; + int n; + + if (mdev->cap.has_2ghz) { + data = phy->iftype[NL80211_BAND_2GHZ]; + n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data); + + band = &phy->mt76->sband_2g.sband; + band->iftype_data = data; + band->n_iftype_data = n; + } + + if (mdev->cap.has_5ghz) { + data = phy->iftype[NL80211_BAND_5GHZ]; + n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data); + + band = &phy->mt76->sband_5g.sband; + band->iftype_data = data; + band->n_iftype_data = n; + } +} + static void mt7915_cap_dbdc_enable(struct mt7915_dev *dev) { @@ -256,6 +444,7 @@ mt7915_cap_dbdc_enable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; mt76_set_stream_caps(&dev->mt76, true); + mt7915_set_stream_he_caps(&dev->phy); } static void @@ -271,6 +460,7 @@ mt7915_cap_dbdc_disable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; mt76_set_stream_caps(&dev->mt76, true); + mt7915_set_stream_he_caps(&dev->phy); } int mt7915_register_ext_phy(struct mt7915_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 231bae4184ca..097225692026 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -691,6 +691,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) phy->chainmask = tx_ant; mt76_set_stream_caps(&dev->mt76, true); + mt7915_set_stream_he_caps(phy); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b275d18e5d9b..47c0ff8f41bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -137,11 +137,13 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, { struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; + const struct ieee80211_sta_he_cap *he_cap; u8 mode = 0; if (sta) { ht_cap = &sta->ht_cap; vht_cap = &sta->vht_cap; + he_cap = &sta->he_cap; } else { struct ieee80211_supported_band *sband; @@ -152,6 +154,7 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, ht_cap = &sband->ht_cap; vht_cap = &sband->vht_cap; + he_cap = ieee80211_get_he_iftype_cap(sband, vif->type); } if (band == NL80211_BAND_2GHZ) { @@ -159,6 +162,9 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, if (ht_cap->ht_supported) mode |= PHY_MODE_GN; + + if (he_cap->has_he) + mode |= PHY_MODE_AX_24G; } else if (band == NL80211_BAND_5GHZ) { mode |= PHY_MODE_A; @@ -167,6 +173,9 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, if (vht_cap->vht_supported) mode |= PHY_MODE_AC; + + if (he_cap->has_he) + mode |= PHY_MODE_AX_5G; } return mode; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index d9c9aab7e6dc..c71161aec767 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -815,6 +815,9 @@ enum { #define PHY_MODE_GN BIT(3) #define PHY_MODE_AN BIT(4) #define PHY_MODE_AC BIT(5) +#define PHY_MODE_AX_24G BIT(6) +#define PHY_MODE_AX_5G BIT(7) +#define PHY_MODE_AX_6G BIT(8) #define MODE_CCK BIT(0) #define MODE_OFDM BIT(1) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 6d3fde7f635a..92a6bf746d73 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -122,6 +122,8 @@ struct mt7915_phy { struct mt76_phy *mt76; struct mt7915_dev *dev; + struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES]; + u32 rxfilter; u32 vif_mask; u32 omac_mask; @@ -443,6 +445,7 @@ void mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *txwi); int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force); int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); +void mt7915_set_stream_he_caps(struct mt7915_phy *phy); void mt7915_update_channel(struct mt76_dev *mdev); int mt7915_init_debugfs(struct mt7915_dev *dev); From patchwork Fri Apr 24 19:32:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508911 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 04D6E14DD for ; Fri, 24 Apr 2020 19:33:09 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BE74E2098B for ; Fri, 24 Apr 2020 19:33:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="D4BT1cOE"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="PItxsjAY" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BE74E2098B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=DJFXdU/IrJXef5dczG0ze0CQ976QjkHiJLxpjuyd8dM=; b=D4BT1cOE+xSbtg gK+NPskRnoIUT8/wwmafBDtMxoxaK1RU2L6luFyCFL14L0GG4auMv4E7Ewslp3Ybxcgo28CHebzTe dydLkzKrtsfY+pJXj0ahBmvIjJZPn4zVUKttM1RztE/ZmwPlr8fRBUdWftSXhgJVW4GYBE70y/ZAi 0O1eOXGYe+2JM4l4GbYwFajKdaGmLAZSjbkH8dxoZ9Og0HwE3MGoezRLlqtitrG/DY3D5/kERvuZ/ EukybOX58q80zAAVNL6Eqks6S5N4KHY1gMdJpjzDhoJKrIZGYY31URJhBrZT8cQpRwFhjuOwZbcFC +y6HlJzrISe3A+o8f6VA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44Q-0007kU-OE; Fri, 24 Apr 2020 19:33:06 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44N-0007iy-Kh for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:33:05 +0000 X-UUID: 541cbb71983b4b2b9843b12ff8f55325-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=chXuOrwHh5hYrsCOMs+Oan8lRNozBmmkY4JoEsM4Cmg=; b=PItxsjAYTvGXsfQjeh0CsRsC0CIFLPSOwIBQmb5SuWZofNZ8s9LTUFMvhvTUTmL50eOTl5MTU+u82xFIfcWe/sdtUMbiHJY2QTFWGGLdW7gQUhGbFUGOx1mSKmbD6EmVgz8xR/dQ68oOmVrMcdwTUDhKNIxH6g2Q1EwWhWVn8/I=; X-UUID: 541cbb71983b4b2b9843b12ff8f55325-20200424 Received: from mtkcas67.mediatek.inc [(172.29.193.45)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 861475035; Fri, 24 Apr 2020 11:32:56 -0800 Received: from MTKMBS06N2.mediatek.inc (172.21.101.130) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:32:51 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs06n2.mediatek.inc (172.21.101.130) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:53 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:52 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 10/18] mt76: mt7915: add HE bss_conf support for interfaces Date: Sat, 25 Apr 2020 03:32:31 +0800 Message-ID: X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-TM-SNTS-SMTP: 6BC6014C5866F70415E6ED55340AF1DD1B7BDE26DDB44987FC4D0214266596552000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_123303_687747_EF8286D7 X-CRM114-Status: GOOD ( 11.49 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org Add basic HE BSS's info for interfaces. As for the advanced features will be added gradually in the future patches. (i.e. BSS color, TWT, spatial reuse and OFDMA) Signed-off-by: Ryder Lee Tested-by: Shayne Chen Tested-by: Chih-Min Chen Tested-by: Evelyn Tsai Acked-by: Yiwei Chung Acked-by: YF Luo --- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 95 ++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7915/mcu.h | 10 ++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 47c0ff8f41bf..61bab6bdcea0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -744,6 +744,47 @@ mt7915_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) omac->hw_bss_idx = idx; } +struct mt7915_he_obss_narrow_bw_ru_data { + bool tolerated; +}; + +static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, + struct cfg80211_bss *bss, + void *_data) +{ + struct mt7915_he_obss_narrow_bw_ru_data *data = _data; + const struct element *elem; + + elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, bss->ies->data, + bss->ies->len); + + if (!elem || elem->datalen < 10 || + !(elem->data[10] & + WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) + data->tolerated = false; +} + +static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7915_he_obss_narrow_bw_ru_data iter_data = { + .tolerated = true, + }; + + if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR)) + return false; + + cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef, + mt7915_check_he_obss_narrow_bw_ru_iter, + &iter_data); + + /* + * If there is at least one AP on radar channel that cannot + * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU. + */ + return !iter_data.tolerated; +} + static void mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt7915_phy *phy) @@ -766,7 +807,20 @@ mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, ch->center_ch1 = ieee80211_frequency_to_channel(freq2); } - ch->he_all_disable = true; + if (vif->bss_conf.he_support && vif->type == NL80211_IFTYPE_STATION) { + struct mt7915_dev *dev = phy->dev; + struct mt76_phy *mphy = &dev->mt76.phy; + bool ext_phy = phy != &dev->phy; + + if (ext_phy && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + ch->he_ru26_block = + mt7915_check_he_obss_narrow_bw_ru(mphy->hw, vif); + ch->he_all_disable = false; + } else { + ch->he_all_disable = true; + } } static void @@ -795,6 +849,42 @@ mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, ra->fast_interval = cpu_to_le32(100); } +static void +mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct mt7915_phy *phy) +{ +#define DEFAULT_HE_PE_DURATION 4 +#define DEFAULT_HE_DURATION_RTS_THRES 1023 + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + enum nl80211_band band = chandef->chan->band; + struct ieee80211_supported_band *sband; + const struct ieee80211_sta_he_cap *cap; + struct bss_info_he *he; + struct tlv *tlv; + + if (band == NL80211_BAND_2GHZ) + sband = &phy->mt76->sband_2g.sband; + else + sband = &phy->mt76->sband_5g.sband; + + cap = ieee80211_get_he_iftype_cap(sband, vif->type); + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he)); + + he = (struct bss_info_he *)tlv; + he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext * 4; + if (!he->he_pe_duration) + he->he_pe_duration = DEFAULT_HE_PE_DURATION; + + he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th * 32); + if (!he->he_rts_thres) + he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); + + he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; + he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; + he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; +} + static void mt7915_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7915_vif *mvif) { @@ -870,6 +960,9 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, mt7915_mcu_bss_bmc_tlv(skb, phy); mt7915_mcu_bss_ra_tlv(skb, vif, phy); + if (vif->bss_conf.he_support) + mt7915_mcu_bss_he_tlv(skb, vif, phy); + if (mvif->omac_idx > HW_BSSID_MAX) mt7915_mcu_bss_ext_tlv(skb, mvif); else diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index c71161aec767..85ef1b35b265 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -396,6 +396,16 @@ struct bss_info_ra { __le32 fast_interval; } __packed; +struct bss_info_he { + __le16 tag; + __le16 len; + u8 he_pe_duration; + u8 vht_op_info_present; + __le16 he_rts_thres; + __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; + u8 rsv[6]; +} __packed; + struct bss_info_bcn { __le16 tag; __le16 len; From patchwork Fri Apr 24 19:32:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508943 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3D081112C for ; Fri, 24 Apr 2020 19:43:22 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 177992173E for ; Fri, 24 Apr 2020 19:43:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="iQF84dL9"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="o8YoOOMA" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 177992173E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=0q8tuJC9uhtUH11djd0Sq75b/R+3pXzB7eslEG72XHI=; b=iQF84dL9ml2Gxz 7UZQnFmKOAUgixQgN0kxGj2rGH+/PoM3N/6Tlk+iOpMRfIKLbHto4vswQhdrx4Kb7w37mxLlDI2uY FQBDy8Vh5jhq0AVEFQwz2D0o0lqG5I22+S/DfMmPt2IbhN4tlRsh0jDA5K7OcUq0kmALxYv6ofcFt 6vrVdCvtCujCENsVn2UKG4ra0vy4Vm3U/bA0E9hOnOToxKOwL7bspb8HvyjNBmgI/ycs+pYDoasfU ofHvS1PdY+dmAeqCg3hKmOD9IvBo+W6HkjxA6c+Q4R6JW833SJVQ3zxwKHtoZapkRETGAclv/bu2u rMbXmfTeHvKwQuugTiqw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EJ-0006DL-R8; Fri, 24 Apr 2020 19:43:19 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EA-000625-V6 for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:12 +0000 X-UUID: 5a526fb7e7af4613964020971e64cc97-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=FlVtMxFH9Yu3gwmGonaYnKLJb4r+GKgCwe0en6YG9q0=; b=o8YoOOMAl0+wb6K/XqraKmxTESHZUdnljyDRM10qdB4kTYkXxu0SFnB4p9DYYmlBKiRMDby6eQQC97EPFPsSEg1ujZ93HLuM4ufGJV5KP+M5v6sZBbmOH/uo3XRGDNEbfvF0vtoFdapbWhV2wtsHoUhRFWzkb7Ta0aEqhZEDZQw=; X-UUID: 5a526fb7e7af4613964020971e64cc97-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1359977817; Fri, 24 Apr 2020 11:43:06 -0800 Received: from MTKMBS02N1.mediatek.inc (172.21.101.77) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:04 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs02n1.mediatek.inc (172.21.101.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:50 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:53 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 11/18] mt76: mt7915: add HE capabilities support for peers Date: Sat, 25 Apr 2020 03:32:32 +0800 Message-ID: <1e34e5449919c34a7fa0f69a200403927852582a.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124311_010112_6BDE6343 X-CRM114-Status: UNSURE ( 9.01 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org Set peer's bsic HE capabilities through starec. Signed-off-by: Ryder Lee Suggested-by: Shihwei Lin Tested-by: Shayne Chen Tested-by: Chih-Min Chen Tested-by: Evelyn Tsai Acked-by: Yiwei Chung Acked-by: YF Luo --- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 197 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.h | 100 +++++++++ 2 files changed, 297 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 61bab6bdcea0..aa24f1306941 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -85,6 +85,9 @@ struct mt7915_fw_region { #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) #define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) +#define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) +#define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) + static enum mt7915_cipher_type mt7915_mcu_get_cipher(int cipher) { @@ -1234,6 +1237,187 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, basic->qos = sta->wme; } +static void +mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +{ + struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; + struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + struct sta_rec_he *he; + struct tlv *tlv; + u32 cap = 0; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he)); + + he = (struct sta_rec_he *)tlv; + + if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) + cap |= STA_REC_HE_CAP_HTC; + + if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) + cap |= STA_REC_HE_CAP_BSR; + + if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) + cap |= STA_REC_HE_CAP_OM; + + if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU) + cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU; + + if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) + cap |= STA_REC_HE_CAP_BQR; + + if (elem->phy_cap_info[0] & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) + cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; + + if (elem->phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) + cap |= STA_REC_HE_CAP_LDPC; + + if (elem->phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US) + cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI; + + if (elem->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US) + cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI; + + if (elem->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ) + cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC; + + if (elem->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) + cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC; + + if (elem->phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) + cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE; + + if (elem->phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI) + cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI; + + if (elem->phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ) + cap |= STA_REC_HE_CAP_GT_80M_TX_STBC; + + if (elem->phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ) + cap |= STA_REC_HE_CAP_GT_80M_RX_STBC; + + if (elem->phy_cap_info[8] & + IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI) + cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI; + + if (elem->phy_cap_info[8] & + IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI) + cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI; + + if (elem->phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK) + cap |= STA_REC_HE_CAP_TRIG_CQI_FK; + + if (elem->phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU) + cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242; + + if (elem->phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU) + cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242; + + he->he_cap = cpu_to_le32(cap); + + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_160: + if (elem->phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) + he->max_nss_mcs[CMD_HE_MCS_BW8080] = + he_cap->he_mcs_nss_supp.rx_mcs_80p80; + + he->max_nss_mcs[CMD_HE_MCS_BW160] = + he_cap->he_mcs_nss_supp.rx_mcs_160; + /* fall through */ + default: + he->max_nss_mcs[CMD_HE_MCS_BW80] = + he_cap->he_mcs_nss_supp.rx_mcs_80; + break; + } + + he->t_frame_dur = + HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); + he->max_ampdu_exp = + HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]); + + he->bw_set = + HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]); + he->device_class = + HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]); + he->punc_pream_rx = + HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); + + he->dcm_tx_mode = + HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]); + he->dcm_tx_max_nss = + HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]); + he->dcm_rx_mode = + HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); + he->dcm_rx_max_nss = + HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); + he->dcm_rx_max_nss = + HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); + + he->pkt_ext = 2; +} + +static void +mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +{ + struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; + struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + struct sta_rec_muru *muru; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru)); + + muru = (struct sta_rec_muru *)tlv; + muru->cfg.ofdma_dl_en = true; + muru->cfg.ofdma_ul_en = true; + muru->cfg.mimo_dl_en = true; + muru->cfg.mimo_ul_en = true; + + muru->ofdma_dl.punc_pream_rx = + HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); + muru->ofdma_dl.he_20m_in_40m_2g = + HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]); + muru->ofdma_dl.he_20m_in_160m = + HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); + muru->ofdma_dl.he_80m_in_160m = + HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); + muru->ofdma_dl.lt16_sigb = 0; + muru->ofdma_dl.rx_su_comp_sigb = 0; + muru->ofdma_dl.rx_su_non_comp_sigb = 0; + + muru->ofdma_ul.t_frame_dur = + HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); + muru->ofdma_ul.mu_cascading = + HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]); + muru->ofdma_ul.uo_ra = + HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]); + muru->ofdma_ul.he_2x996_tone = 0; + muru->ofdma_ul.rx_t_frame_11ac = 0; + + muru->mimo_dl.vht_mu_bfee = + !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); + muru->mimo_dl.partial_bw_dl_mimo = + HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]); + + muru->mimo_ul.full_ul_mimo = + HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]); + muru->mimo_ul.partial_ul_mimo = + HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); +} + static void mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta) @@ -1259,6 +1443,14 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; } + + /* starec he */ + if (sta->he_cap.has_he) + mt7915_mcu_sta_he_tlv(skb, sta); + + /* starec muru */ + if (sta->he_cap.has_he || sta->vht_cap.vht_supported) + mt7915_mcu_sta_muru_tlv(skb, sta); } static void @@ -1454,6 +1646,11 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, } } + if (sta->he_cap.has_he) { + ra->supp_mode |= MODE_HE; + cap |= STA_CAP_HE; + } + ra->sta_status = cpu_to_le32(cap); switch (BIT(fls(ra->supp_mode) - 1)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 85ef1b35b265..cc0e27730aab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -658,6 +658,75 @@ struct sta_rec_vht { u8 rsv[3]; } __packed; +struct sta_rec_muru { + __le16 tag; + __le16 len; + + struct { + bool ofdma_dl_en; + bool ofdma_ul_en; + bool mimo_dl_en; + bool mimo_ul_en; + bool rsv[4]; + } cfg; + + struct { + u8 punc_pream_rx; + bool he_20m_in_40m_2g; + bool he_20m_in_160m; + bool he_80m_in_160m; + bool lt16_sigb; + bool rx_su_comp_sigb; + bool rx_su_non_comp_sigb; + bool rsv; + } ofdma_dl; + + struct { + u8 t_frame_dur; + u8 mu_cascading; + u8 uo_ra; + u8 he_2x996_tone; + u8 rx_t_frame_11ac; + u8 rsv[3]; + } ofdma_ul; + + struct { + bool vht_mu_bfee; + bool partial_bw_dl_mimo; + u8 rsv[2]; + } mimo_dl; + + struct { + bool full_ul_mimo; + bool partial_ul_mimo; + u8 rsv[2]; + } mimo_ul; +} __packed; + +struct sta_rec_he { + __le16 tag; + __le16 len; + + __le32 he_cap; + + u8 t_frame_dur; + u8 max_ampdu_exp; + u8 bw_set; + u8 device_class; + u8 dcm_tx_mode; + u8 dcm_tx_max_nss; + u8 dcm_rx_mode; + u8 dcm_rx_max_nss; + u8 dcm_max_ru; + u8 punc_pream_rx; + u8 pkt_ext; + u8 rsv1; + + __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; + + u8 rsv2[2]; +} __packed; + struct sta_rec_ba { __le16 tag; __le16 len; @@ -803,9 +872,11 @@ enum { #define MT7915_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct sta_rec_basic) + \ sizeof(struct sta_rec_ht) + \ + sizeof(struct sta_rec_he) + \ sizeof(struct sta_rec_ba) + \ sizeof(struct sta_rec_vht) + \ sizeof(struct tlv) + \ + sizeof(struct sta_rec_muru) + \ sizeof(struct sta_rec_sec) + \ sizeof(struct sta_rec_ra) + \ MT7915_WTBL_UPDATE_MAX_SIZE) @@ -833,6 +904,7 @@ enum { #define MODE_OFDM BIT(1) #define MODE_HT BIT(2) #define MODE_VHT BIT(3) +#define MODE_HE BIT(4) #define STA_CAP_WMM BIT(0) #define STA_CAP_SGI_20 BIT(4) @@ -847,5 +919,33 @@ enum { #define STA_CAP_LDPC BIT(24) #define STA_CAP_HT BIT(26) #define STA_CAP_VHT BIT(27) +#define STA_CAP_HE BIT(28) + +/* HE MAC */ +#define STA_REC_HE_CAP_HTC BIT(0) +#define STA_REC_HE_CAP_BQR BIT(1) +#define STA_REC_HE_CAP_BSR BIT(2) +#define STA_REC_HE_CAP_OM BIT(3) +#define STA_REC_HE_CAP_AMSDU_IN_AMPDU BIT(4) +/* HE PHY */ +#define STA_REC_HE_CAP_DUAL_BAND BIT(5) +#define STA_REC_HE_CAP_LDPC BIT(6) +#define STA_REC_HE_CAP_TRIG_CQI_FK BIT(7) +#define STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE BIT(8) +/* STBC */ +#define STA_REC_HE_CAP_LE_EQ_80M_TX_STBC BIT(9) +#define STA_REC_HE_CAP_LE_EQ_80M_RX_STBC BIT(10) +#define STA_REC_HE_CAP_GT_80M_TX_STBC BIT(11) +#define STA_REC_HE_CAP_GT_80M_RX_STBC BIT(12) +/* GI */ +#define STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI BIT(13) +#define STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI BIT(14) +#define STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI BIT(15) +#define STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI BIT(16) +#define STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI BIT(17) +/* 242 TONE */ +#define STA_REC_HE_CAP_BW20_RU242_SUPPORT BIT(18) +#define STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242 BIT(19) +#define STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242 BIT(20) #endif From patchwork Fri Apr 24 19:32:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508923 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E5566112C for ; Fri, 24 Apr 2020 19:33:13 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C3F4D2075A for ; Fri, 24 Apr 2020 19:33:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="BUJktPDg"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="JXmisCG7" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C3F4D2075A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=nrAkdJV7CoCporNX2wVpVmQsSk7m50QeBAiGn5E7CNY=; b=BUJktPDg5aA1Gb RBOSsJGHs1ZQmYHsukSJpzJ0mDO8Y5I35A0OZqsmkNc1hKsWRelsIHB1m7XWaffzuenwE939f/MKX HN12uVqVNxtuxSpVaOV8+Irk7Ad4PZVsNowXH4QNNa1ydNslG+MFnNq2oFbtlwFVeNY8Sr9X+Cfii fJYN8ee+x5EgAmpAng3Nnwpfv+1/daUt6nCtgYbIUKd5XmMt7NFrAr/+2y/ifnhnjUpIwIxIoDTs6 VwZ1e6WyfHYUPlVXKyc0q4CfEmhipUWjg02TuZ6xJpyU6AB+XhTScEWdTRtNjMbWtUt2htU4dp9PT GwvODBlD6HuGaQSgbuIw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44V-0007ob-Ov; Fri, 24 Apr 2020 19:33:11 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS44P-0007j0-13 for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:33:06 +0000 X-UUID: 01dd8b75f4814acab7e4b521f2723b31-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=t4VVOuf2GImWHETPeVHY5WaVAfPQ3wg19Rms0WFr6FU=; b=JXmisCG7LKzg8QsQn8Mx4KTf7U9MKUG0qlTBEar5+yS/oT7s5Y9YrUpx0jejX9rqOeKoiI8dATG/3xq8/Nls4tUEe/s1Gfgq1qjVeHuCpFj+xvXZLe7foyI9f13UaIculKBr6oQyI00nPRdhS7wwrG25oR/vMx4TB9UpDRvBl+w=; X-UUID: 01dd8b75f4814acab7e4b521f2723b31-20200424 Received: from mtkcas68.mediatek.inc [(172.29.94.19)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 862142608; Fri, 24 Apr 2020 11:32:58 -0800 Received: from MTKMBS06N1.mediatek.inc (172.21.101.129) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:32:53 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs06n1.mediatek.inc (172.21.101.129) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:55 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:54 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 12/18] mt76: mt7915: add Rx radiotap header support Date: Sat, 25 Apr 2020 03:32:33 +0800 Message-ID: <485e5f1958d7dce0a7ade9bc771097f9e20e5cb1.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_123305_081507_732B5E39 X-CRM114-Status: UNSURE ( 9.22 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org mac80211 expects the definition of what HE rate info is available inside astruct prepended to the skb. Signed-off-by: Ryder Lee --- .../net/wireless/mediatek/mt76/mt7915/mac.c | 141 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mac.h | 16 ++ 2 files changed, 157 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index dd5b30a066b3..751363b4b7a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -9,6 +9,10 @@ #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) +#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) +#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ + IEEE80211_RADIOTAP_HE_##f) + static const struct mt7915_dfs_radar_spec etsi_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { @@ -172,6 +176,138 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev) rcu_read_unlock(); } +static void +mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, + struct mt7915_rxv *rxv, + struct ieee80211_radiotap_he *he) +{ + u32 ru_h, ru_l; + u8 ru, offs = 0; + + ru_l = FIELD_GET(MT_PRXV_HE_RU_ALLOC_L, le32_to_cpu(rxv->v[0])); + ru_h = FIELD_GET(MT_PRXV_HE_RU_ALLOC_H, le32_to_cpu(rxv->v[1])); + ru = (u8)(ru_l | ru_h << 4); + + status->bw = RATE_INFO_BW_HE_RU; + + switch (ru) { + case 0 ... 36: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; + offs = ru; + break; + case 37 ... 52: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; + offs = ru - 37; + break; + case 53 ... 60: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; + offs = ru - 53; + break; + case 61 ... 64: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; + offs = ru - 61; + break; + case 65 ... 66: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; + offs = ru - 65; + break; + case 67: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + case 68: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; + break; + } + + he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); + he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) | + le16_encode_bits(offs, + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); +} + +static void +mt7915_mac_decode_he_radiotap(struct sk_buff *skb, + struct mt76_rx_status *status, + struct mt7915_rxv *rxv) +{ + /* TODO: struct ieee80211_radiotap_he_mu */ + static const struct ieee80211_radiotap_he known = { + .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | + HE_BITS(DATA1_DATA_DCM_KNOWN) | + HE_BITS(DATA1_STBC_KNOWN) | + HE_BITS(DATA1_CODING_KNOWN), + .data2 = HE_BITS(DATA2_GI_KNOWN) | + HE_BITS(DATA2_TXBF_KNOWN), + }; + struct ieee80211_radiotap_he *he = NULL; + __le32 v2 = rxv->v[2]; + __le32 v11 = rxv->v[11]; + __le32 v14 = rxv->v[14]; + u32 ltf_size = le32_get_bits(v2, MT_CRXV_HE_LTF_SIZE) + 1; + + he = skb_push(skb, sizeof(known)); + memcpy(he, &known, sizeof(known)); + + he->data1 = HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) | + HE_BITS(DATA1_DOPPLER_KNOWN) | + HE_BITS(DATA1_BSS_COLOR_KNOWN); + he->data2 = HE_BITS(DATA2_PE_DISAMBIG_KNOWN) | + HE_BITS(DATA2_TXOP_KNOWN); + + he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, v14) | + HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, v2); + he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, v2) | + le16_encode_bits(ltf_size, + IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); + he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, v14) | + HE_PREP(DATA6_DOPPLER, DOPPLER, v14); + + switch (rxv->phy) { + case MT_PHY_TYPE_HE_SU: + he->data1 |= HE_BITS(DATA1_FORMAT_SU) | + HE_BITS(DATA1_UL_DL_KNOWN) | + HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN); + + he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, v14) | + HE_PREP(DATA3_UL_DL, UPLINK, v2); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, v11); + break; + case MT_PHY_TYPE_HE_EXT_SU: + he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | + HE_BITS(DATA1_UL_DL_KNOWN); + + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, v2); + break; + case MT_PHY_TYPE_HE_MU: + he->data1 |= HE_BITS(DATA1_FORMAT_MU) | + HE_BITS(DATA1_UL_DL_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN); + + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, v2); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, v11); + + mt7915_mac_decode_he_radiotap_ru(status, rxv, he); + break; + case MT_PHY_TYPE_HE_TB: + he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE2_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE4_KNOWN); + + he->data4 = HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, v11) | + HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, v11) | + HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, v11) | + HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, v11); + + mt7915_mac_decode_he_radiotap_ru(status, rxv, he); + break; + default: + break; + } +} + int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -348,6 +484,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) return -EINVAL; break; case MT_PHY_TYPE_HE_MU: + status->flag |= RX_FLAG_RADIOTAP_HE_MU; /* fall through */ case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: @@ -355,6 +492,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) status->nss = FIELD_GET(MT_PRXV_NSTS, rxv.v[0]) + 1; status->encoding = RX_ENC_HE; + status->flag |= RX_FLAG_RADIOTAP_HE; i &= GENMASK(3, 0); if (gi <= NL80211_RATE_INFO_HE_GI_3_2) @@ -405,6 +543,9 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) mt76_insert_ccmp_hdr(skb, key_id); } + if (status->flag & RX_FLAG_RADIOTAP_HE) + mt7915_mac_decode_he_radiotap(skb, status, &rxv); + hdr = mt76_skb_get_hdr(skb); if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 712753484aee..b9bc8b25b031 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -101,6 +101,8 @@ enum rx_pkt_type { #define MT_PRXV_TX_ER_SU_106T BIT(5) #define MT_PRXV_NSTS GENMASK(9, 7) #define MT_PRXV_HT_AD_CODE BIT(11) +#define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28) +#define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0) #define MT_PRXV_RCPI3 GENMASK(31, 24) #define MT_PRXV_RCPI2 GENMASK(23, 16) #define MT_PRXV_RCPI1 GENMASK(15, 8) @@ -111,6 +113,20 @@ enum rx_pkt_type { #define MT_CRXV_TX_MODE GENMASK(7, 4) #define MT_CRXV_FRAME_MODE GENMASK(10, 8) #define MT_CRXV_HT_SHORT_GI GENMASK(14, 13) +#define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17) +#define MT_CRXV_HE_LDPC_EXT_SYM BIT(20) +#define MT_CRXV_HE_PE_DISAMBIG BIT(23) +#define MT_CRXV_HE_UPLINK BIT(31) + +#define MT_CRXV_HE_SR_MASK GENMASK(11, 8) +#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12) +#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17) +#define MT_CRXV_HE_SR3_MASK GENMASK(24, 21) + +#define MT_CRXV_HE_BSS_COLOR GENMASK(5, 0) +#define MT_CRXV_HE_TXOP_DUR GENMASK(12, 6) +#define MT_CRXV_HE_BEAM_CHNG BIT(13) +#define MT_CRXV_HE_DOPPLER BIT(16) struct mt7915_rxv { u32 phy; From patchwork Fri Apr 24 19:32:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508951 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A7B2F112C for ; Fri, 24 Apr 2020 19:43:31 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 83A452098B for ; Fri, 24 Apr 2020 19:43:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="J0ATodtb"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="ImratJ3f" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 83A452098B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=y9FBIpqf20WpZNfpnLzRVQnSF7bznVUXQ2At9rixiic=; b=J0ATodtbMIrLJA LiiMsus2GItkt+i3CSEZb1X63O/SQarg8ZPFuKJpeTs50CyPV/yIUJGXWroifDRugf4QABflvSnpD cjSy6919DshG4WvFWIue/Q2ByRZtNlWHMiYggYKFvQ2GgxTu+6XV+kSZtmiLL7130UHMwQE9JXWET geY4Vjbf8GZbwf1l4wRHz1GxJep9Wog0T5rihzsVEQTiP8hV+4hWkfGFuGspaUexvbWGaCQuQbenx h93c3Aj2wbBB7fUboxBFEyhGzhCRpaNgpDi/OwCDuE2DayZi//vo+67O5RRuzJ4S2NkuT6uQdo0Vg 7EDSvlmeT7D0yX3YNHrQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4ET-0006Zi-Ok; Fri, 24 Apr 2020 19:43:29 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EE-00065h-5b for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:15 +0000 X-UUID: e0e9bd76cef94235b154dc4806071c7b-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=FU4fnFK6FjATZkPgOccxNKSpbEJPY03LnfTBWhP01rs=; b=ImratJ3fT8WLivRtj6Px4LMooJMWaRYtC+prqoUZquGF1ybCl7ZctWNF7yMN4iPZ2vSc83svvxzAgC6XW0jFcAw7JtUTWVuhtQdWD9xoI48nfrujXUZwuJM9BPxQwb5EK7cAR1IHEQNeJ5IqcmJYy4LeOAmbgi8LbZ7PIQ9VFQU=; X-UUID: e0e9bd76cef94235b154dc4806071c7b-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1450620847; Fri, 24 Apr 2020 11:43:10 -0800 Received: from MTKMBS02N2.mediatek.inc (172.21.101.101) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:04 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs02n2.mediatek.inc (172.21.101.101) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:51 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:55 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 13/18] mt76: mt7915: add .sta_add_debugfs support Date: Sat, 25 Apr 2020 03:32:34 +0800 Message-ID: <8b725cdd9b9fb1c3ce3218d38f560203a761cb73.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-TM-SNTS-SMTP: 0116BC3C9EB0ECFBF45BBC0E442DC25C6A68AC45EE6A94034D87A64A1E0074022000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124314_222932_730CB759 X-CRM114-Status: UNSURE ( 8.95 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org This generation supports much more per-peer statistics than legacy ones, so add .sta_add_debugfs accordingly. This is convenient to set/get more settings/counters in the long run. Signed-off-by: Ryder Lee --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 65 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/main.c | 3 + .../wireless/mediatek/mt76/mt7915/mt7915.h | 4 ++ 3 files changed, 72 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 2e3f05f73697..7f67a1a8013b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -302,3 +302,68 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) return 0; } + +/** per-station debugfs **/ + +static int +mt7915_sta_stats_read(struct seq_file *s, void *data) +{ + struct ieee80211_sta *sta = s->private; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_sta_stats *stats = &msta->stats; + struct rate_info *rate = &stats->prob_rate; + static const char * const bw[] = { + "BW20", "BW5", "BW10", "BW40", + "BW80", "BW160", "BW_HE_RU" + }; + + if (!rate->legacy && !rate->flags) + return 0; + + seq_puts(s, "Probing rate - "); + if (rate->flags & RATE_INFO_FLAGS_MCS) + seq_puts(s, "HT "); + else if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) + seq_puts(s, "VHT "); + else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) + seq_puts(s, "HE "); + else + seq_printf(s, "Bitrate %d\n", rate->legacy); + + if (rate->flags) { + seq_printf(s, "%s NSS%d MCS%d ", + bw[rate->bw], rate->nss, rate->mcs); + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + seq_puts(s, "SGI "); + else if (rate->he_gi) + seq_puts(s, "HE GI "); + + if (rate->he_dcm) + seq_puts(s, "DCM "); + } + + seq_printf(s, "\nPPDU PER: %ld.%1ld%%\n", + stats->per / 10, stats->per % 10); + + return 0; +} + +static int +mt7915_sta_stats_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7915_sta_stats_read, inode->i_private); +} + +static const struct file_operations fops_sta_stats = { + .open = mt7915_sta_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct dentry *dir) +{ + debugfs_create_file("stats", 0400, dir, sta, &fops_sta_stats); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 097225692026..6cb69ae6cb0e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -746,4 +746,7 @@ const struct ieee80211_ops mt7915_ops = { .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, .set_coverage_class = mt7915_set_coverage_class, +#ifdef CONFIG_MAC80211_DEBUGFS + .sta_add_debugfs = mt7915_sta_add_debugfs, +#endif }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 92a6bf746d73..35e34d270c15 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -448,5 +448,9 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); void mt7915_set_stream_he_caps(struct mt7915_phy *phy); void mt7915_update_channel(struct mt76_dev *mdev); int mt7915_init_debugfs(struct mt7915_dev *dev); +#ifdef CONFIG_MAC80211_DEBUGFS +void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct dentry *dir); +#endif #endif From patchwork Fri Apr 24 19:32:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508945 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2A93E112C for ; Fri, 24 Apr 2020 19:43:24 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 099B12173E for ; Fri, 24 Apr 2020 19:43:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="lwCMLo9r"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="rYYrQl6l" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 099B12173E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=XXmR4PR/uPDL6rmdrXv/KLzDmLkPs0mCQzKNbkanBwU=; b=lwCMLo9rXVTb2M 3yjB77lpK0nZMTas0YwIfUIyZkGpzTkJf88N1hyXSYIo0Ku1CXAs2G96qUJ/3H8N7xTeOEJ8DM8QL q8mKMCm00fe8UtKTItTK5/Y7Si1vKEtPmBfqh91CdTMEbtXaGrBr7+shWntQuGy0RuvCU+UGWyN5P MUK46IPBCnqzm0ycjhQB5EtiW/zqWxTN9mKdh+7ACTMJZVvj4PY3JsnIFkMNTLJpXaIZXngRZDBJ0 hY79Wm11HCsQlk1pPrUgUdTmw9Bl7NiswmWGKQ9Yq2tU9qFhm1ma9vMrKBy/2/VhmDMbLEAVH0S3y Nt3pKibh1z1Nv9gIMXkQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EM-0006Fy-35; Fri, 24 Apr 2020 19:43:22 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EC-00061n-4J for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:13 +0000 X-UUID: eba66b22280c4cf584f809f2f9e7c61a-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=PM/tnHF829ngtHOTKKrhyuy84EmR7mXqLZMyji6w4Dc=; b=rYYrQl6lJx9gxom2Hz2TNMvXiZ9MeacubPDtiydbLeHx9nI1MVKXXdyNezSpGVUnW8hc7Mu7wyuLgd3eRk2m/T2Vjj05QUaxlUGYLGxBTREv5nwulflAzoADSHpgaUOJadiP1ETQLBSQjWf+opzB8g7IBWGaflwx62SVxDdf/Wg=; X-UUID: eba66b22280c4cf584f809f2f9e7c61a-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 849339699; Fri, 24 Apr 2020 11:43:06 -0800 Received: from mtkmbs08n1.mediatek.inc (172.21.101.55) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:01 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n1.mediatek.inc (172.21.101.55) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:52 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:55 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 14/18] mt76: mt7915: add .sta_statistics support Date: Sat, 25 Apr 2020 03:32:35 +0800 Message-ID: <3eb5f6555d9351aa9cf6ba551c806e025d9ec478.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124312_181621_BFEA36B2 X-CRM114-Status: UNSURE ( 7.44 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org Add useful debug counters since this generation uses struct rate_info to report HE tx rate. Signed-off-by: Ryder Lee --- .../net/wireless/mediatek/mt76/mt7915/main.c | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 6cb69ae6cb0e..b3e26ff32287 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -698,6 +698,31 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) return 0; } +static void mt7915_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_sta_stats *stats = &msta->stats; + + if (!stats->tx_rate.legacy && !stats->tx_rate.flags) + return; + + if (stats->tx_rate.legacy) { + sinfo->txrate.legacy = stats->tx_rate.legacy; + } else { + sinfo->txrate.mcs = stats->tx_rate.mcs; + sinfo->txrate.nss = stats->tx_rate.nss; + sinfo->txrate.bw = stats->tx_rate.bw; + sinfo->txrate.he_gi = stats->tx_rate.he_gi; + sinfo->txrate.he_dcm = stats->tx_rate.he_dcm; + sinfo->txrate.he_ru_alloc = stats->tx_rate.he_ru_alloc; + } + sinfo->txrate.flags = stats->tx_rate.flags; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); +} + static void mt7915_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -746,6 +771,7 @@ const struct ieee80211_ops mt7915_ops = { .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, .set_coverage_class = mt7915_set_coverage_class, + .sta_statistics = mt7915_sta_statistics, #ifdef CONFIG_MAC80211_DEBUGFS .sta_add_debugfs = mt7915_sta_add_debugfs, #endif From patchwork Fri Apr 24 19:32:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508953 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 182F413B2 for ; Fri, 24 Apr 2020 19:43:33 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EAD362098B for ; Fri, 24 Apr 2020 19:43:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="o9t9C4WD"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="GhURu43i" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EAD362098B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=TfHJxpdTg5h6r4BRRLqMcv2pkRduKKBqgbvYW1dRR7I=; b=o9t9C4WDfBLR0c VRKpEKjY8jfQZZ3rXLPhKYNd8hlrZiWa2OYywg58TEE828lZp1xt3xMINk1JhUoVxQb6x7ewzKw0G f3Tb4sZe3QmxoVCz1cotTP/yg8yAqwyKVSLCSvJkKmcnuuTkbwCThS78Kh5bDWmzqRLELL9924oq1 /QFQNjVjr2rnBc5nxXghrFSB4qJjIIUCk6WIMY8n3D7BVQfSqTzowoygW9gALBnzrOlux9y+DiNIk PgE7ufhC6cK4IP8BRtpkek+3hA6RJ9QOJMW57cTCgxbZR1WQ7UnbkD8ssJTZoWZcYUI9/2nr+lVvD RCUV65Uw6UL1Tqt43zoQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EV-0006bQ-3d; Fri, 24 Apr 2020 19:43:31 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EE-00067A-5Y for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:18 +0000 X-UUID: 87ecb31feb2a4e2a9bb5ecaf31af877a-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=Dhp8tKK52n3yoODGWyE5hR5OT1QU6XvTqCmCtQv21/k=; b=GhURu43iLOoY8XVnNBmparOgIPi2iM6LQLd0znTO/cCTmoQ4VBPLYelRUyCc1AaC2jUvItERMDQHCRtnvK0pn4rdMyo5btCemGU9rFMarybidEue71/GGU5qEercT7wC3PgVln7bQ1YKXjzJbAIk9jmTC60t5VQl4nG/TI9LLJM=; X-UUID: 87ecb31feb2a4e2a9bb5ecaf31af877a-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1256326307; Fri, 24 Apr 2020 11:43:10 -0800 Received: from MTKMBS02N2.mediatek.inc (172.21.101.101) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:05 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs02n2.mediatek.inc (172.21.101.101) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:53 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:56 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 15/18] mt76: mt7915: set peer Tx fixed rate through debugfs Date: Sat, 25 Apr 2020 03:32:36 +0800 Message-ID: <76828f8fb5753181546daf9c709c819421b7a5e0.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-TM-SNTS-SMTP: 75C50582A5C776BDEC4AE8153D2A5573093721EE63C5ADAF87DAB4302C3AA7892000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124314_232458_E4492385 X-CRM114-Status: UNSURE ( 9.96 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org Driver can manually set fixed rate for each peer through debugfs. May use .set_bitrate_mask callback and iterate stations under the current vif to achieve the aim once it supports HE rate. Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 13 ++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.c | 46 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.h | 28 +++++++++++ .../wireless/mediatek/mt76/mt7915/mt7915.h | 2 + 4 files changed, 89 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 7f67a1a8013b..cf3b60ded6ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -305,6 +305,18 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) /** per-station debugfs **/ +/* usage: */ +static int mt7915_sta_fixed_rate_set(void *data, u64 rate) +{ + struct ieee80211_sta *sta = data; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + + return mt7915_mcu_set_fixed_rate(msta->vif->dev, sta, rate); +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL, + mt7915_sta_fixed_rate_set, "%llx\n"); + static int mt7915_sta_stats_read(struct seq_file *s, void *data) { @@ -365,5 +377,6 @@ static const struct file_operations fops_sta_stats = { void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { + debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate); debugfs_create_file("stats", 0400, dir, sta, &fops_sta_stats); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index aa24f1306941..cbf96a56947a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1735,6 +1735,52 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, return 0; } +int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, + struct ieee80211_sta *sta, u32 rate) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_vif *mvif = msta->vif; + struct sta_rec_ra_fixed *ra; + struct sk_buff *skb; + struct tlv *tlv; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra)); + ra = (struct sta_rec_ra_fixed *)tlv; + + if (!rate) { + ra->field = cpu_to_le32(RATE_PARAM_AUTO); + goto out; + } else { + ra->field = cpu_to_le32(RATE_PARAM_FIXED); + } + + ra->phy.type = FIELD_GET(RATE_CFG_PHY_TYPE, rate); + ra->phy.bw = FIELD_GET(RATE_CFG_BW, rate); + ra->phy.nss = FIELD_GET(RATE_CFG_NSS, rate); + ra->phy.mcs = FIELD_GET(RATE_CFG_MCS, rate); + ra->phy.stbc = FIELD_GET(RATE_CFG_STBC, rate); + + if (ra->phy.bw) + ra->phy.ldpc = 7; + else + ra->phy.ldpc = FIELD_GET(RATE_CFG_LDPC, rate) * 7; + + /* HT/VHT - SGI: 1, LGI: 0; HE - SGI: 0, MGI: 1, LGI: 2 */ + if (ra->phy.type > MT_PHY_TYPE_VHT) + ra->phy.sgi = ra->phy.mcs * 85; + else + ra->phy.sgi = ra->phy.mcs * 15; + +out: + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + int mt7915_mcu_add_dev_info(struct mt7915_dev *dev, struct ieee80211_vif *vif, bool enable) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index cc0e27730aab..b8d28d971974 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -803,6 +803,34 @@ struct sta_rec_ra { struct ra_phy phy; } __packed; +struct sta_rec_ra_fixed { + __le16 tag; + __le16 len; + + __le32 field; + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + struct ra_phy phy; + + u8 spe_en; + u8 short_preamble; + u8 is_5g; + u8 mmps_mode; +} __packed; + +#define RATE_PARAM_FIXED 3 +#define RATE_PARAM_AUTO 20 +#define RATE_CFG_MCS GENMASK(3, 0) +#define RATE_CFG_NSS GENMASK(7, 4) +#define RATE_CFG_GI GENMASK(11, 8) +#define RATE_CFG_BW GENMASK(15, 12) +#define RATE_CFG_STBC GENMASK(19, 16) +#define RATE_CFG_LDPC GENMASK(23, 20) +#define RATE_CFG_PHY_TYPE GENMASK(27, 24) + enum { STA_REC_BASIC, STA_REC_RA, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 35e34d270c15..e5821d144c85 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -303,6 +303,8 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd); int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif); +int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, + struct ieee80211_sta *sta, u32 rate); int mt7915_mcu_set_eeprom(struct mt7915_dev *dev); int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset); int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable, From patchwork Fri Apr 24 19:32:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508939 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 22867112C for ; Fri, 24 Apr 2020 19:43:19 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EBC282173E for ; Fri, 24 Apr 2020 19:43:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="kaqn3lDJ"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="rubHytii" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EBC282173E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=ORFChiQ/rXyeibeWJBqdnljF8+uU/nt1Y9Gr9c6yOwQ=; b=kaqn3lDJjEFhqE PwtgOGznQ/czDlYSPRjZ3atErsDltulkPP5PqcJ1hjEh2hlVhE1OXRmgg+kBtLX6SiFxuDvHIkng9 qdwPrXYmrS+DMSiqvZxGyXq44O92RZ87GVaHqH85svJ4fUzJbrvcnHg/VchWcnlFQVROkfUgIE519 UCmMqF5Kys1zkfKt7hbX8aIfDo9j25XCORRKssQBHlfO8AXxEj6mppx6u2Z57IzIZoQY6QRjaMKXK TN29y0ASG+ESqV+0uH3RRrzXNFpRbYsLDM7sZC25vxX46PbvBf8Qty1rVPFydnO5Om9BesgBPiB1A zFr0877vBHVJZSE85S5w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EE-00068I-Pm; Fri, 24 Apr 2020 19:43:14 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4E9-000625-LJ for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:10 +0000 X-UUID: 3dbcd8aa82424d6f8629e5e28ee06aa7-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=PrMrGQUfXMNhRG58H8+GNHeDRKweulvlAJdxD1OYkqE=; b=rubHytii83DqpNwO38tQE8V665XJLH7JexkKVj8Apop3G4UIHky+A4JrZqHuzalTEJDW3b6AvU9zfXT2KqWKfUrUUSt+g1GPgOnGGArQKTITTdkdicsAMCsXCz5BO4OmZCMuuiOHBt8EleCmL2yqWOSxZ4b5tBU7IDh/wV/2s8w=; X-UUID: 3dbcd8aa82424d6f8629e5e28ee06aa7-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 184703056; Fri, 24 Apr 2020 11:43:06 -0800 Received: from MTKMBS02N1.mediatek.inc (172.21.101.77) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:04 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs02n1.mediatek.inc (172.21.101.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:54 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:57 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 16/18] mt76: mt7915: add tsf related callbacks Date: Sat, 25 Apr 2020 03:32:37 +0800 Message-ID: <5423850c6348b9d0b0c2ec443c3a1ae4ef06931c.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124309_697941_0BFB14E6 X-CRM114-Status: UNSURE ( 7.33 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org It is useful for IBSS Mesh to adjust t_clockdrift. Signed-off-by: Ryder Lee Reported-by: Shayne Chen Tested-by: Evelyn Tsai --- .../net/wireless/mediatek/mt76/mt7915/main.c | 53 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/regs.h | 11 ++++ 2 files changed, 64 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index b3e26ff32287..ef0c91990b49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -655,6 +655,57 @@ mt7915_get_stats(struct ieee80211_hw *hw, return 0; } +static u64 +mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + union { + u64 t64; + u32 t32[2]; + } tsf; + u16 n; + + mutex_lock(&dev->mt76.mutex); + + n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; + /* TSF software read */ + mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE); + tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band)); + tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band)); + + mutex_unlock(&dev->mt76.mutex); + + return tsf.t64; +} + +static void +mt7915_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 timestamp) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + union { + u64 t64; + u32 t32[2]; + } tsf = { .t64 = timestamp, }; + u16 n; + + mutex_lock(&dev->mt76.mutex); + + n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; + mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); + mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); + /* TSF software overwrite */ + mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_WRITE); + + mutex_unlock(&dev->mt76.mutex); +} + static void mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { @@ -767,6 +818,8 @@ const struct ieee80211_ops mt7915_ops = { .get_txpower = mt76_get_txpower, .channel_switch_beacon = mt7915_channel_switch_beacon, .get_stats = mt7915_get_stats, + .get_tsf = mt7915_get_tsf, + .set_tsf = mt7915_set_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 572bdc16fb2d..6600fc625196 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -75,6 +75,17 @@ #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) #define MT_DMA_DCR0_RXD_G5_EN BIT(23) +/* LPON: band 0(0x24200), band 1(0xa4200) */ +#define MT_WF_LPON_BASE(_band) ((_band) ? 0xa4200 : 0x24200) +#define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs)) + +#define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x080) +#define MT_LPON_UTTR1(_band) MT_WF_LPON(_band, 0x084) + +#define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (n) * 4) +#define MT_LPON_TCR_SW_MODE GENMASK(1, 0) +#define MT_LPON_TCR_SW_WRITE BIT(0) + /* MIB: band 0(0x24800), band 1(0xa4800) */ #define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) From patchwork Fri Apr 24 19:32:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508957 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0BD1F112C for ; Fri, 24 Apr 2020 19:43:36 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DACF92098B for ; Fri, 24 Apr 2020 19:43:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="p1RWoS/y"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="OomgM+g+" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DACF92098B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=VfKJ/coRJ9ZeGnskNA+pSIPNmF10iclMaWqJwrbNSPs=; b=p1RWoS/ygu99OS Pyffxb/+78N+EYV2Y6bnGji6swqE40MuXxxUHK/gX4146ZcICqt92MlIcdynVJ4OhvkXDC/0YbFQU oVM/YoEpGN54rGahdn2FvA2PlnLxEEKn0+2m6jiGadU3tCsQ8KWU4Q2RwOwS9w7j+UtKuKQ9kSU/c b0o5onQZSxyDXFbbctDbaR3JKVklI1zyh+44qPtwSkQz9t50CNuTQT29sqP7YlYnanID0458x5WD7 S7Sj2lA+vsqB+FF8x9yZRMcWNcWwna0oWiGf3X0i7/r3Ht0z9JDc3QuZ8JjVxCWNj5y04gGY/pfdn CWjN4WNgYEMN/eJPNrTw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EX-0006gO-Jk; Fri, 24 Apr 2020 19:43:33 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EF-00065h-Rt for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:18 +0000 X-UUID: 9ac04eae7c6e423aa3795804217a5679-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=aFrIehZ9m26QEoPLHcRTO89hzyqV0PLUvRh73959jlw=; b=OomgM+g+bfFEkTLcmvMY68DFTWsV98fqXbv4PR4kv99KAQi7L/1lE7WzIMhrhZ5A3hxC6V4ToNSRLIlYI0MOL3iXiebvTnjsAd5Lt1dP32HuVAcYOGPS6ZewmBoat1mS4NMzAU0xeQ91deBQ4yGetK5A5C/CtPQs/6wwt9TLFrc=; X-UUID: 9ac04eae7c6e423aa3795804217a5679-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 1648609913; Fri, 24 Apr 2020 11:43:10 -0800 Received: from MTKMBS02N2.mediatek.inc (172.21.101.101) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:06 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs02n2.mediatek.inc (172.21.101.101) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:54 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:58 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 17/18] mt76: mt7915: enable firmware module debug support Date: Sat, 25 Apr 2020 03:32:38 +0800 Message-ID: <5dfe54f1f2b37383a52509aa62c03bc52f7295fc.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-TM-SNTS-SMTP: 07A1567042708B1E617CEFC6098BCA9199495D10D1FD39E5CACDAFF79DBE75AD2000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124315_979884_94429DA7 X-CRM114-Status: UNSURE ( 9.60 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org This allows host driver to get useful information of some important modules. Signed-off-by: Ryder Lee Signed-off-by: Chih-Min Chen --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 36 ++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.c | 58 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.h | 3 + .../wireless/mediatek/mt76/mt7915/mt7915.h | 2 + 4 files changed, 99 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index cf3b60ded6ef..c6c009cd773e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -74,6 +74,41 @@ mt7915_dbdc_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_dbdc, mt7915_dbdc_get, mt7915_dbdc_set, "%lld\n"); +static int +mt7915_fw_debug_set(void *data, u64 val) +{ + struct mt7915_dev *dev = data; + enum { + DEBUG_TXCMD = 62, + DEBUG_CMD_RPT_TX, + DEBUG_CMD_RPT_TRIG, + DEBUG_SPL, + DEBUG_RPT_RX, + } debug; + + dev->fw_debug = !!val; + + mt7915_mcu_fw_log_2_host(dev, dev->fw_debug ? 2 : 0); + + for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) + mt7915_mcu_fw_dbg_ctrl(dev, debug, dev->fw_debug); + + return 0; +} + +static int +mt7915_fw_debug_get(void *data, u64 *val) +{ + struct mt7915_dev *dev = data; + + *val = dev->fw_debug; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7915_fw_debug_get, + mt7915_fw_debug_set, "%lld\n"); + static void mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, struct seq_file *file) @@ -290,6 +325,7 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) mt7915_queues_acq); debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats); debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc); + debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); /* test knobs */ debugfs_create_file("radar_trigger", 0200, dir, dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index cbf96a56947a..3e3d6f1d555a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -502,6 +502,28 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) } } +static void +mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + const char *data = (char *)&rxd[1]; + const char *type; + + switch (rxd->s2d_index) { + case 0: + type = "WM"; + break; + case 2: + type = "WA"; + break; + default: + type = "unknown"; + break; + } + + wiphy_info(mt76_hw(dev)->wiphy, "%s: %s", type, data); +} + static void mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) { @@ -519,6 +541,9 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) case MCU_EXT_EVENT_RATE_REPORT: mt7915_mcu_tx_rate_report(dev, skb); break; + case MCU_EXT_EVENT_FW_LOG_2_HOST: + mt7915_mcu_rx_log_message(dev, skb); + break; default: break; } @@ -544,6 +569,7 @@ void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || + rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || @@ -2265,6 +2291,37 @@ static int mt7915_load_firmware(struct mt7915_dev *dev) return 0; } +int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl) +{ + struct { + u8 ctrl_val; + u8 pad[3]; + } data = { + .ctrl_val = ctrl + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_LOG_2_HOST, + &data, sizeof(data), true); +} + +int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level) +{ + struct { + u8 ver; + u8 pad; + u16 len; + u8 level; + u8 rsv[3]; + u32 module_idx; + } data = { + .module_idx = cpu_to_le32(module), + .level = level, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_DBG_CTRL, + &data, sizeof(data), false); +} + int mt7915_mcu_init(struct mt7915_dev *dev) { static const struct mt76_mcu_ops mt7915_mcu_ops = { @@ -2286,6 +2343,7 @@ int mt7915_mcu_init(struct mt7915_dev *dev) return ret; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + mt7915_mcu_fw_log_2_host(dev, 0); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index b8d28d971974..f68d2094ac6f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -38,6 +38,7 @@ enum { /* ext event table */ enum { MCU_EXT_EVENT_PS_SYNC = 0x5, + MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13, MCU_EXT_EVENT_THERMAL_PROTECT = 0x22, MCU_EXT_EVENT_ASSERT_DUMP = 0x23, MCU_EXT_EVENT_RDD_REPORT = 0x3a, @@ -192,6 +193,7 @@ enum { MCU_EXT_CMD_EFUSE_ACCESS = 0x01, MCU_EXT_CMD_PM_STATE_CTRL = 0x07, MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, + MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, MCU_EXT_CMD_STA_REC_UPDATE = 0x25, MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, @@ -207,6 +209,7 @@ enum { MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_SCS_CTRL = 0x82, MCU_EXT_CMD_RATE_CTRL = 0x87, + MCU_EXT_CMD_FW_DBG_CTRL = 0x95, MCU_EXT_CMD_SET_RDD_TH = 0x9d, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index e5821d144c85..43c956bc09f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -324,6 +324,8 @@ int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx); int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index); int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd, u8 index, u8 rx_sel, u8 val); +int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl); +int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level); void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb); void mt7915_mcu_exit(struct mt7915_dev *dev); From patchwork Fri Apr 24 19:32:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryder Lee X-Patchwork-Id: 11508941 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 626D7112C for ; Fri, 24 Apr 2020 19:43:20 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 412BD2173E for ; Fri, 24 Apr 2020 19:43:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="GZsha2uN"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="reZnLhCQ" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 412BD2173E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=VtHKjCsqdKGqq0XQt3Vz6ko1VGvSkyn1qZrKxlVwk14=; b=GZsha2uNqKvSy0 k0sekbRoXxa2Rcqet7K3QH1EmyaGDdYlOv4NNk9fq0fC5uv7hh4iOJS/PwJzTS+WG/QHdF3WmoB2U A/yGfFBeIiua+EnB7VhQZ/jb6CP++E2bFv6kPZFMmvjbjZZCZj1TnvU5jljL4esO/R/uMjJM++TMx hNrIzQ7pnDPLtTy0A7np8YXPg1cOLkfAKbx/n6+1Fb0PZ1n3DVGPG4xY3OKw2WzHpDhKThWluMpep 8dFkV3M6OLAAfnpB/0OLiVQiJpXw2HqeiMMoTd4P2Z1NE1l4/FulT8iqqlrJojfIjAvOlGbqJdTbd Ti9n8Wbz6k8/R38zmqfg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EG-0006An-Q0; Fri, 24 Apr 2020 19:43:18 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jS4EA-00061n-HX for linux-mediatek@lists.infradead.org; Fri, 24 Apr 2020 19:43:12 +0000 X-UUID: b221049664184fac9235c749aaf77e06-20200424 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=W8k18U645UditgqkusjztcWOOlcdOohCNT8efjekhkA=; b=reZnLhCQq8T5K4SrLSK8ClipJ8OOkRfle+lXacMExlXZWjpWWAjQlihn955emRn/V6YPk0HeGFGKKu7PwA5BhSLkQ9VlnS4F5f//3Z19PDzRXjPGjM6pCTaJU2+kuRc06VT8+Ys4ne9yEqhMihzeZ4kwva0sauFBwb/B6HJ74lI=; X-UUID: b221049664184fac9235c749aaf77e06-20200424 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 816248190; Fri, 24 Apr 2020 11:43:06 -0800 Received: from MTKMBS02N1.mediatek.inc (172.21.101.77) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 24 Apr 2020 12:33:05 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs02n1.mediatek.inc (172.21.101.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 25 Apr 2020 03:32:55 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 25 Apr 2020 03:32:58 +0800 From: Ryder Lee To: Felix Fietkau , Lorenzo Bianconi Subject: [PATCH v3 18/18] mt76: set runtime stream caps by mt76_phy Date: Sat, 25 Apr 2020 03:32:39 +0800 Message-ID: <19659d4b9b37892ed1004b869c2df89f7a8bb17c.1587756404.git.ryder.lee@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200424_124310_587201_5E3D662B X-CRM114-Status: UNSURE ( 9.53 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [216.200.240.184 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 encoding -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: YF Luo , Evelyn Tsai , linux-wireless@vger.kernel.org, Sean Wang , Chih-Min Chen , Ryder Lee , Yiwei Chung , linux-mediatek@lists.infradead.org, Shayne Chen Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org This patch can support concurrent dual-band operation. Signed-off-by: Ryder Lee --- drivers/net/wireless/mediatek/mt76/mac80211.c | 16 ++++++++-------- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2/pci_main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index f65e1b3e8f7a..21407704f1b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -116,12 +116,12 @@ static void mt76_led_cleanup(struct mt76_dev *dev) led_classdev_unregister(&dev->led_cdev); } -static void mt76_init_stream_cap(struct mt76_dev *dev, +static void mt76_init_stream_cap(struct mt76_phy *phy, struct ieee80211_supported_band *sband, bool vht) { struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; - int i, nstream = hweight8(dev->phy.antenna_mask); + int i, nstream = hweight8(phy->antenna_mask); struct ieee80211_sta_vht_cap *vht_cap; u16 mcs_map = 0; @@ -153,12 +153,12 @@ static void mt76_init_stream_cap(struct mt76_dev *dev, vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); } -void mt76_set_stream_caps(struct mt76_dev *dev, bool vht) +void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) { - if (dev->cap.has_2ghz) - mt76_init_stream_cap(dev, &dev->phy.sband_2g.sband, false); - if (dev->cap.has_5ghz) - mt76_init_stream_cap(dev, &dev->phy.sband_5g.sband, vht); + if (phy->dev->cap.has_2ghz) + mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); + if (phy->dev->cap.has_5ghz) + mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); } EXPORT_SYMBOL_GPL(mt76_set_stream_caps); @@ -199,7 +199,7 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - mt76_init_stream_cap(dev, sband, vht); + mt76_init_stream_cap(&dev->phy, sband, vht); if (!vht) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 254fbf5d094a..2d3062e6792f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -819,7 +819,7 @@ void mt76_set_channel(struct mt76_phy *phy); void mt76_update_survey(struct mt76_dev *dev); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); -void mt76_set_stream_caps(struct mt76_dev *dev, bool vht); +void mt76_set_stream_caps(struct mt76_phy *phy, bool vht); int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid, u16 ssn, u16 size); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 9880643888ba..b98ecf00bb08 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -291,7 +291,7 @@ mt7615_cap_dbdc_enable(struct mt7615_dev *dev) dev->phy.chainmask = dev->mphy.antenna_mask; dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); } static void @@ -304,7 +304,7 @@ mt7615_cap_dbdc_disable(struct mt7615_dev *dev) dev->phy.chainmask = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); } int mt7615_register_ext_phy(struct mt7615_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 4e1d162b2664..1be9a042314b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -784,7 +784,7 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) } phy->chainmask = tx_ant; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(phy->mt76, true); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index a74599f7f729..98f4cf398320 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -119,7 +119,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101; dev->mphy.antenna_mask = tx_ant; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); mt76x2_phy_set_antenna(dev); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index bb8325e2edbd..7d59571216e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -443,7 +443,7 @@ mt7915_cap_dbdc_enable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); mt7915_set_stream_he_caps(&dev->phy); } @@ -459,7 +459,7 @@ mt7915_cap_dbdc_disable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); mt7915_set_stream_he_caps(&dev->phy); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index ef0c91990b49..697045e65b24 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -741,7 +741,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) } phy->chainmask = tx_ant; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_he_caps(phy); mutex_unlock(&dev->mt76.mutex);