diff --git a/target_if/regulatory/src/target_if_reg.c b/target_if/regulatory/src/target_if_reg.c index af8b78336c..8f042f4dcb 100644 --- a/target_if/regulatory/src/target_if_reg.c +++ b/target_if/regulatory/src/target_if_reg.c @@ -221,6 +221,48 @@ static int tgt_reg_11d_new_cc_handler(ol_scn_t handle, return 0; } +static int tgt_reg_ch_avoid_event_handler(ol_scn_t handle, + uint8_t *event_buf, uint32_t len) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_lmac_if_reg_rx_ops *reg_rx_ops; + struct ch_avoid_ind_type ch_avoid_event; + QDF_STATUS status; + + TARGET_IF_ENTER(); + + psoc = target_if_get_psoc_from_scn_hdl(handle); + if (!psoc) { + target_if_err("psoc ptr is NULL"); + return -EINVAL; + } + + reg_rx_ops = target_if_regulatory_get_rx_ops(psoc); + + if (!reg_rx_ops->reg_ch_avoid_event_handler) { + target_if_err("reg_ch_avoid_event_handler is NULL"); + return -EINVAL; + } + + if (wmi_extract_reg_ch_avoid_event(GET_WMI_HDL_FROM_PSOC(psoc), + event_buf, &ch_avoid_event, len) != + QDF_STATUS_SUCCESS) { + + target_if_err("Extraction of CH avoid event failed"); + return -EFAULT; + } + + status = reg_rx_ops->reg_ch_avoid_event_handler(psoc, &ch_avoid_event); + if (status != QDF_STATUS_SUCCESS) { + target_if_err("Failed to process CH avoid event"); + return -EFAULT; + } + + target_if_debug("processed CH avoid event"); + + return 0; +} + static QDF_STATUS tgt_if_regulatory_register_master_list_handler( struct wlan_objmgr_psoc *psoc, void *arg) { @@ -284,6 +326,24 @@ static QDF_STATUS tgt_if_regulatory_unregister_11d_new_cc_handler( wmi_11d_new_country_event_id); } +static QDF_STATUS tgt_if_regulatory_register_ch_avoid_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + wmi_unified_t wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc); + + return wmi_unified_register_event(wmi_handle, + wmi_wlan_freq_avoid_event_id, + tgt_reg_ch_avoid_event_handler); +} + +static QDF_STATUS tgt_if_regulatory_unregister_ch_avoid_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + wmi_unified_t wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc); + + return wmi_unified_unregister_event(wmi_handle, + wmi_wlan_freq_avoid_event_id); +} static QDF_STATUS tgt_if_regulatory_start_11d_scan( struct wlan_objmgr_psoc *psoc, struct reg_start_11d_scan_req *reg_start_11d_scan_req) @@ -338,6 +398,12 @@ QDF_STATUS target_if_register_regulatory_tx_ops(struct wlan_lmac_if_tx_ops reg_ops->set_user_country_code = tgt_if_regulatory_set_user_country_code; + reg_ops->register_ch_avoid_event_handler = + tgt_if_regulatory_register_ch_avoid_event_handler; + + reg_ops->unregister_ch_avoid_event_handler = + tgt_if_regulatory_unregister_ch_avoid_event_handler; + return QDF_STATUS_SUCCESS; } diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h index 1eecdb103d..98c54ea0d2 100644 --- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h +++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h @@ -422,6 +422,10 @@ struct wlan_lmac_if_reg_tx_ops { uint8_t pdev_id, struct cc_regdmn_s *rd); QDF_STATUS (*set_country_failed)(struct wlan_objmgr_pdev *pdev); + QDF_STATUS (*register_ch_avoid_event_handler)( + struct wlan_objmgr_psoc *psoc, void *arg); + QDF_STATUS (*unregister_ch_avoid_event_handler)( + struct wlan_objmgr_psoc *psoc, void *arg); }; /** @@ -598,6 +602,8 @@ struct wlan_lmac_if_reg_rx_ops { bool val); QDF_STATUS (*get_dfs_region)(struct wlan_objmgr_pdev *pdev, enum dfs_reg *dfs_reg); + QDF_STATUS (*reg_ch_avoid_event_handler)(struct wlan_objmgr_psoc *psoc, + struct ch_avoid_ind_type *ch_avoid_ind); }; #ifdef CONVERGED_P2P_ENABLE diff --git a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c index 96d8b32472..0bdfa17b96 100644 --- a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c +++ b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c @@ -208,6 +208,9 @@ static void wlan_lmac_if_umac_reg_rx_ops_register( rx_ops->reg_rx_ops.get_dfs_region = wlan_reg_get_dfs_region; + + rx_ops->reg_rx_ops.reg_ch_avoid_event_handler = + tgt_reg_process_ch_avoid_event; } #ifdef CONVERGED_P2P_ENABLE diff --git a/umac/regulatory/core/src/reg_priv.h b/umac/regulatory/core/src/reg_priv.h index cb7ed06fbe..24e62c1f5d 100644 --- a/umac/regulatory/core/src/reg_priv.h +++ b/umac/regulatory/core/src/reg_priv.h @@ -69,6 +69,9 @@ struct wlan_regulatory_psoc_priv_obj { bool user_ctry_set; struct chan_change_cbk_entry cbk_list[REG_MAX_CHAN_CHANGE_CBKS]; uint8_t num_chan_change_cbks; + uint8_t ch_avoid_ind; + struct unsafe_ch_list unsafe_chan_list; + struct ch_avoid_ind_type avoid_freq_list; qdf_spinlock_t cbk_list_lock; }; @@ -92,6 +95,7 @@ struct wlan_regulatory_pdev_priv_obj { bool indoor_chan_enabled; bool en_chan_144; uint32_t wireless_modes; + struct ch_avoid_ind_type freq_avoid_list; }; #endif diff --git a/umac/regulatory/core/src/reg_services.c b/umac/regulatory/core/src/reg_services.c index 46dc61c0b3..1b510ca96c 100644 --- a/umac/regulatory/core/src/reg_services.c +++ b/umac/regulatory/core/src/reg_services.c @@ -1946,6 +1946,38 @@ reg_modify_chan_list_for_nol_list(struct regulatory_channel *chan_list) } } +static void +reg_modify_chan_list_for_unsafe_ch(struct wlan_regulatory_pdev_priv_obj + *pdev_priv_obj) +{ + enum channel_enum chan_enum; + struct regulatory_channel *chan_list; + struct wlan_objmgr_psoc *psoc; + struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; + struct unsafe_ch_list *unsafe_list; + uint8_t i; + + psoc = wlan_pdev_get_psoc(pdev_priv_obj->pdev_ptr); + psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *) + wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_REGULATORY); + if (!psoc_priv_obj) { + reg_err("psoc priv obj is NULL"); + return; + } + + chan_list = pdev_priv_obj->cur_chan_list; + unsafe_list = &psoc_priv_obj->unsafe_chan_list; + + for (i = 0; i < unsafe_list->ch_cnt; i++) { + chan_enum = reg_get_chan_enum(unsafe_list->ch_list[i]); + if (chan_enum == INVALID_CHANNEL) + continue; + chan_list[chan_enum].state = CHANNEL_STATE_DISABLE; + chan_list[chan_enum].chan_flags |= REGULATORY_CHAN_DISABLED; + } +} + static void reg_modify_chan_list_for_freq_range(struct regulatory_channel *chan_list, uint32_t low_freq_2g, @@ -2066,6 +2098,8 @@ static void reg_compute_pdev_current_chan_list(struct wlan_regulatory_pdev_priv_ reg_modify_chan_list_for_chan_144(pdev_priv_obj->cur_chan_list, pdev_priv_obj->en_chan_144); + + reg_modify_chan_list_for_unsafe_ch(pdev_priv_obj); } static void reg_call_chan_change_cbks(struct wlan_objmgr_psoc *psoc, @@ -2076,6 +2110,7 @@ static void reg_call_chan_change_cbks(struct wlan_objmgr_psoc *psoc, struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; struct regulatory_channel *cur_chan_list; uint32_t ctr; + struct avoid_freq_ind_data *avoid_freq_ind = NULL; reg_chan_change_callback callback; psoc_priv_obj = reg_get_psoc_obj(psoc); @@ -2101,6 +2136,22 @@ static void reg_call_chan_change_cbks(struct wlan_objmgr_psoc *psoc, NUM_CHANNELS * sizeof(struct regulatory_channel)); + if (psoc_priv_obj->ch_avoid_ind) { + avoid_freq_ind = qdf_mem_malloc(sizeof(*avoid_freq_ind)); + if (!avoid_freq_ind) { + reg_alert("Mem alloc failed for avoid freq ind"); + goto skip_ch_avoid_ind; + } + qdf_mem_copy(&avoid_freq_ind->freq_list, + &psoc_priv_obj->avoid_freq_list, + sizeof(struct ch_avoid_ind_type)); + qdf_mem_copy(&avoid_freq_ind->chan_list, + &psoc_priv_obj->unsafe_chan_list, + sizeof(struct unsafe_ch_list)); + psoc_priv_obj->ch_avoid_ind = false; + } + +skip_ch_avoid_ind: cbk_list = psoc_priv_obj->cbk_list; for (ctr = 0; ctr < REG_MAX_CHAN_CHANGE_CBKS; ctr++) { @@ -2110,10 +2161,12 @@ static void reg_call_chan_change_cbks(struct wlan_objmgr_psoc *psoc, callback = cbk_list[ctr].cbk; qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock); if (callback != NULL) - callback(psoc, pdev, cur_chan_list, - cbk_list[ctr].arg); + callback(psoc, pdev, cur_chan_list, avoid_freq_ind, + cbk_list[ctr].arg); } qdf_mem_free(cur_chan_list); + if (!avoid_freq_ind) + qdf_mem_free(avoid_freq_ind); } static struct reg_sched_payload @@ -3588,6 +3641,199 @@ QDF_STATUS reg_get_current_cc(struct wlan_objmgr_pdev *pdev, return QDF_STATUS_SUCCESS; } +static QDF_STATUS reg_process_ch_avoid_freq(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + enum channel_enum ch_loop; + enum channel_enum start_ch_idx; + enum channel_enum end_ch_idx; + uint16_t start_channel; + uint16_t end_channel; + uint32_t i; + struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; + + psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_REGULATORY); + + if (!psoc_priv_obj) { + reg_err("reg psoc private obj is NULL"); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < psoc_priv_obj->avoid_freq_list.ch_avoid_range_cnt; + i++) { + if (psoc_priv_obj->unsafe_chan_list.ch_cnt >= NUM_CHANNELS) { + reg_warn("LTE Coex unsafe channel list full"); + break; + } + + start_ch_idx = INVALID_CHANNEL; + end_ch_idx = INVALID_CHANNEL; + start_channel = reg_freq_to_chan(pdev, + psoc_priv_obj->avoid_freq_list.avoid_freq_range[i].start_freq); + end_channel = reg_freq_to_chan(pdev, + psoc_priv_obj->avoid_freq_list.avoid_freq_range[i].end_freq); + reg_debug("start: freq %d, ch %d, end: freq %d, ch %d", + psoc_priv_obj->avoid_freq_list.avoid_freq_range[i].start_freq, + start_channel, + psoc_priv_obj->avoid_freq_list.avoid_freq_range[i].end_freq, + end_channel); + + /* do not process frequency bands that are not mapped to + * predefined channels + */ + if (start_channel == 0 || end_channel == 0) + continue; + + for (ch_loop = 0; ch_loop < NUM_CHANNELS; + ch_loop++) { + if (REG_CH_TO_FREQ(ch_loop) >= psoc_priv_obj->avoid_freq_list. + avoid_freq_range[i].start_freq) { + start_ch_idx = ch_loop; + break; + } + } + for (ch_loop = 0; ch_loop < NUM_CHANNELS; + ch_loop++) { + if (REG_CH_TO_FREQ(ch_loop) >= psoc_priv_obj->avoid_freq_list. + avoid_freq_range[i].end_freq) { + end_ch_idx = ch_loop; + if (REG_CH_TO_FREQ(ch_loop) > psoc_priv_obj->avoid_freq_list. + avoid_freq_range[i].end_freq) + end_ch_idx--; + break; + } + } + + if (start_ch_idx == INVALID_CHANNEL || + end_ch_idx == INVALID_CHANNEL) + continue; + + for (ch_loop = start_ch_idx; ch_loop <= end_ch_idx; + ch_loop++) { + psoc_priv_obj->unsafe_chan_list.ch_list[ + psoc_priv_obj->unsafe_chan_list.ch_cnt++] = + REG_CH_NUM(ch_loop); + if (psoc_priv_obj->unsafe_chan_list.ch_cnt >= + NUM_CHANNELS) { + reg_warn("LTECoex unsafe ch list full"); + break; + } + } + } + + reg_debug("number of unsafe channels is %d ", + psoc_priv_obj->unsafe_chan_list.ch_cnt); + + if (!psoc_priv_obj->unsafe_chan_list.ch_cnt) { + reg_warn("No valid ch are present in avoid freq event"); + psoc_priv_obj->ch_avoid_ind = false; + return QDF_STATUS_SUCCESS; + } + + for (ch_loop = 0; ch_loop < psoc_priv_obj->unsafe_chan_list.ch_cnt; + ch_loop++) { + reg_debug("channel %d is not safe", + psoc_priv_obj->unsafe_chan_list. + ch_list[ch_loop]); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * reg_update_unsafe_ch () - Updates unsafe channels in current channel list + * @pdev: pointer to pdev object + * @ch_avoid_list: pointer to unsafe channel list + * + * Return: None + */ +static void reg_update_unsafe_ch(struct wlan_objmgr_psoc *psoc, + void *object, void *arg) +{ + struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)object; + struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; + struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; + QDF_STATUS status; + + psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_REGULATORY); + + if (!psoc_priv_obj) { + reg_err("reg psoc private obj is NULL"); + return; + } + + pdev_priv_obj = reg_get_pdev_obj(pdev); + + if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) { + reg_err("reg pdev priv obj is NULL"); + return; + } + + if (psoc_priv_obj->ch_avoid_ind) { + status = reg_process_ch_avoid_freq(psoc, pdev); + if (QDF_IS_STATUS_ERROR(status)) + psoc_priv_obj->ch_avoid_ind = false; + } + + reg_compute_pdev_current_chan_list(pdev_priv_obj); + status = reg_send_scheduler_msg_nb(psoc, pdev); + + if (QDF_IS_STATUS_ERROR(status)) + reg_err("channel change msg schedule failed"); + +} + +QDF_STATUS reg_process_ch_avoid_event(struct wlan_objmgr_psoc *psoc, + struct ch_avoid_ind_type *ch_avoid_event) +{ + uint32_t i; + struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; + QDF_STATUS status; + + psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_REGULATORY); + if (!psoc_priv_obj) { + reg_err("reg psoc private obj is NULL"); + return QDF_STATUS_E_FAILURE; + } + /* Make unsafe channel list */ + reg_debug("band count %d", ch_avoid_event->ch_avoid_range_cnt); + + /* generate vendor specific event */ + qdf_mem_zero((void *)&psoc_priv_obj->avoid_freq_list, + sizeof(struct ch_avoid_ind_type)); + qdf_mem_zero((void *)&psoc_priv_obj->unsafe_chan_list, + sizeof(struct unsafe_ch_list)); + + for (i = 0; i < ch_avoid_event->ch_avoid_range_cnt; i++) { + psoc_priv_obj->avoid_freq_list.avoid_freq_range[i].start_freq = + ch_avoid_event->avoid_freq_range[i].start_freq; + psoc_priv_obj->avoid_freq_list.avoid_freq_range[i].end_freq = + ch_avoid_event->avoid_freq_range[i].end_freq; + } + psoc_priv_obj->avoid_freq_list.ch_avoid_range_cnt = + ch_avoid_event->ch_avoid_range_cnt; + + psoc_priv_obj->ch_avoid_ind = true; + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_NB_ID); + + if (QDF_IS_STATUS_ERROR(status)) { + reg_err("error taking psoc ref cnt"); + return status; + } + + status = wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, + reg_update_unsafe_ch, NULL, 1, + WLAN_REGULATORY_NB_ID); + + wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID); + + return status; +} + QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc, uint8_t *country) { @@ -3607,7 +3853,6 @@ QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } - bool reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc) { struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; diff --git a/umac/regulatory/core/src/reg_services.h b/umac/regulatory/core/src/reg_services.h index 32ad7c8999..edaa1fab73 100644 --- a/umac/regulatory/core/src/reg_services.h +++ b/umac/regulatory/core/src/reg_services.h @@ -280,10 +280,10 @@ QDF_STATUS reg_get_curr_band(struct wlan_objmgr_pdev *pdev, enum band_info *band); typedef void (*reg_chan_change_callback)(struct wlan_objmgr_psoc *psoc, - struct wlan_objmgr_pdev *pdev, - struct regulatory_channel - *chan_list, - void *arg); + struct wlan_objmgr_pdev *pdev, + struct regulatory_channel *chan_list, + struct avoid_freq_ind_data *avoid_freq_ind, + void *arg); void reg_register_chan_change_callback(struct wlan_objmgr_psoc *psoc, reg_chan_change_callback cbk, @@ -391,4 +391,14 @@ QDF_STATUS reg_modify_chan_144(struct wlan_objmgr_pdev *pdev, * Return: en_chan_144 flag value */ bool reg_get_en_chan_144(struct wlan_objmgr_pdev *pdev); + +/** + * reg_process_ch_avoid_event() - Process channel avoid event + * @psoc: psoc for country information + * @ch_avoid_event: channel avoid event buffer + * + * Return: QDF_STATUS + */ +QDF_STATUS reg_process_ch_avoid_event(struct wlan_objmgr_psoc *psoc, + struct ch_avoid_ind_type *ch_avoid_event); #endif diff --git a/umac/regulatory/dispatcher/inc/reg_services_public_struct.h b/umac/regulatory/dispatcher/inc/reg_services_public_struct.h index 085d4383dd..530de25ab6 100644 --- a/umac/regulatory/dispatcher/inc/reg_services_public_struct.h +++ b/umac/regulatory/dispatcher/inc/reg_services_public_struct.h @@ -33,8 +33,10 @@ #define MAX_STA_VDEV_CNT 4 #define INVALID_VDEV_ID 0xFF #define INVALID_CHANNEL_NUM 0xBAD +#define CH_AVOID_MAX_RANGE 4 #ifdef CONFIG_LEGACY_CHAN_ENUM + /** * enum channel_enum - channel enumeration * @CHAN_ENUM_1: channel number 1 @@ -846,4 +848,45 @@ struct cur_regdmn_info { uint8_t ctl_5g; uint8_t dfs_region; }; + +/** + * struct ch_avoid_freq_type + * @start_freq: start freq + * @end_freq: end freq + */ +struct ch_avoid_freq_type { + uint32_t start_freq; + uint32_t end_freq; +}; + +/** + * struct ch_avoid_ind_type + * @ch_avoid_range_cnt: count + * @avoid_freq_range: avoid freq range array + */ +struct ch_avoid_ind_type { + uint32_t ch_avoid_range_cnt; + struct ch_avoid_freq_type avoid_freq_range[CH_AVOID_MAX_RANGE]; +}; + +/** + * struct unsafe_ch_list + * @ch_cnt: no.of channels + * @ch_list: channel list + */ +struct unsafe_ch_list { + uint16_t ch_cnt; + uint16_t ch_list[NUM_CHANNELS]; +}; + +/** + * struct avoid_freq_ind_data + * @freq_list: frequency list + * @chan_list: channel list + */ +struct avoid_freq_ind_data { + struct ch_avoid_ind_type freq_list; + struct unsafe_ch_list chan_list; +}; + #endif diff --git a/umac/regulatory/dispatcher/inc/wlan_reg_tgt_api.h b/umac/regulatory/dispatcher/inc/wlan_reg_tgt_api.h index 2fdac561b2..6338430d2c 100644 --- a/umac/regulatory/dispatcher/inc/wlan_reg_tgt_api.h +++ b/umac/regulatory/dispatcher/inc/wlan_reg_tgt_api.h @@ -60,4 +60,13 @@ QDF_STATUS tgt_reg_set_regdb_offloaded(struct wlan_objmgr_psoc *psoc, */ QDF_STATUS tgt_reg_set_11d_offloaded(struct wlan_objmgr_psoc *psoc, bool val); +/** + * tgt_reg_process_ch_avoid_event() - process new ch avoid event + * @psoc: pointer to psoc + * @ch_avoid_evnt: channel avoid event + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_reg_process_ch_avoid_event(struct wlan_objmgr_psoc *psoc, + struct ch_avoid_ind_type *ch_avoid_evnt); #endif diff --git a/umac/regulatory/dispatcher/src/wlan_reg_tgt_api.c b/umac/regulatory/dispatcher/src/wlan_reg_tgt_api.c index 30f3940301..0c03d4af3b 100644 --- a/umac/regulatory/dispatcher/src/wlan_reg_tgt_api.c +++ b/umac/regulatory/dispatcher/src/wlan_reg_tgt_api.c @@ -56,3 +56,9 @@ QDF_STATUS tgt_reg_set_11d_offloaded(struct wlan_objmgr_psoc *psoc, { return reg_set_11d_offloaded(psoc, val); } + +QDF_STATUS tgt_reg_process_ch_avoid_event(struct wlan_objmgr_psoc *psoc, + struct ch_avoid_ind_type *ch_avoid_evnt) +{ + return reg_process_ch_avoid_event(psoc, ch_avoid_evnt); +} diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 6d1509a58f..8b95f74fb2 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -1332,6 +1332,11 @@ QDF_STATUS (*extract_reg_11d_new_country_event)(wmi_unified_t wmi_handle, struct reg_11d_new_country *reg_11d_country, uint32_t len); +QDF_STATUS (*extract_reg_ch_avoid_event)(wmi_unified_t wmi_handle, + uint8_t *evt_buf, + struct ch_avoid_ind_type *ch_avoid_event, + uint32_t len); + QDF_STATUS (*extract_chainmask_tables)(wmi_unified_t wmi_handle, uint8_t *evt_buf, struct wlan_psoc_host_chainmask_table *chainmask_table); diff --git a/wmi/inc/wmi_unified_reg_api.h b/wmi/inc/wmi_unified_reg_api.h index 7bc50f471d..8db288d5d9 100644 --- a/wmi/inc/wmi_unified_reg_api.h +++ b/wmi/inc/wmi_unified_reg_api.h @@ -82,4 +82,19 @@ QDF_STATUS wmi_extract_reg_11d_new_cc_event(void *wmi_hdl, */ QDF_STATUS wmi_unified_set_user_country_code_cmd_send(void *wmi_hdl, uint8_t pdev_id, struct cc_regdmn_s *rd); + +/** + * wmi_extract_reg_ch_avoid_event() - process freq avoid event + * @wmi_hdl: wmi handle. + * @evt_buf: event buffer + * @ch_avoid_ind: buffer pointer to save the event processed data + * @len: lenght of buffer + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_reg_ch_avoid_event(void *wmi_hdl, + uint8_t *evt_buf, + struct ch_avoid_ind_type *ch_avoid_ind, + uint32_t len); + #endif /* _WMI_UNIFIED_REG_API_H_ */ diff --git a/wmi/src/wmi_unified_reg_api.c b/wmi/src/wmi_unified_reg_api.c index f53e3803bb..32864f8d77 100644 --- a/wmi/src/wmi_unified_reg_api.c +++ b/wmi/src/wmi_unified_reg_api.c @@ -101,3 +101,17 @@ QDF_STATUS wmi_unified_set_user_country_code_cmd_send(void *wmi_hdl, return QDF_STATUS_E_FAILURE; } + +QDF_STATUS wmi_extract_reg_ch_avoid_event(void *wmi_hdl, + uint8_t *evt_buf, + struct ch_avoid_ind_type *ch_avoid_ind, + uint32_t len) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *)wmi_hdl; + + if (wmi_handle->ops->extract_reg_ch_avoid_event) + return wmi_handle->ops->extract_reg_ch_avoid_event( + wmi_handle, evt_buf, ch_avoid_ind, len); + + return QDF_STATUS_E_FAILURE; +} diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index db43ca3b23..01294e7ebb 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -18035,6 +18035,55 @@ static QDF_STATUS extract_reg_11d_new_country_event_tlv( return QDF_STATUS_SUCCESS; } + +static QDF_STATUS extract_reg_ch_avoid_event_tlv( + wmi_unified_t wmi_handle, uint8_t *evt_buf, + struct ch_avoid_ind_type *ch_avoid_ind, uint32_t len) +{ + wmi_avoid_freq_ranges_event_fixed_param *afr_fixed_param; + wmi_avoid_freq_range_desc *afr_desc; + uint32_t num_freq_ranges, freq_range_idx; + WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *param_buf = + (WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *) evt_buf; + + if (!param_buf) { + WMI_LOGE("Invalid channel avoid event buffer"); + return QDF_STATUS_E_INVAL; + } + + afr_fixed_param = param_buf->fixed_param; + if (!afr_fixed_param) { + WMI_LOGE("Invalid channel avoid event fixed param buffer"); + return QDF_STATUS_E_INVAL; + } + + if (!ch_avoid_ind) { + WMI_LOGE("Invalid channel avoid indication buffer"); + return QDF_STATUS_E_INVAL; + } + num_freq_ranges = (afr_fixed_param->num_freq_ranges > + CH_AVOID_MAX_RANGE) ? CH_AVOID_MAX_RANGE : + afr_fixed_param->num_freq_ranges; + + WMI_LOGD("Channel avoid event received with %d ranges", + num_freq_ranges); + + ch_avoid_ind->ch_avoid_range_cnt = num_freq_ranges; + afr_desc = (wmi_avoid_freq_range_desc *)(param_buf->avd_freq_range); + for (freq_range_idx = 0; freq_range_idx < num_freq_ranges; + freq_range_idx++) { + ch_avoid_ind->avoid_freq_range[freq_range_idx].start_freq = + afr_desc->start_freq; + ch_avoid_ind->avoid_freq_range[freq_range_idx].end_freq = + afr_desc->end_freq; + WMI_LOGD("range %d tlv id %u, start freq %u, end freq %u", + freq_range_idx, afr_desc->tlv_header, + afr_desc->start_freq, afr_desc->end_freq); + afr_desc++; + } + + return QDF_STATUS_SUCCESS; +} #ifdef DFS_COMPONENT_ENABLE /** * extract_dfs_cac_complete_event_tlv() - extract cac complete event @@ -18678,6 +18727,8 @@ struct wmi_ops tlv_ops = { .send_user_country_code_cmd = send_user_country_code_cmd_tlv, .send_limit_off_chan_cmd = send_limit_off_chan_cmd_tlv, + .extract_reg_ch_avoid_event = + extract_reg_ch_avoid_event_tlv, }; /**