Skip to content

Commit

Permalink
rtw88: add deep PS PG mode for 8822c
Browse files Browse the repository at this point in the history
Compare with LCLK mode, PG mode saves more power, by turning
off more circuits. Therefore, to recover from PG mode, driver
needs to backup some information into rsvd page. Such as CAM
entries, DPK results.

As CAM entries can change, it is required to re-download CAM
entries after set_key.

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  • Loading branch information
Yan-Hsuan Chuang authored and Kalle Valo committed Oct 2, 2019
1 parent d3be4d1 commit 04b786e
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 3 deletions.
77 changes: 77 additions & 0 deletions drivers/net/wireless/realtek/rtw88/fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "fw.h"
#include "tx.h"
#include "reg.h"
#include "sec.h"
#include "debug.h"

static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev,
Expand Down Expand Up @@ -397,6 +398,24 @@ static u8 rtw_get_rsvd_page_location(struct rtw_dev *rtwdev,
return location;
}

void rtw_fw_set_pg_info(struct rtw_dev *rtwdev)
{
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
u8 h2c_pkt[H2C_PKT_SIZE] = {0};
u8 loc_pg, loc_dpk;

loc_pg = rtw_get_rsvd_page_location(rtwdev, RSVD_LPS_PG_INFO);
loc_dpk = rtw_get_rsvd_page_location(rtwdev, RSVD_LPS_PG_DPK);

SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_LPS_PG_INFO);

LPS_PG_INFO_LOC(h2c_pkt, loc_pg);
LPS_PG_DPK_LOC(h2c_pkt, loc_dpk);
LPS_PG_SEC_CAM_EN(h2c_pkt, conf->sec_cam_backup);

rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
}

void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev)
{
u8 h2c_pkt[H2C_PKT_SIZE] = {0};
Expand Down Expand Up @@ -442,6 +461,58 @@ rtw_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
return skb_new;
}

static struct sk_buff *rtw_lps_pg_dpk_get(struct ieee80211_hw *hw)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info;
struct rtw_lps_pg_dpk_hdr *dpk_hdr;
struct sk_buff *skb;
u32 size;

size = chip->tx_pkt_desc_sz + sizeof(*dpk_hdr);
skb = alloc_skb(size, GFP_KERNEL);
if (!skb)
return NULL;

skb_reserve(skb, chip->tx_pkt_desc_sz);
dpk_hdr = skb_put_zero(skb, sizeof(*dpk_hdr));
dpk_hdr->dpk_ch = dpk_info->dpk_ch;
dpk_hdr->dpk_path_ok = dpk_info->dpk_path_ok[0];
memcpy(dpk_hdr->dpk_txagc, dpk_info->dpk_txagc, 2);
memcpy(dpk_hdr->dpk_gs, dpk_info->dpk_gs, 4);
memcpy(dpk_hdr->coef, dpk_info->coef, 160);

return skb;
}

static struct sk_buff *rtw_lps_pg_info_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
struct rtw_lps_pg_info_hdr *pg_info_hdr;
struct sk_buff *skb;
u32 size;

size = chip->tx_pkt_desc_sz + sizeof(*pg_info_hdr);
skb = alloc_skb(size, GFP_KERNEL);
if (!skb)
return NULL;

skb_reserve(skb, chip->tx_pkt_desc_sz);
pg_info_hdr = skb_put_zero(skb, sizeof(*pg_info_hdr));
pg_info_hdr->tx_bu_page_count = rtwdev->fifo.rsvd_drv_pg_num;
pg_info_hdr->macid = find_first_bit(rtwdev->mac_id_map, RTW_MAX_MAC_ID_NUM);
pg_info_hdr->sec_cam_count =
rtw_sec_cam_pg_backup(rtwdev, pg_info_hdr->sec_cam);

conf->sec_cam_backup = pg_info_hdr->sec_cam_count != 0;

return skb;
}

static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum rtw_rsvd_packet_type type)
Expand All @@ -464,6 +535,12 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw,
case RSVD_QOS_NULL:
skb_new = ieee80211_nullfunc_get(hw, vif, true);
break;
case RSVD_LPS_PG_DPK:
skb_new = rtw_lps_pg_dpk_get(hw);
break;
case RSVD_LPS_PG_INFO:
skb_new = rtw_lps_pg_info_get(hw, vif);
break;
default:
return NULL;
}
Expand Down
29 changes: 29 additions & 0 deletions drivers/net/wireless/realtek/rtw88/fw.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ enum rtw_rsvd_packet_type {
RSVD_PROBE_RESP,
RSVD_NULL,
RSVD_QOS_NULL,
RSVD_LPS_PG_DPK,
RSVD_LPS_PG_INFO,
};

enum rtw_fw_rf_type {
Expand Down Expand Up @@ -86,6 +88,25 @@ struct rtw_iqk_para {
u8 segment_iqk;
};

struct rtw_lps_pg_dpk_hdr {
u16 dpk_path_ok;
u8 dpk_txagc[2];
u16 dpk_gs[2];
u32 coef[2][20];
u8 dpk_ch;
} __packed;

struct rtw_lps_pg_info_hdr {
u8 macid;
u8 mbssid;
u8 pattern_count;
u8 mu_tab_group_id;
u8 sec_cam_count;
u8 tx_bu_page_count;
u16 rsvd;
u8 sec_cam[MAX_PG_CAM_BACKUP_NUM];
} __packed;

struct rtw_rsvd_page {
struct list_head list;
struct sk_buff *skb;
Expand Down Expand Up @@ -146,6 +167,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define H2C_CMD_RSVD_PAGE 0x0
#define H2C_CMD_MEDIA_STATUS_RPT 0x01
#define H2C_CMD_SET_PWR_MODE 0x20
#define H2C_CMD_LPS_PG_INFO 0x2b
#define H2C_CMD_RA_INFO 0x40
#define H2C_CMD_RSSI_MONITOR 0x42

Expand Down Expand Up @@ -177,6 +199,12 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 5))
#define SET_PWR_MODE_SET_PWR_STATE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
#define LPS_PG_INFO_LOC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define LPS_PG_DPK_LOC(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
#define LPS_PG_SEC_CAM_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_RSSI_INFO_MACID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_RSSI_INFO_RSSI(h2c_pkt, value) \
Expand Down Expand Up @@ -270,6 +298,7 @@ void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev);

void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para);
void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev);
void rtw_fw_set_pg_info(struct rtw_dev *rtwdev);
void rtw_fw_query_bt_info(struct rtw_dev *rtwdev);
void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw);
void rtw_fw_query_bt_mp_info(struct rtw_dev *rtwdev,
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/wireless/realtek/rtw88/mac80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
rtw_add_rsvd_page(rtwdev, RSVD_PS_POLL, true);
rtw_add_rsvd_page(rtwdev, RSVD_QOS_NULL, true);
rtw_add_rsvd_page(rtwdev, RSVD_NULL, true);
rtw_add_rsvd_page(rtwdev, RSVD_LPS_PG_DPK, true);
rtw_add_rsvd_page(rtwdev, RSVD_LPS_PG_INFO, true);
rtw_fw_download_rsvd_page(rtwdev, vif);
rtw_send_rsvd_page_h2c(rtwdev);
rtw_coex_media_status_notify(rtwdev, conf->assoc);
Expand Down Expand Up @@ -435,6 +437,10 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
break;
}

/* download new cam settings for PG to backup */
if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
rtw_fw_download_rsvd_page(rtwdev, vif);

out:
mutex_unlock(&rtwdev->mutex);

Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/realtek/rtw88/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#define RTW_MAX_MAC_ID_NUM 32
#define RTW_MAX_SEC_CAM_NUM 32
#define MAX_PG_CAM_BACKUP_NUM 8

#define RTW_WATCH_DOG_DELAY_TIME round_jiffies_relative(HZ * 2)

Expand Down Expand Up @@ -532,6 +533,7 @@ enum rtw_lps_mode {
enum rtw_lps_deep_mode {
LPS_DEEP_MODE_NONE = 0,
LPS_DEEP_MODE_LCLK = 1,
LPS_DEEP_MODE_PG = 2,
};

enum rtw_pwr_state {
Expand All @@ -548,6 +550,7 @@ struct rtw_lps_conf {
u8 rlbm;
u8 smart_ps;
u8 port_id;
bool sec_cam_backup;
};

enum rtw_hw_key_type {
Expand Down
10 changes: 8 additions & 2 deletions drivers/net/wireless/realtek/rtw88/ps.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,13 @@ void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)

/* toggle to request power mode, others remain 0 */
request ^= request | BIT_RPWM_TOGGLE;
if (!enter)
if (!enter) {
request |= POWER_MODE_ACK;
else
} else {
request |= POWER_MODE_LCLK;
if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
request |= POWER_MODE_PG;
}

rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);

Expand Down Expand Up @@ -141,6 +144,9 @@ static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
return;
}

if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
rtw_fw_set_pg_info(rtwdev);

rtw_hci_deep_ps(rtwdev, true);
}

Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/realtek/rtw88/ps.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define RTW_LPS_THRESHOLD 2

#define POWER_MODE_ACK BIT(6)
#define POWER_MODE_PG BIT(4)
#define POWER_MODE_LCLK BIT(0)

int rtw_enter_ips(struct rtw_dev *rtwdev);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/realtek/rtw88/rtw8822c.c
Original file line number Diff line number Diff line change
Expand Up @@ -3747,7 +3747,7 @@ struct rtw_chip_info rtw8822c_hw_spec = {
.dig_min = 0x20,
.ht_supported = true,
.vht_supported = true,
.lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK),
.lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK) | BIT(LPS_DEEP_MODE_PG),
.sys_func_en = 0xD8,
.pwr_on_seq = card_enable_flow_8822c,
.pwr_off_seq = card_disable_flow_8822c,
Expand Down
21 changes: 21 additions & 0 deletions drivers/net/wireless/realtek/rtw88/sec.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,27 @@ void rtw_sec_clear_cam(struct rtw_dev *rtwdev,
rtw_write32(rtwdev, RTW_SEC_CMD_REG, command);
}

u8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam)
{
struct rtw_sec_desc *sec = &rtwdev->sec;
u8 offset = 0;
u8 count, n;

if (!used_cam)
return 0;

for (count = 0; count < MAX_PG_CAM_BACKUP_NUM; count++) {
n = find_next_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM, offset);
if (n == RTW_MAX_SEC_CAM_NUM)
break;

used_cam[count] = n;
offset = n + 1;
}

return count;
}

void rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev)
{
struct rtw_sec_desc *sec = &rtwdev->sec;
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/realtek/rtw88/sec.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ void rtw_sec_write_cam(struct rtw_dev *rtwdev,
void rtw_sec_clear_cam(struct rtw_dev *rtwdev,
struct rtw_sec_desc *sec,
u8 hw_key_idx);
u8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam);
void rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev);

#endif

0 comments on commit 04b786e

Please sign in to comment.