Search Linux Wireless

RE: [PATCH 2/2] ath11k: add get_txpower mac ops

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> -----Original Message-----
> From: Jeff Johnson (QUIC) <quic_jjohnson@xxxxxxxxxxx>
> Sent: Thursday, June 2, 2022 20:21
> To: Aditya Kumar Singh (QUIC) <quic_adisi@xxxxxxxxxxx>;
> ath11k@xxxxxxxxxxxxxxxxxxx
> Cc: linux-wireless@xxxxxxxxxxxxxxx
> Subject: Re: [PATCH 2/2] ath11k: add get_txpower mac ops
> 
> On 6/1/2022 10:14 PM, Aditya Kumar Singh wrote:
> > Driver does not support get_txpower mac ops because of which
> > cfg80211 returns vif->bss_conf.txpower to user space. bss_conf.txpower
> > gets its value from ieee80211_channel->max_reg_power. However, the
> > final txpower is dependent on few other parameters apart from max
> > regulatory supported power. It is the firmware which knows about all
> > these parameters and considers the minimum for each packet
> transmission.
> >
> > All ath11k firmware reports the final tx power in firmware pdev stats
> > which falls under fw_stats.
> >
> > Add get_txpower mac ops to get the tx power from firmware leveraging
> > fw_stats and return it accordingly.
> >
> > Tested-on: IPQ8074 hw2.0 AHB
> > WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1
> > Tested-on: QCN9074 hw1.0 PCI
> > WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1
> > Tested-on: WCN6855 hw2.0 PCI
> > WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3
> >
> > Signed-off-by: Aditya Kumar Singh <quic_adisi@xxxxxxxxxxx>
> > ---
> >   drivers/net/wireless/ath/ath11k/mac.c | 91
> +++++++++++++++++++++++++++
> >   1 file changed, 91 insertions(+)
> >
> > diff --git a/drivers/net/wireless/ath/ath11k/mac.c
> > b/drivers/net/wireless/ath/ath11k/mac.c
> > index f11956163822..f2502ce7deac 100644
> > --- a/drivers/net/wireless/ath/ath11k/mac.c
> > +++ b/drivers/net/wireless/ath/ath11k/mac.c
> > @@ -8471,6 +8471,94 @@ static int
> ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
> >   	return ret;
> >   }
> >
> > +static int ath11k_fw_stats_request(struct ath11k *ar,
> > +				   struct stats_request_params *req_param) {
> > +	struct ath11k_base *ab = ar->ab;
> > +	unsigned long time_left;
> > +	int ret;
> > +
> > +	lockdep_assert_held(&ar->conf_mutex);
> > +
> > +	spin_lock_bh(&ar->data_lock);
> > +	ar->fw_stats_done = false;
> > +	ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
> > +	spin_unlock_bh(&ar->data_lock);
> > +
> > +	reinit_completion(&ar->fw_stats_complete);
> > +
> > +	ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
> > +	if (ret) {
> > +		ath11k_warn(ab, "could not request fw stats (%d)\n",
> > +			    ret);
> > +		return ret;
> > +	}
> > +
> > +	time_left = wait_for_completion_timeout(&ar->fw_stats_complete,
> > +						1 * HZ);
> > +
> > +	if (!time_left)
> > +		return -ETIMEDOUT;
> > +
> > +	return 0;
> > +}
> > +
> > +static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw,
> > +				     struct ieee80211_vif *vif,
> > +				     int *dbm)
> > +{
> > +	struct ath11k *ar = hw->priv;
> > +	struct ath11k_base *ab = ar->ab;
> > +	struct stats_request_params req_param;
> 
> suggest you use an = {} initializer here.
Okay. 

> 
> > +	struct ath11k_fw_stats_pdev *pdev;
> > +	int ret;
> > +
> > +	/* Final Tx power is minimum of Target Power, CTL power,
> Regulatory
> > +	 * Power, PSD EIRP Power. We just know the Regulatory power from
> the
> > +	 * regulatory rules obtained. FW knows all these power and sets the
> min
> > +	 * of these. Hence, we request the FW pdev stats in which FW
> reports
> > +	 * the minimum of all vdev's channel Tx power.
> > +	 */
> > +	mutex_lock(&ar->conf_mutex);
> > +
> > +	if (ar->state != ATH11K_STATE_ON)
> > +		goto err_fallback;
> > +
> > +	req_param.pdev_id = ar->pdev->pdev_id;
> > +	req_param.vdev_id = 0;
> 
> and remove this explicit setting of an unused param to 0 since it will not be
> needed if the entire struct is zeroed. the reason for this approach is that if, in
> the future, any additional fields are added to the struct, you don't want to
> have a situation where you forget to add code to clear the new fields, and as
> a result you potentially leak stack memory contents to firmware, which is a
> security hole.
> 
Sure, will address in v2. Thanks for pointing out.


> > +	req_param.stats_id = WMI_REQUEST_PDEV_STAT;
> > +
> > +	ret = ath11k_fw_stats_request(ar, &req_param);
> > +	if (ret) {
> > +		ath11k_warn(ab, "failed to request fw pdev stats: %d\n",
> ret);
> > +		goto err_fallback;
> > +	}
> > +
> > +	spin_lock_bh(&ar->data_lock);
> > +	pdev = list_first_entry_or_null(&ar->fw_stats.pdevs,
> > +					struct ath11k_fw_stats_pdev, list);
> > +	if (!pdev) {
> > +		spin_unlock_bh(&ar->data_lock);
> > +		goto err_fallback;
> > +	}
> > +
> > +	/* tx power is set as 2 units per dBm in FW. */
> > +	*dbm = pdev->chan_tx_power / 2;
> > +
> > +	spin_unlock_bh(&ar->data_lock);
> > +	mutex_unlock(&ar->conf_mutex);
> > +
> > +	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "%s: txpower: %d from
> fw\n",
> > +__func__, *dbm);
> 
> IMO this is misleading. technically pdev->chan_tx_power is the txpower
> from firmware, *dbm is the derived power after converting units. maybe
> that is splitting hairs, but when debugging issues you usually want to be very
> clear about what is the raw data and what is the calculated data
> 
Yes, I see your point. Will rectify this and be clear in debug prints as
you have suggested below.

> Also follow ath11k coding style for debug messages (which follows
> ath10k) which does not allow colons
> 
> so I'd suggest "txpower from firmware %d reported %d"
> 
Sure, will address.

> > +	return 0;
> > +
> > +err_fallback:
> > +	mutex_unlock(&ar->conf_mutex);
> > +	/* We didn't get txpower from FW. Hence, relying on vif-
> >bss_conf.txpower */
> > +	*dbm = vif->bss_conf.txpower;
> > +	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "%s: txpower from
> bss_conf\n",
> > +__func__);
> 
> I'd log *dbm here as well
> 
Much better. Will rectify in v2.

> > +	return 0;
> > +}
> > +
> >   static const struct ieee80211_ops ath11k_ops = {
> >   	.tx				= ath11k_mac_op_tx,
> >   	.start                          = ath11k_mac_op_start,
> > @@ -8521,6 +8609,7 @@ static const struct ieee80211_ops ath11k_ops = {
> >   #if IS_ENABLED(CONFIG_IPV6)
> >   	.ipv6_addr_change = ath11k_mac_op_ipv6_changed,
> >   #endif
> > +	.get_txpower                    = ath11k_mac_op_get_txpower,
> >
> >   	.set_sar_specs			=
> ath11k_mac_op_set_bios_sar_specs,
> >   	.remain_on_channel		=
> ath11k_mac_op_remain_on_channel,
> > @@ -9129,6 +9218,8 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
> >   		clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar-
> >monitor_flags);
> >   		ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID;
> >   		init_completion(&ar->completed_11d_scan);
> > +
> > +		ath11k_fw_stats_init(ar);
> >   	}
> >
> >   	return 0;





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux