ath10k.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv2 0/2] ath10k: Allow setting coverage class
@ 2016-08-01 10:21 Benjamin Berg
  2016-08-01 10:21 ` [PATCHv2 1/2] ath10k: Rename hw_rx_desc_ops to hw_ops to use it for other purposes Benjamin Berg
  2016-08-01 10:21 ` [PATCHv2 2/2] ath10k: Allow setting coverage class Benjamin Berg
  0 siblings, 2 replies; 7+ messages in thread
From: Benjamin Berg @ 2016-08-01 10:21 UTC (permalink / raw)
  To: ath10k
  Cc: Vasanthakumar Thiagarajan, Benjamin Berg, Michal Kazior,
	Sebastian Gottschall

Hi,

a new version of the patch which is based on top of the wake_tx_queue work
and also the work from Vasanthakumar which adds the rx descriptor
abstraction. The patch set is incomplete in the sense that it doesn't
update the later patches from Vasanthakumar and would break them as is.

Benjamin Berg (2):
  ath10k: Rename hw_rx_desc_ops to hw_ops to use it for other purposes
  ath10k: Allow setting coverage class

 drivers/net/wireless/ath/ath10k/core.c |  24 +++----
 drivers/net/wireless/ath/ath10k/core.h |  10 +++
 drivers/net/wireless/ath/ath10k/hw.c   | 116 ++++++++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath10k/hw.h   |  30 +++++++--
 drivers/net/wireless/ath/ath10k/mac.c  |  19 ++++++
 drivers/net/wireless/ath/ath10k/wmi.c  |  29 +++++++++
 6 files changed, 209 insertions(+), 19 deletions(-)

-- 
2.8.1


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCHv2 1/2] ath10k: Rename hw_rx_desc_ops to hw_ops to use it for other purposes
  2016-08-01 10:21 [PATCHv2 0/2] ath10k: Allow setting coverage class Benjamin Berg
@ 2016-08-01 10:21 ` Benjamin Berg
  2016-08-01 10:21 ` [PATCHv2 2/2] ath10k: Allow setting coverage class Benjamin Berg
  1 sibling, 0 replies; 7+ messages in thread
From: Benjamin Berg @ 2016-08-01 10:21 UTC (permalink / raw)
  To: ath10k
  Cc: Vasanthakumar Thiagarajan, Benjamin Berg, Michal Kazior,
	Sebastian Gottschall

The structure contains hardware specific operations. Rename the struct so
that it is appropriate to be used for other operations.

Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
---
 drivers/net/wireless/ath/ath10k/core.c | 24 ++++++++++++------------
 drivers/net/wireless/ath/ath10k/hw.c   |  4 ++--
 drivers/net/wireless/ath/ath10k/hw.h   |  8 ++++----
 3 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 9c5e93b..6dd42d3 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -68,7 +68,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA988X_BOARD_DATA_SZ,
 			.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca988x_rx_desc_ops,
+		.hw_ops = &qca988x_ops,
 	},
 	{
 		.id = QCA9887_HW_1_0_VERSION,
@@ -88,7 +88,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA9887_BOARD_DATA_SZ,
 			.board_ext_size = QCA9887_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca988x_rx_desc_ops,
+		.hw_ops = &qca988x_ops,
 	},
 	{
 		.id = QCA6174_HW_2_1_VERSION,
@@ -106,7 +106,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA6174_BOARD_DATA_SZ,
 			.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca988x_rx_desc_ops,
+		.hw_ops = &qca988x_ops,
 	},
 	{
 		.id = QCA6174_HW_2_1_VERSION,
@@ -125,7 +125,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA6174_BOARD_DATA_SZ,
 			.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca988x_rx_desc_ops,
+		.hw_ops = &qca988x_ops,
 	},
 	{
 		.id = QCA6174_HW_3_0_VERSION,
@@ -144,7 +144,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA6174_BOARD_DATA_SZ,
 			.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca988x_rx_desc_ops,
+		.hw_ops = &qca988x_ops,
 	},
 	{
 		.id = QCA6174_HW_3_2_VERSION,
@@ -164,7 +164,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA6174_BOARD_DATA_SZ,
 			.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca988x_rx_desc_ops,
+		.hw_ops = &qca988x_ops,
 	},
 	{
 		.id = QCA99X0_HW_2_0_DEV_VERSION,
@@ -188,7 +188,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA99X0_BOARD_DATA_SZ,
 			.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca99x0_rx_desc_ops,
+		.hw_ops = &qca99x0_ops,
 	},
 	{
 		.id = QCA9984_HW_1_0_DEV_VERSION,
@@ -212,7 +212,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA99X0_BOARD_DATA_SZ,
 			.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca99x0_rx_desc_ops,
+		.hw_ops = &qca99x0_ops,
 	},
 	{
 		.id = QCA9888_HW_2_0_DEV_VERSION,
@@ -235,7 +235,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA99X0_BOARD_DATA_SZ,
 			.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca99x0_rx_desc_ops,
+		.hw_ops = &qca99x0_ops,
 	},
 	{
 		.id = QCA9377_HW_1_0_DEV_VERSION,
@@ -253,7 +253,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA9377_BOARD_DATA_SZ,
 			.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca988x_rx_desc_ops,
+		.hw_ops = &qca988x_ops,
 	},
 	{
 		.id = QCA9377_HW_1_1_DEV_VERSION,
@@ -271,7 +271,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA9377_BOARD_DATA_SZ,
 			.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca988x_rx_desc_ops,
+		.hw_ops = &qca988x_ops,
 	},
 	{
 		.id = QCA4019_HW_1_0_DEV_VERSION,
@@ -296,7 +296,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.board_size = QCA4019_BOARD_DATA_SZ,
 			.board_ext_size = QCA4019_BOARD_EXT_DATA_SZ,
 		},
-		.hw_rx_desc_ops = &qca99x0_rx_desc_ops,
+		.hw_ops = &qca99x0_ops,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 6149aa9..c2ecb9b 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -220,7 +220,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
 	survey->time_busy = CCNT_TO_MSEC(ar, rcc);
 }
 
-const struct ath10k_hw_rx_desc_ops qca988x_rx_desc_ops = {
+const struct ath10k_hw_ops qca988x_ops = {
 };
 
 static int ath10k_qca99x0_rx_desc_get_l3_pad_bytes(struct htt_rx_desc *rxd)
@@ -229,6 +229,6 @@ static int ath10k_qca99x0_rx_desc_get_l3_pad_bytes(struct htt_rx_desc *rxd)
 		  RX_MSDU_END_INFO1_L3_HDR_PAD);
 }
 
-const struct ath10k_hw_rx_desc_ops qca99x0_rx_desc_ops = {
+const struct ath10k_hw_ops qca99x0_ops = {
 	.rx_desc_get_l3_pad_bytes = ath10k_qca99x0_rx_desc_get_l3_pad_bytes,
 };
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index a281544..1ef7dc6 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -410,18 +410,18 @@ struct ath10k_hw_params {
 		size_t board_ext_size;
 	} fw;
 
-	const struct ath10k_hw_rx_desc_ops *hw_rx_desc_ops;
+	const struct ath10k_hw_ops *hw_ops;
 };
 
 struct htt_rx_desc;
 
 /* Defines needed for Rx descriptor abstraction */
-struct ath10k_hw_rx_desc_ops {
+struct ath10k_hw_ops {
 	int (*rx_desc_get_l3_pad_bytes)(struct htt_rx_desc *rxd);
 };
 
-extern const struct ath10k_hw_rx_desc_ops qca988x_rx_desc_ops;
-extern const struct ath10k_hw_rx_desc_ops qca99x0_rx_desc_ops;
+extern const struct ath10k_hw_ops qca988x_ops;
+extern const struct ath10k_hw_ops qca99x0_ops;
 
 /* Target specific defines for MAIN firmware */
 #define TARGET_NUM_VDEVS			8
-- 
2.8.1


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCHv2 2/2] ath10k: Allow setting coverage class
  2016-08-01 10:21 [PATCHv2 0/2] ath10k: Allow setting coverage class Benjamin Berg
  2016-08-01 10:21 ` [PATCHv2 1/2] ath10k: Rename hw_rx_desc_ops to hw_ops to use it for other purposes Benjamin Berg
@ 2016-08-01 10:21 ` Benjamin Berg
  2016-08-03  7:19   ` Michal Kazior
  1 sibling, 1 reply; 7+ messages in thread
From: Benjamin Berg @ 2016-08-01 10:21 UTC (permalink / raw)
  To: ath10k
  Cc: Simon Wunderlich, Vasanthakumar Thiagarajan, Benjamin Berg,
	Sebastian Gottschall, Michal Kazior, Mathias Kretschmer

Unfortunately ath10k does not generally allow modifying the coverage class
with the stock firmware and Qualcomm has so far refused to implement this
feature so that it can be properly supported in ath10k. If we however know
the registers that need to be modified for proper operation with a higher
coverage class, then we can do these modifications from the driver.

This patch implements this hack for first generation cards which are based
on a core that is similar to ath9k. The registers are modified in place and
need to be re-written every time the firmware sets them. To achieve this
the register status is verified after any WMI event from the firmware.

The coverage class may not be modified temporarily right after the card
re-initializes the registers. This is for example the case during scanning.

Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
working on a userspace support for this. This patch wouldn't have been
possible without this documentation.

Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fit.fraunhofer.de>
---
 drivers/net/wireless/ath/ath10k/core.h |  10 +++
 drivers/net/wireless/ath/ath10k/hw.c   | 112 +++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hw.h   |  22 ++++++-
 drivers/net/wireless/ath/ath10k/mac.c  |  19 ++++++
 drivers/net/wireless/ath/ath10k/wmi.c  |  29 +++++++++
 5 files changed, 191 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 5ace413..4ae730b 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -890,6 +890,16 @@ struct ath10k {
 	struct ath10k_thermal thermal;
 	struct ath10k_wow wow;
 
+	/* protected by data_lock */
+	struct {
+		s16 coverage_class;
+
+		u32 reg_slottime_conf;
+		u32 reg_slottime_orig;
+		u32 reg_ack_cts_timeout_conf;
+		u32 reg_ack_cts_timeout_orig;
+	} fw_coverage;
+
 	/* must be last */
 	u8 drv_priv[0] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index c2ecb9b..f1278ad 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -17,11 +17,13 @@
 #include <linux/types.h>
 #include "core.h"
 #include "hw.h"
+#include "hif.h"
 
 const struct ath10k_hw_regs qca988x_regs = {
 	.rtc_soc_base_address		= 0x00004000,
 	.rtc_wmac_base_address		= 0x00005000,
 	.soc_core_base_address		= 0x00009000,
+	.wlan_mac_base_address		= 0x00020000,
 	.ce_wrapper_base_address	= 0x00057000,
 	.ce0_base_address		= 0x00057400,
 	.ce1_base_address		= 0x00057800,
@@ -48,6 +50,7 @@ const struct ath10k_hw_regs qca6174_regs = {
 	.rtc_soc_base_address			= 0x00000800,
 	.rtc_wmac_base_address			= 0x00001000,
 	.soc_core_base_address			= 0x0003a000,
+	.wlan_mac_base_address			= 0x00020000,
 	.ce_wrapper_base_address		= 0x00034000,
 	.ce0_base_address			= 0x00034400,
 	.ce1_base_address			= 0x00034800,
@@ -74,6 +77,7 @@ const struct ath10k_hw_regs qca99x0_regs = {
 	.rtc_soc_base_address			= 0x00080000,
 	.rtc_wmac_base_address			= 0x00000000,
 	.soc_core_base_address			= 0x00082000,
+	.wlan_mac_base_address			= 0x00030000,
 	.ce_wrapper_base_address		= 0x0004d000,
 	.ce0_base_address			= 0x0004a000,
 	.ce1_base_address			= 0x0004a400,
@@ -109,6 +113,7 @@ const struct ath10k_hw_regs qca99x0_regs = {
 const struct ath10k_hw_regs qca4019_regs = {
 	.rtc_soc_base_address                   = 0x00080000,
 	.soc_core_base_address                  = 0x00082000,
+	.wlan_mac_base_address                  = 0x00030000,
 	.ce_wrapper_base_address                = 0x0004d000,
 	.ce0_base_address                       = 0x0004a000,
 	.ce1_base_address                       = 0x0004a400,
@@ -220,7 +225,114 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
 	survey->time_busy = CCNT_TO_MSEC(ar, rcc);
 }
 
+static void ath10k_qca988x_mac_op_set_coverage_class(struct ath10k *ar,
+						     s16 value)
+{
+	u32 slottime_reg;
+	u32 slottime;
+	u32 timeout_reg;
+	u32 timeout;
+	u32 counters_freq_mhz = ar->hw_params.channel_counters_freq_hz / 1000;
+
+	/* The firmware does not support setting the coverage class. Instead
+	 * this function monitors and modifies the corresponding MAC registers.
+	 */
+
+	spin_lock_bh(&ar->data_lock);
+
+	/* Retrieve the current values of the two registers that need to be
+	 * adjusted.
+	 */
+	slottime_reg = ath10k_hif_read32(ar, WLAN_MAC_BASE_ADDRESS +
+					     WAVE1_PCU_GBL_IFS_SLOT);
+	timeout_reg = ath10k_hif_read32(ar, WLAN_MAC_BASE_ADDRESS +
+					    WAVE1_PCU_ACK_CTS_TIMEOUT);
+
+	if (value < 0)
+		value = ar->fw_coverage.coverage_class;
+
+	/* Break out if the coverage class and registers have the expected
+	 * value.
+	 */
+	if (value == ar->fw_coverage.coverage_class &&
+	    slottime_reg == ar->fw_coverage.reg_slottime_conf &&
+	    timeout_reg == ar->fw_coverage.reg_ack_cts_timeout_conf)
+		goto unlock;
+
+	/* Store new initial register values from the firmware. */
+	if (slottime_reg != ar->fw_coverage.reg_slottime_conf)
+		ar->fw_coverage.reg_slottime_orig = slottime_reg;
+	if (timeout_reg != ar->fw_coverage.reg_ack_cts_timeout_conf)
+		ar->fw_coverage.reg_ack_cts_timeout_orig = timeout_reg;
+
+	/* Calculat new value based on the (original) firmware calculation. */
+	slottime_reg = ar->fw_coverage.reg_slottime_orig;
+	timeout_reg = ar->fw_coverage.reg_ack_cts_timeout_orig;
+
+	/* Do some sanity checks on the slottime register. */
+	if (unlikely(slottime_reg % counters_freq_mhz)) {
+		ath10k_warn(ar,
+			    "failed to set coverage class: expected integer microsecond value in register\n");
+
+		goto store_regs;
+	}
+
+	slottime = (slottime_reg & WAVE1_PCU_GBL_IFS_SLOT_M);
+	slottime = slottime / counters_freq_mhz;
+	if (unlikely(slottime != 9 && slottime != 20)) {
+		ath10k_warn(ar,
+			    "failed to set coverage class: expected slot time of 9 or 20us in HW register. It is %uus.\n",
+			    slottime);
+
+		goto store_regs;
+	}
+
+	/* Recalculate the register values by adding the additional propagation
+	 * delay (3us per coverage class).
+	 */
+
+	slottime = (slottime_reg & WAVE1_PCU_GBL_IFS_SLOT_M);
+	slottime += value * 3 * counters_freq_mhz;
+	slottime = min_t(u32, slottime, WAVE1_PCU_GBL_IFS_SLOT_M);
+	slottime_reg = (slottime_reg & ~WAVE1_PCU_GBL_IFS_SLOT_M) | slottime;
+
+	/* Update ack timeout (lower halfword). */
+	timeout = (timeout_reg & WAVE1_PCU_ACK_CTS_TIMEOUT_ACK);
+	timeout = timeout >> WAVE1_PCU_ACK_CTS_TIMEOUT_ACK_S;
+	timeout += 3 * value * counters_freq_mhz;
+	timeout = min_t(u32, timeout, WAVE1_PCU_ACK_CTS_TIMEOUT_MAX);
+	timeout = (timeout << WAVE1_PCU_ACK_CTS_TIMEOUT_ACK_S);
+	timeout = timeout & WAVE1_PCU_ACK_CTS_TIMEOUT_ACK;
+	timeout_reg = (timeout_reg & ~WAVE1_PCU_ACK_CTS_TIMEOUT_ACK) | timeout;
+
+	/* Update cts timeout (upper halfword). */
+	timeout = (timeout_reg & WAVE1_PCU_ACK_CTS_TIMEOUT_CTS);
+	timeout = timeout >> WAVE1_PCU_ACK_CTS_TIMEOUT_CTS_S;
+	timeout += 3 * value * counters_freq_mhz;
+	timeout = min_t(u32, timeout, WAVE1_PCU_ACK_CTS_TIMEOUT_MAX);
+	timeout = (timeout << WAVE1_PCU_ACK_CTS_TIMEOUT_CTS_S);
+	timeout = timeout & WAVE1_PCU_ACK_CTS_TIMEOUT_CTS;
+	timeout_reg = (timeout_reg & ~WAVE1_PCU_ACK_CTS_TIMEOUT_CTS) | timeout;
+
+	ath10k_hif_write32(ar,
+			   WLAN_MAC_BASE_ADDRESS + WAVE1_PCU_GBL_IFS_SLOT,
+			   slottime_reg);
+	ath10k_hif_write32(ar,
+			   WLAN_MAC_BASE_ADDRESS + WAVE1_PCU_ACK_CTS_TIMEOUT,
+			   timeout_reg);
+
+store_regs:
+	/* After an error we will not retry setting the coverage class. */
+	ar->fw_coverage.coverage_class = value;
+	ar->fw_coverage.reg_slottime_conf = slottime_reg;
+	ar->fw_coverage.reg_ack_cts_timeout_conf = timeout_reg;
+
+unlock:
+	spin_unlock_bh(&ar->data_lock);
+}
+
 const struct ath10k_hw_ops qca988x_ops = {
+	.mac_op_set_coverage_class = ath10k_qca988x_mac_op_set_coverage_class,
 };
 
 static int ath10k_qca99x0_rx_desc_get_l3_pad_bytes(struct htt_rx_desc *rxd)
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 1ef7dc6..532eab5 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -230,6 +230,7 @@ struct ath10k_hw_regs {
 	u32 rtc_soc_base_address;
 	u32 rtc_wmac_base_address;
 	u32 soc_core_base_address;
+	u32 wlan_mac_base_address;
 	u32 ce_wrapper_base_address;
 	u32 ce0_base_address;
 	u32 ce1_base_address;
@@ -418,6 +419,7 @@ struct htt_rx_desc;
 /* Defines needed for Rx descriptor abstraction */
 struct ath10k_hw_ops {
 	int (*rx_desc_get_l3_pad_bytes)(struct htt_rx_desc *rxd);
+	void (*mac_op_set_coverage_class)(struct ath10k *ar, s16 value);
 };
 
 extern const struct ath10k_hw_ops qca988x_ops;
@@ -605,7 +607,7 @@ extern const struct ath10k_hw_ops qca99x0_ops;
 #define WLAN_SI_BASE_ADDRESS			0x00010000
 #define WLAN_GPIO_BASE_ADDRESS			0x00014000
 #define WLAN_ANALOG_INTF_BASE_ADDRESS		0x0001c000
-#define WLAN_MAC_BASE_ADDRESS			0x00020000
+#define WLAN_MAC_BASE_ADDRESS			ar->regs->wlan_mac_base_address
 #define EFUSE_BASE_ADDRESS			0x00030000
 #define FPGA_REG_BASE_ADDRESS			0x00039000
 #define WLAN_UART2_BASE_ADDRESS			0x00054c00
@@ -805,4 +807,22 @@ extern const struct ath10k_hw_ops qca99x0_ops;
 
 #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB)
 
+/* Register definitions for first generation ath10k cards. These cards include
+ * a mac thich has a register allocation similar to ath9k and at least some
+ * registers including the ones relevant for modifying the coverage class are
+ * identical to the ath9k definitions.
+ * These registers are usually managed by the ath10k firmware. However by
+ * overriding them it is possible to support coverage class modifications.
+ */
+#define WAVE1_PCU_ACK_CTS_TIMEOUT		0x8014
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_MAX		0x00003FFF
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_ACK		0x00003FFF
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_ACK_S	0
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_CTS		0x3FFF0000
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_CTS_S	16
+
+#define WAVE1_PCU_GBL_IFS_SLOT			0x1070
+#define WAVE1_PCU_GBL_IFS_SLOT_M		0x0000FFFF
+#define WAVE1_PCU_GBL_IFS_SLOT_RESV0		0xFFFF0000
+
 #endif /* _HW_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index fb8e38d..ad1cb6d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -5372,6 +5372,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static void ath10k_mac_op_set_coverage_class(struct ieee80211_hw *hw, s16 value)
+{
+	struct ath10k *ar = hw->priv;
+
+	/* This function should never be called if setting the coverage class
+	 * is not supported on this hardware.
+	 */
+	if (!ar->hw_params.hw_ops->mac_op_set_coverage_class) {
+		WARN_ON_ONCE(1);
+		return;
+	}
+	ar->hw_params.hw_ops->mac_op_set_coverage_class(ar, value);
+}
+
 static int ath10k_hw_scan(struct ieee80211_hw *hw,
 			  struct ieee80211_vif *vif,
 			  struct ieee80211_scan_request *hw_req)
@@ -7397,6 +7411,7 @@ static const struct ieee80211_ops ath10k_ops = {
 	.remove_interface		= ath10k_remove_interface,
 	.configure_filter		= ath10k_configure_filter,
 	.bss_info_changed		= ath10k_bss_info_changed,
+	.set_coverage_class		= ath10k_mac_op_set_coverage_class,
 	.hw_scan			= ath10k_hw_scan,
 	.cancel_hw_scan			= ath10k_cancel_hw_scan,
 	.set_key			= ath10k_set_key,
@@ -7974,6 +7989,10 @@ int ath10k_mac_register(struct ath10k *ar)
 		      ar->running_fw->fw_file.fw_features))
 		ar->ops->wake_tx_queue = NULL;
 
+	/* Disable set_coverage_class for chipsets that do not support it. */
+	if (!ar->hw_params.hw_ops->mac_op_set_coverage_class)
+		ar->ops->set_coverage_class = NULL;
+
 	ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
 			    ath10k_reg_notifier);
 	if (ret) {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 169cd2e7..700c430 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4992,6 +4992,13 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	}
 
+	/* Check and possibly reset the coverage class configuration override.
+	 * There are many conditions (in particular internal card resets) that
+	 * can cause the registers to be re-initialized.
+	 */
+	if (!ar->hw_params.hw_ops->mac_op_set_coverage_class)
+		ar->hw_params.hw_ops->mac_op_set_coverage_class(ar, -1);
+
 out:
 	dev_kfree_skb(skb);
 }
@@ -5116,6 +5123,13 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	}
 
+	/* Check and possibly reset the coverage class configuration override.
+	 * There are many conditions (in particular internal card resets) that
+	 * can cause the registers to be re-initialized.
+	 */
+	if (!ar->hw_params.hw_ops->mac_op_set_coverage_class)
+		ar->hw_params.hw_ops->mac_op_set_coverage_class(ar, -1);
+
 out:
 	dev_kfree_skb(skb);
 }
@@ -5240,6 +5254,13 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	}
 
+	/* Check and possibly reset the coverage class configuration override.
+	 * There are many conditions (in particular internal card resets) that
+	 * can cause the registers to be re-initialized.
+	 */
+	if (!ar->hw_params.hw_ops->mac_op_set_coverage_class)
+		ar->hw_params.hw_ops->mac_op_set_coverage_class(ar, -1);
+
 out:
 	dev_kfree_skb(skb);
 }
@@ -5323,6 +5344,13 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	}
 
+	/* Check and possibly reset the coverage class configuration override.
+	 * There are many conditions (in particular internal card resets) that
+	 * can cause the registers to be re-initialized.
+	 */
+	if (!ar->hw_params.hw_ops->mac_op_set_coverage_class)
+		ar->hw_params.hw_ops->mac_op_set_coverage_class(ar, -1);
+
 out:
 	dev_kfree_skb(skb);
 }
@@ -6017,6 +6045,7 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar,
 		| WMI_SCAN_EVENT_COMPLETED
 		| WMI_SCAN_EVENT_BSS_CHANNEL
 		| WMI_SCAN_EVENT_FOREIGN_CHANNEL
+		| WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT
 		| WMI_SCAN_EVENT_DEQUEUED;
 	arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT;
 	arg->n_bssids = 1;
-- 
2.8.1


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCHv2 2/2] ath10k: Allow setting coverage class
  2016-08-01 10:21 ` [PATCHv2 2/2] ath10k: Allow setting coverage class Benjamin Berg
@ 2016-08-03  7:19   ` Michal Kazior
  2016-08-03 15:37     ` Sebastian Gottschall
  0 siblings, 1 reply; 7+ messages in thread
From: Michal Kazior @ 2016-08-03  7:19 UTC (permalink / raw)
  To: Benjamin Berg
  Cc: Vasanthakumar Thiagarajan, Mathias Kretschmer,
	Sebastian Gottschall, ath10k, Simon Wunderlich

On 1 August 2016 at 12:21, Benjamin Berg <benjamin@sipsolutions.net> wrote:
> Unfortunately ath10k does not generally allow modifying the coverage class
> with the stock firmware and Qualcomm has so far refused to implement this
> feature so that it can be properly supported in ath10k. If we however know
> the registers that need to be modified for proper operation with a higher
> coverage class, then we can do these modifications from the driver.
>
> This patch implements this hack for first generation cards which are based
> on a core that is similar to ath9k. The registers are modified in place and
> need to be re-written every time the firmware sets them. To achieve this
> the register status is verified after any WMI event from the firmware.
>
> The coverage class may not be modified temporarily right after the card
> re-initializes the registers. This is for example the case during scanning.
>
> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
> working on a userspace support for this. This patch wouldn't have been
> possible without this documentation.
>
> Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
> Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fit.fraunhofer.de>
> ---
>  drivers/net/wireless/ath/ath10k/core.h |  10 +++
>  drivers/net/wireless/ath/ath10k/hw.c   | 112 +++++++++++++++++++++++++++++++++
>  drivers/net/wireless/ath/ath10k/hw.h   |  22 ++++++-
>  drivers/net/wireless/ath/ath10k/mac.c  |  19 ++++++
>  drivers/net/wireless/ath/ath10k/wmi.c  |  29 +++++++++
>  5 files changed, 191 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
> index 5ace413..4ae730b 100644
> --- a/drivers/net/wireless/ath/ath10k/core.h
> +++ b/drivers/net/wireless/ath/ath10k/core.h
> @@ -890,6 +890,16 @@ struct ath10k {
>         struct ath10k_thermal thermal;
>         struct ath10k_wow wow;
>
> +       /* protected by data_lock */
> +       struct {
> +               s16 coverage_class;
> +
> +               u32 reg_slottime_conf;
> +               u32 reg_slottime_orig;
> +               u32 reg_ack_cts_timeout_conf;
> +               u32 reg_ack_cts_timeout_orig;
> +       } fw_coverage;
> +
>         /* must be last */
>         u8 drv_priv[0] __aligned(sizeof(void *));
>  };
> diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
> index c2ecb9b..f1278ad 100644
> --- a/drivers/net/wireless/ath/ath10k/hw.c
> +++ b/drivers/net/wireless/ath/ath10k/hw.c
> @@ -17,11 +17,13 @@
>  #include <linux/types.h>
>  #include "core.h"
>  #include "hw.h"
> +#include "hif.h"
>
>  const struct ath10k_hw_regs qca988x_regs = {
>         .rtc_soc_base_address           = 0x00004000,
>         .rtc_wmac_base_address          = 0x00005000,
>         .soc_core_base_address          = 0x00009000,
> +       .wlan_mac_base_address          = 0x00020000,
>         .ce_wrapper_base_address        = 0x00057000,
>         .ce0_base_address               = 0x00057400,
>         .ce1_base_address               = 0x00057800,
> @@ -48,6 +50,7 @@ const struct ath10k_hw_regs qca6174_regs = {
>         .rtc_soc_base_address                   = 0x00000800,
>         .rtc_wmac_base_address                  = 0x00001000,
>         .soc_core_base_address                  = 0x0003a000,
> +       .wlan_mac_base_address                  = 0x00020000,
>         .ce_wrapper_base_address                = 0x00034000,
>         .ce0_base_address                       = 0x00034400,
>         .ce1_base_address                       = 0x00034800,
> @@ -74,6 +77,7 @@ const struct ath10k_hw_regs qca99x0_regs = {
>         .rtc_soc_base_address                   = 0x00080000,
>         .rtc_wmac_base_address                  = 0x00000000,
>         .soc_core_base_address                  = 0x00082000,
> +       .wlan_mac_base_address                  = 0x00030000,
>         .ce_wrapper_base_address                = 0x0004d000,
>         .ce0_base_address                       = 0x0004a000,
>         .ce1_base_address                       = 0x0004a400,
> @@ -109,6 +113,7 @@ const struct ath10k_hw_regs qca99x0_regs = {
>  const struct ath10k_hw_regs qca4019_regs = {
>         .rtc_soc_base_address                   = 0x00080000,
>         .soc_core_base_address                  = 0x00082000,
> +       .wlan_mac_base_address                  = 0x00030000,
>         .ce_wrapper_base_address                = 0x0004d000,
>         .ce0_base_address                       = 0x0004a000,
>         .ce1_base_address                       = 0x0004a400,
> @@ -220,7 +225,114 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
>         survey->time_busy = CCNT_TO_MSEC(ar, rcc);
>  }
>
> +static void ath10k_qca988x_mac_op_set_coverage_class(struct ath10k *ar,
> +                                                    s16 value)

The naming is wrong. The general convention is:

 ath10k_{base_filename}_{purpose}

If a function is used as an _ops callback (ieee80211_ops, or wmi_ops)
the purpose should start with _ops.

In this case the name should be:

  ath10k_hw_qca988x_set_coverage_class()


> +       if (value < 0)
> +               value = ar->fw_coverage.coverage_class;
> +
> +       /* Break out if the coverage class and registers have the expected
> +        * value.
> +        */
> +       if (value == ar->fw_coverage.coverage_class &&
> +           slottime_reg == ar->fw_coverage.reg_slottime_conf &&
> +           timeout_reg == ar->fw_coverage.reg_ack_cts_timeout_conf)
> +               goto unlock;

I would move this part to the caller and keep the hardware-specific
function just compute and set registers, e.g. have
ath10k_mac_set_coverage_class (as opposed to
ath10k_mac_op_set_coverage_class). It should also reduce some code
duplication.


[...]
>  static int ath10k_qca99x0_rx_desc_get_l3_pad_bytes(struct htt_rx_desc *rxd)
> diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
> index 1ef7dc6..532eab5 100644
> --- a/drivers/net/wireless/ath/ath10k/hw.h
> +++ b/drivers/net/wireless/ath/ath10k/hw.h
> @@ -230,6 +230,7 @@ struct ath10k_hw_regs {
>         u32 rtc_soc_base_address;
>         u32 rtc_wmac_base_address;
>         u32 soc_core_base_address;
> +       u32 wlan_mac_base_address;
>         u32 ce_wrapper_base_address;
>         u32 ce0_base_address;
>         u32 ce1_base_address;
> @@ -418,6 +419,7 @@ struct htt_rx_desc;
>  /* Defines needed for Rx descriptor abstraction */
>  struct ath10k_hw_ops {
>         int (*rx_desc_get_l3_pad_bytes)(struct htt_rx_desc *rxd);
> +       void (*mac_op_set_coverage_class)(struct ath10k *ar, s16 value);

Just "set_coverage_class" is fine.


[...]
> diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
> index 169cd2e7..700c430 100644
> --- a/drivers/net/wireless/ath/ath10k/wmi.c
> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
> @@ -4992,6 +4992,13 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
>                 break;
>         }
>
> +       /* Check and possibly reset the coverage class configuration override.
> +        * There are many conditions (in particular internal card resets) that
> +        * can cause the registers to be re-initialized.
> +        */
> +       if (!ar->hw_params.hw_ops->mac_op_set_coverage_class)
> +               ar->hw_params.hw_ops->mac_op_set_coverage_class(ar, -1);

As discussed in the other thread - it may be better to implicitly
enable dbglog and hook the refresh call there.


Michał

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCHv2 2/2] ath10k: Allow setting coverage class
  2016-08-03  7:19   ` Michal Kazior
@ 2016-08-03 15:37     ` Sebastian Gottschall
  2016-08-04  5:28       ` Michal Kazior
  0 siblings, 1 reply; 7+ messages in thread
From: Sebastian Gottschall @ 2016-08-03 15:37 UTC (permalink / raw)
  To: Michal Kazior, Benjamin Berg
  Cc: Vasanthakumar Thiagarajan, Mathias Kretschmer, ath10k, Simon Wunderlich


>> +       if (value < 0)
>> +               value = ar->fw_coverage.coverage_class;
>> +
>> +       /* Break out if the coverage class and registers have the expected
>> +        * value.
>> +        */
>> +       if (value == ar->fw_coverage.coverage_class &&
>> +           slottime_reg == ar->fw_coverage.reg_slottime_conf &&
>> +           timeout_reg == ar->fw_coverage.reg_ack_cts_timeout_conf)
>> +               goto unlock;
> I would move this part to the caller and keep the hardware-specific
> function just compute and set registers, e.g. have
> ath10k_mac_set_coverage_class (as opposed to
> ath10k_mac_op_set_coverage_class). It should also reduce some code
> duplication.
doesnt make sense. i already enhanced this code to support beeliner 
(99xx) and newers.
the code is that much different that this check need to be treaded in a 
indivudual way
reg_slottime_conf is hardware defacto specific since the value is taken 
from a hardware specific register.
you cannot handle this outside this function since other chips have 
different registers.



-- 
Mit freundlichen Grüssen / Regards

Sebastian Gottschall / CTO

NewMedia-NET GmbH - DD-WRT
Firmensitz:  Berliner Ring 101, 64625 Bensheim
Registergericht: Amtsgericht Darmstadt, HRB 25473
Geschäftsführer: Peter Steinhäuser, Christian Scheele
http://www.dd-wrt.com
email: s.gottschall@dd-wrt.com
Tel.: +496251-582650 / Fax: +496251-5826565


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCHv2 2/2] ath10k: Allow setting coverage class
  2016-08-03 15:37     ` Sebastian Gottschall
@ 2016-08-04  5:28       ` Michal Kazior
  2016-08-04 11:35         ` Sebastian Gottschall
  0 siblings, 1 reply; 7+ messages in thread
From: Michal Kazior @ 2016-08-04  5:28 UTC (permalink / raw)
  To: Sebastian Gottschall
  Cc: Vasanthakumar Thiagarajan, Benjamin Berg, Mathias Kretschmer,
	ath10k, Simon Wunderlich

On 3 August 2016 at 17:37, Sebastian Gottschall <s.gottschall@dd-wrt.com> wrote:
>
>>> +       if (value < 0)
>>> +               value = ar->fw_coverage.coverage_class;
>>> +
>>> +       /* Break out if the coverage class and registers have the
>>> expected
>>> +        * value.
>>> +        */
>>> +       if (value == ar->fw_coverage.coverage_class &&
>>> +           slottime_reg == ar->fw_coverage.reg_slottime_conf &&
>>> +           timeout_reg == ar->fw_coverage.reg_ack_cts_timeout_conf)
>>> +               goto unlock;
>>
>> I would move this part to the caller and keep the hardware-specific
>> function just compute and set registers, e.g. have
>> ath10k_mac_set_coverage_class (as opposed to
>> ath10k_mac_op_set_coverage_class). It should also reduce some code
>> duplication.
>
> doesnt make sense. i already enhanced this code to support beeliner (99xx)
> and newers.
> the code is that much different that this check need to be treaded in a
> indivudual way
> reg_slottime_conf is hardware defacto specific since the value is taken from
> a hardware specific register.
> you cannot handle this outside this function since other chips have
> different registers.

Ah, you're right, my bad :)


Michał

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCHv2 2/2] ath10k: Allow setting coverage class
  2016-08-04  5:28       ` Michal Kazior
@ 2016-08-04 11:35         ` Sebastian Gottschall
  0 siblings, 0 replies; 7+ messages in thread
From: Sebastian Gottschall @ 2016-08-04 11:35 UTC (permalink / raw)
  To: Michal Kazior
  Cc: Vasanthakumar Thiagarajan, Benjamin Berg, Mathias Kretschmer,
	ath10k, Simon Wunderlich

Am 04.08.2016 um 07:28 schrieb Michal Kazior:
> On 3 August 2016 at 17:37, Sebastian Gottschall <s.gottschall@dd-wrt.com> wrote:
>>>> +       if (value < 0)
>>>> +               value = ar->fw_coverage.coverage_class;
>>>> +
>>>> +       /* Break out if the coverage class and registers have the
>>>> expected
>>>> +        * value.
>>>> +        */
>>>> +       if (value == ar->fw_coverage.coverage_class &&
>>>> +           slottime_reg == ar->fw_coverage.reg_slottime_conf &&
>>>> +           timeout_reg == ar->fw_coverage.reg_ack_cts_timeout_conf)
>>>> +               goto unlock;
>>> I would move this part to the caller and keep the hardware-specific
>>> function just compute and set registers, e.g. have
>>> ath10k_mac_set_coverage_class (as opposed to
>>> ath10k_mac_op_set_coverage_class). It should also reduce some code
>>> duplication.
>> doesnt make sense. i already enhanced this code to support beeliner (99xx)
>> and newers.
>> the code is that much different that this check need to be treaded in a
>> indivudual way
>> reg_slottime_conf is hardware defacto specific since the value is taken from
>> a hardware specific register.
>> you cannot handle this outside this function since other chips have
>> different registers.
> Ah, you're right, my bad :)
the current code i sended to benjamin makes several of these vars 
obsolete anyway.
just waiting for his new cleaned up version here on that list.

>
>
> Michał
>


-- 
Mit freundlichen Grüssen / Regards

Sebastian Gottschall / CTO

NewMedia-NET GmbH - DD-WRT
Firmensitz:  Berliner Ring 101, 64625 Bensheim
Registergericht: Amtsgericht Darmstadt, HRB 25473
Geschäftsführer: Peter Steinhäuser, Christian Scheele
http://www.dd-wrt.com
email: s.gottschall@dd-wrt.com
Tel.: +496251-582650 / Fax: +496251-5826565


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-08-04 11:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-01 10:21 [PATCHv2 0/2] ath10k: Allow setting coverage class Benjamin Berg
2016-08-01 10:21 ` [PATCHv2 1/2] ath10k: Rename hw_rx_desc_ops to hw_ops to use it for other purposes Benjamin Berg
2016-08-01 10:21 ` [PATCHv2 2/2] ath10k: Allow setting coverage class Benjamin Berg
2016-08-03  7:19   ` Michal Kazior
2016-08-03 15:37     ` Sebastian Gottschall
2016-08-04  5:28       ` Michal Kazior
2016-08-04 11:35         ` Sebastian Gottschall

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).