wl18xx: PG2.0 HW Watch dog interrupt support
authorIdo Reis <idor@ti.com>
Mon, 23 Apr 2012 14:35:25 +0000 (17:35 +0300)
committerLuciano Coelho <coelho@ti.com>
Thu, 7 Jun 2012 15:11:01 +0000 (18:11 +0300)
In PG2, the HW watchdog interrupt occupies bit0 of the event vector, and
the SW watchdog is relocated to bit9. We perform the relocation
globally, as there's only one watchdog bit on previous platforms (bit0).

[Only mask in the new bit9 for platforms supporting it. This avoids
spurious events on other platforms - Arik]

Signed-off-by: Orit Brayer <orit@ti.com>
Signed-off-by: Ido Reis <idor@ti.com>
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/ti/wl12xx/acx.h
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wl18xx/acx.h
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wlcore/acx.h
drivers/net/wireless/ti/wlcore/main.c

index 1be0f2d31b1977cfecbed67491da5cee4fa3a666..2a26868b837d93a131a68bb4a03e55d7e62a2f5a 100644 (file)
 #include "../wlcore/wlcore.h"
 #include "../wlcore/acx.h"
 
+#define WL12XX_ACX_ALL_EVENTS_VECTOR   (WL1271_ACX_INTR_WATCHDOG      | \
+                                       WL1271_ACX_INTR_INIT_COMPLETE | \
+                                       WL1271_ACX_INTR_EVENT_A       | \
+                                       WL1271_ACX_INTR_EVENT_B       | \
+                                       WL1271_ACX_INTR_CMD_COMPLETE  | \
+                                       WL1271_ACX_INTR_HW_AVAILABLE  | \
+                                       WL1271_ACX_INTR_DATA)
+
+#define WL12XX_INTR_MASK               (WL1271_ACX_INTR_WATCHDOG      | \
+                                       WL1271_ACX_INTR_EVENT_A       | \
+                                       WL1271_ACX_INTR_EVENT_B       | \
+                                       WL1271_ACX_INTR_HW_AVAILABLE  | \
+                                       WL1271_ACX_INTR_DATA)
+
 struct wl1271_acx_host_config_bitmap {
        struct acx_header header;
 
index 41017baaf25301e9c769c4704da4652673397e7c..f74d76c95a7f590d821d70335f858b66c0675c03 100644 (file)
@@ -1034,11 +1034,11 @@ static void wl12xx_pre_upload(struct wl1271 *wl)
 
 static void wl12xx_enable_interrupts(struct wl1271 *wl)
 {
-       wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR);
+       wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL12XX_ACX_ALL_EVENTS_VECTOR);
 
        wlcore_enable_interrupts(wl);
        wlcore_write_reg(wl, REG_INTERRUPT_MASK,
-                        WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
+                        WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
 
        wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
 }
index cb6fd85d077f1e71639c6bd1de2c36859094f888..7d74b031f1145500808a9064af37653d694f49d5 100644 (file)
 /* numbers of bits the length field takes (add 1 for the actual number) */
 #define WL18XX_HOST_IF_LEN_SIZE_FIELD 15
 
+#define WL18XX_ACX_EVENTS_VECTOR_PG1   (WL1271_ACX_INTR_WATCHDOG      | \
+                                       WL1271_ACX_INTR_INIT_COMPLETE | \
+                                       WL1271_ACX_INTR_EVENT_A       | \
+                                       WL1271_ACX_INTR_EVENT_B       | \
+                                       WL1271_ACX_INTR_CMD_COMPLETE  | \
+                                       WL1271_ACX_INTR_HW_AVAILABLE  | \
+                                       WL1271_ACX_INTR_DATA)
+
+#define WL18XX_ACX_EVENTS_VECTOR_PG2   (WL18XX_ACX_EVENTS_VECTOR_PG1 | \
+                                       WL1271_ACX_SW_INTR_WATCHDOG)
+
+#define WL18XX_INTR_MASK_PG1           (WL1271_ACX_INTR_WATCHDOG      | \
+                                       WL1271_ACX_INTR_EVENT_A       | \
+                                       WL1271_ACX_INTR_EVENT_B       | \
+                                       WL1271_ACX_INTR_HW_AVAILABLE  | \
+                                       WL1271_ACX_INTR_DATA)
+
+#define WL18XX_INTR_MASK_PG2           (WL18XX_INTR_MASK_PG1         | \
+                                       WL1271_ACX_SW_INTR_WATCHDOG)
+
 struct wl18xx_acx_host_config_bitmap {
        struct acx_header header;
 
index bdf4ee12914d6e4c8a4d42ca33194446823cd942..84f8e27c29ab5e43ed6c751c9da43b7a8e7447cb 100644 (file)
@@ -776,11 +776,21 @@ static void wl18xx_set_mac_and_phy(struct wl1271 *wl)
 
 static void wl18xx_enable_interrupts(struct wl1271 *wl)
 {
-       wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR);
+       u32 event_mask, intr_mask;
+
+       if (wl->chip.id == CHIP_ID_185x_PG10) {
+               event_mask = WL18XX_ACX_EVENTS_VECTOR_PG1;
+               intr_mask = WL18XX_INTR_MASK_PG1;
+       } else {
+               event_mask = WL18XX_ACX_EVENTS_VECTOR_PG2;
+               intr_mask = WL18XX_INTR_MASK_PG2;
+       }
+
+       wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask);
 
        wlcore_enable_interrupts(wl);
        wlcore_write_reg(wl, REG_INTERRUPT_MASK,
-                        WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
+                        WL1271_ACX_INTR_ALL & ~intr_mask);
 }
 
 static int wl18xx_boot(struct wl1271 *wl)
index 46c300d4dea48e3039ea20df684949b0eb323fda..c0181258b7227e09d1ae00a058788baa8450e08a 100644 (file)
 #define WL1271_ACX_INTR_TRACE_A            BIT(7)
 /* Trace message on MBOX #B */
 #define WL1271_ACX_INTR_TRACE_B            BIT(8)
-
-#define WL1271_ACX_INTR_ALL               0xFFFFFFFF
-#define WL1271_ACX_ALL_EVENTS_VECTOR       (WL1271_ACX_INTR_WATCHDOG      | \
-                                           WL1271_ACX_INTR_INIT_COMPLETE | \
-                                           WL1271_ACX_INTR_EVENT_A       | \
-                                           WL1271_ACX_INTR_EVENT_B       | \
-                                           WL1271_ACX_INTR_CMD_COMPLETE  | \
-                                           WL1271_ACX_INTR_HW_AVAILABLE  | \
-                                           WL1271_ACX_INTR_DATA)
-
-#define WL1271_INTR_MASK                   (WL1271_ACX_INTR_WATCHDOG     | \
-                                           WL1271_ACX_INTR_EVENT_A      | \
-                                           WL1271_ACX_INTR_EVENT_B      | \
-                                           WL1271_ACX_INTR_HW_AVAILABLE | \
-                                           WL1271_ACX_INTR_DATA)
+/* SW FW Initiated interrupt Watchdog timer expiration */
+#define WL1271_ACX_SW_INTR_WATCHDOG        BIT(9)
+
+#define WL1271_ACX_INTR_ALL             0xFFFFFFFF
+
+/* all possible interrupts - only appropriate ones will be masked in */
+#define WLCORE_ALL_INTR_MASK           (WL1271_ACX_INTR_WATCHDOG     | \
+                                       WL1271_ACX_INTR_EVENT_A       | \
+                                       WL1271_ACX_INTR_EVENT_B       | \
+                                       WL1271_ACX_INTR_HW_AVAILABLE  | \
+                                       WL1271_ACX_INTR_DATA          | \
+                                       WL1271_ACX_SW_INTR_WATCHDOG)
 
 /* Target's information element */
 struct acx_header {
index 8800a63539e33dde72a05d03fe4980e483f3712e..176a3117889b0cf85aa1c5e4bcb068eab25d5c22 100644 (file)
@@ -535,14 +535,23 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
                wlcore_hw_tx_immediate_compl(wl);
 
                intr = le32_to_cpu(wl->fw_status_1->intr);
-               intr &= WL1271_INTR_MASK;
+               intr &= WLCORE_ALL_INTR_MASK;
                if (!intr) {
                        done = true;
                        continue;
                }
 
                if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
-                       wl1271_error("watchdog interrupt received! "
+                       wl1271_error("HW watchdog interrupt received! starting recovery.");
+                       wl->watchdog_recovery = true;
+                       wl12xx_queue_recovery_work(wl);
+
+                       /* restarting the chip. ignore any other interrupt. */
+                       goto out;
+               }
+
+               if (unlikely(intr & WL1271_ACX_SW_INTR_WATCHDOG)) {
+                       wl1271_error("SW watchdog interrupt received! "
                                     "starting recovery.");
                        wl->watchdog_recovery = true;
                        wl12xx_queue_recovery_work(wl);