linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] ath11k: support one MSI vector
@ 2020-12-23  3:02 Carl Huang
  2020-12-23  3:02 ` [PATCH 1/6] ath11k: get msi_data again after request_irq is called Carl Huang
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Carl Huang @ 2020-12-23  3:02 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless

This patch set is to support one MSI vector for QCA6390.

Carl Huang (6):
  ath11k: get msi_data again after request_irq is called
  ath11k: add ce and ext irq flag to indicate irq_handler
  ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for dp irqx
  ath11k: refactor mulitple msi vector implementation
  ath11k: supports one MSI vector
  ath11k: do not restore ASPM in case of single MSI vector

 drivers/net/wireless/ath/ath11k/core.h |   2 +
 drivers/net/wireless/ath/ath11k/mhi.c  |  13 ++-
 drivers/net/wireless/ath/ath11k/pci.c  | 200 +++++++++++++++++++++++++++------
 drivers/net/wireless/ath/ath11k/pci.h  |   8 ++
 4 files changed, 189 insertions(+), 34 deletions(-)

-- 
2.7.4


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

* [PATCH 1/6] ath11k: get msi_data again after request_irq is called
  2020-12-23  3:02 [PATCH 0/6] ath11k: support one MSI vector Carl Huang
@ 2020-12-23  3:02 ` Carl Huang
  2020-12-23  3:02 ` [PATCH 2/6] ath11k: add ce and ext irq flag to indicate irq_handler Carl Huang
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Carl Huang @ 2020-12-23  3:02 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless

The reservation mode of interrupts is kernel assigns a dummy vector
when the interrupt is allocated and assigns a real vector when the
request_irq is called. The reservation mode helps to ease vector
pressure when devices with a large amount of queues/interrupts
are initialized, but only a minimal subset of those queues/interrupts
is actually used.

So on reservation mode, the msi_data may change after request_irq
is called, so ath11k reads msi_data again after request_irq is called,
and then the correct msi_data is programmed into QCA6390 hardware
components. Without this change, spurious interrupt occurs in case of
one MSI vector. When VT-D in BIOS is enabled and ath11k can get 32 MSI
vectors, ath11k always get the same msi_data before and after request_irq,
that's why this change is only required when one MSI vector is to be
supported.

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

Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
---
 drivers/net/wireless/ath/ath11k/pci.c | 37 +++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 78478b2..c1ae1df 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -804,6 +804,32 @@ static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
 	pci_free_irq_vectors(ab_pci->pdev);
 }
 
+static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
+{
+	struct msi_desc *msi_desc;
+	int ret;
+
+	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
+	if (!msi_desc) {
+		ath11k_err(ab_pci->ab, "%s msi_desc is NULL!\n", __func__);
+		ret = -EINVAL;
+		goto free_msi_vector;
+	}
+
+	ab_pci->msi_ep_base_data = msi_desc->msg.data;
+
+	ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI,
+		   "msi base data after request_irq is %d\n",
+		   ab_pci->msi_ep_base_data);
+
+	return 0;
+
+free_msi_vector:
+	pci_free_irq_vectors(ab_pci->pdev);
+
+	return ret;
+}
+
 static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
 {
 	struct ath11k_base *ab = ab_pci->ab;
@@ -1174,6 +1200,17 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
 		goto err_ce_free;
 	}
 
+	/* kernel may allocate a dummy vector before request_irq and
+	 * then allocate a real vector when request_irq is called.
+	 * So get msi_data here again to avoid spurious interrupt
+	 * as msi_data will configured to srngs.
+	 */
+	ret = ath11k_pci_config_msi_data(ab_pci);
+	if (ret) {
+		ath11k_err(ab, "failed to config msi_data: %d\n", ret);
+		goto err_ce_free;
+	}
+
 	ret = ath11k_core_init(ab);
 	if (ret) {
 		ath11k_err(ab, "failed to init core: %d\n", ret);
-- 
2.7.4


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

* [PATCH 2/6] ath11k: add ce and ext irq flag to indicate irq_handler
  2020-12-23  3:02 [PATCH 0/6] ath11k: support one MSI vector Carl Huang
  2020-12-23  3:02 ` [PATCH 1/6] ath11k: get msi_data again after request_irq is called Carl Huang
@ 2020-12-23  3:02 ` Carl Huang
  2020-12-23  3:02 ` [PATCH 3/6] ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for dp irqx Carl Huang
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Carl Huang @ 2020-12-23  3:02 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless

This change adds two flags to indicate whether irq handler for CE
and dp can be called. This is because in one MSI vector case,
interrupt is not disabled in hif_stop and hif_irq_disable. Otherwise,
MHI interrupt is disabled too.

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

Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
---
 drivers/net/wireless/ath/ath11k/core.h |  2 ++
 drivers/net/wireless/ath/ath11k/pci.c  | 13 +++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 799bf3d..3dacca5 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -741,6 +741,8 @@ struct ath11k_base {
 
 	struct completion htc_suspend;
 
+	bool ce_irq_enabled_flag;
+	bool ext_irq_enabled_flag;
 	/* must be last */
 	u8 drv_priv[0] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index c1ae1df..deb2d47 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -487,6 +487,8 @@ static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
 {
 	int i;
 
+	ab->ce_irq_enabled_flag = false;
+
 	for (i = 0; i < ab->hw_params.ce_count; i++) {
 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
 			continue;
@@ -521,6 +523,9 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
 {
 	struct ath11k_ce_pipe *ce_pipe = arg;
 
+	if (!ab->ce_irq_enabled_flag)
+		return IRQ_HANDLED;
+
 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
 	tasklet_schedule(&ce_pipe->intr_tq);
 
@@ -539,6 +544,8 @@ static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
 {
 	int i;
 
+	ab->ext_irq_enabled_flag = false;
+
 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
 
@@ -561,6 +568,8 @@ static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
 {
 	int i;
 
+	ab->ext_irq_enabled_flag = true;
+
 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
 
@@ -613,6 +622,9 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
 {
 	struct ath11k_ext_irq_grp *irq_grp = arg;
 
+	if (!irq_grp->ab->ext_irq_enabled_flag)
+		return IRQ_HANDLED;
+
 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
 
 	ath11k_pci_ext_grp_disable(irq_grp);
@@ -1026,6 +1038,7 @@ static int ath11k_pci_start(struct ath11k_base *ab)
 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
 
 	ath11k_pci_aspm_restore(ab_pci);
+	ab->ce_irq_enabled_flag = true;
 
 	ath11k_pci_ce_irqs_enable(ab);
 	ath11k_ce_rx_post_buf(ab);
-- 
2.7.4


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

* [PATCH 3/6] ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for dp irqx
  2020-12-23  3:02 [PATCH 0/6] ath11k: support one MSI vector Carl Huang
  2020-12-23  3:02 ` [PATCH 1/6] ath11k: get msi_data again after request_irq is called Carl Huang
  2020-12-23  3:02 ` [PATCH 2/6] ath11k: add ce and ext irq flag to indicate irq_handler Carl Huang
@ 2020-12-23  3:02 ` Carl Huang
  2020-12-23  3:02 ` [PATCH 4/6] ath11k: refactor mulitple msi vector implementation Carl Huang
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Carl Huang @ 2020-12-23  3:02 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless

Like ATH11K_PCI_IRQ_CE0_OFFSET, define ATH11K_PCI_IRQ_DP_OFFSET for
dp to save the irq instead of base_vector from msi config.

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

Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
---
 drivers/net/wireless/ath/ath11k/pci.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index deb2d47..7ec2209 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -16,7 +16,8 @@
 #define ATH11K_PCI_BAR_NUM		0
 #define ATH11K_PCI_DMA_MASK		32
 
-#define ATH11K_PCI_IRQ_CE0_OFFSET		3
+#define ATH11K_PCI_IRQ_CE0_OFFSET	3
+#define ATH11K_PCI_IRQ_DP_OFFSET	14
 
 #define WINDOW_ENABLE_BIT		0x40000000
 #define WINDOW_REG_ADDRESS		0x310c
@@ -668,7 +669,7 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
 		}
 
 		irq_grp->num_irq = num_irq;
-		irq_grp->irqs[0] = base_vector + i;
+		irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i;
 
 		for (j = 0; j < irq_grp->num_irq; j++) {
 			int irq_idx = irq_grp->irqs[j];
-- 
2.7.4


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

* [PATCH 4/6] ath11k: refactor mulitple msi vector implementation
  2020-12-23  3:02 [PATCH 0/6] ath11k: support one MSI vector Carl Huang
                   ` (2 preceding siblings ...)
  2020-12-23  3:02 ` [PATCH 3/6] ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for dp irqx Carl Huang
@ 2020-12-23  3:02 ` Carl Huang
  2020-12-23  3:02 ` [PATCH 5/6] ath11k: supports one MSI vector Carl Huang
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Carl Huang @ 2020-12-23  3:02 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless

This is to prepare for one msi vector support.
Irq enable and disable functions of ce and dp are wrapped.

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

Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
---
 drivers/net/wireless/ath/ath11k/pci.c | 86 +++++++++++++++++++++++++++--------
 drivers/net/wireless/ath/ath11k/pci.h |  8 ++++
 2 files changed, 75 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 7ec2209..5fdfc72 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -406,17 +406,18 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_nam
 				       int *num_vectors, u32 *user_base_data,
 				       u32 *base_vector)
 {
+	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
 	struct ath11k_base *ab = ab_pci->ab;
 	int idx;
 
-	for (idx = 0; idx < msi_config.total_users; idx++) {
-		if (strcmp(user_name, msi_config.users[idx].name) == 0) {
-			*num_vectors = msi_config.users[idx].num_vectors;
-			*user_base_data = msi_config.users[idx].base_vector
-				+ ab_pci->msi_ep_base_data;
-			*base_vector = msi_config.users[idx].base_vector;
+	for (idx = 0; idx < msi_config->total_users; idx++) {
+		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
+			*num_vectors = msi_config->users[idx].num_vectors;
+			*base_vector =  msi_config->users[idx].base_vector;
+			*user_base_data = *base_vector + ab_pci->msi_ep_base_data;
 
-			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
+			ath11k_dbg(ab, ATH11K_DBG_PCI,
+				   "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
 				   user_name, *num_vectors, *user_base_data,
 				   *base_vector);
 
@@ -468,7 +469,7 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab)
 	ath11k_pci_free_ext_irq(ab);
 }
 
-static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
+static void ath11k_pci_ce_irq_enable_multiple_msi(struct ath11k_base *ab, u16 ce_id)
 {
 	u32 irq_idx;
 
@@ -476,7 +477,15 @@ static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
 	enable_irq(ab->irq_num[irq_idx]);
 }
 
-static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
+static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
+{
+	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
+
+	if (ab_pci->ce_irq_enable)
+		ab_pci->ce_irq_enable(ab, ce_id);
+}
+
+static void ath11k_pci_ce_irq_disable_multiple_msi(struct ath11k_base *ab, u16 ce_id)
 {
 	u32 irq_idx;
 
@@ -484,12 +493,19 @@ static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
 	disable_irq_nosync(ab->irq_num[irq_idx]);
 }
 
+static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
+{
+	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
+
+	if (ab_pci->ce_irq_disable)
+		ab_pci->ce_irq_disable(ab, ce_id);
+}
+
 static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
 {
 	int i;
 
 	ab->ce_irq_enabled_flag = false;
-
 	for (i = 0; i < ab->hw_params.ce_count; i++) {
 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
 			continue;
@@ -523,6 +539,7 @@ static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
 static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
 {
 	struct ath11k_ce_pipe *ce_pipe = arg;
+	struct ath11k_base *ab = ce_pipe->ab;
 
 	if (!ab->ce_irq_enabled_flag)
 		return IRQ_HANDLED;
@@ -533,7 +550,7 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
-static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
+static void ath11k_pci_ext_grp_disable_multiple_msi(struct ath11k_ext_irq_grp *irq_grp)
 {
 	int i;
 
@@ -541,14 +558,21 @@ static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
 }
 
-static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
+static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
+{
+	struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
+
+	if (ab_pci->ext_grp_disable)
+		ab_pci->ext_grp_disable(irq_grp);
+}
+
+static void __ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
 {
 	int i;
 
 	ab->ext_irq_enabled_flag = false;
-
 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
-		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
+		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
 
 		ath11k_pci_ext_grp_disable(irq_grp);
 
@@ -557,7 +581,7 @@ static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
 	}
 }
 
-static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
+static void ath11k_pci_ext_grp_enable_multiple_msi(struct ath11k_ext_irq_grp *irq_grp)
 {
 	int i;
 
@@ -565,6 +589,14 @@ static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
 }
 
+static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
+{
+	struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
+
+	if (ab_pci->ext_grp_enable)
+		ab_pci->ext_grp_enable(irq_grp);
+}
+
 static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
 {
 	int i;
@@ -637,6 +669,7 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
 
 static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
 {
+	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
 	int i, j, ret, num_vectors = 0;
 	u32 user_base_data = 0, base_vector = 0;
 
@@ -681,16 +714,15 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
 			ath11k_dbg(ab, ATH11K_DBG_PCI,
 				   "irq:%d group:%d\n", irq, i);
 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
-					  IRQF_SHARED,
+					  ab_pci->irq_flags,
 					  "DP_EXT_IRQ", irq_grp);
 			if (ret) {
 				ath11k_err(ab, "failed request irq %d: %d\n",
 					   vector, ret);
 				return ret;
 			}
-
-			disable_irq_nosync(ab->irq_num[irq_idx]);
 		}
+		ath11k_pci_ext_grp_disable(irq_grp);
 	}
 
 	return 0;
@@ -698,6 +730,7 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
 
 static int ath11k_pci_config_irq(struct ath11k_base *ab)
 {
+	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
 	struct ath11k_ce_pipe *ce_pipe;
 	u32 msi_data_start;
 	u32 msi_data_count;
@@ -725,7 +758,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
 
 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
-				  IRQF_SHARED, irq_name[irq_idx],
+				  ab_pci->irq_flags, irq_name[irq_idx],
 				  ce_pipe);
 		if (ret) {
 			ath11k_err(ab, "failed to request irq %d: %d\n",
@@ -770,6 +803,19 @@ static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
 	}
 }
 
+static void ath11k_pci_init_irq_handlers(struct ath11k_pci *ab_pci, bool multiple_msi)
+{
+	if (multiple_msi) {
+		ab_pci->vectors_32_capability = true;
+		ab_pci->ext_grp_enable = ath11k_pci_ext_grp_enable_multiple_msi;
+		ab_pci->ext_grp_disable = ath11k_pci_ext_grp_disable_multiple_msi;
+		ab_pci->ce_irq_enable = ath11k_pci_ce_irq_enable_multiple_msi;
+		ab_pci->ce_irq_disable = ath11k_pci_ce_irq_disable_multiple_msi;
+		ab_pci->msi_config = &msi_config;
+		ab_pci->irq_flags = IRQF_SHARED;
+	}
+}
+
 static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
 {
 	struct ath11k_base *ab = ab_pci->ab;
@@ -789,6 +835,8 @@ static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
 			return -EINVAL;
 		else
 			return num_vectors;
+	} else {
+		ath11k_pci_init_irq_handlers(ab_pci, true);
 	}
 
 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h
index fe44d0d..2097466 100644
--- a/drivers/net/wireless/ath/ath11k/pci.h
+++ b/drivers/net/wireless/ath/ath11k/pci.h
@@ -72,6 +72,7 @@ struct ath11k_pci {
 	u16 dev_id;
 	char amss_path[100];
 	u32 msi_ep_base_data;
+	bool vectors_32_capability;
 	struct mhi_controller *mhi_ctrl;
 	unsigned long mhi_state;
 	u32 register_window;
@@ -82,6 +83,13 @@ struct ath11k_pci {
 	/* enum ath11k_pci_flags */
 	unsigned long flags;
 	u16 link_ctl;
+
+	const struct ath11k_msi_config *msi_config;
+	unsigned long irq_flags;
+	void (*ext_grp_disable)(struct ath11k_ext_irq_grp *irq_grp);
+	void (*ext_grp_enable)(struct ath11k_ext_irq_grp *irq_grp);
+	void (*ce_irq_enable)(struct ath11k_base *ab, u16 ce_id);
+	void (*ce_irq_disable)(struct ath11k_base *ab, u16 ce_id);
 };
 
 static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab)
-- 
2.7.4


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

* [PATCH 5/6] ath11k: supports one MSI vector
  2020-12-23  3:02 [PATCH 0/6] ath11k: support one MSI vector Carl Huang
                   ` (3 preceding siblings ...)
  2020-12-23  3:02 ` [PATCH 4/6] ath11k: refactor mulitple msi vector implementation Carl Huang
@ 2020-12-23  3:02 ` Carl Huang
  2020-12-23  3:02 ` [PATCH 6/6] ath11k: do not restore ASPM in case of single " Carl Huang
  2021-02-11  7:07 ` [PATCH 0/6] ath11k: support one " Kalle Valo
  6 siblings, 0 replies; 10+ messages in thread
From: Carl Huang @ 2020-12-23  3:02 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless

Some platforms can't allocate 32 MSI vectors to QCA6390, and QCA6390
will request one MSI vector instead.

In case of one MSI vector, interrupt migration needs to be disabled.
This is because when interrupt migration happens, the msi_data may
change. However, msi_data is already programmed to rings during
initial phase and ath11k has no way to know that msi_data is changed
during run time and reprogram again.

In case of one MSI vector, MHI subsystem should not use IRQF_NO_SUSPEND
as QCA6390 doesn't set this flag too. Ath11k doesn't need to leave
IRQ enabled in suspend state.

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

Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
---
 drivers/net/wireless/ath/ath11k/mhi.c | 13 ++++++--
 drivers/net/wireless/ath/ath11k/pci.c | 59 +++++++++++++++++++++++++++--------
 2 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
index 09858e5..2d35309 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.c
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
@@ -152,14 +152,17 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
 {
 	struct ath11k_base *ab = ab_pci->ab;
 	u32 user_base_data, base_vector;
+	u32 vectors_32_capability;
 	int ret, num_vectors, i;
 	int *irq;
+	unsigned int msi_data;
 
 	ret = ath11k_pci_get_user_msi_assignment(ab_pci,
 						 "MHI", &num_vectors,
 						 &user_base_data, &base_vector);
 	if (ret)
 		return ret;
+	vectors_32_capability = ab_pci->vectors_32_capability;
 
 	ath11k_dbg(ab, ATH11K_DBG_PCI, "Number of assigned MSI for MHI is %d, base vector is %d\n",
 		   num_vectors, base_vector);
@@ -168,9 +171,13 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
 	if (!irq)
 		return -ENOMEM;
 
-	for (i = 0; i < num_vectors; i++)
+	for (i = 0; i < num_vectors; i++) {
+		msi_data = vectors_32_capability ?
+			   i + base_vector : base_vector;
+
 		irq[i] = ath11k_pci_get_msi_irq(ab->dev,
-						base_vector + i);
+						msi_data);
+	}
 
 	ab_pci->mhi_ctrl->irq = irq;
 	ab_pci->mhi_ctrl->nr_irqs = num_vectors;
@@ -243,6 +250,8 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
 		return ret;
 	}
 
+	if (!ab_pci->vectors_32_capability)
+		mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
 	mhi_ctrl->iova_start = 0;
 	mhi_ctrl->iova_stop = 0xffffffff;
 	mhi_ctrl->sbl_size = SZ_512K;
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 5fdfc72..a120d7c 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -62,6 +62,17 @@ static const struct ath11k_msi_config msi_config = {
 	},
 };
 
+static const struct ath11k_msi_config msi_config_one_msi = {
+	.total_vectors = 1,
+	.total_users = 4,
+	.users = (struct ath11k_msi_user[]) {
+		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
+		{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
+		{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
+		{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
+	},
+};
+
 static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
 	"bhi",
 	"mhi-er0",
@@ -530,10 +541,11 @@ static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
 static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
 {
 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
+	int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
 
 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
 
-	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
+	enable_irq(ce_pipe->ab->irq_num[irq_idx]);
 }
 
 static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
@@ -541,10 +553,13 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
 	struct ath11k_ce_pipe *ce_pipe = arg;
 	struct ath11k_base *ab = ce_pipe->ab;
 
+	int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
+
 	if (!ab->ce_irq_enabled_flag)
 		return IRQ_HANDLED;
 
-	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
+	disable_irq_nosync(ab->irq_num[irq_idx]);
+
 	tasklet_schedule(&ce_pipe->intr_tq);
 
 	return IRQ_HANDLED;
@@ -638,11 +653,13 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
 						napi);
 	struct ath11k_base *ab = irq_grp->ab;
 	int work_done;
+	int i;
 
 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
 	if (work_done < budget) {
 		napi_complete_done(napi, work_done);
-		ath11k_pci_ext_grp_enable(irq_grp);
+		for (i = 0; i < irq_grp->num_irq; i++)
+			enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
 	}
 
 	if (work_done > budget)
@@ -654,13 +671,15 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
 static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
 {
 	struct ath11k_ext_irq_grp *irq_grp = arg;
+	int i;
 
 	if (!irq_grp->ab->ext_irq_enabled_flag)
 		return IRQ_HANDLED;
 
 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
 
-	ath11k_pci_ext_grp_disable(irq_grp);
+	for (i = 0; i < irq_grp->num_irq; i++)
+		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
 
 	napi_schedule(&irq_grp->napi);
 
@@ -747,6 +766,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab)
 	/* Configure CE irqs */
 	for (i = 0; i < ab->hw_params.ce_count; i++) {
 		msi_data = (i % msi_data_count) + msi_irq_start;
+
 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
 		ce_pipe = &ab->ce.ce_pipe[i];
 
@@ -813,6 +833,14 @@ static void ath11k_pci_init_irq_handlers(struct ath11k_pci *ab_pci, bool multipl
 		ab_pci->ce_irq_disable = ath11k_pci_ce_irq_disable_multiple_msi;
 		ab_pci->msi_config = &msi_config;
 		ab_pci->irq_flags = IRQF_SHARED;
+	} else {
+		ab_pci->vectors_32_capability = false;
+		ab_pci->ext_grp_enable = NULL;
+		ab_pci->ext_grp_disable = NULL;
+		ab_pci->ce_irq_enable = NULL;
+		ab_pci->ce_irq_disable = NULL;
+		ab_pci->msi_config = &msi_config_one_msi;
+		ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
 	}
 }
 
@@ -827,16 +855,20 @@ static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
 					    msi_config.total_vectors,
 					    msi_config.total_vectors,
 					    PCI_IRQ_MSI);
-	if (num_vectors != msi_config.total_vectors) {
-		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
-			   msi_config.total_vectors, num_vectors);
-
-		if (num_vectors >= 0)
-			return -EINVAL;
-		else
-			return num_vectors;
-	} else {
+
+	if (num_vectors == msi_config.total_vectors) {
 		ath11k_pci_init_irq_handlers(ab_pci, true);
+	} else {
+		num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
+						    1,
+						    1,
+						    PCI_IRQ_MSI);
+		if (num_vectors < 0) {
+			ret = -EINVAL;
+			goto reset_msi_config;
+		}
+		ath11k_pci_init_irq_handlers(ab_pci, false);
+		ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n");
 	}
 
 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
@@ -857,6 +889,7 @@ static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
 free_msi_vector:
 	pci_free_irq_vectors(ab_pci->pdev);
 
+reset_msi_config:
 	return ret;
 }
 
-- 
2.7.4


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

* [PATCH 6/6] ath11k: do not restore ASPM in case of single MSI vector
  2020-12-23  3:02 [PATCH 0/6] ath11k: support one MSI vector Carl Huang
                   ` (4 preceding siblings ...)
  2020-12-23  3:02 ` [PATCH 5/6] ath11k: supports one MSI vector Carl Huang
@ 2020-12-23  3:02 ` Carl Huang
  2021-02-11  7:07 ` [PATCH 0/6] ath11k: support one " Kalle Valo
  6 siblings, 0 replies; 10+ messages in thread
From: Carl Huang @ 2020-12-23  3:02 UTC (permalink / raw)
  To: ath11k; +Cc: linux-wireless

For single MSI vector, ath11k doesn't restore ASPM as the MHI
register reading in M2 causes system hung.

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

Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
---
 drivers/net/wireless/ath/ath11k/pci.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index a120d7c..8c6147b 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -1119,7 +1119,11 @@ static int ath11k_pci_start(struct ath11k_base *ab)
 
 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
 
-	ath11k_pci_aspm_restore(ab_pci);
+	/* TODO: fo now don't restore ASPM in case of single MSI
+	 * vector as MHI register reading in M2 causes system hang.
+	 */
+	if (ab_pci->vectors_32_capability)
+		ath11k_pci_aspm_restore(ab_pci);
 	ab->ce_irq_enabled_flag = true;
 
 	ath11k_pci_ce_irqs_enable(ab);
-- 
2.7.4


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

* Re: [PATCH 0/6] ath11k: support one MSI vector
  2020-12-23  3:02 [PATCH 0/6] ath11k: support one MSI vector Carl Huang
                   ` (5 preceding siblings ...)
  2020-12-23  3:02 ` [PATCH 6/6] ath11k: do not restore ASPM in case of single " Carl Huang
@ 2021-02-11  7:07 ` Kalle Valo
  2021-10-22  8:04   ` Janusz Dziedzic
  6 siblings, 1 reply; 10+ messages in thread
From: Kalle Valo @ 2021-02-11  7:07 UTC (permalink / raw)
  To: Carl Huang; +Cc: ath11k, linux-wireless

Carl Huang <cjhuang@codeaurora.org> writes:

> This patch set is to support one MSI vector for QCA6390.
>
> Carl Huang (6):
>   ath11k: get msi_data again after request_irq is called
>   ath11k: add ce and ext irq flag to indicate irq_handler
>   ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for dp irqx
>   ath11k: refactor mulitple msi vector implementation
>   ath11k: supports one MSI vector
>   ath11k: do not restore ASPM in case of single MSI vector

I did some cleanup and before submitting v2 I noticed the patchset (both
v1 and v2) is crashing during suspend on my Dell XPS 13 9310. We are
investigating the reason for that and will submit v2 once those are
fixed.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

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

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

* Re: [PATCH 0/6] ath11k: support one MSI vector
  2021-02-11  7:07 ` [PATCH 0/6] ath11k: support one " Kalle Valo
@ 2021-10-22  8:04   ` Janusz Dziedzic
  2021-11-15 10:43     ` Kalle Valo
  0 siblings, 1 reply; 10+ messages in thread
From: Janusz Dziedzic @ 2021-10-22  8:04 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Carl Huang, ath11k, linux-wireless

czw., 11 lut 2021 o 08:10 Kalle Valo <kvalo@codeaurora.org> napisał(a):
>
> Carl Huang <cjhuang@codeaurora.org> writes:
>
> > This patch set is to support one MSI vector for QCA6390.
> >
> > Carl Huang (6):
> >   ath11k: get msi_data again after request_irq is called
> >   ath11k: add ce and ext irq flag to indicate irq_handler
> >   ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for dp irqx
> >   ath11k: refactor mulitple msi vector implementation
> >   ath11k: supports one MSI vector
> >   ath11k: do not restore ASPM in case of single MSI vector
>
> I did some cleanup and before submitting v2 I noticed the patchset (both
> v1 and v2) is crashing during suspend on my Dell XPS 13 9310. We are
> investigating the reason for that and will submit v2 once those are
> fixed.
>
Hello Kalle,

What is status for this series?
I am using ath11k in my banana-pi-r64 (backports-5.15-rc6) board and hit:
[  162.392043] ath11k_pci 0000:01:00.0: failed to get 32 MSI vectors,
only -28 available
[  162.399927] ath11k_pci 0000:01:00.0: failed to enable msi: -28
[  162.405778] ath11k_pci 0000:01:00.0: disabling bus mastering
[  162.411481] ath11k_pci: probe of 0000:01:00.0 failed with error -28

I suspect this series should fix my issue?

BR
Janusz

> --
> https://patchwork.kernel.org/project/linux-wireless/list/
>
> https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



-- 
Janusz Dziedzic

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

* Re: [PATCH 0/6] ath11k: support one MSI vector
  2021-10-22  8:04   ` Janusz Dziedzic
@ 2021-11-15 10:43     ` Kalle Valo
  0 siblings, 0 replies; 10+ messages in thread
From: Kalle Valo @ 2021-11-15 10:43 UTC (permalink / raw)
  To: Janusz Dziedzic; +Cc: Carl Huang, ath11k, linux-wireless

Janusz Dziedzic <janusz.dziedzic@gmail.com> writes:

> czw., 11 lut 2021 o 08:10 Kalle Valo <kvalo@codeaurora.org> napisał(a):
>>
>> Carl Huang <cjhuang@codeaurora.org> writes:
>>
>> > This patch set is to support one MSI vector for QCA6390.
>> >
>> > Carl Huang (6):
>> >   ath11k: get msi_data again after request_irq is called
>> >   ath11k: add ce and ext irq flag to indicate irq_handler
>> >   ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for dp irqx
>> >   ath11k: refactor mulitple msi vector implementation
>> >   ath11k: supports one MSI vector
>> >   ath11k: do not restore ASPM in case of single MSI vector
>>
>> I did some cleanup and before submitting v2 I noticed the patchset (both
>> v1 and v2) is crashing during suspend on my Dell XPS 13 9310. We are
>> investigating the reason for that and will submit v2 once those are
>> fixed.
>>
> Hello Kalle,
>
> What is status for this series?

There's now a new version available:

https://patchwork.kernel.org/project/linux-wireless/cover/20211026041616.4956-1-bqiang@codeaurora.org/

If you can, please do test the version in the master-pending branch
(commit 9a914cfdbfd69):

https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/log/?h=master-pending

> I am using ath11k in my banana-pi-r64 (backports-5.15-rc6) board and hit:
> [  162.392043] ath11k_pci 0000:01:00.0: failed to get 32 MSI vectors,
> only -28 available
> [  162.399927] ath11k_pci 0000:01:00.0: failed to enable msi: -28
> [  162.405778] ath11k_pci 0000:01:00.0: disabling bus mastering
> [  162.411481] ath11k_pci: probe of 0000:01:00.0 failed with error -28
>
> I suspect this series should fix my issue?

Most likely this should fix it. You could also try changing your BIOS
settings to get more MSI vectors, IIRC enabling VT-d help on NUC boards
at least.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

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

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

end of thread, other threads:[~2021-11-15 10:43 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-23  3:02 [PATCH 0/6] ath11k: support one MSI vector Carl Huang
2020-12-23  3:02 ` [PATCH 1/6] ath11k: get msi_data again after request_irq is called Carl Huang
2020-12-23  3:02 ` [PATCH 2/6] ath11k: add ce and ext irq flag to indicate irq_handler Carl Huang
2020-12-23  3:02 ` [PATCH 3/6] ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for dp irqx Carl Huang
2020-12-23  3:02 ` [PATCH 4/6] ath11k: refactor mulitple msi vector implementation Carl Huang
2020-12-23  3:02 ` [PATCH 5/6] ath11k: supports one MSI vector Carl Huang
2020-12-23  3:02 ` [PATCH 6/6] ath11k: do not restore ASPM in case of single " Carl Huang
2021-02-11  7:07 ` [PATCH 0/6] ath11k: support one " Kalle Valo
2021-10-22  8:04   ` Janusz Dziedzic
2021-11-15 10:43     ` Kalle Valo

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).