diff options
author | Tilman Schmidt <tilman@imap.cc> | 2006-04-11 01:55:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-11 09:18:50 -0400 |
commit | 69049cc87dccb1e6fb54aa25c63033efac805dbd (patch) | |
tree | 9db1953a831091335b98f8749865f4c8b410ff9b /drivers/isdn/gigaset/ev-layer.c | |
parent | 27d1ac2ef7d0b9250ca9fd2ef506e12866ce8fdf (diff) |
[PATCH] isdn4linux: Siemens Gigaset drivers: make some variables non-atomic
With Hansjoerg Lipp <hjlipp@web.de>
Replace some atomic_t variables in the Gigaset drivers by non-atomic ones,
using spinlocks instead to assure atomicity, as proposed in discussions on the
linux-kernel mailing list.
Signed-off-by: Hansjoerg Lipp <hjlipp@web.de>
Signed-off-by: Tilman Schmidt <tilman@imap.cc>
Cc: Karsten Keil <kkeil@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/isdn/gigaset/ev-layer.c')
-rw-r--r-- | drivers/isdn/gigaset/ev-layer.c | 87 |
1 files changed, 57 insertions, 30 deletions
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 2e826d051c85..1ba3424a286b 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c | |||
@@ -482,14 +482,6 @@ static int isdn_gethex(char *p) | |||
482 | return v; | 482 | return v; |
483 | } | 483 | } |
484 | 484 | ||
485 | static inline void new_index(atomic_t *index, int max) | ||
486 | { | ||
487 | if (atomic_read(index) == max) //FIXME race? | ||
488 | atomic_set(index, 0); | ||
489 | else | ||
490 | atomic_inc(index); | ||
491 | } | ||
492 | |||
493 | /* retrieve CID from parsed response | 485 | /* retrieve CID from parsed response |
494 | * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535 | 486 | * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535 |
495 | */ | 487 | */ |
@@ -581,8 +573,8 @@ void gigaset_handle_modem_response(struct cardstate *cs) | |||
581 | } | 573 | } |
582 | 574 | ||
583 | spin_lock_irqsave(&cs->ev_lock, flags); | 575 | spin_lock_irqsave(&cs->ev_lock, flags); |
584 | head = atomic_read(&cs->ev_head); | 576 | head = cs->ev_head; |
585 | tail = atomic_read(&cs->ev_tail); | 577 | tail = cs->ev_tail; |
586 | 578 | ||
587 | abort = 1; | 579 | abort = 1; |
588 | curarg = 0; | 580 | curarg = 0; |
@@ -715,7 +707,7 @@ void gigaset_handle_modem_response(struct cardstate *cs) | |||
715 | break; | 707 | break; |
716 | } | 708 | } |
717 | 709 | ||
718 | atomic_set(&cs->ev_tail, tail); | 710 | cs->ev_tail = tail; |
719 | spin_unlock_irqrestore(&cs->ev_lock, flags); | 711 | spin_unlock_irqrestore(&cs->ev_lock, flags); |
720 | 712 | ||
721 | if (curarg != params) | 713 | if (curarg != params) |
@@ -734,14 +726,16 @@ static void disconnect(struct at_state_t **at_state_p) | |||
734 | struct bc_state *bcs = (*at_state_p)->bcs; | 726 | struct bc_state *bcs = (*at_state_p)->bcs; |
735 | struct cardstate *cs = (*at_state_p)->cs; | 727 | struct cardstate *cs = (*at_state_p)->cs; |
736 | 728 | ||
737 | new_index(&(*at_state_p)->seq_index, MAX_SEQ_INDEX); | 729 | spin_lock_irqsave(&cs->lock, flags); |
730 | ++(*at_state_p)->seq_index; | ||
738 | 731 | ||
739 | /* revert to selected idle mode */ | 732 | /* revert to selected idle mode */ |
740 | if (!atomic_read(&cs->cidmode)) { | 733 | if (!cs->cidmode) { |
741 | cs->at_state.pending_commands |= PC_UMMODE; | 734 | cs->at_state.pending_commands |= PC_UMMODE; |
742 | atomic_set(&cs->commands_pending, 1); //FIXME | 735 | atomic_set(&cs->commands_pending, 1); //FIXME |
743 | gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); | 736 | gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); |
744 | } | 737 | } |
738 | spin_unlock_irqrestore(&cs->lock, flags); | ||
745 | 739 | ||
746 | if (bcs) { | 740 | if (bcs) { |
747 | /* B channel assigned: invoke hardware specific handler */ | 741 | /* B channel assigned: invoke hardware specific handler */ |
@@ -933,17 +927,21 @@ static void bchannel_up(struct bc_state *bcs) | |||
933 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN); | 927 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN); |
934 | } | 928 | } |
935 | 929 | ||
936 | static void start_dial(struct at_state_t *at_state, void *data, int seq_index) | 930 | static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_index) |
937 | { | 931 | { |
938 | struct bc_state *bcs = at_state->bcs; | 932 | struct bc_state *bcs = at_state->bcs; |
939 | struct cardstate *cs = at_state->cs; | 933 | struct cardstate *cs = at_state->cs; |
940 | int retval; | 934 | int retval; |
935 | unsigned long flags; | ||
941 | 936 | ||
942 | bcs->chstate |= CHS_NOTIFY_LL; | 937 | bcs->chstate |= CHS_NOTIFY_LL; |
943 | //atomic_set(&bcs->status, BCS_INIT); | ||
944 | 938 | ||
945 | if (atomic_read(&at_state->seq_index) != seq_index) | 939 | spin_lock_irqsave(&cs->lock, flags); |
940 | if (at_state->seq_index != seq_index) { | ||
941 | spin_unlock_irqrestore(&cs->lock, flags); | ||
946 | goto error; | 942 | goto error; |
943 | } | ||
944 | spin_unlock_irqrestore(&cs->lock, flags); | ||
947 | 945 | ||
948 | retval = gigaset_isdn_setup_dial(at_state, data); | 946 | retval = gigaset_isdn_setup_dial(at_state, data); |
949 | if (retval != 0) | 947 | if (retval != 0) |
@@ -988,6 +986,7 @@ static void do_start(struct cardstate *cs) | |||
988 | if (atomic_read(&cs->mstate) != MS_LOCKED) | 986 | if (atomic_read(&cs->mstate) != MS_LOCKED) |
989 | schedule_init(cs, MS_INIT); | 987 | schedule_init(cs, MS_INIT); |
990 | 988 | ||
989 | cs->isdn_up = 1; | ||
991 | gigaset_i4l_cmd(cs, ISDN_STAT_RUN); | 990 | gigaset_i4l_cmd(cs, ISDN_STAT_RUN); |
992 | // FIXME: not in locked mode | 991 | // FIXME: not in locked mode |
993 | // FIXME 2: only after init sequence | 992 | // FIXME 2: only after init sequence |
@@ -1003,6 +1002,12 @@ static void finish_shutdown(struct cardstate *cs) | |||
1003 | atomic_set(&cs->mode, M_UNKNOWN); | 1002 | atomic_set(&cs->mode, M_UNKNOWN); |
1004 | } | 1003 | } |
1005 | 1004 | ||
1005 | /* Tell the LL that the device is not available .. */ | ||
1006 | if (cs->isdn_up) { | ||
1007 | cs->isdn_up = 0; | ||
1008 | gigaset_i4l_cmd(cs, ISDN_STAT_STOP); | ||
1009 | } | ||
1010 | |||
1006 | /* The rest is done by cleanup_cs () in user mode. */ | 1011 | /* The rest is done by cleanup_cs () in user mode. */ |
1007 | 1012 | ||
1008 | cs->cmd_result = -ENODEV; | 1013 | cs->cmd_result = -ENODEV; |
@@ -1025,6 +1030,12 @@ static void do_shutdown(struct cardstate *cs) | |||
1025 | 1030 | ||
1026 | static void do_stop(struct cardstate *cs) | 1031 | static void do_stop(struct cardstate *cs) |
1027 | { | 1032 | { |
1033 | unsigned long flags; | ||
1034 | |||
1035 | spin_lock_irqsave(&cs->lock, flags); | ||
1036 | cs->connected = 0; | ||
1037 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1038 | |||
1028 | do_shutdown(cs); | 1039 | do_shutdown(cs); |
1029 | } | 1040 | } |
1030 | 1041 | ||
@@ -1153,7 +1164,7 @@ static int do_unlock(struct cardstate *cs) | |||
1153 | atomic_set(&cs->mstate, MS_UNINITIALIZED); | 1164 | atomic_set(&cs->mstate, MS_UNINITIALIZED); |
1154 | atomic_set(&cs->mode, M_UNKNOWN); | 1165 | atomic_set(&cs->mode, M_UNKNOWN); |
1155 | gigaset_free_channels(cs); | 1166 | gigaset_free_channels(cs); |
1156 | if (atomic_read(&cs->connected)) | 1167 | if (cs->connected) |
1157 | schedule_init(cs, MS_INIT); | 1168 | schedule_init(cs, MS_INIT); |
1158 | 1169 | ||
1159 | return 0; | 1170 | return 0; |
@@ -1185,11 +1196,14 @@ static void do_action(int action, struct cardstate *cs, | |||
1185 | cs->at_state.pending_commands &= ~PC_INIT; | 1196 | cs->at_state.pending_commands &= ~PC_INIT; |
1186 | cs->cur_at_seq = SEQ_NONE; | 1197 | cs->cur_at_seq = SEQ_NONE; |
1187 | atomic_set(&cs->mode, M_UNIMODEM); | 1198 | atomic_set(&cs->mode, M_UNIMODEM); |
1188 | if (!atomic_read(&cs->cidmode)) { | 1199 | spin_lock_irqsave(&cs->lock, flags); |
1200 | if (!cs->cidmode) { | ||
1201 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1189 | gigaset_free_channels(cs); | 1202 | gigaset_free_channels(cs); |
1190 | atomic_set(&cs->mstate, MS_READY); | 1203 | atomic_set(&cs->mstate, MS_READY); |
1191 | break; | 1204 | break; |
1192 | } | 1205 | } |
1206 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1193 | cs->at_state.pending_commands |= PC_CIDMODE; | 1207 | cs->at_state.pending_commands |= PC_CIDMODE; |
1194 | atomic_set(&cs->commands_pending, 1); | 1208 | atomic_set(&cs->commands_pending, 1); |
1195 | gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); | 1209 | gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); |
@@ -1536,8 +1550,9 @@ static void do_action(int action, struct cardstate *cs, | |||
1536 | 1550 | ||
1537 | /* events from the proc file system */ // FIXME without ACT_xxxx? | 1551 | /* events from the proc file system */ // FIXME without ACT_xxxx? |
1538 | case ACT_PROC_CIDMODE: | 1552 | case ACT_PROC_CIDMODE: |
1539 | if (ev->parameter != atomic_read(&cs->cidmode)) { | 1553 | spin_lock_irqsave(&cs->lock, flags); |
1540 | atomic_set(&cs->cidmode, ev->parameter); | 1554 | if (ev->parameter != cs->cidmode) { |
1555 | cs->cidmode = ev->parameter; | ||
1541 | if (ev->parameter) { | 1556 | if (ev->parameter) { |
1542 | cs->at_state.pending_commands |= PC_CIDMODE; | 1557 | cs->at_state.pending_commands |= PC_CIDMODE; |
1543 | gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); | 1558 | gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); |
@@ -1547,6 +1562,7 @@ static void do_action(int action, struct cardstate *cs, | |||
1547 | } | 1562 | } |
1548 | atomic_set(&cs->commands_pending, 1); | 1563 | atomic_set(&cs->commands_pending, 1); |
1549 | } | 1564 | } |
1565 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1550 | cs->waiting = 0; | 1566 | cs->waiting = 0; |
1551 | wake_up(&cs->waitqueue); | 1567 | wake_up(&cs->waitqueue); |
1552 | break; | 1568 | break; |
@@ -1615,8 +1631,9 @@ static void process_event(struct cardstate *cs, struct event_t *ev) | |||
1615 | /* Setting the pointer to the dial array */ | 1631 | /* Setting the pointer to the dial array */ |
1616 | rep = at_state->replystruct; | 1632 | rep = at_state->replystruct; |
1617 | 1633 | ||
1634 | spin_lock_irqsave(&cs->lock, flags); | ||
1618 | if (ev->type == EV_TIMEOUT) { | 1635 | if (ev->type == EV_TIMEOUT) { |
1619 | if (ev->parameter != atomic_read(&at_state->timer_index) | 1636 | if (ev->parameter != at_state->timer_index |
1620 | || !at_state->timer_active) { | 1637 | || !at_state->timer_active) { |
1621 | ev->type = RSP_NONE; /* old timeout */ | 1638 | ev->type = RSP_NONE; /* old timeout */ |
1622 | gig_dbg(DEBUG_ANY, "old timeout"); | 1639 | gig_dbg(DEBUG_ANY, "old timeout"); |
@@ -1625,6 +1642,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev) | |||
1625 | else | 1642 | else |
1626 | gig_dbg(DEBUG_ANY, "stopped waiting"); | 1643 | gig_dbg(DEBUG_ANY, "stopped waiting"); |
1627 | } | 1644 | } |
1645 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1628 | 1646 | ||
1629 | /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] | 1647 | /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] |
1630 | or at_state->str_var[STR_XXXX], set it */ | 1648 | or at_state->str_var[STR_XXXX], set it */ |
@@ -1686,7 +1704,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev) | |||
1686 | } else { | 1704 | } else { |
1687 | /* Send command to modem if not NULL... */ | 1705 | /* Send command to modem if not NULL... */ |
1688 | if (p_command/*rep->command*/) { | 1706 | if (p_command/*rep->command*/) { |
1689 | if (atomic_read(&cs->connected)) | 1707 | if (cs->connected) |
1690 | send_command(cs, p_command, | 1708 | send_command(cs, p_command, |
1691 | sendcid, cs->dle, | 1709 | sendcid, cs->dle, |
1692 | GFP_ATOMIC); | 1710 | GFP_ATOMIC); |
@@ -1703,8 +1721,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev) | |||
1703 | } else if (rep->timeout > 0) { /* new timeout */ | 1721 | } else if (rep->timeout > 0) { /* new timeout */ |
1704 | at_state->timer_expires = rep->timeout * 10; | 1722 | at_state->timer_expires = rep->timeout * 10; |
1705 | at_state->timer_active = 1; | 1723 | at_state->timer_active = 1; |
1706 | new_index(&at_state->timer_index, | 1724 | ++at_state->timer_index; |
1707 | MAX_TIMER_INDEX); | ||
1708 | } | 1725 | } |
1709 | spin_unlock_irqrestore(&cs->lock, flags); | 1726 | spin_unlock_irqrestore(&cs->lock, flags); |
1710 | } | 1727 | } |
@@ -1724,6 +1741,7 @@ static void process_command_flags(struct cardstate *cs) | |||
1724 | struct bc_state *bcs; | 1741 | struct bc_state *bcs; |
1725 | int i; | 1742 | int i; |
1726 | int sequence; | 1743 | int sequence; |
1744 | unsigned long flags; | ||
1727 | 1745 | ||
1728 | atomic_set(&cs->commands_pending, 0); | 1746 | atomic_set(&cs->commands_pending, 0); |
1729 | 1747 | ||
@@ -1773,8 +1791,9 @@ static void process_command_flags(struct cardstate *cs) | |||
1773 | } | 1791 | } |
1774 | 1792 | ||
1775 | /* only switch back to unimodem mode, if no commands are pending and no channels are up */ | 1793 | /* only switch back to unimodem mode, if no commands are pending and no channels are up */ |
1794 | spin_lock_irqsave(&cs->lock, flags); | ||
1776 | if (cs->at_state.pending_commands == PC_UMMODE | 1795 | if (cs->at_state.pending_commands == PC_UMMODE |
1777 | && !atomic_read(&cs->cidmode) | 1796 | && !cs->cidmode |
1778 | && list_empty(&cs->temp_at_states) | 1797 | && list_empty(&cs->temp_at_states) |
1779 | && atomic_read(&cs->mode) == M_CID) { | 1798 | && atomic_read(&cs->mode) == M_CID) { |
1780 | sequence = SEQ_UMMODE; | 1799 | sequence = SEQ_UMMODE; |
@@ -1788,6 +1807,7 @@ static void process_command_flags(struct cardstate *cs) | |||
1788 | } | 1807 | } |
1789 | } | 1808 | } |
1790 | } | 1809 | } |
1810 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1791 | cs->at_state.pending_commands &= ~PC_UMMODE; | 1811 | cs->at_state.pending_commands &= ~PC_UMMODE; |
1792 | if (sequence != SEQ_NONE) { | 1812 | if (sequence != SEQ_NONE) { |
1793 | schedule_sequence(cs, at_state, sequence); | 1813 | schedule_sequence(cs, at_state, sequence); |
@@ -1900,18 +1920,21 @@ static void process_events(struct cardstate *cs) | |||
1900 | int i; | 1920 | int i; |
1901 | int check_flags = 0; | 1921 | int check_flags = 0; |
1902 | int was_busy; | 1922 | int was_busy; |
1923 | unsigned long flags; | ||
1903 | 1924 | ||
1904 | /* no locking needed (only one reader) */ | 1925 | spin_lock_irqsave(&cs->ev_lock, flags); |
1905 | head = atomic_read(&cs->ev_head); | 1926 | head = cs->ev_head; |
1906 | 1927 | ||
1907 | for (i = 0; i < 2 * MAX_EVENTS; ++i) { | 1928 | for (i = 0; i < 2 * MAX_EVENTS; ++i) { |
1908 | tail = atomic_read(&cs->ev_tail); | 1929 | tail = cs->ev_tail; |
1909 | if (tail == head) { | 1930 | if (tail == head) { |
1910 | if (!check_flags && !atomic_read(&cs->commands_pending)) | 1931 | if (!check_flags && !atomic_read(&cs->commands_pending)) |
1911 | break; | 1932 | break; |
1912 | check_flags = 0; | 1933 | check_flags = 0; |
1934 | spin_unlock_irqrestore(&cs->ev_lock, flags); | ||
1913 | process_command_flags(cs); | 1935 | process_command_flags(cs); |
1914 | tail = atomic_read(&cs->ev_tail); | 1936 | spin_lock_irqsave(&cs->ev_lock, flags); |
1937 | tail = cs->ev_tail; | ||
1915 | if (tail == head) { | 1938 | if (tail == head) { |
1916 | if (!atomic_read(&cs->commands_pending)) | 1939 | if (!atomic_read(&cs->commands_pending)) |
1917 | break; | 1940 | break; |
@@ -1921,16 +1944,20 @@ static void process_events(struct cardstate *cs) | |||
1921 | 1944 | ||
1922 | ev = cs->events + head; | 1945 | ev = cs->events + head; |
1923 | was_busy = cs->cur_at_seq != SEQ_NONE; | 1946 | was_busy = cs->cur_at_seq != SEQ_NONE; |
1947 | spin_unlock_irqrestore(&cs->ev_lock, flags); | ||
1924 | process_event(cs, ev); | 1948 | process_event(cs, ev); |
1949 | spin_lock_irqsave(&cs->ev_lock, flags); | ||
1925 | kfree(ev->ptr); | 1950 | kfree(ev->ptr); |
1926 | ev->ptr = NULL; | 1951 | ev->ptr = NULL; |
1927 | if (was_busy && cs->cur_at_seq == SEQ_NONE) | 1952 | if (was_busy && cs->cur_at_seq == SEQ_NONE) |
1928 | check_flags = 1; | 1953 | check_flags = 1; |
1929 | 1954 | ||
1930 | head = (head + 1) % MAX_EVENTS; | 1955 | head = (head + 1) % MAX_EVENTS; |
1931 | atomic_set(&cs->ev_head, head); | 1956 | cs->ev_head = head; |
1932 | } | 1957 | } |
1933 | 1958 | ||
1959 | spin_unlock_irqrestore(&cs->ev_lock, flags); | ||
1960 | |||
1934 | if (i == 2 * MAX_EVENTS) { | 1961 | if (i == 2 * MAX_EVENTS) { |
1935 | dev_err(cs->dev, | 1962 | dev_err(cs->dev, |
1936 | "infinite loop in process_events; aborting.\n"); | 1963 | "infinite loop in process_events; aborting.\n"); |