// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include "main.h"
#include "fw.h"
#include "wow.h"
#include "reg.h"
#include "debug.h"
#include "mac.h"
#include "ps.h"
static void rtw_wow_show_wakeup_reason(struct rtw_dev *rtwdev)
{
u8 reason;
reason = rtw_read8(rtwdev, REG_WOWLAN_WAKE_REASON);
if (reason == RTW_WOW_RSN_RX_DEAUTH)
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx deauth\n");
else if (reason == RTW_WOW_RSN_DISCONNECT)
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: AP is off\n");
else if (reason == RTW_WOW_RSN_RX_MAGIC_PKT)
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx magic packet\n");
else if (reason == RTW_WOW_RSN_RX_GTK_REKEY)
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx gtk rekey\n");
else if (reason == RTW_WOW_RSN_RX_PTK_REKEY)
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx ptk rekey\n");
else if (reason == RTW_WOW_RSN_RX_PATTERN_MATCH)
rtw_dbg(rtwdev, RTW_DBG_WOW, "WOW: Rx pattern match packet\n");
else if (reason == RTW_WOW_RSN_RX_NLO)
rtw_dbg(rtwdev, RTW_DBG_WOW, "Rx NLO\n");
else
rtw_warn(rtwdev, "Unknown wakeup reason %x\n", reason);
}
static void rtw_wow_pattern_write_cam(struct rtw_dev *rtwdev, u8 addr,
u32 wdata)
{
rtw_write32(rtwdev, REG_WKFMCAM_RWD, wdata);
rtw_write32(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 |
BIT_WKFCAM_WE | BIT_WKFCAM_ADDR_V2(addr));
if (!check_hw_ready(rtwdev, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1, 0))
rtw_err(rtwdev, "failed to write pattern cam\n");
}
static void rtw_wow_pattern_write_cam_ent(struct rtw_dev *rtwdev, u8 id,
struct rtw_wow_pattern *rtw_pattern)
{
int i;
u8 addr;
u32 wdata;
for (i = 0; i < RTW_MAX_PATTERN_MASK_SIZE / 4; i++) {
addr = (id << 3) + i;
wdata = rtw_pattern->mask[i * 4];
wdata |= rtw_pattern->mask[i * 4 + 1] << 8;
wdata |= rtw_pattern->mask[i * 4 + 2] << 16;
wdata |= rtw_pattern->mask[i * 4 + 3] << 24;
rtw_wow_pattern_write_cam(rtwdev, addr, wdata);
}
wdata = rtw_pattern->crc;
addr = (id << 3) + RTW_MAX_PATTERN_MASK_SIZE / 4;
switch (rtw_pattern->type) {
case RTW_PATTERN_BROADCAST:
wdata |= BIT_WKFMCAM_BC | BIT_WKFMCAM_VALID;
break;
case RTW_PATTERN_MULTICAST:
wdata |= BIT_WKFMCAM_MC | BIT_WKFMCAM_VALID;
break;
case RTW_PATTERN_UNICAST:
wdata |= BIT_WKFMCAM_UC | BIT_WKFMCAM_VALID;
break;
default:
break;
}
rtw_wow_pattern_write_cam(rtwdev, addr, wdata);
}
/* RTK internal CRC16 for Pattern Cam */
static u16 __rtw_cal_crc16(u8 data, u16 crc)
{
u8 shift_in, data_bit;
u8 crc_bit4, crc_bit11, crc_bit15;
u16 crc_result;
int index;
for (index = 0; index < 8; index++) {
crc_bit15 = ((crc & BIT(15)) ? 1 : 0);
data_bit = (data & (BIT(0) << index) ? 1 : 0);
shift_in = crc_bit15 ^ data_bit;
crc_result = crc << 1;
if (shift_in == 0)
crc_result &= (~BIT(0));
else
crc_result |= BIT(0);
crc_bit11 = ((crc & BIT(11)) ? 1 : 0) ^ shift_in;
if (crc_bit11 == 0)
crc_result &= (~BIT(12));
else
crc_result |= BIT(12);
crc_bit4 = ((crc & BIT(4)) ? 1 : 0) ^ shift_in;
if (crc_bit4 == 0)
crc_result &= (~BIT(5));
else
crc_result |= BIT(5);
crc = crc_result;
}
return crc;
}
static u16 rtw_calc_crc(u8 *pdata, int length)
{
u16 crc = 0xffff;
int i;
for (i = 0; i < length; i++)
crc = __rtw_cal_crc16