summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérôme Pouiller <jerome.pouiller@silabs.com>2020-05-05 14:37:50 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-05-13 13:26:41 +0200
commitf00dc1d789e1caab0e154d0b2bf581fa1be87b2b (patch)
tree9c9f0d54668fc785ec95d0c50804534ca4e17079
parent57aa557f110d9fb6980cb58498cfd3a51feb5473 (diff)
staging: wfx: poll IRQ during init
When the chip starts in SDIO mode, the external IRQ (aka Out-Of-Band IRQ) cannot be used before to configure it. Therefore, the first exchanges with the chip have to be done without the OOB IRQ. This patch allow to poll the data until the OOB IRQ is correctly setup. In order to keep the code simpler, this patch also poll data even if OOB IRQ is not used. Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com> Link: https://lore.kernel.org/r/20200505123757.39506-9-Jerome.Pouiller@silabs.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/staging/wfx/bh.c1
-rw-r--r--drivers/staging/wfx/bus.h2
-rw-r--r--drivers/staging/wfx/bus_sdio.c17
-rw-r--r--drivers/staging/wfx/bus_spi.c16
-rw-r--r--drivers/staging/wfx/hif_tx.c3
-rw-r--r--drivers/staging/wfx/main.c28
-rw-r--r--drivers/staging/wfx/wfx.h1
7 files changed, 47 insertions, 21 deletions
diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c
index d3e7eed89c38..2572fbcf1a33 100644
--- a/drivers/staging/wfx/bh.c
+++ b/drivers/staging/wfx/bh.c
@@ -320,6 +320,7 @@ void wfx_bh_poll_irq(struct wfx_dev *wdev)
ktime_t now, start;
u32 reg;
+ WARN(!wdev->poll_irq, "unexpected IRQ polling can mask IRQ");
start = ktime_get();
for (;;) {
control_reg_read(wdev, &reg);
diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h
index 62d6ecabe4cb..0370b6c59863 100644
--- a/drivers/staging/wfx/bus.h
+++ b/drivers/staging/wfx/bus.h
@@ -25,6 +25,8 @@ struct hwbus_ops {
void *dst, size_t count);
int (*copy_to_io)(void *bus_priv, unsigned int addr,
const void *src, size_t count);
+ int (*irq_subscribe)(void *bus_priv);
+ int (*irq_unsubscribe)(void *bus_priv);
void (*lock)(void *bus_priv);
void (*unlock)(void *bus_priv);
size_t (*align_size)(void *bus_priv, size_t size);
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 43a6b10c772a..6464b2c508e4 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -106,8 +106,9 @@ static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv)
return IRQ_HANDLED;
}
-static int wfx_sdio_irq_subscribe(struct wfx_sdio_priv *bus)
+static int wfx_sdio_irq_subscribe(void *priv)
{
+ struct wfx_sdio_priv *bus = priv;
u32 flags;
int ret;
u8 cccr;
@@ -134,8 +135,9 @@ static int wfx_sdio_irq_subscribe(struct wfx_sdio_priv *bus)
"wfx", bus);
}
-static int wfx_sdio_irq_unsubscribe(struct wfx_sdio_priv *bus)
+static int wfx_sdio_irq_unsubscribe(void *priv)
{
+ struct wfx_sdio_priv *bus = priv;
int ret;
if (bus->of_irq)
@@ -156,6 +158,8 @@ static size_t wfx_sdio_align_size(void *priv, size_t size)
static const struct hwbus_ops wfx_sdio_hwbus_ops = {
.copy_from_io = wfx_sdio_copy_from_io,
.copy_to_io = wfx_sdio_copy_to_io,
+ .irq_subscribe = wfx_sdio_irq_subscribe,
+ .irq_unsubscribe = wfx_sdio_irq_unsubscribe,
.lock = wfx_sdio_lock,
.unlock = wfx_sdio_unlock,
.align_size = wfx_sdio_align_size,
@@ -218,18 +222,12 @@ static int wfx_sdio_probe(struct sdio_func *func,
goto err1;
}
- ret = wfx_sdio_irq_subscribe(bus);
- if (ret)
- goto err1;
-
ret = wfx_probe(bus->core);
if (ret)
- goto err2;
+ goto err1;
return 0;
-err2:
- wfx_sdio_irq_unsubscribe(bus);
err1:
sdio_claim_host(func);
sdio_disable_func(func);
@@ -243,7 +241,6 @@ static void wfx_sdio_remove(struct sdio_func *func)
struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
wfx_release(bus->core);
- wfx_sdio_irq_unsubscribe(bus);
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index 00613d046c3f..e8da61fb096b 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -12,6 +12,7 @@
#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/of.h>
#include "bus.h"
@@ -143,8 +144,9 @@ static irqreturn_t wfx_spi_irq_handler(int irq, void *priv)
return IRQ_HANDLED;
}
-static int wfx_spi_irq_subscribe(struct wfx_spi_priv *bus)
+static int wfx_spi_irq_subscribe(void *priv)
{
+ struct wfx_spi_priv *bus = priv;
u32 flags;
flags = irq_get_trigger_type(bus->func->irq);
@@ -156,6 +158,14 @@ static int wfx_spi_irq_subscribe(struct wfx_spi_priv *bus)
"wfx", bus);
}
+static int wfx_spi_irq_unsubscribe(void *priv)
+{
+ struct wfx_spi_priv *bus = priv;
+
+ devm_free_irq(&bus->func->dev, bus->func->irq, bus);
+ return 0;
+}
+
static size_t wfx_spi_align_size(void *priv, size_t size)
{
// Most of SPI controllers avoid DMA if buffer size is not 32bit aligned
@@ -165,6 +175,8 @@ static size_t wfx_spi_align_size(void *priv, size_t size)
static const struct hwbus_ops wfx_spi_hwbus_ops = {
.copy_from_io = wfx_spi_copy_from_io,
.copy_to_io = wfx_spi_copy_to_io,
+ .irq_subscribe = wfx_spi_irq_subscribe,
+ .irq_unsubscribe = wfx_spi_irq_unsubscribe,
.lock = wfx_spi_lock,
.unlock = wfx_spi_unlock,
.align_size = wfx_spi_align_size,
@@ -216,8 +228,6 @@ static int wfx_spi_probe(struct spi_device *func)
if (!bus->core)
return -EIO;
- wfx_spi_irq_subscribe(bus);
-
return wfx_probe(bus->core);
}
diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c
index e8f3c5f9ce7b..511ef874a6d9 100644
--- a/drivers/staging/wfx/hif_tx.c
+++ b/drivers/staging/wfx/hif_tx.c
@@ -82,6 +82,9 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply,
if (async)
return 0;
+ if (wdev->poll_irq)
+ wfx_bh_poll_irq(wdev);
+
ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ);
if (!ret) {
dev_err(wdev->dev, "chip is abnormally long to answer\n");
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 5d0754b55429..623a9fc31153 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -363,22 +363,24 @@ int wfx_probe(struct wfx_dev *wdev)
// prevent bh() to touch it.
gpio_saved = wdev->pdata.gpio_wakeup;
wdev->pdata.gpio_wakeup = NULL;
+ wdev->poll_irq = true;
wfx_bh_register(wdev);
err = wfx_init_device(wdev);
if (err)
- goto err1;
+ goto err0;
+ wfx_bh_poll_irq(wdev);
err = wait_for_completion_timeout(&wdev->firmware_ready, 1 * HZ);
if (err <= 0) {
if (err == 0) {
- dev_err(wdev->dev, "timeout while waiting for startup indication. IRQ configuration error?\n");
+ dev_err(wdev->dev, "timeout while waiting for startup indication\n");
err = -ETIMEDOUT;
} else if (err == -ERESTARTSYS) {
dev_info(wdev->dev, "probe interrupted by user\n");
}
- goto err1;
+ goto err0;
}
// FIXME: fill wiphy::hw_version
@@ -400,14 +402,14 @@ int wfx_probe(struct wfx_dev *wdev)
"unsupported firmware API version (expect 1 while firmware returns %d)\n",
wdev->hw_caps.api_version_major);
err = -ENOTSUPP;
- goto err1;
+ goto err0;
}
err = wfx_sl_init(wdev);
if (err && wdev->hw_caps.capabilities.link_mode == SEC_LINK_ENFORCED) {
dev_err(wdev->dev,
"chip require secure_link, but can't negociate it\n");
- goto err1;
+ goto err0;
}
if (wdev->hw_caps.regul_sel_mode_info.region_sel_mode) {
@@ -420,7 +422,16 @@ int wfx_probe(struct wfx_dev *wdev)
wdev->pdata.file_pds);
err = wfx_send_pdata_pds(wdev);
if (err < 0)
- goto err1;
+ goto err0;
+
+ wdev->poll_irq = false;
+ err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv);
+ if (err)
+ goto err0;
+
+ err = hif_use_multi_tx_conf(wdev, true);
+ if (err)
+ dev_err(wdev->dev, "misconfigured IRQ?\n");
wdev->pdata.gpio_wakeup = gpio_saved;
if (wdev->pdata.gpio_wakeup) {
@@ -435,8 +446,6 @@ int wfx_probe(struct wfx_dev *wdev)
hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE);
}
- hif_use_multi_tx_conf(wdev, true);
-
for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
eth_zero_addr(wdev->addresses[i].addr);
macaddr = of_get_mac_address(wdev->dev->of_node);
@@ -470,6 +479,8 @@ int wfx_probe(struct wfx_dev *wdev)
err2:
ieee80211_unregister_hw(wdev->hw);
err1:
+ wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv);
+err0:
wfx_bh_unregister(wdev);
return err;
}
@@ -478,6 +489,7 @@ void wfx_release(struct wfx_dev *wdev)
{
ieee80211_unregister_hw(wdev->hw);
hif_shutdown(wdev);
+ wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv);
wfx_bh_unregister(wdev);
wfx_sl_deinit(wdev);
}
diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
index 09bbb5da4f06..4eb7762142fc 100644
--- a/drivers/staging/wfx/wfx.h
+++ b/drivers/staging/wfx/wfx.h
@@ -46,6 +46,7 @@ struct wfx_dev {
struct wfx_hif hif;
struct sl_context sl;
struct delayed_work cooling_timeout_work;
+ bool poll_irq;
bool chip_frozen;
struct mutex conf_mutex;