mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 10:33:41 +02:00
Fix connection issue caused by AMPDU frames with abnormal PN patterns (out-of-order packets with correct MPDU sequence numbers but paired with abnormal PN values, which is next PN of previous in-order packet). This is causing packet drops, low throughput and disconnections. It is observed in fields with some specific AP firmwares. Do this workaround for better interoperability since some APs could never receive a proper FW update. Signed-off-by: Po-Hao Huang <phhuang@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20260310080146.31113-12-pkshih@realtek.com
100 lines
2.8 KiB
C
100 lines
2.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
|
* Copyright(c) 2019-2020 Realtek Corporation
|
|
*/
|
|
#ifndef __RTW89_UTIL_H__
|
|
#define __RTW89_UTIL_H__
|
|
|
|
#include "core.h"
|
|
|
|
#define RTW89_KEY_PN_0 GENMASK_ULL(7, 0)
|
|
#define RTW89_KEY_PN_1 GENMASK_ULL(15, 8)
|
|
#define RTW89_KEY_PN_2 GENMASK_ULL(23, 16)
|
|
#define RTW89_KEY_PN_3 GENMASK_ULL(31, 24)
|
|
#define RTW89_KEY_PN_4 GENMASK_ULL(39, 32)
|
|
#define RTW89_KEY_PN_5 GENMASK_ULL(47, 40)
|
|
|
|
#define rtw89_iterate_vifs_bh(rtwdev, iterator, data) \
|
|
ieee80211_iterate_active_interfaces_atomic((rtwdev)->hw, \
|
|
IEEE80211_IFACE_ITER_NORMAL, iterator, data)
|
|
|
|
/* call this function with wiphy mutex is held */
|
|
#define rtw89_for_each_rtwvif(rtwdev, rtwvif) \
|
|
list_for_each_entry(rtwvif, &(rtwdev)->rtwvifs_list, list)
|
|
|
|
/* Before adding rtwvif to list, we need to check if it already exist, beacase
|
|
* in some case such as SER L2 happen during WoWLAN flow, calling reconfig
|
|
* twice cause the list to be added twice.
|
|
*/
|
|
static inline bool rtw89_rtwvif_in_list(struct rtw89_dev *rtwdev,
|
|
struct rtw89_vif *new)
|
|
{
|
|
struct rtw89_vif *rtwvif;
|
|
|
|
lockdep_assert_wiphy(rtwdev->hw->wiphy);
|
|
|
|
rtw89_for_each_rtwvif(rtwdev, rtwvif)
|
|
if (rtwvif == new)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/* The result of negative dividend and positive divisor is undefined, but it
|
|
* should be one case of round-down or round-up. So, make it round-down if the
|
|
* result is round-up.
|
|
* Note: the maximum value of divisor is 0x7FFF_FFFF, because we cast it to
|
|
* signed value to make compiler to use signed divide instruction.
|
|
*/
|
|
static inline s32 s32_div_u32_round_down(s32 dividend, u32 divisor, s32 *remainder)
|
|
{
|
|
s32 i_divisor = (s32)divisor;
|
|
s32 i_remainder;
|
|
s32 quotient;
|
|
|
|
quotient = dividend / i_divisor;
|
|
i_remainder = dividend % i_divisor;
|
|
|
|
if (i_remainder < 0) {
|
|
quotient--;
|
|
i_remainder += i_divisor;
|
|
}
|
|
|
|
if (remainder)
|
|
*remainder = i_remainder;
|
|
return quotient;
|
|
}
|
|
|
|
static inline s32 s32_div_u32_round_closest(s32 dividend, u32 divisor)
|
|
{
|
|
return s32_div_u32_round_down(dividend + divisor / 2, divisor, NULL);
|
|
}
|
|
|
|
static inline void ether_addr_copy_mask(u8 *dst, const u8 *src, u8 mask)
|
|
{
|
|
int i;
|
|
|
|
eth_zero_addr(dst);
|
|
for (i = 0; i < ETH_ALEN; i++) {
|
|
if (mask & BIT(i))
|
|
dst[i] = src[i];
|
|
}
|
|
}
|
|
|
|
static inline void ccmp_hdr2pn(s64 *pn, const u8 *hdr)
|
|
{
|
|
*pn = u64_encode_bits(hdr[0], RTW89_KEY_PN_0) |
|
|
u64_encode_bits(hdr[1], RTW89_KEY_PN_1) |
|
|
u64_encode_bits(hdr[4], RTW89_KEY_PN_2) |
|
|
u64_encode_bits(hdr[5], RTW89_KEY_PN_3) |
|
|
u64_encode_bits(hdr[6], RTW89_KEY_PN_4) |
|
|
u64_encode_bits(hdr[7], RTW89_KEY_PN_5);
|
|
}
|
|
|
|
s32 rtw89_linear_to_db_quarter(u64 val);
|
|
s32 rtw89_linear_to_db(u64 val);
|
|
u64 rtw89_db_quarter_to_linear(s32 db);
|
|
u64 rtw89_db_to_linear(s32 db);
|
|
void rtw89_might_trailing_ellipsis(char *buf, size_t size, ssize_t used);
|
|
|
|
#endif
|