wil6210_unmask_irq_misc(wil, false);
 
+       /* in non-triple MSI case, this is done inside wil6210_thread_irq
+        * because it has to be done after unmasking the pseudo.
+        */
+       if (wil->n_msi == 3 && wil->suspend_resp_rcvd) {
+               wil_dbg_irq(wil, "set suspend_resp_comp to true\n");
+               wil->suspend_resp_comp = true;
+               wake_up_interruptible(&wil->wq);
+       }
+
        return IRQ_HANDLED;
 }
 
        return rc;
 }
 
+static int wil6210_request_3msi(struct wil6210_priv *wil, int irq)
+{
+       int rc;
+
+       /* IRQ's are in the following order:
+        * - Tx
+        * - Rx
+        * - Misc
+        */
+       rc = request_irq(irq, wil->txrx_ops.irq_tx, IRQF_SHARED,
+                        WIL_NAME "_tx", wil);
+       if (rc)
+               return rc;
+
+       rc = request_irq(irq + 1, wil->txrx_ops.irq_rx, IRQF_SHARED,
+                        WIL_NAME "_rx", wil);
+       if (rc)
+               goto free0;
+
+       rc = request_threaded_irq(irq + 2, wil6210_irq_misc,
+                                 wil6210_irq_misc_thread,
+                                 IRQF_SHARED, WIL_NAME "_misc", wil);
+       if (rc)
+               goto free1;
+
+       return 0;
+free1:
+       free_irq(irq + 1, wil);
+free0:
+       free_irq(irq, wil);
+
+       return rc;
+}
+
 /* can't use wil_ioread32_and_clear because ICC value is not set yet */
 static inline void wil_clear32(void __iomem *addr)
 {
        wil6210_unmask_halp(wil);
 }
 
-int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi)
+int wil6210_init_irq(struct wil6210_priv *wil, int irq)
 {
        int rc;
 
-       wil_dbg_misc(wil, "init_irq: %s\n", use_msi ? "MSI" : "INTx");
+       wil_dbg_misc(wil, "init_irq: %s, n_msi=%d\n",
+                    wil->n_msi ? "MSI" : "INTx", wil->n_msi);
 
        if (wil->use_enhanced_dma_hw) {
                wil->txrx_ops.irq_tx = wil6210_irq_tx_edma;
                wil->txrx_ops.irq_tx = wil6210_irq_tx;
                wil->txrx_ops.irq_rx = wil6210_irq_rx;
        }
-       rc = request_threaded_irq(irq, wil6210_hardirq,
-                                 wil6210_thread_irq,
-                                 use_msi ? 0 : IRQF_SHARED,
-                                 WIL_NAME, wil);
+
+       if (wil->n_msi == 3)
+               rc = wil6210_request_3msi(wil, irq);
+       else
+               rc = request_threaded_irq(irq, wil6210_hardirq,
+                                         wil6210_thread_irq,
+                                         wil->n_msi ? 0 : IRQF_SHARED,
+                                         WIL_NAME, wil);
        return rc;
 }
 
 
        wil_mask_irq(wil);
        free_irq(irq, wil);
+       if (wil->n_msi == 3) {
+               free_irq(irq + 1, wil);
+               free_irq(irq + 2, wil);
+       }
 }
 
                                     wil->platform_capa)) ?
                        BIT(WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL) : 0;
 
+               if (wil->n_msi == 3)
+                       features |= BIT(WIL_PLATFORM_FEATURE_TRIPLE_MSI);
+
                wil->platform_ops.set_features(wil->platform_handle, features);
        }
 }
 
 #include <linux/rtnetlink.h>
 #include <linux/pm_runtime.h>
 
-static bool use_msi = true;
-module_param(use_msi, bool, 0444);
-MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true");
+static int n_msi = 1;
+module_param(n_msi, int, 0444);
+MODULE_PARM_DESC(n_msi, " Use MSI interrupt: 0 - use INTx, 1 - (default) - single, or 3");
 
 static bool ftm_mode;
 module_param(ftm_mode, bool, 0444);
 
 void wil_disable_irq(struct wil6210_priv *wil)
 {
-       disable_irq(wil->pdev->irq);
+       int irq = wil->pdev->irq;
+
+       disable_irq(irq);
+       if (wil->n_msi == 3) {
+               disable_irq(irq + 1);
+               disable_irq(irq + 2);
+       }
 }
 
 void wil_enable_irq(struct wil6210_priv *wil)
 {
-       enable_irq(wil->pdev->irq);
+       int irq = wil->pdev->irq;
+
+       enable_irq(irq);
+       if (wil->n_msi == 3) {
+               enable_irq(irq + 1);
+               enable_irq(irq + 2);
+       }
 }
 
 static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
         * and only MSI should be used
         */
        int msi_only = pdev->msi_enabled;
-       bool _use_msi = use_msi;
 
        wil_dbg_misc(wil, "if_pcie_enable\n");
 
        pci_set_master(pdev);
 
-       wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx");
+       /* how many MSI interrupts to request? */
+       switch (n_msi) {
+       case 3:
+       case 1:
+               wil_dbg_misc(wil, "Setup %d MSI interrupts\n", n_msi);
+               break;
+       case 0:
+               wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
+               break;
+       default:
+               wil_err(wil, "Invalid n_msi=%d, default to 1\n", n_msi);
+               n_msi = 1;
+       }
+
+       if (n_msi == 3 &&
+           pci_alloc_irq_vectors(pdev, n_msi, n_msi, PCI_IRQ_MSI) < n_msi) {
+               wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
+               n_msi = 1;
+       }
 
-       if (use_msi && pci_enable_msi(pdev)) {
+       if (n_msi == 1 && pci_enable_msi(pdev)) {
                wil_err(wil, "pci_enable_msi failed, use INTx\n");
-               _use_msi = false;
+               n_msi = 0;
        }
 
-       if (!_use_msi && msi_only) {
+       wil->n_msi = n_msi;
+
+       if (wil->n_msi == 0 && msi_only) {
                wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");
                rc = -ENODEV;
                goto stop_master;
        }
 
-       rc = wil6210_init_irq(wil, pdev->irq, _use_msi);
+       rc = wil6210_init_irq(wil, pdev->irq);
        if (rc)
-               goto stop_master;
+               goto release_vectors;
 
        /* need reset here to obtain MAC */
        mutex_lock(&wil->mutex);
 
  release_irq:
        wil6210_fini_irq(wil, pdev->irq);
-       /* safe to call if no MSI */
-       pci_disable_msi(pdev);
+ release_vectors:
+       /* safe to call if no allocation */
+       pci_free_irq_vectors(pdev);
  stop_master:
        pci_clear_master(pdev);
        return rc;
 
        u32 bar_size;
        struct wiphy *wiphy;
        struct net_device *main_ndev;
+       int n_msi;
        void __iomem *csr;
        DECLARE_BITMAP(status, wil_status_last);
        u8 fw_version[ETHTOOL_FWVERS_LEN];
 int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize);
 
 void wil6210_clear_irq(struct wil6210_priv *wil);
-int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi);
+int wil6210_init_irq(struct wil6210_priv *wil, int irq);
 void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
 void wil_mask_irq(struct wil6210_priv *wil);
 void wil_unmask_irq(struct wil6210_priv *wil);
 
 
 enum wil_platform_features {
        WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL = 0,
+       WIL_PLATFORM_FEATURE_TRIPLE_MSI = 1,
        WIL_PLATFORM_FEATURE_MAX,
 };