aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/cw1200
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2013-08-27 20:29:46 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-09-09 14:40:53 -0400
commitaec8e88c947b7017e2b4bbcb68a4bfc4a1f8ad35 (patch)
tree584e2a99402483e16d6145bdf1d29416a1a0abce /drivers/net/wireless/cw1200
parente7d33bb5ea82922e6ddcfc6b28a630b1a4ced071 (diff)
cw1200: Don't perform SPI transfers in interrupt context
When we get an interrupt from the hardware, the first thing the driver does is tell the device to mask off the interrupt line. Unfortunately this involves a SPI transaction in interrupt context. Some (most?) SPI controllers perform the transfer asynchronously and try to sleep. This is bad, and triggers a BUG(). So, work around this by using adding a hwbus hook for the cw1200 driver core to call. The cw1200_spi driver translates this into irq_disable()/irq_enable() calls instead, which can safely be called in interrupt context. Apparently the platforms I used to develop the cw1200_spi driver used synchronous spi_sync() implementations, which is why this didn't surface until now. Many thanks to Dave Sizeburns for the inital bug report and his services as a tester. Signed-off-by: Solomon Peachy <pizza@shaftnet.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/cw1200')
-rw-r--r--drivers/net/wireless/cw1200/cw1200_spi.c19
-rw-r--r--drivers/net/wireless/cw1200/fwio.c2
-rw-r--r--drivers/net/wireless/cw1200/hwbus.h1
-rw-r--r--drivers/net/wireless/cw1200/hwio.c15
4 files changed, 33 insertions, 4 deletions
diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c
index d06376014bcd..c31580ba883b 100644
--- a/drivers/net/wireless/cw1200/cw1200_spi.c
+++ b/drivers/net/wireless/cw1200/cw1200_spi.c
@@ -41,6 +41,7 @@ struct hwbus_priv {
41 const struct cw1200_platform_data_spi *pdata; 41 const struct cw1200_platform_data_spi *pdata;
42 spinlock_t lock; /* Serialize all bus operations */ 42 spinlock_t lock; /* Serialize all bus operations */
43 int claimed; 43 int claimed;
44 int irq_disabled;
44}; 45};
45 46
46#define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2) 47#define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2)
@@ -230,6 +231,8 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
230 struct hwbus_priv *self = dev_id; 231 struct hwbus_priv *self = dev_id;
231 232
232 if (self->core) { 233 if (self->core) {
234 disable_irq_nosync(self->func->irq);
235 self->irq_disabled = 1;
233 cw1200_irq_handler(self->core); 236 cw1200_irq_handler(self->core);
234 return IRQ_HANDLED; 237 return IRQ_HANDLED;
235 } else { 238 } else {
@@ -263,13 +266,22 @@ exit:
263 266
264static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) 267static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self)
265{ 268{
266 int ret = 0;
267
268 pr_debug("SW IRQ unsubscribe\n"); 269 pr_debug("SW IRQ unsubscribe\n");
269 disable_irq_wake(self->func->irq); 270 disable_irq_wake(self->func->irq);
270 free_irq(self->func->irq, self); 271 free_irq(self->func->irq, self);
271 272
272 return ret; 273 return 0;
274}
275
276static int cw1200_spi_irq_enable(struct hwbus_priv *self, int enable)
277{
278 /* Disables are handled by the interrupt handler */
279 if (enable && self->irq_disabled) {
280 enable_irq(self->func->irq);
281 self->irq_disabled = 0;
282 }
283
284 return 0;
273} 285}
274 286
275static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) 287static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
@@ -349,6 +361,7 @@ static struct hwbus_ops cw1200_spi_hwbus_ops = {
349 .unlock = cw1200_spi_unlock, 361 .unlock = cw1200_spi_unlock,
350 .align_size = cw1200_spi_align_size, 362 .align_size = cw1200_spi_align_size,
351 .power_mgmt = cw1200_spi_pm, 363 .power_mgmt = cw1200_spi_pm,
364 .irq_enable = cw1200_spi_irq_enable,
352}; 365};
353 366
354/* Probe Function to be called by SPI stack when device is discovered */ 367/* Probe Function to be called by SPI stack when device is discovered */
diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c
index acdff0f7f952..0b2061bbc68b 100644
--- a/drivers/net/wireless/cw1200/fwio.c
+++ b/drivers/net/wireless/cw1200/fwio.c
@@ -485,7 +485,7 @@ int cw1200_load_firmware(struct cw1200_common *priv)
485 485
486 /* Enable interrupt signalling */ 486 /* Enable interrupt signalling */
487 priv->hwbus_ops->lock(priv->hwbus_priv); 487 priv->hwbus_ops->lock(priv->hwbus_priv);
488 ret = __cw1200_irq_enable(priv, 1); 488 ret = __cw1200_irq_enable(priv, 2);
489 priv->hwbus_ops->unlock(priv->hwbus_priv); 489 priv->hwbus_ops->unlock(priv->hwbus_priv);
490 if (ret < 0) 490 if (ret < 0)
491 goto unsubscribe; 491 goto unsubscribe;
diff --git a/drivers/net/wireless/cw1200/hwbus.h b/drivers/net/wireless/cw1200/hwbus.h
index 8b2fc831c3de..51dfb3a90735 100644
--- a/drivers/net/wireless/cw1200/hwbus.h
+++ b/drivers/net/wireless/cw1200/hwbus.h
@@ -28,6 +28,7 @@ struct hwbus_ops {
28 void (*unlock)(struct hwbus_priv *self); 28 void (*unlock)(struct hwbus_priv *self);
29 size_t (*align_size)(struct hwbus_priv *self, size_t size); 29 size_t (*align_size)(struct hwbus_priv *self, size_t size);
30 int (*power_mgmt)(struct hwbus_priv *self, bool suspend); 30 int (*power_mgmt)(struct hwbus_priv *self, bool suspend);
31 int (*irq_enable)(struct hwbus_priv *self, int enable);
31}; 32};
32 33
33#endif /* CW1200_HWBUS_H */ 34#endif /* CW1200_HWBUS_H */
diff --git a/drivers/net/wireless/cw1200/hwio.c b/drivers/net/wireless/cw1200/hwio.c
index ff230b7aeedd..41bd7615ccaa 100644
--- a/drivers/net/wireless/cw1200/hwio.c
+++ b/drivers/net/wireless/cw1200/hwio.c
@@ -273,6 +273,21 @@ int __cw1200_irq_enable(struct cw1200_common *priv, int enable)
273 u16 val16; 273 u16 val16;
274 int ret; 274 int ret;
275 275
276 /* We need to do this hack because the SPI layer can sleep on I/O
277 and the general path involves I/O to the device in interrupt
278 context.
279
280 However, the initial enable call needs to go to the hardware.
281
282 We don't worry about shutdown because we do a full reset which
283 clears the interrupt enabled bits.
284 */
285 if (priv->hwbus_ops->irq_enable) {
286 ret = priv->hwbus_ops->irq_enable(priv->hwbus_priv, enable);
287 if (ret || enable < 2)
288 return ret;
289 }
290
276 if (HIF_8601_SILICON == priv->hw_type) { 291 if (HIF_8601_SILICON == priv->hw_type) {
277 ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); 292 ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32);
278 if (ret < 0) { 293 if (ret < 0) {