mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 14:33:24 -04:00
wifi: mt76: mt7996: handle UNI PS sync events
Enable MT_DRV_HW_PS_BUFFERING and handle MCU_UNI_EVENT_PS_SYNC with all three TLV formats (single client, multi-client packed entries, and bitmap). Link: https://patch.msgid.link/20260801145334.1166751-3-nbd@nbd.name Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
@@ -826,6 +826,89 @@ mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_mcu_ps_transition(struct mt7996_dev *dev, u16 wcid_idx, bool ps)
|
||||
{
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
wcid = mt76_wcid_ptr(dev, wcid_idx);
|
||||
if (!wcid || !wcid_to_sta(wcid))
|
||||
return;
|
||||
|
||||
mt76_sta_ps_transition(&dev->mt76, wcid, ps);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_mcu_rx_ps_sync(struct mt7996_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct mt7996_mcu_ps_sync_event *event = (void *)skb->data;
|
||||
struct tlv *tlv;
|
||||
int len;
|
||||
|
||||
if (skb->len < sizeof(*event))
|
||||
return;
|
||||
|
||||
skb_pull(skb, sizeof(*event));
|
||||
|
||||
len = skb->len;
|
||||
while (len >= sizeof(*tlv)) {
|
||||
u16 tag, tag_len;
|
||||
|
||||
tlv = (struct tlv *)skb->data;
|
||||
tag = le16_to_cpu(tlv->tag);
|
||||
tag_len = le16_to_cpu(tlv->len);
|
||||
/* a tag_len below the header size would not advance the buffer */
|
||||
if (tag_len < sizeof(*tlv) || tag_len > len)
|
||||
break;
|
||||
|
||||
switch (tag) {
|
||||
case UNI_PS_CLIENT_INFO: {
|
||||
struct mt7996_mcu_ps_client_info *info = (void *)tlv;
|
||||
|
||||
if (tag_len < sizeof(*info))
|
||||
break;
|
||||
|
||||
mt7996_mcu_ps_transition(dev,
|
||||
le16_to_cpu(info->wlan_idx),
|
||||
info->ps_bit);
|
||||
break;
|
||||
}
|
||||
case UNI_PS_MULTI_CLIENT_INFO: {
|
||||
struct mt7996_mcu_ps_multi_client_info *info = (void *)tlv;
|
||||
u16 cnt;
|
||||
int i;
|
||||
|
||||
if (tag_len < sizeof(*info))
|
||||
break;
|
||||
|
||||
cnt = min_t(u16, le16_to_cpu(info->sta_cnt),
|
||||
(tag_len - sizeof(*info)) / sizeof(info->sta_ps_info[0]));
|
||||
for (i = 0; i < cnt; i++) {
|
||||
u16 entry = le16_to_cpu(info->sta_ps_info[i]);
|
||||
|
||||
mt7996_mcu_ps_transition(dev,
|
||||
FIELD_GET(MT7996_PS_MULTI_WCID, entry),
|
||||
!!(entry & MT7996_PS_MULTI_PS_BIT));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UNI_PS_MULTI_CLIENT_INFO_BITMAP: {
|
||||
u8 *bitmap = tlv->data;
|
||||
int bitmap_len = tag_len - sizeof(*tlv);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bitmap_len * 8; i++)
|
||||
mt7996_mcu_ps_transition(dev, i,
|
||||
!!(bitmap[i / 8] & BIT(i % 8)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
skb_pull(skb, tag_len);
|
||||
len -= tag_len;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
@@ -847,6 +930,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
|
||||
case MCU_UNI_EVENT_WED_RRO:
|
||||
mt7996_mcu_wed_rro_event(dev, skb);
|
||||
break;
|
||||
case MCU_UNI_EVENT_PS_SYNC:
|
||||
mt7996_mcu_rx_ps_sync(dev, skb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -293,6 +293,39 @@ enum {
|
||||
UNI_WED_RRO_BA_SESSION_DELETE,
|
||||
};
|
||||
|
||||
struct mt7996_mcu_ps_sync_event {
|
||||
struct mt7996_mcu_rxd rxd;
|
||||
|
||||
u8 bss_idx;
|
||||
u8 __rsv[3];
|
||||
} __packed;
|
||||
|
||||
struct mt7996_mcu_ps_client_info {
|
||||
__le16 tag;
|
||||
__le16 len;
|
||||
u8 ps_bit;
|
||||
u8 __rsv;
|
||||
__le16 wlan_idx;
|
||||
u8 buffer_size;
|
||||
u8 __rsv2[3];
|
||||
} __packed;
|
||||
|
||||
struct mt7996_mcu_ps_multi_client_info {
|
||||
__le16 tag;
|
||||
__le16 len;
|
||||
__le16 sta_cnt;
|
||||
__le16 sta_ps_info[];
|
||||
} __packed;
|
||||
|
||||
#define MT7996_PS_MULTI_WCID GENMASK(10, 0)
|
||||
#define MT7996_PS_MULTI_PS_BIT BIT(15)
|
||||
|
||||
enum {
|
||||
UNI_PS_CLIENT_INFO = 0,
|
||||
UNI_PS_MULTI_CLIENT_INFO = 1,
|
||||
UNI_PS_MULTI_CLIENT_INFO_BITMAP = 2,
|
||||
};
|
||||
|
||||
struct mt7996_mcu_thermal_notify {
|
||||
struct mt7996_mcu_rxd rxd;
|
||||
|
||||
|
||||
@@ -838,7 +838,8 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
|
||||
.link_data_size = sizeof(struct mt7996_vif_link),
|
||||
.drv_flags = MT_DRV_TXWI_NO_FREE |
|
||||
MT_DRV_AMSDU_OFFLOAD |
|
||||
MT_DRV_HW_MGMT_TXQ,
|
||||
MT_DRV_HW_MGMT_TXQ |
|
||||
MT_DRV_HW_PS_BUFFERING,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX |
|
||||
SURVEY_INFO_TIME_RX |
|
||||
SURVEY_INFO_TIME_BSS_RX,
|
||||
|
||||
Reference in New Issue
Block a user