aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorIdo Yariv <ido@wizery.com>2011-03-31 04:07:01 -0400
committerLuciano Coelho <coelho@ti.com>2011-04-19 09:49:20 -0400
commit341b7cde6ccc60672fcd7fc84dd24a1b7c0b8d94 (patch)
tree25b284f436f24a0c21e4a656531831619002757c /drivers/net
parentd2f4d47d84f8c665ab9babb2cc84d2e7872a96e1 (diff)
wl12xx: Handle platforms without level trigger interrupts
Some platforms are incapable of triggering on level interrupts. Add a platform quirks member in the platform data structure, as well as an edge interrupt quirk which can be set on such platforms. When the interrupt is requested with IRQF_TRIGGER_RISING, IRQF_ONESHOT cannot be used, as we might miss interrupts that occur after the FW status is cleared and before the threaded interrupt handler exits. Moreover, when IRQF_ONESHOT is not set, iterating more than once in the threaded interrupt handler introduces a few race conditions between this handler and the hardirq handler. Currently this is worked around by limiting the loop to one iteration only. This workaround has an impact on performance. To remove to this restriction, the race conditions will need to be addressed. Signed-off-by: Ido Yariv <ido@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/wl12xx/main.c9
-rw-r--r--drivers/net/wireless/wl12xx/sdio.c9
-rw-r--r--drivers/net/wireless/wl12xx/spi.c9
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h3
4 files changed, 28 insertions, 2 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 1feb9551ef8f..7126506611c1 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -30,6 +30,7 @@
30#include <linux/vmalloc.h> 30#include <linux/vmalloc.h>
31#include <linux/platform_device.h> 31#include <linux/platform_device.h>
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <linux/wl12xx.h>
33 34
34#include "wl12xx.h" 35#include "wl12xx.h"
35#include "wl12xx_80211.h" 36#include "wl12xx_80211.h"
@@ -719,6 +720,13 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
719 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); 720 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
720 cancel_work_sync(&wl->tx_work); 721 cancel_work_sync(&wl->tx_work);
721 722
723 /*
724 * In case edge triggered interrupt must be used, we cannot iterate
725 * more than once without introducing race conditions with the hardirq.
726 */
727 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
728 loopcount = 1;
729
722 mutex_lock(&wl->mutex); 730 mutex_lock(&wl->mutex);
723 731
724 wl1271_debug(DEBUG_IRQ, "IRQ work"); 732 wl1271_debug(DEBUG_IRQ, "IRQ work");
@@ -3648,6 +3656,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
3648 wl->ap_ps_map = 0; 3656 wl->ap_ps_map = 0;
3649 wl->ap_fw_ps_map = 0; 3657 wl->ap_fw_ps_map = 0;
3650 wl->quirks = 0; 3658 wl->quirks = 0;
3659 wl->platform_quirks = 0;
3651 3660
3652 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); 3661 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
3653 for (i = 0; i < ACX_TX_DESCRIPTORS; i++) 3662 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 8246e9de4306..bcd4ad7ba90d 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -220,6 +220,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
220 struct ieee80211_hw *hw; 220 struct ieee80211_hw *hw;
221 const struct wl12xx_platform_data *wlan_data; 221 const struct wl12xx_platform_data *wlan_data;
222 struct wl1271 *wl; 222 struct wl1271 *wl;
223 unsigned long irqflags;
223 int ret; 224 int ret;
224 225
225 /* We are only able to handle the wlan function */ 226 /* We are only able to handle the wlan function */
@@ -251,9 +252,15 @@ static int __devinit wl1271_probe(struct sdio_func *func,
251 wl->irq = wlan_data->irq; 252 wl->irq = wlan_data->irq;
252 wl->ref_clock = wlan_data->board_ref_clock; 253 wl->ref_clock = wlan_data->board_ref_clock;
253 wl->tcxo_clock = wlan_data->board_tcxo_clock; 254 wl->tcxo_clock = wlan_data->board_tcxo_clock;
255 wl->platform_quirks = wlan_data->platform_quirks;
256
257 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
258 irqflags = IRQF_TRIGGER_RISING;
259 else
260 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
254 261
255 ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, 262 ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
256 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 263 irqflags,
257 DRIVER_NAME, wl); 264 DRIVER_NAME, wl);
258 if (ret < 0) { 265 if (ret < 0) {
259 wl1271_error("request_irq() failed: %d", ret); 266 wl1271_error("request_irq() failed: %d", ret);
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index 7b82b5f0e490..51662bb68019 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -364,6 +364,7 @@ static int __devinit wl1271_probe(struct spi_device *spi)
364 struct wl12xx_platform_data *pdata; 364 struct wl12xx_platform_data *pdata;
365 struct ieee80211_hw *hw; 365 struct ieee80211_hw *hw;
366 struct wl1271 *wl; 366 struct wl1271 *wl;
367 unsigned long irqflags;
367 int ret; 368 int ret;
368 369
369 pdata = spi->dev.platform_data; 370 pdata = spi->dev.platform_data;
@@ -402,6 +403,12 @@ static int __devinit wl1271_probe(struct spi_device *spi)
402 403
403 wl->ref_clock = pdata->board_ref_clock; 404 wl->ref_clock = pdata->board_ref_clock;
404 wl->tcxo_clock = pdata->board_tcxo_clock; 405 wl->tcxo_clock = pdata->board_tcxo_clock;
406 wl->platform_quirks = pdata->platform_quirks;
407
408 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
409 irqflags = IRQF_TRIGGER_RISING;
410 else
411 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
405 412
406 wl->irq = spi->irq; 413 wl->irq = spi->irq;
407 if (wl->irq < 0) { 414 if (wl->irq < 0) {
@@ -411,7 +418,7 @@ static int __devinit wl1271_probe(struct spi_device *spi)
411 } 418 }
412 419
413 ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, 420 ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
414 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 421 irqflags,
415 DRIVER_NAME, wl); 422 DRIVER_NAME, wl);
416 if (ret < 0) { 423 if (ret < 0) {
417 wl1271_error("request_irq() failed: %d", ret); 424 wl1271_error("request_irq() failed: %d", ret);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 9ccbcfdd0802..fb2b79fa42b4 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -579,6 +579,9 @@ struct wl1271 {
579 579
580 /* Quirks of specific hardware revisions */ 580 /* Quirks of specific hardware revisions */
581 unsigned int quirks; 581 unsigned int quirks;
582
583 /* Platform limitations */
584 unsigned int platform_quirks;
582}; 585};
583 586
584struct wl1271_station { 587struct wl1271_station {