aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2014-11-12 00:12:08 -0500
committerChristoph Hellwig <hch@lst.de>2014-11-20 03:11:13 -0500
commit16b29e75a78ae03250233468b68f7ae467d3dc7a (patch)
treea5ba9e016d5557d2a6f5fb60dc83ae906ae771af /arch/m68k
parentcbad48deb38d8e442db9760ca1f950cd24429707 (diff)
atari_scsi: Fix atari_scsi deadlocks on Falcon
Don't disable irqs when waiting for the ST DMA "lock"; its release may require an interrupt. Introduce stdma_try_lock() for use in soft irq context. atari_scsi now tells the SCSI mid-layer to defer queueing a command if the ST DMA lock is not available, as per Michael's patch: http://marc.info/?l=linux-m68k&m=139095335824863&w=2 The falcon_got_lock variable is race prone: we can't disable IRQs while waiting to acquire the lock, so after acquiring it there must be some interval during which falcon_got_lock remains false. Introduce stdma_is_locked_by() to replace falcon_got_lock. The falcon_got_lock tests in the EH handlers are incorrect these days. It can happen that an EH handler is called after a command completes normally. Remove these checks along with falcon_got_lock. Also remove the complicated and racy fairness wait queues. If fairness is an issue (when SCSI competes with IDE for the ST DMA interrupt), the solution is likely to be a lower value for host->can_queue. Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Reviewed-by: Hannes Reinecke <hare@suse.de> Tested-by: Michael Schmitz <schmitzmic@gmail.com> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'arch/m68k')
-rw-r--r--arch/m68k/atari/stdma.c61
-rw-r--r--arch/m68k/include/asm/atari_stdma.h4
2 files changed, 42 insertions, 23 deletions
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index ddbf43ca8858..e5a66596b116 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -59,6 +59,31 @@ static irqreturn_t stdma_int (int irq, void *dummy);
59/************************* End of Prototypes **************************/ 59/************************* End of Prototypes **************************/
60 60
61 61
62/**
63 * stdma_try_lock - attempt to acquire ST DMA interrupt "lock"
64 * @handler: interrupt handler to use after acquisition
65 *
66 * Returns !0 if lock was acquired; otherwise 0.
67 */
68
69int stdma_try_lock(irq_handler_t handler, void *data)
70{
71 unsigned long flags;
72
73 local_irq_save(flags);
74 if (stdma_locked) {
75 local_irq_restore(flags);
76 return 0;
77 }
78
79 stdma_locked = 1;
80 stdma_isr = handler;
81 stdma_isr_data = data;
82 local_irq_restore(flags);
83 return 1;
84}
85EXPORT_SYMBOL(stdma_try_lock);
86
62 87
63/* 88/*
64 * Function: void stdma_lock( isrfunc isr, void *data ) 89 * Function: void stdma_lock( isrfunc isr, void *data )
@@ -78,19 +103,10 @@ static irqreturn_t stdma_int (int irq, void *dummy);
78 103
79void stdma_lock(irq_handler_t handler, void *data) 104void stdma_lock(irq_handler_t handler, void *data)
80{ 105{
81 unsigned long flags;
82
83 local_irq_save(flags); /* protect lock */
84
85 /* Since the DMA is used for file system purposes, we 106 /* Since the DMA is used for file system purposes, we
86 have to sleep uninterruptible (there may be locked 107 have to sleep uninterruptible (there may be locked
87 buffers) */ 108 buffers) */
88 wait_event(stdma_wait, !stdma_locked); 109 wait_event(stdma_wait, stdma_try_lock(handler, data));
89
90 stdma_locked = 1;
91 stdma_isr = handler;
92 stdma_isr_data = data;
93 local_irq_restore(flags);
94} 110}
95EXPORT_SYMBOL(stdma_lock); 111EXPORT_SYMBOL(stdma_lock);
96 112
@@ -122,22 +138,25 @@ void stdma_release(void)
122EXPORT_SYMBOL(stdma_release); 138EXPORT_SYMBOL(stdma_release);
123 139
124 140
125/* 141/**
126 * Function: int stdma_others_waiting( void ) 142 * stdma_is_locked_by - allow lock holder to check whether it needs to release.
127 * 143 * @handler: interrupt handler previously used to acquire lock.
128 * Purpose: Check if someone waits for the ST-DMA lock.
129 *
130 * Inputs: none
131 *
132 * Returns: 0 if no one is waiting, != 0 otherwise
133 * 144 *
145 * Returns !0 if locked for the given handler; 0 otherwise.
134 */ 146 */
135 147
136int stdma_others_waiting(void) 148int stdma_is_locked_by(irq_handler_t handler)
137{ 149{
138 return waitqueue_active(&stdma_wait); 150 unsigned long flags;
151 int result;
152
153 local_irq_save(flags);
154 result = stdma_locked && (stdma_isr == handler);
155 local_irq_restore(flags);
156
157 return result;
139} 158}
140EXPORT_SYMBOL(stdma_others_waiting); 159EXPORT_SYMBOL(stdma_is_locked_by);
141 160
142 161
143/* 162/*
diff --git a/arch/m68k/include/asm/atari_stdma.h b/arch/m68k/include/asm/atari_stdma.h
index 8e389b7fa70c..d24e34d870dc 100644
--- a/arch/m68k/include/asm/atari_stdma.h
+++ b/arch/m68k/include/asm/atari_stdma.h
@@ -8,11 +8,11 @@
8 8
9/***************************** Prototypes *****************************/ 9/***************************** Prototypes *****************************/
10 10
11int stdma_try_lock(irq_handler_t, void *);
11void stdma_lock(irq_handler_t handler, void *data); 12void stdma_lock(irq_handler_t handler, void *data);
12void stdma_release( void ); 13void stdma_release( void );
13int stdma_others_waiting( void );
14int stdma_islocked( void ); 14int stdma_islocked( void );
15void *stdma_locked_by( void ); 15int stdma_is_locked_by(irq_handler_t);
16void stdma_init( void ); 16void stdma_init( void );
17 17
18/************************* End of Prototypes **************************/ 18/************************* End of Prototypes **************************/