|
@@ -33,12 +33,6 @@
|
|
|
#include "ce.h"
|
|
|
#include "pci.h"
|
|
|
|
|
|
-enum ath10k_pci_irq_mode {
|
|
|
- ATH10K_PCI_IRQ_AUTO = 0,
|
|
|
- ATH10K_PCI_IRQ_LEGACY = 1,
|
|
|
- ATH10K_PCI_IRQ_MSI = 2,
|
|
|
-};
|
|
|
-
|
|
|
enum ath10k_pci_reset_mode {
|
|
|
ATH10K_PCI_RESET_AUTO = 0,
|
|
|
ATH10K_PCI_RESET_WARM_ONLY = 1,
|
|
@@ -745,10 +739,7 @@ static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar)
|
|
|
{
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
|
|
|
- if (ar_pci->num_msi_intrs > 1)
|
|
|
- return "msi-x";
|
|
|
-
|
|
|
- if (ar_pci->num_msi_intrs == 1)
|
|
|
+ if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_MSI)
|
|
|
return "msi";
|
|
|
|
|
|
return "legacy";
|
|
@@ -1502,13 +1493,8 @@ void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
|
|
|
void ath10k_pci_kill_tasklet(struct ath10k *ar)
|
|
|
{
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
- int i;
|
|
|
|
|
|
tasklet_kill(&ar_pci->intr_tq);
|
|
|
- tasklet_kill(&ar_pci->msi_fw_err);
|
|
|
-
|
|
|
- for (i = 0; i < CE_COUNT; i++)
|
|
|
- tasklet_kill(&ar_pci->pipe_info[i].intr);
|
|
|
|
|
|
del_timer_sync(&ar_pci->rx_post_retry);
|
|
|
}
|
|
@@ -1624,10 +1610,8 @@ static void ath10k_pci_irq_disable(struct ath10k *ar)
|
|
|
static void ath10k_pci_irq_sync(struct ath10k *ar)
|
|
|
{
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
- int i;
|
|
|
|
|
|
- for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
|
|
|
- synchronize_irq(ar_pci->pdev->irq + i);
|
|
|
+ synchronize_irq(ar_pci->pdev->irq);
|
|
|
}
|
|
|
|
|
|
static void ath10k_pci_irq_enable(struct ath10k *ar)
|
|
@@ -2596,65 +2580,6 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
-static void ath10k_pci_ce_tasklet(unsigned long ptr)
|
|
|
-{
|
|
|
- struct ath10k_pci_pipe *pipe = (struct ath10k_pci_pipe *)ptr;
|
|
|
- struct ath10k_pci *ar_pci = pipe->ar_pci;
|
|
|
-
|
|
|
- ath10k_ce_per_engine_service(ar_pci->ar, pipe->pipe_num);
|
|
|
-}
|
|
|
-
|
|
|
-static void ath10k_msi_err_tasklet(unsigned long data)
|
|
|
-{
|
|
|
- struct ath10k *ar = (struct ath10k *)data;
|
|
|
-
|
|
|
- if (!ath10k_pci_has_fw_crashed(ar)) {
|
|
|
- ath10k_warn(ar, "received unsolicited fw crash interrupt\n");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- ath10k_pci_irq_disable(ar);
|
|
|
- ath10k_pci_fw_crashed_clear(ar);
|
|
|
- ath10k_pci_fw_crashed_dump(ar);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Handler for a per-engine interrupt on a PARTICULAR CE.
|
|
|
- * This is used in cases where each CE has a private MSI interrupt.
|
|
|
- */
|
|
|
-static irqreturn_t ath10k_pci_per_engine_handler(int irq, void *arg)
|
|
|
-{
|
|
|
- struct ath10k *ar = arg;
|
|
|
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
- int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL;
|
|
|
-
|
|
|
- if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) {
|
|
|
- ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
|
|
|
- ce_id);
|
|
|
- return IRQ_HANDLED;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * NOTE: We are able to derive ce_id from irq because we
|
|
|
- * use a one-to-one mapping for CE's 0..5.
|
|
|
- * CE's 6 & 7 do not use interrupts at all.
|
|
|
- *
|
|
|
- * This mapping must be kept in sync with the mapping
|
|
|
- * used by firmware.
|
|
|
- */
|
|
|
- tasklet_schedule(&ar_pci->pipe_info[ce_id].intr);
|
|
|
- return IRQ_HANDLED;
|
|
|
-}
|
|
|
-
|
|
|
-static irqreturn_t ath10k_pci_msi_fw_handler(int irq, void *arg)
|
|
|
-{
|
|
|
- struct ath10k *ar = arg;
|
|
|
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
-
|
|
|
- tasklet_schedule(&ar_pci->msi_fw_err);
|
|
|
- return IRQ_HANDLED;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Top-level interrupt handler for all PCI interrupts from a Target.
|
|
|
* When a block of MSI interrupts is allocated, this top-level handler
|
|
@@ -2672,7 +2597,7 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
|
|
|
return IRQ_NONE;
|
|
|
}
|
|
|
|
|
|
- if (ar_pci->num_msi_intrs == 0) {
|
|
|
+ if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) {
|
|
|
if (!ath10k_pci_irq_pending(ar))
|
|
|
return IRQ_NONE;
|
|
|
|
|
@@ -2699,43 +2624,10 @@ static void ath10k_pci_tasklet(unsigned long data)
|
|
|
ath10k_ce_per_engine_service_any(ar);
|
|
|
|
|
|
/* Re-enable legacy irq that was disabled in the irq handler */
|
|
|
- if (ar_pci->num_msi_intrs == 0)
|
|
|
+ if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY)
|
|
|
ath10k_pci_enable_legacy_irq(ar);
|
|
|
}
|
|
|
|
|
|
-static int ath10k_pci_request_irq_msix(struct ath10k *ar)
|
|
|
-{
|
|
|
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
- int ret, i;
|
|
|
-
|
|
|
- ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW,
|
|
|
- ath10k_pci_msi_fw_handler,
|
|
|
- IRQF_SHARED, "ath10k_pci", ar);
|
|
|
- if (ret) {
|
|
|
- ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n",
|
|
|
- ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- for (i = MSI_ASSIGN_CE_INITIAL; i <= MSI_ASSIGN_CE_MAX; i++) {
|
|
|
- ret = request_irq(ar_pci->pdev->irq + i,
|
|
|
- ath10k_pci_per_engine_handler,
|
|
|
- IRQF_SHARED, "ath10k_pci", ar);
|
|
|
- if (ret) {
|
|
|
- ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n",
|
|
|
- ar_pci->pdev->irq + i, ret);
|
|
|
-
|
|
|
- for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
|
|
|
- free_irq(ar_pci->pdev->irq + i, ar);
|
|
|
-
|
|
|
- free_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ar);
|
|
|
- return ret;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int ath10k_pci_request_irq_msi(struct ath10k *ar)
|
|
|
{
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
@@ -2774,41 +2666,28 @@ static int ath10k_pci_request_irq(struct ath10k *ar)
|
|
|
{
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
|
|
|
- switch (ar_pci->num_msi_intrs) {
|
|
|
- case 0:
|
|
|
+ switch (ar_pci->oper_irq_mode) {
|
|
|
+ case ATH10K_PCI_IRQ_LEGACY:
|
|
|
return ath10k_pci_request_irq_legacy(ar);
|
|
|
- case 1:
|
|
|
+ case ATH10K_PCI_IRQ_MSI:
|
|
|
return ath10k_pci_request_irq_msi(ar);
|
|
|
default:
|
|
|
- return ath10k_pci_request_irq_msix(ar);
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static void ath10k_pci_free_irq(struct ath10k *ar)
|
|
|
{
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
- int i;
|
|
|
|
|
|
- /* There's at least one interrupt irregardless whether its legacy INTR
|
|
|
- * or MSI or MSI-X */
|
|
|
- for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
|
|
|
- free_irq(ar_pci->pdev->irq + i, ar);
|
|
|
+ free_irq(ar_pci->pdev->irq, ar);
|
|
|
}
|
|
|
|
|
|
void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
|
|
|
{
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
- int i;
|
|
|
|
|
|
tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
|
|
|
- tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
|
|
|
- (unsigned long)ar);
|
|
|
-
|
|
|
- for (i = 0; i < CE_COUNT; i++) {
|
|
|
- ar_pci->pipe_info[i].ar_pci = ar_pci;
|
|
|
- tasklet_init(&ar_pci->pipe_info[i].intr, ath10k_pci_ce_tasklet,
|
|
|
- (unsigned long)&ar_pci->pipe_info[i]);
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
static int ath10k_pci_init_irq(struct ath10k *ar)
|
|
@@ -2822,20 +2701,9 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
|
|
|
ath10k_info(ar, "limiting irq mode to: %d\n",
|
|
|
ath10k_pci_irq_mode);
|
|
|
|
|
|
- /* Try MSI-X */
|
|
|
- if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
|
|
|
- ar_pci->num_msi_intrs = MSI_ASSIGN_CE_MAX + 1;
|
|
|
- ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
|
|
|
- ar_pci->num_msi_intrs);
|
|
|
- if (ret > 0)
|
|
|
- return 0;
|
|
|
-
|
|
|
- /* fall-through */
|
|
|
- }
|
|
|
-
|
|
|
/* Try MSI */
|
|
|
if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) {
|
|
|
- ar_pci->num_msi_intrs = 1;
|
|
|
+ ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_MSI;
|
|
|
ret = pci_enable_msi(ar_pci->pdev);
|
|
|
if (ret == 0)
|
|
|
return 0;
|
|
@@ -2851,7 +2719,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
|
|
|
* This write might get lost if target has NOT written BAR.
|
|
|
* For now, fix the race by repeating the write in below
|
|
|
* synchronization checking. */
|
|
|
- ar_pci->num_msi_intrs = 0;
|
|
|
+ ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY;
|
|
|
|
|
|
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
|
|
|
PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
|
|
@@ -2869,8 +2737,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
|
|
|
{
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
|
|
|
- switch (ar_pci->num_msi_intrs) {
|
|
|
- case 0:
|
|
|
+ switch (ar_pci->oper_irq_mode) {
|
|
|
+ case ATH10K_PCI_IRQ_LEGACY:
|
|
|
ath10k_pci_deinit_irq_legacy(ar);
|
|
|
break;
|
|
|
default:
|
|
@@ -2908,7 +2776,7 @@ int ath10k_pci_wait_for_target_init(struct ath10k *ar)
|
|
|
if (val & FW_IND_INITIALIZED)
|
|
|
break;
|
|
|
|
|
|
- if (ar_pci->num_msi_intrs == 0)
|
|
|
+ if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY)
|
|
|
/* Fix potential race by repeating CORE_BASE writes */
|
|
|
ath10k_pci_enable_legacy_irq(ar);
|
|
|
|
|
@@ -3186,8 +3054,8 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
|
|
goto err_sleep;
|
|
|
}
|
|
|
|
|
|
- ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
|
|
|
- ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs,
|
|
|
+ ath10k_info(ar, "pci irq %s oper_irq_mode %d irq_mode %d reset_mode %d\n",
|
|
|
+ ath10k_pci_get_irq_method(ar), ar_pci->oper_irq_mode,
|
|
|
ath10k_pci_irq_mode, ath10k_pci_reset_mode);
|
|
|
|
|
|
ret = ath10k_pci_request_irq(ar);
|