/****************************************************************************** * * Copyright(c) 2007 - 2017 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. * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: * wlanfae * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * * Larry Finger * *****************************************************************************/ /************************************************************* * include files ************************************************************/ #include "mp_precomp.h" #include "phydm_precomp.h" #ifdef CONFIG_ADAPTIVE_SOML void phydm_dynamicsoftmletting(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; u32 ret_val; #if (RTL8822B_SUPPORT == 1) if (!*dm->mp_mode) { if (dm->support_ic_type & ODM_RTL8822B) { if (!dm->is_linked | dm->iot_table.is_linked_cmw500) return; if (dm->bsomlenabled) { PHYDM_DBG(dm, ODM_COMP_API, "PHYDM_DynamicSoftMLSetting(): SoML has been enable, skip dynamic SoML switch\n"); return; } ret_val = odm_get_bb_reg(dm, R_0xf8c, MASKBYTE0); PHYDM_DBG(dm, ODM_COMP_API, "PHYDM_DynamicSoftMLSetting(): Read 0xF8C = 0x%08X\n", ret_val); if (ret_val < 0x16) { PHYDM_DBG(dm, ODM_COMP_API, "PHYDM_DynamicSoftMLSetting(): 0xF8C(== 0x%08X) < 0x16, enable SoML\n", ret_val); phydm_somlrxhp_setting(dm, true); dm->bsomlenabled = true; } } } #endif } void phydm_soml_on_off(void *dm_void, u8 swch) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; if (swch == SOML_ON) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "(( Turn on )) SOML\n"); if (dm->support_ic_type & (ODM_RTL8197F | ODM_RTL8192F)) odm_set_bb_reg(dm, R_0x998, BIT(6), swch); #if (RTL8822B_SUPPORT == 1) else if (dm->support_ic_type == ODM_RTL8822B) phydm_somlrxhp_setting(dm, true); #endif } else if (swch == SOML_OFF) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "(( Turn off )) SOML\n"); if (dm->support_ic_type & (ODM_RTL8197F | ODM_RTL8192F)) odm_set_bb_reg(dm, R_0x998, BIT(6), swch); #if (RTL8822B_SUPPORT == 1) else if (dm->support_ic_type == ODM_RTL8822B) phydm_somlrxhp_setting(dm, false); #endif } soml_tab->soml_on_off = swch; } #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) void phydm_adaptive_soml_callback(struct phydm_timer_list *timer) { void *adapter = (void *)timer->Adapter; HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter)); struct dm_struct *dm = &hal_data->DM_OutSrc; struct adaptive_soml *soml_tab = &dm->dm_soml_table; #if DEV_BUS_TYPE == RT_PCI_INTERFACE #if USE_WORKITEM odm_schedule_work_item(&soml_tab->phydm_adaptive_soml_workitem); #else { phydm_adsl(dm); } #endif #else odm_schedule_work_item(&soml_tab->phydm_adaptive_soml_workitem); #endif } void phydm_adaptive_soml_workitem_callback(void *context) { #ifdef CONFIG_ADAPTIVE_SOML void *adapter = (void *)context; HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter)); struct dm_struct *dm = &hal_data->DM_OutSrc; phydm_adsl(dm); #endif } #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) void phydm_adaptive_soml_callback(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; void *padapter = dm->adapter; if (*dm->is_net_closed == true) return; if (dm->support_interface == ODM_ITRF_PCIE) phydm_adsl(dm); else { /* @Can't do I/O in timer callback*/ phydm_run_in_thread_cmd(dm, phydm_adaptive_soml_workitem_callback, dm); } } void phydm_adaptive_soml_workitem_callback(void *context) { struct dm_struct *dm = (void *)context; phydm_adsl(dm); } #else void phydm_adaptive_soml_callback(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; PHYDM_DBG(dm, DBG_ADPTV_SOML, "******SOML_Callback******\n"); phydm_adsl(dm); } #endif void phydm_rx_rate_for_soml(void *dm_void, void *pkt_info_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; struct phydm_perpkt_info_struct *pktinfo = NULL; u8 data_rate; pktinfo = (struct phydm_perpkt_info_struct *)pkt_info_void; data_rate = (pktinfo->data_rate & 0x7f); if (pktinfo->data_rate >= ODM_RATEMCS0 && pktinfo->data_rate <= ODM_RATEMCS31) soml_tab->ht_cnt[data_rate - ODM_RATEMCS0]++; else if ((pktinfo->data_rate >= ODM_RATEVHTSS1MCS0) && (pktinfo->data_rate <= ODM_RATEVHTSS4MCS9)) soml_tab->vht_cnt[data_rate - ODM_RATEVHTSS1MCS0]++; } void phydm_rx_qam_for_soml(void *dm_void, void *pkt_info_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; struct phydm_perpkt_info_struct *pktinfo = NULL; u8 date_rate; pktinfo = (struct phydm_perpkt_info_struct *)pkt_info_void; date_rate = (pktinfo->data_rate & 0x7f); if (soml_tab->soml_state_cnt < (soml_tab->soml_train_num << 1)) { if (soml_tab->soml_on_off == SOML_ON) { return; } else if (soml_tab->soml_on_off == SOML_OFF) { if (date_rate >= ODM_RATEMCS8 && date_rate <= ODM_RATEMCS10) soml_tab->num_ht_qam[BPSK_QPSK]++; else if ((date_rate >= ODM_RATEMCS11) && (date_rate <= ODM_RATEMCS12)) soml_tab->num_ht_qam[QAM16]++; else if ((date_rate >= ODM_RATEMCS13) && (date_rate <= ODM_RATEMCS15)) soml_tab->num_ht_qam[QAM64]++; else if ((date_rate >= ODM_RATEVHTSS2MCS0) && (date_rate <= ODM_RATEVHTSS2MCS2)) soml_tab->num_vht_qam[BPSK_QPSK]++; else if ((date_rate >= ODM_RATEVHTSS2MCS3) && (date_rate <= ODM_RATEVHTSS2MCS4)) soml_tab->num_vht_qam[QAM16]++; else if ((date_rate >= ODM_RATEVHTSS2MCS5) && (date_rate <= ODM_RATEVHTSS2MCS5)) soml_tab->num_vht_qam[QAM64]++; else if ((date_rate >= ODM_RATEVHTSS2MCS8) && (date_rate <= ODM_RATEVHTSS2MCS9)) soml_tab->num_vht_qam[QAM256]++; } } } void phydm_soml_reset_rx_rate(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u8 order; for (order = 0; order < HT_RATE_IDX; order++) { soml_tab->ht_cnt[order] = 0; soml_tab->pre_ht_cnt[order] = 0; } for (order = 0; order < VHT_RATE_IDX; order++) { soml_tab->vht_cnt[order] = 0; soml_tab->pre_vht_cnt[order] = 0; } } void phydm_soml_reset_qam(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u8 order; for (order = 0; order < HT_ORDER_TYPE; order++) soml_tab->num_ht_qam[order] = 0; for (order = 0; order < VHT_ORDER_TYPE; order++) soml_tab->num_vht_qam[order] = 0; } void phydm_soml_cfo_process(void *dm_void, s32 *diff_a, s32 *diff_b) { struct dm_struct *dm = (struct dm_struct *)dm_void; u32 value32, value32_1, value32_2, value32_3; s32 cfo_acq_a, cfo_acq_b, cfo_end_a, cfo_end_b; value32 = odm_get_bb_reg(dm, R_0xd10, MASKDWORD); value32_1 = odm_get_bb_reg(dm, R_0xd14, MASKDWORD); value32_2 = odm_get_bb_reg(dm, R_0xd50, MASKDWORD); value32_3 = odm_get_bb_reg(dm, R_0xd54, MASKDWORD); cfo_acq_a = (s32)((value32 & 0x1fff0000) >> 16); cfo_end_a = (s32)((value32_1 & 0x1fff0000) >> 16); cfo_acq_b = (s32)((value32_2 & 0x1fff0000) >> 16); cfo_end_b = (s32)((value32_3 & 0x1fff0000) >> 16); *diff_a = ((cfo_acq_a >= cfo_end_a) ? (cfo_acq_a - cfo_end_a) : (cfo_end_a - cfo_acq_a)); *diff_b = ((cfo_acq_b >= cfo_end_b) ? (cfo_acq_b - cfo_end_b) : (cfo_end_b - cfo_acq_b)); *diff_a = ((*diff_a * 312) + (*diff_a >> 1)) >> 12; /* @312.5/2^12 */ *diff_b = ((*diff_b * 312) + (*diff_b >> 1)) >> 12; /* @312.5/2^12 */ } void phydm_soml_debug(void *dm_void, char input[][16], u32 *_used, char *output, u32 *_out_len) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u32 used = *_used; u32 out_len = *_out_len; u32 dm_value[10] = {0}; u8 i = 0, input_idx = 0; for (i = 0; i < 5; i++) { if (input[i + 1]) { PHYDM_SSCANF(input[i + 1], DCMD_DECIMAL, &dm_value[i]); input_idx++; } } if (input_idx == 0) return; if (dm_value[0] == 1) { /*Turn on/off SOML*/ soml_tab->soml_select = (u8)dm_value[1]; } else if (dm_value[0] == 2) { /*training number for SOML*/ soml_tab->soml_train_num = (u8)dm_value[1]; PDM_SNPF(out_len, used, output + used, out_len - used, "soml_train_num = ((%d))\n", soml_tab->soml_train_num); } else if (dm_value[0] == 3) { /*training interval for SOML*/ soml_tab->soml_intvl = (u8)dm_value[1]; PDM_SNPF(out_len, used, output + used, out_len - used, "soml_intvl = ((%d))\n", soml_tab->soml_intvl); } else if (dm_value[0] == 4) { /*@function period for SOML*/ soml_tab->soml_period = (u8)dm_value[1]; PDM_SNPF(out_len, used, output + used, out_len - used, "soml_period = ((%d))\n", soml_tab->soml_period); } else if (dm_value[0] == 5) { /*@delay_time for SOML*/ soml_tab->soml_delay_time = (u8)dm_value[1]; PDM_SNPF(out_len, used, output + used, out_len - used, "soml_delay_time = ((%d))\n", soml_tab->soml_delay_time); } else if (dm_value[0] == 6) { /* @for SOML Rx QAM distribution th*/ if (dm_value[1] == 256) { soml_tab->qam256_dist_th = (u8)dm_value[2]; PDM_SNPF(out_len, used, output + used, out_len - used, "qam256_dist_th = ((%d))\n", soml_tab->qam256_dist_th); } else if (dm_value[1] == 64) { soml_tab->qam64_dist_th = (u8)dm_value[2]; PDM_SNPF(out_len, used, output + used, out_len - used, "qam64_dist_th = ((%d))\n", soml_tab->qam64_dist_th); } else if (dm_value[1] == 16) { soml_tab->qam16_dist_th = (u8)dm_value[2]; PDM_SNPF(out_len, used, output + used, out_len - used, "qam16_dist_th = ((%d))\n", soml_tab->qam16_dist_th); } else if (dm_value[1] == 4) { soml_tab->bpsk_qpsk_dist_th = (u8)dm_value[2]; PDM_SNPF(out_len, used, output + used, out_len - used, "bpsk_qpsk_dist_th = ((%d))\n", soml_tab->bpsk_qpsk_dist_th); } } else if (dm_value[0] == 7) { /* @for SOML cfo th*/ if (dm_value[1] == 256) { soml_tab->cfo_qam256_th = (u8)dm_value[2]; PDM_SNPF(out_len, used, output + used, out_len - used, "cfo_qam256_th = ((%d KHz))\n", soml_tab->cfo_qam256_th); } else if (dm_value[1] == 64) { soml_tab->cfo_qam64_th = (u8)dm_value[2]; PDM_SNPF(out_len, used, output + used, out_len - used, "cfo_qam64_th = ((%d KHz))\n", soml_tab->cfo_qam64_th); } else if (dm_value[1] == 16) { soml_tab->cfo_qam16_th = (u8)dm_value[2]; PDM_SNPF(out_len, used, output + used, out_len - used, "cfo_qam16_th = ((%d KHz))\n", soml_tab->cfo_qam16_th); } else if (dm_value[1] == 4) { soml_tab->cfo_qpsk_th = (u8)dm_value[2]; PDM_SNPF(out_len, used, output + used, out_len - used, "cfo_qpsk_th = ((%d KHz))\n", soml_tab->cfo_qpsk_th); } } else if (dm_value[0] == 100) { /*show parameters*/ PDM_SNPF(out_len, used, output + used, out_len - used, "soml_select = ((%d))\n", soml_tab->soml_select); PDM_SNPF(out_len, used, output + used, out_len - used, "soml_train_num = ((%d))\n", soml_tab->soml_train_num); PDM_SNPF(out_len, used, output + used, out_len - used, "soml_intvl = ((%d))\n", soml_tab->soml_intvl); PDM_SNPF(out_len, used, output + used, out_len - used, "soml_period = ((%d))\n", soml_tab->soml_period); PDM_SNPF(out_len, used, output + used, out_len - used, "soml_delay_time = ((%d))\n\n", soml_tab->soml_delay_time); PDM_SNPF(out_len, used, output + used, out_len - used, "qam256_dist_th = ((%d)), qam64_dist_th = ((%d)), ", soml_tab->qam256_dist_th, soml_tab->qam64_dist_th); PDM_SNPF(out_len, used, output + used, out_len - used, "qam16_dist_th = ((%d)), bpsk_qpsk_dist_th = ((%d))\n", soml_tab->qam16_dist_th, soml_tab->bpsk_qpsk_dist_th); PDM_SNPF(out_len, used, output + used, out_len - used, "cfo_qam256_th = ((%d KHz)), cfo_qam64_th = ((%d KHz)), ", soml_tab->cfo_qam256_th, soml_tab->cfo_qam64_th); PDM_SNPF(out_len, used, output + used, out_len - used, "cfo_qam16_th = ((%d KHz)), cfo_qpsk_th = ((%d KHz))\n", soml_tab->cfo_qam16_th, soml_tab->cfo_qpsk_th); } *_used = used; *_out_len = out_len; } void phydm_soml_stats_ht_on(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u8 i, mcs0; u16 num_bytes_diff, num_rate_diff; mcs0 = ODM_RATEMCS0; for (i = mcs0; i <= ODM_RATEMCS15; i++) { num_rate_diff = soml_tab->ht_cnt[i - mcs0] - soml_tab->pre_ht_cnt[i - mcs0]; soml_tab->ht_cnt_on[i - mcs0] += num_rate_diff; soml_tab->pre_ht_cnt[i - mcs0] = soml_tab->ht_cnt[i - mcs0]; num_bytes_diff = soml_tab->ht_byte[i - mcs0] - soml_tab->pre_ht_byte[i - mcs0]; soml_tab->ht_byte_on[i - mcs0] += num_bytes_diff; soml_tab->pre_ht_byte[i - mcs0] = soml_tab->ht_byte[i - mcs0]; } } void phydm_soml_stats_ht_off(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u8 i, mcs0; u16 num_bytes_diff, num_rate_diff; mcs0 = ODM_RATEMCS0; for (i = mcs0; i <= ODM_RATEMCS15; i++) { num_rate_diff = soml_tab->ht_cnt[i - mcs0] - soml_tab->pre_ht_cnt[i - mcs0]; soml_tab->ht_cnt_off[i - mcs0] += num_rate_diff; soml_tab->pre_ht_cnt[i - mcs0] = soml_tab->ht_cnt[i - mcs0]; num_bytes_diff = soml_tab->ht_byte[i - mcs0] - soml_tab->pre_ht_byte[i - mcs0]; soml_tab->ht_byte_off[i - mcs0] += num_bytes_diff; soml_tab->pre_ht_byte[i - mcs0] = soml_tab->ht_byte[i - mcs0]; } } void phydm_soml_stats_vht_on(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u8 j, vht0; u16 num_bytes_diff, num_rate_diff; vht0 = ODM_RATEVHTSS1MCS0; for (j = vht0; j <= ODM_RATEVHTSS2MCS9; j++) { num_rate_diff = soml_tab->vht_cnt[j - vht0] - soml_tab->pre_vht_cnt[j - vht0]; soml_tab->vht_cnt_on[j - vht0] += num_rate_diff; soml_tab->pre_vht_cnt[j - vht0] = soml_tab->vht_cnt[j - vht0]; num_bytes_diff = soml_tab->vht_byte[j - vht0] - soml_tab->pre_vht_byte[j - vht0]; soml_tab->vht_byte_on[j - vht0] += num_bytes_diff; soml_tab->pre_vht_byte[j - vht0] = soml_tab->vht_byte[j - vht0]; } } void phydm_soml_stats_vht_off(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u8 j, vht0; u16 num_bytes_diff, num_rate_diff; vht0 = ODM_RATEVHTSS1MCS0; for (j = vht0; j <= ODM_RATEVHTSS2MCS9; j++) { num_rate_diff = soml_tab->vht_cnt[j - vht0] - soml_tab->pre_vht_cnt[j - vht0]; soml_tab->vht_cnt_off[j - vht0] += num_rate_diff; soml_tab->pre_vht_cnt[j - vht0] = soml_tab->vht_cnt[j - vht0]; num_bytes_diff = soml_tab->vht_byte[j - vht0] - soml_tab->pre_vht_byte[j - vht0]; soml_tab->vht_byte_off[j - vht0] += num_bytes_diff; soml_tab->pre_vht_byte[j - vht0] = soml_tab->vht_byte[j - vht0]; } } void phydm_soml_statistics(void *dm_void, u8 on_off_state) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; if (on_off_state == SOML_ON) { if (*dm->channel <= 14) phydm_soml_stats_ht_on(dm); if (dm->support_ic_type == ODM_RTL8822B) phydm_soml_stats_vht_on(dm); } else if (on_off_state == SOML_OFF) { if (*dm->channel <= 14) phydm_soml_stats_ht_off(dm); if (dm->support_ic_type == ODM_RTL8822B) phydm_soml_stats_vht_off(dm); } } void phydm_adsl_init_state(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u8 next_on_off; u16 ht_reset[HT_RATE_IDX] = {0}, vht_reset[VHT_RATE_IDX] = {0}; u8 size = sizeof(ht_reset[0]); phydm_soml_reset_rx_rate(dm); odm_move_memory(dm, soml_tab->ht_byte, ht_reset, HT_RATE_IDX * size); odm_move_memory(dm, soml_tab->ht_byte_on, ht_reset, HT_RATE_IDX * size); odm_move_memory(dm, soml_tab->ht_byte_off, ht_reset, HT_RATE_IDX * size); odm_move_memory(dm, soml_tab->vht_byte, vht_reset, VHT_RATE_IDX * size); odm_move_memory(dm, soml_tab->vht_byte_on, vht_reset, VHT_RATE_IDX * size); odm_move_memory(dm, soml_tab->vht_byte_off, vht_reset, VHT_RATE_IDX * size); if (dm->support_ic_type == ODM_RTL8822B) { soml_tab->cfo_cnt++; phydm_soml_cfo_process(dm, &soml_tab->cfo_diff_a, &soml_tab->cfo_diff_b); PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ (%d) cfo_diff_a = %d KHz; cfo_diff_b = %d KHz ]\n", soml_tab->cfo_cnt, soml_tab->cfo_diff_a, soml_tab->cfo_diff_b); soml_tab->cfo_diff_sum_a += soml_tab->cfo_diff_a; soml_tab->cfo_diff_sum_b += soml_tab->cfo_diff_b; } soml_tab->is_soml_method_enable = 1; soml_tab->soml_state_cnt++; next_on_off = (soml_tab->soml_on_off == SOML_ON) ? SOML_ON : SOML_OFF; phydm_soml_on_off(dm, next_on_off); odm_set_timer(dm, &soml_tab->phydm_adaptive_soml_timer, soml_tab->soml_delay_time); /*@ms*/ } void phydm_adsl_odd_state(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u16 ht_reset[HT_RATE_IDX] = {0}, vht_reset[VHT_RATE_IDX] = {0}; u8 size = sizeof(ht_reset[0]); soml_tab->soml_state_cnt++; odm_move_memory(dm, soml_tab->pre_ht_cnt, soml_tab->ht_cnt, HT_RATE_IDX * size); odm_move_memory(dm, soml_tab->pre_vht_cnt, soml_tab->vht_cnt, VHT_RATE_IDX * size); odm_move_memory(dm, soml_tab->pre_ht_byte, soml_tab->ht_byte, HT_RATE_IDX * size); odm_move_memory(dm, soml_tab->pre_vht_byte, soml_tab->vht_byte, VHT_RATE_IDX * size); if (dm->support_ic_type == ODM_RTL8822B) { soml_tab->cfo_cnt++; phydm_soml_cfo_process(dm, &soml_tab->cfo_diff_a, &soml_tab->cfo_diff_b); PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ (%d) cfo_diff_a = %d KHz; cfo_diff_b = %d KHz ]\n", soml_tab->cfo_cnt, soml_tab->cfo_diff_a, soml_tab->cfo_diff_b); soml_tab->cfo_diff_sum_a += soml_tab->cfo_diff_a; soml_tab->cfo_diff_sum_b += soml_tab->cfo_diff_b; } odm_set_timer(dm, &soml_tab->phydm_adaptive_soml_timer, soml_tab->soml_intvl); /*@ms*/ } void phydm_adsl_even_state(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u8 next_on_off; if (dm->support_ic_type == ODM_RTL8822B) { soml_tab->cfo_cnt++; phydm_soml_cfo_process(dm, &soml_tab->cfo_diff_a, &soml_tab->cfo_diff_b); PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ (%d) cfo_diff_a = %d KHz; cfo_diff_b = %d KHz ]\n", soml_tab->cfo_cnt, soml_tab->cfo_diff_a, soml_tab->cfo_diff_b); soml_tab->cfo_diff_sum_a += soml_tab->cfo_diff_a; soml_tab->cfo_diff_sum_b += soml_tab->cfo_diff_b; } soml_tab->soml_state_cnt++; phydm_soml_statistics(dm, soml_tab->soml_on_off); next_on_off = (soml_tab->soml_on_off == SOML_ON) ? SOML_OFF : SOML_ON; phydm_soml_on_off(dm, next_on_off); odm_set_timer(dm, &soml_tab->phydm_adaptive_soml_timer, soml_tab->soml_delay_time); /*@ms*/ } void phydm_adsl_decision_state(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; u8 i; u8 next_on_off, mcs0 = ODM_RATEMCS0, vht0 = ODM_RATEVHTSS1MCS0; u8 rate_num = 1, rate_ss_shift = 0; u16 num_total_qam = 0; u32 ht_total_cnt_on = 0, ht_total_cnt_off = 0; u32 total_ht_rate_on = 0, total_ht_rate_off = 0; u32 vht_total_cnt_on = 0, vht_total_cnt_off = 0; u32 total_vht_rate_on = 0, total_vht_rate_off = 0; u32 rate_per_pkt_on = 0, rate_per_pkt_off = 0; s32 cfo_diff_avg_a, cfo_diff_avg_b; u16 vht_phy_rate_table[] = { /*@20M*/ 6, 13, 19, 26, 39, 52, 58, 65, 78, 90, /*@1SS MCS0~9*/ 13, 26, 39, 52, 78, 104, 117, 130, 156, 180 /*@2SSMCS0~9*/ }; if (dm->support_ic_type & ODM_IC_4SS) rate_num = 4; else if (dm->support_ic_type & ODM_IC_3SS) rate_num = 3; else if (dm->support_ic_type & ODM_IC_2SS) rate_num = 2; PHYDM_DBG(dm, DBG_ADPTV_SOML, "[Decisoin state ]\n"); phydm_soml_statistics(dm, soml_tab->soml_on_off); if (*dm->channel <= 14) { /* @[Search 1st and 2nd rate by counter] */ for (i = 0; i < rate_num; i++) { rate_ss_shift = (i << 3); PHYDM_DBG(dm, DBG_ADPTV_SOML, "*ht_cnt_on HT MCS[%d :%d ] = {%d, %d, %d, %d, %d, %d, %d, %d}\n", (rate_ss_shift), (rate_ss_shift + 7), soml_tab->ht_cnt_on[rate_ss_shift + 0], soml_tab->ht_cnt_on[rate_ss_shift + 1], soml_tab->ht_cnt_on[rate_ss_shift + 2], soml_tab->ht_cnt_on[rate_ss_shift + 3], soml_tab->ht_cnt_on[rate_ss_shift + 4], soml_tab->ht_cnt_on[rate_ss_shift + 5], soml_tab->ht_cnt_on[rate_ss_shift + 6], soml_tab->ht_cnt_on[rate_ss_shift + 7]); } for (i = 0; i < rate_num; i++) { rate_ss_shift = (i << 3); PHYDM_DBG(dm, DBG_ADPTV_SOML, "*ht_byte_off HT MCS[%d :%d ] = {%d, %d, %d, %d, %d, %d, %d, %d}\n", (rate_ss_shift), (rate_ss_shift + 7), soml_tab->ht_cnt_off[rate_ss_shift + 0], soml_tab->ht_cnt_off[rate_ss_shift + 1], soml_tab->ht_cnt_off[rate_ss_shift + 2], soml_tab->ht_cnt_off[rate_ss_shift + 3], soml_tab->ht_cnt_off[rate_ss_shift + 4], soml_tab->ht_cnt_off[rate_ss_shift + 5], soml_tab->ht_cnt_off[rate_ss_shift + 6], soml_tab->ht_cnt_off[rate_ss_shift + 7]); } for (i = ODM_RATEMCS8; i <= ODM_RATEMCS15; i++) { ht_total_cnt_on += soml_tab->ht_cnt_on[i - mcs0]; ht_total_cnt_off += soml_tab->ht_cnt_off[i - mcs0]; total_ht_rate_on += (soml_tab->ht_cnt_on[i - mcs0] * (phy_rate_table[i] >> 1)); total_ht_rate_off += (soml_tab->ht_cnt_off[i - mcs0] * (phy_rate_table[i] >> 1)); } total_ht_rate_on = total_ht_rate_on << 3; total_ht_rate_off = total_ht_rate_off << 3; rate_per_pkt_on = (ht_total_cnt_on != 0) ? (total_ht_rate_on / ht_total_cnt_on) : 0; rate_per_pkt_off = (ht_total_cnt_off != 0) ? (total_ht_rate_off / ht_total_cnt_off) : 0; } if (dm->support_ic_type == ODM_RTL8822B) { cfo_diff_avg_a = soml_tab->cfo_diff_sum_a / soml_tab->cfo_cnt; cfo_diff_avg_b = soml_tab->cfo_diff_sum_b / soml_tab->cfo_cnt; soml_tab->cfo_diff_avg_a = (soml_tab->cfo_cnt != 0) ? cfo_diff_avg_a : 0; soml_tab->cfo_diff_avg_b = (soml_tab->cfo_cnt != 0) ? cfo_diff_avg_b : 0; PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ cfo_diff_avg_a = %d KHz; cfo_diff_avg_b = %d KHz]\n", soml_tab->cfo_diff_avg_a, soml_tab->cfo_diff_avg_b); for (i = 0; i < VHT_ORDER_TYPE; i++) num_total_qam += soml_tab->num_vht_qam[i]; PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ ((2SS)) BPSK_QPSK_count = %d ; 16QAM_count = %d ; 64QAM_count = %d ; 256QAM_count = %d ; num_total_qam = %d]\n", soml_tab->num_vht_qam[BPSK_QPSK], soml_tab->num_vht_qam[QAM16], soml_tab->num_vht_qam[QAM64], soml_tab->num_vht_qam[QAM256], num_total_qam); if (((soml_tab->num_vht_qam[QAM256] * 100) > (num_total_qam * soml_tab->qam256_dist_th)) && cfo_diff_avg_a > soml_tab->cfo_qam256_th && cfo_diff_avg_b > soml_tab->cfo_qam256_th) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ QAM256_ratio > %d ; cfo_diff_avg_a > %d KHz ==> SOML_OFF]\n", soml_tab->qam256_dist_th, soml_tab->cfo_qam256_th); PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ Final decisoin ] : "); phydm_soml_on_off(dm, SOML_OFF); return; } else if (((soml_tab->num_vht_qam[QAM64] * 100) > (num_total_qam * soml_tab->qam64_dist_th)) && (cfo_diff_avg_a > soml_tab->cfo_qam64_th) && (cfo_diff_avg_b > soml_tab->cfo_qam64_th)) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ QAM64_ratio > %d ; cfo_diff_avg_a > %d KHz ==> SOML_OFF]\n", soml_tab->qam64_dist_th, soml_tab->cfo_qam64_th); PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ Final decisoin ] : "); phydm_soml_on_off(dm, SOML_OFF); return; } else if (((soml_tab->num_vht_qam[QAM16] * 100) > (num_total_qam * soml_tab->qam16_dist_th)) && (cfo_diff_avg_a > soml_tab->cfo_qam16_th) && (cfo_diff_avg_b > soml_tab->cfo_qam16_th)) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ QAM16_ratio > %d ; cfo_diff_avg_a > %d KHz ==> SOML_OFF]\n", soml_tab->qam16_dist_th, soml_tab->cfo_qam16_th); PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ Final decisoin ] : "); phydm_soml_on_off(dm, SOML_OFF); return; } else if (((soml_tab->num_vht_qam[BPSK_QPSK] * 100) > (num_total_qam * soml_tab->bpsk_qpsk_dist_th)) && (cfo_diff_avg_a > soml_tab->cfo_qpsk_th) && (cfo_diff_avg_b > soml_tab->cfo_qpsk_th)) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ BPSK_QPSK_ratio > %d ; cfo_diff_avg_a > %d KHz ==> SOML_OFF]\n", soml_tab->bpsk_qpsk_dist_th, soml_tab->cfo_qpsk_th); PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ Final decisoin ] : "); phydm_soml_on_off(dm, SOML_OFF); return; } for (i = 0; i < rate_num; i++) { rate_ss_shift = 10 * i; PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ vht_cnt_on VHT-%d ss MCS[0:9] = {%d, %d, %d, %d, %d, %d, %d, %d, %d, %d} ]\n", (i + 1), soml_tab->vht_cnt_on[rate_ss_shift + 0], soml_tab->vht_cnt_on[rate_ss_shift + 1], soml_tab->vht_cnt_on[rate_ss_shift + 2], soml_tab->vht_cnt_on[rate_ss_shift + 3], soml_tab->vht_cnt_on[rate_ss_shift + 4], soml_tab->vht_cnt_on[rate_ss_shift + 5], soml_tab->vht_cnt_on[rate_ss_shift + 6], soml_tab->vht_cnt_on[rate_ss_shift + 7], soml_tab->vht_cnt_on[rate_ss_shift + 8], soml_tab->vht_cnt_on[rate_ss_shift + 9]); } for (i = 0; i < rate_num; i++) { rate_ss_shift = 10 * i; PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ vht_cnt_off VHT-%d ss MCS[0:9] = {%d, %d, %d, %d, %d, %d, %d, %d, %d, %d} ]\n", (i + 1), soml_tab->vht_cnt_off[rate_ss_shift + 0], soml_tab->vht_cnt_off[rate_ss_shift + 1], soml_tab->vht_cnt_off[rate_ss_shift + 2], soml_tab->vht_cnt_off[rate_ss_shift + 3], soml_tab->vht_cnt_off[rate_ss_shift + 4], soml_tab->vht_cnt_off[rate_ss_shift + 5], soml_tab->vht_cnt_off[rate_ss_shift + 6], soml_tab->vht_cnt_off[rate_ss_shift + 7], soml_tab->vht_cnt_off[rate_ss_shift + 8], soml_tab->vht_cnt_off[rate_ss_shift + 9]); } for (i = ODM_RATEVHTSS2MCS0; i <= ODM_RATEVHTSS2MCS9; i++) { vht_total_cnt_on += soml_tab->vht_cnt_on[i - vht0]; vht_total_cnt_off += soml_tab->vht_cnt_off[i - vht0]; total_vht_rate_on += (soml_tab->vht_cnt_on[i - vht0] * (vht_phy_rate_table[i - vht0] >> 1 )); total_vht_rate_off += (soml_tab->vht_cnt_off[i - vht0] * (vht_phy_rate_table[i - vht0] >> 1 )); } total_vht_rate_on = total_vht_rate_on << 3; total_vht_rate_off = total_vht_rate_off << 3; rate_per_pkt_on = (vht_total_cnt_on != 0) ? (total_vht_rate_on / vht_total_cnt_on) : 0; rate_per_pkt_off = (vht_total_cnt_off != 0) ? (total_vht_rate_off / vht_total_cnt_off) : 0; } /* @[Decision] */ PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ rate_per_pkt_on = %d ; rate_per_pkt_off = %d ]\n", rate_per_pkt_on, rate_per_pkt_off); if (rate_per_pkt_on > rate_per_pkt_off) { next_on_off = SOML_ON; PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ rate_per_pkt_on > rate_per_pkt_off ==> SOML_ON ]\n"); } else if (rate_per_pkt_on < rate_per_pkt_off) { next_on_off = SOML_OFF; PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ rate_per_pkt_on < rate_per_pkt_off ==> SOML_OFF ]\n"); } else { PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ stay at soml_last_state ]\n"); next_on_off = soml_tab->soml_last_state; } PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ Final decisoin ] : "); phydm_soml_on_off(dm, next_on_off); soml_tab->soml_last_state = next_on_off; } void phydm_adsl(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; if (dm->support_ic_type & PHYDM_ADAPTIVE_SOML_IC) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "soml_state_cnt =((%d))\n", soml_tab->soml_state_cnt); /*Traning state: 0(alt) 1(ori) 2(alt) 3(ori)===============*/ if (soml_tab->soml_state_cnt < (soml_tab->soml_train_num << 1)) { if (soml_tab->soml_state_cnt == 0) phydm_adsl_init_state(dm); else if ((soml_tab->soml_state_cnt % 2) != 0) phydm_adsl_odd_state(dm); else if ((soml_tab->soml_state_cnt % 2) == 0) phydm_adsl_even_state(dm); } else { phydm_adsl_decision_state(dm); } } } void phydm_adaptive_soml_reset(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; soml_tab->soml_state_cnt = 0; soml_tab->is_soml_method_enable = 0; soml_tab->soml_counter = 0; } void phydm_set_adsl_val(void *dm_void, u32 *val_buf, u8 val_len) { struct dm_struct *dm = (struct dm_struct *)dm_void; if (val_len != 1) { PHYDM_DBG(dm, ODM_COMP_API, "[Error][ADSL]Need val_len=1\n"); return; } phydm_soml_on_off(dm, (u8)val_buf[1]); } void phydm_soml_bytes_acq(void *dm_void, u8 rate_id, u32 length) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; if (rate_id >= ODM_RATEMCS0 && rate_id <= ODM_RATEMCS31) soml_tab->ht_byte[rate_id - ODM_RATEMCS0] += (u16)length; else if (rate_id >= ODM_RATEVHTSS1MCS0 && rate_id <= ODM_RATEVHTSS4MCS9) soml_tab->vht_byte[rate_id - ODM_RATEVHTSS1MCS0] += (u16)length; } #if defined(CONFIG_RTL_TRIBAND_SUPPORT) && defined(CONFIG_USB_HCI) #define INIT_TIMER_EVENT_ENTRY(_entry, _func, _data) \ do { \ _rtw_init_listhead(&(_entry)->list); \ (_entry)->data = (_data); \ (_entry)->function = (_func); \ } while (0) static void pre_phydm_adaptive_soml_callback(unsigned long task_dm) { struct dm_struct *dm = (struct dm_struct *)task_dm; struct rtl8192cd_priv *priv = dm->priv; struct priv_shared_info *pshare = priv->pshare; if (pshare->bDriverStopped || pshare->bSurpriseRemoved) { printk("[%s] bDriverStopped(%d) OR bSurpriseRemoved(%d)\n", __FUNCTION__, pshare->bDriverStopped, pshare->bSurpriseRemoved); return; } rtw_enqueue_timer_event(priv, &pshare->adaptive_soml_event, ENQUEUE_TO_TAIL); } void phydm_adaptive_soml_timers_usb(void *dm_void, u8 state) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; struct rtl8192cd_priv *priv = dm->priv; if (state == INIT_SOML_TIMMER) { init_timer(&soml_tab->phydm_adaptive_soml_timer); soml_tab->phydm_adaptive_soml_timer.data = (unsigned long)dm; soml_tab->phydm_adaptive_soml_timer.function = pre_phydm_adaptive_soml_callback; INIT_TIMER_EVENT_ENTRY(&priv->pshare->adaptive_soml_event, phydm_adaptive_soml_callback, (unsigned long)dm); } else if (state == CANCEL_SOML_TIMMER) { odm_cancel_timer(dm, &soml_tab->phydm_adaptive_soml_timer); } else if (state == RELEASE_SOML_TIMMER) { odm_release_timer(dm, &soml_tab->phydm_adaptive_soml_timer); } } #endif /* defined(CONFIG_RTL_TRIBAND_SUPPORT) && defined(CONFIG_USB_HCI) */ void phydm_adaptive_soml_timers(void *dm_void, u8 state) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; #if defined(CONFIG_RTL_TRIBAND_SUPPORT) && defined(CONFIG_USB_HCI) struct rtl8192cd_priv *priv = dm->priv; if (priv->hci_type == RTL_HCI_USB) { phydm_adaptive_soml_timers_usb(dm_void, state); } else #endif /* defined(CONFIG_RTL_TRIBAND_SUPPORT) && defined(CONFIG_USB_HCI) */ { if (state == INIT_SOML_TIMMER) { odm_initialize_timer(dm, &soml_tab->phydm_adaptive_soml_timer, (void *)phydm_adaptive_soml_callback, NULL, "phydm_adaptive_soml_timer"); } else if (state == CANCEL_SOML_TIMMER) { odm_cancel_timer(dm, &soml_tab->phydm_adaptive_soml_timer); } else if (state == RELEASE_SOML_TIMMER) { odm_release_timer(dm, &soml_tab->phydm_adaptive_soml_timer); } } } void phydm_adaptive_soml_init(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; PHYDM_DBG(dm, DBG_ADPTV_SOML, "%s\n", __func__); soml_tab->soml_state_cnt = 0; soml_tab->soml_delay_time = 40; soml_tab->soml_intvl = 150; soml_tab->soml_train_num = 4; soml_tab->is_soml_method_enable = 0; soml_tab->soml_counter = 0; #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) soml_tab->soml_period = 1; #else soml_tab->soml_period = 4; #endif soml_tab->soml_select = 0; soml_tab->cfo_cnt = 0; soml_tab->cfo_diff_sum_a = 0; soml_tab->cfo_diff_sum_b = 0; soml_tab->cfo_qpsk_th = 94; soml_tab->cfo_qam16_th = 38; soml_tab->cfo_qam64_th = 17; soml_tab->cfo_qam256_th = 7; soml_tab->bpsk_qpsk_dist_th = 20; soml_tab->qam16_dist_th = 20; soml_tab->qam64_dist_th = 20; soml_tab->qam256_dist_th = 20; if (dm->support_ic_type & (ODM_RTL8197F | ODM_RTL8192F)) odm_set_bb_reg(dm, 0x988, BIT(25), 1); } void phydm_adaptive_soml(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; if (!(dm->support_ability & ODM_BB_ADAPTIVE_SOML)) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "[Return!!!] Not Support Adaptive SOML Function\n"); return; } if (dm->pause_ability & ODM_BB_ADAPTIVE_SOML) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "Return: Pause ADSL in LV=%d\n", dm->pause_lv_table.lv_adsl); return; } if (soml_tab->soml_counter < soml_tab->soml_period) { soml_tab->soml_counter++; return; } soml_tab->soml_counter = 0; soml_tab->soml_state_cnt = 0; soml_tab->cfo_cnt = 0; soml_tab->cfo_diff_sum_a = 0; soml_tab->cfo_diff_sum_b = 0; phydm_soml_reset_qam(dm); if (soml_tab->soml_select == 0) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ Adaptive SOML Training !!!]\n"); } else if (soml_tab->soml_select == 1) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ Stop Adaptive SOML !!!]\n"); phydm_soml_on_off(dm, SOML_ON); return; } else if (soml_tab->soml_select == 2) { PHYDM_DBG(dm, DBG_ADPTV_SOML, "[ Stop Adaptive SOML !!!]\n"); phydm_soml_on_off(dm, SOML_OFF); return; } if (dm->support_ic_type & PHYDM_ADAPTIVE_SOML_IC) phydm_adsl(dm); } void phydm_enable_adaptive_soml(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; PHYDM_DBG(dm, DBG_ADPTV_SOML, "[%s]\n", __func__); dm->support_ability |= ODM_BB_ADAPTIVE_SOML; phydm_soml_on_off(dm, SOML_ON); } void phydm_stop_adaptive_soml(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; PHYDM_DBG(dm, DBG_ADPTV_SOML, "[%s]\n", __func__); dm->support_ability &= ~ODM_BB_ADAPTIVE_SOML; phydm_soml_on_off(dm, SOML_ON); } void phydm_adaptive_soml_para_set(void *dm_void, u8 train_num, u8 intvl, u8 period, u8 delay_time) { struct dm_struct *dm = (struct dm_struct *)dm_void; struct adaptive_soml *soml_tab = &dm->dm_soml_table; soml_tab->soml_train_num = train_num; soml_tab->soml_intvl = intvl; soml_tab->soml_period = period; soml_tab->soml_delay_time = delay_time; } #endif /* @end of CONFIG_ADAPTIVE_SOML*/ void phydm_init_soft_ml_setting(void *dm_void) { struct dm_struct *dm = (struct dm_struct *)dm_void; u32 soml_mask = BIT(31) | BIT(30) | BIT(29) | BIT(28); #if (RTL8822B_SUPPORT == 1) if (!*dm->mp_mode) { if (dm->support_ic_type & ODM_RTL8822B) { phydm_somlrxhp_setting(dm, true); dm->bsomlenabled = true; } } #endif #if (RTL8821C_SUPPORT == 1) if (!*dm->mp_mode) { if (dm->support_ic_type & ODM_RTL8821C) odm_set_bb_reg(dm, R_0x19a8, soml_mask, 0xd); } #endif #if (RTL8195B_SUPPORT == 1) if (!*dm->mp_mode) { if (dm->support_ic_type & ODM_RTL8195B) odm_set_bb_reg(dm, R_0x19a8, soml_mask, 0xd); } #endif }