@@ -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, ®);
@@ -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);
@@ -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,
@@ -212,18 +216,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);
@@ -237,7 +235,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);
@@ -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);
}
@@ -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");
@@ -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);
}
@@ -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;