[PATCH 12/15] wifi: mt76: mt7925: add ULW event handling and peer ULW update

Sean Wang <[email protected]>
Newsgroups org.kernel.vger.linux-wireless,org.infradead.lists.linux-mediatek
Message-ID <[email protected]>
From: Stella Liu <[email protected]>

Forward NAN Unaligned Window attributes between FW and mac80211:
report ULW updates from FW via cfg80211_nan_ulw_update() and push
peer ULW attributes to FW with NAN_UNI_CMD_UPDATE_ULW.

Co-developed-by: Sean Wang <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
Signed-off-by: Stella Liu <[email protected]>
---
 .../net/wireless/mediatek/mt76/mt7925/nan.c   | 84 +++++++++++++++++++
 .../net/wireless/mediatek/mt76/mt7925/nan.h   | 40 ++++++++-
 2 files changed, 123 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
index 16fb196e1bf5..53736b156f69 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
@@ -397,6 +397,52 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
 	ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, true, GFP_KERNEL);
 }
 
+static void
+mt7925_nan_handle_ulw_update(struct mt792x_dev *dev, struct tlv *tlv)
+{
+	struct mt7925_nan_ulw_event *evt;
+	struct mt7925_nan_ulw_attr attr;
+	struct wireless_dev *wdev;
+	u16 len;
+
+	if (!dev || !tlv)
+		return;
+
+	if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif))
+		return;
+
+	len = le16_to_cpu(tlv->len);
+	if (len < sizeof(*tlv) + sizeof(*evt)) {
+		dev_warn(dev->mt76.dev,
+			 "nan: short ulw event tlv len=%u\n", len);
+		return;
+	}
+
+	evt = (struct mt7925_nan_ulw_event *)tlv->data;
+	wdev = ieee80211_vif_to_wdev(dev->nan_vif);
+	if (!wdev)
+		return;
+
+	dev_dbg(dev->mt76.dev,
+		"nan: ulw_update wdev=%p owner_nlportid=%u sched_id=%u seq=%u dur=%u\n",
+		wdev, wdev->owner_nlportid,
+		evt->sched_id, evt->seq_id, le32_to_cpu(evt->duration));
+
+	/* Reorder the FW fields into NAN spec Table 109 attribute layout */
+	attr.attr_id = NAN_ULW_ATTR_ID;
+	attr.length = cpu_to_le16(NAN_ULW_FIXED_PAYLOAD);
+	attr.sched_id = evt->sched_id;
+	attr.seq_id = evt->seq_id;
+	attr.start_time = evt->start_time;
+	attr.duration = evt->duration;
+	attr.period = evt->period;
+	attr.count_down = evt->count_down;
+	attr.ulw_overwrite = evt->ulw_overwrite;
+
+	cfg80211_nan_ulw_update(wdev, (const u8 *)&attr, sizeof(attr),
+				GFP_KERNEL);
+}
+
 void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
 {
 	struct tlv *tlv;
@@ -425,6 +471,9 @@ void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
 		case NAN_UNI_EVENT_REPORT_DW_START:
 			mt7925_nan_handle_dw_ind(dev, tlv);
 			break;
+		case NAN_UNI_EVENT_ID_ULW_UPDATE:
+			mt7925_nan_handle_ulw_update(dev, tlv);
+			break;
 		default:
 			break;
 		}
@@ -736,6 +785,37 @@ static int mt7925_nan_update_crb_tlv(struct sk_buff *skb,
 	return 0;
 }
 
+static int
+mt7925_nan_peer_ulw_tlv(struct sk_buff *skb,
+			struct ieee80211_sta *sta,
+			struct mt792x_sta *msta)
+{
+	struct mt7925_nan_update_ulw_tlv *ulw_tlv = NULL;
+	struct ieee80211_nan_peer_sched *sched = NULL;
+	struct tlv *tlv = NULL;
+
+	if (!skb || !sta || !msta)
+		return -EINVAL;
+
+	sched = sta->nan_sched;
+	if (!sched || !sched->init_ulw || !sched->ulw_size)
+		return 0; /* No ULW to send, not an error */
+
+	if (sched->ulw_size > NAN_ULW_MAX_SIZE)
+		return -EINVAL;
+
+	tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_ULW,
+				      sizeof(struct mt7925_nan_update_ulw_tlv));
+	if (!tlv)
+		return -ENOMEM;
+
+	ulw_tlv = (struct mt7925_nan_update_ulw_tlv *)tlv;
+	ether_addr_copy(ulw_tlv->nmi_addr, sta->addr);
+	memcpy(ulw_tlv->ulw_attr, sched->init_ulw, sched->ulw_size);
+
+	return 0;
+}
+
 int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,
 				 struct ieee80211_sta *sta)
 {
@@ -788,6 +868,10 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,
 		goto free_skb;
 	}
 
+	ret = mt7925_nan_peer_ulw_tlv(skb, sta, msta);
+	if (ret)
+		goto free_skb;
+
 	ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
 	if (ret && idx_allocated)
 		goto clear_idx;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
index 32e2e9cfffc7..c9207b5c899e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
@@ -50,7 +50,8 @@
 	(sizeof(struct mt7925_nan_common_hdr) +				\
 	 sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv) +		\
 	 sizeof(struct mt7925_nan_sched_update_peer_cap_tlv) +		\
-	 sizeof(struct mt7925_nan_sched_update_crb_tlv))
+	 sizeof(struct mt7925_nan_sched_update_crb_tlv) +		\
+	 sizeof(struct mt7925_nan_update_ulw_tlv))
 
 /* NAN Availability Attribute */
 #define NAN_AVAIL_ATTR_ID_OFFSET	0
@@ -81,6 +82,7 @@ enum nan_uni_cmd_tag {
 	NAN_UNI_CMD_UPDATE_CRB			= 10,
 	NAN_UNI_CMD_MANAGE_PEER_SCH_RECORD	= 12,
 	NAN_UNI_CMD_MAP_STA_RECORD		= 13,
+	NAN_UNI_CMD_UPDATE_ULW			= 16,
 	NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL	= 20,
 	NAN_UNI_CMD_UPDATE_PEER_CAPABILITY	= 21,
 	NAN_UNI_CMD_CHANGE_NMI_ADDRESS		= 24,
@@ -92,6 +94,7 @@ enum nan_uni_cmd_tag {
 
 enum nan_uni_event_tag {
 	NAN_UNI_EVENT_ID_DE_EVENT_IND		= 19,
+	NAN_UNI_EVENT_ID_ULW_UPDATE		= 39,
 	NAN_UNI_EVENT_REPORT_DW_START		= 59,
 	NAN_UNI_EVENT_REPORT_DW_END		= 60,
 };
@@ -165,6 +168,32 @@ struct nan_rpt_dw_evt {
 	__le16 dw_num;
 };
 
+#define NAN_ULW_ATTR_ID		0x17
+#define NAN_ULW_FIXED_PAYLOAD	16	/* Table 109 fixed fields */
+
+struct mt7925_nan_ulw_event {
+	u8 sched_id;
+	u8 seq_id;
+	u8 count_down;
+	u8 ulw_overwrite;
+	__le32 start_time;
+	__le32 duration;
+	__le32 period;
+} __packed;
+
+/* ULW attribute laid out in NAN spec Table 109 field order */
+struct mt7925_nan_ulw_attr {
+	u8 attr_id;
+	__le16 length;
+	u8 sched_id;
+	u8 seq_id;
+	__le32 start_time;
+	__le32 duration;
+	__le32 period;
+	u8 count_down;
+	u8 ulw_overwrite;
+} __packed;
+
 struct mt7925_nan_conf_dw {
 	u8 config_2dot4g_dw_band;
 	__le32 dw_2dot4g_interval_val;
@@ -389,6 +418,15 @@ struct mt7925_nan_sched_update_crb_tlv {
 	struct mt7925_nan_sched_faw_ndc_timeline faw_ndc_timeline[NAN_TIMELINE_MGMT_SIZE];
 } __packed __aligned(4);
 
+#define NAN_ULW_MAX_SIZE	256
+
+struct mt7925_nan_update_ulw_tlv {
+	__le16 tag;
+	__le16 len;
+	u8 nmi_addr[ETH_ALEN];
+	u8 ulw_attr[NAN_ULW_MAX_SIZE];
+} __packed __aligned(4);
+
 struct mt7925_nan_sched_map_sta_rec_tlv {
 	__le16 tag;
 	__le16 len;
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.