/****************************************************************************** * * Copyright(c) 2019 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ #include "hal_headers.h" /** * rtw_hal_bf_dbg_dump_entry * @entry: hal_bf_entry for dump content **/ void rtw_hal_bf_dbg_dump_entry(void *entry) { struct hal_bf_entry *bf_entry = (struct hal_bf_entry *)entry; if (bf_entry == NULL) { return; } PHL_INFO("-----DUMP BF ENTRY-----\n"); PHL_INFO("bf_entry->bf_idx 0x%x \n", bf_entry->bf_idx); PHL_INFO("bf_entry->macid 0x%x \n", bf_entry->macid); PHL_INFO("bf_entry->aid12 0x%x \n", bf_entry->aid12); PHL_INFO("bf_entry->band 0x%x \n", bf_entry->band); PHL_INFO("bf_entry->en_swap 0x%x \n", bf_entry->en_swap ? 1 : 0); PHL_INFO("bf_entry->counter 0x%x \n", bf_entry->couter); PHL_INFO("bf_entry->csi_buf 0x%x \n", bf_entry->csi_buf); PHL_INFO("bf_entry->csi_buf_swap 0x%x \n", bf_entry->csi_buf_swap); if (bf_entry->bfee != NULL) { PHL_INFO("bf_entry->bfee->type 0x%x \n", bf_entry->bfee->type); } } /** * rtw_hal_bf_dbg_dump_entry_all * @hal: hal_info_t **/ void rtw_hal_bf_dbg_dump_entry_all(void *hal) { struct hal_info_t *hal_info = (struct hal_info_t *)hal; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_bf_entry *bf_entry; _os_list *busy_list = &bf_obj->bf_busy_list; _os_list *idle_list = &bf_obj->bf_idle_list; PHL_INFO("-----DUMP BF BUSY LIST-----\n"); if(list_empty(busy_list)) { PHL_INFO("BF Entry BUSY LIST is Empty\n"); } else { phl_list_for_loop(bf_entry, struct hal_bf_entry, busy_list, list) { PHL_INFO("bf_entry->bf_idx 0x%x \n", bf_entry->bf_idx); PHL_INFO("bf_entry->macid 0x%x \n", bf_entry->macid); PHL_INFO("bf_entry->aid12 0x%x \n", bf_entry->aid12); PHL_INFO("bf_entry->band 0x%x \n", bf_entry->band); PHL_INFO("bf_entry->en_swap 0x%x \n", bf_entry->en_swap ? 1 : 0); PHL_INFO("bf_entry->counter 0x%x \n", bf_entry->couter); PHL_INFO("bf_entry->csi_buf 0x%x \n", bf_entry->csi_buf); PHL_INFO("bf_entry->csi_buf_swap 0x%x \n", bf_entry->csi_buf_swap); if (NULL!=bf_entry->bfee) { PHL_INFO("bfee->idx 0x%x \n", bf_entry->bfee->idx); PHL_INFO("bfee->type 0x%x \n", bf_entry->bfee->type); } } } PHL_INFO("-----DUMP BF IDLE LIST-----\n"); if(list_empty(idle_list)) { PHL_INFO("BF Entry IDLE LIST is Empty\n"); } else { phl_list_for_loop(bf_entry, struct hal_bf_entry, idle_list, list) { PHL_INFO("bf_entry->bf_idx 0x%x \n", bf_entry->bf_idx); PHL_INFO("bf_entry->macid 0x%x \n", bf_entry->macid); PHL_INFO("bf_entry->aid12 0x%x \n", bf_entry->aid12); PHL_INFO("bf_entry->band 0x%x \n", bf_entry->band); PHL_INFO("bf_entry->csi_buf 0x%x \n", bf_entry->csi_buf); } } } void _reset_bf_entry(struct hal_bf_entry *bf_entry) { bf_entry->macid = 0; bf_entry->aid12 = 0; bf_entry->csi_buf = 0; bf_entry->bfee = NULL; bf_entry->csi_buf_swap = 0; bf_entry->couter = 0; } void _reset_sumu_entry(struct hal_sumu_entry *entry) { entry->snd_sts = 0; return; } /* START of tx bf entry */ static struct hal_bf_entry *_query_idle_bf_entry(struct hal_info_t *hal_info, struct hal_bf_obj *bf_obj) { void *drv_priv = hal_to_drvpriv(hal_info); _os_list *idle_list = &bf_obj->bf_idle_list; struct hal_bf_entry *bf_entry = NULL; _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); if (true == list_empty(idle_list)) { bf_entry = NULL; } else { bf_entry = list_first_entry(idle_list, struct hal_bf_entry, list); bf_obj->num_idle_bf_entry--; list_del(&bf_entry->list); } _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); return bf_entry; } static enum rtw_hal_status _enqueue_idle_bf_entry( struct hal_info_t *hal_info, struct hal_bf_obj *bf_obj, struct hal_bf_entry *bf_entry) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; void *drv_priv = hal_to_drvpriv(hal_info); _os_list *list = &bf_obj->bf_idle_list; if (bf_entry != NULL) { _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); list_add(&bf_entry->list, list); bf_obj->num_idle_bf_entry++; _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); status = RTW_HAL_STATUS_SUCCESS; } return status; } static enum rtw_hal_status _enqueue_busy_bf_entry( struct hal_info_t *hal_info, struct hal_bf_obj *bf_obj, struct hal_bf_entry *bf_entry) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; void *drv_priv = hal_to_drvpriv(hal_info); _os_list *list = &bf_obj->bf_busy_list; if (bf_entry != NULL) { _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); list_add_tail(&bf_entry->list, list); _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); status = RTW_HAL_STATUS_SUCCESS; } return status; } /*su entry*/ static struct hal_sumu_entry *_query_idle_su_entry(struct hal_info_t *hal_info, struct hal_bf_obj *bf_obj) { void *drv_priv = hal_to_drvpriv(hal_info); _os_list *idle_list = &bf_obj->su_idle_list; struct hal_sumu_entry *su_entry = NULL; _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); if (true == list_empty(idle_list)) { su_entry = NULL; } else { su_entry = list_first_entry(idle_list, struct hal_sumu_entry, list); bf_obj->num_idle_su_entry--; list_del(&su_entry->list); } _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); return su_entry; } static enum rtw_hal_status _enqueue_idle_su_entry( struct hal_info_t *hal_info, struct hal_bf_obj *bf_obj, struct hal_sumu_entry *su_entry) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; void *drv_priv = hal_to_drvpriv(hal_info); _os_list *list = &bf_obj->su_idle_list; if (su_entry != NULL) { _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); list_add(&su_entry->list, list); bf_obj->num_idle_su_entry++; _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); status = RTW_HAL_STATUS_SUCCESS; } return status; } static enum rtw_hal_status _enqueue_busy_su_entry( struct hal_info_t *hal_info, struct hal_bf_obj *bf_obj, struct hal_sumu_entry *su_entry) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; void *drv_priv = hal_to_drvpriv(hal_info); _os_list *list = &bf_obj->su_busy_list; if (su_entry != NULL) { _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); list_add_tail(&su_entry->list, list); _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); status = RTW_HAL_STATUS_SUCCESS; } return status; } /*mu entry*/ static struct hal_sumu_entry *_query_idle_mu_entry(struct hal_info_t *hal_info, struct hal_bf_obj *bf_obj) { void *drv_priv = hal_to_drvpriv(hal_info); _os_list *idle_list = &bf_obj->mu_idle_list; struct hal_sumu_entry *mu_entry = NULL; _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); if (true == list_empty(idle_list)) { mu_entry = NULL; } else { mu_entry = list_first_entry(idle_list, struct hal_sumu_entry, list); bf_obj->num_idle_mu_entry--; list_del(&mu_entry->list); } _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); return mu_entry; } static enum rtw_hal_status _enqueue_idle_mu_entry( struct hal_info_t *hal_info, struct hal_bf_obj *bf_obj, struct hal_sumu_entry *mu_entry) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; void *drv_priv = hal_to_drvpriv(hal_info); _os_list *list = &bf_obj->mu_idle_list; if (mu_entry != NULL) { _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); list_add(&mu_entry->list, list); bf_obj->num_idle_mu_entry++; _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); status = RTW_HAL_STATUS_SUCCESS; } return status; } static enum rtw_hal_status _enqueue_busy_mu_entry( struct hal_info_t *hal_info, struct hal_bf_obj *bf_obj, struct hal_sumu_entry *mu_entry) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; void *drv_priv = hal_to_drvpriv(hal_info); _os_list *list = &bf_obj->mu_busy_list; if (mu_entry != NULL) { _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); list_add_tail(&mu_entry->list, list); _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); status = RTW_HAL_STATUS_SUCCESS; } return status; } /* hal bf init */ enum rtw_hal_status _hal_bf_init_su_entry( struct hal_info_t *hal_info, u8 num) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; void *drv_priv = hal_to_drvpriv(hal_info); struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_sumu_entry *su_entry = NULL; u8 i; do { bf_obj->su_entry = _os_mem_alloc(drv_priv, sizeof(*su_entry) * num); if (NULL == bf_obj->su_entry) { status = RTW_HAL_STATUS_RESOURCE; break; } _os_mem_set(drv_priv, bf_obj->su_entry, 0, sizeof(*su_entry) * num); su_entry = bf_obj->su_entry; for ( i = 0 ; i < num; i++) { su_entry[i].idx = i; su_entry[i].type = HAL_BFEE_SU; _reset_sumu_entry(&su_entry[i]); INIT_LIST_HEAD(&su_entry[i].list); list_add_tail(&su_entry[i].list, &bf_obj->su_idle_list); bf_obj->num_idle_su_entry++; } } while (0); return status; } enum rtw_hal_status _hal_bf_init_mu_entry( struct hal_info_t *hal_info, u8 num) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; void *drv_priv = hal_to_drvpriv(hal_info); struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_sumu_entry *mu_entry = NULL; u8 i; do { bf_obj->mu_entry = _os_mem_alloc(drv_priv, sizeof(*mu_entry) * num); if (NULL == bf_obj->mu_entry) { status = RTW_HAL_STATUS_RESOURCE; break; } _os_mem_set(drv_priv, bf_obj->mu_entry, 0, sizeof(*mu_entry) * num); mu_entry = bf_obj->mu_entry; for ( i = 0 ; i < num; i++) { mu_entry[i].idx = i; mu_entry[i].type = HAL_BFEE_MU; _reset_sumu_entry(&mu_entry[i]); INIT_LIST_HEAD(&mu_entry[i].list); list_add_tail(&mu_entry[i].list, &bf_obj->mu_idle_list); bf_obj->num_idle_mu_entry++; } } while (0); return status; } enum rtw_hal_status _hal_bf_init_bf_entry( struct hal_info_t *hal_info, u8 num) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; void *drv_priv = hal_to_drvpriv(hal_info); struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_bf_entry *bf_entry = NULL; u8 i; do { bf_obj->bf_entry = _os_mem_alloc(drv_priv, sizeof(*bf_entry) * num); if (NULL == bf_obj->bf_entry) { status = RTW_HAL_STATUS_RESOURCE; break; } _os_mem_set(drv_priv, bf_obj->bf_entry, 0, sizeof(*bf_entry) * num); bf_entry = bf_obj->bf_entry; for ( i = 0 ; i < num; i++) { bf_entry[i].bf_idx = i; _reset_bf_entry(&bf_entry[i]); INIT_LIST_HEAD(&bf_entry[i].list); list_add_tail(&bf_entry[i].list, &bf_obj->bf_idle_list); bf_obj->num_idle_bf_entry++; } } while (0); return status; } /* Start of HAL API for other HAL modules */ /** * hal_bf_init: * initialize of beamform resource mgnt module * input : * @hal_info: (struct hal_info_t *) * @bf_entry_nr: Number of HW support TxBF Entry * @su_entry_nr: Number of HW support BFee-SU Entry * @mu_entry_nr: Number of HW support BFee-MU Entry **/ enum rtw_hal_status hal_bf_init( struct hal_info_t *hal_info, u8 bf_entry_nr, u8 su_entry_nr, u8 mu_entry_nr) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = NULL; void *drv_priv = hal_to_drvpriv(hal_info); FUNCIN(); do { bf_obj = _os_mem_alloc(drv_priv, sizeof(*bf_obj)); if (bf_obj == NULL) { status = RTW_HAL_STATUS_RESOURCE; break; } hal_com->bf_obj = bf_obj; _os_spinlock_init(drv_priv, &bf_obj->bf_lock); INIT_LIST_HEAD(&bf_obj->bf_idle_list); INIT_LIST_HEAD(&bf_obj->bf_busy_list); INIT_LIST_HEAD(&bf_obj->su_idle_list); INIT_LIST_HEAD(&bf_obj->su_busy_list); INIT_LIST_HEAD(&bf_obj->mu_idle_list); INIT_LIST_HEAD(&bf_obj->mu_busy_list); if (RTW_HAL_STATUS_SUCCESS != _hal_bf_init_bf_entry(hal_info, bf_entry_nr)) { status = RTW_HAL_STATUS_RESOURCE; break; } bf_obj->max_bf_entry_nr = bf_entry_nr; if (RTW_HAL_STATUS_SUCCESS != _hal_bf_init_su_entry(hal_info, su_entry_nr)) { status = RTW_HAL_STATUS_RESOURCE; break; } bf_obj->max_su_bfee_nr = su_entry_nr; if (RTW_HAL_STATUS_SUCCESS != _hal_bf_init_mu_entry(hal_info, mu_entry_nr)) { status = RTW_HAL_STATUS_RESOURCE; break; } bf_obj->max_mu_bfee_nr = mu_entry_nr; bf_obj->self_bf_cap[0] = 0; bf_obj->self_bf_cap[1] = 0; } while (0); if (RTW_HAL_STATUS_SUCCESS != status) { hal_bf_deinit(hal_info); } FUNCOUT(); return status; } /** * hal_bf_deinit * deinitialize of beamform resource mgnt module * input : * @hal_info: (struct hal_info_t *) **/ void hal_bf_deinit(struct hal_info_t *hal_info) { struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; void *drv_priv = hal_to_drvpriv(hal_info); struct hal_bf_entry *bf_entry = bf_obj->bf_entry; struct hal_sumu_entry *mu_entry = bf_obj->mu_entry; struct hal_sumu_entry *su_entry = bf_obj->su_entry; if (bf_obj != NULL) { if (bf_entry != NULL) { _os_mem_free(hal_to_drvpriv(hal_info), bf_entry, sizeof(*bf_entry) * bf_obj->max_bf_entry_nr); bf_obj->bf_entry = NULL; } if (su_entry != NULL) { _os_mem_free(hal_to_drvpriv(hal_info), su_entry, sizeof(*su_entry) * bf_obj->max_su_bfee_nr); bf_obj->su_entry = NULL; } if (mu_entry != NULL) { _os_mem_free(hal_to_drvpriv(hal_info), mu_entry, sizeof(*mu_entry) * bf_obj->max_mu_bfee_nr); bf_obj->mu_entry = NULL; } _os_spinlock_free(drv_priv, &bf_obj->bf_lock); /* bf obj need free as last */ _os_mem_free(hal_to_drvpriv(hal_info), bf_obj, sizeof(struct hal_bf_obj)); hal_com->bf_obj = NULL; } } /** * hal_bf_release_target_bf_entry * Release the bf entry resource * input * @hal_info: (struct hal_info_t *) * @entry: hal_bf_entry to be released **/ enum rtw_hal_status hal_bf_release_target_bf_entry( struct hal_info_t *hal_info, void *entry) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_bf_entry *bf_entry = (struct hal_bf_entry *)entry; void *drv_priv = hal_to_drvpriv(hal_info); u8 bfee_idx = 0; u16 macid_rsvd = 0; FUNCIN(); if (bf_obj != NULL && bf_entry != NULL) { if (bf_entry->bfee != NULL) { bfee_idx = bf_entry->bfee->idx + ((bf_entry->bfee->type == HAL_BFEE_MU) ? bf_obj->max_su_bfee_nr : 0); /* Clear HW CR to avoid TxBF when sounding is abort */ rtw_hal_mac_ax_set_bf_entry(hal_info->mac, bf_entry->band, (u8)macid_rsvd, bfee_idx, bf_entry->bf_idx, 0); _reset_sumu_entry(bf_entry->bfee); _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); list_del(&bf_entry->bfee->list); _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); if (bf_entry->bfee->type == HAL_BFEE_MU) { _enqueue_idle_mu_entry( hal_info, bf_obj, bf_entry->bfee); } else { _enqueue_idle_su_entry( hal_info, bf_obj, bf_entry->bfee); } } _reset_bf_entry(bf_entry); _os_spinlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); list_del(&bf_entry->list); _os_spinunlock(drv_priv, &bf_obj->bf_lock, _ps, NULL); _enqueue_idle_bf_entry(hal_info, bf_obj, bf_entry); status = RTW_HAL_STATUS_SUCCESS; } FUNCOUT(); return status; } /** * hal_bf_query_idle_bf_entry * Get available beamformee entry * @hal_info: (struct hal_info_t *) * @mu: Is MU BFee ? 1 = MU / 0 = SU * return : * @hal_bf_entry: hal_bf_entry pointer **/ struct hal_bf_entry * hal_bf_query_idle_bf_entry( struct hal_info_t *hal_info, bool mu) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_bf_entry *bf_entry = NULL; struct hal_sumu_entry *sumu_entry; FUNCIN(); do { if (bf_obj == NULL) break; bf_entry = _query_idle_bf_entry(hal_info, bf_obj); PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "_query_idle_bf_entry bf_entry %p \n", bf_entry); if (NULL == bf_entry) break; if (true == mu) bf_entry->bfee = _query_idle_mu_entry(hal_info, bf_obj); else bf_entry->bfee = _query_idle_su_entry(hal_info, bf_obj); if (NULL == bf_entry->bfee) break; PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "_query_idle_bf_entry sumu_entry %p \n", bf_entry->bfee); sumu_entry = bf_entry->bfee; status = _enqueue_busy_bf_entry(hal_info, bf_obj, bf_entry); if (RTW_HAL_STATUS_SUCCESS != status) { PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "warring :hal_bf_entry add busy queue fail !!!\n"); break; } if (true == mu) status = _enqueue_busy_mu_entry( hal_info, bf_obj, sumu_entry); else status = _enqueue_busy_su_entry( hal_info, bf_obj, sumu_entry); if (RTW_HAL_STATUS_SUCCESS != status) { PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "warring :sumu_entry add busy queue fail !!!\n"); break; } } while (0); if((status != RTW_HAL_STATUS_SUCCESS) && (bf_entry != NULL)) { PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "Get BF Entry Fail !!!\n"); hal_bf_release_target_bf_entry(hal_info, (void *)bf_entry); } FUNCOUT(); return bf_entry; } /** * hal_bf_cfg_swbf_entry * Fill BF Entry SW Content * input: * @sta: rtw_phl_stainfo_t **/ enum rtw_hal_status hal_bf_cfg_swbf_entry(struct rtw_phl_stainfo_t *sta, bool swap) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; struct hal_bf_entry *bf_entry = (struct hal_bf_entry *)sta->hal_sta->bf_entry; PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "hal_bf_cfg_swbf_entry bf_entry->idx = 0x%x\n", bf_entry->bf_idx); bf_entry->macid = sta->macid; bf_entry->aid12 = sta->aid; bf_entry->band = sta->wrole->hw_band; //TODO: :BSOD in snd_test whole = NULL bf_entry->csi_buf = sta->hal_sta->bf_csi_buf; if (swap) { bf_entry->en_swap = true; bf_entry->csi_buf_swap = sta->hal_sta->bf_csi_buf_swap; } return status; } /** * hal_bf_set_entry_hwcfg * Configure BF Entry HW Setting * input * @hal_info: (struct hal_info_t *) * @entry: struct hal_bf_entry **/ enum rtw_hal_status hal_bf_set_entry_hwcfg( struct hal_info_t *hal_info, void *entry) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_bf_entry *bf_entry = (struct hal_bf_entry *)entry; u8 bfee_idx = 0; u16 csi_buf = 0; /*TODO: 8852A : SU : 0 ~ N-1; MU : N ~ M*/ bfee_idx = bf_entry->bfee->idx + ((bf_entry->bfee->type == HAL_BFEE_MU) ? bf_obj->max_su_bfee_nr : 0); PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "hal_bf_set_entry_hwcfg set bf sts idx = 0x%x \n", bfee_idx); /*1. HALMAC Settings*/ if ((bf_entry->bfee->type == HAL_BFEE_MU) && bf_entry->en_swap) { /*swap mode*/ if(0 == (bf_entry->couter % 2)) csi_buf = bf_entry->csi_buf&CSI_BUF_IDX_HW_MSK; else csi_buf = bf_entry->csi_buf_swap&CSI_BUF_IDX_HW_MSK; rtw_hal_mac_ax_set_bf_entry( hal_info->mac, bf_entry->band, (u8)(bf_entry->macid&0xFF), bfee_idx, bf_entry->bf_idx, csi_buf); bf_entry->couter++; } else { rtw_hal_mac_ax_set_bf_entry( hal_info->mac, bf_entry->band, (u8)(bf_entry->macid&0xFF), bfee_idx, bf_entry->bf_idx, bf_entry->csi_buf&CSI_BUF_IDX_HW_MSK); } /*2.TODO: HALBB Settings if needed*/ return status; } /** * hal_bf_update_entry_snd_sts * Update BF Entry Sounding Status * input * @hal_info: (struct hal_info_t *) * @entry: struct hal_bf_entry **/ void hal_bf_update_entry_snd_sts(struct hal_info_t *hal_info, void *entry) { enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_bf_entry *bf_entry = (struct hal_bf_entry *)entry; u8 bfee_idx = 0; /*TODO: 8852A : SU : 0 ~ N-1; MU : N ~ M*/ if (NULL == bf_entry) { PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "[ERROR] hal_bf_update_entry_snd_sts BF_Entry = NULL\n"); return; } if (NULL == bf_entry->bfee) { PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "[ERROR] rtw_hal_bf_get_entry_snd_sts bf_entry->macid = 0x%x\n", bf_entry->macid); PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "[ERROR] rtw_hal_bf_get_entry_snd_sts bf_entry->bfee = NULL\n"); return; } bfee_idx = bf_entry->bfee->idx + ((bf_entry->bfee->type == HAL_BFEE_MU) ? bf_obj->max_su_bfee_nr : 0); PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "hal_bf_update_entry_snd_sts idx = 0x%x \n", bfee_idx); status = rtw_hal_mac_ax_get_snd_sts(hal_info->mac, bf_entry->band, bfee_idx); bf_entry->bfee->snd_sts = (status == RTW_HAL_STATUS_SUCCESS) ? 1 : 0; PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "hal_bf_update_entry_snd_sts bf_entry->bfee->snd_sts = 0x%x \n", bf_entry->bfee->snd_sts); } enum rtw_hal_status hal_bf_hw_mac_deinit_bfee(struct hal_info_t *hal_info, u8 band) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; do { if (band >= 2) { status = RTW_HAL_STATUS_FAILURE; break; } if ((0 == (bf_obj->self_bf_cap[band]&BF_CAP_HE_BFEE)) && (0 == (bf_obj->self_bf_cap[band]&BF_CAP_VHT_BFEE))) { /* already disable */ break; } status = rtw_hal_mac_ax_deinit_bfee(hal_info->hal_com, band); if (status != RTW_HAL_STATUS_SUCCESS) break; bf_obj->self_bf_cap[band] &= ~(BF_CAP_HE_BFEE|BF_CAP_VHT_BFEE); } while (0); return status; } /** * rtw_hal_bf_get_entry_snd_sts * Get BF Entry Sounding Status * input * @hal_info: (struct hal_info_t *) * @entry: struct hal_bf_entry * return * rtw_hal_status : RTW_HAL_STATUS_FAILURE or RTW_HAL_STATUS_SUCCESS **/ enum rtw_hal_status rtw_hal_bf_get_entry_snd_sts(void *entry) { enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE; struct hal_bf_entry *bf_entry = (struct hal_bf_entry *)entry; if (NULL == bf_entry) { PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "[ERROR] rtw_hal_bf_get_entry_snd_sts BF_Entry = NULL\n"); return hstatus; } if (NULL == bf_entry->bfee) { PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "[ERROR] rtw_hal_bf_get_entry_snd_sts bf_entry->macid = 0x%x\n", bf_entry->macid); PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_, "[ERROR] rtw_hal_bf_get_entry_snd_sts bf_entry->bfee = NULL\n"); return hstatus; } if (1 == bf_entry->bfee->snd_sts) hstatus = RTW_HAL_STATUS_SUCCESS; return hstatus; } /** * hal_bf_hw_mac_init_bfee * Initialize BFee HW Settings * input * @hal_info: struct hal_info_t * @band: Band 0 / Band 1 **/ enum rtw_hal_status hal_bf_hw_mac_init_bfee( struct hal_info_t *hal_info, u8 band) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; do { if (band >= 2) { status = RTW_HAL_STATUS_FAILURE; break; } status = rtw_hal_mac_ax_init_bf_role( hal_info->hal_com, HAL_BF_ROLE_BFEE, band); if(status != RTW_HAL_STATUS_SUCCESS) break; /*TODO: Check Wireless Mode*/ bf_obj->self_bf_cap[band] |= BF_CAP_HE_BFEE|BF_CAP_VHT_BFEE; } while (0); return status; } #ifdef RTW_WKARD_DYNAMIC_BFEE_CAP enum rtw_hal_status rtw_hal_bf_bfee_ctrl(void *hal, u8 band, bool ctrl) { struct hal_info_t *hal_info = (struct hal_info_t *)hal; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; bool cur_bfee_cap = false; if ((bf_obj->self_bf_cap[band] & BF_CAP_HE_BFEE) || (bf_obj->self_bf_cap[band] & BF_CAP_VHT_BFEE)) { cur_bfee_cap = true; } /* BB Workaround */ if ((ctrl != cur_bfee_cap) && (true == ctrl)) { /* From Tx to Rx (need Enable BFee) */ rtw_hal_bb_dcr_en(hal_info, true); } else if ((ctrl != cur_bfee_cap) && (false == ctrl)) { rtw_hal_bb_dcr_en(hal_info, false); } if ((ctrl == true) && (false == rtw_hal_bb_csi_rsp(hal_info))) { ctrl = false; } if (ctrl != cur_bfee_cap) { status = ((true == ctrl) ? hal_bf_hw_mac_init_bfee(hal_info, band) : hal_bf_hw_mac_deinit_bfee(hal_info, band)); } return status; } #endif /** * hal_bf_set_bfee_csi_para * Set self bfee hw capability. * input: * @hal_info: struct hal_info_t * * @cr_cctl: set bfee capabiliy method * true = by register (only support 2 sets, Port 0 / Port 1-4 ) * false = by cmac control table * @sta: struct rtw_phl_stainfo_t * (self) */ enum rtw_hal_status hal_bf_set_bfee_csi_para(struct hal_info_t *hal_info, bool cr_cctl, struct rtw_phl_stainfo_t *sta) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; u32 rrsc = BIT(HAL_BF_RRSC_6M) | BIT(HAL_BF_RRSC_24M); if (false == cr_cctl) { status = rtw_hal_mac_ax_bfee_para_reg(hal_info->mac, sta); } else { status = rtw_hal_mac_ax_bfee_para_cctl(hal_info->mac, sta); } /* mac/bb csi rate settings initialize */ if (RTW_HAL_STATUS_SUCCESS == status) { /* Initialize CSI rate RA parameters */ sta->hal_sta->ra_info.fixed_csi_rate_en = false; sta->hal_sta->ra_info.ra_csi_rate_en = true; sta->hal_sta->ra_info.band_num = sta->wrole->hw_band; if (sta->chandef.bw >= CHANNEL_WIDTH_80) sta->hal_sta->ra_info.csi_rate.bw = HAL_RATE_BW_80; else if (sta->chandef.bw == CHANNEL_WIDTH_40) sta->hal_sta->ra_info.csi_rate.bw = HAL_RATE_BW_40; else sta->hal_sta->ra_info.csi_rate.bw = HAL_RATE_BW_20; sta->hal_sta->ra_info.csi_rate.gi_ltf = RTW_GILTF_LGI_4XHE32; sta->hal_sta->ra_info.csi_rate.mcs_ss_idx = 5; if (sta->wmode & WLAN_MD_11N) { rrsc |= (BIT(HAL_BF_RRSC_HT_MSC0) | BIT(HAL_BF_RRSC_HT_MSC3) | BIT(HAL_BF_RRSC_HT_MSC5)); sta->hal_sta->ra_info.csi_rate.mode = HAL_HT_MODE; } if (sta->wmode & WLAN_MD_11AC) { rrsc |= (BIT(HAL_BF_RRSC_VHT_MSC0) | BIT(HAL_BF_RRSC_VHT_MSC3) | BIT(HAL_BF_RRSC_VHT_MSC5)); sta->hal_sta->ra_info.csi_rate.mode = HAL_VHT_MODE; } if (sta->wmode & WLAN_MD_11AX) { rrsc |= (BIT(HAL_BF_RRSC_HE_MSC0) | BIT(HAL_BF_RRSC_HE_MSC3) | BIT(HAL_BF_RRSC_HE_MSC5)); sta->hal_sta->ra_info.csi_rate.mode = HAL_HE_MODE; } /* Initialize mac rrsc function */ rtw_hal_mac_ax_bfee_set_csi_rrsc(hal_info->mac, sta->wrole->hw_band, rrsc); PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, " set bfee csi rrsc = 0x%x\n", rrsc); } return status; } /** * hal_bf_hw_mac_init_bfer * Initialize BFer HW Settings * @hal_info: struct hal_info_t * @band: Band 0 / Band 1 **/ enum rtw_hal_status hal_bf_hw_mac_init_bfer( struct hal_info_t *hal_info, u8 band) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; do { if (band >= 2) { status = RTW_HAL_STATUS_FAILURE; break; } status = rtw_hal_mac_ax_init_bf_role(hal_info->hal_com, HAL_BF_ROLE_BFER, band); if(status != RTW_HAL_STATUS_SUCCESS) break; /*TODO: Check Wireless Mode*/ bf_obj->self_bf_cap[band] |= BF_CAP_HE_BFER|BF_CAP_VHT_BFER; } while (0); return status; } /** * rtw_hal_bf_chk_bf_type * Check the STA's BF Entry Type * @hal_info: struct hal_info_t * @sta: rtw_phl_stainfo_t * * @mu: check condition MU or SU? * return : * @ret: true : bf entry type is same to flag(mu) * false : bf entry is not same to flag(mu) or bf entry is NULL **/ bool rtw_hal_bf_chk_bf_type( void *hal_info, struct rtw_phl_stainfo_t *sta, bool mu) { struct hal_bf_entry *bf_entry = (struct hal_bf_entry *)sta->hal_sta->bf_entry; bool ret = false; do { if (NULL == bf_entry) break; if (bf_entry->bfee == NULL) break; if (true == mu) { if (HAL_BFEE_MU != bf_entry->bfee->type) break; } else { if (HAL_BFEE_SU != bf_entry->bfee->type) break; } ret = true; } while(0); return ret; } u8 rtw_hal_bf_get_sumu_idx(void *hal, void *entry) { struct hal_bf_entry *bf_entry = (struct hal_bf_entry *)entry; u8 ret = 0xFF; if (bf_entry->bfee != NULL) ret = bf_entry->bfee->idx; return ret; } void rtw_hal_bf_preset_mu_ba_info( void *hal, struct rtw_phl_stainfo_t *psta, void *hal_ba_info) { struct hal_info_t *hal_info = (struct hal_info_t *)hal; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; void *drv_priv = hal_to_drvpriv(hal_info); struct rtw_hal_muba_info *ba_info = (struct rtw_hal_muba_info *)hal_ba_info; if (1 == bf_obj->fixed_para.fix_ba_info.fix_ba) { /*Fixed BA info*/ _os_mem_cpy(drv_priv, ba_info, &bf_obj->fixed_para.fix_ba_info, sizeof(*ba_info)); } else { /* TODO: Config BA by STA Capabiliy or default value*/ ba_info->fix_ba = 0; ba_info->ru_psd = 0; ba_info->tf_rate = RTW_DATA_RATE_OFDM24; ba_info->rf_gain_fix = 0; ba_info->rf_gain_idx = 0; ba_info->tb_ppdu_bw = (psta->chandef.bw == CHANNEL_WIDTH_80) ? 2 : 0; ba_info->dcm = 0; ba_info->ss = 0; ba_info->mcs = 3; ba_info->gi_ltf = 2; ba_info->doppler = 0; ba_info->stbc = 0; ba_info->sta_coding = 0; ba_info->tb_t_pe_nom = 0; ba_info->pr20_bw_en = 0; ba_info->ma_type = 0; } } void rtw_hal_bf_set_txmu_para(void *hal, u8 gid , u8 en, enum rtw_hal_protection_type rts_type, enum rtw_hal_ack_resp_type ack_type) { struct hal_info_t *hal_info = (struct hal_info_t *)hal; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_bf_fixed_m_para *para = &bf_obj->fixed_para; para->fix_m = (1 == en) ? HAL_BF_FIX_M_MU : HAL_BF_FIX_M_DISABLE; para->gid = gid; para->fix_resp = en; para->fix_prot = en; if (en) { para->prot_type = rts_type; para->resp_type = ack_type; } } enum rtw_hal_status rtw_hal_bf_set_fix_mode(void *hal, bool mu, bool he) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; struct hal_info_t *hal_info = (struct hal_info_t *)hal; struct rtw_hal_com_t *hal_com = hal_info->hal_com; struct hal_bf_obj *bf_obj = (struct hal_bf_obj *)hal_com->bf_obj; struct hal_bf_fixed_m_para *para = &bf_obj->fixed_para; if (mu) { status = rtw_hal_mac_ax_set_mu_fix_mode( hal_info->mac, para->gid, para->prot_type, para->resp_type, (para->fix_m == HAL_BF_FIX_M_MU) ? true : false, he, para->fix_resp, para->fix_prot); } else { /*TODO: Force SU*/ } return status; } enum rtw_hal_status hal_bf_set_mu_sta_fw(void *hal, struct rtw_phl_stainfo_t *sta) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; struct hal_info_t *hal_info = (struct hal_info_t *)hal; struct hal_bf_entry *bf_entry = (struct hal_bf_entry *)sta->hal_sta->bf_entry; struct hal_sumu_entry *mu_entry = NULL; do { if (NULL == bf_entry) break; if (NULL == bf_entry->bfee) break; mu_entry = bf_entry->bfee; if (HAL_BFEE_MU != mu_entry->type) break; status = rtw_hal_mac_ax_mu_sta_upd( hal_info->mac, (u8)(sta->macid&0xFF), mu_entry->idx, sta->hal_sta->prot_type, sta->hal_sta->resp_type, sta->hal_sta->mugrp_bmp); } while (0); return status; } void rtw_hal_beamform_set_vht_gid(void *hal, u8 band, struct rtw_phl_gid_pos_tbl *tbl) { PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "--> %s()\n", __func__); if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mac_bfee_set_vht_gid(hal, band, tbl)) { PHL_INFO("%s : Error to set VHT GID Position to MAC !!! \n", __func__); } PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "<-- %s()\n", __func__); } enum rtw_hal_status rtw_hal_beamform_set_aid(void *hal, struct rtw_phl_stainfo_t *sta, u16 aid) { enum rtw_hal_status status = RTW_HAL_STATUS_SUCCESS; struct hal_info_t *hal_info = (struct hal_info_t *)hal; PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "--> %s() : set aid = %d\n", __func__, aid); /*TODO: halmac need provide api that only change AID */ status = rtw_hal_mac_addr_cam_set_aid(hal_info, sta, aid); if (status != RTW_HAL_STATUS_SUCCESS) { PHL_ERR("rtw_hal_mac_addr_cam_change_entry failed\n"); } PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "<-- %s()\n", __func__); return status; }