|
@@ -24,9 +24,9 @@
|
|
#include <linux/rtnetlink.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <linux/pm_runtime.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;
|
|
static bool ftm_mode;
|
|
module_param(ftm_mode, bool, 0444);
|
|
module_param(ftm_mode, bool, 0444);
|
|
@@ -150,12 +150,24 @@ int wil_set_capabilities(struct wil6210_priv *wil)
|
|
|
|
|
|
void wil_disable_irq(struct wil6210_priv *wil)
|
|
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)
|
|
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)
|
|
static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
|
|
@@ -182,28 +194,47 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
|
* and only MSI should be used
|
|
* and only MSI should be used
|
|
*/
|
|
*/
|
|
int msi_only = pdev->msi_enabled;
|
|
int msi_only = pdev->msi_enabled;
|
|
- bool _use_msi = use_msi;
|
|
|
|
|
|
|
|
wil_dbg_misc(wil, "if_pcie_enable\n");
|
|
wil_dbg_misc(wil, "if_pcie_enable\n");
|
|
|
|
|
|
pci_set_master(pdev);
|
|
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");
|
|
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");
|
|
wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");
|
|
rc = -ENODEV;
|
|
rc = -ENODEV;
|
|
goto stop_master;
|
|
goto stop_master;
|
|
}
|
|
}
|
|
|
|
|
|
- rc = wil6210_init_irq(wil, pdev->irq, _use_msi);
|
|
|
|
|
|
+ rc = wil6210_init_irq(wil, pdev->irq);
|
|
if (rc)
|
|
if (rc)
|
|
- goto stop_master;
|
|
|
|
|
|
+ goto release_vectors;
|
|
|
|
|
|
/* need reset here to obtain MAC */
|
|
/* need reset here to obtain MAC */
|
|
mutex_lock(&wil->mutex);
|
|
mutex_lock(&wil->mutex);
|
|
@@ -216,8 +247,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
|
|
|
|
|
release_irq:
|
|
release_irq:
|
|
wil6210_fini_irq(wil, pdev->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:
|
|
stop_master:
|
|
pci_clear_master(pdev);
|
|
pci_clear_master(pdev);
|
|
return rc;
|
|
return rc;
|