diff options
Diffstat (limited to 'drivers/net/wireless/realtek')
32 files changed, 4147 insertions, 511 deletions
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index ad3f32f4c6e7..136992f0200c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -570,7 +570,7 @@ struct rtl8723au_phy_stats { u8 cck_rpt_b_ofdm_cfosho_b; u8 reserved_1; u8 noise_power_db_msb; - u8 path_cfotail[RTL8723A_MAX_RF_PATHS]; + s8 path_cfotail[RTL8723A_MAX_RF_PATHS]; u8 pcts_mask[RTL8723A_MAX_RF_PATHS]; s8 stream_rxevm[RTL8723A_MAX_RF_PATHS]; u8 path_rxsnr[RTL8723A_MAX_RF_PATHS]; @@ -1323,6 +1323,19 @@ struct rtl8xxxu_ra_report { u8 desc_rate; }; +#define CFO_TH_XTAL_HIGH 20 /* kHz */ +#define CFO_TH_XTAL_LOW 10 /* kHz */ +#define CFO_TH_ATC 80 /* kHz */ + +struct rtl8xxxu_cfo_tracking { + bool adjust; + bool atc_status; + int cfo_tail[2]; + u8 crystal_cap; + u32 packet_count; + u32 packet_count_pre; +}; + struct rtl8xxxu_priv { struct ieee80211_hw *hw; struct usb_device *udev; @@ -1381,9 +1394,9 @@ struct rtl8xxxu_priv { u32 ep_tx_high_queue:1; u32 ep_tx_normal_queue:1; u32 ep_tx_low_queue:1; - u32 has_xtalk:1; u32 rx_buf_aggregation:1; - u8 xtalk; + u32 cck_agc_report_type:1; + u8 default_crystal_cap; unsigned int pipe_interrupt; unsigned int pipe_in; unsigned int pipe_out[TXDESC_QUEUE_MAX]; @@ -1441,6 +1454,7 @@ struct rtl8xxxu_priv { struct sk_buff_head c2hcmd_queue; struct rtl8xxxu_btcoex bt_coex; struct rtl8xxxu_ra_report ra_report; + struct rtl8xxxu_cfo_tracking cfo_tracking; }; struct rtl8xxxu_rx_urb { @@ -1456,6 +1470,7 @@ struct rtl8xxxu_tx_urb { }; struct rtl8xxxu_fileops { + int (*identify_chip) (struct rtl8xxxu_priv *priv); int (*parse_efuse) (struct rtl8xxxu_priv *priv); int (*load_firmware) (struct rtl8xxxu_priv *priv); int (*power_on) (struct rtl8xxxu_priv *priv); @@ -1471,6 +1486,7 @@ struct rtl8xxxu_fileops { int (*parse_rx_desc) (struct rtl8xxxu_priv *priv, struct sk_buff *skb); void (*init_aggregation) (struct rtl8xxxu_priv *priv); void (*init_statistics) (struct rtl8xxxu_priv *priv); + void (*init_burst) (struct rtl8xxxu_priv *priv); void (*enable_rf) (struct rtl8xxxu_priv *priv); void (*disable_rf) (struct rtl8xxxu_priv *priv); void (*usb_quirks) (struct rtl8xxxu_priv *priv); @@ -1485,6 +1501,8 @@ struct rtl8xxxu_fileops { struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, bool short_preamble, bool ampdu_enable, u32 rts_rate); + void (*set_crystal_cap) (struct rtl8xxxu_priv *priv, u8 crystal_cap); + s8 (*cck_rssi) (struct rtl8xxxu_priv *priv, u8 cck_agc_rpt); int writeN_block_size; int rx_agg_buf_size; char tx_desc_size; @@ -1545,6 +1563,10 @@ int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv, int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name); void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv); void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv); +void rtl8xxxu_identify_vendor_1bit(struct rtl8xxxu_priv *priv, u32 vendor); +void rtl8xxxu_identify_vendor_2bits(struct rtl8xxxu_priv *priv, u32 vendor); +void rtl8xxxu_config_endpoints_sie(struct rtl8xxxu_priv *priv); +int rtl8xxxu_config_endpoints_no_sie(struct rtl8xxxu_priv *priv); int rtl8xxxu_read_efuse8(struct rtl8xxxu_priv *priv, u16 offset, u8 *data); void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv); int rtl8xxxu_auto_llt_table(struct rtl8xxxu_priv *priv); @@ -1576,6 +1598,7 @@ void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_enable_rf(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_disable_rf(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen2_disable_rf(struct rtl8xxxu_priv *priv); +void rtl8xxxu_init_burst(struct rtl8xxxu_priv *priv); int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb); int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb); int rtl8xxxu_gen2_channel_to_group(int channel); @@ -1594,6 +1617,8 @@ void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5); void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv); +void rtl8723a_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap); +s8 rtl8723a_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt); extern struct rtl8xxxu_fileops rtl8188fu_fops; extern struct rtl8xxxu_fileops rtl8192cu_fops; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index 0025bb32538d..2c4f403ba68f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -321,7 +321,37 @@ static const struct rtl8xxxu_rfregval rtl8188fu_cut_b_radioa_init_table[] = { {0xff, 0xffffffff} }; -static void rtl8xxxu_8188f_channel_to_group(int channel, int *group, int *cck_group) +static int rtl8188fu_identify_chip(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u32 sys_cfg, vendor; + int ret = 0; + + strscpy(priv->chip_name, "8188FU", sizeof(priv->chip_name)); + priv->rtl_chip = RTL8188F; + priv->rf_paths = 1; + priv->rx_paths = 1; + priv->tx_paths = 1; + priv->has_wifi = 1; + + sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG); + priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK); + if (sys_cfg & SYS_CFG_TRP_VAUX_EN) { + dev_info(dev, "Unsupported test chip\n"); + ret = -ENOTSUPP; + goto out; + } + + vendor = sys_cfg & SYS_CFG_VENDOR_EXT_MASK; + rtl8xxxu_identify_vendor_2bits(priv, vendor); + + ret = rtl8xxxu_config_endpoints_no_sie(priv); + +out: + return ret; +} + +static void rtl8188f_channel_to_group(int channel, int *group, int *cck_group) { if (channel < 3) *group = 0; @@ -347,7 +377,7 @@ rtl8188f_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) u8 cck, ofdmbase, mcsbase; int group, cck_group; - rtl8xxxu_8188f_channel_to_group(channel, &group, &cck_group); + rtl8188f_channel_to_group(channel, &group, &cck_group); cck = priv->cck_tx_power_index_A[cck_group]; @@ -703,7 +733,7 @@ static int rtl8188fu_parse_efuse(struct rtl8xxxu_priv *priv) priv->ofdm_tx_power_diff[0].a = efuse->tx_power_index_A.ht20_ofdm_1s_diff.a; priv->ht20_tx_power_diff[0].a = efuse->tx_power_index_A.ht20_ofdm_1s_diff.b; - priv->xtalk = efuse->xtal_k & 0x3f; + priv->default_crystal_cap = efuse->xtal_k & 0x3f; dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.7s\n", efuse->device_name); @@ -737,7 +767,6 @@ static void rtl8188fu_init_phy_bb(struct rtl8xxxu_priv *priv) { u8 val8; u16 val16; - u32 val32; /* Enable BB and RF */ val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC); @@ -759,12 +788,6 @@ static void rtl8188fu_init_phy_bb(struct rtl8xxxu_priv *priv) rtl8xxxu_init_phy_regs(priv, rtl8188fu_phy_init_table); rtl8xxxu_init_phy_regs(priv, rtl8188f_agc_table); - - val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); - val8 = priv->xtalk; - val32 &= ~0x007FF800; - val32 |= ((val8 | (val8 << 6)) << 11); - rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32); } static int rtl8188fu_init_phy_rf(struct rtl8xxxu_priv *priv) @@ -1636,7 +1659,68 @@ static void rtl8188f_usb_quirks(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32); } +#define XTAL1 GENMASK(22, 17) +#define XTAL0 GENMASK(16, 11) + +static void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap) +{ + struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking; + u32 val32; + + if (crystal_cap == cfo->crystal_cap) + return; + + val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); + + dev_dbg(&priv->udev->dev, + "%s: Adjusting crystal cap from 0x%x (actually 0x%lx 0x%lx) to 0x%x\n", + __func__, + cfo->crystal_cap, + FIELD_GET(XTAL1, val32), + FIELD_GET(XTAL0, val32), + crystal_cap); + + val32 &= ~(XTAL1 | XTAL0); + val32 |= FIELD_PREP(XTAL1, crystal_cap) | + FIELD_PREP(XTAL0, crystal_cap); + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32); + + cfo->crystal_cap = crystal_cap; +} + +static s8 rtl8188f_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) +{ + s8 rx_pwr_all = 0x00; + u8 vga_idx, lna_idx; + + lna_idx = (cck_agc_rpt & 0xE0) >> 5; + vga_idx = cck_agc_rpt & 0x1F; + + switch (lna_idx) { + case 7: + if (vga_idx <= 27) + rx_pwr_all = -100 + 2 * (27 - vga_idx); + else + rx_pwr_all = -100; + break; + case 5: + rx_pwr_all = -74 + 2 * (21 - vga_idx); + break; + case 3: + rx_pwr_all = -60 + 2 * (20 - vga_idx); + break; + case 1: + rx_pwr_all = -44 + 2 * (19 - vga_idx); + break; + default: + break; + } + + return rx_pwr_all; +} + struct rtl8xxxu_fileops rtl8188fu_fops = { + .identify_chip = rtl8188fu_identify_chip, .parse_efuse = rtl8188fu_parse_efuse, .load_firmware = rtl8188fu_load_firmware, .power_on = rtl8188fu_power_on, @@ -1652,6 +1736,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .parse_rx_desc = rtl8xxxu_parse_rxdesc24, .init_aggregation = rtl8188fu_init_aggregation, .init_statistics = rtl8188fu_init_statistics, + .init_burst = rtl8xxxu_init_burst, .enable_rf = rtl8188f_enable_rf, .disable_rf = rtl8188f_disable_rf, .usb_quirks = rtl8188f_usb_quirks, @@ -1659,6 +1744,8 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, + .set_crystal_cap = rtl8188f_set_crystal_cap, + .cck_rssi = rtl8188f_cck_rssi, .writeN_block_size = 128, .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24), .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c index e9bc94edfa79..3bef9ffc8b02 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c @@ -326,6 +326,64 @@ static const struct rtl8xxxu_rfregval rtl8188ru_radioa_1t_highpa_table[] = { {0xff, 0xffffffff} }; +static int rtl8192cu_identify_chip(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u32 val32, bonding, sys_cfg, vendor; + int ret = 0; + + sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG); + priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK); + if (sys_cfg & SYS_CFG_TRP_VAUX_EN) { + dev_info(dev, "Unsupported test chip\n"); + ret = -ENOTSUPP; + goto out; + } + + if (sys_cfg & SYS_CFG_TYPE_ID) { + bonding = rtl8xxxu_read32(priv, REG_HPON_FSM); + bonding &= HPON_FSM_BONDING_MASK; + if (bonding == HPON_FSM_BONDING_1T2R) { + strscpy(priv->chip_name, "8191CU", sizeof(priv->chip_name)); + priv->tx_paths = 1; + priv->usb_interrupts = 1; + priv->rtl_chip = RTL8191C; + } else { + strscpy(priv->chip_name, "8192CU", sizeof(priv->chip_name)); + priv->tx_paths = 2; + priv->usb_interrupts = 0; + priv->rtl_chip = RTL8192C; + } + priv->rf_paths = 2; + priv->rx_paths = 2; + } else { + strscpy(priv->chip_name, "8188CU", sizeof(priv->chip_name)); + priv->rf_paths = 1; + priv->rx_paths = 1; + priv->tx_paths = 1; + priv->rtl_chip = RTL8188C; + priv->usb_interrupts = 0; + } + priv->has_wifi = 1; + + vendor = sys_cfg & SYS_CFG_VENDOR_ID; + rtl8xxxu_identify_vendor_1bit(priv, vendor); + + val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS); + priv->rom_rev = u32_get_bits(val32, GPIO_RF_RL_ID); + + rtl8xxxu_config_endpoints_sie(priv); + + /* + * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX + */ + if (!priv->ep_tx_count) + ret = rtl8xxxu_config_endpoints_no_sie(priv); + +out: + return ret; +} + static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv) { char *fw_name; @@ -392,7 +450,7 @@ static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv) priv->power_base = &rtl8192c_power_base; if (efuse->rf_regulatory & 0x20) { - sprintf(priv->chip_name, "8188RU"); + strscpy(priv->chip_name, "8188RU", sizeof(priv->chip_name)); priv->rtl_chip = RTL8188R; priv->hi_pa = 1; priv->no_pape = 1; @@ -541,6 +599,7 @@ static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv) } struct rtl8xxxu_fileops rtl8192cu_fops = { + .identify_chip = rtl8192cu_identify_chip, .parse_efuse = rtl8192cu_parse_efuse, .load_firmware = rtl8192cu_load_firmware, .power_on = rtl8192cu_power_on, @@ -561,6 +620,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops = { .update_rate_mask = rtl8xxxu_update_rate_mask, .report_connect = rtl8xxxu_gen1_report_connect, .fill_txdesc = rtl8xxxu_fill_txdesc_v1, + .cck_rssi = rtl8723a_cck_rssi, .writeN_block_size = 128, .rx_agg_buf_size = 16000, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index 550290ae9e17..6dc1e5858e77 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -478,6 +478,53 @@ static const struct rtl8xxxu_rfregval rtl8192eu_radiob_init_table[] = { {0xff, 0xffffffff} }; +static int rtl8192eu_identify_chip(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u32 val32, bonding, sys_cfg, vendor; + int ret = 0; + + sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG); + priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK); + if (sys_cfg & SYS_CFG_TRP_VAUX_EN) { + dev_info(dev, "Unsupported test chip\n"); + ret = -ENOTSUPP; + goto out; + } + + bonding = rtl8xxxu_read32(priv, REG_HPON_FSM); + bonding &= HPON_FSM_BONDING_MASK; + if (bonding == HPON_FSM_BONDING_1T2R) { + strscpy(priv->chip_name, "8191EU", sizeof(priv->chip_name)); + priv->tx_paths = 1; + priv->rtl_chip = RTL8191E; + } else { + strscpy(priv->chip_name, "8192EU", sizeof(priv->chip_name)); + priv->tx_paths = 2; + priv->rtl_chip = RTL8192E; + } + priv->rf_paths = 2; + priv->rx_paths = 2; + priv->has_wifi = 1; + + vendor = sys_cfg & SYS_CFG_VENDOR_EXT_MASK; + rtl8xxxu_identify_vendor_2bits(priv, vendor); + + val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS); + priv->rom_rev = u32_get_bits(val32, GPIO_RF_RL_ID); + + rtl8xxxu_config_endpoints_sie(priv); + + /* + * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX + */ + if (!priv->ep_tx_count) + ret = rtl8xxxu_config_endpoints_no_sie(priv); + +out: + return ret; +} + static void rtl8192e_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) { @@ -635,8 +682,7 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) efuse->tx_power_index_B.pwr_diff[i - 1].ht40; } - priv->has_xtalk = 1; - priv->xtalk = priv->efuse_wifi.efuse8192eu.xtal_k & 0x3f; + priv->default_crystal_cap = priv->efuse_wifi.efuse8192eu.xtal_k & 0x3f; /* * device_info section seems to be laid out as records @@ -1671,7 +1717,30 @@ static void rtl8192e_enable_rf(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_PAD_CTRL1, val8); } +static s8 rtl8192e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) +{ + static const s8 lna_gain_table_0[8] = {15, 9, -10, -21, -23, -27, -43, -44}; + static const s8 lna_gain_table_1[8] = {24, 18, 13, -4, -11, -18, -31, -36}; + + s8 rx_pwr_all = 0x00; + u8 vga_idx, lna_idx; + s8 lna_gain = 0; + + lna_idx = (cck_agc_rpt & 0xE0) >> 5; + vga_idx = cck_agc_rpt & 0x1F; + + if (priv->cck_agc_report_type == 0) + lna_gain = lna_gain_table_0[lna_idx]; + else + lna_gain = lna_gain_table_1[lna_idx]; + + rx_pwr_all = lna_gain - (2 * vga_idx); + + return rx_pwr_all; +} + struct rtl8xxxu_fileops rtl8192eu_fops = { + .identify_chip = rtl8192eu_identify_chip, .parse_efuse = rtl8192eu_parse_efuse, .load_firmware = rtl8192eu_load_firmware, .power_on = rtl8192eu_power_on, @@ -1691,6 +1760,8 @@ struct rtl8xxxu_fileops rtl8192eu_fops = { .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, + .set_crystal_cap = rtl8723a_set_crystal_cap, + .cck_rssi = rtl8192e_cck_rssi, .writeN_block_size = 128, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40), .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c index 44565bf4c1c2..707ac48ecc83 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c @@ -129,6 +129,55 @@ static const struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = { {0xff, 0xffffffff} }; +static int rtl8723au_identify_chip(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u32 val32, sys_cfg, vendor; + int ret = 0; + + sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG); + priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK); + if (sys_cfg & SYS_CFG_TRP_VAUX_EN) { + dev_info(dev, "Unsupported test chip\n"); + ret = -ENOTSUPP; + goto out; + } + + strscpy(priv->chip_name, "8723AU", sizeof(priv->chip_name)); + priv->usb_interrupts = 1; + priv->rtl_chip = RTL8723A; + + priv->rf_paths = 1; + priv->rx_paths = 1; + priv->tx_paths = 1; + + val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL); + if (val32 & MULTI_WIFI_FUNC_EN) + priv->has_wifi = 1; + if (val32 & MULTI_BT_FUNC_EN) + priv->has_bluetooth = 1; + if (val32 & MULTI_GPS_FUNC_EN) + priv->has_gps = 1; + priv->is_multi_func = 1; + + vendor = sys_cfg & SYS_CFG_VENDOR_ID; + rtl8xxxu_identify_vendor_1bit(priv, vendor); + + val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS); + priv->rom_rev = u32_get_bits(val32, GPIO_RF_RL_ID); + + rtl8xxxu_config_endpoints_sie(priv); + + /* + * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX + */ + if (!priv->ep_tx_count) + ret = rtl8xxxu_config_endpoints_no_sie(priv); + +out: + return ret; +} + static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) { struct rtl8723au_efuse *efuse = &priv->efuse_wifi.efuse8723; @@ -166,10 +215,10 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv) efuse->ht20_max_power_offset, sizeof(efuse->ht20_max_power_offset)); - if (priv->efuse_wifi.efuse8723.version >= 0x01) { - priv->has_xtalk = 1; - priv->xtalk = priv->efuse_wifi.efuse8723.xtal_k & 0x3f; - } + if (priv->efuse_wifi.efuse8723.version >= 0x01) + priv->default_crystal_cap = priv->efuse_wifi.efuse8723.xtal_k & 0x3f; + else + priv->fops->set_crystal_cap = NULL; priv->power_base = &rtl8723a_power_base; @@ -357,7 +406,59 @@ exit: return ret; } +#define XTAL1 GENMASK(23, 18) +#define XTAL0 GENMASK(17, 12) + +void rtl8723a_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap) +{ + struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking; + u32 val32; + + if (crystal_cap == cfo->crystal_cap) + return; + + val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL); + + dev_dbg(&priv->udev->dev, + "%s: Adjusting crystal cap from 0x%x (actually 0x%lx 0x%lx) to 0x%x\n", + __func__, + cfo->crystal_cap, + FIELD_GET(XTAL1, val32), + FIELD_GET(XTAL0, val32), + crystal_cap); + + val32 &= ~(XTAL1 | XTAL0); + val32 |= FIELD_PREP(XTAL1, crystal_cap) | + FIELD_PREP(XTAL0, crystal_cap); + rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32); + + cfo->crystal_cap = crystal_cap; +} + +s8 rtl8723a_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) +{ + s8 rx_pwr_all = 0x00; + + switch (cck_agc_rpt & 0xc0) { + case 0xc0: + rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); + break; + case 0x80: + rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); + break; + case 0x40: + rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); + break; + case 0x00: + rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); + break; + } + + return rx_pwr_all; +} + struct rtl8xxxu_fileops rtl8723au_fops = { + .identify_chip = rtl8723au_identify_chip, .parse_efuse = rtl8723au_parse_efuse, .load_firmware = rtl8723au_load_firmware, .power_on = rtl8723au_power_on, @@ -378,6 +479,8 @@ struct rtl8xxxu_fileops rtl8723au_fops = { .update_rate_mask = rtl8xxxu_update_rate_mask, .report_connect = rtl8xxxu_gen1_report_connect, .fill_txdesc = rtl8xxxu_fill_txdesc_v1, + .set_crystal_cap = rtl8723a_set_crystal_cap, + .cck_rssi = rtl8723a_cck_rssi, .writeN_block_size = 1024, .rx_agg_buf_size = 16000, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index a27fe06d6f77..a0ec895b61a4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -304,6 +304,53 @@ static const struct rtl8xxxu_rfregval rtl8723bu_radioa_1t_init_table[] = { {0xff, 0xffffffff} }; +static int rtl8723bu_identify_chip(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u32 val32, sys_cfg, vendor; + int ret = 0; + + sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG); + priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK); + if (sys_cfg & SYS_CFG_TRP_VAUX_EN) { + dev_info(dev, "Unsupported test chip\n"); + ret = -ENOTSUPP; + goto out; + } + + strscpy(priv->chip_name, "8723BU", sizeof(priv->chip_name)); + priv->rtl_chip = RTL8723B; + priv->rf_paths = 1; + priv->rx_paths = 1; + priv->tx_paths = 1; + + val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL); + if (val32 & MULTI_WIFI_FUNC_EN) + priv->has_wifi = 1; + if (val32 & MULTI_BT_FUNC_EN) + priv->has_bluetooth = 1; + if (val32 & MULTI_GPS_FUNC_EN) + priv->has_gps = 1; + priv->is_multi_func = 1; + + vendor = sys_cfg & SYS_CFG_VENDOR_EXT_MASK; + rtl8xxxu_identify_vendor_2bits(priv, vendor); + + val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS); + priv->rom_rev = u32_get_bits(val32, GPIO_RF_RL_ID); + + rtl8xxxu_config_endpoints_sie(priv); + + /* + * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX + */ + if (!priv->ep_tx_count) + ret = rtl8xxxu_config_endpoints_no_sie(priv); + +out: + return ret; +} + static void rtl8723bu_write_btreg(struct rtl8xxxu_priv *priv, u8 reg, u8 data) { struct h2c_cmd h2c; @@ -445,8 +492,7 @@ static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv) efuse->tx_power_index_B.pwr_diff[i - 1].ht40; } - priv->has_xtalk = 1; - priv->xtalk = priv->efuse_wifi.efuse8723bu.xtal_k & 0x3f; + priv->default_crystal_cap = priv->efuse_wifi.efuse8723bu.xtal_k & 0x3f; dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); dev_info(&priv->udev->dev, "Product: %.41s\n", efuse->device_name); @@ -1640,7 +1686,36 @@ static void rtl8723bu_init_statistics(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_OFDM0_FA_RSTC, val32); } +static s8 rtl8723b_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt) +{ + s8 rx_pwr_all = 0x00; + u8 vga_idx, lna_idx; + + lna_idx = (cck_agc_rpt & 0xE0) >> 5; + vga_idx = cck_agc_rpt & 0x1F; + + switch (lna_idx) { + case 6: + rx_pwr_all = -34 - (2 * vga_idx); + break; + case 4: + rx_pwr_all = -14 - (2 * vga_idx); + break; + case 1: + rx_pwr_all = 6 - (2 * vga_idx); + break; + case 0: + rx_pwr_all = 16 - (2 * vga_idx); + break; + default: + break; + } + + return rx_pwr_all; +} + struct rtl8xxxu_fileops rtl8723bu_fops = { + .identify_chip = rtl8723bu_identify_chip, .parse_efuse = rtl8723bu_parse_efuse, .load_firmware = rtl8723bu_load_firmware, .power_on = rtl8723bu_power_on, @@ -1656,6 +1731,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .parse_rx_desc = rtl8xxxu_parse_rxdesc24, .init_aggregation = rtl8723bu_init_aggregation, .init_statistics = rtl8723bu_init_statistics, + .init_burst = rtl8xxxu_init_burst, .enable_rf = rtl8723b_enable_rf, .disable_rf = rtl8xxxu_gen2_disable_rf, .usb_quirks = rtl8xxxu_gen2_usb_quirks, @@ -1663,6 +1739,8 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, + .set_crystal_cap = rtl8723a_set_crystal_cap, + .cck_rssi = rtl8723b_cck_rssi, .writeN_block_size = 1024, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40), .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 65bb4dc8f555..e8fcd531c437 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -1574,30 +1574,14 @@ rtl8xxxu_set_spec_sifs(struct rtl8xxxu_priv *priv, u16 cck, u16 ofdm) static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv) { struct device *dev = &priv->udev->dev; - char *cut; + char cut = '?'; - switch (priv->chip_cut) { - case 0: - cut = "A"; - break; - case 1: - cut = "B"; - break; - case 2: - cut = "C"; - break; - case 3: - cut = "D"; - break; - case 4: - cut = "E"; - break; - default: - cut = "unknown"; - } + /* Currently always true: chip_cut is 4 bits. */ + if (priv->chip_cut <= 15) + cut = 'A' + priv->chip_cut; dev_info(dev, - "RTL%s rev %s (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n", + "RTL%s rev %c (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n", priv->chip_name, cut, priv->chip_vendor, priv->tx_paths, priv->rx_paths, priv->ep_tx_count, priv->has_wifi, priv->has_bluetooth, priv->has_gps, priv->hi_pa); @@ -1605,148 +1589,40 @@ static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv) dev_info(dev, "RTL%s MAC: %pM\n", priv->chip_name, priv->mac_addr); } -static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv) +void rtl8xxxu_identify_vendor_1bit(struct rtl8xxxu_priv *priv, u32 vendor) { - const struct usb_device_descriptor *descriptor = &priv->udev->descriptor; - struct device *dev = &priv->udev->dev; - struct ieee80211_hw *hw = priv->hw; - u32 val32, bonding, sys_cfg; - u16 val16; - - sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG); - priv->chip_cut = (sys_cfg & SYS_CFG_CHIP_VERSION_MASK) >> - SYS_CFG_CHIP_VERSION_SHIFT; - if (sys_cfg & SYS_CFG_TRP_VAUX_EN) { - dev_info(dev, "Unsupported test chip\n"); - return -ENOTSUPP; - } - - if (descriptor->idVendor == USB_VENDOR_ID_REALTEK && - descriptor->idProduct == 0xf179) { - sprintf(priv->chip_name, "8188FU"); - priv->rtl_chip = RTL8188F; - priv->rf_paths = 1; - priv->rx_paths = 1; - priv->tx_paths = 1; - priv->has_wifi = 1; - goto skip_complicated_chip_detection; - } - - if (sys_cfg & SYS_CFG_BT_FUNC) { - if (priv->chip_cut >= 3) { - sprintf(priv->chip_name, "8723BU"); - priv->rtl_chip = RTL8723B; - } else { - sprintf(priv->chip_name, "8723AU"); - priv->usb_interrupts = 1; - priv->rtl_chip = RTL8723A; - } - - priv->rf_paths = 1; - priv->rx_paths = 1; - priv->tx_paths = 1; - - val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL); - if (val32 & MULTI_WIFI_FUNC_EN) - priv->has_wifi = 1; - if (val32 & MULTI_BT_FUNC_EN) - priv->has_bluetooth = 1; - if (val32 & MULTI_GPS_FUNC_EN) - priv->has_gps = 1; - priv->is_multi_func = 1; - } else if (sys_cfg & SYS_CFG_TYPE_ID) { - bonding = rtl8xxxu_read32(priv, REG_HPON_FSM); - bonding &= HPON_FSM_BONDING_MASK; - if (priv->fops->tx_desc_size == - sizeof(struct rtl8xxxu_txdesc40)) { - if (bonding == HPON_FSM_BONDING_1T2R) { - sprintf(priv->chip_name, "8191EU"); - priv->rf_paths = 2; - priv->rx_paths = 2; - priv->tx_paths = 1; - priv->rtl_chip = RTL8191E; - } else { - sprintf(priv->chip_name, "8192EU"); - priv->rf_paths = 2; - priv->rx_paths = 2; - priv->tx_paths = 2; - priv->rtl_chip = RTL8192E; - } - } else if (bonding == HPON_FSM_BONDING_1T2R) { - sprintf(priv->chip_name, "8191CU"); - priv->rf_paths = 2; - priv->rx_paths = 2; - priv->tx_paths = 1; - priv->usb_interrupts = 1; - priv->rtl_chip = RTL8191C; - } else { - sprintf(priv->chip_name, "8192CU"); - priv->rf_paths = 2; - priv->rx_paths = 2; - priv->tx_paths = 2; - priv->usb_interrupts = 0; - priv->rtl_chip = RTL8192C; - } - priv->has_wifi = 1; + if (vendor) { + strscpy(priv->chip_vendor, "UMC", sizeof(priv->chip_vendor)); + priv->vendor_umc = 1; } else { - sprintf(priv->chip_name, "8188CU"); - priv->rf_paths = 1; - priv->rx_paths = 1; - priv->tx_paths = 1; - priv->rtl_chip = RTL8188C; - priv->usb_interrupts = 0; - priv->has_wifi = 1; + strscpy(priv->chip_vendor, "TSMC", sizeof(priv->chip_vendor)); } +} -skip_complicated_chip_detection: - - hw->wiphy->available_antennas_tx = BIT(priv->tx_paths) - 1; - hw->wiphy->available_antennas_rx = BIT(priv->rx_paths) - 1; - - switch (priv->rtl_chip) { - case RTL8188E: - case RTL8188F: - case RTL8192E: - case RTL8723B: - switch (sys_cfg & SYS_CFG_VENDOR_EXT_MASK) { - case SYS_CFG_VENDOR_ID_TSMC: - sprintf(priv->chip_vendor, "TSMC"); - break; - case SYS_CFG_VENDOR_ID_SMIC: - sprintf(priv->chip_vendor, "SMIC"); - priv->vendor_smic = 1; - break; - case SYS_CFG_VENDOR_ID_UMC: - sprintf(priv->chip_vendor, "UMC"); - priv->vendor_umc = 1; - break; - default: - sprintf(priv->chip_vendor, "unknown"); - } +void rtl8xxxu_identify_vendor_2bits(struct rtl8xxxu_priv *priv, u32 vendor) +{ + switch (vendor) { + case SYS_CFG_VENDOR_ID_TSMC: + strscpy(priv->chip_vendor, "TSMC", sizeof(priv->chip_vendor)); + break; + case SYS_CFG_VENDOR_ID_SMIC: + strscpy(priv->chip_vendor, "SMIC", sizeof(priv->chip_vendor)); + priv->vendor_smic = 1; + break; + case SYS_CFG_VENDOR_ID_UMC: + strscpy(priv->chip_vendor, "UMC", sizeof(priv->chip_vendor)); + priv->vendor_umc = 1; break; default: - if (sys_cfg & SYS_CFG_VENDOR_ID) { - sprintf(priv->chip_vendor, "UMC"); - priv->vendor_umc = 1; - } else { - sprintf(priv->chip_vendor, "TSMC"); - } + strscpy(priv->chip_vendor, "unknown", sizeof(priv->chip_vendor)); } +} - val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS); - priv->rom_rev = (val32 & GPIO_RF_RL_ID) >> 28; +void rtl8xxxu_config_endpoints_sie(struct rtl8xxxu_priv *priv) +{ + u16 val16; - /* - * 8188FU vendor driver doesn't use REG_NORMAL_SIE_EP_TX, - * it just decides the queue mapping based on nr_out_eps. - * However, reading the register returns "0x321" which - * results in a wrong ep_tx_count of 3 and most frames - * not being transmitted. - */ - if (priv->rtl_chip == RTL8188F) - val16 = 0; - else - val16 = rtl8xxxu_read16(priv, REG_NORMAL_SIE_EP_TX); + val16 = rtl8xxxu_read16(priv, REG_NORMAL_SIE_EP_TX); if (val16 & NORMAL_SIE_EP_TX_HIGH_MASK) { priv->ep_tx_high_queue = 1; @@ -1762,29 +1638,29 @@ skip_complicated_chip_detection: priv->ep_tx_low_queue = 1; priv->ep_tx_count++; } +} - /* - * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX - */ - if (!priv->ep_tx_count) { - switch (priv->nr_out_eps) { - case 4: - case 3: - priv->ep_tx_low_queue = 1; - priv->ep_tx_count++; - fallthrough; - case 2: - priv->ep_tx_normal_queue = 1; - priv->ep_tx_count++; - fallthrough; - case 1: - priv->ep_tx_high_queue = 1; - priv->ep_tx_count++; - break; - default: - dev_info(dev, "Unsupported USB TX end-points\n"); - return -ENOTSUPP; - } +int rtl8xxxu_config_endpoints_no_sie(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + + switch (priv->nr_out_eps) { + case 4: + case 3: + priv->ep_tx_low_queue = 1; + priv->ep_tx_count++; + fallthrough; + case 2: + priv->ep_tx_normal_queue = 1; + priv->ep_tx_count++; + fallthrough; + case 1: + priv->ep_tx_high_queue = 1; + priv->ep_tx_count++; + break; + default: + dev_info(dev, "Unsupported USB TX end-points\n"); + return -ENOTSUPP; } return 0; @@ -2031,7 +1907,8 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL); if (val8 & MCU_FW_RAM_SEL) { - pr_info("do the RAM reset\n"); + dev_info(&priv->udev->dev, + "Firmware is already running, resetting the MCU.\n"); rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00); priv->fops->reset_8051(priv); } @@ -2286,7 +2163,6 @@ void rtl8xxxu_gen1_init_phy_bb(struct rtl8xxxu_priv *priv) */ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) { - u8 val8; u32 val32; priv->fops->init_phy_bb(priv); @@ -2351,15 +2227,8 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_TX_TO_TX, val32); } - if (priv->has_xtalk) { - val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL); - - val8 = priv->xtalk; - val32 &= 0xff000fff; - val32 |= ((val8 | (val8 << 6)) << 12); - - rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32); - } + if (priv->fops->set_crystal_cap) + priv->fops->set_crystal_cap(priv, priv->default_crystal_cap); if (priv->rtl_chip == RTL8192E) rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x000f81fb); @@ -3909,6 +3778,52 @@ static void rtl8xxxu_init_queue_reserved_page(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_RQPN, val32); } +void rtl8xxxu_init_burst(struct rtl8xxxu_priv *priv) +{ + u8 val8; + + /* + * For USB high speed set 512B packets + */ + val8 = rtl8xxxu_read8(priv, REG_RXDMA_PRO_8723B); + u8p_replace_bits(&val8, 1, RXDMA_PRO_DMA_BURST_SIZE); + u8p_replace_bits(&val8, 3, RXDMA_PRO_DMA_BURST_CNT); + val8 |= RXDMA_PRO_DMA_MODE; + rtl8xxxu_write8(priv, REG_RXDMA_PRO_8723B, val8); + + /* + * Enable single packet AMPDU + */ + val8 = rtl8xxxu_read8(priv, REG_HT_SINGLE_AMPDU_8723B); + val8 |= HT_SINGLE_AMPDU_ENABLE; + rtl8xxxu_write8(priv, REG_HT_SINGLE_AMPDU_8723B, val8); + + rtl8xxxu_write16(priv, REG_MAX_AGGR_NUM, 0x0c14); + if (priv->rtl_chip == RTL8723B) + val8 = 0x5e; + else if (priv->rtl_chip == RTL8188F) + val8 = 0x70; /* 0x5e would make it very slow */ + rtl8xxxu_write8(priv, REG_AMPDU_MAX_TIME_8723B, val8); + rtl8xxxu_write32(priv, REG_AGGLEN_LMT, 0xffffffff); + rtl8xxxu_write8(priv, REG_RX_PKT_LIMIT, 0x18); + rtl8xxxu_write8(priv, REG_PIFS, 0x00); + if (priv->rtl_chip == RTL8188F) { + rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL, FWHW_TXQ_CTRL_AMPDU_RETRY); + rtl8xxxu_write32(priv, REG_FAST_EDCA_CTRL, 0x03086666); + } + if (priv->rtl_chip == RTL8723B) + val8 = 0x50; + else if (priv->rtl_chip == RTL8188F) + val8 = 0x28; /* 0x50 would make the upload slow */ + rtl8xxxu_write8(priv, REG_USTIME_TSF_8723B, val8); + rtl8xxxu_write8(priv, REG_USTIME_EDCA, val8); + + /* to prevent mac is reseted by bus. */ + val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL); + val8 |= RSV_CTRL_WLOCK_1C | RSV_CTRL_DIS_PRST; + rtl8xxxu_write8(priv, REG_RSV_CTRL, val8); +} + static int rtl8xxxu_init_device(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; @@ -4162,48 +4077,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* * Initialize burst parameters */ - if (priv->rtl_chip == RTL8723B || priv->rtl_chip == RTL8188F) { - /* - * For USB high speed set 512B packets - */ - val8 = rtl8xxxu_read8(priv, REG_RXDMA_PRO_8723B); - val8 &= ~(BIT(4) | BIT(5)); - val8 |= BIT(4); - val8 |= BIT(1) | BIT(2) | BIT(3); - rtl8xxxu_write8(priv, REG_RXDMA_PRO_8723B, val8); - - /* - * For USB high speed set 512B packets - */ - val8 = rtl8xxxu_read8(priv, REG_HT_SINGLE_AMPDU_8723B); - val8 |= BIT(7); - rtl8xxxu_write8(priv, REG_HT_SINGLE_AMPDU_8723B, val8); - - rtl8xxxu_write16(priv, REG_MAX_AGGR_NUM, 0x0c14); - if (priv->rtl_chip == RTL8723B) - val8 = 0x5e; - else if (priv->rtl_chip == RTL8188F) - val8 = 0x70; /* 0x5e would make it very slow */ - rtl8xxxu_write8(priv, REG_AMPDU_MAX_TIME_8723B, val8); - rtl8xxxu_write32(priv, REG_AGGLEN_LMT, 0xffffffff); - rtl8xxxu_write8(priv, REG_RX_PKT_LIMIT, 0x18); - rtl8xxxu_write8(priv, REG_PIFS, 0x00); - if (priv->rtl_chip == RTL8188F) { - rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL, FWHW_TXQ_CTRL_AMPDU_RETRY); - rtl8xxxu_write32(priv, REG_FAST_EDCA_CTRL, 0x03086666); - } - if (priv->rtl_chip == RTL8723B) - val8 = 0x50; - else if (priv->rtl_chip == RTL8188F) - val8 = 0x28; /* 0x50 would make the upload slow */ - rtl8xxxu_write8(priv, REG_USTIME_TSF_8723B, val8); - rtl8xxxu_write8(priv, REG_USTIME_EDCA, val8); - /* to prevent mac is reseted by bus. */ - val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL); - val8 |= BIT(5) | BIT(6); - rtl8xxxu_write8(priv, REG_RSV_CTRL, val8); - } + if (priv->fops->init_burst) + priv->fops->init_burst(priv); if (fops->init_aggregation) fops->init_aggregation(priv); @@ -4326,7 +4202,39 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) val32 &= 0xfff00fff; val32 |= 0x0007e000; rtl8xxxu_write32(priv, REG_AFE_MISC, val32); + + /* + * 0x824[9] = 0x82C[9] = 0xA80[7] those registers setting + * should be equal or CCK RSSI report may be incorrect + */ + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2); + priv->cck_agc_report_type = val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR; + + val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_HSSI_PARM2); + if (priv->cck_agc_report_type != (bool)(val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR)) { + if (priv->cck_agc_report_type) + val32 |= FPGA0_HSSI_PARM2_CCK_HIGH_PWR; + else + val32 &= ~FPGA0_HSSI_PARM2_CCK_HIGH_PWR; + rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM2, val32); + } + + val32 = rtl8xxxu_read32(priv, REG_AGC_RPT); + if (priv->cck_agc_report_type) + val32 |= AGC_RPT_CCK; + else + val32 &= ~AGC_RPT_CCK; + rtl8xxxu_write32(priv, REG_AGC_RPT, val32); } + + /* Initialise the center frequency offset tracking */ + if (priv->fops->set_crystal_cap) { + val32 = rtl8xxxu_read32(priv, REG_OFDM1_CFO_TRACKING); + priv->cfo_tracking.atc_status = val32 & CFO_TRACKING_ATC_STATUS; + priv->cfo_tracking.adjust = true; + priv->cfo_tracking.crystal_cap = priv->default_crystal_cap; + } + exit: return ret; } @@ -5294,7 +5202,8 @@ error: static void rtl8xxxu_rx_parse_phystats(struct rtl8xxxu_priv *priv, struct ieee80211_rx_status *rx_status, struct rtl8723au_phy_stats *phy_stats, - u32 rxmcs) + u32 rxmcs, struct ieee80211_hdr *hdr, + bool crc_icv_err) { if (phy_stats->sgi_en) rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; @@ -5305,21 +5214,23 @@ static void rtl8xxxu_rx_parse_phystats(struct rtl8xxxu_priv *priv, */ u8 cck_agc_rpt = phy_stats->cck_agc_rpt_ofdm_cfosho_a; - switch (cck_agc_rpt & 0xc0) { - case 0xc0: - rx_status->signal = -46 - (cck_agc_rpt & 0x3e); - break; - case 0x80: - rx_status->signal = -26 - (cck_agc_rpt & 0x3e); - break; - case 0x40: - rx_status->signal = -12 - (cck_agc_rpt & 0x3e); - break; - case 0x00: - rx_status->signal = 16 - (cck_agc_rpt & 0x3e); - break; - } + rx_status->signal = priv->fops->cck_rssi(priv, cck_agc_rpt); } else { + bool parse_cfo = priv->fops->set_crystal_cap && + priv->vif && + priv->vif->type == NL80211_IFTYPE_STATION && + priv->vif->cfg.assoc && + !crc_icv_err && + !ieee80211_is_ctl(hdr->frame_control) && + ether_addr_equal(priv->vif->bss_conf.bssid, hdr->addr2); + + if (parse_cfo) { + priv->cfo_tracking.cfo_tail[0] = phy_stats->path_cfotail[0]; + priv->cfo_tracking.cfo_tail[1] = phy_stats->path_cfotail[1]; + + priv->cfo_tracking.packet_count++; + } + rx_status->signal = (phy_stats->cck_sig_qual_ofdm_pwdb_all >> 1) - 110; } @@ -5402,7 +5313,8 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work) rtl8xxxu_queue_rx_urb(priv, rx_urb); break; default: - pr_info("failed to requeue urb %i\n", ret); + dev_warn(&priv->udev->dev, + "failed to requeue urb with error %i\n", ret); skb = (struct sk_buff *)rx_urb->urb.context; dev_kfree_skb(skb); usb_free_urb(&rx_urb->urb); @@ -5802,7 +5714,8 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) if (rx_desc->phy_stats) rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, - rx_desc->rxmcs); + rx_desc->rxmcs, (struct ieee80211_hdr *)skb->data, + rx_desc->crc32 || rx_desc->icverr); rx_status->mactime = rx_desc->tsfl; rx_status->flag |= RX_FLAG_MACTIME_START; @@ -5873,7 +5786,8 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb) if (rx_desc->phy_stats) rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats, - rx_desc->rxmcs); + rx_desc->rxmcs, (struct ieee80211_hdr *)skb->data, + rx_desc->crc32 || rx_desc->icverr); rx_status->mactime = rx_desc->tsfl; rx_status->flag |= RX_FLAG_MACTIME_START; @@ -6488,6 +6402,94 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, } } +static void rtl8xxxu_set_atc_status(struct rtl8xxxu_priv *priv, bool atc_status) +{ + struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking; + u32 val32; + + if (atc_status == cfo->atc_status) + return; + + cfo->atc_status = atc_status; + + val32 = rtl8xxxu_read32(priv, REG_OFDM1_CFO_TRACKING); + if (atc_status) + val32 |= CFO_TRACKING_ATC_STATUS; + else + val32 &= ~CFO_TRACKING_ATC_STATUS; + rtl8xxxu_write32(priv, REG_OFDM1_CFO_TRACKING, val32); +} + +/* Central frequency offset correction */ +static void rtl8xxxu_track_cfo(struct rtl8xxxu_priv *priv) +{ + struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking; + int cfo_khz_a, cfo_khz_b, cfo_average; + int crystal_cap; + + if (!priv->vif || !priv->vif->cfg.assoc) { + /* Reset */ + cfo->adjust = true; + + if (cfo->crystal_cap > priv->default_crystal_cap) + priv->fops->set_crystal_cap(priv, cfo->crystal_cap - 1); + else if (cfo->crystal_cap < priv->default_crystal_cap) + priv->fops->set_crystal_cap(priv, cfo->crystal_cap + 1); + + rtl8xxxu_set_atc_status(priv, true); + + return; + } + + if (cfo->packet_count == cfo->packet_count_pre) + /* No new information. */ + return; + + cfo->packet_count_pre = cfo->packet_count; + + /* CFO_tail[1:0] is S(8,7), (num_subcarrier>>7) x 312.5K = CFO value(K Hz) */ + cfo_khz_a = (int)((cfo->cfo_tail[0] * 3125) / 10) >> 7; + cfo_khz_b = (int)((cfo->cfo_tail[1] * 3125) / 10) >> 7; + + if (priv->tx_paths == 1) + cfo_average = cfo_khz_a; + else + cfo_average = (cfo_khz_a + cfo_khz_b) / 2; + + dev_dbg(&priv->udev->dev, "cfo_average: %d\n", cfo_average); + + if (cfo->adjust) { + if (abs(cfo_average) < CFO_TH_XTAL_LOW) + cfo->adjust = false; + } else { + if (abs(cfo_average) > CFO_TH_XTAL_HIGH) + cfo->adjust = true; + } + + /* + * TODO: We should return here only if bluetooth is enabled. + * See the vendor drivers for how to determine that. + */ + if (priv->has_bluetooth) + return; + + if (!cfo->adjust) + return; + + crystal_cap = cfo->crystal_cap; + + if (cfo_average > CFO_TH_XTAL_LOW) + crystal_cap++; + else if (cfo_average < -CFO_TH_XTAL_LOW) + crystal_cap--; + + crystal_cap = clamp(crystal_cap, 0, 0x3f); + + priv->fops->set_crystal_cap(priv, crystal_cap); + + rtl8xxxu_set_atc_status(priv, abs(cfo_average) >= CFO_TH_ATC); +} + static void rtl8xxxu_watchdog_callback(struct work_struct *work) { struct ieee80211_vif *vif; @@ -6512,6 +6514,10 @@ static void rtl8xxxu_watchdog_callback(struct work_struct *work) rcu_read_unlock(); signal = ieee80211_ave_rssi(vif); + + if (priv->fops->set_crystal_cap) + rtl8xxxu_track_cfo(priv); + rtl8xxxu_refresh_rate_mask(priv, signal, sta); } @@ -6823,12 +6829,15 @@ static int rtl8xxxu_probe(struct usb_interface *interface, if (ret) goto err_set_intfdata; - ret = rtl8xxxu_identify_chip(priv); + ret = priv->fops->identify_chip(priv); if (ret) { dev_err(&udev->dev, "Fatal - failed to identify chip\n"); goto err_set_intfdata; } + hw->wiphy->available_antennas_tx = BIT(priv->tx_paths) - 1; + hw->wiphy->available_antennas_rx = BIT(priv->rx_paths) - 1; + ret = rtl8xxxu_read_efuse(priv); if (ret) { dev_err(&udev->dev, "Fatal - failed to read EFuse\n"); @@ -6893,6 +6902,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, * The firmware handles rate control */ ieee80211_hw_set(hw, HAS_RATE_CONTROL); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, AMPDU_AGGREGATION); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 35bde1404793..3e79efdfb4c2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -68,6 +68,8 @@ #define REG_SPS_OCP_CFG 0x0018 #define REG_8192E_LDOV12_CTRL 0x0014 #define REG_RSV_CTRL 0x001c +#define RSV_CTRL_WLOCK_1C BIT(5) +#define RSV_CTRL_DIS_PRST BIT(6) #define REG_RF_CTRL 0x001f #define RF_ENABLE BIT(0) @@ -313,7 +315,6 @@ #define SYS_CFG_SPS_SEL BIT(24) /* 1:LDO regulator mode; 0:Switching regulator mode*/ #define SYS_CFG_CHIP_VERSION_MASK 0xf000 /* Bit 12 - 15 */ -#define SYS_CFG_CHIP_VERSION_SHIFT 12 #define REG_GPIO_OUTSTS 0x00f4 /* For RTL8723 only. */ #define GPIO_EFS_HCI_SEL (BIT(0) | BIT(1)) @@ -472,6 +473,9 @@ /* Presumably only found on newer chips such as 8723bu */ #define REG_RX_DMA_CTRL_8723B 0x0286 #define REG_RXDMA_PRO_8723B 0x0290 +#define RXDMA_PRO_DMA_MODE BIT(1) /* Set to 0x1. */ +#define RXDMA_PRO_DMA_BURST_CNT GENMASK(3, 2) /* Set to 0x3. */ +#define RXDMA_PRO_DMA_BURST_SIZE GENMASK(5, 4) /* Set to 0x1. */ #define REG_RF_BB_CMD_ADDR 0x02c0 #define REG_RF_BB_CMD_DATA 0x02c4 @@ -577,6 +581,7 @@ #define REG_STBC_SETTING 0x04c4 #define REG_QUEUE_CTRL 0x04c6 #define REG_HT_SINGLE_AMPDU_8723B 0x04c7 +#define HT_SINGLE_AMPDU_ENABLE BIT(7) #define REG_PROT_MODE_CTRL 0x04c8 #define REG_MAX_AGGR_NUM 0x04ca #define REG_RTS_MAX_AGGR_NUM 0x04cb @@ -960,6 +965,9 @@ #define CCK_PD_TYPE1_LV3_TH 0xdd #define CCK_PD_TYPE1_LV4_TH 0xed +#define REG_AGC_RPT 0xa80 +#define AGC_RPT_CCK BIT(7) + #define REG_CONFIG_ANT_A 0x0b68 #define REG_CONFIG_ANT_B 0x0b6c @@ -1027,6 +1035,7 @@ #define REG_OFDM1_TRX_PATH_ENABLE 0x0d04 #define REG_OFDM1_CFO_TRACKING 0x0d2c +#define CFO_TRACKING_ATC_STATUS BIT(11) #define REG_OFDM1_CSI_FIX_MASK1 0x0d40 #define REG_OFDM1_CSI_FIX_MASK2 0x0d44 diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index 8043d819fb85..a182cdeb58e2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -997,7 +997,6 @@ bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index) struct rtl_priv *rtlpriv = rtl_priv(hw); u16 read_point, write_point; bool ret = false; - static u8 stop_report_cnt; struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; { @@ -1038,13 +1037,6 @@ bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index) rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) ret = true; - if (hw_queue < BEACON_QUEUE) { - if (!ret) - stop_report_cnt++; - else - stop_report_cnt = 0; - } - return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index ec0f5da65d6a..2dc48fa10c6b 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -15,6 +15,8 @@ rtw89_core-y += core.o \ chan.o \ ser.o +rtw89_core-$(CONFIG_PM) += wow.o + obj-$(CONFIG_RTW89_8852A) += rtw89_8852a.o rtw89_8852a-objs := rtw8852a.o \ rtw8852a_table.o \ diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index a0fa9639b509..f30aadc41f2b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -171,7 +171,7 @@ bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitr return true; } -static struct ieee80211_supported_band rtw89_sband_2ghz = { +static const struct ieee80211_supported_band rtw89_sband_2ghz = { .band = NL80211_BAND_2GHZ, .channels = rtw89_channels_2ghz, .n_channels = ARRAY_SIZE(rtw89_channels_2ghz), @@ -181,7 +181,7 @@ static struct ieee80211_supported_band rtw89_sband_2ghz = { .vht_cap = {0}, }; -static struct ieee80211_supported_band rtw89_sband_5ghz = { +static const struct ieee80211_supported_band rtw89_sband_5ghz = { .band = NL80211_BAND_5GHZ, .channels = rtw89_channels_5ghz, .n_channels = ARRAY_SIZE(rtw89_channels_5ghz), @@ -193,7 +193,7 @@ static struct ieee80211_supported_band rtw89_sband_5ghz = { .vht_cap = {0}, }; -static struct ieee80211_supported_band rtw89_sband_6ghz = { +static const struct ieee80211_supported_band rtw89_sband_6ghz = { .band = NL80211_BAND_6GHZ, .channels = rtw89_channels_6ghz, .n_channels = ARRAY_SIZE(rtw89_channels_6ghz), @@ -2204,6 +2204,9 @@ static void rtw89_track_work(struct work_struct *work) track_work.work); bool tfc_changed; + if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags)) + return; + mutex_lock(&rtwdev->mutex); if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) @@ -2413,6 +2416,8 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { rtwsta->mac_id = rtw89_core_acquire_bit_map(rtwdev->mac_id_map, RTW89_MAX_MAC_ID_NUM); + if (rtwsta->mac_id == RTW89_MAX_MAC_ID_NUM) + return -ENOSPC; } return 0; @@ -2530,7 +2535,7 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, } /* update cam aid mac_id net_type */ - rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; @@ -2960,7 +2965,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) return ret; rtw89_phy_init_bb_reg(rtwdev); - rtw89_phy_init_rf_reg(rtwdev); + rtw89_phy_init_rf_reg(rtwdev, false); rtw89_btc_ntfy_init(rtwdev, BTC_MODE_NORMAL); @@ -3040,6 +3045,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) continue; INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]); } + INIT_LIST_HEAD(&rtwdev->wow.pkt_list); INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work); INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work); INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work); @@ -3271,6 +3277,10 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) hw->wiphy->max_scan_ssids = RTW89_SCANOFLD_MAX_SSID; hw->wiphy->max_scan_ie_len = RTW89_SCANOFLD_MAX_IE_LEN; +#ifdef CONFIG_PM + hw->wiphy->wowlan = rtwdev->chip->wowlan_stub; +#endif + hw->wiphy->tid_config_support.vif |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL); hw->wiphy->tid_config_support.peer |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL); hw->wiphy->tid_config_support.vif |= BIT(NL80211_TID_CONFIG_ATTR_AMSDU_CTRL); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 90bf7bdb6062..b60de6662548 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -178,7 +178,9 @@ enum rtw89_upd_mode { RTW89_ROLE_REMOVE, RTW89_ROLE_TYPE_CHANGE, RTW89_ROLE_INFO_CHANGE, - RTW89_ROLE_CON_DISCONN + RTW89_ROLE_CON_DISCONN, + RTW89_ROLE_BAND_SW, + RTW89_ROLE_FW_RESTORE, }; enum rtw89_self_role { @@ -477,6 +479,20 @@ enum rtw89_regulation_type { RTW89_REGD_NUM, }; +enum rtw89_fw_pkt_ofld_type { + RTW89_PKT_OFLD_TYPE_PROBE_RSP = 0, + RTW89_PKT_OFLD_TYPE_PS_POLL = 1, + RTW89_PKT_OFLD_TYPE_NULL_DATA = 2, + RTW89_PKT_OFLD_TYPE_QOS_NULL = 3, + RTW89_PKT_OFLD_TYPE_CTS2SELF = 4, + RTW89_PKT_OFLD_TYPE_ARP_RSP = 5, + RTW89_PKT_OFLD_TYPE_NDP = 6, + RTW89_PKT_OFLD_TYPE_EAPOL_KEY = 7, + RTW89_PKT_OFLD_TYPE_SA_QUERY = 8, + RTW89_PKT_OFLD_TYPE_PROBE_REQ = 12, + RTW89_PKT_OFLD_TYPE_NUM, +}; + struct rtw89_txpwr_byrate { s8 cck[RTW89_RATE_CCK_MAX]; s8 ofdm[RTW89_RATE_OFDM_MAX]; @@ -636,6 +652,13 @@ enum rtw89_sc_offset { RTW89_SC_40_LOWER = 10, }; +enum rtw89_wow_flags { + RTW89_WOW_FLAG_EN_MAGIC_PKT, + RTW89_WOW_FLAG_EN_REKEY_PKT, + RTW89_WOW_FLAG_EN_DISCONNECT, + RTW89_WOW_FLAG_NUM, +}; + struct rtw89_chan { u8 channel; u8 primary_channel; @@ -2286,6 +2309,16 @@ struct rtw89_hci_ops { */ void (*recovery_start)(struct rtw89_dev *rtwdev); void (*recovery_complete)(struct rtw89_dev *rtwdev); + + void (*ctrl_txdma_ch)(struct rtw89_dev *rtwdev, bool enable); + void (*ctrl_txdma_fw_ch)(struct rtw89_dev *rtwdev, bool enable); + void (*ctrl_trxhci)(struct rtw89_dev *rtwdev, bool enable); + int (*poll_txdma_ch)(struct rtw89_dev *rtwdev); + void (*clr_idx_all)(struct rtw89_dev *rtwdev); + void (*clear)(struct rtw89_dev *rtwdev, struct pci_dev *pdev); + void (*disable_intr)(struct rtw89_dev *rtwdev); + void (*enable_intr)(struct rtw89_dev *rtwdev); + int (*rst_bdram)(struct rtw89_dev *rtwdev); }; struct rtw89_hci_info { @@ -2389,6 +2422,7 @@ enum rtw89_dma_ch { enum rtw89_qta_mode { RTW89_QTA_SCC, RTW89_QTA_DLFW, + RTW89_QTA_WOW, /* keep last */ RTW89_QTA_INVALID, @@ -2623,6 +2657,8 @@ struct rtw89_chip_info { u32 rsvd_ple_ofst; const struct rtw89_hfc_param_ini *hfc_param_ini; const struct rtw89_dle_mem *dle_mem; + u8 wde_qempty_acq_num; + u8 wde_qempty_mgq_sel; u32 rf_base_addr[2]; u8 support_chanctx_num; u8 support_bands; @@ -2724,6 +2760,7 @@ struct rtw89_chip_info { const struct rtw89_imr_info *imr_info; const struct rtw89_rrsr_cfgs *rrsr_cfgs; u32 dma_ch_mask; + const struct wiphy_wowlan_support *wowlan_stub; }; union rtw89_bus_info { @@ -2920,6 +2957,8 @@ enum rtw89_flags { RTW89_FLAG_LOW_POWER_MODE, RTW89_FLAG_INACTIVE_PS, RTW89_FLAG_CRASH_SIMULATING, + RTW89_FLAG_WOWLAN, + RTW89_FLAG_FORBIDDEN_TRACK_WROK, NUM_OF_RTW89_FLAGS, }; @@ -2948,6 +2987,7 @@ struct rtw89_pkt_drop_params { u8 port; u8 mbssid; bool tf_trs; + u32 macid_band_sel[4]; }; struct rtw89_pkt_stat { @@ -3449,6 +3489,31 @@ struct rtw89_phy_efuse_gain { s8 comp[RF_PATH_MAX][RTW89_SUBBAND_NR]; /* S(8, 0) */ }; +#define RTW89_MAX_PATTERN_NUM 18 +#define RTW89_MAX_PATTERN_MASK_SIZE 4 +#define RTW89_MAX_PATTERN_SIZE 128 + +struct rtw89_wow_cam_info { + bool r_w; + u8 idx; + u32 mask[RTW89_MAX_PATTERN_MASK_SIZE]; + u16 crc; + bool negative_pattern_match; + bool skip_mac_hdr; + bool uc; + bool mc; + bool bc; + bool valid; +}; + +struct rtw89_wow_param { + struct ieee80211_vif *wow_vif; + DECLARE_BITMAP(flags, RTW89_WOW_FLAG_NUM); + struct rtw89_wow_cam_info patterns[RTW89_MAX_PATTERN_NUM]; + u8 pattern_cnt; + struct list_head pkt_list; +}; + struct rtw89_dev { struct ieee80211_hw *hw; struct device *dev; @@ -3537,6 +3602,8 @@ struct rtw89_dev { enum rtw89_ps_mode ps_mode; bool lps_enabled; + struct rtw89_wow_param wow; + /* napi structure */ struct net_device netdev; struct napi_struct napi; @@ -3619,6 +3686,66 @@ static inline void rtw89_hci_recovery_complete(struct rtw89_dev *rtwdev) rtwdev->hci.ops->recovery_complete(rtwdev); } +static inline void rtw89_hci_enable_intr(struct rtw89_dev *rtwdev) +{ + if (rtwdev->hci.ops->enable_intr) + rtwdev->hci.ops->enable_intr(rtwdev); +} + +static inline void rtw89_hci_disable_intr(struct rtw89_dev *rtwdev) +{ + if (rtwdev->hci.ops->disable_intr) + rtwdev->hci.ops->disable_intr(rtwdev); +} + +static inline void rtw89_hci_ctrl_txdma_ch(struct rtw89_dev *rtwdev, bool enable) +{ + if (rtwdev->hci.ops->ctrl_txdma_ch) + rtwdev->hci.ops->ctrl_txdma_ch(rtwdev, enable); +} + +static inline void rtw89_hci_ctrl_txdma_fw_ch(struct rtw89_dev *rtwdev, bool enable) +{ + if (rtwdev->hci.ops->ctrl_txdma_fw_ch) + rtwdev->hci.ops->ctrl_txdma_fw_ch(rtwdev, enable); +} + +static inline void rtw89_hci_ctrl_trxhci(struct rtw89_dev *rtwdev, bool enable) +{ + if (rtwdev->hci.ops->ctrl_trxhci) + rtwdev->hci.ops->ctrl_trxhci(rtwdev, enable); +} + +static inline int rtw89_hci_poll_txdma_ch(struct rtw89_dev *rtwdev) +{ + int ret = 0; + + if (rtwdev->hci.ops->poll_txdma_ch) + ret = rtwdev->hci.ops->poll_txdma_ch(rtwdev); + return ret; +} + +static inline void rtw89_hci_clr_idx_all(struct rtw89_dev *rtwdev) +{ + if (rtwdev->hci.ops->clr_idx_all) + rtwdev->hci.ops->clr_idx_all(rtwdev); +} + +static inline int rtw89_hci_rst_bdram(struct rtw89_dev *rtwdev) +{ + int ret = 0; + + if (rtwdev->hci.ops->rst_bdram) + ret = rtwdev->hci.ops->rst_bdram(rtwdev); + return ret; +} + +static inline void rtw89_hci_clear(struct rtw89_dev *rtwdev, struct pci_dev *pdev) +{ + if (rtwdev->hci.ops->clear) + rtwdev->hci.ops->clear(rtwdev, pdev); +} + static inline u8 rtw89_read8(struct rtw89_dev *rtwdev, u32 addr) { return rtwdev->hci.ops->read8(rtwdev, addr); diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 8f27c883eeab..8297e35bfa52 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -8,6 +8,7 @@ #include "debug.h" #include "fw.h" #include "mac.h" +#include "pci.h" #include "ps.h" #include "reg.h" #include "sar.h" @@ -51,6 +52,22 @@ struct rtw89_debugfs_priv { }; }; +static const u16 rtw89_rate_info_bw_to_mhz_map[] = { + [RATE_INFO_BW_20] = 20, + [RATE_INFO_BW_40] = 40, + [RATE_INFO_BW_80] = 80, + [RATE_INFO_BW_160] = 160, + [RATE_INFO_BW_320] = 320, +}; + +static u16 rtw89_rate_info_bw_to_mhz(enum rate_info_bw bw) +{ + if (bw < ARRAY_SIZE(rtw89_rate_info_bw_to_mhz_map)) + return rtw89_rate_info_bw_to_mhz_map[bw]; + + return 0; +} + static int rtw89_debugfs_single_show(struct seq_file *m, void *v) { struct rtw89_debugfs_priv *debugfs_priv = m->private; @@ -972,7 +989,9 @@ static int rtw89_debug_mac_dump_dle_dbg(struct rtw89_dev *rtwdev, static int rtw89_debug_mac_dump_dmac_dbg(struct rtw89_dev *rtwdev, struct seq_file *m) { - int ret; + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 dmac_err; + int i, ret; ret = rtw89_mac_check_mac_en(rtwdev, 0, RTW89_DMAC_SEL); if (ret) { @@ -980,98 +999,347 @@ static int rtw89_debug_mac_dump_dmac_dbg(struct rtw89_dev *rtwdev, return ret; } - seq_printf(m, "R_AX_DMAC_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_DMAC_ERR_ISR)); - seq_printf(m, "[0]R_AX_WDRLS_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_WDRLS_ERR_ISR)); - seq_printf(m, "[1]R_AX_SEC_ERR_IMR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_ERR_IMR_ISR)); - seq_printf(m, "[2.1]R_AX_MPDU_TX_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_ISR)); - seq_printf(m, "[2.2]R_AX_MPDU_RX_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_ISR)); - seq_printf(m, "[3]R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); - seq_printf(m, "[4]R_AX_WDE_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); - seq_printf(m, "[5.1]R_AX_TXPKTCTL_ERR_IMR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR)); - seq_printf(m, "[5.2]R_AX_TXPKTCTL_ERR_IMR_ISR_B1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR_B1)); - seq_printf(m, "[6]R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); - seq_printf(m, "[7]R_AX_PKTIN_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); - seq_printf(m, "[8.1]R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); - seq_printf(m, "[8.2]R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); - seq_printf(m, "[8.3]R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); - seq_printf(m, "[10]R_AX_CPUIO_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_CPUIO_ERR_ISR)); - seq_printf(m, "[11.1]R_AX_BBRPT_COM_ERR_IMR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR_ISR)); - seq_printf(m, "[11.2]R_AX_BBRPT_CHINFO_ERR_IMR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR_ISR)); - seq_printf(m, "[11.3]R_AX_BBRPT_DFS_ERR_IMR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR_ISR)); - seq_printf(m, "[11.4]R_AX_LA_ERRFLAG=0x%08x\n", - rtw89_read32(rtwdev, R_AX_LA_ERRFLAG)); + dmac_err = rtw89_read32(rtwdev, R_AX_DMAC_ERR_ISR); + seq_printf(m, "R_AX_DMAC_ERR_ISR=0x%08x\n", dmac_err); + seq_printf(m, "R_AX_DMAC_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DMAC_ERR_IMR)); + + if (dmac_err) { + seq_printf(m, "R_AX_WDE_ERR_FLAG_CFG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_FLAG_CFG_NUM1)); + seq_printf(m, "R_AX_PLE_ERR_FLAG_CFG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_CFG_NUM1)); + if (chip->chip_id == RTL8852C) { + seq_printf(m, "R_AX_PLE_ERRFLAG_MSG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERRFLAG_MSG)); + seq_printf(m, "R_AX_WDE_ERRFLAG_MSG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERRFLAG_MSG)); + seq_printf(m, "R_AX_PLE_DBGERR_LOCKEN=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_DBGERR_LOCKEN)); + seq_printf(m, "R_AX_PLE_DBGERR_STS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_DBGERR_STS)); + } + } + + if (dmac_err & B_AX_WDRLS_ERR_FLAG) { + seq_printf(m, "R_AX_WDRLS_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDRLS_ERR_IMR)); + seq_printf(m, "R_AX_WDRLS_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDRLS_ERR_ISR)); + if (chip->chip_id == RTL8852C) + seq_printf(m, "R_AX_RPQ_RXBD_IDX=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX_V1)); + else + seq_printf(m, "R_AX_RPQ_RXBD_IDX=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); + } + + if (dmac_err & B_AX_WSEC_ERR_FLAG) { + if (chip->chip_id == RTL8852C) { + seq_printf(m, "R_AX_SEC_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_ERROR_FLAG_IMR)); + seq_printf(m, "R_AX_SEC_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_ERROR_FLAG)); + seq_printf(m, "R_AX_SEC_ENG_CTRL=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); + seq_printf(m, "R_AX_SEC_MPDU_PROC=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); + seq_printf(m, "R_AX_SEC_CAM_ACCESS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); + seq_printf(m, "R_AX_SEC_CAM_RDATA=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); + seq_printf(m, "R_AX_SEC_DEBUG1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_DEBUG1)); + seq_printf(m, "R_AX_SEC_TX_DEBUG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); + seq_printf(m, "R_AX_SEC_RX_DEBUG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); + + rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, + B_AX_DBG_SEL0, 0x8B); + rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, + B_AX_DBG_SEL1, 0x8B); + rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, + B_AX_SEL_0XC0_MASK, 1); + for (i = 0; i < 0x10; i++) { + rtw89_write32_mask(rtwdev, R_AX_SEC_ENG_CTRL, + B_AX_SEC_DBG_PORT_FIELD_MASK, i); + seq_printf(m, "sel=%x,R_AX_SEC_DEBUG2=0x%08x\n", + i, rtw89_read32(rtwdev, R_AX_SEC_DEBUG2)); + } + } else { + seq_printf(m, "R_AX_SEC_ERR_IMR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_DEBUG)); + seq_printf(m, "R_AX_SEC_ENG_CTRL=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); + seq_printf(m, "R_AX_SEC_MPDU_PROC=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); + seq_printf(m, "R_AX_SEC_CAM_ACCESS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); + seq_printf(m, "R_AX_SEC_CAM_RDATA=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); + seq_printf(m, "R_AX_SEC_CAM_WDATA=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_WDATA)); + seq_printf(m, "R_AX_SEC_TX_DEBUG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); + seq_printf(m, "R_AX_SEC_RX_DEBUG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); + seq_printf(m, "R_AX_SEC_TRX_PKT_CNT=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TRX_PKT_CNT)); + seq_printf(m, "R_AX_SEC_TRX_BLK_CNT=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TRX_BLK_CNT)); + } + } + + if (dmac_err & B_AX_MPDU_ERR_FLAG) { + seq_printf(m, "R_AX_MPDU_TX_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_IMR)); + seq_printf(m, "R_AX_MPDU_TX_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_ISR)); + seq_printf(m, "R_AX_MPDU_RX_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_IMR)); + seq_printf(m, "R_AX_MPDU_RX_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_ISR)); + } + + if (dmac_err & B_AX_STA_SCHEDULER_ERR_FLAG) { + seq_printf(m, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR)); + seq_printf(m, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); + } + + if (dmac_err & B_AX_WDE_DLE_ERR_FLAG) { + seq_printf(m, "R_AX_WDE_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); + seq_printf(m, "R_AX_WDE_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); + seq_printf(m, "R_AX_PLE_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); + seq_printf(m, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); + } + + if (dmac_err & B_AX_TXPKTCTRL_ERR_FLAG) { + if (chip->chip_id == RTL8852C) { + seq_printf(m, "R_AX_TXPKTCTL_B0_ERRFLAG_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_IMR)); + seq_printf(m, "R_AX_TXPKTCTL_B0_ERRFLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_ISR)); + seq_printf(m, "R_AX_TXPKTCTL_B1_ERRFLAG_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_B1_ERRFLAG_IMR)); + seq_printf(m, "R_AX_TXPKTCTL_B1_ERRFLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_B1_ERRFLAG_ISR)); + } else { + seq_printf(m, "R_AX_TXPKTCTL_ERR_IMR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR)); + seq_printf(m, "R_AX_TXPKTCTL_ERR_IMR_ISR_B1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR_B1)); + } + } + + if (dmac_err & B_AX_PLE_DLE_ERR_FLAG) { + seq_printf(m, "R_AX_WDE_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); + seq_printf(m, "R_AX_WDE_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); + seq_printf(m, "R_AX_PLE_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); + seq_printf(m, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); + seq_printf(m, "R_AX_WD_CPUQ_OP_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_0)); + seq_printf(m, "R_AX_WD_CPUQ_OP_1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_1)); + seq_printf(m, "R_AX_WD_CPUQ_OP_2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_2)); + seq_printf(m, "R_AX_WD_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_STATUS)); + seq_printf(m, "R_AX_PL_CPUQ_OP_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_0)); + seq_printf(m, "R_AX_PL_CPUQ_OP_1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_1)); + seq_printf(m, "R_AX_PL_CPUQ_OP_2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_2)); + seq_printf(m, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS)); + if (chip->chip_id == RTL8852C) { + seq_printf(m, "R_AX_RX_CTRL0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL0)); + seq_printf(m, "R_AX_RX_CTRL1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL1)); + seq_printf(m, "R_AX_RX_CTRL2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL2)); + } else { + seq_printf(m, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); + seq_printf(m, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); + seq_printf(m, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); + } + } + + if (dmac_err & B_AX_PKTIN_ERR_FLAG) { + seq_printf(m, "R_AX_PKTIN_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PKTIN_ERR_IMR)); + seq_printf(m, "R_AX_PKTIN_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); + } + + if (dmac_err & B_AX_DISPATCH_ERR_FLAG) { + seq_printf(m, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); + seq_printf(m, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); + seq_printf(m, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR)); + seq_printf(m, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); + seq_printf(m, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR)); + seq_printf(m, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); + } + + if (dmac_err & B_AX_BBRPT_ERR_FLAG) { + if (chip->chip_id == RTL8852C) { + seq_printf(m, "R_AX_BBRPT_COM_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR)); + seq_printf(m, "R_AX_BBRPT_COM_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_ISR)); + seq_printf(m, "R_AX_BBRPT_CHINFO_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_ISR)); + seq_printf(m, "R_AX_BBRPT_CHINFO_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR)); + seq_printf(m, "R_AX_BBRPT_DFS_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR)); + seq_printf(m, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); + } else { + seq_printf(m, "R_AX_BBRPT_COM_ERR_IMR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR_ISR)); + seq_printf(m, "R_AX_BBRPT_CHINFO_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_ISR)); + seq_printf(m, "R_AX_BBRPT_CHINFO_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR)); + seq_printf(m, "R_AX_BBRPT_DFS_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR)); + seq_printf(m, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); + } + } + + if (dmac_err & B_AX_HAXIDMA_ERR_FLAG && chip->chip_id == RTL8852C) { + seq_printf(m, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK)); + seq_printf(m, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HAXI_IDCT)); + } return 0; } -static int rtw89_debug_mac_dump_cmac_dbg(struct rtw89_dev *rtwdev, - struct seq_file *m) +static int rtw89_debug_mac_dump_cmac_err(struct rtw89_dev *rtwdev, + struct seq_file *m, + enum rtw89_mac_idx band) { + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 offset = 0; + u32 cmac_err; int ret; - ret = rtw89_mac_check_mac_en(rtwdev, 0, RTW89_CMAC_SEL); + ret = rtw89_mac_check_mac_en(rtwdev, band, RTW89_CMAC_SEL); if (ret) { - seq_puts(m, "[CMAC] : CMAC 0 not enabled\n"); + if (band) + seq_puts(m, "[CMAC] : CMAC1 not enabled\n"); + else + seq_puts(m, "[CMAC] : CMAC0 not enabled\n"); return ret; } - seq_printf(m, "R_AX_CMAC_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR)); - seq_printf(m, "[0]R_AX_SCHEDULE_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_ISR)); - seq_printf(m, "[1]R_AX_PTCL_ISR0=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PTCL_ISR0)); - seq_printf(m, "[3]R_AX_DLE_CTRL=0x%08x\n", - rtw89_read32(rtwdev, R_AX_DLE_CTRL)); - seq_printf(m, "[4]R_AX_PHYINFO_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR)); - seq_printf(m, "[5]R_AX_TXPWR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_TXPWR_ISR)); - seq_printf(m, "[6]R_AX_RMAC_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RMAC_ERR_ISR)); - seq_printf(m, "[7]R_AX_TMAC_ERR_IMR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR)); - - ret = rtw89_mac_check_mac_en(rtwdev, 1, RTW89_CMAC_SEL); - if (ret) { - seq_puts(m, "[CMAC] : CMAC 1 not enabled\n"); - return ret; + if (band) + offset = RTW89_MAC_AX_BAND_REG_OFFSET; + + cmac_err = rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR + offset); + seq_printf(m, "R_AX_CMAC_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR + offset)); + seq_printf(m, "R_AX_CMAC_FUNC_EN [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_CMAC_FUNC_EN + offset)); + seq_printf(m, "R_AX_CK_EN [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_CK_EN + offset)); + + if (cmac_err & B_AX_SCHEDULE_TOP_ERR_IND) { + seq_printf(m, "R_AX_SCHEDULE_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_IMR + offset)); + seq_printf(m, "R_AX_SCHEDULE_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_ISR + offset)); } - seq_printf(m, "R_AX_CMAC_ERR_ISR_C1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR_C1)); - seq_printf(m, "[0]R_AX_SCHEDULE_ERR_ISR_C1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_ISR_C1)); - seq_printf(m, "[1]R_AX_PTCL_ISR0_C1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PTCL_ISR0_C1)); - seq_printf(m, "[3]R_AX_DLE_CTRL_C1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_DLE_CTRL_C1)); - seq_printf(m, "[4]R_AX_PHYINFO_ERR_ISR_C1=0x%02x\n", - rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR_C1)); - seq_printf(m, "[5]R_AX_TXPWR_ISR_C1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_TXPWR_ISR_C1)); - seq_printf(m, "[6]R_AX_RMAC_ERR_ISR_C1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RMAC_ERR_ISR_C1)); - seq_printf(m, "[7]R_AX_TMAC_ERR_IMR_ISR_C1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR_C1)); + if (cmac_err & B_AX_PTCL_TOP_ERR_IND) { + seq_printf(m, "R_AX_PTCL_IMR0 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PTCL_IMR0 + offset)); + seq_printf(m, "R_AX_PTCL_ISR0 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PTCL_ISR0 + offset)); + } + + if (cmac_err & B_AX_DMA_TOP_ERR_IND) { + if (chip->chip_id == RTL8852C) { + seq_printf(m, "R_AX_RX_ERR_FLAG [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_RX_ERR_FLAG + offset)); + seq_printf(m, "R_AX_RX_ERR_FLAG_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_RX_ERR_FLAG_IMR + offset)); + } else { + seq_printf(m, "R_AX_DLE_CTRL [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_DLE_CTRL + offset)); + } + } + + if (cmac_err & B_AX_DMA_TOP_ERR_IND || cmac_err & B_AX_WMAC_RX_ERR_IND) { + if (chip->chip_id == RTL8852C) { + seq_printf(m, "R_AX_PHYINFO_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR + offset)); + seq_printf(m, "R_AX_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR + offset)); + } else { + seq_printf(m, "R_AX_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR + offset)); + } + } + + if (cmac_err & B_AX_TXPWR_CTRL_ERR_IND) { + seq_printf(m, "R_AX_TXPWR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TXPWR_IMR + offset)); + seq_printf(m, "R_AX_TXPWR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TXPWR_ISR + offset)); + } + + if (cmac_err & B_AX_WMAC_TX_ERR_IND) { + if (chip->chip_id == RTL8852C) { + seq_printf(m, "R_AX_TRXPTCL_ERROR_INDICA [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TRXPTCL_ERROR_INDICA + offset)); + seq_printf(m, "R_AX_TRXPTCL_ERROR_INDICA_MASK [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TRXPTCL_ERROR_INDICA_MASK + offset)); + } else { + seq_printf(m, "R_AX_TMAC_ERR_IMR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR + offset)); + } + seq_printf(m, "R_AX_DBGSEL_TRXPTCL [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL + offset)); + } + + seq_printf(m, "R_AX_CMAC_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_CMAC_ERR_IMR + offset)); + + return 0; +} + +static int rtw89_debug_mac_dump_cmac_dbg(struct rtw89_dev *rtwdev, + struct seq_file *m) +{ + rtw89_debug_mac_dump_cmac_err(rtwdev, m, RTW89_MAC_0); + if (rtwdev->dbcc_en) + rtw89_debug_mac_dump_cmac_err(rtwdev, m, RTW89_MAC_1); return 0; } @@ -1098,6 +1366,303 @@ static const struct rtw89_mac_dbg_port_info dbg_port_ptcl_c1 = { .rd_msk = B_AX_PTCL_DBG_INFO_MASK }; +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx0_5 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0xD, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx6 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x5, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx7 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x9, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx8 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x3, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx9_C = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x1, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_txD = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x0, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx0 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0xB, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx1 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x4, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx3 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x8, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx4 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x7, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx5_8 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x1, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx9 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x3, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_txA_C = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x0, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx0 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x8, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx1_2 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x0, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx3 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x6, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx4 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x0, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx5 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 2, + .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, + .srt = 0x0, + .end = 0x0, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_rx_p0_0 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 1, + .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, + .srt = 0x0, + .end = 0x3, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_rx_p0_1 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 1, + .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, + .srt = 0x0, + .end = 0x6, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_rx_p0_2 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 1, + .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, + .srt = 0x0, + .end = 0x0, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_rx_p1 = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 1, + .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, + .srt = 0x8, + .end = 0xE, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_stf_ctrl = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 1, + .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, + .srt = 0x0, + .end = 0x5, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_addr_ctrl = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 1, + .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, + .srt = 0x0, + .end = 0x6, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_wde_intf = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 1, + .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, + .srt = 0x0, + .end = 0xF, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_ple_intf = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 1, + .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, + .srt = 0x0, + .end = 0x9, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + +static const struct rtw89_mac_dbg_port_info dbg_port_dspt_flow_ctrl = { + .sel_addr = R_AX_DISPATCHER_DBG_PORT, + .sel_byte = 1, + .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, + .srt = 0x0, + .end = 0x3, + .rd_addr = R_AX_DBG_PORT_SEL, + .rd_byte = 4, + .rd_msk = B_AX_DEBUG_ST_MASK +}; + static const struct rtw89_mac_dbg_port_info dbg_port_sch_c0 = { .sel_addr = R_AX_SCH_DBG_SEL, .sel_byte = 1, @@ -1508,7 +2073,7 @@ static const struct rtw89_mac_dbg_port_info dbg_port_pktinfo = { static const struct rtw89_mac_dbg_port_info dbg_port_pcie_txdma = { .sel_addr = R_AX_PCIE_DBG_CTRL, .sel_byte = 2, - .sel_msk = B_AX_DBG_SEL_MASK, + .sel_msk = B_AX_PCIE_DBG_SEL_MASK, .srt = 0x00, .end = 0x03, .rd_addr = R_AX_DBG_PORT_SEL, @@ -1519,7 +2084,7 @@ static const struct rtw89_mac_dbg_port_info dbg_port_pcie_txdma = { static const struct rtw89_mac_dbg_port_info dbg_port_pcie_rxdma = { .sel_addr = R_AX_PCIE_DBG_CTRL, .sel_byte = 2, - .sel_msk = B_AX_DBG_SEL_MASK, + .sel_msk = B_AX_PCIE_DBG_SEL_MASK, .srt = 0x00, .end = 0x04, .rd_addr = R_AX_DBG_PORT_SEL, @@ -1530,7 +2095,7 @@ static const struct rtw89_mac_dbg_port_info dbg_port_pcie_rxdma = { static const struct rtw89_mac_dbg_port_info dbg_port_pcie_cvt = { .sel_addr = R_AX_PCIE_DBG_CTRL, .sel_byte = 2, - .sel_msk = B_AX_DBG_SEL_MASK, + .sel_msk = B_AX_PCIE_DBG_SEL_MASK, .srt = 0x00, .end = 0x01, .rd_addr = R_AX_DBG_PORT_SEL, @@ -1541,7 +2106,7 @@ static const struct rtw89_mac_dbg_port_info dbg_port_pcie_cvt = { static const struct rtw89_mac_dbg_port_info dbg_port_pcie_cxpl = { .sel_addr = R_AX_PCIE_DBG_CTRL, .sel_byte = 2, - .sel_msk = B_AX_DBG_SEL_MASK, + .sel_msk = B_AX_PCIE_DBG_SEL_MASK, .srt = 0x00, .end = 0x05, .rd_addr = R_AX_DBG_PORT_SEL, @@ -1552,7 +2117,7 @@ static const struct rtw89_mac_dbg_port_info dbg_port_pcie_cxpl = { static const struct rtw89_mac_dbg_port_info dbg_port_pcie_io = { .sel_addr = R_AX_PCIE_DBG_CTRL, .sel_byte = 2, - .sel_msk = B_AX_DBG_SEL_MASK, + .sel_msk = B_AX_PCIE_DBG_SEL_MASK, .srt = 0x00, .end = 0x05, .rd_addr = R_AX_DBG_PORT_SEL, @@ -1563,7 +2128,7 @@ static const struct rtw89_mac_dbg_port_info dbg_port_pcie_io = { static const struct rtw89_mac_dbg_port_info dbg_port_pcie_misc = { .sel_addr = R_AX_PCIE_DBG_CTRL, .sel_byte = 2, - .sel_msk = B_AX_DBG_SEL_MASK, + .sel_msk = B_AX_PCIE_DBG_SEL_MASK, .srt = 0x00, .end = 0x06, .rd_addr = R_AX_DBG_PORT_SEL, @@ -1587,6 +2152,7 @@ rtw89_debug_mac_dbg_port_sel(struct seq_file *m, struct rtw89_dev *rtwdev, u32 sel) { const struct rtw89_mac_dbg_port_info *info; + u32 index; u32 val32; u16 val16; u8 val8; @@ -1862,6 +2428,235 @@ rtw89_debug_mac_dbg_port_sel(struct seq_file *m, info = &dbg_port_pktinfo; seq_puts(m, "Enable pktinfo dump.\n"); break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX0: + rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, + B_AX_DBG_SEL0, 0x80); + rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, + B_AX_SEL_0XC0_MASK, 1); + fallthrough; + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX1: + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX2: + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX3: + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX4: + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX5: + info = &dbg_port_dspt_hdt_tx0_5; + index = sel - RTW89_DBG_PORT_SEL_DSPT_HDT_TX0; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 0); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, index); + seq_printf(m, "Enable Dispatcher hdt tx%x dump.\n", index); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX6: + info = &dbg_port_dspt_hdt_tx6; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 0); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 6); + seq_puts(m, "Enable Dispatcher hdt tx6 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX7: + info = &dbg_port_dspt_hdt_tx7; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 0); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 7); + seq_puts(m, "Enable Dispatcher hdt tx7 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX8: + info = &dbg_port_dspt_hdt_tx8; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 0); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 8); + seq_puts(m, "Enable Dispatcher hdt tx8 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_TX9: + case RTW89_DBG_PORT_SEL_DSPT_HDT_TXA: + case RTW89_DBG_PORT_SEL_DSPT_HDT_TXB: + case RTW89_DBG_PORT_SEL_DSPT_HDT_TXC: + info = &dbg_port_dspt_hdt_tx9_C; + index = sel + 9 - RTW89_DBG_PORT_SEL_DSPT_HDT_TX9; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 0); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, index); + seq_printf(m, "Enable Dispatcher hdt tx%x dump.\n", index); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_TXD: + info = &dbg_port_dspt_hdt_txD; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 0); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 0xD); + seq_puts(m, "Enable Dispatcher hdt txD dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_TX0: + info = &dbg_port_dspt_cdt_tx0; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 1); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 0); + seq_puts(m, "Enable Dispatcher cdt tx0 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_TX1: + info = &dbg_port_dspt_cdt_tx1; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 1); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 1); + seq_puts(m, "Enable Dispatcher cdt tx1 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_TX3: + info = &dbg_port_dspt_cdt_tx3; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 1); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 3); + seq_puts(m, "Enable Dispatcher cdt tx3 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_TX4: + info = &dbg_port_dspt_cdt_tx4; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 1); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 4); + seq_puts(m, "Enable Dispatcher cdt tx4 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_TX5: + case RTW89_DBG_PORT_SEL_DSPT_CDT_TX6: + case RTW89_DBG_PORT_SEL_DSPT_CDT_TX7: + case RTW89_DBG_PORT_SEL_DSPT_CDT_TX8: + info = &dbg_port_dspt_cdt_tx5_8; + index = sel + 5 - RTW89_DBG_PORT_SEL_DSPT_CDT_TX5; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 1); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, index); + seq_printf(m, "Enable Dispatcher cdt tx%x dump.\n", index); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_TX9: + info = &dbg_port_dspt_cdt_tx9; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 1); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 9); + seq_puts(m, "Enable Dispatcher cdt tx9 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_TXA: + case RTW89_DBG_PORT_SEL_DSPT_CDT_TXB: + case RTW89_DBG_PORT_SEL_DSPT_CDT_TXC: + info = &dbg_port_dspt_cdt_txA_C; + index = sel + 0xA - RTW89_DBG_PORT_SEL_DSPT_CDT_TXA; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 1); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, index); + seq_printf(m, "Enable Dispatcher cdt tx%x dump.\n", index); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_RX0: + info = &dbg_port_dspt_hdt_rx0; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 2); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 0); + seq_puts(m, "Enable Dispatcher hdt rx0 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_RX1: + case RTW89_DBG_PORT_SEL_DSPT_HDT_RX2: + info = &dbg_port_dspt_hdt_rx1_2; + index = sel + 1 - RTW89_DBG_PORT_SEL_DSPT_HDT_RX1; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 2); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, index); + seq_printf(m, "Enable Dispatcher hdt rx%x dump.\n", index); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_RX3: + info = &dbg_port_dspt_hdt_rx3; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 2); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 3); + seq_puts(m, "Enable Dispatcher hdt rx3 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_RX4: + info = &dbg_port_dspt_hdt_rx4; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 2); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 4); + seq_puts(m, "Enable Dispatcher hdt rx4 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_HDT_RX5: + info = &dbg_port_dspt_hdt_rx5; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 2); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 5); + seq_puts(m, "Enable Dispatcher hdt rx5 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_0: + info = &dbg_port_dspt_cdt_rx_p0_0; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 3); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 0); + seq_puts(m, "Enable Dispatcher cdt rx part0 0 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0: + case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_1: + info = &dbg_port_dspt_cdt_rx_p0_1; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 3); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 1); + seq_puts(m, "Enable Dispatcher cdt rx part0 1 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_2: + info = &dbg_port_dspt_cdt_rx_p0_2; + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 3); + rtw89_write16_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_CH_SEL_MASK, 2); + seq_puts(m, "Enable Dispatcher cdt rx part0 2 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P1: + info = &dbg_port_dspt_cdt_rx_p1; + rtw89_write8_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 3); + seq_puts(m, "Enable Dispatcher cdt rx part1 dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_STF_CTRL: + info = &dbg_port_dspt_stf_ctrl; + rtw89_write8_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 4); + seq_puts(m, "Enable Dispatcher stf control dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_ADDR_CTRL: + info = &dbg_port_dspt_addr_ctrl; + rtw89_write8_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 5); + seq_puts(m, "Enable Dispatcher addr control dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_WDE_INTF: + info = &dbg_port_dspt_wde_intf; + rtw89_write8_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 6); + seq_puts(m, "Enable Dispatcher wde interface dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_PLE_INTF: + info = &dbg_port_dspt_ple_intf; + rtw89_write8_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 7); + seq_puts(m, "Enable Dispatcher ple interface dump.\n"); + break; + case RTW89_DBG_PORT_SEL_DSPT_FLOW_CTRL: + info = &dbg_port_dspt_flow_ctrl; + rtw89_write8_mask(rtwdev, info->sel_addr, + B_AX_DISPATCHER_INTN_SEL_MASK, 8); + seq_puts(m, "Enable Dispatcher flow control dump.\n"); + break; case RTW89_DBG_PORT_SEL_PCIE_TXDMA: info = &dbg_port_pcie_txdma; val32 = rtw89_read32(rtwdev, R_AX_DBG_CTRL); @@ -1914,7 +2709,7 @@ rtw89_debug_mac_dbg_port_sel(struct seq_file *m, info = &dbg_port_pcie_misc2; val16 = rtw89_read16(rtwdev, R_AX_PCIE_DBG_CTRL); val16 = u16_replace_bits(val16, PCIE_MISC2_DBG_SEL, - B_AX_DBG_SEL_MASK); + B_AX_PCIE_DBG_SEL_MASK); rtw89_write16(rtwdev, R_AX_PCIE_DBG_CTRL, val16); seq_puts(m, "Enable pcie misc2 dump.\n"); break; @@ -1940,6 +2735,10 @@ static bool is_dbg_port_valid(struct rtw89_dev *rtwdev, u32 sel) sel >= RTW89_DBG_PORT_SEL_WDE_BUFMGN_FREEPG && sel <= RTW89_DBG_PORT_SEL_PKTINFO) return false; + if (rtw89_mac_check_mac_en(rtwdev, 0, RTW89_DMAC_SEL) && + sel >= RTW89_DBG_PORT_SEL_DSPT_HDT_TX0 && + sel <= RTW89_DBG_PORT_SEL_DSPT_FLOW_CTRL) + return false; if (rtw89_mac_check_mac_en(rtwdev, 0, RTW89_CMAC_SEL) && sel >= RTW89_DBG_PORT_SEL_PTCL_C0 && sel <= RTW89_DBG_PORT_SEL_TXTF_INFOH_C0) @@ -2010,6 +2809,50 @@ static int rtw89_debug_mac_dbg_port_dump(struct rtw89_dev *rtwdev, case_DBG_SEL(PLE_QUEMGN_QLNKTBL); case_DBG_SEL(PLE_QUEMGN_QEMPTY); case_DBG_SEL(PKTINFO); + case_DBG_SEL(DSPT_HDT_TX0); + case_DBG_SEL(DSPT_HDT_TX1); + case_DBG_SEL(DSPT_HDT_TX2); + case_DBG_SEL(DSPT_HDT_TX3); + case_DBG_SEL(DSPT_HDT_TX4); + case_DBG_SEL(DSPT_HDT_TX5); + case_DBG_SEL(DSPT_HDT_TX6); + case_DBG_SEL(DSPT_HDT_TX7); + case_DBG_SEL(DSPT_HDT_TX8); + case_DBG_SEL(DSPT_HDT_TX9); + case_DBG_SEL(DSPT_HDT_TXA); + case_DBG_SEL(DSPT_HDT_TXB); + case_DBG_SEL(DSPT_HDT_TXC); + case_DBG_SEL(DSPT_HDT_TXD); + case_DBG_SEL(DSPT_HDT_TXE); + case_DBG_SEL(DSPT_HDT_TXF); + case_DBG_SEL(DSPT_CDT_TX0); + case_DBG_SEL(DSPT_CDT_TX1); + case_DBG_SEL(DSPT_CDT_TX3); + case_DBG_SEL(DSPT_CDT_TX4); + case_DBG_SEL(DSPT_CDT_TX5); + case_DBG_SEL(DSPT_CDT_TX6); + case_DBG_SEL(DSPT_CDT_TX7); + case_DBG_SEL(DSPT_CDT_TX8); + case_DBG_SEL(DSPT_CDT_TX9); + case_DBG_SEL(DSPT_CDT_TXA); + case_DBG_SEL(DSPT_CDT_TXB); + case_DBG_SEL(DSPT_CDT_TXC); + case_DBG_SEL(DSPT_HDT_RX0); + case_DBG_SEL(DSPT_HDT_RX1); + case_DBG_SEL(DSPT_HDT_RX2); + case_DBG_SEL(DSPT_HDT_RX3); + case_DBG_SEL(DSPT_HDT_RX4); + case_DBG_SEL(DSPT_HDT_RX5); + case_DBG_SEL(DSPT_CDT_RX_P0); + case_DBG_SEL(DSPT_CDT_RX_P0_0); + case_DBG_SEL(DSPT_CDT_RX_P0_1); + case_DBG_SEL(DSPT_CDT_RX_P0_2); + case_DBG_SEL(DSPT_CDT_RX_P1); + case_DBG_SEL(DSPT_STF_CTRL); + case_DBG_SEL(DSPT_ADDR_CTRL); + case_DBG_SEL(DSPT_WDE_INTF); + case_DBG_SEL(DSPT_PLE_INTF); + case_DBG_SEL(DSPT_FLOW_CTRL); case_DBG_SEL(PCIE_TXDMA); case_DBG_SEL(PCIE_RXDMA); case_DBG_SEL(PCIE_CVT); @@ -2379,6 +3222,7 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) else seq_printf(m, "Legacy %d", rate->legacy); seq_printf(m, "%s", rtwsta->ra_report.might_fallback_legacy ? " FB_G" : ""); + seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(rate->bw)); seq_printf(m, "\t(hw_rate=0x%x)", rtwsta->ra_report.hw_rate); seq_printf(m, "\t==> agg_wait=%d (%d)\n", rtwsta->max_agg_wait, sta->deflink.agg.max_rc_amsdu_len); @@ -2404,6 +3248,7 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) he_gi_str[rate->he_gi] : "N/A"); break; } + seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(status->bw)); seq_printf(m, "\t(hw_rate=0x%x)\n", rtwsta->rx_hw_rate); rssi = ewma_rssi_read(&rtwsta->avg_rssi); diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index ee243aadde87..e7971583acbc 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -26,6 +26,7 @@ enum rtw89_debug_mask { RTW89_DBG_HW_SCAN = BIT(15), RTW89_DBG_SAR = BIT(16), RTW89_DBG_STATE = BIT(17), + RTW89_DBG_WOW = BIT(18), RTW89_DBG_UNEXP = BIT(31), }; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d21f87e25ae1..10c5ed21da02 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -85,15 +85,31 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, { struct rtw89_fw_hdr_section_info *section_info; const u8 *fw_end = fw + len; + const u8 *fwdynhdr; const u8 *bin; + u32 base_hdr_len; u32 i; if (!info) return -EINVAL; info->section_num = GET_FW_HDR_SEC_NUM(fw); - info->hdr_len = RTW89_FW_HDR_SIZE + - info->section_num * RTW89_FW_SECTION_HDR_SIZE; + base_hdr_len = RTW89_FW_HDR_SIZE + + info->section_num * RTW89_FW_SECTION_HDR_SIZE; + info->dynamic_hdr_en = GET_FW_HDR_DYN_HDR(fw); + + if (info->dynamic_hdr_en) { + info->hdr_len = GET_FW_HDR_LEN(fw); + info->dynamic_hdr_len = info->hdr_len - base_hdr_len; + fwdynhdr = fw + base_hdr_len; + if (GET_FW_DYNHDR_LEN(fwdynhdr) != info->dynamic_hdr_len) { + rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n"); + return -EINVAL; + } + } else { + info->hdr_len = base_hdr_len; + info->dynamic_hdr_len = 0; + } bin = fw + info->hdr_len; @@ -515,6 +531,11 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type) u8 val; int ret; + rtw89_mac_disable_cpu(rtwdev); + ret = rtw89_mac_enable_cpu(rtwdev, 0, true); + if (ret) + return ret; + if (!fw || !len) { rtw89_err(rtwdev, "fw type %d isn't recognized\n", type); return -ENOENT; @@ -534,7 +555,7 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type) goto fwdl_err; } - ret = rtw89_fw_download_hdr(rtwdev, fw, info.hdr_len); + ret = rtw89_fw_download_hdr(rtwdev, fw, info.hdr_len - info.dynamic_hdr_len); if (ret) { ret = -EBUSY; goto fwdl_err; @@ -848,6 +869,56 @@ fail: return ret; } +static int rtw89_fw_h2c_add_wow_fw_ofld(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + enum rtw89_fw_pkt_ofld_type type, + u8 *id) +{ + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_pktofld_info *info; + struct sk_buff *skb; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + switch (type) { + case RTW89_PKT_OFLD_TYPE_PS_POLL: + skb = ieee80211_pspoll_get(rtwdev->hw, vif); + break; + case RTW89_PKT_OFLD_TYPE_PROBE_RSP: + skb = ieee80211_proberesp_get(rtwdev->hw, vif); + break; + case RTW89_PKT_OFLD_TYPE_NULL_DATA: + skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, false); + break; + case RTW89_PKT_OFLD_TYPE_QOS_NULL: + skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, true); + break; + default: + goto err; + } + + if (!skb) + goto err; + + list_add_tail(&info->list, &rtw_wow->pkt_list); + ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, skb); + kfree_skb(skb); + + if (ret) + return ret; + + *id = info->id; + return 0; + +err: + kfree(info); + return -ENOMEM; +} + #define H2C_GENERAL_PKT_LEN 6 #define H2C_GENERAL_PKT_ID_UND 0xff int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, u8 macid) @@ -2879,6 +2950,7 @@ int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev, case RTW89_PKT_DROP_SEL_MACID_BK_ONCE: case RTW89_PKT_DROP_SEL_MACID_VI_ONCE: case RTW89_PKT_DROP_SEL_MACID_VO_ONCE: + case RTW89_PKT_DROP_SEL_BAND_ONCE: break; default: rtw89_debug(rtwdev, RTW89_DBG_FW, @@ -2894,6 +2966,14 @@ int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev, RTW89_SET_FWCMD_PKT_DROP_PORT(skb->data, params->port); RTW89_SET_FWCMD_PKT_DROP_MBSSID(skb->data, params->mbssid); RTW89_SET_FWCMD_PKT_DROP_ROLE_A_INFO_TF_TRS(skb->data, params->tf_trs); + RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_0(skb->data, + params->macid_band_sel[0]); + RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_1(skb->data, + params->macid_band_sel[1]); + RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_2(skb->data, + params->macid_band_sel[2]); + RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_3(skb->data, + params->macid_band_sel[3]); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -2913,3 +2993,234 @@ fail: dev_kfree_skb_any(skb); return ret; } + +#define H2C_KEEP_ALIVE_LEN 4 +int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool enable) +{ + struct sk_buff *skb; + u8 pkt_id = 0; + int ret; + + if (enable) { + ret = rtw89_fw_h2c_add_wow_fw_ofld(rtwdev, rtwvif, + RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id); + if (ret) + return -EPERM; + } + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_KEEP_ALIVE_LEN); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); + return -ENOMEM; + } + + skb_put(skb, H2C_KEEP_ALIVE_LEN); + + RTW89_SET_KEEP_ALIVE_ENABLE(skb->data, enable); + RTW89_SET_KEEP_ALIVE_PKT_NULL_ID(skb->data, pkt_id); + RTW89_SET_KEEP_ALIVE_PERIOD(skb->data, 5); + RTW89_SET_KEEP_ALIVE_MACID(skb->data, rtwvif->mac_id); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_WOW, + H2C_FUNC_KEEP_ALIVE, 0, 1, + H2C_KEEP_ALIVE_LEN); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; + +fail: + dev_kfree_skb_any(skb); + + return ret; +} + +#define H2C_DISCONNECT_DETECT_LEN 8 +int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool enable) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct sk_buff *skb; + u8 macid = rtwvif->mac_id; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DISCONNECT_DETECT_LEN); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); + return -ENOMEM; + } + + skb_put(skb, H2C_DISCONNECT_DETECT_LEN); + + if (test_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags)) { + RTW89_SET_DISCONNECT_DETECT_ENABLE(skb->data, enable); + RTW89_SET_DISCONNECT_DETECT_DISCONNECT(skb->data, !enable); + RTW89_SET_DISCONNECT_DETECT_MAC_ID(skb->data, macid); + RTW89_SET_DISCONNECT_DETECT_CHECK_PERIOD(skb->data, 100); + RTW89_SET_DISCONNECT_DETECT_TRY_PKT_COUNT(skb->data, 5); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_WOW, + H2C_FUNC_DISCONNECT_DETECT, 0, 1, + H2C_DISCONNECT_DETECT_LEN); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; + +fail: + dev_kfree_skb_any(skb); + + return ret; +} + +#define H2C_WOW_GLOBAL_LEN 8 +int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool enable) +{ + struct sk_buff *skb; + u8 macid = rtwvif->mac_id; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_GLOBAL_LEN); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); + return -ENOMEM; + } + + skb_put(skb, H2C_WOW_GLOBAL_LEN); + + RTW89_SET_WOW_GLOBAL_ENABLE(skb->data, enable); + RTW89_SET_WOW_GLOBAL_MAC_ID(skb->data, macid); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_WOW, + H2C_FUNC_WOW_GLOBAL, 0, 1, + H2C_WOW_GLOBAL_LEN); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; + +fail: + dev_kfree_skb_any(skb); + + return ret; +} + +#define H2C_WAKEUP_CTRL_LEN 4 +int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + bool enable) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct sk_buff *skb; + u8 macid = rtwvif->mac_id; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WAKEUP_CTRL_LEN); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); + return -ENOMEM; + } + + skb_put(skb, H2C_WAKEUP_CTRL_LEN); + + if (rtw_wow->pattern_cnt) + RTW89_SET_WOW_WAKEUP_CTRL_PATTERN_MATCH_ENABLE(skb->data, enable); + if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags)) + RTW89_SET_WOW_WAKEUP_CTRL_MAGIC_ENABLE(skb->data, enable); + if (test_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags)) + RTW89_SET_WOW_WAKEUP_CTRL_DEAUTH_ENABLE(skb->data, enable); + + RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(skb->data, macid); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_WOW, + H2C_FUNC_WAKEUP_CTRL, 0, 1, + H2C_WAKEUP_CTRL_LEN); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; + +fail: + dev_kfree_skb_any(skb); + + return ret; +} + +#define H2C_WOW_CAM_UPD_LEN 24 +int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info) +{ + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_CAM_UPD_LEN); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); + return -ENOMEM; + } + + skb_put(skb, H2C_WOW_CAM_UPD_LEN); + + RTW89_SET_WOW_CAM_UPD_R_W(skb->data, cam_info->r_w); + RTW89_SET_WOW_CAM_UPD_IDX(skb->data, cam_info->idx); + if (cam_info->valid) { + RTW89_SET_WOW_CAM_UPD_WKFM1(skb->data, cam_info->mask[0]); + RTW89_SET_WOW_CAM_UPD_WKFM2(skb->data, cam_info->mask[1]); + RTW89_SET_WOW_CAM_UPD_WKFM3(skb->data, cam_info->mask[2]); + RTW89_SET_WOW_CAM_UPD_WKFM4(skb->data, cam_info->mask[3]); + RTW89_SET_WOW_CAM_UPD_CRC(skb->data, cam_info->crc); + RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(skb->data, + cam_info->negative_pattern_match); + RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(skb->data, + cam_info->skip_mac_hdr); + RTW89_SET_WOW_CAM_UPD_UC(skb->data, cam_info->uc); + RTW89_SET_WOW_CAM_UPD_MC(skb->data, cam_info->mc); + RTW89_SET_WOW_CAM_UPD_BC(skb->data, cam_info->bc); + } + RTW89_SET_WOW_CAM_UPD_VALID(skb->data, cam_info->valid); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_WOW, + H2C_FUNC_WOW_CAM_UPD, 0, 1, + H2C_WOW_CAM_UPD_LEN); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 6ef392ef9c6f..509a3eac5ffe 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -176,6 +176,8 @@ struct rtw89_fw_hdr_section_info { struct rtw89_fw_bin_info { u8 section_num; u32 hdr_len; + bool dynamic_hdr_en; + u32 dynamic_hdr_len; struct rtw89_fw_hdr_section_info section_info[FWDL_SECTION_MAX_NUM]; }; @@ -495,6 +497,8 @@ static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val) le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 16)) #define GET_FW_HDR_SUBINDEX(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(31, 24)) +#define GET_FW_HDR_LEN(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 3), GENMASK(23, 16)) #define GET_FW_HDR_MONTH(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(7, 0)) #define GET_FW_HDR_DATE(fwhdr) \ @@ -507,8 +511,16 @@ static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val) le32_get_bits(*((const __le32 *)(fwhdr) + 5), GENMASK(31, 0)) #define GET_FW_HDR_SEC_NUM(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 6), GENMASK(15, 8)) +#define GET_FW_HDR_DYN_HDR(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 7), BIT(16)) #define GET_FW_HDR_CMD_VERSERION(fwhdr) \ le32_get_bits(*((const __le32 *)(fwhdr) + 7), GENMASK(31, 24)) + +#define GET_FW_DYNHDR_LEN(fwdynhdr) \ + le32_get_bits(*((const __le32 *)(fwdynhdr)), GENMASK(31, 0)) +#define GET_FW_DYNHDR_COUNT(fwdynhdr) \ + le32_get_bits(*((const __le32 *)(fwdynhdr) + 1), GENMASK(31, 0)) + static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val) { le32p_replace_bits((__le32 *)fwhdr + 7, val, GENMASK(15, 0)); @@ -1861,6 +1873,231 @@ static inline void RTW89_SET_FWCMD_PKT_DROP_ROLE_A_INFO_TF_TRS(void *cmd, u32 va le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(15, 8)); } +static inline void RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_0(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)cmd + 2, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_1(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)cmd + 3, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_2(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)cmd + 4, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_3(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)cmd + 5, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_KEEP_ALIVE_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(1, 0)); +} + +static inline void RTW89_SET_KEEP_ALIVE_PKT_NULL_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); +} + +static inline void RTW89_SET_KEEP_ALIVE_PERIOD(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(24, 16)); +} + +static inline void RTW89_SET_KEEP_ALIVE_MACID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); +} + +static inline void RTW89_SET_DISCONNECT_DETECT_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(0)); +} + +static inline void RTW89_SET_DISCONNECT_DETECT_TRYOK_BCNFAIL_COUNT_EN(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(1)); +} + +static inline void RTW89_SET_DISCONNECT_DETECT_DISCONNECT(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(2)); +} + +static inline void RTW89_SET_DISCONNECT_DETECT_MAC_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); +} + +static inline void RTW89_SET_DISCONNECT_DETECT_CHECK_PERIOD(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 16)); +} + +static inline void RTW89_SET_DISCONNECT_DETECT_TRY_PKT_COUNT(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); +} + +static inline void RTW89_SET_DISCONNECT_DETECT_TRYOK_BCNFAIL_COUNT_LIMIT(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_WOW_GLOBAL_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(0)); +} + +static inline void RTW89_SET_WOW_GLOBAL_DROP_ALL_PKT(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(1)); +} + +static inline void RTW89_SET_WOW_GLOBAL_RX_PARSE_AFTER_WAKE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(2)); +} + +static inline void RTW89_SET_WOW_GLOBAL_WAKE_BAR_PULLED(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(3)); +} + +static inline void RTW89_SET_WOW_GLOBAL_MAC_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); +} + +static inline void RTW89_SET_WOW_GLOBAL_PAIRWISE_SEC_ALGO(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 16)); +} + +static inline void RTW89_SET_WOW_GLOBAL_GROUP_SEC_ALGO(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); +} + +static inline void RTW89_SET_WOW_GLOBAL_REMOTECTRL_INFO_CONTENT(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_WOW_WAKEUP_CTRL_PATTERN_MATCH_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(0)); +} + +static inline void RTW89_SET_WOW_WAKEUP_CTRL_MAGIC_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(1)); +} + +static inline void RTW89_SET_WOW_WAKEUP_CTRL_HW_UNICAST_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(2)); +} + +static inline void RTW89_SET_WOW_WAKEUP_CTRL_FW_UNICAST_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(3)); +} + +static inline void RTW89_SET_WOW_WAKEUP_CTRL_DEAUTH_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(4)); +} + +static inline void RTW89_SET_WOW_WAKEUP_CTRL_REKEYP_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(5)); +} + +static inline void RTW89_SET_WOW_WAKEUP_CTRL_EAP_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(6)); +} + +static inline void RTW89_SET_WOW_WAKEUP_CTRL_ALL_DATA_ENABLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(7)); +} + +static inline void RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_R_W(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(0)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_IDX(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 1)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_WKFM1(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_WKFM2(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 2, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_WKFM3(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 3, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_WKFM4(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 4, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_CRC(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 5, val, GENMASK(15, 0)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(22)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(23)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_UC(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(24)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_MC(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(25)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_BC(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(26)); +} + +static inline void RTW89_SET_WOW_CAM_UPD_VALID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(31)); +} + enum rtw89_btc_btf_h2c_class { BTFC_SET = 0x10, BTFC_GET = 0x11, @@ -2677,6 +2914,14 @@ struct rtw89_fw_h2c_rf_reg_info { #define H2C_FUNC_LOG_CFG 0x0 #define H2C_FUNC_MAC_GENERAL_PKT 0x1 +/* CLASS 1 - WOW */ +#define H2C_CL_MAC_WOW 0x1 +#define H2C_FUNC_KEEP_ALIVE 0x0 +#define H2C_FUNC_DISCONNECT_DETECT 0x1 +#define H2C_FUNC_WOW_GLOBAL 0x2 +#define H2C_FUNC_WAKEUP_CTRL 0x8 +#define H2C_FUNC_WOW_CAM_UPD 0xC + /* CLASS 2 - PS */ #define H2C_CL_MAC_PS 0x2 #define H2C_FUNC_MAC_LPS_PARM 0x0 @@ -2846,7 +3091,21 @@ int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, u8 act, u8 noa_id); int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, bool en); - +int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool enable); +int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool enable); +int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool enable); +int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool enable); +int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool enable); +int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool enable); + +int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info); static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 3531a859d6c8..ecd603a88134 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -7,6 +7,7 @@ #include "debug.h" #include "fw.h" #include "mac.h" +#include "pci.h" #include "ps.h" #include "reg.h" #include "util.h" @@ -274,106 +275,163 @@ static void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, } } -static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, - enum mac_ax_err_info err) +static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) { - u32 dmac_err, cmac_err; + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 dmac_err; + int i, ret; - if (err != MAC_AX_ERR_L1_ERR_DMAC && - err != MAC_AX_ERR_L0_PROMOTE_TO_L1 && - err != MAC_AX_ERR_L0_ERR_CMAC0 && - err != MAC_AX_ERR_L0_ERR_CMAC1) + ret = rtw89_mac_check_mac_en(rtwdev, 0, RTW89_DMAC_SEL); + if (ret) { + rtw89_warn(rtwdev, "[DMAC] : DMAC not enabled\n"); return; + } - rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); - rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); - - cmac_err = rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR); - rtw89_info(rtwdev, "R_AX_CMAC_ERR_ISR =0x%08x\n", cmac_err); dmac_err = rtw89_read32(rtwdev, R_AX_DMAC_ERR_ISR); - rtw89_info(rtwdev, "R_AX_DMAC_ERR_ISR =0x%08x\n", dmac_err); + rtw89_info(rtwdev, "R_AX_DMAC_ERR_ISR=0x%08x\n", dmac_err); + rtw89_info(rtwdev, "R_AX_DMAC_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DMAC_ERR_IMR)); if (dmac_err) { - rtw89_info(rtwdev, "R_AX_WDE_ERR_FLAG_CFG =0x%08x ", - rtw89_read32(rtwdev, R_AX_WDE_ERR_FLAG_CFG)); - rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_CFG =0x%08x\n", - rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_CFG)); + rtw89_info(rtwdev, "R_AX_WDE_ERR_FLAG_CFG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_FLAG_CFG_NUM1)); + rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_CFG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_CFG_NUM1)); + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_PLE_ERRFLAG_MSG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERRFLAG_MSG)); + rtw89_info(rtwdev, "R_AX_WDE_ERRFLAG_MSG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERRFLAG_MSG)); + rtw89_info(rtwdev, "R_AX_PLE_DBGERR_LOCKEN=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_DBGERR_LOCKEN)); + rtw89_info(rtwdev, "R_AX_PLE_DBGERR_STS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_DBGERR_STS)); + } } if (dmac_err & B_AX_WDRLS_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_WDRLS_ERR_IMR =0x%08x ", + rtw89_info(rtwdev, "R_AX_WDRLS_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_WDRLS_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_WDRLS_ERR_ISR =0x%08x\n", + rtw89_info(rtwdev, "R_AX_WDRLS_ERR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_WDRLS_ERR_ISR)); + if (chip->chip_id == RTL8852C) + rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX_V1)); + else + rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); } if (dmac_err & B_AX_WSEC_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR_ISR =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_DEBUG)); - rtw89_info(rtwdev, "SEC_local_Register 0x9D00 =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); - rtw89_info(rtwdev, "SEC_local_Register 0x9D04 =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); - rtw89_info(rtwdev, "SEC_local_Register 0x9D10 =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); - rtw89_info(rtwdev, "SEC_local_Register 0x9D14 =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); - rtw89_info(rtwdev, "SEC_local_Register 0x9D18 =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_CAM_WDATA)); - rtw89_info(rtwdev, "SEC_local_Register 0x9D20 =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); - rtw89_info(rtwdev, "SEC_local_Register 0x9D24 =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); - rtw89_info(rtwdev, "SEC_local_Register 0x9D28 =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_TRX_PKT_CNT)); - rtw89_info(rtwdev, "SEC_local_Register 0x9D2C =0x%08x\n", - rtw89_read32(rtwdev, R_AX_SEC_TRX_BLK_CNT)); + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_ERROR_FLAG_IMR)); + rtw89_info(rtwdev, "R_AX_SEC_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_ERROR_FLAG)); + rtw89_info(rtwdev, "R_AX_SEC_ENG_CTRL=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); + rtw89_info(rtwdev, "R_AX_SEC_MPDU_PROC=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); + rtw89_info(rtwdev, "R_AX_SEC_CAM_ACCESS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); + rtw89_info(rtwdev, "R_AX_SEC_CAM_RDATA=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); + rtw89_info(rtwdev, "R_AX_SEC_DEBUG1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_DEBUG1)); + rtw89_info(rtwdev, "R_AX_SEC_TX_DEBUG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); + rtw89_info(rtwdev, "R_AX_SEC_RX_DEBUG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); + + rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, + B_AX_DBG_SEL0, 0x8B); + rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, + B_AX_DBG_SEL1, 0x8B); + rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, + B_AX_SEL_0XC0_MASK, 1); + for (i = 0; i < 0x10; i++) { + rtw89_write32_mask(rtwdev, R_AX_SEC_ENG_CTRL, + B_AX_SEC_DBG_PORT_FIELD_MASK, i); + rtw89_info(rtwdev, "sel=%x,R_AX_SEC_DEBUG2=0x%08x\n", + i, rtw89_read32(rtwdev, R_AX_SEC_DEBUG2)); + } + } else { + rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_DEBUG)); + rtw89_info(rtwdev, "R_AX_SEC_ENG_CTRL=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); + rtw89_info(rtwdev, "R_AX_SEC_MPDU_PROC=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); + rtw89_info(rtwdev, "R_AX_SEC_CAM_ACCESS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); + rtw89_info(rtwdev, "R_AX_SEC_CAM_RDATA=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); + rtw89_info(rtwdev, "R_AX_SEC_CAM_WDATA=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_WDATA)); + rtw89_info(rtwdev, "R_AX_SEC_TX_DEBUG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); + rtw89_info(rtwdev, "R_AX_SEC_RX_DEBUG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); + rtw89_info(rtwdev, "R_AX_SEC_TRX_PKT_CNT=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TRX_PKT_CNT)); + rtw89_info(rtwdev, "R_AX_SEC_TRX_BLK_CNT=0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TRX_BLK_CNT)); + } } if (dmac_err & B_AX_MPDU_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_IMR =0x%08x ", + rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_ISR =0x%08x\n", + rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_ISR)); - rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_IMR =0x%08x ", + rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_ISR =0x%08x\n", + rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_ISR)); } if (dmac_err & B_AX_STA_SCHEDULER_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR =0x%08x ", + rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR= 0x%08x\n", + rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); } if (dmac_err & B_AX_WDE_DLE_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x ", + rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); rtw89_info(rtwdev, "R_AX_WDE_ERR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); - rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x ", + rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); - dump_err_status_dispatcher(rtwdev); } if (dmac_err & B_AX_TXPKTCTRL_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR)); - rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR_B1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR_B1)); + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_IMR)); + rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_ISR)); + rtw89_info(rtwdev, "R_AX_TXPKTCTL_B1_ERRFLAG_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_B1_ERRFLAG_IMR)); + rtw89_info(rtwdev, "R_AX_TXPKTCTL_B1_ERRFLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_B1_ERRFLAG_ISR)); + } else { + rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR)); + rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR_B1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR_B1)); + } } if (dmac_err & B_AX_PLE_DLE_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x ", + rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); rtw89_info(rtwdev, "R_AX_WDE_ERR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); - rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x ", + rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); @@ -393,86 +451,190 @@ static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_2)); rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n", rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS)); - rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); - rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); - rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", - rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); - dump_err_status_dispatcher(rtwdev); + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_RX_CTRL0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL0)); + rtw89_info(rtwdev, "R_AX_RX_CTRL1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL1)); + rtw89_info(rtwdev, "R_AX_RX_CTRL2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RX_CTRL2)); + } else { + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); + } } if (dmac_err & B_AX_PKTIN_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_PKTIN_ERR_IMR =0x%08x ", - rtw89_read32(rtwdev, R_AX_PKTIN_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_PKTIN_ERR_ISR =0x%08x\n", - rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); - rtw89_info(rtwdev, "R_AX_PKTIN_ERR_IMR =0x%08x ", + rtw89_info(rtwdev, "R_AX_PKTIN_ERR_IMR=0x%08x\n", rtw89_read32(rtwdev, R_AX_PKTIN_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_PKTIN_ERR_ISR =0x%08x\n", + rtw89_info(rtwdev, "R_AX_PKTIN_ERR_ISR=0x%08x\n", rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); } - if (dmac_err & B_AX_DISPATCH_ERR_FLAG) - dump_err_status_dispatcher(rtwdev); + if (dmac_err & B_AX_DISPATCH_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); + } + + if (dmac_err & B_AX_BBRPT_ERR_FLAG) { + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_BBRPT_CHINFO_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_BBRPT_CHINFO_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); + } else { + rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR_ISR)); + rtw89_info(rtwdev, "R_AX_BBRPT_CHINFO_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_BBRPT_CHINFO_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); + } + } - if (dmac_err & B_AX_DLE_CPUIO_ERR_FLAG) { - rtw89_info(rtwdev, "R_AX_CPUIO_ERR_IMR=0x%08x ", - rtw89_read32(rtwdev, R_AX_CPUIO_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_CPUIO_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_CPUIO_ERR_ISR)); + if (dmac_err & B_AX_HAXIDMA_ERR_FLAG && chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK)); + rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HAXI_IDCT)); } +} + +static void rtw89_mac_dump_cmac_err_status(struct rtw89_dev *rtwdev, + u8 band) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 offset = 0; + u32 cmac_err; + int ret; - if (dmac_err & BIT(11)) { - rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR_ISR)); + ret = rtw89_mac_check_mac_en(rtwdev, band, RTW89_CMAC_SEL); + if (ret) { + if (band) + rtw89_warn(rtwdev, "[CMAC] : CMAC1 not enabled\n"); + else + rtw89_warn(rtwdev, "[CMAC] : CMAC0 not enabled\n"); + return; } + if (band) + offset = RTW89_MAC_AX_BAND_REG_OFFSET; + + cmac_err = rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR + offset); + rtw89_info(rtwdev, "R_AX_CMAC_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR + offset)); + rtw89_info(rtwdev, "R_AX_CMAC_FUNC_EN [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_CMAC_FUNC_EN + offset)); + rtw89_info(rtwdev, "R_AX_CK_EN [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_CK_EN + offset)); + if (cmac_err & B_AX_SCHEDULE_TOP_ERR_IND) { - rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_IMR=0x%08x ", - rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_IMR)); - rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_ISR=0x%04x\n", - rtw89_read16(rtwdev, R_AX_SCHEDULE_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_IMR + offset)); + rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_ISR + offset)); } if (cmac_err & B_AX_PTCL_TOP_ERR_IND) { - rtw89_info(rtwdev, "R_AX_PTCL_IMR0=0x%08x ", - rtw89_read32(rtwdev, R_AX_PTCL_IMR0)); - rtw89_info(rtwdev, "R_AX_PTCL_ISR0=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PTCL_ISR0)); + rtw89_info(rtwdev, "R_AX_PTCL_IMR0 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PTCL_IMR0 + offset)); + rtw89_info(rtwdev, "R_AX_PTCL_ISR0 [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PTCL_ISR0 + offset)); } if (cmac_err & B_AX_DMA_TOP_ERR_IND) { - rtw89_info(rtwdev, "R_AX_DLE_CTRL=0x%08x\n", - rtw89_read32(rtwdev, R_AX_DLE_CTRL)); + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_RX_ERR_FLAG [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_RX_ERR_FLAG + offset)); + rtw89_info(rtwdev, "R_AX_RX_ERR_FLAG_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_RX_ERR_FLAG_IMR + offset)); + } else { + rtw89_info(rtwdev, "R_AX_DLE_CTRL [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_DLE_CTRL + offset)); + } } - if (cmac_err & B_AX_PHYINTF_ERR_IND) { - rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_IMR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR)); + if (cmac_err & B_AX_DMA_TOP_ERR_IND || cmac_err & B_AX_WMAC_RX_ERR_IND) { + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR + offset)); + rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR + offset)); + } else { + rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR + offset)); + } } if (cmac_err & B_AX_TXPWR_CTRL_ERR_IND) { - rtw89_info(rtwdev, "R_AX_TXPWR_IMR=0x%08x ", - rtw89_read32(rtwdev, R_AX_TXPWR_IMR)); - rtw89_info(rtwdev, "R_AX_TXPWR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_TXPWR_ISR)); - } - - if (cmac_err & B_AX_WMAC_RX_ERR_IND) { - rtw89_info(rtwdev, "R_AX_DBGSEL_TRXPTCL=0x%08x ", - rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL)); - rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_ISR=0x%08x\n", - rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_TXPWR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TXPWR_IMR + offset)); + rtw89_info(rtwdev, "R_AX_TXPWR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TXPWR_ISR + offset)); } if (cmac_err & B_AX_WMAC_TX_ERR_IND) { - rtw89_info(rtwdev, "R_AX_TMAC_ERR_IMR_ISR=0x%08x ", - rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR)); - rtw89_info(rtwdev, "R_AX_DBGSEL_TRXPTCL=0x%08x\n", - rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL)); + if (chip->chip_id == RTL8852C) { + rtw89_info(rtwdev, "R_AX_TRXPTCL_ERROR_INDICA [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TRXPTCL_ERROR_INDICA + offset)); + rtw89_info(rtwdev, "R_AX_TRXPTCL_ERROR_INDICA_MASK [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TRXPTCL_ERROR_INDICA_MASK + offset)); + } else { + rtw89_info(rtwdev, "R_AX_TMAC_ERR_IMR_ISR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR + offset)); + } + rtw89_info(rtwdev, "R_AX_DBGSEL_TRXPTCL [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL + offset)); } + rtw89_info(rtwdev, "R_AX_CMAC_ERR_IMR [%d]=0x%08x\n", band, + rtw89_read32(rtwdev, R_AX_CMAC_ERR_IMR + offset)); +} + +static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err) +{ + if (err != MAC_AX_ERR_L1_ERR_DMAC && + err != MAC_AX_ERR_L0_PROMOTE_TO_L1 && + err != MAC_AX_ERR_L0_ERR_CMAC0 && + err != MAC_AX_ERR_L0_ERR_CMAC1) + return; + + rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); + rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); + + rtw89_mac_dump_dmac_err_status(rtwdev); + rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_0); + if (rtwdev->dbcc_en) + rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_1); + rtwdev->hci.ops->dump_err_status(rtwdev); if (err == MAC_AX_ERR_L0_PROMOTE_TO_L1) @@ -1306,6 +1468,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt47 = {525, 0, 32, 20, 1034, 13, 1199, 0, 1053, 62, 160, 1037,}, /* PCIE 64 */ .ple_qt58 = {147, 0, 16, 20, 157, 13, 229, 0, 172, 14, 24, 0,}, + /* 8852A PCIE WOW */ + .ple_qt_52a_wow = {264, 0, 32, 20, 64, 13, 1005, 0, 64, 128, 120,}, }; EXPORT_SYMBOL(rtw89_mac_size); @@ -1333,6 +1497,60 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, return cfg; } +static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) +{ + struct rtw89_mac_dle_dfi_qempty qempty; + u32 qnum, qtmp, val32, msk32; + int i, j, ret; + + qnum = rtwdev->chip->wde_qempty_acq_num; + qempty.dle_type = DLE_CTRL_TYPE_WDE; + + for (i = 0; i < qnum; i++) { + qempty.grpsel = i; + ret = dle_dfi_qempty(rtwdev, &qempty); + if (ret) { + rtw89_warn(rtwdev, "dle dfi acq empty %d\n", ret); + return false; + } + qtmp = qempty.qempty; + for (j = 0 ; j < QEMP_ACQ_GRP_MACID_NUM; j++) { + val32 = FIELD_GET(QEMP_ACQ_GRP_QSEL_MASK, qtmp); + if (val32 != QEMP_ACQ_GRP_QSEL_MASK) + return false; + qtmp >>= QEMP_ACQ_GRP_QSEL_SH; + } + } + + qempty.grpsel = rtwdev->chip->wde_qempty_mgq_sel; + ret = dle_dfi_qempty(rtwdev, &qempty); + if (ret) { + rtw89_warn(rtwdev, "dle dfi mgq empty %d\n", ret); + return false; + } + msk32 = B_CMAC0_MGQ_NORMAL | B_CMAC0_MGQ_NO_PWRSAV | B_CMAC0_CPUMGQ; + if ((qempty.qempty & msk32) != msk32) + return false; + + if (rtwdev->dbcc_en) { + msk32 |= B_CMAC1_MGQ_NORMAL | B_CMAC1_MGQ_NO_PWRSAV | B_CMAC1_CPUMGQ; + if ((qempty.qempty & msk32) != msk32) + return false; + } + + msk32 = B_AX_WDE_EMPTY_QTA_DMAC_WLAN_CPU | B_AX_WDE_EMPTY_QTA_DMAC_DATA_CPU | + B_AX_PLE_EMPTY_QTA_DMAC_WLAN_CPU | B_AX_PLE_EMPTY_QTA_DMAC_H2C | + B_AX_WDE_EMPTY_QUE_OTHERS | B_AX_PLE_EMPTY_QUE_DMAC_MPDU_TX | + B_AX_WDE_EMPTY_QTA_DMAC_CPUIO | B_AX_PLE_EMPTY_QTA_DMAC_CPUIO | + B_AX_WDE_EMPTY_QUE_DMAC_PKTIN | B_AX_WDE_EMPTY_QTA_DMAC_HIF | + B_AX_PLE_EMPTY_QUE_DMAC_SEC_TX | B_AX_WDE_EMPTY_QTA_DMAC_PKTIN | + B_AX_PLE_EMPTY_QTA_DMAC_B0_TXPL | B_AX_PLE_EMPTY_QTA_DMAC_B1_TXPL | + B_AX_PLE_EMPTY_QTA_DMAC_MPDU_TX; + val32 = rtw89_read32(rtwdev, R_AX_DLE_EMPTY0); + + return (val32 & msk32) == msk32; +} + static inline u32 dle_used_size(const struct rtw89_dle_size *wde, const struct rtw89_dle_size *ple) { @@ -1431,10 +1649,8 @@ static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg #define INVALID_QT_WCPU U16_MAX #define SET_QUOTA_VAL(_min_x, _max_x, _module, _idx) \ do { \ - val = ((_min_x) & \ - B_AX_ ## _module ## _MIN_SIZE_MASK) | \ - (((_max_x) << 16) & \ - B_AX_ ## _module ## _MAX_SIZE_MASK); \ + val = u32_encode_bits(_min_x, B_AX_ ## _module ## _MIN_SIZE_MASK) | \ + u32_encode_bits(_max_x, B_AX_ ## _module ## _MAX_SIZE_MASK); \ rtw89_write32(rtwdev, \ R_AX_ ## _module ## _QTA ## _idx ## _CFG, \ val); \ @@ -1478,8 +1694,48 @@ static void ple_quota_cfg(struct rtw89_dev *rtwdev, SET_QUOTA(tx_rpt, PLE, 11); } +int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow) +{ + const struct rtw89_ple_quota *min_cfg, *max_cfg; + const struct rtw89_dle_mem *cfg; + u32 val; + + if (rtwdev->chip->chip_id == RTL8852C) + return 0; + + if (rtwdev->mac.qta_mode != RTW89_QTA_SCC) { + rtw89_err(rtwdev, "[ERR]support SCC mode only\n"); + return -EINVAL; + } + + if (wow) + cfg = get_dle_mem_cfg(rtwdev, RTW89_QTA_WOW); + else + cfg = get_dle_mem_cfg(rtwdev, RTW89_QTA_SCC); + if (!cfg) { + rtw89_err(rtwdev, "[ERR]get_dle_mem_cfg\n"); + return -EINVAL; + } + + min_cfg = cfg->ple_min_qt; + max_cfg = cfg->ple_max_qt; + SET_QUOTA(cma0_dma, PLE, 6); + SET_QUOTA(cma1_dma, PLE, 7); + + return 0; +} #undef SET_QUOTA +void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool enable) +{ + u32 msk32 = B_AX_UC_MGNT_DEC | B_AX_BMC_MGNT_DEC; + + if (enable) + rtw89_write32_set(rtwdev, R_AX_SEC_ENG_CTRL, msk32); + else + rtw89_write32_clr(rtwdev, R_AX_SEC_ENG_CTRL, msk32); +} + static void dle_quota_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg, u16 ext_wde_min_qt_wcpu) @@ -1829,10 +2085,10 @@ static int scheduler_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } -static int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, - enum rtw89_machdr_frame_type type, - enum rtw89_mac_fwd_target fwd_target, - u8 mac_idx) +int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, + enum rtw89_machdr_frame_type type, + enum rtw89_mac_fwd_target fwd_target, + u8 mac_idx) { u32 reg; u32 val; @@ -3116,7 +3372,7 @@ static void rtw89_disable_fw_watchdog(struct rtw89_dev *rtwdev) rtw89_mac_mem_write(rtwdev, R_AX_WDT_STATUS, val32, RTW89_MAC_MEM_CPU_LOCAL); } -static void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev) +void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev) { clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); @@ -3131,8 +3387,7 @@ static void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); } -static int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, - bool dlfw) +int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw) { u32 val; int ret; @@ -3271,11 +3526,6 @@ int rtw89_mac_partial_init(struct rtw89_dev *rtwdev) return ret; } - rtw89_mac_disable_cpu(rtwdev); - ret = rtw89_mac_enable_cpu(rtwdev, 0, true); - if (ret) - return ret; - ret = rtw89_fw_download(rtwdev, RTW89_FW_NORMAL); if (ret) return ret; @@ -4867,3 +5117,24 @@ void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_mac_pkt_drop_vif_iter, rtwvif); } + +int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx band) +{ + struct rtw89_pkt_drop_params params = {0}; + bool empty; + int i, ret = 0, try_cnt = 3; + + params.mac_band = band; + params.sel = RTW89_PKT_DROP_SEL_BAND_ONCE; + + for (i = 0; i < try_cnt; i++) { + ret = read_poll_timeout(mac_is_txq_empty, empty, empty, 50, + 50000, false, rtwdev); + if (ret) + rtw89_fw_h2c_pkt_drop(rtwdev, ¶ms); + else + return 0; + } + return ret; +} diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index a6cbafb75a2b..045e8ec61a41 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -211,6 +211,51 @@ enum rtw89_mac_dbg_port_sel { RTW89_DBG_PORT_SEL_PLE_QUEMGN_QLNKTBL, RTW89_DBG_PORT_SEL_PLE_QUEMGN_QEMPTY, RTW89_DBG_PORT_SEL_PKTINFO, + /* DISPATCHER related */ + RTW89_DBG_PORT_SEL_DSPT_HDT_TX0, + RTW89_DBG_PORT_SEL_DSPT_HDT_TX1, + RTW89_DBG_PORT_SEL_DSPT_HDT_TX2, + RTW89_DBG_PORT_SEL_DSPT_HDT_TX3, + RTW89_DBG_PORT_SEL_DSPT_HDT_TX4, + RTW89_DBG_PORT_SEL_DSPT_HDT_TX5, + RTW89_DBG_PORT_SEL_DSPT_HDT_TX6, + RTW89_DBG_PORT_SEL_DSPT_HDT_TX7, + RTW89_DBG_PORT_SEL_DSPT_HDT_TX8, + RTW89_DBG_PORT_SEL_DSPT_HDT_TX9, + RTW89_DBG_PORT_SEL_DSPT_HDT_TXA, + RTW89_DBG_PORT_SEL_DSPT_HDT_TXB, + RTW89_DBG_PORT_SEL_DSPT_HDT_TXC, + RTW89_DBG_PORT_SEL_DSPT_HDT_TXD, + RTW89_DBG_PORT_SEL_DSPT_HDT_TXE, + RTW89_DBG_PORT_SEL_DSPT_HDT_TXF, + RTW89_DBG_PORT_SEL_DSPT_CDT_TX0, + RTW89_DBG_PORT_SEL_DSPT_CDT_TX1, + RTW89_DBG_PORT_SEL_DSPT_CDT_TX3, + RTW89_DBG_PORT_SEL_DSPT_CDT_TX4, + RTW89_DBG_PORT_SEL_DSPT_CDT_TX5, + RTW89_DBG_PORT_SEL_DSPT_CDT_TX6, + RTW89_DBG_PORT_SEL_DSPT_CDT_TX7, + RTW89_DBG_PORT_SEL_DSPT_CDT_TX8, + RTW89_DBG_PORT_SEL_DSPT_CDT_TX9, + RTW89_DBG_PORT_SEL_DSPT_CDT_TXA, + RTW89_DBG_PORT_SEL_DSPT_CDT_TXB, + RTW89_DBG_PORT_SEL_DSPT_CDT_TXC, + RTW89_DBG_PORT_SEL_DSPT_HDT_RX0, + RTW89_DBG_PORT_SEL_DSPT_HDT_RX1, + RTW89_DBG_PORT_SEL_DSPT_HDT_RX2, + RTW89_DBG_PORT_SEL_DSPT_HDT_RX3, + RTW89_DBG_PORT_SEL_DSPT_HDT_RX4, + RTW89_DBG_PORT_SEL_DSPT_HDT_RX5, + RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0, + RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_0, + RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_1, + RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_2, + RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P1, + RTW89_DBG_PORT_SEL_DSPT_STF_CTRL, + RTW89_DBG_PORT_SEL_DSPT_ADDR_CTRL, + RTW89_DBG_PORT_SEL_DSPT_WDE_INTF, + RTW89_DBG_PORT_SEL_DSPT_PLE_INTF, + RTW89_DBG_PORT_SEL_DSPT_FLOW_CTRL, /* PCIE related */ RTW89_DBG_PORT_SEL_PCIE_TXDMA, RTW89_DBG_PORT_SEL_PCIE_RXDMA, @@ -395,6 +440,7 @@ enum rtw89_mac_bf_rrsc_rate { #define ACCESS_CMAC(_addr) \ ({typeof(_addr) __addr = (_addr); \ __addr >= R_AX_CMAC_REG_START && __addr <= R_AX_CMAC_REG_END; }) +#define RTW89_MAC_AX_BAND_REG_OFFSET 0x2000 #define PTCL_IDLE_POLL_CNT 10000 #define SW_CVR_DUR_US 8 @@ -420,6 +466,17 @@ enum rtw89_mac_bf_rrsc_rate { #define S_AX_PLE_PAGE_SEL_128 1 #define S_AX_PLE_PAGE_SEL_256 2 +#define B_CMAC0_MGQ_NORMAL BIT(2) +#define B_CMAC0_MGQ_NO_PWRSAV BIT(3) +#define B_CMAC0_CPUMGQ BIT(4) +#define B_CMAC1_MGQ_NORMAL BIT(10) +#define B_CMAC1_MGQ_NO_PWRSAV BIT(11) +#define B_CMAC1_CPUMGQ BIT(12) + +#define QEMP_ACQ_GRP_MACID_NUM 8 +#define QEMP_ACQ_GRP_QSEL_SH 4 +#define QEMP_ACQ_GRP_QSEL_MASK 0xF + #define SDIO_LOCAL_BASE_ADDR 0x80000000 #define PWR_CMD_WRITE 0 @@ -719,6 +776,7 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt46; const struct rtw89_ple_quota ple_qt47; const struct rtw89_ple_quota ple_qt58; + const struct rtw89_ple_quota ple_qt_52a_wow; }; extern const struct rtw89_mac_size_set rtw89_mac_size; @@ -815,6 +873,8 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); +void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev); +int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw); int rtw89_mac_enable_bb_rf(struct rtw89_dev *rtwdev); int rtw89_mac_disable_bb_rf(struct rtw89_dev *rtwdev); @@ -966,6 +1026,16 @@ static inline void rtw89_mac_ctrl_hci_dma_trx(struct rtw89_dev *rtwdev, B_AX_HCI_TXDMA_EN | B_AX_HCI_RXDMA_EN); } +static inline bool rtw89_mac_get_power_state(struct rtw89_dev *rtwdev) +{ + u32 val; + + val = rtw89_read32_mask(rtwdev, R_AX_IC_PWR_STATE, + B_AX_WLMAC_PWR_STE_MASK); + + return !!val; +} + int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool resume, u32 tx_time); int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, @@ -1024,5 +1094,12 @@ void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); u16 rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd); int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev, struct rtw89_cpuio_ctrl *ctrl_para, bool wd); +int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, + enum rtw89_machdr_frame_type type, + enum rtw89_mac_fwd_target fwd_target, u8 mac_idx); +int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow); +int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx band); +void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool wow); #endif diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index a296bfa8188f..6e79bf899901 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -14,6 +14,7 @@ #include "sar.h" #include "ser.h" #include "util.h" +#include "wow.h" static void rtw89_ops_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, @@ -916,6 +917,55 @@ static int rtw89_ops_set_tid_config(struct ieee80211_hw *hw, return 0; } +#ifdef CONFIG_PM +static int rtw89_ops_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct rtw89_dev *rtwdev = hw->priv; + int ret; + + set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); + cancel_delayed_work_sync(&rtwdev->track_work); + + mutex_lock(&rtwdev->mutex); + ret = rtw89_wow_suspend(rtwdev, wowlan); + mutex_unlock(&rtwdev->mutex); + + if (ret) { + rtw89_warn(rtwdev, "failed to suspend for wow %d\n", ret); + clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); + return 1; + } + + return 0; +} + +static int rtw89_ops_resume(struct ieee80211_hw *hw) +{ + struct rtw89_dev *rtwdev = hw->priv; + int ret; + + mutex_lock(&rtwdev->mutex); + ret = rtw89_wow_resume(rtwdev); + if (ret) + rtw89_warn(rtwdev, "failed to resume for wow %d\n", ret); + mutex_unlock(&rtwdev->mutex); + + clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work, + RTW89_TRACK_WORK_PERIOD); + + return ret ? 1 : 0; +} + +static void rtw89_ops_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct rtw89_dev *rtwdev = hw->priv; + + device_set_wakeup_enable(rtwdev->dev, enabled); +} +#endif + const struct ieee80211_ops rtw89_ops = { .tx = rtw89_ops_tx, .wake_tx_queue = rtw89_ops_wake_tx_queue, @@ -953,5 +1003,10 @@ const struct ieee80211_ops rtw89_ops = { .set_sar_specs = rtw89_ops_set_sar_specs, .sta_rc_update = rtw89_ops_sta_rc_update, .set_tid_config = rtw89_ops_set_tid_config, +#ifdef CONFIG_PM + .suspend = rtw89_ops_suspend, + .resume = rtw89_ops_resume, + .set_wakeup = rtw89_ops_set_wakeup, +#endif }; EXPORT_SYMBOL(rtw89_ops); diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 5f8e19639362..7aa0af18cdd5 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -186,6 +186,17 @@ static void rtw89_pci_ctrl_txdma_ch_pcie(struct rtw89_dev *rtwdev, bool enable) } } +static void rtw89_pci_ctrl_txdma_fw_ch_pcie(struct rtw89_dev *rtwdev, bool enable) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_reg_def *dma_stop1 = &info->dma_stop1; + + if (enable) + rtw89_write32_clr(rtwdev, dma_stop1->addr, B_AX_STOP_CH12); + else + rtw89_write32_set(rtwdev, dma_stop1->addr, B_AX_STOP_CH12); +} + static bool rtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls, struct sk_buff *new, @@ -960,8 +971,10 @@ static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; + const struct rtw89_chip_info *chip = rtwdev->chip; u32 bd_cnt, wd_cnt, min_cnt = 0; struct rtw89_pci_rx_ring *rx_ring; + enum rtw89_debug_mask debug_mask; u32 cnt; rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; @@ -985,10 +998,20 @@ static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring); wd_cnt = wd_ring->curr_num; min_cnt = min(bd_cnt, wd_cnt); - if (min_cnt == 0) - rtw89_debug(rtwdev, rtwpci->low_power ? RTW89_DBG_TXRX : RTW89_DBG_UNEXP, + if (min_cnt == 0) { + /* This message can be frequently shown in low power mode or + * high traffic with 8852B, and we have recognized it as normal + * behavior, so print with mask RTW89_DBG_TXRX in these situations. + */ + if (rtwpci->low_power || chip->chip_id == RTL8852B) + debug_mask = RTW89_DBG_TXRX; + else + debug_mask = RTW89_DBG_UNEXP; + + rtw89_debug(rtwdev, debug_mask, "still no tx resource after reclaim: wd_cnt=%d bd_cnt=%d\n", wd_cnt, bd_cnt); + } out_unlock: spin_unlock_bh(&rtwpci->trx_lock); @@ -2513,7 +2536,7 @@ static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) /* disable all channels except to FW CMD channel to download firmware */ rtw89_pci_ctrl_txdma_ch_pcie(rtwdev, false); - rtw89_write32_clr(rtwdev, info->dma_stop1.addr, B_AX_STOP_CH12); + rtw89_pci_ctrl_txdma_fw_ch_pcie(rtwdev, true); /* start DMA activities */ rtw89_pci_ctrl_dma_all(rtwdev, true); @@ -3771,6 +3794,16 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { .recovery_start = rtw89_pci_ops_recovery_start, .recovery_complete = rtw89_pci_ops_recovery_complete, + + .ctrl_txdma_ch = rtw89_pci_ctrl_txdma_ch_pcie, + .ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch_pcie, + .ctrl_trxhci = rtw89_pci_ctrl_dma_trx, + .poll_txdma_ch = rtw89_poll_txdma_ch_idle_pcie, + .clr_idx_all = rtw89_pci_clr_idx_all, + .clear = rtw89_pci_clear_resource, + .disable_intr = rtw89_pci_disable_intr_lock, + .enable_intr = rtw89_pci_enable_intr_lock, + .rst_bdram = rtw89_pci_rst_bdram_pcie, }; int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 179740607778..7d033501d4d9 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -202,6 +202,18 @@ #define B_AX_RXP1DMA_INT BIT(1) #define B_AX_RXDMA_INT BIT(0) +#define R_AX_HAXI_IDCT_MSK 0x10B8 +#define B_AX_TXBD_LEN0_ERR_IDCT_MSK BIT(3) +#define B_AX_TXBD_4KBOUND_ERR_IDCT_MSK BIT(2) +#define B_AX_RXMDA_STUCK_IDCT_MSK BIT(1) +#define B_AX_TXMDA_STUCK_IDCT_MSK BIT(0) + +#define R_AX_HAXI_IDCT 0x10BC +#define B_AX_TXBD_LEN0_ERR_IDCT BIT(3) +#define B_AX_TXBD_4KBOUND_ERR_IDCT BIT(2) +#define B_AX_RXMDA_STUCK_IDCT BIT(1) +#define B_AX_TXMDA_STUCK_IDCT BIT(0) + #define R_AX_HAXI_HIMR10 0x11E0 #define B_AX_TXDMA_CH11_INT_EN_V1 BIT(1) #define B_AX_TXDMA_CH10_INT_EN_V1 BIT(0) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 35a0d190434a..dd4685698983 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -801,6 +801,11 @@ bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, } EXPORT_SYMBOL(rtw89_phy_write_rf_v1); +static bool rtw89_chip_rf_v1(struct rtw89_dev *rtwdev) +{ + return rtwdev->chip->ops->write_rf == rtw89_phy_write_rf_v1; +} + static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -1123,6 +1128,24 @@ out: return ret; } +static void rtw89_phy_config_rf_reg_noio(struct rtw89_dev *rtwdev, + const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, + void *extra_data) +{ + u32 addr = reg->addr; + + if (addr == 0xfe || addr == 0xfd || addr == 0xfc || addr == 0xfb || + addr == 0xfa || addr == 0xf9) + return; + + if (rtw89_chip_rf_v1(rtwdev) && addr < 0x100) + return; + + rtw89_phy_cofig_rf_reg_store(rtwdev, reg, rf_path, + (struct rtw89_fw_h2c_rf_reg_info *)extra_data); +} + static void rtw89_phy_config_rf_reg(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg, enum rtw89_rf_path rf_path, @@ -1335,7 +1358,7 @@ static u32 rtw89_phy_nctl_poll(struct rtw89_dev *rtwdev) return rtw89_phy_read32(rtwdev, 0x8080); } -void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev) +void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio) { void (*config)(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg, enum rtw89_rf_path rf_path, void *data); @@ -1351,7 +1374,11 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev) for (path = RF_PATH_A; path < chip->rf_path_num; path++) { rf_table = chip->rf_table[path]; rf_reg_info->rf_path = rf_table->rf_path; - config = rf_table->config ? rf_table->config : rtw89_phy_config_rf_reg; + if (noio) + config = rtw89_phy_config_rf_reg_noio; + else + config = rf_table->config ? rf_table->config : + rtw89_phy_config_rf_reg; rtw89_phy_init_reg(rtwdev, rf_table, config, (void *)rf_reg_info); if (rtw89_phy_config_rf_reg_fw(rtwdev, rf_reg_info)) rtw89_warn(rtwdev, "rf path %d reg h2c config failed\n", diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 995c13f6f906..dac69a02e868 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -500,7 +500,7 @@ bool rtw89_phy_write_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, u32 addr, u32 mask, u32 data); void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev); -void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev); +void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio); void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg, enum rtw89_rf_path rf_path, diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index bf41a1141679..40498812205e 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -59,7 +59,7 @@ static void rtw89_ps_power_mode_change(struct rtw89_dev *rtwdev, bool enter) rtw89_mac_power_mode_change(rtwdev, enter); } -static void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { if (rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) return; diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h index 0feae3991623..6ac1f7ea5339 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.h +++ b/drivers/net/wireless/realtek/rtw89/ps.h @@ -8,6 +8,7 @@ void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_leave_lps(struct rtw89_dev *rtwdev); void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); +void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); void rtw89_enter_ips(struct rtw89_dev *rtwdev); void rtw89_leave_ips(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 2b938d11d238..dbe06542f443 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -326,8 +326,7 @@ #define R_AX_PCIE_DBG_CTRL 0x11C0 #define B_AX_DBG_DUMMY_MASK GENMASK(23, 16) -#define B_AX_DBG_SEL_MASK GENMASK(15, 13) -#define B_AX_PCIE_DBG_SEL BIT(12) +#define B_AX_PCIE_DBG_SEL_MASK GENMASK(15, 13) #define B_AX_MRD_TIMEOUT_EN BIT(10) #define B_AX_ASFF_FULL_NO_STK BIT(1) #define B_AX_EN_STUCK_DBG BIT(0) @@ -545,6 +544,19 @@ #define B_AX_WDE_EMPTY_QUE_CMAC0_MBH BIT(1) #define B_AX_WDE_EMPTY_QUE_CMAC0_ALL_AC BIT(0) +#define R_AX_DLE_EMPTY1 0x8434 +#define B_AX_PLE_EMPTY_QTA_DMAC_WDRLS BIT(20) +#define B_AX_PLE_EMPTY_QTA_CMAC1_DMA_BBRPT BIT(19) +#define B_AX_PLE_EMPTY_QTA_CMAC1_DMA_RX BIT(18) +#define B_AX_PLE_EMPTY_QTA_CMAC0_DMA_RX BIT(17) +#define B_AX_PLE_EMPTY_QTA_DMAC_C2H BIT(16) +#define B_AX_PLE_EMPTY_QUE_DMAC_PLRLS BIT(5) +#define B_AX_PLE_EMPTY_QUE_DMAC_CPUIO BIT(4) +#define B_AX_PLE_EMPTY_QUE_DMAC_SEC_RX BIT(3) +#define B_AX_PLE_EMPTY_QUE_DMAC_MPDU_RX BIT(2) +#define B_AX_PLE_EMPTY_QUE_DMAC_HDP BIT(1) +#define B_AX_WDE_EMPTY_QUE_DMAC_WDRLS BIT(0) + #define R_AX_DMAC_ERR_IMR 0x8520 #define B_AX_DLE_CPUIO_ERR_INT_EN BIT(10) #define B_AX_APB_BRIDGE_ERR_INT_EN BIT(9) @@ -561,6 +573,10 @@ #define DMAC_ERR_IMR_DIS 0 #define R_AX_DMAC_ERR_ISR 0x8524 +#define B_AX_HAXIDMA_ERR_FLAG BIT(14) +#define B_AX_PAXIDMA_ERR_FLAG BIT(13) +#define B_AX_HCI_BUF_ERR_FLAG BIT(12) +#define B_AX_BBRPT_ERR_FLAG BIT(11) #define B_AX_DLE_CPUIO_ERR_FLAG BIT(10) #define B_AX_APB_BRIDGE_ERR_FLAG BIT(9) #define B_AX_DISPATCH_ERR_FLAG BIT(8) @@ -939,6 +955,14 @@ B_AX_STF_OQT_OVERFLOW_ERR_INT_EN | \ B_AX_STF_OQT_UNDERFLOW_ERR_INT_EN) +#define R_AX_DISPATCHER_DBG_PORT 0x8860 +#define B_AX_DISPATCHER_DBG_SEL_MASK GENMASK(11, 8) +#define B_AX_DISPATCHER_INTN_SEL_MASK GENMASK(7, 4) +#define B_AX_DISPATCHER_CH_SEL_MASK GENMASK(3, 0) + +#define R_AX_RX_FUNCTION_STOP 0x8920 +#define B_AX_HDR_RX_STOP BIT(0) + #define R_AX_HCI_FC_CTRL 0x8A00 #define B_AX_HCI_FC_CH12_FULL_COND_MASK GENMASK(11, 10) #define B_AX_HCI_FC_WP_CH811_FULL_COND_MASK GENMASK(9, 8) @@ -1020,7 +1044,13 @@ #define R_AX_WDE_ERRFLAG_MSG 0x8C30 #define B_AX_WDE_ERR_FLAG_MSG_MASK GENMASK(31, 0) -#define R_AX_WDE_ERR_FLAG_CFG 0x8C34 +#define R_AX_WDE_ERR_FLAG_CFG_NUM1 0x8C34 +#define B_AX_WDE_ERR_FLAG_NUM1_VLD BIT(31) +#define B_AX_WDE_ERR_FLAG_NUM1_MSTIDX_MASK GENMASK(27, 24) +#define B_AX_WDE_ERR_FLAG_NUM1_ISRIDX_MASK GENMASK(20, 16) +#define B_AX_WDE_DATCHN_FRZTMR_MODE BIT(2) +#define B_AX_WDE_QUEMGN_FRZTMR_MODE BIT(1) +#define B_AX_WDE_BUFMGN_FRZTMR_MODE BIT(0) #define R_AX_WDE_ERR_IMR 0x8C38 #define B_AX_WDE_DATCHN_RRDY_ERR_INT_EN BIT(27) @@ -1204,7 +1234,59 @@ #define B_AX_PLE_START_BOUND_MASK GENMASK(13, 8) #define B_AX_PLE_PAGE_SEL_MASK GENMASK(1, 0) #define B_AX_PLE_FREE_PAGE_NUM_MASK GENMASK(28, 16) -#define R_AX_PLE_ERR_FLAG_CFG 0x9034 + +#define R_AX_PLE_DBGERR_LOCKEN 0x9020 +#define B_AX_PLE_LOCKEN_DLEPIF07 BIT(7) +#define B_AX_PLE_LOCKEN_DLEPIF06 BIT(6) +#define B_AX_PLE_LOCKEN_DLEPIF05 BIT(5) +#define B_AX_PLE_LOCKEN_DLEPIF04 BIT(4) +#define B_AX_PLE_LOCKEN_DLEPIF03 BIT(3) +#define B_AX_PLE_LOCKEN_DLEPIF02 BIT(2) +#define B_AX_PLE_LOCKEN_DLEPIF01 BIT(1) +#define B_AX_PLE_LOCKEN_DLEPIF00 BIT(0) + +#define R_AX_PLE_DBGERR_STS 0x9024 +#define B_AX_PLE_LOCKON_DLEPIF07 BIT(7) +#define B_AX_PLE_LOCKON_DLEPIF06 BIT(6) +#define B_AX_PLE_LOCKON_DLEPIF05 BIT(5) +#define B_AX_PLE_LOCKON_DLEPIF04 BIT(4) +#define B_AX_PLE_LOCKON_DLEPIF03 BIT(3) +#define B_AX_PLE_LOCKON_DLEPIF02 BIT(2) +#define B_AX_PLE_LOCKON_DLEPIF01 BIT(1) +#define B_AX_PLE_LOCKON_DLEPIF00 BIT(0) + +#define R_AX_PLE_ERR_FLAG_CFG_NUM1 0x9034 +#define B_AX_PLE_ERR_FLAG_NUM1_VLD BIT(31) +#define B_AX_PLE_ERR_FLAG_NUM1_MSTIDX_MASK GENMASK(27, 24) +#define B_AX_PLE_ERR_FLAG_NUM1_ISRIDX_MASK GENMASK(20, 16) +#define B_AX_PLE_DATCHN_FRZTMR_MODE BIT(2) +#define B_AX_PLE_QUEMGN_FRZTMR_MODE BIT(1) +#define B_AX_PLE_BUFMGN_FRZTMR_MODE BIT(0) + +#define R_AX_PLE_ERRFLAG_MSG 0x9030 +#define B_AX_PLE_ERR_FLAG_MSG_MASK GENMASK(31, 0) +#define B_AX_PLE_DATCHN_CAMREQ_ERR_INT_EN BIT(29) +#define B_AX_PLE_DATCHN_ADRERR_ERR_INT_EN BIT(28) +#define B_AX_PLE_BUFMGN_FRZTO_ERR_INT_EN_V1 BIT(9) +#define B_AX_PLE_GETNPG_PGOFST_ERR_INT_EN_V1 BIT(8) +#define B_AX_PLE_GETNPG_STRPG_ERR_INT_EN_V1 BIT(7) +#define B_AX_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN_V1 BIT(6) +#define B_AX_PLE_BUFRTN_SIZE_ERR_INT_EN_V1 BIT(5) +#define B_AX_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN_V1 BIT(4) +#define B_AX_PLE_BUFREQ_UNAVAL_ERR_INT_EN_V1 BIT(3) +#define B_AX_PLE_BUFREQ_SIZELMT_INT_EN BIT(2) +#define B_AX_PLE_BUFREQ_SIZE0_INT_EN BIT(1) +#define B_AX_PLE_DATCHN_CAMREQ_ERR BIT(29) +#define B_AX_PLE_DATCHN_ADRERR_ERR BIT(28) +#define B_AX_PLE_BUFMGN_FRZTO_ERR_V1 BIT(9) +#define B_AX_PLE_GETNPG_PGOFST_ERR_V1 BIT(8) +#define B_AX_PLE_GETNPG_STRPG_ERR_V1 BIT(7) +#define B_AX_PLE_BUFREQ_SRCHTAILPG_ERR_V1 BIT(6) +#define B_AX_PLE_BUFRTN_SIZE_ERR_V1 BIT(5) +#define B_AX_PLE_BUFRTN_INVLD_PKTID_ERR_V1 BIT(4) +#define B_AX_PLE_BUFREQ_UNAVAL_ERR_V1 BIT(3) +#define B_AX_PLE_BUFREQ_SIZELMT_ERR BIT(2) +#define B_AX_PLE_BUFREQ_SIZE0_ERR BIT(1) #define R_AX_PLE_ERR_IMR 0x9038 #define B_AX_PLE_DATCHN_RRDY_ERR_INT_EN BIT(27) @@ -1415,6 +1497,19 @@ #define B_AX_BBRPT_COM_NULL_PLPKTID_ERR BIT(16) #define B_AX_BBRPT_COM_NULL_PLPKTID_ERR_INT_EN BIT(0) +#define R_AX_BBRPT_COM_ERR_ISR 0x960C +#define B_AX_BBRPT_COM_NULL_PLPKTID_ERR_INT_V1 BIT(0) + +#define R_AX_BBRPT_CHINFO_ERR_ISR 0x962C +#define B_AX_BBPRT_CHIF_TO_ERR_V1 BIT(7) +#define B_AX_BBPRT_CHIF_NULL_ERR_V1 BIT(6) +#define B_AX_BBPRT_CHIF_LEFT2_ERR_V1 BIT(5) +#define B_AX_BBPRT_CHIF_LEFT1_ERR_V1 BIT(4) +#define B_AX_BBPRT_CHIF_HDRL_ERR_V1 BIT(3) +#define B_AX_BBPRT_CHIF_BOVF_ERR_V1 BIT(2) +#define B_AX_BBPRT_CHIF_OVF_ERR_V1 BIT(1) +#define B_AX_BBPRT_CHIF_BB_TO_ERR_V1 BIT(0) + #define R_AX_BBRPT_CHINFO_ERR_IMR 0x9628 #define B_AX_BBPRT_CHIF_TO_ERR_INT_EN BIT(7) #define B_AX_BBPRT_CHIF_NULL_ERR_INT_EN BIT(6) @@ -1466,6 +1561,9 @@ #define B_AX_BBRPT_DFS_TO_ERR BIT(16) #define B_AX_BBRPT_DFS_TO_ERR_INT_EN BIT(0) +#define R_AX_BBRPT_DFS_ERR_ISR 0x963C +#define B_AX_BBRPT_DFS_TO_ERR_V1 BIT(0) + #define R_AX_LA_ERRFLAG 0x966C #define B_AX_LA_ISR_DATA_LOSS_ERR BIT(16) #define B_AX_LA_IMR_DATA_LOSS_ERR BIT(0) @@ -1557,6 +1655,8 @@ #define R_AX_ACTION_FWD0 0x9C04 #define TRXCFG_MPDU_PROC_ACT_FRWD 0x02A95A95 +#define R_AX_ACTION_FWD1 0x9C08 + #define R_AX_TF_FWD 0x9C14 #define TRXCFG_MPDU_PROC_TF_FRWD 0x0000AA55 @@ -1568,6 +1668,9 @@ #define R_AX_CUT_AMSDU_CTRL 0x9C40 #define TRXCFG_MPDU_PROC_CUT_CTRL 0x010E05F0 +#define R_AX_WOW_CTRL 0x9C50 +#define B_AX_WOW_WOWEN BIT(1) + #define R_AX_MPDU_RX_ERR_ISR 0x9CF0 #define R_AX_MPDU_RX_ERR_IMR 0x9CF4 #define B_AX_RPT_ERR_INT_EN BIT(3) @@ -1576,6 +1679,7 @@ #define B_AX_MPDU_RX_IMR_SET_V1 B_AX_RPT_ERR_INT_EN #define R_AX_SEC_ENG_CTRL 0x9D00 +#define B_AX_SEC_DBG_PORT_FIELD_MASK GENMASK(19, 16) #define B_AX_TX_PARTIAL_MODE BIT(11) #define B_AX_CLK_EN_CGCMP BIT(10) #define B_AX_CLK_EN_WAPI BIT(9) @@ -1605,12 +1709,21 @@ #define R_AX_SEC_TX_DEBUG 0x9D20 #define R_AX_SEC_RX_DEBUG 0x9D24 #define R_AX_SEC_TRX_PKT_CNT 0x9D28 + +#define R_AX_SEC_DEBUG2 0x9D28 +#define B_AX_DBG_READ_SH 2 +#define B_AX_DBG_READ_MSK 0x3fffffff + #define R_AX_SEC_TRX_BLK_CNT 0x9D2C #define R_AX_SEC_ERROR_FLAG_IMR 0x9D2C #define B_AX_RX_HANG_IMR BIT(1) #define B_AX_TX_HANG_IMR BIT(0) +#define R_AX_SEC_ERROR_FLAG 0x9D30 +#define B_AX_RX_HANG_ERROR_V1 BIT(1) +#define B_AX_TX_HANG_ERROR_V1 BIT(0) + #define R_AX_SS_CTRL 0x9E10 #define B_AX_SS_INIT_DONE_1 BIT(31) #define B_AX_SS_WARM_INIT_FLG BIT(29) @@ -1745,6 +1858,28 @@ B_AX_B0_IMR_ERR_PRELD_RLSPKTSZERR | \ B_AX_B0_IMR_ERR_PRELD_ENTNUMCFG) +#define R_AX_TXPKTCTL_B0_ERRFLAG_ISR 0x9F7C +#define B_AX_B0_ISR_ERR_PRELD_EVT3 BIT(23) +#define B_AX_B0_ISR_ERR_PRELD_EVT2 BIT(22) +#define B_AX_B0_ISR_ERR_PRELD_ENTNUMCFG BIT(21) +#define B_AX_B0_ISR_ERR_PRELD_RLSPKTSZERR BIT(20) +#define B_AX_B0_ISR_ERR_MPDUIF_ERR1 BIT(19) +#define B_AX_B0_ISR_ERR_MPDUIF_DATAERR BIT(18) +#define B_AX_B0_ISR_ERR_MPDUINFO_ERR1 BIT(17) +#define B_AX_B0_ISR_ERR_MPDUINFO_RECFG BIT(16) +#define B_AX_B0_ISR_ERR_CMDPSR_TBLSZ BIT(11) +#define B_AX_B0_ISR_ERR_CMDPSR_FRZTO BIT(10) +#define B_AX_B0_ISR_ERR_CMDPSR_CMDTYPE BIT(9) +#define B_AX_B0_ISR_ERR_CMDPSR_1STCMDERR BIT(8) +#define B_AX_B0_ISR_ERR_USRCTL_EVT7 BIT(7) +#define B_AX_B0_ISR_ERR_USRCTL_EVT6 BIT(6) +#define B_AX_B0_ISR_ERR_USRCTL_EVT5 BIT(5) +#define B_AX_B0_ISR_ERR_USRCTL_EVT4 BIT(4) +#define B_AX_B0_ISR_ERR_USRCTL_RLSBMPLEN BIT(3) +#define B_AX_B0_ISR_ERR_USRCTL_RDNRLSCMD BIT(2) +#define B_AX_B0_ISR_ERR_USRCTL_NOINIT BIT(1) +#define B_AX_B0_ISR_ERR_USRCTL_REINIT BIT(0) + #define R_AX_TXPKTCTL_B1_PRELD_CFG0 0x9F88 #define B_AX_B1_PRELD_FEN BIT(31) #define B_AX_B1_PRELD_USEMAXSZ_MASK GENMASK(25, 16) @@ -1792,6 +1927,28 @@ B_AX_B1_IMR_ERR_PRELD_RLSPKTSZERR | \ B_AX_B1_IMR_ERR_PRELD_ENTNUMCFG) +#define R_AX_TXPKTCTL_B1_ERRFLAG_ISR 0x9FBC +#define B_AX_B1_ISR_ERR_PRELD_EVT3 BIT(23) +#define B_AX_B1_ISR_ERR_PRELD_EVT2 BIT(22) +#define B_AX_B1_ISR_ERR_PRELD_ENTNUMCFG BIT(21) +#define B_AX_B1_ISR_ERR_PRELD_RLSPKTSZERR BIT(20) +#define B_AX_B1_ISR_ERR_MPDUIF_ERR1 BIT(19) +#define B_AX_B1_ISR_ERR_MPDUIF_DATAERR BIT(18) +#define B_AX_B1_ISR_ERR_MPDUINFO_ERR1 BIT(17) +#define B_AX_B1_ISR_ERR_MPDUINFO_RECFG BIT(16) +#define B_AX_B1_ISR_ERR_CMDPSR_TBLSZ BIT(11) +#define B_AX_B1_ISR_ERR_CMDPSR_FRZTO BIT(10) +#define B_AX_B1_ISR_ERR_CMDPSR_CMDTYPE BIT(9) +#define B_AX_B1_ISR_ERR_CMDPSR_1STCMDERR BIT(8) +#define B_AX_B1_ISR_ERR_USRCTL_EVT7 BIT(7) +#define B_AX_B1_ISR_ERR_USRCTL_EVT6 BIT(6) +#define B_AX_B1_ISR_ERR_USRCTL_EVT5 BIT(5) +#define B_AX_B1_ISR_ERR_USRCTL_EVT4 BIT(4) +#define B_AX_B1_ISR_ERR_USRCTL_RLSBMPLEN BIT(3) +#define B_AX_B1_ISR_ERR_USRCTL_RDNRLSCMD BIT(2) +#define B_AX_B1_ISR_ERR_USRCTL_NOINIT BIT(1) +#define B_AX_B1_ISR_ERR_USRCTL_REINIT BIT(0) + #define R_AX_AFE_CTRL1 0x0024 #define B_AX_R_SYM_WLCMAC1_P4_PC_EN BIT(4) @@ -2360,6 +2517,41 @@ #define B_AX_DLE_IMR_SET (B_AX_RXSTS_FSM_HANG_ERROR_IMR | \ B_AX_RXDATA_FSM_HANG_ERROR_IMR) +#define R_AX_RX_ERR_FLAG 0xC800 +#define R_AX_RX_ERR_FLAG_C1 0xE800 +#define B_AX_RX_GET_NO_PAGE_ERR BIT(31) +#define B_AX_RX_GET_NULL_PKT_ERR BIT(30) +#define B_AX_RX_RU0_FSM_HANG_ERR BIT(29) +#define B_AX_RX_RU1_FSM_HANG_ERR BIT(28) +#define B_AX_RX_RU2_FSM_HANG_ERR BIT(27) +#define B_AX_RX_RU3_FSM_HANG_ERR BIT(26) +#define B_AX_RX_RU4_FSM_HANG_ERR BIT(25) +#define B_AX_RX_RU5_FSM_HANG_ERR BIT(24) +#define B_AX_RX_RU6_FSM_HANG_ERR BIT(23) +#define B_AX_RX_RU7_FSM_HANG_ERR BIT(22) +#define B_AX_RX_RXSTS_FSM_HANG_ERR BIT(21) +#define B_AX_RX_CSI_FSM_HANG_ERR BIT(20) +#define B_AX_RX_TXRPT_FSM_HANG_ERR BIT(19) +#define B_AX_RX_F2PCMD_FSM_HANG_ERR BIT(18) +#define B_AX_RX_RU0_ZERO_LEN_ERR BIT(17) +#define B_AX_RX_RU1_ZERO_LEN_ERR BIT(16) +#define B_AX_RX_RU2_ZERO_LEN_ERR BIT(15) +#define B_AX_RX_RU3_ZERO_LEN_ERR BIT(14) +#define B_AX_RX_RU4_ZERO_LEN_ERR BIT(13) +#define B_AX_RX_RU5_ZERO_LEN_ERR BIT(12) +#define B_AX_RX_RU6_ZERO_LEN_ERR BIT(11) +#define B_AX_RX_RU7_ZERO_LEN_ERR BIT(10) +#define B_AX_RX_RXSTS_ZERO_LEN_ERR BIT(9) +#define B_AX_RX_CSI_ZERO_LEN_ERR BIT(8) +#define B_AX_PLE_DATA_OPT_FSM_HANG BIT(7) +#define B_AX_PLE_RXDATA_REQ_BUF_FSM_HANG BIT(6) +#define B_AX_PLE_TXRPT_REQ_BUF_FSM_HANG BIT(5) +#define B_AX_PLE_WD_OPT_FSM_HANG BIT(4) +#define B_AX_PLE_ENQ_FSM_HANG BIT(3) +#define B_AX_RXDATA_ENQUE_ORDER_ERR BIT(2) +#define B_AX_RXSTS_ENQUE_ORDER_ERR BIT(1) +#define B_AX_RX_CSI_PKT_NUM_ERR BIT(0) + #define R_AX_RXDMA_CTRL_0 0xC804 #define R_AX_RXDMA_CTRL_0_C1 0xE804 #define B_AX_RXDMA_DBGOUT_EN BIT(31) @@ -2382,6 +2574,49 @@ B_AX_RU2_PTR_FULL_MODE | B_AX_RU3_PTR_FULL_MODE | \ B_AX_CSI_PTR_FULL_MODE | B_AX_RXSTS_PTR_FULL_MODE) +#define R_AX_RX_CTRL0 0xC808 +#define R_AX_RX_CTRL0_C1 0xE808 +#define B_AX_DLE_CLOCK_FORCE_V1 BIT(31) +#define B_AX_TXDMA_CLOCK_FORCE_V1 BIT(30) +#define B_AX_RXDMA_CLOCK_FORCE_V1 BIT(29) +#define B_AX_RXDMA_DEFAULT_PAGE_V1_MASK GENMASK(28, 24) +#define B_AX_RXDMA_CSI_TGT_QUEID_MASK GENMASK(23, 18) +#define B_AX_RXDMA_CSI_TGT_PRID_MASK GENMASK(17, 15) +#define B_AX_RXDMA_DIS_CSI_RELEASE_V1 BIT(14) +#define B_AX_CSI_PTR_FULL_MODE_V1 BIT(13) +#define B_AX_RXDATA_PTR_FULL_MODE BIT(12) +#define B_AX_RXSTS_PTR_FULL_MODE_V1 BIT(11) +#define B_AX_TXRPT_FULL_RSV_DEPTH_V1_MASK GENMASK(10, 8) +#define B_AX_RXDATA_FULL_RSV_DEPTH_MASK GENMASK(7, 5) +#define B_AX_RXSTS_FULL_RSV_DEPTH_V1_MASK GENMASK(4, 2) +#define B_AX_ORDER_FIFO_MASK GENMASK(1, 0) + +#define R_AX_RX_CTRL1 0xC80C +#define R_AX_RX_CTRL1_C1 0xE80C +#define B_AX_RXDMA_TXRPT_QUEUE_ID_SW_EN BIT(31) +#define B_AX_RXDMA_TXRPT_QUEUE_ID_SW_V1_MASK GENMASK(30, 25) +#define B_AX_RXDMA_F2PCMD_QUEUE_ID_SW_EN BIT(24) +#define B_AX_RXDMA_F2PCMD_QUEUE_ID_SW_V1_MASK GENMASK(23, 18) +#define B_AX_RXDMA_TXRPT_QUEUE_ID_TGT_SW_EN BIT(17) +#define B_AX_RXDMA_TXRPT_QUEUE_ID_TGT_SW_1_MASK GENMASK(16, 11) +#define B_AX_RXDMA_F2PCMD_QUEUE_ID_TGT_SW_EN BIT(10) +#define B_AX_RXDMA_F2PCMD_QUEUE_ID_TGT_SW_1_MASK GENMASK(9, 4) +#define B_AX_ORDER_FIFO_OUT BIT(3) +#define B_AX_ORDER_FIFO_EMPTY BIT(2) +#define B_AX_DBG_SEL_MASK GENMASK(1, 0) + +#define R_AX_RX_CTRL2 0xC810 +#define R_AX_RX_CTRL2_C1 0xE810 +#define B_AX_DLE_WDE_STATE_V1_MASK GENMASK(31, 30) +#define B_AX_DLE_PLE_STATE_V1_MASK GENMASK(29, 28) +#define B_AX_DLE_REQ_BUF_STATE_MASK GENMASK(27, 26) +#define B_AX_DLE_ENQ_STATE_V1 BIT(25) +#define B_AX_RX_DBG_SEL_MASK GENMASK(24, 19) +#define B_AX_MACRX_CS_MASK GENMASK(18, 14) +#define B_AX_RXSTS_CS_MASK GENMASK(13, 9) +#define B_AX_ERR_INDICATOR BIT(5) +#define B_AX_TXRPT_CS_MASK GENMASK(4, 0) + #define R_AX_RXDMA_PKT_INFO_0 0xC814 #define R_AX_RXDMA_PKT_INFO_1 0xC818 #define R_AX_RXDMA_PKT_INFO_2 0xC81C @@ -2689,6 +2924,18 @@ B_AX_TMAC_MIMO_CTRL | \ B_AX_RMAC_FTM) +#define R_AX_TRXPTCL_ERROR_INDICA 0xCCC0 +#define R_AX_TRXPTCL_ERROR_INDICA_C1 0xECC0 +#define B_AX_FTM_ERROR_FLAG_CLR BIT(8) +#define B_AX_CSI_ERROR_FLAG_CLR BIT(7) +#define B_AX_MIMOCTRL_ERROR_FLAG_CLR BIT(6) +#define B_AX_RXTB_ERROR_FLAG_CLR BIT(5) +#define B_AX_HWSIGB_GEN_ERROR_FLAG_CLR BIT(4) +#define B_AX_TXPLCP_ERROR_FLAG_CLR BIT(3) +#define B_AX_RESP_ERROR_FLAG_CLR BIT(2) +#define B_AX_TXCTL_ERROR_FLAG_CLR BIT(1) +#define B_AX_MACTX_ERROR_FLAG_CLR BIT(0) + #define R_AX_WMAC_TX_TF_INFO_0 0xCCD0 #define R_AX_WMAC_TX_TF_INFO_0_C1 0xECD0 #define B_AX_WMAC_TX_TF_INFO_SEL_MASK GENMASK(2, 0) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index b5aa8697a098..4cea5fb4327d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -48,6 +48,10 @@ static const struct rtw89_dle_mem rtw8852a_dle_mem_pcie[] = { &rtw89_mac_size.ple_size0, &rtw89_mac_size.wde_qt0, &rtw89_mac_size.wde_qt0, &rtw89_mac_size.ple_qt4, &rtw89_mac_size.ple_qt5}, + [RTW89_QTA_WOW] = {RTW89_QTA_WOW, &rtw89_mac_size.wde_size0, + &rtw89_mac_size.ple_size0, &rtw89_mac_size.wde_qt0, + &rtw89_mac_size.wde_qt0, &rtw89_mac_size.ple_qt4, + &rtw89_mac_size.ple_qt_52a_wow}, [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size4, &rtw89_mac_size.ple_size4, &rtw89_mac_size.wde_qt4, &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, @@ -1986,6 +1990,15 @@ static void rtw8852a_query_ppdu(struct rtw89_dev *rtwdev, rtw8852a_fill_freq_with_ppdu(rtwdev, phy_ppdu, status); } +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support rtw_wowlan_stub_8852a = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = RTW89_MAX_PATTERN_NUM, + .pattern_max_len = RTW89_MAX_PATTERN_SIZE, + .pattern_min_len = 1, +}; +#endif + static const struct rtw89_chip_ops rtw8852a_chip_ops = { .enable_bb_rf = rtw89_mac_enable_bb_rf, .disable_bb_rf = rtw89_mac_disable_bb_rf, @@ -2045,6 +2058,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852a_hfc_param_ini_pcie, .dle_mem = rtw8852a_dle_mem_pcie, + .wde_qempty_acq_num = 16, + .wde_qempty_mgq_sel = 16, .rf_base_addr = {0xc000, 0xd000}, .pwr_on_seq = pwr_on_seq_8852a, .pwr_off_seq = pwr_off_seq_8852a, @@ -2133,6 +2148,9 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .imr_info = &rtw8852a_imr_info, .rrsr_cfgs = &rtw8852a_rrsr_cfgs, .dma_ch_mask = 0, +#ifdef CONFIG_PM + .wowlan_stub = &rtw_wowlan_stub_8852a, +#endif }; EXPORT_SYMBOL(rtw8852a_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c index 8fd01502ac5b..722ae34b09c1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c @@ -1754,7 +1754,7 @@ static void _dpk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, id == 0x14 ? "PWR_CAL" : id == 0x15 ? "DPK_RXAGC" : id == 0x16 ? "KIP_PRESET" : - id == 0x17 ? "KIP_RESOTRE" : "DPK_TXAGC", + id == 0x17 ? "KIP_RESTORE" : "DPK_TXAGC", dpk_cmd); } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index f6bcac826816..6619ba730719 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -1683,12 +1683,12 @@ static void rtw8852c_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) { + static const u32 ru_alloc_msk[2] = {B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY0, + B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY1}; struct rtw89_hal *hal = &rtwdev->hal; bool cck_en = chan->band_type == RTW89_BAND_2G; u8 pri_ch_idx = chan->pri_ch_idx; u32 mask, reg; - u32 ru_alloc_msk[2] = {B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY0, - B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY1}; u8 ntx_path; if (chan->band_type == RTW89_BAND_2G) @@ -2796,6 +2796,15 @@ static int rtw8852c_mac_disable_bb_rf(struct rtw89_dev *rtwdev) return 0; } +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support rtw_wowlan_stub_8852c = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = RTW89_MAX_PATTERN_NUM, + .pattern_max_len = RTW89_MAX_PATTERN_SIZE, + .pattern_min_len = 1, +}; +#endif + static const struct rtw89_chip_ops rtw8852c_chip_ops = { .enable_bb_rf = rtw8852c_mac_enable_bb_rf, .disable_bb_rf = rtw8852c_mac_disable_bb_rf, @@ -2855,6 +2864,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = rtw8852c_hfc_param_ini_pcie, .dle_mem = rtw8852c_dle_mem_pcie, + .wde_qempty_acq_num = 16, + .wde_qempty_mgq_sel = 16, .rf_base_addr = {0xe000, 0xf000}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, @@ -2947,6 +2958,9 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .imr_info = &rtw8852c_imr_info, .rrsr_cfgs = &rtw8852c_rrsr_cfgs, .dma_ch_mask = 0, +#ifdef CONFIG_PM + .wowlan_stub = &rtw_wowlan_stub_8852c, +#endif }; EXPORT_SYMBOL(rtw8852c_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/util.h b/drivers/net/wireless/realtek/rtw89/util.h index 1ae80b7561da..e2ed4565025d 100644 --- a/drivers/net/wireless/realtek/rtw89/util.h +++ b/drivers/net/wireless/realtek/rtw89/util.h @@ -44,4 +44,15 @@ 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]; + } +} + #endif diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c new file mode 100644 index 000000000000..b2b826b2e09a --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -0,0 +1,859 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2019-2022 Realtek Corporation + */ +#include "cam.h" +#include "core.h" +#include "debug.h" +#include "fw.h" +#include "mac.h" +#include "phy.h" +#include "ps.h" +#include "reg.h" +#include "util.h" +#include "wow.h" + +static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev) +{ + __rtw89_leave_ps_mode(rtwdev); +} + +static void rtw89_wow_enter_deep_ps(struct rtw89_dev *rtwdev) +{ + struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + + __rtw89_enter_ps_mode(rtwdev, rtwvif); +} + +static void rtw89_wow_enter_lps(struct rtw89_dev *rtwdev) +{ + struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + + rtw89_enter_lps(rtwdev, rtwvif); +} + +static void rtw89_wow_leave_lps(struct rtw89_dev *rtwdev) +{ + rtw89_leave_lps(rtwdev); +} + +static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow) +{ + int ret; + + if (enable_wow) { + ret = rtw89_mac_resize_ple_rx_quota(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); + return ret; + } + rtw89_write32_set(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); + rtw89_write32_clr(rtwdev, R_AX_RX_FLTR_OPT, B_AX_SNIFFER_MODE); + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); + rtw89_write32(rtwdev, R_AX_ACTION_FWD0, 0); + rtw89_write32(rtwdev, R_AX_ACTION_FWD1, 0); + rtw89_write32(rtwdev, R_AX_TF_FWD, 0); + rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0); + } else { + ret = rtw89_mac_resize_ple_rx_quota(rtwdev, false); + if (ret) { + rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); + return ret; + } + rtw89_write32_clr(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); + rtw89_write32(rtwdev, R_AX_ACTION_FWD0, TRXCFG_MPDU_PROC_ACT_FRWD); + rtw89_write32(rtwdev, R_AX_TF_FWD, TRXCFG_MPDU_PROC_TF_FRWD); + } + + return 0; +} + +static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable) +{ + enum rtw89_mac_fwd_target fwd_target = enable ? + RTW89_FWD_DONT_CARE : + RTW89_FWD_TO_HOST; + + rtw89_mac_typ_fltr_opt(rtwdev, RTW89_MGNT, fwd_target, RTW89_MAC_0); + rtw89_mac_typ_fltr_opt(rtwdev, RTW89_CTRL, fwd_target, RTW89_MAC_0); + rtw89_mac_typ_fltr_opt(rtwdev, RTW89_DATA, fwd_target, RTW89_MAC_0); +} + +static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) +{ + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + struct cfg80211_wowlan_nd_info nd_info; + struct cfg80211_wowlan_wakeup wakeup = { + .pattern_idx = -1, + }; + u32 wow_reason_reg; + u8 reason; + + if (chip_id == RTL8852A || chip_id == RTL8852B) + wow_reason_reg = R_AX_C2HREG_DATA3 + 3; + else + wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3; + + reason = rtw89_read8(rtwdev, wow_reason_reg); + + switch (reason) { + case RTW89_WOW_RSN_RX_DEAUTH: + wakeup.disconnect = true; + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx deauth\n"); + break; + case RTW89_WOW_RSN_DISCONNECT: + wakeup.disconnect = true; + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: AP is off\n"); + break; + case RTW89_WOW_RSN_RX_MAGIC_PKT: + wakeup.magic_pkt = true; + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx magic packet\n"); + break; + case RTW89_WOW_RSN_RX_GTK_REKEY: + wakeup.gtk_rekey_failure = true; + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx gtk rekey\n"); + break; + case RTW89_WOW_RSN_RX_PATTERN_MATCH: + /* Current firmware and driver don't report pattern index + * Use pattern_idx to 0 defaultly. + */ + wakeup.pattern_idx = 0; + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx pattern match packet\n"); + break; + case RTW89_WOW_RSN_RX_NLO: + /* Current firmware and driver don't report ssid index. + * Use 0 for n_matches based on its comment. + */ + nd_info.n_matches = 0; + wakeup.net_detect = &nd_info; + rtw89_debug(rtwdev, RTW89_DBG_WOW, "Rx NLO\n"); + break; + default: + rtw89_warn(rtwdev, "Unknown wakeup reason %x\n", reason); + ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, NULL, + GFP_KERNEL); + return; + } + + ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, &wakeup, + GFP_KERNEL); +} + +static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + + /* Current wowlan function support setting of only one STATION vif. + * So when one suitable vif is found, stop the iteration. + */ + if (rtw_wow->wow_vif || vif->type != NL80211_IFTYPE_STATION) + return; + + switch (rtwvif->net_type) { + case RTW89_NET_TYPE_INFRA: + rtw_wow->wow_vif = vif; + break; + case RTW89_NET_TYPE_NO_LINK: + default: + break; + } +} + +static u16 __rtw89_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(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 rtw89_calc_crc(u8 *pdata, int length) +{ + u16 crc = 0xffff; + int i; + + for (i = 0; i < length; i++) + crc = __rtw89_cal_crc16(pdata[i], crc); + + /* get 1' complement */ + return ~crc; +} + +static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif, + struct rtw89_wow_cam_info *rtw_pattern, + const u8 *pattern, u8 da_mask) +{ + u8 da[ETH_ALEN]; + + ether_addr_copy_mask(da, pattern, da_mask); + + /* Each pattern is divided into different kinds by DA address + * a. DA is broadcast address: set bc = 0; + * b. DA is multicast address: set mc = 0 + * c. DA is unicast address same as dev's mac address: set uc = 0 + * d. DA is unmasked. Also called wildcard type: set uc = bc = mc = 0 + * e. Others is invalid type. + */ + + if (is_broadcast_ether_addr(da)) + rtw_pattern->bc = true; + else if (is_multicast_ether_addr(da)) + rtw_pattern->mc = true; + else if (ether_addr_equal(da, rtwvif->mac_addr) && + da_mask == GENMASK(5, 0)) + rtw_pattern->uc = true; + else if (!da_mask) /*da_mask == 0 mean wildcard*/ + return 0; + else + return -EPERM; + + return 0; +} + +static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + const struct cfg80211_pkt_pattern *pkt_pattern, + struct rtw89_wow_cam_info *rtw_pattern) +{ + u8 mask_hw[RTW89_MAX_PATTERN_MASK_SIZE * 4] = {0}; + u8 content[RTW89_MAX_PATTERN_SIZE] = {0}; + const u8 *mask; + const u8 *pattern; + u8 mask_len; + u16 count; + u32 len; + int i, ret; + + pattern = pkt_pattern->pattern; + len = pkt_pattern->pattern_len; + mask = pkt_pattern->mask; + mask_len = DIV_ROUND_UP(len, 8); + memset(rtw_pattern, 0, sizeof(*rtw_pattern)); + + ret = rtw89_wow_pattern_get_type(rtwvif, rtw_pattern, pattern, + mask[0] & GENMASK(5, 0)); + if (ret) + return ret; + + /* translate mask from os to mask for hw + * pattern from OS uses 'ethenet frame', like this: + * | 6 | 6 | 2 | 20 | Variable | 4 | + * |--------+--------+------+-----------+------------+-----| + * | 802.3 Mac Header | IP Header | TCP Packet | FCS | + * | DA | SA | Type | + * + * BUT, packet catched by our HW is in '802.11 frame', begin from LLC + * | 24 or 30 | 6 | 2 | 20 | Variable | 4 | + * |-------------------+--------+------+-----------+------------+-----| + * | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS | + * | Others | Tpye | + * + * Therefore, we need translate mask_from_OS to mask_to_hw. + * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0, + * because new mask[0~5] means 'SA', but our HW packet begins from LLC, + * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match. + */ + + /* Shift 6 bits */ + for (i = 0; i < mask_len - 1; i++) { + mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6)) | + u8_get_bits(mask[i + 1], GENMASK(5, 0)) << 2; + } + mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6)); + + /* Set bit 0-5 to zero */ + mask_hw[0] &= ~GENMASK(5, 0); + + memcpy(rtw_pattern->mask, mask_hw, sizeof(rtw_pattern->mask)); + + /* To get the wake up pattern from the mask. + * We do not count first 12 bits which means + * DA[6] and SA[6] in the pattern to match HW design. + */ + count = 0; + for (i = 12; i < len; i++) { + if ((mask[i / 8] >> (i % 8)) & 0x01) { + content[count] = pattern[i]; + count++; + } + } + + rtw_pattern->crc = rtw89_calc_crc(content, count); + + return 0; +} + +static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct cfg80211_wowlan *wowlan) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns; + int i; + int ret; + + if (!wowlan->n_patterns || !wowlan->patterns) + return 0; + + for (i = 0; i < wowlan->n_patterns; i++) { + rtw_pattern = &rtw_wow->patterns[i]; + ret = rtw89_wow_pattern_generate(rtwdev, rtwvif, + &wowlan->patterns[i], + rtw_pattern); + if (ret) { + rtw89_err(rtwdev, "failed to generate pattern(%d)\n", i); + rtw_wow->pattern_cnt = 0; + return ret; + } + + rtw_pattern->r_w = true; + rtw_pattern->idx = i; + rtw_pattern->negative_pattern_match = false; + rtw_pattern->skip_mac_hdr = true; + rtw_pattern->valid = true; + } + rtw_wow->pattern_cnt = wowlan->n_patterns; + + return 0; +} + +static void rtw89_wow_pattern_clear_cam(struct rtw89_dev *rtwdev) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns; + int i = 0; + + for (i = 0; i < rtw_wow->pattern_cnt; i++) { + rtw_pattern = &rtw_wow->patterns[i]; + rtw_pattern->valid = false; + rtw89_fw_wow_cam_update(rtwdev, rtw_pattern); + } +} + +static void rtw89_wow_pattern_write(struct rtw89_dev *rtwdev) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns; + int i; + + for (i = 0; i < rtw_wow->pattern_cnt; i++) + rtw89_fw_wow_cam_update(rtwdev, rtw_pattern + i); +} + +static void rtw89_wow_pattern_clear(struct rtw89_dev *rtwdev) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + + rtw89_wow_pattern_clear_cam(rtwdev); + + rtw_wow->pattern_cnt = 0; + memset(rtw_wow->patterns, 0, sizeof(rtw_wow->patterns)); +} + +static void rtw89_wow_clear_wakeups(struct rtw89_dev *rtwdev) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + + rtw_wow->wow_vif = NULL; + rtw89_core_release_all_bits_map(rtw_wow->flags, RTW89_WOW_FLAG_NUM); + rtw_wow->pattern_cnt = 0; +} + +static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev, + struct cfg80211_wowlan *wowlan) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_vif *rtwvif; + + if (wowlan->disconnect) + set_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags); + if (wowlan->magic_pkt) + set_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags); + + rtw89_for_each_rtwvif(rtwdev, rtwvif) + rtw89_wow_vif_iter(rtwdev, rtwvif); + + if (!rtw_wow->wow_vif) + return -EPERM; + + rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; + return rtw89_wow_parse_patterns(rtwdev, rtwvif, wowlan); +} + +static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct ieee80211_sta *wow_sta; + struct rtw89_sta *rtwsta = NULL; + bool is_conn = true; + int ret; + + wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); + if (wow_sta) + rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; + else + is_conn = false; + + if (wow) { + if (rtw_wow->pattern_cnt) + rtwvif->wowlan_pattern = true; + if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags)) + rtwvif->wowlan_magic = true; + } else { + rtwvif->wowlan_pattern = false; + rtwvif->wowlan_magic = false; + } + + ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow); + if (ret) { + rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n"); + return ret; + } + + if (wow) { + ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); + if (ret) { + rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n", + ret); + return ret; + } + } + + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn); + if (ret) { + rtw89_warn(rtwdev, "failed to send h2c join info\n"); + return ret; + } + + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + if (ret) { + rtw89_warn(rtwdev, "failed to send h2c cam\n"); + return ret; + } + + ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow); + if (ret) { + rtw89_err(rtwdev, "failed to fw wow global\n"); + return ret; + } + + return 0; +} + +static int rtw89_wow_check_fw_status(struct rtw89_dev *rtwdev, bool wow_enable) +{ + u8 polling; + int ret; + + ret = read_poll_timeout_atomic(rtw89_read8_mask, polling, + wow_enable == !!polling, + 50, 50000, false, rtwdev, + R_AX_WOW_CTRL, B_AX_WOW_WOWEN); + if (ret) + rtw89_err(rtwdev, "failed to check wow status %s\n", + wow_enable ? "enabled" : "disabled"); + return ret; +} + +static void rtw89_wow_release_pkt_list(struct rtw89_dev *rtwdev) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct list_head *pkt_list = &rtw_wow->pkt_list; + struct rtw89_pktofld_info *info, *tmp; + + list_for_each_entry_safe(info, tmp, pkt_list, list) { + rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); + rtw89_core_release_bit_map(rtwdev->pkt_offload, + info->id); + list_del(&info->list); + kfree(info); + } +} + +static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) +{ + enum rtw89_fw_type fw_type = wow ? RTW89_FW_WOWLAN : RTW89_FW_NORMAL; + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct ieee80211_sta *wow_sta; + struct rtw89_sta *rtwsta = NULL; + bool is_conn = true; + int ret; + + rtw89_hci_disable_intr(rtwdev); + + wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); + if (wow_sta) + rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; + else + is_conn = false; + + ret = rtw89_fw_download(rtwdev, fw_type); + if (ret) { + rtw89_warn(rtwdev, "download fw failed\n"); + return ret; + } + + rtw89_phy_init_rf_reg(rtwdev, true); + + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, + RTW89_ROLE_FW_RESTORE); + if (ret) { + rtw89_warn(rtwdev, "failed to send h2c role maintain\n"); + return ret; + } + + ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta); + if (ret) { + rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n"); + return ret; + } + + if (!is_conn) + rtw89_cam_reset_keys(rtwdev); + + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn); + if (ret) { + rtw89_warn(rtwdev, "failed to send h2c join info\n"); + return ret; + } + + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + if (ret) { + rtw89_warn(rtwdev, "failed to send h2c cam\n"); + return ret; + } + + if (is_conn) { + rtw89_phy_ra_assoc(rtwdev, wow_sta); + rtw89_phy_set_bss_color(rtwdev, wow_vif); + rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, wow_vif); + } + + rtw89_mac_hw_mgnt_sec(rtwdev, wow); + rtw89_hci_enable_intr(rtwdev); + + return 0; +} + +static int rtw89_wow_enable_trx_pre(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_hci_ctrl_txdma_ch(rtwdev, false); + rtw89_hci_ctrl_txdma_fw_ch(rtwdev, true); + + rtw89_mac_ptk_drop_by_band_and_wait(rtwdev, RTW89_MAC_0); + + ret = rtw89_hci_poll_txdma_ch(rtwdev); + if (ret) { + rtw89_err(rtwdev, "txdma ch busy\n"); + return ret; + } + rtw89_wow_set_rx_filter(rtwdev, true); + + ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); + if (ret) { + rtw89_err(rtwdev, "cfg ppdu status\n"); + return ret; + } + + return 0; +} + +static int rtw89_wow_enable_trx_post(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_hci_disable_intr(rtwdev); + rtw89_hci_ctrl_trxhci(rtwdev, false); + + ret = rtw89_hci_poll_txdma_ch(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to poll txdma ch idle pcie\n"); + return ret; + } + + ret = rtw89_wow_config_mac(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "failed to config mac\n"); + return ret; + } + + rtw89_wow_set_rx_filter(rtwdev, false); + rtw89_hci_reset(rtwdev); + + return 0; +} + +static int rtw89_wow_disable_trx_pre(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_hci_clr_idx_all(rtwdev); + + ret = rtw89_hci_rst_bdram(rtwdev); + if (ret) { + rtw89_warn(rtwdev, "reset bdram busy\n"); + return ret; + } + + rtw89_hci_ctrl_trxhci(rtwdev, true); + rtw89_hci_ctrl_txdma_ch(rtwdev, true); + + ret = rtw89_wow_config_mac(rtwdev, false); + if (ret) { + rtw89_err(rtwdev, "failed to config mac\n"); + return ret; + } + rtw89_hci_enable_intr(rtwdev); + + return 0; +} + +static int rtw89_wow_disable_trx_post(struct rtw89_dev *rtwdev) +{ + int ret; + + ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); + if (ret) + rtw89_err(rtwdev, "cfg ppdu status\n"); + + return ret; +} + +static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; + int ret; + + rtw89_wow_pattern_write(rtwdev); + + ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, true); + if (ret) { + rtw89_err(rtwdev, "wow: failed to enable keep alive\n"); + return ret; + } + + ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, true); + if (ret) { + rtw89_err(rtwdev, "wow: failed to enable disconnect detect\n"); + goto out; + } + + ret = rtw89_wow_cfg_wake(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "wow: failed to config wake\n"); + goto out; + } + + ret = rtw89_wow_check_fw_status(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "wow: failed to check enable fw ready\n"); + goto out; + } + +out: + return ret; +} + +static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; + int ret; + + rtw89_wow_pattern_clear(rtwdev); + + ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, false); + if (ret) { + rtw89_err(rtwdev, "wow: failed to disable keep alive\n"); + goto out; + } + + rtw89_wow_release_pkt_list(rtwdev); + + ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, false); + if (ret) { + rtw89_err(rtwdev, "wow: failed to disable disconnect detect\n"); + goto out; + } + + ret = rtw89_wow_cfg_wake(rtwdev, false); + if (ret) { + rtw89_err(rtwdev, "wow: failed to disable config wake\n"); + goto out; + } + + ret = rtw89_wow_check_fw_status(rtwdev, false); + if (ret) { + rtw89_err(rtwdev, "wow: failed to check disable fw ready\n"); + goto out; + } + +out: + return ret; +} + +static int rtw89_wow_enable(struct rtw89_dev *rtwdev) +{ + int ret; + + set_bit(RTW89_FLAG_WOWLAN, rtwdev->flags); + + ret = rtw89_wow_enable_trx_pre(rtwdev); + if (ret) { + rtw89_err(rtwdev, "wow: failed to enable trx_pre\n"); + goto out; + } + + ret = rtw89_wow_swap_fw(rtwdev, true); + if (ret) { + rtw89_err(rtwdev, "wow: failed to swap to wow fw\n"); + goto out; + } + + ret = rtw89_wow_fw_start(rtwdev); + if (ret) { + rtw89_err(rtwdev, "wow: failed to let wow fw start\n"); + goto out; + } + + rtw89_wow_enter_lps(rtwdev); + + ret = rtw89_wow_enable_trx_post(rtwdev); + if (ret) { + rtw89_err(rtwdev, "wow: failed to enable trx_post\n"); + goto out; + } + + return 0; + +out: + clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags); + return ret; +} + +static int rtw89_wow_disable(struct rtw89_dev *rtwdev) +{ + int ret; + + ret = rtw89_wow_disable_trx_pre(rtwdev); + if (ret) { + rtw89_err(rtwdev, "wow: failed to disable trx_pre\n"); + goto out; + } + + rtw89_wow_leave_lps(rtwdev); + + ret = rtw89_wow_fw_stop(rtwdev); + if (ret) { + rtw89_err(rtwdev, "wow: failed to swap to normal fw\n"); + goto out; + } + + ret = rtw89_wow_swap_fw(rtwdev, false); + if (ret) { + rtw89_err(rtwdev, "wow: failed to disable trx_post\n"); + goto out; + } + + ret = rtw89_wow_disable_trx_post(rtwdev); + if (ret) { + rtw89_err(rtwdev, "wow: failed to disable trx_pre\n"); + goto out; + } + +out: + clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags); + return ret; +} + +int rtw89_wow_resume(struct rtw89_dev *rtwdev) +{ + int ret; + + if (!test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) { + rtw89_err(rtwdev, "wow is not enabled\n"); + ret = -EPERM; + goto out; + } + + if (!rtw89_mac_get_power_state(rtwdev)) { + rtw89_err(rtwdev, "chip is no power when resume\n"); + ret = -EPERM; + goto out; + } + + rtw89_wow_leave_deep_ps(rtwdev); + + rtw89_wow_show_wakeup_reason(rtwdev); + + ret = rtw89_wow_disable(rtwdev); + if (ret) + rtw89_err(rtwdev, "failed to disable wow\n"); + +out: + rtw89_wow_clear_wakeups(rtwdev); + return ret; +} + +int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan) +{ + int ret; + + ret = rtw89_wow_set_wakeups(rtwdev, wowlan); + if (ret) { + rtw89_err(rtwdev, "failed to set wakeup event\n"); + return ret; + } + + rtw89_wow_leave_lps(rtwdev); + + ret = rtw89_wow_enable(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to enable wow\n"); + return ret; + } + + rtw89_wow_enter_deep_ps(rtwdev); + + return 0; +} diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h new file mode 100644 index 000000000000..a2f7b2e3cdb4 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2019-2022 Realtek Corporation + */ + +#ifndef __RTW89_WOW_H__ +#define __RTW89_WOW_H__ + +enum rtw89_wake_reason { + RTW89_WOW_RSN_RX_PTK_REKEY = 0x1, + RTW89_WOW_RSN_RX_GTK_REKEY = 0x2, + RTW89_WOW_RSN_RX_DEAUTH = 0x8, + RTW89_WOW_RSN_DISCONNECT = 0x10, + RTW89_WOW_RSN_RX_MAGIC_PKT = 0x21, + RTW89_WOW_RSN_RX_PATTERN_MATCH = 0x23, + RTW89_WOW_RSN_RX_NLO = 0x55, +}; + +int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan); +int rtw89_wow_resume(struct rtw89_dev *rtwdev); + +#endif |