aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFederico Vaga <federico.vaga@cern.ch>2014-06-26 03:46:24 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-09 20:02:15 -0400
commit968d04e8de53789ccdb9f74413eb497f155d266b (patch)
treeee8556805aa1573c7ed660896cb027945d3901df
parentb86e1926be37c77deeb176466d98678feab04066 (diff)
ipoctal: protect only the real critical section
In some conditions (echo or particular sequence of special characters), on buffer push, the tty layer calls the write operation while we are holding the spinlock. This means deadlock within the same process on kernels version < 3.12. It seems not a problem on recent kernel, but the patch still valid as locking optimization. The protected variables by the spinlock are: xmit_buf, nb_bytes, pointer_read and pointer_write. So, this patch reduces the locked area in the IRQ handler only to these variables. Most of the code inside the locked area in the IRQ handler is not protected elsewhere; it means that it is not protected at all. Signed-off-by: Federico Vaga <federico.vaga@cern.ch> Acked-by: Samuel Iglesias Gonsalvez <siglesias@igalia.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/ipack/devices/ipoctal.c5
1 files changed, 2 insertions, 3 deletions
diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c
index 141094e7c06e..69687f156999 100644
--- a/drivers/ipack/devices/ipoctal.c
+++ b/drivers/ipack/devices/ipoctal.c
@@ -177,19 +177,20 @@ static void ipoctal_irq_tx(struct ipoctal_channel *channel)
177 if (channel->nb_bytes == 0) 177 if (channel->nb_bytes == 0)
178 return; 178 return;
179 179
180 spin_lock(&channel->lock);
180 value = channel->tty_port.xmit_buf[*pointer_write]; 181 value = channel->tty_port.xmit_buf[*pointer_write];
181 iowrite8(value, &channel->regs->w.thr); 182 iowrite8(value, &channel->regs->w.thr);
182 channel->stats.tx++; 183 channel->stats.tx++;
183 (*pointer_write)++; 184 (*pointer_write)++;
184 *pointer_write = *pointer_write % PAGE_SIZE; 185 *pointer_write = *pointer_write % PAGE_SIZE;
185 channel->nb_bytes--; 186 channel->nb_bytes--;
187 spin_unlock(&channel->lock);
186} 188}
187 189
188static void ipoctal_irq_channel(struct ipoctal_channel *channel) 190static void ipoctal_irq_channel(struct ipoctal_channel *channel)
189{ 191{
190 u8 isr, sr; 192 u8 isr, sr;
191 193
192 spin_lock(&channel->lock);
193 /* The HW is organized in pair of channels. See which register we need 194 /* The HW is organized in pair of channels. See which register we need
194 * to read from */ 195 * to read from */
195 isr = ioread8(&channel->block_regs->r.isr); 196 isr = ioread8(&channel->block_regs->r.isr);
@@ -213,8 +214,6 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel)
213 /* TX of each character */ 214 /* TX of each character */
214 if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY)) 215 if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY))
215 ipoctal_irq_tx(channel); 216 ipoctal_irq_tx(channel);
216
217 spin_unlock(&channel->lock);
218} 217}
219 218
220static irqreturn_t ipoctal_irq_handler(void *arg) 219static irqreturn_t ipoctal_irq_handler(void *arg)