|
@@ -34,6 +34,7 @@
|
|
|
|
|
|
#define ATH10K_WMI_BARRIER_ECHO_ID 0xBA991E9
|
|
|
#define ATH10K_WMI_BARRIER_TIMEOUT_HZ (3 * HZ)
|
|
|
+#define ATH10K_WMI_DFS_CONF_TIMEOUT_HZ (HZ / 6)
|
|
|
|
|
|
/* MAIN WMI cmd track */
|
|
|
static struct wmi_cmd_map wmi_cmd_map = {
|
|
@@ -199,6 +200,7 @@ static struct wmi_cmd_map wmi_cmd_map = {
|
|
|
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
+ .radar_found_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
};
|
|
|
|
|
|
/* 10.X WMI cmd track */
|
|
@@ -367,6 +369,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
|
|
|
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
+ .radar_found_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
};
|
|
|
|
|
|
/* 10.2.4 WMI cmd track */
|
|
@@ -535,6 +538,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
|
|
|
.pdev_bss_chan_info_request_cmdid =
|
|
|
WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
|
|
|
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
+ .radar_found_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
};
|
|
|
|
|
|
/* 10.4 WMI cmd track */
|
|
@@ -745,6 +749,7 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = {
|
|
|
.tdls_set_state_cmdid = WMI_10_4_TDLS_SET_STATE_CMDID,
|
|
|
.tdls_peer_update_cmdid = WMI_10_4_TDLS_PEER_UPDATE_CMDID,
|
|
|
.tdls_set_offchan_mode_cmdid = WMI_10_4_TDLS_SET_OFFCHAN_MODE_CMDID,
|
|
|
+ .radar_found_cmdid = WMI_10_4_RADAR_FOUND_CMDID,
|
|
|
};
|
|
|
|
|
|
/* MAIN WMI VDEV param map */
|
|
@@ -1490,6 +1495,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
|
|
|
.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,
|
|
|
+ .radar_found_cmdid = WMI_CMD_UNSUPPORTED,
|
|
|
};
|
|
|
|
|
|
static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = {
|
|
@@ -3683,6 +3689,68 @@ void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb)
|
|
|
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
|
|
|
}
|
|
|
|
|
|
+static void ath10k_radar_detected(struct ath10k *ar)
|
|
|
+{
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
|
|
|
+ ATH10K_DFS_STAT_INC(ar, radar_detected);
|
|
|
+
|
|
|
+ /* Control radar events reporting in debugfs file
|
|
|
+ * dfs_block_radar_events
|
|
|
+ */
|
|
|
+ if (ar->dfs_block_radar_events)
|
|
|
+ ath10k_info(ar, "DFS Radar detected, but ignored as requested\n");
|
|
|
+ else
|
|
|
+ ieee80211_radar_detected(ar->hw);
|
|
|
+}
|
|
|
+
|
|
|
+static void ath10k_radar_confirmation_work(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct ath10k *ar = container_of(work, struct ath10k,
|
|
|
+ radar_confirmation_work);
|
|
|
+ struct ath10k_radar_found_info radar_info;
|
|
|
+ int ret, time_left;
|
|
|
+
|
|
|
+ reinit_completion(&ar->wmi.radar_confirm);
|
|
|
+
|
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
|
+ memcpy(&radar_info, &ar->last_radar_info, sizeof(radar_info));
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+
|
|
|
+ ret = ath10k_wmi_report_radar_found(ar, &radar_info);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn(ar, "failed to send radar found %d\n", ret);
|
|
|
+ goto wait_complete;
|
|
|
+ }
|
|
|
+
|
|
|
+ time_left = wait_for_completion_timeout(&ar->wmi.radar_confirm,
|
|
|
+ ATH10K_WMI_DFS_CONF_TIMEOUT_HZ);
|
|
|
+ if (time_left) {
|
|
|
+ /* DFS Confirmation status event received and
|
|
|
+ * necessary action completed.
|
|
|
+ */
|
|
|
+ goto wait_complete;
|
|
|
+ } else {
|
|
|
+ /* DFS Confirmation event not received from FW.Considering this
|
|
|
+ * as real radar.
|
|
|
+ */
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
|
|
|
+ "dfs confirmation not received from fw, considering as radar\n");
|
|
|
+ goto radar_detected;
|
|
|
+ }
|
|
|
+
|
|
|
+radar_detected:
|
|
|
+ ath10k_radar_detected(ar);
|
|
|
+
|
|
|
+ /* Reset state to allow sending confirmation on consecutive radar
|
|
|
+ * detections, unless radar confirmation is disabled/stopped.
|
|
|
+ */
|
|
|
+wait_complete:
|
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
|
+ if (ar->radar_conf_state != ATH10K_RADAR_CONFIRMATION_STOPPED)
|
|
|
+ ar->radar_conf_state = ATH10K_RADAR_CONFIRMATION_IDLE;
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+}
|
|
|
+
|
|
|
static void ath10k_dfs_radar_report(struct ath10k *ar,
|
|
|
struct wmi_phyerr_ev_arg *phyerr,
|
|
|
const struct phyerr_radar_report *rr,
|
|
@@ -3691,8 +3759,10 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
|
|
|
u32 reg0, reg1, tsf32l;
|
|
|
struct ieee80211_channel *ch;
|
|
|
struct pulse_event pe;
|
|
|
+ struct radar_detector_specs rs;
|
|
|
u64 tsf64;
|
|
|
u8 rssi, width;
|
|
|
+ struct ath10k_radar_found_info *radar_info;
|
|
|
|
|
|
reg0 = __le32_to_cpu(rr->reg0);
|
|
|
reg1 = __le32_to_cpu(rr->reg1);
|
|
@@ -3757,25 +3827,46 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
|
|
|
|
|
|
ATH10K_DFS_STAT_INC(ar, pulses_detected);
|
|
|
|
|
|
- if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe, NULL)) {
|
|
|
+ if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe, &rs)) {
|
|
|
ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
|
|
|
"dfs no pulse pattern detected, yet\n");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
-radar_detected:
|
|
|
- ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
|
|
|
- ATH10K_DFS_STAT_INC(ar, radar_detected);
|
|
|
+ if ((test_bit(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, ar->wmi.svc_map)) &&
|
|
|
+ ar->dfs_detector->region == NL80211_DFS_FCC) {
|
|
|
+ /* Consecutive radar indications need not be
|
|
|
+ * sent to the firmware until we get confirmation
|
|
|
+ * for the previous detected radar.
|
|
|
+ */
|
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
|
+ if (ar->radar_conf_state != ATH10K_RADAR_CONFIRMATION_IDLE) {
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ar->radar_conf_state = ATH10K_RADAR_CONFIRMATION_INPROGRESS;
|
|
|
+ radar_info = &ar->last_radar_info;
|
|
|
|
|
|
- /* Control radar events reporting in debugfs file
|
|
|
- * dfs_block_radar_events
|
|
|
- */
|
|
|
- if (ar->dfs_block_radar_events) {
|
|
|
- ath10k_info(ar, "DFS Radar detected, but ignored as requested\n");
|
|
|
+ radar_info->pri_min = rs.pri_min;
|
|
|
+ radar_info->pri_max = rs.pri_max;
|
|
|
+ radar_info->width_min = rs.width_min;
|
|
|
+ radar_info->width_max = rs.width_max;
|
|
|
+ /*TODO Find sidx_min and sidx_max */
|
|
|
+ radar_info->sidx_min = MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX);
|
|
|
+ radar_info->sidx_max = MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX);
|
|
|
+
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
|
|
|
+ "sending wmi radar found cmd pri_min %d pri_max %d width_min %d width_max %d sidx_min %d sidx_max %d\n",
|
|
|
+ radar_info->pri_min, radar_info->pri_max,
|
|
|
+ radar_info->width_min, radar_info->width_max,
|
|
|
+ radar_info->sidx_min, radar_info->sidx_max);
|
|
|
+ ieee80211_queue_work(ar->hw, &ar->radar_confirmation_work);
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- ieee80211_radar_detected(ar->hw);
|
|
|
+radar_detected:
|
|
|
+ ath10k_radar_detected(ar);
|
|
|
}
|
|
|
|
|
|
static int ath10k_dfs_fft_report(struct ath10k *ar,
|
|
@@ -4125,6 +4216,47 @@ void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+ath10k_wmi_10_4_op_pull_dfs_status_ev(struct ath10k *ar, struct sk_buff *skb,
|
|
|
+ struct wmi_dfs_status_ev_arg *arg)
|
|
|
+{
|
|
|
+ struct wmi_dfs_status_ev_arg *ev = (void *)skb->data;
|
|
|
+
|
|
|
+ if (skb->len < sizeof(*ev))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
+ arg->status = ev->status;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+ath10k_wmi_event_dfs_status_check(struct ath10k *ar, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct wmi_dfs_status_ev_arg status_arg = {};
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = ath10k_wmi_pull_dfs_status(ar, skb, &status_arg);
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn(ar, "failed to parse dfs status event: %d\n", ret);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
|
|
|
+ "dfs status event received from fw: %d\n",
|
|
|
+ status_arg.status);
|
|
|
+
|
|
|
+ /* Even in case of radar detection failure we follow the same
|
|
|
+ * behaviour as if radar is detected i.e to switch to a different
|
|
|
+ * channel.
|
|
|
+ */
|
|
|
+ if (status_arg.status == WMI_HW_RADAR_DETECTED ||
|
|
|
+ status_arg.status == WMI_RADAR_DETECTION_FAIL)
|
|
|
+ ath10k_radar_detected(ar);
|
|
|
+ complete(&ar->wmi.radar_confirm);
|
|
|
+}
|
|
|
+
|
|
|
void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
|
|
|
{
|
|
|
struct wmi_roam_ev_arg arg = {};
|
|
@@ -5876,6 +6008,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
|
|
case WMI_10_4_PDEV_TPC_TABLE_EVENTID:
|
|
|
ath10k_wmi_event_tpc_final_table(ar, skb);
|
|
|
break;
|
|
|
+ case WMI_10_4_DFS_STATUS_CHECK_EVENTID:
|
|
|
+ ath10k_wmi_event_dfs_status_check(ar, skb);
|
|
|
+ break;
|
|
|
default:
|
|
|
ath10k_warn(ar, "Unknown eventid: %d\n", id);
|
|
|
break;
|
|
@@ -8461,6 +8596,32 @@ ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar,
|
|
|
return skb;
|
|
|
}
|
|
|
|
|
|
+static struct sk_buff *
|
|
|
+ath10k_wmi_10_4_gen_radar_found(struct ath10k *ar,
|
|
|
+ const struct ath10k_radar_found_info *arg)
|
|
|
+{
|
|
|
+ struct wmi_radar_found_info *cmd;
|
|
|
+ struct sk_buff *skb;
|
|
|
+
|
|
|
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
|
|
|
+ if (!skb)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+
|
|
|
+ cmd = (struct wmi_radar_found_info *)skb->data;
|
|
|
+ cmd->pri_min = __cpu_to_le32(arg->pri_min);
|
|
|
+ cmd->pri_max = __cpu_to_le32(arg->pri_max);
|
|
|
+ cmd->width_min = __cpu_to_le32(arg->width_min);
|
|
|
+ cmd->width_max = __cpu_to_le32(arg->width_max);
|
|
|
+ cmd->sidx_min = __cpu_to_le32(arg->sidx_min);
|
|
|
+ cmd->sidx_max = __cpu_to_le32(arg->sidx_max);
|
|
|
+
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
|
|
|
+ "wmi radar found pri_min %d pri_max %d width_min %d width_max %d sidx_min %d sidx_max %d\n",
|
|
|
+ arg->pri_min, arg->pri_max, arg->width_min,
|
|
|
+ arg->width_max, arg->sidx_min, arg->sidx_max);
|
|
|
+ return skb;
|
|
|
+}
|
|
|
+
|
|
|
static struct sk_buff *
|
|
|
ath10k_wmi_op_gen_echo(struct ath10k *ar, u32 value)
|
|
|
{
|
|
@@ -8798,6 +8959,7 @@ static const struct wmi_ops wmi_10_4_ops = {
|
|
|
.pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,
|
|
|
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
|
|
|
.pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
|
|
|
+ .pull_dfs_status_ev = ath10k_wmi_10_4_op_pull_dfs_status_ev,
|
|
|
.get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme,
|
|
|
|
|
|
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
|
|
@@ -8844,6 +9006,7 @@ static const struct wmi_ops wmi_10_4_ops = {
|
|
|
.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,
|
|
|
+ .gen_radar_found = ath10k_wmi_10_4_gen_radar_found,
|
|
|
|
|
|
/* shared with 10.2 */
|
|
|
.pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
|
|
@@ -8906,8 +9069,11 @@ int ath10k_wmi_attach(struct ath10k *ar)
|
|
|
init_completion(&ar->wmi.service_ready);
|
|
|
init_completion(&ar->wmi.unified_ready);
|
|
|
init_completion(&ar->wmi.barrier);
|
|
|
+ init_completion(&ar->wmi.radar_confirm);
|
|
|
|
|
|
INIT_WORK(&ar->svc_rdy_work, ath10k_wmi_event_service_ready_work);
|
|
|
+ INIT_WORK(&ar->radar_confirmation_work,
|
|
|
+ ath10k_radar_confirmation_work);
|
|
|
|
|
|
return 0;
|
|
|
}
|