Browse Source

qcacld-3.0: Register spectral scan to wmi handler

Register spectral scan phy err handler to wmi
event handler.

Change-Id: I577223729553cc6f90f67ae33e4cb096156791d0
CRs-Fixed: 2175941
Sandeep Puligilla 7 years ago
parent
commit
707cea53d5
1 changed files with 365 additions and 0 deletions
  1. 365 0
      core/wma/src/wma_main.c

+ 365 - 0
core/wma/src/wma_main.c

@@ -2348,6 +2348,337 @@ static int wma_flush_complete_evt_handler(void *handle,
 			WLAN_LOG_INDICATOR_FIRMWARE, reason_code);
 	return QDF_STATUS_E_FAILURE;
 }
+/**
+ * wma_extract_single_phyerr_spectral() - extract single phy error from event
+ * @handle: wma handle
+ * @param evt_buf: pointer to event buffer
+ * @param datalen: data length of event buffer
+ * @param buf_offset: Pointer to hold value of current event buffer offset
+ * post extraction
+ * @param phyerr: Pointer to hold phyerr
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS wma_extract_single_phyerr_spectral(void *handle,
+		void *evt_buf,
+		uint16_t datalen, uint16_t *buf_offset,
+		wmi_host_phyerr_t *phyerr)
+{
+	wmi_single_phyerr_rx_event *ev;
+	int n = *buf_offset;
+
+	ev = (wmi_single_phyerr_rx_event *)((uint8_t *)evt_buf + n);
+
+	if (n < datalen) {
+		/* ensure there's at least space for the header */
+		if ((datalen - n) < sizeof(ev->hdr)) {
+			WMA_LOGE("%s: not enough space? (datalen=%d, n=%d, hdr=%zu bytes",
+					__func__, datalen, n, sizeof(ev->hdr));
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		phyerr->bufp = ev->bufp;
+		phyerr->buf_len = ev->hdr.buf_len;
+
+		/*
+		 * Sanity check the buffer length of the event against
+		 * what we currently have.
+		 *
+		 * Since buf_len is 32 bits, we check if it overflows
+		 * a large 32 bit value.  It's not 0x7fffffff because
+		 * we increase n by (buf_len + sizeof(hdr)), which would
+		 * in itself cause n to overflow.
+		 *
+		 * If "int" is 64 bits then this becomes a moot point.
+		 */
+		if (ev->hdr.buf_len > 0x7f000000) {
+			WMA_LOGE("%s: buf_len is garbage? (0x%x)",
+				__func__, ev->hdr.buf_len);
+			return QDF_STATUS_E_FAILURE;
+		}
+		if (n + ev->hdr.buf_len > datalen) {
+			WMA_LOGE("%s: buf_len exceeds available space n=%d, buf_len=%d, datalen=%d",
+				__func__, n, ev->hdr.buf_len, datalen);
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		phyerr->phy_err_code = WMI_UNIFIED_PHYERRCODE_GET(&ev->hdr);
+		phyerr->tsf_timestamp = ev->hdr.tsf_timestamp;
+
+#ifdef DEBUG_SPECTRAL_SCAN
+		WMA_LOGD("%s: len=%d, tsf=0x%08x, rssi = 0x%x/0x%x/0x%x/0x%x, comb rssi = 0x%x, phycode=%d",
+				__func__,
+				ev->hdr.buf_len,
+				ev->hdr.tsf_timestamp,
+				ev->hdr.rssi_chain0,
+				ev->hdr.rssi_chain1,
+				ev->hdr.rssi_chain2,
+				ev->hdr.rssi_chain3,
+				WMI_UNIFIED_RSSI_COMB_GET(&ev->hdr),
+					  phyerr->phy_err_code);
+
+		/*
+		 * For now, unroll this loop - the chain 'value' field isn't
+		 * a variable but glued together into a macro field definition.
+		 * Grr. :-)
+		 */
+		WMA_LOGD("%s: chain 0: raw=0x%08x; pri20=%d sec20=%d sec40=%d sec80=%d",
+				__func__,
+				ev->hdr.rssi_chain0,
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, PRI20),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC20),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC40),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC80));
+
+		WMA_LOGD("%s: chain 1: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d",
+				__func__,
+				ev->hdr.rssi_chain1,
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, PRI20),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC20),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC40),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC80));
+
+		WMA_LOGD("%s: chain 2: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d",
+				__func__,
+				ev->hdr.rssi_chain2,
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, PRI20),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC20),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC40),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC80));
+
+		WMA_LOGD("%s: chain 3: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d",
+				__func__,
+				ev->hdr.rssi_chain3,
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, PRI20),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC20),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC40),
+				WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC80));
+
+
+		WMA_LOGD("%s: freq_info_1=0x%08x, freq_info_2=0x%08x",
+			   __func__, ev->hdr.freq_info_1, ev->hdr.freq_info_2);
+
+		/*
+		 * The NF chain values are signed and are negative - hence
+		 * the cast evilness.
+		 */
+		WMA_LOGD("%s: nfval[1]=0x%08x, nfval[2]=0x%08x, nf=%d/%d/%d/%d, freq1=%d, freq2=%d, cw=%d",
+				__func__,
+				ev->hdr.nf_list_1,
+				ev->hdr.nf_list_2,
+				(int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 0),
+				(int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 1),
+				(int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 2),
+				(int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 3),
+				WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 1),
+				WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 2),
+				WMI_UNIFIED_CHWIDTH_GET(&ev->hdr));
+#endif
+
+		/*
+		 * If required, pass spectral events to the spectral module
+		 */
+		if (ev->hdr.buf_len > 0) {
+
+			/* Initialize the NF values to Zero. */
+			phyerr->rf_info.noise_floor[0] =
+			    WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 0);
+			phyerr->rf_info.noise_floor[1] =
+			    WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 1);
+			phyerr->rf_info.noise_floor[2] =
+			    WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 2);
+			phyerr->rf_info.noise_floor[3] =
+			    WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 3);
+
+			/* populate the rf info */
+			phyerr->rf_info.rssi_comb =
+			    WMI_UNIFIED_RSSI_COMB_GET(&ev->hdr);
+
+			/* Need to unroll loop due to macro
+			 * constraints chain 0
+			 */
+			phyerr->rf_info.pc_rssi_info[0].rssi_pri20 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, PRI20);
+			phyerr->rf_info.pc_rssi_info[0].rssi_sec20 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC20);
+			phyerr->rf_info.pc_rssi_info[0].rssi_sec40 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC40);
+			phyerr->rf_info.pc_rssi_info[0].rssi_sec80 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC80);
+
+			/* chain 1 */
+			phyerr->rf_info.pc_rssi_info[1].rssi_pri20 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, PRI20);
+			phyerr->rf_info.pc_rssi_info[1].rssi_sec20 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC20);
+			phyerr->rf_info.pc_rssi_info[1].rssi_sec40 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC40);
+			phyerr->rf_info.pc_rssi_info[1].rssi_sec80 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC80);
+
+			/* chain 2 */
+			phyerr->rf_info.pc_rssi_info[2].rssi_pri20 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, PRI20);
+			phyerr->rf_info.pc_rssi_info[2].rssi_sec20 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC20);
+			phyerr->rf_info.pc_rssi_info[2].rssi_sec40 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC40);
+			phyerr->rf_info.pc_rssi_info[2].rssi_sec80 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC80);
+
+			/* chain 3 */
+			phyerr->rf_info.pc_rssi_info[3].rssi_pri20 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, PRI20);
+			phyerr->rf_info.pc_rssi_info[3].rssi_sec20 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC20);
+			phyerr->rf_info.pc_rssi_info[3].rssi_sec40 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC40);
+			phyerr->rf_info.pc_rssi_info[3].rssi_sec80 =
+			WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC80);
+
+			phyerr->chan_info.center_freq1 =
+			    WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 1);
+			phyerr->chan_info.center_freq2 =
+			    WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 2);
+
+		}
+
+		/*
+		 * Advance the buffer pointer to the next PHY error.
+		 * buflen is the length of this payload, so we need to
+		 * advance past the current header _AND_ the payload.
+		 */
+		 n += sizeof(*ev) + ev->hdr.buf_len;
+	}
+	*buf_offset += n;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wma_extract_comb_phyerr_spectral() - extract comb phy error from event
+ * @handle: wma handle
+ * @param evt_buf: pointer to event buffer
+ * @param datalen: data length of event buffer
+ * @param buf_offset: Pointer to hold value of current event buffer offset
+ * post extraction
+ * @param phyerr: Pointer to hold phyerr
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS wma_extract_comb_phyerr_spectral(void *handle, void *data,
+		uint16_t datalen, uint16_t *buf_offset,
+		wmi_host_phyerr_t *phyerr)
+{
+	WMI_PHYERR_EVENTID_param_tlvs *param_tlvs;
+	wmi_comb_phyerr_rx_hdr *pe_hdr;
+
+	param_tlvs = (WMI_PHYERR_EVENTID_param_tlvs *) data;
+	if (!param_tlvs) {
+		WMA_LOGE("%s: Received NULL data from FW", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pe_hdr = param_tlvs->hdr;
+	if (pe_hdr == NULL) {
+		WMA_LOGE("%s: Received Data PE Header is NULL", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Ensure it's at least the size of the header */
+	if (datalen < sizeof(*pe_hdr)) {
+		WMA_LOGE("%s:  Expected minimum size %zu, received %d",
+			 __func__, sizeof(*pe_hdr), datalen);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/*
+	 * Reconstruct the 64 bit event TSF. This isn't from the MAC, it's
+	 * at the time the event was sent to us, the TSF value will be
+	 * in the future.
+	 */
+	phyerr->tsf64 = pe_hdr->tsf_l32;
+	phyerr->tsf64 |= (((uint64_t) pe_hdr->tsf_u32) << 32);
+
+	phyerr->bufp = param_tlvs->bufp;
+	phyerr->buf_len = pe_hdr->buf_len;
+
+	phyerr->phy_err_mask0 = pe_hdr->rsPhyErrMask0;
+	phyerr->phy_err_mask1 = pe_hdr->rsPhyErrMask1;
+
+	*buf_offset = sizeof(*pe_hdr) + sizeof(uint32_t);
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * spectral_phyerr_event_handler() - spectral phyerr event handler
+ * @handle: wma handle
+ * @data: data buffer
+ * @datalen: buffer length
+ *
+ * Return:  QDF_STATUS
+ */
+static QDF_STATUS spectral_phyerr_event_handler(void *handle,
+					uint8_t *data, uint32_t datalen)
+{
+	tp_wma_handle wma = (tp_wma_handle) handle;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint16_t buf_offset, event_buf_len = 0;
+	wmi_single_phyerr_rx_event *ev;
+	wmi_host_phyerr_t phyerr;
+	struct target_if_spectral_rfqual_info rfqual_info;
+	struct target_if_spectral_chan_info chan_info;
+	struct target_if_spectral_acs_stats acs_stats;
+
+	if (NULL == wma) {
+		WMA_LOGE("%s:wma handle is NULL", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	memset(&phyerr, 0, sizeof(wmi_host_phyerr_t));
+	if (wma_extract_comb_phyerr_spectral(handle, data,
+			datalen, &buf_offset, &phyerr)) {
+		WMA_LOGE("%s: extract comb phyerr failed", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ev = (wmi_single_phyerr_rx_event *)phyerr.bufp;
+	event_buf_len = phyerr.buf_len;
+	/* Loop over the bufp, extracting out phyerrors */
+	buf_offset = 0;
+	while (buf_offset < event_buf_len) {
+		if (wma_extract_single_phyerr_spectral(handle, ev,
+			event_buf_len, &buf_offset, &phyerr)) {
+			WMA_LOGE("%s: extract single phy err failed", __func__);
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		if (phyerr.buf_len > 0) {
+			if (sizeof(phyerr.rf_info) > sizeof(rfqual_info))
+				qdf_mem_copy(&rfqual_info, &phyerr.rf_info,
+						sizeof(rfqual_info));
+			else
+				qdf_mem_copy(&rfqual_info, &phyerr.rf_info,
+						sizeof(phyerr.rf_info));
+
+			if (sizeof(phyerr.chan_info) > sizeof(chan_info))
+				qdf_mem_copy(&chan_info, &phyerr.chan_info,
+						sizeof(chan_info));
+			else
+				qdf_mem_copy(&chan_info, &phyerr.chan_info,
+						sizeof(phyerr.chan_info));
+
+			target_if_spectral_process_phyerr(wma->pdev, phyerr.bufp,
+							phyerr.buf_len,
+							&rfqual_info,
+							&chan_info,
+							phyerr.tsf64,
+							&acs_stats);
+		}
+	}
+
+	return status;
+}
 
 /**
  * wma_unified_phyerr_rx_event_handler() - phyerr event handler
@@ -2368,6 +2699,40 @@ static int wma_unified_phyerr_rx_event_handler(void *handle,
 	 * need complete testing of non offloaded DFS code before we enable
 	 * it in cmn code.
 	 **/
+	tp_wma_handle wma = (tp_wma_handle) handle;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	wmi_host_phyerr_t phyerr;
+	uint16_t buf_offset = 0;
+
+	if (NULL == wma) {
+		WMA_LOGE("%s:wma handle is NULL", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* sanity check on data length */
+	if (wma_extract_comb_phyerr_spectral(wma->wmi_handle, data,
+			datalen, &buf_offset, &phyerr) != QDF_STATUS_SUCCESS) {
+		WMA_LOGE("%s: extract phy error from comb phy event failure",
+				__func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* handle different PHY Error conditions */
+	if (((phyerr.phy_err_mask0 & (WMI_PHY_ERROR_MASK0_RADAR |
+				WMI_PHY_ERROR_MASK0_FALSE_RADAR_EXT |
+				WMI_PHY_ERROR_MASK0_SPECTRAL_SCAN)) == 0)) {
+		WMA_LOGD("%s:Unknown phy error event", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Handle Spectral or DFS PHY Error */
+	if (phyerr.phy_err_mask0 & (WMI_PHY_ERROR_MASK0_RADAR |
+				WMI_PHY_ERROR_MASK0_FALSE_RADAR_EXT)) {
+		/* Do nothing*/
+	} else if (phyerr.phy_err_mask0 & (WMI_PHY_ERROR_MASK0_SPECTRAL_SCAN |
+				WMI_PHY_ERROR_MASK0_FALSE_RADAR_EXT)) {
+		status = spectral_phyerr_event_handler(wma, data, datalen);
+	}
 	return QDF_STATUS_SUCCESS;
 }