Skip to contentSkip to conversation

Add support for MCI BT coex

PATCH Superseded Mohammed Shafi Shajakhan 2 participants 23 messages Nov 22, 2011 – Nov 24, 2011 Qualcomm Atheros ATH9K wireless driver

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover Add support for MCI BT coex

From: Mohammed Shafi Shajakhan <[email protected]>

Add support for MCI BT-Coex for AR9462. with AR9462 we have WLAN and BT coexists via MCI protocol(Message Coexistence Interface) WLAN and BT exchanges GPM, SCHED messages and few other messages for coexistence.

*thanks to Senthil Balasubramanian <[email protected]> for his technical support

*thanks to Wilson Tsao <[email protected]> who being the core author of MCI, for his valuable help and documents

*thanks a lot to Rajkumar Manoharan <[email protected]> for his suggestions, review comments, code cleanups, and modifications in design.

bug fixes and few miscellaneous cleanups will be added then and there

Mohammed Shafi Shajakhan (18):
ath9k_hw: add definitions to support MCI h/w code
ath9k_hw: add GPIO output MUX related macros
ath9k_hw: Add MCI h/w specific structure
ath9k_hw: initialize MCI parameters
ath9k_hw: Add MCI h/w code and state machine
ath9k: Add MCI interrupt to interrupt mask
ath9k_hw: take care of enabling MCI interrupts
ath9k_hw: check for asynchronous MCI interrupt pending
ath9k_hw: check for MCI interrupt in get_isr
ath9k: add MCI specific definitions and structures
ath9k: Add functions to allocate/free buffers for MCI
ath9k_hw: MCI related changes in chip management
ath9k_hw: MCI related changes in set_reset_reg
ath9k_hw: Add support for MCI WLAN calibration
ath9k_hw: Add MCI related changes in chip reset
ath9k: make ath_reset non-static
ath9k: MCI state machine based on MCI interrupt
ath9k: fix a typo

 drivers/net/wireless/ath/ath9k/Makefile       |    3 +-
 drivers/net/wireless/ath/ath9k/ar9003_calib.c |   43 +
 drivers/net/wireless/ath/ath9k/ar9003_mac.c   |   36 +-
 drivers/net/wireless/ath/ath9k/ar9003_mci.c   | 1464 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/ar9003_mci.h   |  102 ++
 drivers/net/wireless/ath/ath9k/ar9003_phy.h   |    3 +
 drivers/net/wireless/ath/ath9k/ath9k.h        |    2 +
 drivers/net/wireless/ath/ath9k/btcoex.c       |    2 +-
 drivers/net/wireless/ath/ath9k/btcoex.h       |   31 +
 drivers/net/wireless/ath/ath9k/hw.c           |  174 +++-
 drivers/net/wireless/ath/ath9k/hw.h           |  182 +++
 drivers/net/wireless/ath/ath9k/init.c         |   33 +
 drivers/net/wireless/ath/ath9k/mac.c          |   17 +-
 drivers/net/wireless/ath/ath9k/main.c         |   11 +-
 drivers/net/wireless/ath/ath9k/mci.c          |  419 +++++++
 drivers/net/wireless/ath/ath9k/mci.h          |   20 +
 drivers/net/wireless/ath/ath9k/reg.h          |  306 +++++-
 17 files changed, 2807 insertions(+), 41 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_mci.c
 create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_mci.h
#1 lore raw

PATCH 1/18 ath9k_hw: add definitions to support MCI h/w code

From: Mohammed Shafi Shajakhan <[email protected]>

these definitions will be used by MCI state machine and the corresponding hardware code

---
 drivers/net/wireless/ath/ath9k/ar9003_mci.h |  102 +++++++++
 drivers/net/wireless/ath/ath9k/ar9003_phy.h |    3 +
 drivers/net/wireless/ath/ath9k/hw.h         |  146 +++++++++++++
 drivers/net/wireless/ath/ath9k/reg.h        |  304 ++++++++++++++++++++++++---
 4 files changed, 529 insertions(+), 26 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_mci.h
drivers/net/wireless/ath/ath9k/ar9003_mci.h new file +102 -0
new file mode 100644
index 0000000..798da11
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef AR9003_MCI_H
+#define AR9003_MCI_H
+
+#define MCI_FLAG_DISABLE_TIMESTAMP      0x00000001      /* Disable time stamp */
+
+/* Default remote BT device MCI COEX version */
+#define MCI_GPM_COEX_MAJOR_VERSION_DEFAULT  3
+#define MCI_GPM_COEX_MINOR_VERSION_DEFAULT  0
+
+/* Local WLAN MCI COEX version */
+#define MCI_GPM_COEX_MAJOR_VERSION_WLAN     3
+#define MCI_GPM_COEX_MINOR_VERSION_WLAN     0
+
+enum mci_gpm_coex_query_type {
+	MCI_GPM_COEX_QUERY_BT_ALL_INFO      = BIT(0),
+	MCI_GPM_COEX_QUERY_BT_TOPOLOGY      = BIT(1),
+	MCI_GPM_COEX_QUERY_BT_DEBUG         = BIT(2),
+};
+
+enum mci_gpm_coex_halt_bt_gpm {
+	MCI_GPM_COEX_BT_GPM_UNHALT,
+	MCI_GPM_COEX_BT_GPM_HALT
+};
+
+enum mci_gpm_coex_bt_update_flags_op {
+	MCI_GPM_COEX_BT_FLAGS_READ,
+	MCI_GPM_COEX_BT_FLAGS_SET,
+	MCI_GPM_COEX_BT_FLAGS_CLEAR
+};
+
+#define MCI_NUM_BT_CHANNELS     79
+
+#define MCI_BT_MCI_FLAGS_UPDATE_CORR          0x00000002
+#define MCI_BT_MCI_FLAGS_UPDATE_HDR           0x00000004
+#define MCI_BT_MCI_FLAGS_UPDATE_PLD           0x00000008
+#define MCI_BT_MCI_FLAGS_LNA_CTRL             0x00000010
+#define MCI_BT_MCI_FLAGS_DEBUG                0x00000020
+#define MCI_BT_MCI_FLAGS_SCHED_MSG            0x00000040
+#define MCI_BT_MCI_FLAGS_CONT_MSG             0x00000080
+#define MCI_BT_MCI_FLAGS_COEX_GPM             0x00000100
+#define MCI_BT_MCI_FLAGS_CPU_INT_MSG          0x00000200
+#define MCI_BT_MCI_FLAGS_MCI_MODE             0x00000400
+#define MCI_BT_MCI_FLAGS_AR9462_MODE          0x00001000
+#define MCI_BT_MCI_FLAGS_OTHER                0x00010000
+
+#define MCI_DEFAULT_BT_MCI_FLAGS              0x00011dde
+
+#define MCI_TOGGLE_BT_MCI_FLAGS  (MCI_BT_MCI_FLAGS_UPDATE_CORR | \
+				  MCI_BT_MCI_FLAGS_UPDATE_HDR  | \
+				  MCI_BT_MCI_FLAGS_UPDATE_PLD  | \
+				  MCI_BT_MCI_FLAGS_MCI_MODE)
+
+#define MCI_2G_FLAGS_CLEAR_MASK   0x00000000
+#define MCI_2G_FLAGS_SET_MASK     MCI_TOGGLE_BT_MCI_FLAGS
+#define MCI_2G_FLAGS              MCI_DEFAULT_BT_MCI_FLAGS
+
+#define MCI_5G_FLAGS_CLEAR_MASK   MCI_TOGGLE_BT_MCI_FLAGS
+#define MCI_5G_FLAGS_SET_MASK     0x00000000
+#define MCI_5G_FLAGS              (MCI_DEFAULT_BT_MCI_FLAGS & \
+				   ~MCI_TOGGLE_BT_MCI_FLAGS)
+
+/*
+ * Default value for AR9462 is 0x00002201
+ */
+#define ATH_MCI_CONFIG_CONCUR_TX            0x00000003
+#define ATH_MCI_CONFIG_MCI_OBS_MCI          0x00000004
+#define ATH_MCI_CONFIG_MCI_OBS_TXRX         0x00000008
+#define ATH_MCI_CONFIG_MCI_OBS_BT           0x00000010
+#define ATH_MCI_CONFIG_DISABLE_MCI_CAL      0x00000020
+#define ATH_MCI_CONFIG_DISABLE_OSLA         0x00000040
+#define ATH_MCI_CONFIG_DISABLE_FTP_STOMP    0x00000080
+#define ATH_MCI_CONFIG_AGGR_THRESH          0x00000700
+#define ATH_MCI_CONFIG_AGGR_THRESH_S        8
+#define ATH_MCI_CONFIG_DISABLE_AGGR_THRESH  0x00000800
+#define ATH_MCI_CONFIG_CLK_DIV              0x00003000
+#define ATH_MCI_CONFIG_CLK_DIV_S            12
+#define ATH_MCI_CONFIG_DISABLE_TUNING       0x00004000
+#define ATH_MCI_CONFIG_MCI_WEIGHT_DBG       0x40000000
+#define ATH_MCI_CONFIG_DISABLE_MCI          0x80000000
+
+#define ATH_MCI_CONFIG_MCI_OBS_MASK     (ATH_MCI_CONFIG_MCI_OBS_MCI  | \
+					 ATH_MCI_CONFIG_MCI_OBS_TXRX | \
+					 ATH_MCI_CONFIG_MCI_OBS_BT)
+#define ATH_MCI_CONFIG_MCI_OBS_GPIO     0x0000002F
+
+#endif
drivers/net/wireless/ath/ath9k/ar9003_phy.h +3 -0
index 497d746..ed64114 100644
@@ -490,6 +490,8 @@
 #define AR_PHY_TEST_CTL_TSTADC_EN_S       8
 #define AR_PHY_TEST_CTL_RX_OBS_SEL        0x3C00
 #define AR_PHY_TEST_CTL_RX_OBS_SEL_S      10
+#define AR_PHY_TEST_CTL_DEBUGPORT_SEL	  0xe0000000
+#define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S	  29
 
 
 #define AR_PHY_TSTDAC            (AR_SM_BASE + 0x168)
@@ -1001,6 +1003,7 @@
 
 /* GLB Registers */
 #define AR_GLB_BASE	0x20000
+#define AR_GLB_GPIO_CONTROL	(AR_GLB_BASE)
 #define AR_PHY_GLB_CONTROL	(AR_GLB_BASE + 0x44)
 #define AR_GLB_SCRATCH(_ah)	(AR_GLB_BASE + \
 					(AR_SREV_9462_20(_ah) ? 0x4c : 0x50))
drivers/net/wireless/ath/ath9k/hw.h +146 -0

164 lines not on this page · raw message

drivers/net/wireless/ath/ath9k/reg.h +278 -26

333 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#2 lore raw

PATCH 2/18 ath9k_hw: add GPIO output MUX related macros

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

---
 drivers/net/wireless/ath/ath9k/hw.h |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/hw.h +10 -0
index 4f786cb..cd43d59 100644
@@ -126,6 +126,16 @@
 #define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL  4
 #define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    5
 #define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      6
+#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA      0x16
+#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK       0x17
+#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA        0x18
+#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK         0x19
+#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX           0x14
+#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX           0x13
+#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX           9
+#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX           8
+#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_STROBE      0x1d
+#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA        0x1e
 
 #define AR_GPIOD_MASK               0x00001FFF
 #define AR_GPIO_BIT(_gpio)          (1 << (_gpio))
Signature · 1 line
1.7.0.4
#3 lore raw

PATCH 3/18 ath9k_hw: Add MCI h/w specific structure

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

---
 drivers/net/wireless/ath/ath9k/btcoex.h |   31 +++++++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/btcoex.h +31 -0
index d5e5db1..278361c 100644
@@ -54,8 +54,39 @@ enum ath_btcoex_scheme {
 	ATH_BTCOEX_CFG_MCI,
 };
 
+struct ath9k_hw_mci {
+	u32 raw_intr;
+	u32 rx_msg_intr;
+	u32 cont_status;
+	u32 gpm_addr;
+	u32 gpm_len;
+	u32 gpm_idx;
+	u32 sched_addr;
+	u32 wlan_channels[4];
+	u32 wlan_cal_seq;
+	u32 wlan_cal_done;
+	u32 config;
+	u8 *gpm_buf;
+	u8 *sched_buf;
+	bool ready;
+	bool update_2g5g;
+	bool is_2g;
+	bool query_bt;
+	bool unhalt_bt_gpm; /* need send UNHALT */
+	bool halted_bt_gpm; /* HALT sent */
+	bool need_flush_btinfo;
+	bool bt_version_known;
+	bool wlan_channels_update;
+	u8 wlan_ver_major;
+	u8 wlan_ver_minor;
+	u8 bt_ver_major;
+	u8 bt_ver_minor;
+	u8 bt_state;
+};
+
 struct ath_btcoex_hw {
 	enum ath_btcoex_scheme scheme;
+	struct ath9k_hw_mci mci;
 	bool enabled;
 	u8 wlanactive_gpio;
 	u8 btactive_gpio;
Signature · 1 line
1.7.0.4
#4 lore raw

PATCH 4/18 ath9k_hw: initialize MCI parameters

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

these parameter will be utilized and modified in the MCI hardware codes state machine

---
 drivers/net/wireless/ath/ath9k/init.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/init.c +22 -0
index e046de9..34b922b 100644
@@ -408,6 +408,7 @@ fail:
 static int ath9k_init_btcoex(struct ath_softc *sc)
 {
 	struct ath_txq *txq;
+	struct ath_hw *ah = sc->sc_ah;
 	int r;
 
 	switch (sc->sc_ah->btcoex_hw.scheme) {
@@ -426,6 +427,27 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
 		sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
 		sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
 		INIT_LIST_HEAD(&sc->btcoex.mci.info);
+		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
+			ah->btcoex_hw.mci.ready = false;
+			ah->btcoex_hw.mci.bt_state = 0;
+			ah->btcoex_hw.mci.bt_ver_major = 3;
+			ah->btcoex_hw.mci.bt_ver_minor = 0;
+			ah->btcoex_hw.mci.bt_version_known = false;
+			ah->btcoex_hw.mci.update_2g5g = true;
+			ah->btcoex_hw.mci.is_2g = true;
+			ah->btcoex_hw.mci.wlan_channels_update = false;
+			ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
+			ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
+			ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
+			ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
+			ah->btcoex_hw.mci.query_bt = true;
+			ah->btcoex_hw.mci.unhalt_bt_gpm = true;
+			ah->btcoex_hw.mci.halted_bt_gpm = false;
+			ah->btcoex_hw.mci.need_flush_btinfo = false;
+			ah->btcoex_hw.mci.wlan_cal_seq = 0;
+			ah->btcoex_hw.mci.wlan_cal_done = 0;
+			ah->btcoex_hw.mci.config = 0x2201;
+		}
 		break;
 	default:
 		WARN_ON(1);
Signature · 1 line
1.7.0.4
#5 lore raw

PATCH 5/18 ath9k_hw: Add MCI h/w code and state machine

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

---
 drivers/net/wireless/ath/ath9k/Makefile     |    3 +-
 drivers/net/wireless/ath/ath9k/ar9003_mci.c | 1464 +++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/hw.h         |   26 +
 3 files changed, 1492 insertions(+), 1 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_mci.c
drivers/net/wireless/ath/ath9k/Makefile +2 -1
index 49d3f25..390797d 100644
@@ -34,7 +34,8 @@ ath9k_hw-y:=	\
 		ar9002_mac.o \
 		ar9003_mac.o \
 		ar9003_eeprom.o \
-		ar9003_paprd.o
+		ar9003_paprd.o \
+		ar9003_mci.o
 
 obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
 
drivers/net/wireless/ath/ath9k/ar9003_mci.c new file +1464 -0

1,464 lines not on this page · raw message

drivers/net/wireless/ath/ath9k/hw.h +26 -0
index cd43d59..c9c3b18 100644
@@ -1203,6 +1203,32 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
 void ath9k_hw_proc_mib_event(struct ath_hw *ah);
 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
 
+bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
+			     u32 *payload, u8 len, bool wait_done,
+			     bool check_bt);
+void ar9003_mci_mute_bt(struct ath_hw *ah);
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
+void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
+		      u16 len, u32 sched_addr);
+void ar9003_mci_cleanup(struct ath_hw *ah);
+void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
+				      bool wait_done);
+u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
+			    u8 gpm_opcode, int time_out);
+void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g);
+void ar9003_mci_disable_interrupt(struct ath_hw *ah);
+void ar9003_mci_enable_interrupt(struct ath_hw *ah);
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
+		      bool is_full_sleep);
+bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints);
+void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_sync_bt_state(struct ath_hw *ah);
+void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
+			      u32 *rx_msg_intr);
+
 #define ATH9K_CLOCK_RATE_CCK		22
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM	40
 #define ATH9K_CLOCK_RATE_2GHZ_OFDM	44
Signature · 1 line
1.7.0.4
#6 lore raw

PATCH 6/18 ath9k: Add MCI interrupt to interrupt mask

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

---
 drivers/net/wireless/ath/ath9k/main.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
drivers/net/wireless/ath/ath9k/main.c +5 -1
index e43c41c..90d35f2 100644
@@ -764,7 +764,8 @@ irqreturn_t ath_isr(int irq, void *dev)
 		ATH9K_INT_BMISS |		\
 		ATH9K_INT_CST |			\
 		ATH9K_INT_TSFOOR |		\
-		ATH9K_INT_GENTIMER)
+		ATH9K_INT_GENTIMER |		\
+		ATH9K_INT_MCI)
 
 	struct ath_softc *sc = dev;
 	struct ath_hw *ah = sc->sc_ah;
@@ -1119,6 +1120,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
 		ah->imask |= ATH9K_INT_CST;
 
+	if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+		ah->imask |= ATH9K_INT_MCI;
+
 	sc->sc_flags &= ~SC_OP_INVALID;
 	sc->sc_ah->is_monitoring = false;
 
Signature · 1 line
1.7.0.4
#7 lore raw

PATCH 7/18 ath9k_hw: take care of enabling MCI interrupts

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

enable MCI interrupt when ath9k_hw_enable_interrupts is called, like during the completion of chip_reset before which the interrupts are disabled

---
 drivers/net/wireless/ath/ath9k/mac.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)
drivers/net/wireless/ath/ath9k/mac.c +8 -4
index ecdb6fd..9d69320 100644
@@ -798,6 +798,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	u32 sync_default = AR_INTR_SYNC_DEFAULT;
+	u32 async_mask;
 
 	if (!(ah->imask & ATH9K_INT_GLOBAL))
 		return;
@@ -812,13 +813,16 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
 	if (AR_SREV_9340(ah))
 		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
 
+	async_mask = AR_INTR_MAC_IRQ;
+
+	if (ah->imask & ATH9K_INT_MCI)
+		async_mask |= AR_INTR_ASYNC_MASK_MCI;
+
 	ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n");
 	REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
 	if (!AR_SREV_9100(ah)) {
-		REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
-			  AR_INTR_MAC_IRQ);
-		REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
-
+		REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, async_mask);
+		REG_WRITE(ah, AR_INTR_ASYNC_MASK, async_mask);
 
 		REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
 		REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default);
Signature · 1 line
1.7.0.4
#8 lore raw

PATCH 8/18 ath9k_hw: check for asynchronous MCI interrupt pending

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

MCI interrupt is an asynchronous one, so take care of it by having a check in ath9k_hw_intrpend, which actually decides whether the interrupt is really for the driver from ath_isr

---
 drivers/net/wireless/ath/ath9k/mac.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)
drivers/net/wireless/ath/ath9k/mac.c +4 -1
index 9d69320..0e4fbb3 100644
@@ -760,7 +760,10 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
 		return true;
 
 	host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
-	if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS))
+
+	if (((host_isr & AR_INTR_MAC_IRQ) ||
+	     (host_isr & AR_INTR_ASYNC_MASK_MCI)) &&
+	    (host_isr != AR_INTR_SPURIOUS))
 		return true;
 
 	host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
Signature · 1 line
1.7.0.4
#9 lore raw

PATCH 9/18 ath9k_hw: check for MCI interrupt in get_isr

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

check for the condition of MCI interrupt being triggered and appropriately obtain the values of MCI_INTERRUPT_RX_MSG_RAW and MCI_INTERRUPT_RAW

---
 drivers/net/wireless/ath/ath9k/ar9003_mac.c |   36 +++++++++++++++++++++++++-
 1 files changed, 34 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath9k/ar9003_mac.c +34 -2
index ccde784..95587e3 100644
@@ -175,15 +175,47 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 	u32 isr = 0;
 	u32 mask2 = 0;
 	struct ath9k_hw_capabilities *pCap = &ah->caps;
-	u32 sync_cause = 0;
 	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+	u32 sync_cause = 0, async_cause;
 
-	if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
+	async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
+
+	if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) {
 		if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
 				== AR_RTC_STATUS_ON)
 			isr = REG_READ(ah, AR_ISR);
 	}
 
+	if (async_cause & AR_INTR_ASYNC_MASK_MCI) {
+		u32 raw_intr, rx_msg_intr;
+
+		rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
+		raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);
+
+		if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef))
+			ath_dbg(common, ATH_DBG_MCI,
+				"MCI gets 0xdeadbeef during MCI int processing"
+				"new raw_intr=0x%08x, new rx_msg_raw=0x%08x, "
+				"raw_intr=0x%08x, rx_msg_raw=0x%08x\n",
+				raw_intr, rx_msg_intr, mci->raw_intr,
+				mci->rx_msg_intr);
+		else {
+			mci->rx_msg_intr |= rx_msg_intr;
+			mci->raw_intr |= raw_intr;
+			*masked |= ATH9K_INT_MCI;
+
+			if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)
+				mci->cont_status =
+					REG_READ(ah, AR_MCI_CONT_STATUS);
+
+			REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);
+			REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);
+			ath_dbg(common, ATH_DBG_MCI, "AR_INTR_SYNC_MCI\n");
+
+		}
+	}
+
 	sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT;
 
 	*masked = 0;
Signature · 1 line
1.7.0.4
#10 lore raw

PATCH 10/18 ath9k: add MCI specific definitions and structures

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

---
 drivers/net/wireless/ath/ath9k/mci.h |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/mci.h +17 -0
index 9590c61..5df0d60 100644
@@ -17,6 +17,9 @@
 #ifndef MCI_H
 #define MCI_H
 
+#define ATH_MCI_SCHED_BUF_SIZE		(16 * 16) /* 16 entries, 4 dword each */
+#define ATH_MCI_GPM_MAX_ENTRY		16
+#define ATH_MCI_GPM_BUF_SIZE		(ATH_MCI_GPM_MAX_ENTRY * 16)
 #define ATH_MCI_DEF_BT_PERIOD		40
 #define ATH_MCI_BDR_DUTY_CYCLE		20
 #define ATH_MCI_MAX_DUTY_CYCLE		90
@@ -110,6 +113,20 @@ struct ath_mci_profile {
 	u8 num_bdr;
 };
 
+
+struct ath_mci_buf {
+	void *bf_addr;		/* virtual addr of desc */
+	dma_addr_t bf_paddr;    /* physical addr of buffer */
+	u32 bf_len;		/* len of data */
+};
+
+struct ath_mci_coex {
+	atomic_t mci_cal_flag;
+	struct ath_mci_buf sched_buf;
+	struct ath_mci_buf gpm_buf;
+	u32 bt_cal_start;
+};
+
 void ath_mci_flush_profile(struct ath_mci_profile *mci);
 void ath_mci_process_profile(struct ath_softc *sc,
 			     struct ath_mci_profile_info *info);
Signature · 1 line
1.7.0.4
#11 lore raw

PATCH 11/18 ath9k: Add functions to allocate/free buffers for MCI

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

required buffers and dma allocation is done for GPM and SCHED messages

---
 drivers/net/wireless/ath/ath9k/ath9k.h |    1 +
 drivers/net/wireless/ath/ath9k/mci.c   |   78 ++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/mci.h   |    2 +
 3 files changed, 81 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/ath9k.h +1 -0
index 93b45b4..9f28cc4 100644
@@ -647,6 +647,7 @@ struct ath_softc {
 	struct delayed_work tx_complete_work;
 	struct delayed_work hw_pll_work;
 	struct ath_btcoex btcoex;
+	struct ath_mci_coex mci_coex;
 
 	struct ath_descdma txsdma;
 
drivers/net/wireless/ath/ath9k/mci.c +78 -0

87 lines not on this page · raw message

drivers/net/wireless/ath/ath9k/mci.h +2 -0
index 5df0d60..4eeb0fe 100644
@@ -132,4 +132,6 @@ void ath_mci_process_profile(struct ath_softc *sc,
 			     struct ath_mci_profile_info *info);
 void ath_mci_process_status(struct ath_softc *sc,
 			    struct ath_mci_profile_status *status);
+int ath_mci_setup(struct ath_softc *sc);
+void ath_mci_cleanup(struct ath_softc *sc);
 #endif
Signature · 1 line
1.7.0.4
#12 lore raw

PATCH 12/18 ath9k_hw: MCI related changes in chip management

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

send halt BT GPM if the chip is in network sleep and BT state is awake

---
 drivers/net/wireless/ath/ath9k/hw.c  |   24 ++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/reg.h |    2 ++
 2 files changed, 26 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/hw.c +24 -0
index 662ab7e..ba5734a 100644
@@ -1933,6 +1933,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 	int status = true, setChip = true;
 	static const char *modes[] = {
 		"AWAKE",
@@ -1950,12 +1951,35 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 	switch (mode) {
 	case ATH9K_PM_AWAKE:
 		status = ath9k_hw_set_power_awake(ah, setChip);
+
+		if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+			REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+
 		break;
 	case ATH9K_PM_FULL_SLEEP:
+
+		if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
+			if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
+				(mci->bt_state != MCI_BT_SLEEP) &&
+				!mci->halted_bt_gpm) {
+				ath_dbg(common, ATH_DBG_MCI, "MCI halt BT GPM"
+						"(full_sleep)");
+				ar9003_mci_send_coex_halt_bt_gpm(ah,
+								 true, true);
+			}
+
+			mci->ready = false;
+			REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+		}
+
 		ath9k_set_power_sleep(ah, setChip);
 		ah->chip_fullsleep = true;
 		break;
 	case ATH9K_PM_NETWORK_SLEEP:
+
+		if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+			REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+
 		ath9k_set_power_network_sleep(ah, setChip);
 		break;
 	default:
drivers/net/wireless/ath/ath9k/reg.h +2 -0
index ba3672f..6e2f188 100644
@@ -1279,6 +1279,8 @@ enum {
 #define AR_RTC_INTR_MASK \
 	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058)
 
+#define AR_RTC_KEEP_AWAKE	0x7034
+
 /* RTC_DERIVED_* - only for AR9100 */
 
 #define AR_RTC_DERIVED_CLK \
Signature · 1 line
1.7.0.4
#13 lore raw

PATCH 13/18 ath9k_hw: MCI related changes in set_reset_reg

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

---
 drivers/net/wireless/ath/ath9k/hw.c |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)
drivers/net/wireless/ath/ath9k/hw.c +11 -3
index ba5734a..1d71d1b 100644
@@ -1350,6 +1350,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 {
+	bool ret = false;
 
 	if (AR_SREV_9300_20_OR_LATER(ah)) {
 		REG_WRITE(ah, AR_WA, ah->WARegVal);
@@ -1361,13 +1362,20 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 
 	switch (type) {
 	case ATH9K_RESET_POWER_ON:
-		return ath9k_hw_set_reset_power_on(ah);
+		ret = ath9k_hw_set_reset_power_on(ah);
+		break;
 	case ATH9K_RESET_WARM:
 	case ATH9K_RESET_COLD:
-		return ath9k_hw_set_reset(ah, type);
+		ret = ath9k_hw_set_reset(ah, type);
+		break;
 	default:
-		return false;
+		break;
 	}
+
+	if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+		REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+
+	return ret;
 }
 
 static bool ath9k_hw_chip_reset(struct ath_hw *ah,
Signature · 1 line
1.7.0.4
#14 lore raw

PATCH 14/18 ath9k_hw: Add support for MCI WLAN calibration

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

WLAN communicates with BT for its calibration by sending WLAN_CAL_REQ, waits for BT_CAL_GRANT. This is done with the help of GPM messages. also WLAN_CAL_DONE messages is sent once WLAN calibration is done.

---
 drivers/net/wireless/ath/ath9k/ar9003_calib.c |   43 +++++++++++++++++++++++++
 1 files changed, 43 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/ar9003_calib.c +43 -0
index 12a730d..f7bc05c 100644
@@ -18,6 +18,7 @@
 #include "hw-ops.h"
 #include "ar9003_phy.h"
 #include "ar9003_rtt.h"
+#include "ar9003_mci.h"
 
 #define MAX_MEASUREMENT	MAX_IQCAL_MEASUREMENT
 #define MAX_MAG_DELTA	11
@@ -934,10 +935,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_cal_data *caldata = ah->caldata;
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
 	bool txiqcal_done = false, txclcal_done = false;
 	bool is_reusable = true, status = true;
 	bool run_rtt_cal = false, run_agc_cal;
 	bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
+	bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
 	u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
 					  AR_PHY_AGC_CONTROL_FLTR_CAL   |
 					  AR_PHY_AGC_CONTROL_PKDET_CAL;
@@ -1005,6 +1008,31 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 	} else if (caldata && !caldata->done_txiqcal_once)
 		run_agc_cal = true;
 
+	if (mci && IS_CHAN_2GHZ(chan) &&
+	    (mci_hw->bt_state  == MCI_BT_AWAKE) &&
+	    run_agc_cal &&
+	    !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
+
+		u32 pld[4] = {0, 0, 0, 0};
+
+		/* send CAL_REQ only when BT is AWAKE. */
+		ath_dbg(common, ATH_DBG_MCI, "MCI send WLAN_CAL_REQ 0x%x\n",
+			mci_hw->wlan_cal_seq);
+		MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);
+		pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;
+		ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
+
+		/* Wait BT_CAL_GRANT for 50ms */
+		ath_dbg(common, ATH_DBG_MCI, "MCI wait for BT_CAL_GRANT");
+
+		if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000))
+			ath_dbg(common, ATH_DBG_MCI, "MCI got BT_CAL_GRANT");
+		else {
+			is_reusable = false;
+			ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is not responding");
+		}
+	}
+
 	txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
 	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
 	udelay(5);
@@ -1022,6 +1050,21 @@ skip_tx_iqcal:
 				       AR_PHY_AGC_CONTROL_CAL,
 				       0, AH_WAIT_TIMEOUT);
 	}
+
+	if (mci && IS_CHAN_2GHZ(chan) &&
+	    (mci_hw->bt_state  == MCI_BT_AWAKE)	&&
+	    run_agc_cal	&&
+	    !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
+
+		u32 pld[4] = {0, 0, 0, 0};
+
+		ath_dbg(common, ATH_DBG_MCI, "MCI Send WLAN_CAL_DONE 0x%x\n",
+			mci_hw->wlan_cal_done);
+		MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);
+		pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;
+		ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
+	}
+
 	if (rtt && !run_rtt_cal) {
 		agc_ctrl |= agc_supp_cals;
 		REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
Signature · 1 line
1.7.0.4
#15 lore raw

PATCH 15/18 ath9k_hw: Add MCI related changes in chip reset

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

here we check for BT state and if BT calibration has started, give 25ms for BT Calibration to finish. we also take care of 2G/5G switch and LNA transfer incase WLAN is operating in 5G. in case the BT state is awake when we do WLAN calibration re-calibrate and we reset the message exchange between WLAN and BT. BT is given preference when simultaneous CAL request happens. calibration for WLAN/BT is done assuming that the other co-existing module is in awake state, if not we continue to do calibration while if the other module's state changes we need to do restart the calibration handshake

---
 drivers/net/wireless/ath/ath9k/hw.c |  132 +++++++++++++++++++++++++++++++++++
 1 files changed, 132 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/hw.c +132 -0
index 1d71d1b..e2860d7 100644
@@ -1514,6 +1514,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 		   struct ath9k_hw_cal_data *caldata, bool bChannelChange)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
 	u32 saveLedState;
 	struct ath9k_channel *curchan = ah->curchan;
 	u32 saveDefAntenna;
@@ -1521,6 +1522,53 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	u64 tsf = 0;
 	int i, r;
 	bool allow_fbs = false;
+	bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
+	bool save_fullsleep = ah->chip_fullsleep;
+
+	if (mci) {
+
+		ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
+
+		if (mci_hw->bt_state == MCI_BT_CAL_START) {
+			u32 payload[4] = {0, 0, 0, 0};
+
+			ath_dbg(common, ATH_DBG_MCI, "MCI stop rx for BT CAL");
+
+			mci_hw->bt_state = MCI_BT_CAL;
+
+			/*
+			 * MCI FIX: disable mci interrupt here. This is to avoid
+			 * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and
+			 * lead to mci_intr reentry.
+			 */
+
+			ar9003_mci_disable_interrupt(ah);
+
+			ath_dbg(common, ATH_DBG_MCI, "send WLAN_CAL_GRANT");
+			MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
+			ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
+						16, true, false);
+
+			ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is calibrating");
+
+			/* Wait BT calibration to be completed for 25ms */
+
+			if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,
+								  0, 25000))
+				ath_dbg(common, ATH_DBG_MCI,
+					"MCI got BT_CAL_DONE\n");
+			else
+				ath_dbg(common, ATH_DBG_MCI,
+					"MCI ### BT cal takes to long, force"
+					"bt_state to be bt_awake\n");
+			mci_hw->bt_state = MCI_BT_AWAKE;
+			/* MCI FIX: enable mci interrupt here */
+			ar9003_mci_enable_interrupt(ah);
+
+			return true;
+		}
+	}
+
 
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
 		return -EIO;
@@ -1558,12 +1606,29 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 		if (ath9k_hw_channel_change(ah, chan)) {
 			ath9k_hw_loadnf(ah, ah->curchan);
 			ath9k_hw_start_nfcal(ah, true);
+			if (mci && mci_hw->ready)
+				ar9003_mci_2g5g_switch(ah, true);
+
 			if (AR_SREV_9271(ah))
 				ar9002_hw_load_ani_reg(ah, chan);
 			return 0;
 		}
 	}
 
+	if (mci) {
+		ar9003_mci_disable_interrupt(ah);
+
+		if (mci_hw->ready && !save_fullsleep) {
+			ar9003_mci_mute_bt(ah);
+			udelay(20);
+			REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
+		}
+
+		mci_hw->bt_state = MCI_BT_SLEEP;
+		mci_hw->ready = false;
+	}
+
+
 	saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
 	if (saveDefAntenna == 0)
 		saveDefAntenna = 1;
@@ -1619,6 +1684,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (r)
 		return r;
 
+	if (mci)
+		ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
+
 	/*
 	 * Some AR91xx SoC devices frequently fail to accept TSF writes
 	 * right after the chip reset. When that happens, write a new
@@ -1736,6 +1804,55 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	ath9k_hw_loadnf(ah, chan);
 	ath9k_hw_start_nfcal(ah, true);
 
+	if (mci && mci_hw->ready) {
+
+		if (IS_CHAN_2GHZ(chan) &&
+		    (mci_hw->bt_state == MCI_BT_SLEEP)) {
+
+			if (ar9003_mci_check_int(ah,
+			    AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
+			    ar9003_mci_check_int(ah,
+			    AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
+
+				/*
+				 * BT is sleeping. Check if BT wakes up during
+				 * WLAN calibration. If BT wakes up during
+				 * WLAN calibration, need to go through all
+				 * message exchanges again and recal.
+				 */
+
+				ath_dbg(common, ATH_DBG_MCI, "MCI BT wakes up"
+					"during WLAN calibration\n");
+
+				REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+					  AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
+					  AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
+				ath_dbg(common, ATH_DBG_MCI, "MCI send"
+					"REMOTE_RESET\n");
+				ar9003_mci_remote_reset(ah, true);
+				ar9003_mci_send_sys_waking(ah, true);
+				udelay(1);
+				if (IS_CHAN_2GHZ(chan))
+					ar9003_mci_send_lna_transfer(ah, true);
+
+				mci_hw->bt_state = MCI_BT_AWAKE;
+
+				ath_dbg(common, ATH_DBG_MCI, "MCI re-cal\n");
+
+				if (caldata) {
+					caldata->done_txiqcal_once = false;
+					caldata->done_txclcal_once = false;
+					caldata->rtt_hist.num_readings = 0;
+				}
+
+				if (!ath9k_hw_init_cal(ah, chan))
+					return -EIO;
+
+			}
+		}
+		ar9003_mci_enable_interrupt(ah);
+	}
+
 	ENABLE_REGWRITE_BUFFER(ah);
 
 	ath9k_hw_restore_chainmask(ah);
@@ -1778,6 +1895,21 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (ah->btcoex_hw.enabled)
 		ath9k_hw_btcoex_enable(ah);
 
+	if (mci && mci_hw->ready) {
+		/*
+		 * check BT state again to make
+		 * sure it's not changed.
+		 */
+
+		ar9003_mci_sync_bt_state(ah);
+		ar9003_mci_2g5g_switch(ah, true);
+
+		if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
+				(mci_hw->query_bt == true)) {
+			mci_hw->need_flush_btinfo = true;
+		}
+	}
+
 	if (AR_SREV_9300_20_OR_LATER(ah)) {
 		ar9003_hw_bb_watchdog_config(ah);
 
Signature · 1 line
1.7.0.4
#16 lore raw

PATCH 16/18 ath9k: make ath_reset non-static

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

to be used by MCI specific changes

---
 drivers/net/wireless/ath/ath9k/ath9k.h |    1 +
 drivers/net/wireless/ath/ath9k/main.c  |    2 +-
 2 files changed, 2 insertions(+), 1 deletions(-)
drivers/net/wireless/ath/ath9k/ath9k.h +1 -0
index 9f28cc4..c04ff7d 100644
@@ -424,6 +424,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
 
 #define ATH_PAPRD_TIMEOUT	100 /* msecs */
 
+int ath_reset(struct ath_softc *sc, bool retry_tx);
 void ath_reset_work(struct work_struct *work);
 void ath_hw_check(struct work_struct *work);
 void ath_hw_pll_work(struct work_struct *work);
drivers/net/wireless/ath/ath9k/main.c +1 -1
index 90d35f2..c9578ab 100644
@@ -959,7 +959,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 	ath9k_ps_restore(sc);
 }
 
-static int ath_reset(struct ath_softc *sc, bool retry_tx)
+int ath_reset(struct ath_softc *sc, bool retry_tx)
 {
 	int r;
 
Signature · 1 line
1.7.0.4
#17 lore raw

PATCH 16/18 ath9k: make ath_reset non-static

Quoted 8 lines · Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

to be used by MCI specific changes

NACK. ath_reset can no longer be called in tasklet context (which you seem to be doing in the next patch).
Replace your ath_reset() call with:
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);

- Felix

#18 lore raw

PATCH 16/18 ath9k: make ath_reset non-static

Hi Felix,

thanks for your review.

Quoted 9 lines · Felix Fietkau
Quoted 8 lines · Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan<[email protected]>

to be used by MCI specific changes

Quoted 6 lines

NACK. ath_reset can no longer be called in tasklet context (which you seem to be doing in the next patch).
Replace your ath_reset() call with:

   ieee80211_queue_work(sc->hw,&sc->hw_reset_work);

- Felix

just like in ath9k_flush, i like to have the chip reset immediately rather than queuing at as a work.
in chip reset we have:
*we have BT calibration
*sync up with BT state
*2g_5g change
*LNA transfer
and few other things

when BT asks for calibration i understand we have to immediately give preference to it.
please let me know if i had missed something and also if queuing ath_reset actually helps us in some way.
i will revert this back once i test queue_work does no harm.

Signature · 2 lines
thanks,
shafi
#19 lore raw

PATCH 16/18 ath9k: make ath_reset non-static

Quoted 29 lines · Mohammed Shafi Shajakhan

Hi Felix,

thanks for your review.

Quoted 9 lines · Felix Fietkau
Quoted 8 lines · Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan<[email protected]>

to be used by MCI specific changes

Quoted 6 lines

NACK. ath_reset can no longer be called in tasklet context (which you seem to be doing in the next patch).
Replace your ath_reset() call with:

   ieee80211_queue_work(sc->hw,&sc->hw_reset_work);

- Felix

just like in ath9k_flush, i like to have the chip reset immediately rather than queuing at as a work.
in chip reset we have:
*we have BT calibration
*sync up with BT state
*2g_5g change
*LNA transfer
and few other things

Quoted 5 lines

when BT asks for calibration i understand we have to immediately give preference to it.
please let me know if i had missed something and also if queuing ath_reset actually helps us in some way.
i will revert this back once i test queue_work does no harm.

Doing reset from tasklet context created several nasty stability issues that were hard to track down, and the potential gain from doing reset 'immediately' that way is purely theoretical. Resets should be rare in normal operation, as they're also expensive.
The main problem when running reset from a tasklet is that there is no way of gracefully shutting down ongoing workqueue activity, so the result of the reset could be that the work items mess up the state right after the reset is done.

- Felix

#20 lore raw

PATCH 16/18 ath9k: make ath_reset non-static

Quoted 8 lines · Felix Fietkau

Doing reset from tasklet context created several nasty stability issues that were hard to track down, and the potential gain from doing reset 'immediately' that way is purely theoretical. Resets should be rare in normal operation, as they're also expensive.
The main problem when running reset from a tasklet is that there is no way of gracefully shutting down ongoing workqueue activity, so the result of the reset could be that the work items mess up the state right after the reset is done.

thanks, true in this case ath_reset is called from tasklet context. i will send a v2 for using queue_work.

Quoted 2 lines

- Felix

Signature · 2 lines
thanks,
shafi
#21 lore raw

PATCH 17/18 ath9k: MCI state machine based on MCI interrupt

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

---
 drivers/net/wireless/ath/ath9k/hw.c   |    4 +-
 drivers/net/wireless/ath/ath9k/init.c |   11 +
 drivers/net/wireless/ath/ath9k/main.c |    3 +
 drivers/net/wireless/ath/ath9k/mci.c  |  341 +++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/mci.h  |    1 +
 5 files changed, 359 insertions(+), 1 deletions(-)
drivers/net/wireless/ath/ath9k/hw.c +3 -1
index e2860d7..5abe682 100644
@@ -2397,7 +2397,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 		pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
 	if (common->btcoex_enabled) {
-		if (AR_SREV_9300_20_OR_LATER(ah)) {
+		if (AR_SREV_9462(ah))
+			btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
+		else if (AR_SREV_9300_20_OR_LATER(ah)) {
 			btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
 			btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
 			btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
drivers/net/wireless/ath/ath9k/init.c +11 -0
index 34b922b..e9711e2 100644
@@ -425,8 +425,16 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
 		txq = sc->tx.txq_map[WME_AC_BE];
 		ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
 		sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+		break;
+	case ATH_BTCOEX_CFG_MCI:
+		sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
 		sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
 		INIT_LIST_HEAD(&sc->btcoex.mci.info);
+
+		r = ath_mci_setup(sc);
+		if (r)
+			return r;
+
 		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
 			ah->btcoex_hw.mci.ready = false;
 			ah->btcoex_hw.mci.bt_state = 0;
@@ -861,6 +869,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
 	    sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
 		ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
 
+	if (sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_MCI)
+		ath_mci_cleanup(sc);
+
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
 		if (ATH_TXQ_SETUP(sc, i))
 			ath_tx_cleanupq(sc, &sc->tx.txq[i]);
drivers/net/wireless/ath/ath9k/main.c +3 -0
index c9578ab..1149764 100644
@@ -742,6 +742,9 @@ void ath9k_tasklet(unsigned long data)
 		if (status & ATH9K_INT_GENTIMER)
 			ath_gen_timer_isr(sc->sc_ah);
 
+	if (status & ATH9K_INT_MCI)
+		ath_mci_intr(sc);
+
 out:
 	/* re-enable hardware interrupt */
 	ath9k_hw_enable_interrupts(ah);
drivers/net/wireless/ath/ath9k/mci.c +341 -0

356 lines not on this page · raw message

drivers/net/wireless/ath/ath9k/mci.h +1 -0
index 4eeb0fe..b71bded 100644
@@ -134,4 +134,5 @@ void ath_mci_process_status(struct ath_softc *sc,
 			    struct ath_mci_profile_status *status);
 int ath_mci_setup(struct ath_softc *sc);
 void ath_mci_cleanup(struct ath_softc *sc);
+void ath_mci_intr(struct ath_softc *sc);
 #endif
Signature · 1 line
1.7.0.4
#22 lore raw

PATCH 18/18 ath9k: fix a typo

In reply to Mohammed Shafi Shajakhan

From: Mohammed Shafi Shajakhan <[email protected]>

---
 drivers/net/wireless/ath/ath9k/btcoex.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/net/wireless/ath/ath9k/btcoex.c +1 -1
index 9ac28d9..bbb2081 100644
@@ -21,7 +21,7 @@ enum ath_bt_mode {
 	ATH_BT_COEX_MODE_LEGACY,        /* legacy rx_clear mode */
 	ATH_BT_COEX_MODE_UNSLOTTED,     /* untimed/unslotted mode */
 	ATH_BT_COEX_MODE_SLOTTED,       /* slotted mode */
-	ATH_BT_COEX_MODE_DISALBED,      /* coexistence disabled */
+	ATH_BT_COEX_MODE_DISABLED,      /* coexistence disabled */
 };
 
 struct ath_btcoex_config {
Signature · 1 line
1.7.0.4