瀏覽代碼

ath10k: don't consume other's shared interrupts

ath10k assumed all interrupts were directed to it.
This isn't the case for legacy shared interrupts.
ath10k consumed interrupts for other devices.

Check device irq status and return IRQ_NONE when
appropriate.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Michal Kazior 11 年之前
父節點
當前提交
e539887b15
共有 2 個文件被更改,包括 17 次插入0 次删除
  1. 1 0
      drivers/net/wireless/ath/ath10k/hw.h
  2. 16 0
      drivers/net/wireless/ath/ath10k/pci.c

+ 1 - 0
drivers/net/wireless/ath/ath10k/hw.h

@@ -269,6 +269,7 @@ enum ath10k_mcast2ucast_mode {
 #define CORE_CTRL_CPU_INTR_MASK			0x00002000
 #define CORE_CTRL_CPU_INTR_MASK			0x00002000
 #define CORE_CTRL_ADDRESS			0x0000
 #define CORE_CTRL_ADDRESS			0x0000
 #define PCIE_INTR_ENABLE_ADDRESS		0x0008
 #define PCIE_INTR_ENABLE_ADDRESS		0x0008
+#define PCIE_INTR_CAUSE_ADDRESS			0x000c
 #define PCIE_INTR_CLR_ADDRESS			0x0014
 #define PCIE_INTR_CLR_ADDRESS			0x0014
 #define SCRATCH_3_ADDRESS			0x0030
 #define SCRATCH_3_ADDRESS			0x0030
 
 

+ 16 - 0
drivers/net/wireless/ath/ath10k/pci.c

@@ -201,6 +201,19 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
 	/* CE7 used only by Host */
 	/* CE7 used only by Host */
 };
 };
 
 
+static bool ath10k_pci_irq_pending(struct ath10k *ar)
+{
+	u32 cause;
+
+	/* Check if the shared legacy irq is for us */
+	cause = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+				  PCIE_INTR_CAUSE_ADDRESS);
+	if (cause & (PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL))
+		return true;
+
+	return false;
+}
+
 /*
 /*
  * Diagnostic read/write access is provided for startup/config/debug usage.
  * Diagnostic read/write access is provided for startup/config/debug usage.
  * Caller must guarantee proper alignment, when applicable, and single user
  * Caller must guarantee proper alignment, when applicable, and single user
@@ -2086,6 +2099,9 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
 
 	if (ar_pci->num_msi_intrs == 0) {
 	if (ar_pci->num_msi_intrs == 0) {
+		if (!ath10k_pci_irq_pending(ar))
+			return IRQ_NONE;
+
 		/*
 		/*
 		 * IMPORTANT: INTR_CLR regiser has to be set after
 		 * IMPORTANT: INTR_CLR regiser has to be set after
 		 * INTR_ENABLE is set to 0, otherwise interrupt can not be
 		 * INTR_ENABLE is set to 0, otherwise interrupt can not be