From 4c002343ad293d88a29ab853052ea3669c385e1e Mon Sep 17 00:00:00 2001 From: Edayilliam Jayadev Date: Tue, 27 Nov 2018 11:20:55 +0530 Subject: [PATCH] qcacmn: Time stamp WAR for spectral Spectral HW time stamp gets reset when a reset happens in within target. This can potentially result in unpredictable behaviour during classification. To mitigate this calculated offset is added to the time stamp value in the FFT report. HT = Spectral HW timer AT = Actual time stamp in spectral report CF = Time stamp correction factor CT = Corrected time stamp L = Time stamp in the last FFT report before reset F = Time stamp in the first FFT report after reset D = Time gap between the last spectral report before reset and the end of reset(This is provided by FW via direct DMA framework) ***Target Reset*** ^ | |<---D---->| time line---> _______________________________________________________ ^ ^ ^ ^ | | | | HT --> 0 L 0 F AT --> 0 L F CF --> 0 0 (L+D) CT --> 0 L (F+L+D) Spectral driver corrects the time stamp received from target using the following formula and sends upwards. CT(Corrected time stamp) = AT(Actual time stamp) + CF(Correction Factor) Calculation of Correction factor (CF):- --------------------------------------- Initialization : CF = 0 CF += (L + D) (Done only for the first spectral report after reset) This scheme takes care of the wrap around in the 32 bit time stamp which would have occurred if the timer was not restarted due to target reset. CRs-Fixed: 2356382 2355486 Change-Id: I17b55d39eb91eb03b867bcfddaf3eb03d1fc5d1b --- target_if/spectral/target_if_spectral.c | 4 ++++ target_if/spectral/target_if_spectral.h | 6 ++++++ .../spectral/target_if_spectral_phyerr.c | 19 +++++++++++++++---- wmi/inc/wmi_unified_dbr_param.h | 2 ++ wmi/src/wmi_unified_dbr_tlv.c | 5 ++++- 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/target_if/spectral/target_if_spectral.c b/target_if/spectral/target_if_spectral.c index a42f06a3dd..16221559b2 100644 --- a/target_if/spectral/target_if_spectral.c +++ b/target_if/spectral/target_if_spectral.c @@ -1973,6 +1973,8 @@ target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev) spectral->inband_fftbin_size_adj = 0; spectral->null_fftbin_adj = 0; } + spectral->last_fft_timestamp = 0; + spectral->timestamp_war_offset = 0; if ((target_type == TARGET_TYPE_QCA8074) || (target_type == TARGET_TYPE_QCA8074V2) || @@ -2562,6 +2564,8 @@ target_if_spectral_scan_enable_params(struct target_if_spectral *spectral, if (!p_sops->is_spectral_active(spectral)) { p_sops->configure_spectral(spectral, spectral_params); p_sops->start_spectral_scan(spectral); + spectral->timestamp_war_offset = 0; + spectral->last_fft_timestamp = 0; } else { } diff --git a/target_if/spectral/target_if_spectral.h b/target_if/spectral/target_if_spectral.h index e62f39fe00..ee47a60909 100644 --- a/target_if/spectral/target_if_spectral.h +++ b/target_if/spectral/target_if_spectral.h @@ -381,10 +381,12 @@ struct spectral_sscan_report_gen3 { * struct Spectral_report - spectral report * @data: Report buffer * @noisefloor: Noise floor values + * @reset_delay: Time taken for warm reset in us */ struct spectral_report { uint8_t *data; int32_t noisefloor[DBR_MAX_CHAINS]; + uint32_t reset_delay; }; #endif /* END of spectral GEN III HW specific details */ @@ -796,6 +798,8 @@ struct wmi_spectral_cmd_ops { * (as expected), but cannot arrange for a smaller length to be reported by HW. * In these circumstances, the driver would have to disregard the NULL bins and * report a bin count of 0 to higher layers. + * @last_fft_timestamp: last fft report timestamp + * @timestamp_war_offset: Offset to be added to correct timestamp */ struct target_if_spectral { struct wlan_objmgr_pdev *pdev_obj; @@ -902,6 +906,8 @@ struct target_if_spectral { u_int8_t null_fftbin_adj; enum spectral_160mhz_report_delivery_state state_160mhz_delivery; void *spectral_report_cache; + uint32_t last_fft_timestamp; + uint32_t timestamp_war_offset; }; /** diff --git a/target_if/spectral/target_if_spectral_phyerr.c b/target_if/spectral/target_if_spectral_phyerr.c index 0b9566258c..05d4ea8381 100644 --- a/target_if/spectral/target_if_spectral_phyerr.c +++ b/target_if/spectral/target_if_spectral_phyerr.c @@ -1577,9 +1577,17 @@ target_if_consume_spectral_report_gen3( } } - tsf64 = p_fft_report->fft_timestamp; target_if_process_sfft_report_gen3(p_fft_report, p_sfft); detector_id = p_sfft->fft_detector_id; + + if (report->reset_delay) { + spectral->timestamp_war_offset += (report->reset_delay + + spectral->last_fft_timestamp); + } + tsf64 = p_sfft->timestamp; + spectral->last_fft_timestamp = p_sfft->timestamp; + tsf64 += spectral->timestamp_war_offset; + /* Agile detector is not supported */ if (detector_id >= SPECTRAL_DETECTOR_AGILE) { spectral->diag_stats.spectral_invalid_detector_id++; @@ -1805,9 +1813,12 @@ int target_if_spectral_process_report_gen3( } report.data = payload->vaddr; - if (payload->meta_data_valid) - qdf_mem_copy(report.noisefloor, &payload->meta_data, - sizeof(payload->meta_data)); + if (payload->meta_data_valid) { + qdf_mem_copy(report.noisefloor, payload->meta_data.noisefloor, + qdf_min(sizeof(report.noisefloor), + sizeof(payload->meta_data.noisefloor))); + report.reset_delay = payload->meta_data.reset_delay; + } if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) { spectral_debug("Printing the spectral phyerr buffer for debug"); diff --git a/wmi/inc/wmi_unified_dbr_param.h b/wmi/inc/wmi_unified_dbr_param.h index a09db77f21..f0f903287f 100644 --- a/wmi/inc/wmi_unified_dbr_param.h +++ b/wmi/inc/wmi_unified_dbr_param.h @@ -110,9 +110,11 @@ struct direct_buf_rx_cfg_req { * struct direct_buf_rx_metadata: direct buffer metadata * * @noisefloor: noisefloor + * @reset_delay: reset delay */ struct direct_buf_rx_metadata { int32_t noisefloor[WMI_HOST_MAX_NUM_CHAINS]; + uint32_t reset_delay; }; /** diff --git a/wmi/src/wmi_unified_dbr_tlv.c b/wmi/src/wmi_unified_dbr_tlv.c index 7a3b40bfcf..5cb110f6c0 100644 --- a/wmi/src/wmi_unified_dbr_tlv.c +++ b/wmi/src/wmi_unified_dbr_tlv.c @@ -154,7 +154,10 @@ static QDF_STATUS extract_dbr_buf_metadata_tlv( } qdf_mem_copy(param->noisefloor, entry->noise_floor, - sizeof(entry->noise_floor)); + qdf_min(sizeof(entry->noise_floor), + sizeof(param->noisefloor))); + param->reset_delay = entry->reset_delay; + return QDF_STATUS_SUCCESS; }