|
@@ -1,6 +1,7 @@
|
|
|
/*
|
|
|
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
|
|
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
|
|
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
|
|
*
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
@@ -196,6 +197,7 @@ static struct wmi_cmd_map wmi_cmd_map = {
|
|
|
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
+ .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
};
|
|
|
|
|
|
/* 10.X WMI cmd track */
|
|
@@ -362,6 +364,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
|
|
|
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
+ .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
};
|
|
|
|
|
|
/* 10.2.4 WMI cmd track */
|
|
@@ -528,6 +531,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
|
|
|
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.pdev_bss_chan_info_request_cmdid =
|
|
|
WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
|
|
|
+ .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
};
|
|
|
|
|
|
/* 10.4 WMI cmd track */
|
|
@@ -1480,6 +1484,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
|
|
|
.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
+ .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
};
|
|
|
|
|
|
static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = {
|
|
@@ -4313,19 +4318,11 @@ static void ath10k_tpc_config_disp_tables(struct ath10k *ar,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|
|
+void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table,
|
|
|
+ u32 num_tx_chain)
|
|
|
{
|
|
|
- u32 i, j, pream_idx, num_tx_chain;
|
|
|
- u8 rate_code[WMI_TPC_RATE_MAX], rate_idx;
|
|
|
- u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
|
|
|
- struct wmi_pdev_tpc_config_event *ev;
|
|
|
- struct ath10k_tpc_stats *tpc_stats;
|
|
|
-
|
|
|
- ev = (struct wmi_pdev_tpc_config_event *)skb->data;
|
|
|
-
|
|
|
- tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
|
|
|
- if (!tpc_stats)
|
|
|
- return;
|
|
|
+ u32 i, j, pream_idx;
|
|
|
+ u8 rate_idx;
|
|
|
|
|
|
/* Create the rate code table based on the chains supported */
|
|
|
rate_idx = 0;
|
|
@@ -4349,8 +4346,6 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|
|
pream_table[pream_idx] = rate_idx;
|
|
|
pream_idx++;
|
|
|
|
|
|
- num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
|
|
-
|
|
|
/* Fill HT20 rate code */
|
|
|
for (i = 0; i < num_tx_chain; i++) {
|
|
|
for (j = 0; j < 8; j++) {
|
|
@@ -4374,7 +4369,7 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|
|
pream_idx++;
|
|
|
|
|
|
/* Fill VHT20 rate code */
|
|
|
- for (i = 0; i < __le32_to_cpu(ev->num_tx_chain); i++) {
|
|
|
+ for (i = 0; i < num_tx_chain; i++) {
|
|
|
for (j = 0; j < 10; j++) {
|
|
|
rate_code[rate_idx] =
|
|
|
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT);
|
|
@@ -4418,6 +4413,26 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|
|
ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM);
|
|
|
|
|
|
pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END;
|
|
|
+}
|
|
|
+
|
|
|
+void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ u32 num_tx_chain;
|
|
|
+ u8 rate_code[WMI_TPC_RATE_MAX];
|
|
|
+ u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
|
|
|
+ struct wmi_pdev_tpc_config_event *ev;
|
|
|
+ struct ath10k_tpc_stats *tpc_stats;
|
|
|
+
|
|
|
+ ev = (struct wmi_pdev_tpc_config_event *)skb->data;
|
|
|
+
|
|
|
+ tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
|
|
|
+ if (!tpc_stats)
|
|
|
+ return;
|
|
|
+
|
|
|
+ num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
|
|
+
|
|
|
+ ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
|
|
|
+ num_tx_chain);
|
|
|
|
|
|
tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
|
|
|
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
|
|
@@ -4457,6 +4472,246 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|
|
__le32_to_cpu(ev->rate_max));
|
|
|
}
|
|
|
|
|
|
+static u8
|
|
|
+ath10k_wmi_tpc_final_get_rate(struct ath10k *ar,
|
|
|
+ struct wmi_pdev_tpc_final_table_event *ev,
|
|
|
+ u32 rate_idx, u32 num_chains,
|
|
|
+ u32 rate_code, u8 type, u32 pream_idx)
|
|
|
+{
|
|
|
+ u8 tpc, num_streams, preamble, ch, stm_idx;
|
|
|
+ s8 pow_agcdd, pow_agstbc, pow_agtxbf;
|
|
|
+ int pream;
|
|
|
+
|
|
|
+ num_streams = ATH10K_HW_NSS(rate_code);
|
|
|
+ preamble = ATH10K_HW_PREAMBLE(rate_code);
|
|
|
+ ch = num_chains - 1;
|
|
|
+ stm_idx = num_streams - 1;
|
|
|
+ pream = -1;
|
|
|
+
|
|
|
+ if (__le32_to_cpu(ev->chan_freq) <= 2483) {
|
|
|
+ switch (pream_idx) {
|
|
|
+ case WMI_TPC_PREAM_2GHZ_CCK:
|
|
|
+ pream = 0;
|
|
|
+ break;
|
|
|
+ case WMI_TPC_PREAM_2GHZ_OFDM:
|
|
|
+ pream = 1;
|
|
|
+ break;
|
|
|
+ case WMI_TPC_PREAM_2GHZ_HT20:
|
|
|
+ case WMI_TPC_PREAM_2GHZ_VHT20:
|
|
|
+ pream = 2;
|
|
|
+ break;
|
|
|
+ case WMI_TPC_PREAM_2GHZ_HT40:
|
|
|
+ case WMI_TPC_PREAM_2GHZ_VHT40:
|
|
|
+ pream = 3;
|
|
|
+ break;
|
|
|
+ case WMI_TPC_PREAM_2GHZ_VHT80:
|
|
|
+ pream = 4;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ pream = -1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (__le32_to_cpu(ev->chan_freq) >= 5180) {
|
|
|
+ switch (pream_idx) {
|
|
|
+ case WMI_TPC_PREAM_5GHZ_OFDM:
|
|
|
+ pream = 0;
|
|
|
+ break;
|
|
|
+ case WMI_TPC_PREAM_5GHZ_HT20:
|
|
|
+ case WMI_TPC_PREAM_5GHZ_VHT20:
|
|
|
+ pream = 1;
|
|
|
+ break;
|
|
|
+ case WMI_TPC_PREAM_5GHZ_HT40:
|
|
|
+ case WMI_TPC_PREAM_5GHZ_VHT40:
|
|
|
+ pream = 2;
|
|
|
+ break;
|
|
|
+ case WMI_TPC_PREAM_5GHZ_VHT80:
|
|
|
+ pream = 3;
|
|
|
+ break;
|
|
|
+ case WMI_TPC_PREAM_5GHZ_HTCUP:
|
|
|
+ pream = 4;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ pream = -1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pream == 4)
|
|
|
+ tpc = min_t(u8, ev->rates_array[rate_idx],
|
|
|
+ ev->max_reg_allow_pow[ch]);
|
|
|
+ else
|
|
|
+ tpc = min_t(u8, min_t(u8, ev->rates_array[rate_idx],
|
|
|
+ ev->max_reg_allow_pow[ch]),
|
|
|
+ ev->ctl_power_table[0][pream][stm_idx]);
|
|
|
+
|
|
|
+ if (__le32_to_cpu(ev->num_tx_chain) <= 1)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (preamble == WMI_RATE_PREAMBLE_CCK)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (num_chains <= num_streams)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case WMI_TPC_TABLE_TYPE_STBC:
|
|
|
+ pow_agstbc = ev->max_reg_allow_pow_agstbc[ch - 1][stm_idx];
|
|
|
+ if (pream == 4)
|
|
|
+ tpc = min_t(u8, tpc, pow_agstbc);
|
|
|
+ else
|
|
|
+ tpc = min_t(u8, min_t(u8, tpc, pow_agstbc),
|
|
|
+ ev->ctl_power_table[0][pream][stm_idx]);
|
|
|
+ break;
|
|
|
+ case WMI_TPC_TABLE_TYPE_TXBF:
|
|
|
+ pow_agtxbf = ev->max_reg_allow_pow_agtxbf[ch - 1][stm_idx];
|
|
|
+ if (pream == 4)
|
|
|
+ tpc = min_t(u8, tpc, pow_agtxbf);
|
|
|
+ else
|
|
|
+ tpc = min_t(u8, min_t(u8, tpc, pow_agtxbf),
|
|
|
+ ev->ctl_power_table[1][pream][stm_idx]);
|
|
|
+ break;
|
|
|
+ case WMI_TPC_TABLE_TYPE_CDD:
|
|
|
+ pow_agcdd = ev->max_reg_allow_pow_agcdd[ch - 1][stm_idx];
|
|
|
+ if (pream == 4)
|
|
|
+ tpc = min_t(u8, tpc, pow_agcdd);
|
|
|
+ else
|
|
|
+ tpc = min_t(u8, min_t(u8, tpc, pow_agcdd),
|
|
|
+ ev->ctl_power_table[0][pream][stm_idx]);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ath10k_warn(ar, "unknown wmi tpc final table type: %d\n", type);
|
|
|
+ tpc = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ return tpc;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar,
|
|
|
+ struct wmi_pdev_tpc_final_table_event *ev,
|
|
|
+ struct ath10k_tpc_stats_final *tpc_stats,
|
|
|
+ u8 *rate_code, u16 *pream_table, u8 type)
|
|
|
+{
|
|
|
+ u32 i, j, pream_idx, flags;
|
|
|
+ u8 tpc[WMI_TPC_TX_N_CHAIN];
|
|
|
+ char tpc_value[WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
|
|
|
+ char buff[WMI_TPC_BUF_SIZE];
|
|
|
+
|
|
|
+ flags = __le32_to_cpu(ev->flags);
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case WMI_TPC_TABLE_TYPE_CDD:
|
|
|
+ if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD)) {
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "CDD not supported\n");
|
|
|
+ tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case WMI_TPC_TABLE_TYPE_STBC:
|
|
|
+ if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC)) {
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "STBC not supported\n");
|
|
|
+ tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case WMI_TPC_TABLE_TYPE_TXBF:
|
|
|
+ if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF)) {
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "TXBF not supported\n");
|
|
|
+ tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
|
|
|
+ "invalid table type in wmi tpc event: %d\n", type);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ pream_idx = 0;
|
|
|
+ for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
|
|
|
+ memset(tpc_value, 0, sizeof(tpc_value));
|
|
|
+ memset(buff, 0, sizeof(buff));
|
|
|
+ if (i == pream_table[pream_idx])
|
|
|
+ pream_idx++;
|
|
|
+
|
|
|
+ for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
|
|
|
+ if (j >= __le32_to_cpu(ev->num_tx_chain))
|
|
|
+ break;
|
|
|
+
|
|
|
+ tpc[j] = ath10k_wmi_tpc_final_get_rate(ar, ev, i, j + 1,
|
|
|
+ rate_code[i],
|
|
|
+ type, pream_idx);
|
|
|
+ snprintf(buff, sizeof(buff), "%8d ", tpc[j]);
|
|
|
+ strncat(tpc_value, buff, strlen(buff));
|
|
|
+ }
|
|
|
+ tpc_stats->tpc_table_final[type].pream_idx[i] = pream_idx;
|
|
|
+ tpc_stats->tpc_table_final[type].rate_code[i] = rate_code[i];
|
|
|
+ memcpy(tpc_stats->tpc_table_final[type].tpc_value[i],
|
|
|
+ tpc_value, sizeof(tpc_value));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ u32 num_tx_chain;
|
|
|
+ u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
|
|
|
+ u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
|
|
|
+ struct wmi_pdev_tpc_final_table_event *ev;
|
|
|
+ struct ath10k_tpc_stats_final *tpc_stats;
|
|
|
+
|
|
|
+ ev = (struct wmi_pdev_tpc_final_table_event *)skb->data;
|
|
|
+
|
|
|
+ tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
|
|
|
+ if (!tpc_stats)
|
|
|
+ return;
|
|
|
+
|
|
|
+ num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
|
|
+
|
|
|
+ ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
|
|
|
+ num_tx_chain);
|
|
|
+
|
|
|
+ tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
|
|
|
+ tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
|
|
|
+ tpc_stats->ctl = __le32_to_cpu(ev->ctl);
|
|
|
+ tpc_stats->reg_domain = __le32_to_cpu(ev->reg_domain);
|
|
|
+ tpc_stats->twice_antenna_gain = a_sle32_to_cpu(ev->twice_antenna_gain);
|
|
|
+ tpc_stats->twice_antenna_reduction =
|
|
|
+ __le32_to_cpu(ev->twice_antenna_reduction);
|
|
|
+ tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
|
|
|
+ tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
|
|
|
+ tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
|
|
+ tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
|
|
|
+
|
|
|
+ ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
|
|
|
+ rate_code, pream_table,
|
|
|
+ WMI_TPC_TABLE_TYPE_CDD);
|
|
|
+ ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
|
|
|
+ rate_code, pream_table,
|
|
|
+ WMI_TPC_TABLE_TYPE_STBC);
|
|
|
+ ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
|
|
|
+ rate_code, pream_table,
|
|
|
+ WMI_TPC_TABLE_TYPE_TXBF);
|
|
|
+
|
|
|
+ ath10k_debug_tpc_stats_final_process(ar, tpc_stats);
|
|
|
+
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
|
|
|
+ "wmi event tpc final table channel %d mode %d ctl %d regd %d gain %d %d limit %d max_power %d tx_chanins %d rates %d\n",
|
|
|
+ __le32_to_cpu(ev->chan_freq),
|
|
|
+ __le32_to_cpu(ev->phy_mode),
|
|
|
+ __le32_to_cpu(ev->ctl),
|
|
|
+ __le32_to_cpu(ev->reg_domain),
|
|
|
+ a_sle32_to_cpu(ev->twice_antenna_gain),
|
|
|
+ __le32_to_cpu(ev->twice_antenna_reduction),
|
|
|
+ __le32_to_cpu(ev->power_limit),
|
|
|
+ __le32_to_cpu(ev->twice_max_rd_power) / 2,
|
|
|
+ __le32_to_cpu(ev->num_tx_chain),
|
|
|
+ __le32_to_cpu(ev->rate_max));
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb)
|
|
|
{
|
|
@@ -5549,6 +5804,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
|
|
case WMI_10_4_TDLS_PEER_EVENTID:
|
|
|
ath10k_wmi_handle_tdls_peer_event(ar, skb);
|
|
|
break;
|
|
|
+ case WMI_10_4_PDEV_TPC_TABLE_EVENTID:
|
|
|
+ ath10k_wmi_event_tpc_final_table(ar, skb);
|
|
|
+ break;
|
|
|
default:
|
|
|
ath10k_warn(ar, "Unknown eventid: %d\n", id);
|
|
|
break;
|
|
@@ -7989,6 +8247,24 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
|
|
|
return peer_qos;
|
|
|
}
|
|
|
|
|
|
+static struct sk_buff *
|
|
|
+ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param)
|
|
|
+{
|
|
|
+ struct wmi_pdev_get_tpc_table_cmd *cmd;
|
|
|
+ struct sk_buff *skb;
|
|
|
+
|
|
|
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
|
|
|
+ if (!skb)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+
|
|
|
+ cmd = (struct wmi_pdev_get_tpc_table_cmd *)skb->data;
|
|
|
+ cmd->param = __cpu_to_le32(param);
|
|
|
+
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
|
|
|
+ "wmi pdev get tpc table param:%d\n", param);
|
|
|
+ return skb;
|
|
|
+}
|
|
|
+
|
|
|
static struct sk_buff *
|
|
|
ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar,
|
|
|
const struct wmi_tdls_peer_update_cmd_arg *arg,
|
|
@@ -8430,6 +8706,8 @@ static const struct wmi_ops wmi_10_4_ops = {
|
|
|
.ext_resource_config = ath10k_wmi_10_4_ext_resource_config,
|
|
|
.gen_update_fw_tdls_state = ath10k_wmi_10_4_gen_update_fw_tdls_state,
|
|
|
.gen_tdls_peer_update = ath10k_wmi_10_4_gen_tdls_peer_update,
|
|
|
+ .gen_pdev_get_tpc_table_cmdid =
|
|
|
+ ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid,
|
|
|
|
|
|
/* shared with 10.2 */
|
|
|
.pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
|