Subject: ath10k: adjust tx power reduction for US regulatory domain
From: Sven Eckelmann <[email-masked]>
Date: Wed, 28 Nov 2018 16:16:27 +0100

FCC allows maximum antenna gain of 6 dBi. 15.247(b)(4):

> (4) The conducted output power limit
> specified in paragraph (b) of this section
> is based on the use of antennas
> with directional gains that do not exceed
> 6 dBi. Except as shown in paragraph
> (c) of this section, if transmitting
> antennas of directional gain greater
> than 6 dBi are used, the conducted
> output power from the intentional radiator
> shall be reduced below the stated
> values in paragraphs (b)(1), (b)(2),
> and (b)(3) of this section, as appropriate,
> by the amount in dB that the
> directional gain of the antenna exceeds
> 6 dBi.

https://www.gpo.gov/fdsys/pkg/CFR-2013-title47-vol1/pdf/CFR-2013-title47-vol1-sec15-247.pdf

Signed-off-by: Sven Eckelmann <[email-masked]>

Forwarded: no

--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1028,6 +1028,40 @@ static inline int ath10k_vdev_setup_sync
 	return ar->last_wmi_vdev_start_status;
 }
 
+static u32 ath10k_get_max_antenna_gain(struct ath10k *ar,
+				       u32 ch_max_antenna_gain)
+{
+	u32 max_antenna_gain;
+
+	if (ar->dfs_detector && ar->dfs_detector->region == NL80211_DFS_FCC) {
+		/* FCC allows maximum antenna gain of 6 dBi. 15.247(b)(4):
+		 *
+		 * > (4) The conducted output power limit
+		 * > specified in paragraph (b) of this section
+		 * > is based on the use of antennas
+		 * > with directional gains that do not exceed
+		 * > 6 dBi. Except as shown in paragraph
+		 * > (c) of this section, if transmitting
+		 * > antennas of directional gain greater
+		 * > than 6 dBi are used, the conducted
+		 * > output power from the intentional radiator
+		 * > shall be reduced below the stated
+		 * > values in paragraphs (b)(1), (b)(2),
+		 * > and (b)(3) of this section, as appropriate,
+		 * > by the amount in dB that the
+		 * > directional gain of the antenna exceeds
+		 * > 6 dBi.
+		 *
+		 * https://www.gpo.gov/fdsys/pkg/CFR-2013-title47-vol1/pdf/CFR-2013-title47-vol1-sec15-247.pdf
+		 */
+		max_antenna_gain = 6;
+	} else {
+		max_antenna_gain = 0;
+	}
+
+	return max(ch_max_antenna_gain, max_antenna_gain);
+}
+
 static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
 {
 	struct cfg80211_chan_def *chandef = NULL;
@@ -1060,7 +1094,8 @@ static int ath10k_monitor_vdev_start(str
 	arg.channel.min_power = 0;
 	arg.channel.max_power = channel->max_power * 2;
 	arg.channel.max_reg_power = channel->max_reg_power * 2;
-	arg.channel.max_antenna_gain = channel->max_antenna_gain;
+	arg.channel.max_antenna_gain = ath10k_get_max_antenna_gain(ar,
+						channel->max_antenna_gain);
 
 	reinit_completion(&ar->vdev_setup_done);
 	reinit_completion(&ar->vdev_delete_done);
@@ -1506,7 +1541,8 @@ static int ath10k_vdev_start_restart(str
 	arg.channel.min_power = 0;
 	arg.channel.max_power = chandef->chan->max_power * 2;
 	arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
-	arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain;
+	arg.channel.max_antenna_gain = ath10k_get_max_antenna_gain(ar,
+					chandef->chan->max_antenna_gain);
 
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 		arg.ssid = arvif->u.ap.ssid;
@@ -3434,7 +3470,8 @@ static int ath10k_update_channel_list(st
 			ch->min_power = 0;
 			ch->max_power = channel->max_power * 2;
 			ch->max_reg_power = channel->max_reg_power * 2;
-			ch->max_antenna_gain = channel->max_antenna_gain;
+			ch->max_antenna_gain = ath10k_get_max_antenna_gain(ar,
+						channel->max_antenna_gain);
 			ch->reg_class_id = 0; /* FIXME */
 
 			/* FIXME: why use only legacy modes, why not any