isdn: hisax/elsa: fix sleep_on race in elsa FSM
authorArnd Bergmann <arnd@arndb.de>
Wed, 26 Feb 2014 11:01:53 +0000 (12:01 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 26 Feb 2014 21:06:13 +0000 (16:06 -0500)
The state machine code in the elsa driver uses interruptible_sleep_on
to wait for state changes, which is racy. A closer look at the possible
states reveals that it is always used to wait for getting back into
ARCOFI_NOP, so we can use wait_event_interruptible instead.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Karsten Keil <isdn@linux-pingi.de>
Cc: netdev@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/elsa_ser.c

index 2be1c8a3bb5f2b7fd84f0d3cd039fb8dc5da3dd0..d8ef64da26f1fe6e0a25c5515401079ed19ff3cb 100644 (file)
@@ -509,7 +509,8 @@ static void
 set_arcofi(struct IsdnCardState *cs, int bc) {
        cs->dc.isac.arcofi_bc = bc;
        arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5);
-       interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+       wait_event_interruptible(cs->dc.isac.arcofi_wait,
+                                cs->dc.isac.arcofi_state == ARCOFI_NOP);
 }
 
 static int
@@ -528,7 +529,8 @@ check_arcofi(struct IsdnCardState *cs)
                }
        cs->dc.isac.arcofi_bc = 0;
        arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION);
-       interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+       wait_event_interruptible(cs->dc.isac.arcofi_wait,
+                                cs->dc.isac.arcofi_state == ARCOFI_NOP);
        if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) {
                debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp);
                p = cs->dc.isac.mon_rx;
@@ -595,7 +597,8 @@ check_arcofi(struct IsdnCardState *cs)
                               Elsa_Types[cs->subtyp],
                               cs->hw.elsa.base + 8);
                arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0);
-               interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+               wait_event_interruptible(cs->dc.isac.arcofi_wait,
+                                cs->dc.isac.arcofi_state == ARCOFI_NOP);
                return (1);
        }
        return (0);
index 3f84dd8f1757d8b645af7bf6b3088b7ce084d320..a2a358c1dc8e59fe5b69f99891c8d3130717df8b 100644 (file)
@@ -573,7 +573,8 @@ modem_l2l1(struct PStack *st, int pr, void *arg)
                test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
                bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
                arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
-               interruptible_sleep_on(&bcs->cs->dc.isac.arcofi_wait);
+               wait_event_interruptible(bcs->cs->dc.isac.arcofi_wait,
+                                bcs->cs->dc.isac.arcofi_state == ARCOFI_NOP);
                bcs->cs->hw.elsa.MFlag = 1;
        } else {
                printk(KERN_WARNING "ElsaSer: unknown pr %x\n", pr);