Skip to contentSkip to conversation

ath11k: suspend support for QCA6390 PCI

PATCH In review Kalle Valo 1 participant 13 messages Dec 11, 2020 – Dec 12, 2020 Qualcomm Atheros ATH11K wireless driver

lore
Share & tools
lore

Kalle Valo

author
#0 lore raw

cover ath11k: suspend support for QCA6390 PCI

Here is suspend support for QCA6390 PCI devices. For suspend we switch firmware to WoW mode and keep the firmware running. At the moment we are not able to shutdown and fully power off the device due to bugs in MHI subsystem, so WoW mode is a workaround for the time being.

This patchset depends on patchset:

ath11k: QCA6390 stability fixes
https://patchwork.kernel.org/project/linux-wireless/list/?series=399797

Please review.

Kalle

Carl Huang (9):
ath11k: mhi: hook suspend and resume
ath11k: hif: implement suspend and resume functions
ath11k: pci: read select_window register to ensure write is finished
ath11k: htc: implement suspend handling
ath11k: dp: stop rx pktlog before suspend
ath11k: set credit_update flag for flow controlled ep only
ath11k: implement WoW enable and wakeup commands
ath11k: hif: add ce irq enable and disable functions
ath11k: implement suspend for QCA6390 PCI devices

Kalle Valo (1):
ath11k: htc: remove unused struct ath11k_htc_ops

 drivers/net/wireless/ath/ath11k/Makefile |   3 +-
 drivers/net/wireless/ath/ath11k/ce.c     |   2 +-
 drivers/net/wireless/ath/ath11k/ce.h     |   2 +
 drivers/net/wireless/ath/ath11k/core.c   |  88 +++++++++++++++++
 drivers/net/wireless/ath/ath11k/core.h   |  11 +++
 drivers/net/wireless/ath/ath11k/dp.c     |   2 +-
 drivers/net/wireless/ath/ath11k/dp.h     |   2 +
 drivers/net/wireless/ath/ath11k/dp_rx.c  |  48 +++++++++
 drivers/net/wireless/ath/ath11k/dp_rx.h  |   3 +
 drivers/net/wireless/ath/ath11k/hif.h    |  32 ++++++
 drivers/net/wireless/ath/ath11k/htc.c    |  31 +++++-
 drivers/net/wireless/ath/ath11k/htc.h    |  10 +-
 drivers/net/wireless/ath/ath11k/hw.h     |   1 +
 drivers/net/wireless/ath/ath11k/mac.c    |   4 +
 drivers/net/wireless/ath/ath11k/mhi.c    |  11 +++
 drivers/net/wireless/ath/ath11k/mhi.h    |   3 +
 drivers/net/wireless/ath/ath11k/pci.c    |  71 ++++++++++++-
 drivers/net/wireless/ath/ath11k/wmi.c    |  99 +++++++++++++++++++
 drivers/net/wireless/ath/ath11k/wmi.h    | 165 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/wow.c    |  73 ++++++++++++++
 drivers/net/wireless/ath/ath11k/wow.h    |  10 ++
 21 files changed, 656 insertions(+), 15 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath11k/wow.c
 create mode 100644 drivers/net/wireless/ath/ath11k/wow.h
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#1 lore raw

PATCH 1/10 ath11k: mhi: hook suspend and resume

From: Carl Huang <[email protected]>

MHI suspend and resume isn't hooked in ath11k yet, so hook these functions needed for suspend support.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

---
 drivers/net/wireless/ath/ath11k/mhi.c | 11 +++++++++++
 drivers/net/wireless/ath/ath11k/mhi.h |  3 +++
 2 files changed, 14 insertions(+)
drivers/net/wireless/ath/ath11k/mhi.c +11 -0
index 4cf093718888..72aa39afc04c 100644
@@ -418,8 +418,10 @@ static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci,
 		ret = 0;
 		break;
 	case ATH11K_MHI_SUSPEND:
+		ret = mhi_pm_suspend(ab_pci->mhi_ctrl);
 		break;
 	case ATH11K_MHI_RESUME:
+		ret = mhi_pm_resume(ab_pci->mhi_ctrl);
 		break;
 	case ATH11K_MHI_TRIGGER_RDDM:
 		ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl);
@@ -470,3 +472,12 @@ void ath11k_mhi_stop(struct ath11k_pci *ab_pci)
 	ath11k_mhi_set_state(ab_pci, ATH11K_MHI_DEINIT);
 }
 
+void ath11k_mhi_suspend(struct ath11k_pci *ab_pci)
+{
+	ath11k_mhi_set_state(ab_pci, ATH11K_MHI_SUSPEND);
+}
+
+void ath11k_mhi_resume(struct ath11k_pci *ab_pci)
+{
+	ath11k_mhi_set_state(ab_pci, ATH11K_MHI_RESUME);
+}
drivers/net/wireless/ath/ath11k/mhi.h +3 -0
index a7fd5e201d18..488dada5d31c 100644
@@ -36,4 +36,7 @@ void ath11k_mhi_unregister(struct ath11k_pci *ar_pci);
 void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab);
 void ath11k_mhi_clear_vector(struct ath11k_base *ab);
 
+void ath11k_mhi_suspend(struct ath11k_pci *ar_pci);
+void ath11k_mhi_resume(struct ath11k_pci *ar_pci);
+
 #endif
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#2 lore raw

Re: [PATCH 01/10] ath11k: mhi: hook suspend and resume

Quoted 7 lines · Kalle Valo

MHI suspend and resume isn't hooked in ath11k yet, so hook these functions needed for suspend support.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

10 patches applied to ath-next branch of ath.git, thanks.

34fb81e4eb92 ath11k: mhi: hook suspend and resume
fa5917e44ee8 ath11k: hif: implement suspend and resume functions f6fa37a4928f ath11k: pci: read select_window register to ensure write is finished d50370c953bc ath11k: htc: remove unused struct ath11k_htc_ops 8733d835ec43 ath11k: htc: implement suspend handling
840c36fa727a ath11k: dp: stop rx pktlog before suspend
2151ffde188a ath11k: set credit_update flag for flow controlled ep only 79802b13a492 ath11k: implement WoW enable and wakeup commands d578ec2a0d5c ath11k: hif: add ce irq enable and disable functions d1b0c33850d2 ath11k: implement suspend for QCA6390 PCI devices

Signature · 9 lines
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#3 lore raw

Re: [PATCH 01/10] ath11k: mhi: hook suspend and resume

In reply to Kalle Valo
Quoted 7 lines · Kalle Valo

MHI suspend and resume isn't hooked in ath11k yet, so hook these functions needed for suspend support.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

10 patches applied to ath-next branch of ath.git, thanks.

34fb81e4eb92 ath11k: mhi: hook suspend and resume
fa5917e44ee8 ath11k: hif: implement suspend and resume functions f6fa37a4928f ath11k: pci: read select_window register to ensure write is finished d50370c953bc ath11k: htc: remove unused struct ath11k_htc_ops 8733d835ec43 ath11k: htc: implement suspend handling
840c36fa727a ath11k: dp: stop rx pktlog before suspend
2151ffde188a ath11k: set credit_update flag for flow controlled ep only 79802b13a492 ath11k: implement WoW enable and wakeup commands d578ec2a0d5c ath11k: hif: add ce irq enable and disable functions d1b0c33850d2 ath11k: implement suspend for QCA6390 PCI devices

Signature · 3 lines
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
author
#4 lore raw

PATCH 2/10 ath11k: hif: implement suspend and resume functions

In reply to Kalle Valo

From: Carl Huang <[email protected]>

For suspend support add suspend and resume to HIF layer. These ops are optional and, for example, AHB bus driver does not need to implement these.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

---
 drivers/net/wireless/ath/ath11k/hif.h | 18 ++++++++++++++++++
 drivers/net/wireless/ath/ath11k/pci.c | 20 ++++++++++++++++++++
 2 files changed, 38 insertions(+)
drivers/net/wireless/ath/ath11k/hif.h +18 -0
index dbe5568916e8..147f1e802ca9 100644
@@ -17,6 +17,8 @@ struct ath11k_hif_ops {
 	void (*stop)(struct ath11k_base *sc);
 	int (*power_up)(struct ath11k_base *sc);
 	void (*power_down)(struct ath11k_base *sc);
+	int (*suspend)(struct ath11k_base *ab);
+	int (*resume)(struct ath11k_base *ab);
 	int (*map_service_to_pipe)(struct ath11k_base *sc, u16 service_id,
 				   u8 *ul_pipe, u8 *dl_pipe);
 	int (*get_user_msi_vector)(struct ath11k_base *ab, char *user_name,
@@ -56,6 +58,22 @@ static inline void ath11k_hif_power_down(struct ath11k_base *sc)
 	sc->hif.ops->power_down(sc);
 }
 
+static inline int ath11k_hif_suspend(struct ath11k_base *ab)
+{
+	if (ab->hif.ops->suspend)
+		return ab->hif.ops->suspend(ab);
+
+	return 0;
+}
+
+static inline int ath11k_hif_resume(struct ath11k_base *ab)
+{
+	if (ab->hif.ops->resume)
+		return ab->hif.ops->resume(ab);
+
+	return 0;
+}
+
 static inline u32 ath11k_hif_read32(struct ath11k_base *sc, u32 address)
 {
 	return sc->hif.ops->read32(sc, address);
drivers/net/wireless/ath/ath11k/pci.c +20 -0
index 818e37c32a85..770cefd53290 100644
@@ -913,6 +913,24 @@ static void ath11k_pci_power_down(struct ath11k_base *ab)
 	ath11k_pci_sw_reset(ab_pci->ab, false);
 }
 
+static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
+{
+	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
+
+	ath11k_mhi_suspend(ar_pci);
+
+	return 0;
+}
+
+static int ath11k_pci_hif_resume(struct ath11k_base *ab)
+{
+	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
+
+	ath11k_mhi_resume(ar_pci);
+
+	return 0;
+}
+
 static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
 {
 	int i;
@@ -997,6 +1015,8 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
 	.write32 = ath11k_pci_write32,
 	.power_down = ath11k_pci_power_down,
 	.power_up = ath11k_pci_power_up,
+	.suspend = ath11k_pci_hif_suspend,
+	.resume = ath11k_pci_hif_resume,
 	.irq_enable = ath11k_pci_ext_irq_enable,
 	.irq_disable = ath11k_pci_ext_irq_disable,
 	.get_msi_address =  ath11k_pci_get_msi_address,
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#5 lore raw

PATCH 3/10 ath11k: pci: read select_window register to ensure write is finished

In reply to Kalle Valo

From: Carl Huang <[email protected]>

Just when resume from WoW, the write to select_window doesn't take effect immediately, so read the register again to ensure the write operation is finished.

Another change is to reset select_window to ZERO because this register isn't restored after WoW, so the content of this register becomes ZERO too.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

---
 drivers/net/wireless/ath/ath11k/pci.c | 1 +
 1 file changed, 1 insertion(+)
drivers/net/wireless/ath/ath11k/pci.c +1 -0
index 770cefd53290..ee1c2edefa20 100644
@@ -126,6 +126,7 @@ static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offse
 	if (window != ab_pci->register_window) {
 		iowrite32(WINDOW_ENABLE_BIT | window,
 			  ab->mem + WINDOW_REG_ADDRESS);
+		ioread32(ab->mem + WINDOW_REG_ADDRESS);
 		ab_pci->register_window = window;
 	}
 }
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#6 lore raw

PATCH 4/10 ath11k: htc: remove unused struct ath11k_htc_ops

In reply to Kalle Valo

No need for it so remove. Compile tested only.

---
 drivers/net/wireless/ath/ath11k/htc.h | 6 ------
 1 file changed, 6 deletions(-)
drivers/net/wireless/ath/ath11k/htc.h +0 -6
index f0a3387567ca..848147cf81ee 100644
@@ -221,10 +221,6 @@ enum ath11k_htc_ep_id {
 	ATH11K_HTC_EP_COUNT,
 };
 
-struct ath11k_htc_ops {
-	void (*target_send_suspend_complete)(struct ath11k_base *ar);
-};
-
 struct ath11k_htc_ep_ops {
 	void (*ep_tx_complete)(struct ath11k_base *, struct sk_buff *);
 	void (*ep_rx_complete)(struct ath11k_base *, struct sk_buff *);
@@ -284,8 +280,6 @@ struct ath11k_htc {
 	/* protects endpoints */
 	spinlock_t tx_lock;
 
-	struct ath11k_htc_ops htc_ops;
-
 	u8 control_resp_buffer[ATH11K_HTC_MAX_CTRL_MSG_LEN];
 	int control_resp_len;
 
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#7 lore raw

PATCH 5/10 ath11k: htc: implement suspend handling

In reply to Kalle Valo

From: Carl Huang <[email protected]>

When ath11k sends suspend command to firmware, firmware will return suspend_complete events and add handlers for those.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

---
 drivers/net/wireless/ath/ath11k/core.c |  2 ++
 drivers/net/wireless/ath/ath11k/core.h |  4 ++++
 drivers/net/wireless/ath/ath11k/htc.c  | 23 ++++++++++++++++++++++-
 drivers/net/wireless/ath/ath11k/htc.h  |  4 +++-
 4 files changed, 31 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath11k/core.c +2 -0
index 3c28e7ad7d51..1c2789ce6239 100644
@@ -968,6 +968,8 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
 	init_waitqueue_head(&ab->qmi.cold_boot_waitq);
 	INIT_WORK(&ab->restart_work, ath11k_core_restart);
 	timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
+	init_completion(&ab->htc_suspend);
+
 	ab->dev = dev;
 	ab->bus_params = *bus_params;
 	ab->hif.bus = bus;
drivers/net/wireless/ath/ath11k/core.h +4 -0
index 3f539cf52690..689aa24fe28f 100644
@@ -186,6 +186,7 @@ enum ath11k_dev_flags {
 	ATH11K_FLAG_UNREGISTERING,
 	ATH11K_FLAG_REGISTERED,
 	ATH11K_FLAG_QMI_FAIL,
+	ATH11K_FLAG_HTC_SUSPEND_COMPLETE,
 };
 
 enum ath11k_monitor_flags {
@@ -732,6 +733,9 @@ struct ath11k_base {
 	u32 num_db_cap;
 
 	struct timer_list mon_reap_timer;
+
+	struct completion htc_suspend;
+
 	/* must be last */
 	u8 drv_priv[0] __aligned(sizeof(void *));
 };
drivers/net/wireless/ath/ath11k/htc.c +22 -1
index 6b57dc273e0b..059b48ded5cc 100644
@@ -231,6 +231,18 @@ static int ath11k_htc_process_trailer(struct ath11k_htc *htc,
 	return status;
 }
 
+static void ath11k_htc_suspend_complete(struct ath11k_base *ab, bool ack)
+{
+	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot suspend complete %d\n", ack);
+
+	if (ack)
+		set_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags);
+	else
+		clear_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags);
+
+	complete(&ab->htc_suspend);
+}
+
 void ath11k_htc_rx_completion_handler(struct ath11k_base *ab,
 				      struct sk_buff *skb)
 {
@@ -328,8 +340,17 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab,
 
 			complete(&htc->ctl_resp);
 			break;
+		case ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE:
+			ath11k_htc_suspend_complete(ab, true);
+			break;
+		case ATH11K_HTC_MSG_NACK_SUSPEND:
+			ath11k_htc_suspend_complete(ab, false);
+			break;
+		case ATH11K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID:
+			break;
 		default:
-			ath11k_warn(ab, "ignoring unsolicited htc ep0 event\n");
+			ath11k_warn(ab, "ignoring unsolicited htc ep0 event %ld\n",
+				    FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id));
 			break;
 		}
 		goto out;
drivers/net/wireless/ath/ath11k/htc.h +3 -1
index 848147cf81ee..6c8a469d7f9d 100644
@@ -65,7 +65,9 @@ enum ath11k_htc_msg_id {
 	ATH11K_HTC_MSG_CONNECT_SERVICE_RESP_ID = 3,
 	ATH11K_HTC_MSG_SETUP_COMPLETE_ID       = 4,
 	ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID    = 5,
-	ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE   = 6
+	ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE   = 6,
+	ATH11K_HTC_MSG_NACK_SUSPEND	       = 7,
+	ATH11K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID  = 8,
 };
 
 enum ath11k_htc_version {
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#8 lore raw

PATCH 6/10 ath11k: dp: stop rx pktlog before suspend

In reply to Kalle Valo

From: Carl Huang <[email protected]>

Stop dp rx pktlog when entering suspend and reap the mon_status buffer to keep it empty. During resume restart the reap timer.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

---
 drivers/net/wireless/ath/ath11k/dp.h    |  1 +
 drivers/net/wireless/ath/ath11k/dp_rx.c | 48 +++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/dp_rx.h |  3 +++
 drivers/net/wireless/ath/ath11k/mac.c   |  4 +++
 4 files changed, 56 insertions(+)
drivers/net/wireless/ath/ath11k/dp.h +1 -0
index d4fd02375fad..1d9e2d6de3ae 100644
@@ -40,6 +40,7 @@ struct dp_rx_tid {
 
 #define DP_REO_DESC_FREE_THRESHOLD  64
 #define DP_REO_DESC_FREE_TIMEOUT_MS 1000
+#define DP_MON_PURGE_TIMEOUT_MS     100
 #define DP_MON_SERVICE_BUDGET       128
 
 struct dp_reo_cache_flush_elem {
drivers/net/wireless/ath/ath11k/dp_rx.c +48 -0

57 lines not on this page · raw message

drivers/net/wireless/ath/ath11k/dp_rx.h +3 -0
index fbea45f79c9b..bf399312b5ff 100644
@@ -91,4 +91,7 @@ int ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar);
 int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar);
 int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id);
 
+int ath11k_dp_rx_pktlog_start(struct ath11k_base *ab);
+int ath11k_dp_rx_pktlog_stop(struct ath11k_base *ab, bool stop_timer);
+
 #endif /* ATH11K_DP_RX_H */
drivers/net/wireless/ath/ath11k/mac.c +4 -0
index d08afa111647..5c175e3e09b2 100644
@@ -4146,6 +4146,10 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable)
 						       &tlv_filter);
 	}
 
+	if (enable && !ar->ab->hw_params.rxdma1_enable)
+		mod_timer(&ar->ab->mon_reap_timer, jiffies +
+			  msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL));
+
 	return ret;
 }
 
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#9 lore raw

PATCH 7/10 ath11k: set credit_update flag for flow controlled ep only

In reply to Kalle Valo

From: Carl Huang <[email protected]>

Firmware will check all the pipes before entering WoW mode during suspend. If ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE is set, firmware treats this pipe needed to return credit even though it's actually not required. If any pipe needs to return credit, the suspend_complete message doesn't send to host but is dropped. So host gets time out and WoW suspend failed.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

---
 drivers/net/wireless/ath/ath11k/htc.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/net/wireless/ath/ath11k/htc.c +5 -3
index 059b48ded5cc..54b1d34724d7 100644
@@ -60,9 +60,11 @@ static void ath11k_htc_prepare_tx_skb(struct ath11k_htc_ep *ep,
 	memset(hdr, 0, sizeof(*hdr));
 	hdr->htc_info = FIELD_PREP(HTC_HDR_ENDPOINTID, ep->eid) |
 			FIELD_PREP(HTC_HDR_PAYLOADLEN,
-				   (skb->len - sizeof(*hdr))) |
-			FIELD_PREP(HTC_HDR_FLAGS,
-				   ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE);
+				   (skb->len - sizeof(*hdr)));
+
+	if (ep->tx_credit_flow_enabled)
+		hdr->htc_info |= FIELD_PREP(HTC_HDR_FLAGS,
+					    ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE);
 
 	spin_lock_bh(&ep->htc->tx_lock);
 	hdr->ctrl_info = FIELD_PREP(HTC_HDR_CONTROLBYTES1, ep->seq_no++);
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#10 lore raw

PATCH 8/10 ath11k: implement WoW enable and wakeup commands

In reply to Kalle Valo

From: Carl Huang <[email protected]>

Implement wow enable ane wow wakeup commands which are needed for suspend.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

---
 drivers/net/wireless/ath/ath11k/Makefile |   3 +-
 drivers/net/wireless/ath/ath11k/core.c   |   1 +
 drivers/net/wireless/ath/ath11k/core.h   |   5 +
 drivers/net/wireless/ath/ath11k/wmi.c    |  99 +++++++++++++++++++
 drivers/net/wireless/ath/ath11k/wmi.h    | 165 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/wow.c    |  73 ++++++++++++++
 drivers/net/wireless/ath/ath11k/wow.h    |  10 ++
 7 files changed, 355 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/wireless/ath/ath11k/wow.c
 create mode 100644 drivers/net/wireless/ath/ath11k/wow.h
drivers/net/wireless/ath/ath11k/Makefile +2 -1
index c41d87bd025a..c1fce4159f1f 100644
@@ -16,7 +16,8 @@ ath11k-y += core.o \
 	    ce.o \
 	    peer.o \
 	    dbring.o \
-	    hw.o
+	    hw.o \
+	    wow.o
 
 ath11k-$(CONFIG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
 ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o
drivers/net/wireless/ath/ath11k/core.c +1 -0
index 1c2789ce6239..451748fa8fff 100644
@@ -969,6 +969,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
 	INIT_WORK(&ab->restart_work, ath11k_core_restart);
 	timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
 	init_completion(&ab->htc_suspend);
+	init_completion(&ab->wow.wakeup_completed);
 
 	ab->dev = dev;
 	ab->bus_params = *bus_params;
drivers/net/wireless/ath/ath11k/core.h +5 -0
index 689aa24fe28f..ba8f2222169d 100644
@@ -466,6 +466,7 @@ struct ath11k {
 		struct ieee80211_sband_iftype_data
 			iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES];
 	} mac;
+
 	unsigned long dev_flags;
 	unsigned int filter_flags;
 	unsigned long monitor_flags;
@@ -672,6 +673,10 @@ struct ath11k_base {
 		const struct ath11k_hif_ops *ops;
 	} hif;
 
+	struct {
+		struct completion wakeup_completed;
+	} wow;
+
 	struct ath11k_ce ce;
 	struct timer_list rx_replenish_retry;
 	struct ath11k_hal hal;
drivers/net/wireless/ath/ath11k/wmi.c +99 -0

114 lines not on this page · raw message

drivers/net/wireless/ath/ath11k/wmi.h +165 -0

176 lines not on this page · raw message

drivers/net/wireless/ath/ath11k/wow.c new file +73 -0

73 lines not on this page · raw message

drivers/net/wireless/ath/ath11k/wow.h new file +10 -0
new file mode 100644
index 000000000000..dabc4ee63cf6
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ */
+
+#define ATH11K_WOW_RETRY_NUM		3
+#define ATH11K_WOW_RETRY_WAIT_MS	200
+
+int ath11k_wow_enable(struct ath11k_base *ab);
+int ath11k_wow_wakeup(struct ath11k_base *ab);
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#11 lore raw

PATCH 9/10 ath11k: hif: add ce irq enable and disable functions

In reply to Kalle Valo

From: Carl Huang <[email protected]>

Add ce irq enable and disable hif layer functions, so core module can enable enable them without cleaning pipe and refilling pipe. Needed for suspend.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

---
 drivers/net/wireless/ath/ath11k/hif.h | 14 ++++++++++++++
 drivers/net/wireless/ath/ath11k/pci.c | 19 ++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/ath11k/hif.h +14 -0
index 147f1e802ca9..6285c52afc44 100644
@@ -26,8 +26,22 @@ struct ath11k_hif_ops {
 				   u32 *base_vector);
 	void (*get_msi_address)(struct ath11k_base *ab, u32 *msi_addr_lo,
 				u32 *msi_addr_hi);
+	void (*ce_irq_enable)(struct ath11k_base *ab);
+	void (*ce_irq_disable)(struct ath11k_base *ab);
 };
 
+static inline void ath11k_hif_ce_irq_enable(struct ath11k_base *ab)
+{
+	if (ab->hif.ops->ce_irq_enable)
+		ab->hif.ops->ce_irq_enable(ab);
+}
+
+static inline void ath11k_hif_ce_irq_disable(struct ath11k_base *ab)
+{
+	if (ab->hif.ops->ce_irq_disable)
+		ab->hif.ops->ce_irq_disable(ab);
+}
+
 static inline int ath11k_hif_start(struct ath11k_base *sc)
 {
 	return sc->hif.ops->start(sc);
drivers/net/wireless/ath/ath11k/pci.c +18 -1
index ee1c2edefa20..e720ac6354fc 100644
@@ -946,11 +946,16 @@ static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
 	}
 }
 
-static void ath11k_pci_stop(struct ath11k_base *ab)
+static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
 {
 	ath11k_pci_ce_irqs_disable(ab);
 	ath11k_pci_sync_ce_irqs(ab);
 	ath11k_pci_kill_tasklets(ab);
+}
+
+static void ath11k_pci_stop(struct ath11k_base *ab)
+{
+	ath11k_pci_ce_irq_disable_sync(ab);
 	ath11k_ce_cleanup_pipes(ab);
 }
 
@@ -966,6 +971,16 @@ static int ath11k_pci_start(struct ath11k_base *ab)
 	return 0;
 }
 
+static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
+{
+	ath11k_pci_ce_irqs_enable(ab);
+}
+
+static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
+{
+	ath11k_pci_ce_irq_disable_sync(ab);
+}
+
 static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
 					  u8 *ul_pipe, u8 *dl_pipe)
 {
@@ -1023,6 +1038,8 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
 	.get_msi_address =  ath11k_pci_get_msi_address,
 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
+	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
+	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
 };
 
 static int ath11k_pci_probe(struct pci_dev *pdev,
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k
author
#12 lore raw

PATCH 10/10 ath11k: implement suspend for QCA6390 PCI devices

In reply to Kalle Valo

From: Carl Huang <[email protected]>

Now that all the needed pieces are in place implement suspend support QCA6390 PCI devices. All other devices will return -EOPNOTSUPP during suspend. The suspend is implemented by switching the firmware to WoW mode during suspend, so the firmware will be running on low power mode while host is in suspend.

At the moment we are not able to shutdown and fully power off the device due to bugs in MHI subsystem, so WoW mode is a workaround for the time being.

During suspend we enable WoW mode, disable CE irq and DP irq, then put MHI to suspend state. During resume, driver resumes MHI firstly, then enables CE irq and dp IRQ, and sends WoW wakeup command to firmware.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

---
 drivers/net/wireless/ath/ath11k/ce.c   |  2 +-
 drivers/net/wireless/ath/ath11k/ce.h   |  2 +
 drivers/net/wireless/ath/ath11k/core.c | 85 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/core.h |  2 +
 drivers/net/wireless/ath/ath11k/dp.c   |  2 +-
 drivers/net/wireless/ath/ath11k/dp.h   |  1 +
 drivers/net/wireless/ath/ath11k/hw.h   |  1 +
 drivers/net/wireless/ath/ath11k/pci.c  | 31 +++++++++++++
 8 files changed, 124 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath11k/ce.c +1 -1
index 9d730f8ac816..987c65010272 100644
@@ -195,7 +195,7 @@ static bool ath11k_ce_need_shadow_fix(int ce_id)
 	return false;
 }
 
-static void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab)
+void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab)
 {
 	int i;
 
drivers/net/wireless/ath/ath11k/ce.h +2 -0
index 269b599ac0b0..d6eeef919349 100644
@@ -190,4 +190,6 @@ int ath11k_ce_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
 int ath11k_ce_attr_attach(struct ath11k_base *ab);
 void ath11k_ce_get_shadow_config(struct ath11k_base *ab,
 				 u32 **shadow_cfg, u32 *shadow_cfg_len);
+void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab);
+
 #endif
drivers/net/wireless/ath/ath11k/core.c +85 -0

112 lines not on this page · raw message

drivers/net/wireless/ath/ath11k/core.h +2 -0
index ba8f2222169d..799bf3de1117 100644
@@ -897,6 +897,8 @@ void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd);
 int ath11k_core_check_dt(struct ath11k_base *ath11k);
 
 void ath11k_core_halt(struct ath11k *ar);
+int ath11k_core_resume(struct ath11k_base *ab);
+int ath11k_core_suspend(struct ath11k_base *ab);
 
 const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
 						    const char *filename);
drivers/net/wireless/ath/ath11k/dp.c +1 -1
index f977056ae5e8..04f6c4e0658b 100644
@@ -304,7 +304,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
 	return 0;
 }
 
-static void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab)
+void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab)
 {
 	int i;
 
drivers/net/wireless/ath/ath11k/dp.h +1 -0
index 1d9e2d6de3ae..ee768ccce46e 100644
@@ -1641,5 +1641,6 @@ void ath11k_dp_shadow_stop_timer(struct ath11k_base *ab,
 void ath11k_dp_shadow_init_timer(struct ath11k_base *ab,
 				 struct ath11k_hp_update_timer *update_timer,
 				 u32 interval, u32 ring_id);
+void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab);
 
 #endif
drivers/net/wireless/ath/ath11k/hw.h +1 -0
index f33a458a465f..8af0034fdb05 100644
@@ -156,6 +156,7 @@ struct ath11k_hw_params {
 	bool supports_shadow_regs;
 	bool idle_ps;
 	bool cold_boot_calib;
+	bool supports_suspend;
 };
 
 struct ath11k_hw_ops {
drivers/net/wireless/ath/ath11k/pci.c +31 -0
index e720ac6354fc..857647aa57c8 100644
@@ -1204,12 +1204,43 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev)
 	ath11k_pci_power_down(ab);
 }
 
+static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
+{
+	struct ath11k_base *ab = dev_get_drvdata(dev);
+	int ret;
+
+	ret = ath11k_core_suspend(ab);
+	if (ret)
+		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
+
+	return ret;
+}
+
+static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
+{
+	struct ath11k_base *ab = dev_get_drvdata(dev);
+	int ret;
+
+	ret = ath11k_core_resume(ab);
+	if (ret)
+		ath11k_warn(ab, "failed to resume core: %d\n", ret);
+
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
+			 ath11k_pci_pm_suspend,
+			 ath11k_pci_pm_resume);
+
 static struct pci_driver ath11k_pci_driver = {
 	.name = "ath11k_pci",
 	.id_table = ath11k_pci_id_table,
 	.probe = ath11k_pci_probe,
 	.remove = ath11k_pci_remove,
 	.shutdown = ath11k_pci_shutdown,
+#ifdef CONFIG_PM
+	.driver.pm = &ath11k_pci_pm_ops,
+#endif
 };
 
 static int ath11k_pci_init(void)
Signature · 7 lines
2.7.4


-- 
ath11k mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/ath11k