Parcourir la source

qcacld-3.0: Add support for cumulative mlo vdev stats

Add support for aggregation of vdev station stats
in case of mlo connection.

Change-Id: I387baa6971d5a16083a8e29257b4cfd1dbeba0d3
CRs-Fixed: 3531561
Aditya Kodukula il y a 1 an
Parent
commit
f71fc8b924

+ 2 - 2
components/target_if/cp_stats/src/target_if_mc_cp_stats.c

@@ -901,9 +901,9 @@ target_if_cp_stats_extract_vdev_extd_stats(struct wmi_unified *wmi_hdl,
 			qdf_mem_free(stats);
 			goto end;
 		}
-		ev->vdev_extd_stats[i].vdev_id = stats[i].vdev_id;
+		ev->vdev_extd_stats[i].vdev_id = stats[0].vdev_id;
 		ev->vdev_extd_stats[i].is_mlo_vdev_active =
-						stats[i].is_mlo_vdev_active;
+						stats[0].is_mlo_vdev_active;
 	}
 
 	qdf_mem_free(stats);

+ 34 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -587,6 +587,40 @@ struct hdd_peer_stats {
 	uint32_t fcs_count;
 };
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
+/**
+ * struct wlan_hdd_station_stats_info - Station stats info
+ * @signal: Signal strength of last received PPDU
+ * @signal_avg: Average signal strength
+ * @chain_signal_avg: Per-chain signal strength average
+ * @rxrate: Last unicast data frame rx rate
+ * @txrate: Current unicasr tx rate
+ * @rx_bytes: Total received bytes (MPDU length)
+ * @tx_bytes: Total transmitted bytes (MPDU length)
+ * @rx_packets: Total received packets (MSDUs and MMPDUs)
+ * @tx_packets: Total transmitted packets (MSDUs and MMPDUs)
+ * @tx_retries: Cumulative retry count (MPDU)
+ * @tx_failed: Number of failed transmissions (MPDUs)
+ * @rx_mpdu_count: Number of MPDUs received from this station
+ * @fcs_err_count: Number of MPDUs received from this station with an FCS error
+ */
+struct wlan_hdd_station_stats_info {
+	int8_t signal;
+	int8_t signal_avg;
+	int8_t chain_signal_avg[IEEE80211_MAX_CHAINS];
+	struct rate_info txrate;
+	struct rate_info rxrate;
+	uint64_t rx_bytes;
+	uint64_t tx_bytes;
+	uint32_t rx_packets;
+	uint32_t tx_packets;
+	uint32_t tx_retries;
+	uint32_t tx_failed;
+	uint32_t rx_mpdu_count;
+	uint32_t fcs_err_count;
+};
+#endif
+
 #define MAX_SUBTYPES_TRACKED	4
 
 struct hdd_stats {

+ 294 - 138
core/hdd/src/wlan_hdd_stats.c

@@ -451,6 +451,21 @@ int wlan_hdd_qmi_put_suspend(void)
 }
 #endif /* end if of WLAN_FEATURE_WMI_SEND_RECV_QMI */
 
+/*
+ * wlan_hdd_is_legacy_adapter() - Check if adapter is legacy or mlo
+ * @adapter: Pointer to hdd adapter
+ *
+ * Return: True if legacy connection, else False
+ */
+static bool wlan_hdd_is_legacy_adapter(struct hdd_adapter *adapter)
+{
+	if (hdd_adapter_is_ml_adapter(adapter) ||
+	    hdd_adapter_is_link_adapter(adapter))
+		return false;
+
+	return true;
+}
+
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
 
 /**
@@ -6229,131 +6244,6 @@ wlan_hdd_refill_actual_rate(struct station_info *sinfo,
 }
 #endif
 
-#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
-static inline void wlan_hdd_populate_mlo_rssi(int8_t *rssi, int8_t *link_rssi)
-{
-	if (!(*rssi) || !(*link_rssi))
-		*rssi = QDF_MIN(*rssi, *link_rssi);
-	else
-		*rssi = QDF_MAX(*rssi, *link_rssi);
-}
-
-static inline void wlan_hdd_populate_mlo_snr(int32_t *snr, int32_t *link_snr)
-{
-	*snr = QDF_MAX(*snr, *link_snr);
-}
-
-#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
-static inline void
-wlan_hdd_mlo_update_stats_info(struct wlan_hdd_link_info *link_info)
-{
-	int8_t *rssi, *link_rssi;
-	uint32_t *snr, *link_snr;
-	struct wlan_objmgr_vdev *vdev;
-	struct wlan_hdd_link_info *iter_link_info;
-	struct hdd_station_ctx *sta_ctx;
-	struct hdd_adapter *adapter = link_info->adapter;
-
-	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
-
-	rssi = &link_info->hdd_stats.summary_stat.rssi;
-	snr = &link_info->hdd_stats.summary_stat.snr;
-
-	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
-	if (!vdev)
-		return;
-
-	/* For non ML connection just
-	 * update the values in the adapter
-	 */
-	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
-		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
-		goto stat_update;
-	}
-	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
-
-	hdd_debug("Link0: RSSI: %d, SNR: %d", *rssi, *snr);
-	hdd_adapter_for_each_active_link_info(adapter, iter_link_info) {
-		if (link_info == iter_link_info)
-			continue;
-
-		link_rssi = &iter_link_info->hdd_stats.summary_stat.rssi;
-		wlan_hdd_populate_mlo_rssi(rssi, link_rssi);
-
-		link_snr = &iter_link_info->hdd_stats.summary_stat.snr;
-		wlan_hdd_populate_mlo_snr(snr, link_snr);
-		hdd_debug("Partner Link: RSSI: %d, SNR: %d",
-			  *link_rssi, *link_snr);
-	}
-stat_update:
-	link_info->rssi = *rssi;
-	link_info->snr = *snr;
-}
-#else
-static void wlan_hdd_mlo_update_stats_info(struct wlan_hdd_link_info *link_info)
-{
-	int8_t *rssi, *link_rssi;
-	uint32_t *snr, *link_snr;
-	uint8_t iter;
-	struct hdd_mlo_adapter_info *mlo_adapter_info;
-	struct hdd_adapter *link_adapter, *ml_adapter, *adapter;
-	struct wlan_objmgr_vdev *vdev;
-
-	adapter = link_info->adapter;
-	if (hdd_adapter_is_link_adapter(adapter))
-		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
-	else
-		ml_adapter = adapter;
-
-	rssi = &ml_adapter->deflink->hdd_stats.summary_stat.rssi;
-	snr = &ml_adapter->deflink->hdd_stats.summary_stat.snr;
-
-	vdev = hdd_objmgr_get_vdev_by_user(link_info,
-					   WLAN_OSIF_STATS_ID);
-	if (!vdev)
-		return;
-
-	/* For non ML connection just
-	 * update the values in the adapter
-	 */
-	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
-		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
-		goto stat_update;
-	}
-	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
-
-	hdd_debug("Link0: RSSI: %d, SNR: %d", *rssi, *snr);
-
-	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
-	for (iter = 0; iter < WLAN_MAX_MLD; iter++) {
-		link_adapter = mlo_adapter_info->link_adapter[iter];
-		if (!link_adapter ||
-		    hdd_adapter_is_associated_with_ml_adapter(link_adapter))
-			continue;
-
-		link_rssi = &link_adapter->deflink->hdd_stats.summary_stat.rssi;
-		wlan_hdd_populate_mlo_rssi(rssi, link_rssi);
-
-		link_snr = &link_adapter->deflink->hdd_stats.summary_stat.snr;
-		wlan_hdd_populate_mlo_snr(snr, link_snr);
-		hdd_debug("Partner Link: RSSI: %d, SNR: %d",
-			  *link_rssi, *link_snr);
-	}
-
-stat_update:
-	link_info->rssi = *rssi;
-	link_info->snr = *snr;
-}
-#endif
-#else
-static inline void
-wlan_hdd_mlo_update_stats_info(struct wlan_hdd_link_info *link_info)
-{
-	link_info->rssi = link_info->hdd_stats.summary_stat.rssi;
-	link_info->snr = link_info->hdd_stats.summary_stat.snr;
-}
-#endif
-
 static void wlan_hdd_update_rssi(struct wlan_hdd_link_info *link_info,
 				 struct station_info *sinfo)
 {
@@ -6368,6 +6258,8 @@ static void wlan_hdd_update_rssi(struct wlan_hdd_link_info *link_info,
 	}
 
 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+	link_info->rssi = link_info->hdd_stats.summary_stat.rssi;
+	link_info->snr = link_info->hdd_stats.summary_stat.snr;
 	snr = link_info->snr;
 
 	/* for new connection there might be no valid previous RSSI */
@@ -6633,8 +6525,6 @@ static int wlan_hdd_get_sta_stats(struct wlan_hdd_link_info *link_info,
 
 	wlan_hdd_get_peer_rx_rate_stats(link_info);
 
-	wlan_hdd_mlo_update_stats_info(link_info);
-
 	wlan_hdd_update_rssi(link_info, sinfo);
 
 	/*
@@ -6687,6 +6577,232 @@ hdd_get_link_info_by_bssid(struct hdd_context *hdd_ctx, const uint8_t *bssid)
 	return NULL;
 }
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
+/**
+ * wlan_hdd_is_per_link_stats_supported - Check if FW supports per link stats
+ * @hdd_ctx: Pointer to hdd context
+ *
+ * Return: true if FW supports, else False
+ */
+static bool
+wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
+{
+	if (hdd_ctx->is_mlo_per_link_stats_supported) {
+		hdd_debug("mlo per link stats is not supported by FW");
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * wlan_hdd_copy_hdd_stats_to_sinfo() - Copy hdd station stats info to sinfo
+ * @sinfo: Pointer to kernel station info struct
+ * @hdd_sinfo: Pointer to the hdd station stats info struct
+ *
+ * Return: none
+ */
+static void
+wlan_hdd_copy_hdd_stats_to_sinfo(struct station_info *sinfo,
+				 struct wlan_hdd_station_stats_info *hdd_sinfo)
+{
+	uint8_t i;
+
+	sinfo->signal = hdd_sinfo->signal;
+	sinfo->signal_avg = hdd_sinfo->signal_avg;
+	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
+		sinfo->chain_signal_avg[i] = hdd_sinfo->chain_signal_avg[i];
+
+	qdf_mem_copy(&sinfo->txrate,
+		     &hdd_sinfo->txrate, sizeof(sinfo->txrate));
+
+	qdf_mem_copy(&sinfo->rxrate,
+		     &hdd_sinfo->rxrate, sizeof(sinfo->rxrate));
+	sinfo->rx_bytes = hdd_sinfo->rx_bytes;
+	sinfo->tx_bytes = hdd_sinfo->tx_bytes;
+	sinfo->rx_packets = hdd_sinfo->rx_packets;
+	sinfo->tx_packets = hdd_sinfo->tx_packets;
+	sinfo->tx_retries = hdd_sinfo->tx_retries;
+	sinfo->tx_failed = hdd_sinfo->tx_failed;
+	sinfo->rx_mpdu_count = hdd_sinfo->rx_mpdu_count;
+	sinfo->fcs_err_count = hdd_sinfo->fcs_err_count;
+}
+
+/*
+ * wlan_hdd_update_mlo_rate_info() - Populate mlo station stats rate info
+ * @hdd_sinfo: Pointer to hdd stats station info struct
+ * @sinfo: Pointer to kernel station info struct
+ *
+ * Return: none
+ */
+static void
+wlan_hdd_update_mlo_rate_info(struct wlan_hdd_station_stats_info *hdd_sinfo,
+			      struct station_info *sinfo)
+{
+	uint8_t i;
+
+	hdd_sinfo->signal = sinfo->signal;
+	hdd_sinfo->signal_avg = sinfo->signal_avg;
+	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
+		hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i];
+
+	qdf_mem_copy(&hdd_sinfo->txrate,
+		     &sinfo->txrate, sizeof(sinfo->txrate));
+
+	qdf_mem_copy(&hdd_sinfo->rxrate,
+		     &sinfo->rxrate, sizeof(sinfo->rxrate));
+}
+
+/*
+ * wlan_hdd_update_mlo_sinfo() - Populate mlo stats station info
+ * @link_info: Link info pointer of STA adapter
+ * @hdd_sinfo: Pointer to hdd stats station info struct
+ * @sinfo: Pointer to kernel station info struct
+ *
+ * Return: none
+ */
+static void
+wlan_hdd_update_mlo_sinfo(struct wlan_hdd_link_info *link_info,
+			  struct wlan_hdd_station_stats_info *hdd_sinfo,
+			  struct station_info *sinfo)
+{
+	if (!link_info->is_mlo_vdev_active) {
+		hdd_nofl_debug("vdev_id[%d] is inactive", link_info->vdev_id);
+		return;
+	}
+
+	if (!hdd_adapter_is_link_adapter(link_info->adapter))
+		/* Send Assoc Link's Signal and Rates to userspace */
+		wlan_hdd_update_mlo_rate_info(hdd_sinfo, sinfo);
+
+	/* If Partner link RSSI is better then update
+	 * Partner Link's Signal and Rates to userspace
+	 */
+	if (hdd_adapter_is_link_adapter(link_info->adapter) &&
+	    sinfo->signal > hdd_sinfo->signal) {
+		hdd_nofl_debug("Updating rates for vdev_id[%d]",
+			       link_info->vdev_id);
+		wlan_hdd_update_mlo_rate_info(hdd_sinfo, sinfo);
+	}
+
+	/* Send cumulative Tx/Rx packets and bytes data
+	 * of all active links to userspace
+	 */
+	hdd_sinfo->rx_bytes += sinfo->rx_bytes;
+	hdd_sinfo->tx_bytes += sinfo->tx_bytes;
+	hdd_sinfo->rx_packets += sinfo->rx_packets;
+	hdd_sinfo->tx_packets += sinfo->tx_packets;
+	hdd_sinfo->tx_retries += sinfo->tx_retries;
+	hdd_sinfo->tx_failed += sinfo->tx_failed;
+	hdd_sinfo->rx_mpdu_count += sinfo->rx_mpdu_count;
+	hdd_sinfo->fcs_err_count += sinfo->fcs_err_count;
+}
+
+/**
+ * wlan_hdd_get_mlo_sta_stats - get aggregate STA stats for MLO
+ * @link_info: Link info pointer of STA adapter to get stats for
+ * @mac: mac address
+ * @sinfo: kernel station_info struct to populate
+ *
+ * Return: 0 on success; errno on failure
+ */
+static int wlan_hdd_get_mlo_sta_stats(struct wlan_hdd_link_info *link_info,
+				      const uint8_t *mac,
+				      struct station_info *sinfo)
+{
+	struct hdd_adapter *ml_adapter, *link_adapter;
+	struct hdd_mlo_adapter_info *mlo_adapter_info;
+	struct wlan_hdd_station_stats_info hdd_sinfo = {0};
+	uint8_t i;
+
+	ml_adapter = link_info->adapter;
+	if (hdd_adapter_is_link_adapter(ml_adapter))
+		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(
+							link_info->adapter);
+
+	wlan_hdd_get_sta_stats(ml_adapter->deflink, mac, sinfo);
+	wlan_hdd_update_mlo_sinfo(ml_adapter->deflink, &hdd_sinfo, sinfo);
+
+	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
+	for (i = 0; i < WLAN_MAX_MLD; i++) {
+		link_adapter = mlo_adapter_info->link_adapter[i];
+		if (!link_adapter ||
+		    hdd_adapter_is_associated_with_ml_adapter(link_adapter))
+			continue;
+
+		wlan_hdd_get_sta_stats(link_adapter->deflink, mac, sinfo);
+		wlan_hdd_update_mlo_sinfo(link_adapter->deflink, &hdd_sinfo,
+					  sinfo);
+	}
+
+	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo);
+
+	return 0;
+}
+#else
+static inline bool
+wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
+{
+	return false;
+}
+
+static int wlan_hdd_get_mlo_sta_stats(struct wlan_hdd_link_info *link_info,
+				      const uint8_t *mac,
+				      struct station_info *sinfo)
+{
+	return wlan_hdd_get_sta_stats(link_info, mac, sinfo);
+}
+#endif
+
+/*
+ * wlan_hdd_send_mlo_aggregated_stats() - Whether to send aggregated stats
+ * @link_info: Link info pointer of STA adapter
+ * @mac: mac address
+ *
+ * Return: True if requested on mld_mac or FW doesn't support per link stats
+ *	   else False
+ */
+static bool
+wlan_hdd_send_mlo_aggregated_stats(struct wlan_hdd_link_info *link_info,
+				   const uint8_t *mac)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct hdd_adapter *adapter = link_info->adapter;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	bool ret = false;
+
+	if (wlan_hdd_is_legacy_adapter(adapter)) {
+		hdd_nofl_debug("Fetching station stats for legacy connection");
+		return false;
+	}
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
+	if (!vdev) {
+		hdd_err("invalid vdev");
+		return false;
+	}
+
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev)) {
+		if (qdf_is_macaddr_equal(&adapter->mld_addr,
+					 (struct qdf_mac_addr *)mac)) {
+			hdd_nofl_debug("Fetching aggregated station stats");
+			ret = true;
+			goto end;
+		}
+
+		if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx)) {
+			hdd_debug("FW doesn't support per link stats."
+				  " Fetching aggregated station stats");
+			ret = true;
+			goto end;
+		}
+	}
+	hdd_debug("Fetching stats for mlo_vdev_id[%u]", link_info->vdev_id);
+end:
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
+	return ret;
+}
+
 /**
  * __wlan_hdd_cfg80211_get_station() - get station statistics
  * @wiphy: Pointer to wiphy
@@ -6758,7 +6874,11 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
 			link_info = adapter->deflink;
 			hdd_err_rl("the bssid is invalid");
 		}
-		return wlan_hdd_get_sta_stats(link_info, mac, sinfo);
+
+		if (!wlan_hdd_send_mlo_aggregated_stats(link_info, mac))
+			return wlan_hdd_get_sta_stats(link_info, mac, sinfo);
+
+		return wlan_hdd_get_mlo_sta_stats(link_info, mac, sinfo);
 	}
 }
 
@@ -6909,9 +7029,14 @@ static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
 			return -ENOENT;
 
 		qdf_mem_copy(mac, dev->dev_addr, QDF_MAC_ADDR_SIZE);
-		errno = wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
-	}
 
+		if (!wlan_hdd_send_mlo_aggregated_stats(adapter->deflink, mac))
+			return wlan_hdd_get_sta_stats(adapter->deflink,
+						      mac, sinfo);
+
+		errno = wlan_hdd_get_mlo_sta_stats(adapter->deflink,
+						   mac, sinfo);
+	}
 	return errno;
 }
 
@@ -7714,12 +7839,48 @@ int wlan_hdd_get_link_speed(struct wlan_hdd_link_info *link_info,
 }
 
 #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER
+/**
+ * wlan_hdd_get_per_peer_stats - get per peer stats if supported by FW
+ * @link_info: Link info pointer of STA adapter to get stats for
+ * @peer_stats: Pointer to peer_stats
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+wlan_hdd_get_per_peer_stats(struct wlan_hdd_link_info *link_info,
+			    struct cdp_peer_stats *peer_stats)
+{
+	QDF_STATUS status;
+	ol_txrx_soc_handle soc;
+	uint8_t *peer_mac;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
+
+	if (wlan_hdd_validate_context(hdd_ctx)) {
+		hdd_err("invalid hdd_ctx");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	soc = cds_get_context(QDF_MODULE_ID_SOC);
+	peer_mac = link_info->session.station.conn_info.bssid.bytes;
+
+	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx)) {
+		hdd_debug("mlo per link stats is not supported by FW");
+		status = cdp_host_get_peer_stats(soc, link_info->vdev_id,
+						 peer_mac, peer_stats);
+		return status;
+	}
+
+	status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
+						 peer_mac, peer_stats,
+						 CDP_WILD_PEER_TYPE,
+						 WLAN_MAX_MLD);
+	return status;
+}
+
 void wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info *link_info)
 {
 	struct cdp_peer_stats *peer_stats;
 	QDF_STATUS status;
-	ol_txrx_soc_handle soc;
-	uint8_t *peer_mac_addr;
 	struct wlan_objmgr_psoc *psoc;
 	struct hdd_stats *hdd_stats = &link_info->hdd_stats;
 
@@ -7727,22 +7888,17 @@ void wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info *link_info)
 	if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc))
 		return;
 
-	soc = cds_get_context(QDF_MODULE_ID_SOC);
-
 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
 	if (!peer_stats)
 		return;
 
-	peer_mac_addr = link_info->session.station.conn_info.bssid.bytes;
-
 	/*
 	 * If failed to get RX rates info, assign an invalid value to the
 	 * preamble, used to tell driver to report max rates. The rx_rate
 	 * and rx_mcs_index are also assigned with tx_rate and tx_mcs_index
 	 * if they are invalid after ASSOC/REASSOC/ROAMING
 	 */
-	status = cdp_host_get_peer_stats(soc, link_info->vdev_id,
-					 peer_mac_addr, peer_stats);
+	status = wlan_hdd_get_per_peer_stats(link_info, peer_stats);
 	if (qdf_unlikely(QDF_IS_STATUS_ERROR(status)) ||
 	    qdf_unlikely(peer_stats->rx.last_rx_rate == 0)) {
 		hdd_debug("No rates, reporting max rate, rx mcs=%d, status=%d",