aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/isicom.c
diff options
context:
space:
mode:
authorJiri Slaby <jirislaby@gmail.com>2006-12-29 19:48:00 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-30 13:55:55 -0500
commitcfe7c09ac2be2a89aa46bb23d480d9d908e8c041 (patch)
treef05d110db6f6dc595e0e672b99397d3f2ea6d6e8 /drivers/char/isicom.c
parent10f549fa1538849548787879d96bbb3450f06117 (diff)
[PATCH] Char: isicom, eliminate spinlock recursion
Many spinlock recursion was in the isicom driver. Eliminate it. Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/isicom.c')
-rw-r--r--drivers/char/isicom.c103
1 files changed, 51 insertions, 52 deletions
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 5a747e685993..01084abffddf 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -230,6 +230,20 @@ static struct isi_port isi_ports[PORT_COUNT];
230 * it wants to talk. 230 * it wants to talk.
231 */ 231 */
232 232
233static inline int WaitTillCardIsFree(u16 base)
234{
235 unsigned int count = 0;
236 unsigned int a = in_atomic(); /* do we run under spinlock? */
237
238 while (!(inw(base + 0xe) & 0x1) && count++ < 100)
239 if (a)
240 mdelay(1);
241 else
242 msleep(1);
243
244 return !(inw(base + 0xe) & 0x1);
245}
246
233static int lock_card(struct isi_board *card) 247static int lock_card(struct isi_board *card)
234{ 248{
235 char retries; 249 char retries;
@@ -276,69 +290,71 @@ static void unlock_card(struct isi_board *card)
276 * ISI Card specific ops ... 290 * ISI Card specific ops ...
277 */ 291 */
278 292
293/* card->lock HAS to be held */
279static void raise_dtr(struct isi_port *port) 294static void raise_dtr(struct isi_port *port)
280{ 295{
281 struct isi_board *card = port->card; 296 struct isi_board *card = port->card;
282 unsigned long base = card->base; 297 unsigned long base = card->base;
283 u16 channel = port->channel; 298 u16 channel = port->channel;
284 299
285 if (!lock_card(card)) 300 if (WaitTillCardIsFree(base))
286 return; 301 return;
287 302
288 outw(0x8000 | (channel << card->shift_count) | 0x02, base); 303 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
289 outw(0x0504, base); 304 outw(0x0504, base);
290 InterruptTheCard(base); 305 InterruptTheCard(base);
291 port->status |= ISI_DTR; 306 port->status |= ISI_DTR;
292 unlock_card(card);
293} 307}
294 308
309/* card->lock HAS to be held */
295static inline void drop_dtr(struct isi_port *port) 310static inline void drop_dtr(struct isi_port *port)
296{ 311{
297 struct isi_board *card = port->card; 312 struct isi_board *card = port->card;
298 unsigned long base = card->base; 313 unsigned long base = card->base;
299 u16 channel = port->channel; 314 u16 channel = port->channel;
300 315
301 if (!lock_card(card)) 316 if (WaitTillCardIsFree(base))
302 return; 317 return;
303 318
304 outw(0x8000 | (channel << card->shift_count) | 0x02, base); 319 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
305 outw(0x0404, base); 320 outw(0x0404, base);
306 InterruptTheCard(base); 321 InterruptTheCard(base);
307 port->status &= ~ISI_DTR; 322 port->status &= ~ISI_DTR;
308 unlock_card(card);
309} 323}
310 324
325/* card->lock HAS to be held */
311static inline void raise_rts(struct isi_port *port) 326static inline void raise_rts(struct isi_port *port)
312{ 327{
313 struct isi_board *card = port->card; 328 struct isi_board *card = port->card;
314 unsigned long base = card->base; 329 unsigned long base = card->base;
315 u16 channel = port->channel; 330 u16 channel = port->channel;
316 331
317 if (!lock_card(card)) 332 if (WaitTillCardIsFree(base))
318 return; 333 return;
319 334
320 outw(0x8000 | (channel << card->shift_count) | 0x02, base); 335 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
321 outw(0x0a04, base); 336 outw(0x0a04, base);
322 InterruptTheCard(base); 337 InterruptTheCard(base);
323 port->status |= ISI_RTS; 338 port->status |= ISI_RTS;
324 unlock_card(card);
325} 339}
340
341/* card->lock HAS to be held */
326static inline void drop_rts(struct isi_port *port) 342static inline void drop_rts(struct isi_port *port)
327{ 343{
328 struct isi_board *card = port->card; 344 struct isi_board *card = port->card;
329 unsigned long base = card->base; 345 unsigned long base = card->base;
330 u16 channel = port->channel; 346 u16 channel = port->channel;
331 347
332 if (!lock_card(card)) 348 if (WaitTillCardIsFree(base))
333 return; 349 return;
334 350
335 outw(0x8000 | (channel << card->shift_count) | 0x02, base); 351 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
336 outw(0x0804, base); 352 outw(0x0804, base);
337 InterruptTheCard(base); 353 InterruptTheCard(base);
338 port->status &= ~ISI_RTS; 354 port->status &= ~ISI_RTS;
339 unlock_card(card);
340} 355}
341 356
357/* card->lock MUST NOT be held */
342static inline void raise_dtr_rts(struct isi_port *port) 358static inline void raise_dtr_rts(struct isi_port *port)
343{ 359{
344 struct isi_board *card = port->card; 360 struct isi_board *card = port->card;
@@ -355,35 +371,20 @@ static inline void raise_dtr_rts(struct isi_port *port)
355 unlock_card(card); 371 unlock_card(card);
356} 372}
357 373
374/* card->lock HAS to be held */
358static void drop_dtr_rts(struct isi_port *port) 375static void drop_dtr_rts(struct isi_port *port)
359{ 376{
360 struct isi_board *card = port->card; 377 struct isi_board *card = port->card;
361 unsigned long base = card->base; 378 unsigned long base = card->base;
362 u16 channel = port->channel; 379 u16 channel = port->channel;
363 380
364 if (!lock_card(card)) 381 if (WaitTillCardIsFree(base))
365 return; 382 return;
366 383
367 outw(0x8000 | (channel << card->shift_count) | 0x02, base); 384 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
368 outw(0x0c04, base); 385 outw(0x0c04, base);
369 InterruptTheCard(base); 386 InterruptTheCard(base);
370 port->status &= ~(ISI_RTS | ISI_DTR); 387 port->status &= ~(ISI_RTS | ISI_DTR);
371 unlock_card(card);
372}
373
374static inline void kill_queue(struct isi_port *port, short queue)
375{
376 struct isi_board *card = port->card;
377 unsigned long base = card->base;
378 u16 channel = port->channel;
379
380 if (!lock_card(card))
381 return;
382
383 outw(0x8000 | (channel << card->shift_count) | 0x02, base);
384 outw((queue << 8) | 0x06, base);
385 InterruptTheCard(base);
386 unlock_card(card);
387} 388}
388 389
389/* 390/*
@@ -744,7 +745,7 @@ static void isicom_config_port(struct isi_port *port)
744 else 745 else
745 raise_dtr(port); 746 raise_dtr(port);
746 747
747 if (lock_card(card)) { 748 if (WaitTillCardIsFree(base) == 0) {
748 outw(0x8000 | (channel << shift_count) |0x03, base); 749 outw(0x8000 | (channel << shift_count) |0x03, base);
749 outw(linuxb_to_isib[baud] << 8 | 0x03, base); 750 outw(linuxb_to_isib[baud] << 8 | 0x03, base);
750 channel_setup = 0; 751 channel_setup = 0;
@@ -772,7 +773,6 @@ static void isicom_config_port(struct isi_port *port)
772 } 773 }
773 outw(channel_setup, base); 774 outw(channel_setup, base);
774 InterruptTheCard(base); 775 InterruptTheCard(base);
775 unlock_card(card);
776 } 776 }
777 if (C_CLOCAL(tty)) 777 if (C_CLOCAL(tty))
778 port->flags &= ~ASYNC_CHECK_CD; 778 port->flags &= ~ASYNC_CHECK_CD;
@@ -791,12 +791,11 @@ static void isicom_config_port(struct isi_port *port)
791 if (I_IXOFF(tty)) 791 if (I_IXOFF(tty))
792 flow_ctrl |= ISICOM_INITIATE_XONXOFF; 792 flow_ctrl |= ISICOM_INITIATE_XONXOFF;
793 793
794 if (lock_card(card)) { 794 if (WaitTillCardIsFree(base) == 0) {
795 outw(0x8000 | (channel << shift_count) |0x04, base); 795 outw(0x8000 | (channel << shift_count) |0x04, base);
796 outw(flow_ctrl << 8 | 0x05, base); 796 outw(flow_ctrl << 8 | 0x05, base);
797 outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); 797 outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
798 InterruptTheCard(base); 798 InterruptTheCard(base);
799 unlock_card(card);
800 } 799 }
801 800
802 /* rx enabled -> enable port for rx on the card */ 801 /* rx enabled -> enable port for rx on the card */
@@ -821,10 +820,9 @@ static inline void isicom_setup_board(struct isi_board *bp)
821 } 820 }
822 port = bp->ports; 821 port = bp->ports;
823 bp->status |= BOARD_ACTIVE; 822 bp->status |= BOARD_ACTIVE;
824 spin_unlock_irqrestore(&bp->card_lock, flags);
825 for (channel = 0; channel < bp->port_count; channel++, port++) 823 for (channel = 0; channel < bp->port_count; channel++, port++)
826 drop_dtr_rts(port); 824 drop_dtr_rts(port);
827 return; 825 spin_unlock_irqrestore(&bp->card_lock, flags);
828} 826}
829 827
830static int isicom_setup_port(struct isi_port *port) 828static int isicom_setup_port(struct isi_port *port)
@@ -857,7 +855,12 @@ static int isicom_setup_port(struct isi_port *port)
857 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; 855 port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
858 856
859 /* discard any residual data */ 857 /* discard any residual data */
860 kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX); 858 if (WaitTillCardIsFree(card->base) == 0) {
859 outw(0x8000 | (port->channel << card->shift_count) | 0x02,
860 card->base);
861 outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
862 InterruptTheCard(card->base);
863 }
861 864
862 isicom_config_port(port); 865 isicom_config_port(port);
863 port->flags |= ASYNC_INITIALIZED; 866 port->flags |= ASYNC_INITIALIZED;
@@ -983,28 +986,22 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
983 986
984static inline void isicom_shutdown_board(struct isi_board *bp) 987static inline void isicom_shutdown_board(struct isi_board *bp)
985{ 988{
986 unsigned long flags;
987
988 spin_lock_irqsave(&bp->card_lock, flags);
989 if (bp->status & BOARD_ACTIVE) { 989 if (bp->status & BOARD_ACTIVE) {
990 bp->status &= ~BOARD_ACTIVE; 990 bp->status &= ~BOARD_ACTIVE;
991 } 991 }
992 spin_unlock_irqrestore(&bp->card_lock, flags);
993} 992}
994 993
994/* card->lock HAS to be held */
995static void isicom_shutdown_port(struct isi_port *port) 995static void isicom_shutdown_port(struct isi_port *port)
996{ 996{
997 struct isi_board *card = port->card; 997 struct isi_board *card = port->card;
998 struct tty_struct *tty; 998 struct tty_struct *tty;
999 unsigned long flags;
1000 999
1001 tty = port->tty; 1000 tty = port->tty;
1002 1001
1003 spin_lock_irqsave(&card->card_lock, flags); 1002 if (!(port->flags & ASYNC_INITIALIZED))
1004 if (!(port->flags & ASYNC_INITIALIZED)) {
1005 spin_unlock_irqrestore(&card->card_lock, flags);
1006 return; 1003 return;
1007 } 1004
1008 if (port->xmit_buf) { 1005 if (port->xmit_buf) {
1009 free_page((unsigned long) port->xmit_buf); 1006 free_page((unsigned long) port->xmit_buf);
1010 port->xmit_buf = NULL; 1007 port->xmit_buf = NULL;
@@ -1012,7 +1009,6 @@ static void isicom_shutdown_port(struct isi_port *port)
1012 port->flags &= ~ASYNC_INITIALIZED; 1009 port->flags &= ~ASYNC_INITIALIZED;
1013 /* 3rd October 2000 : Vinayak P Risbud */ 1010 /* 3rd October 2000 : Vinayak P Risbud */
1014 port->tty = NULL; 1011 port->tty = NULL;
1015 spin_unlock_irqrestore(&card->card_lock, flags);
1016 1012
1017 /*Fix done by Anil .S on 30-04-2001 1013 /*Fix done by Anil .S on 30-04-2001
1018 remote login through isi port has dtr toggle problem 1014 remote login through isi port has dtr toggle problem
@@ -1258,10 +1254,12 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
1258 unsigned int set, unsigned int clear) 1254 unsigned int set, unsigned int clear)
1259{ 1255{
1260 struct isi_port *port = tty->driver_data; 1256 struct isi_port *port = tty->driver_data;
1257 unsigned long flags;
1261 1258
1262 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) 1259 if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
1263 return -ENODEV; 1260 return -ENODEV;
1264 1261
1262 spin_lock_irqsave(&port->card->card_lock, flags);
1265 if (set & TIOCM_RTS) 1263 if (set & TIOCM_RTS)
1266 raise_rts(port); 1264 raise_rts(port);
1267 if (set & TIOCM_DTR) 1265 if (set & TIOCM_DTR)
@@ -1271,6 +1269,7 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
1271 drop_rts(port); 1269 drop_rts(port);
1272 if (clear & TIOCM_DTR) 1270 if (clear & TIOCM_DTR)
1273 drop_dtr(port); 1271 drop_dtr(port);
1272 spin_unlock_irqrestore(&port->card->card_lock, flags);
1274 1273
1275 return 0; 1274 return 0;
1276} 1275}
@@ -1303,7 +1302,10 @@ static int isicom_set_serial_info(struct isi_port *port,
1303 (newinfo.flags & ASYNC_FLAGS)); 1302 (newinfo.flags & ASYNC_FLAGS));
1304 } 1303 }
1305 if (reconfig_port) { 1304 if (reconfig_port) {
1305 unsigned long flags;
1306 spin_lock_irqsave(&port->card->card_lock, flags);
1306 isicom_config_port(port); 1307 isicom_config_port(port);
1308 spin_unlock_irqrestore(&port->card->card_lock, flags);
1307 } 1309 }
1308 return 0; 1310 return 0;
1309} 1311}
@@ -1384,6 +1386,7 @@ static void isicom_set_termios(struct tty_struct *tty,
1384 struct ktermios *old_termios) 1386 struct ktermios *old_termios)
1385{ 1387{
1386 struct isi_port *port = tty->driver_data; 1388 struct isi_port *port = tty->driver_data;
1389 unsigned long flags;
1387 1390
1388 if (isicom_paranoia_check(port, tty->name, "isicom_set_termios")) 1391 if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
1389 return; 1392 return;
@@ -1392,7 +1395,9 @@ static void isicom_set_termios(struct tty_struct *tty,
1392 tty->termios->c_iflag == old_termios->c_iflag) 1395 tty->termios->c_iflag == old_termios->c_iflag)
1393 return; 1396 return;
1394 1397
1398 spin_lock_irqsave(&port->card->card_lock, flags);
1395 isicom_config_port(port); 1399 isicom_config_port(port);
1400 spin_unlock_irqrestore(&port->card->card_lock, flags);
1396 1401
1397 if ((old_termios->c_cflag & CRTSCTS) && 1402 if ((old_termios->c_cflag & CRTSCTS) &&
1398 !(tty->termios->c_cflag & CRTSCTS)) { 1403 !(tty->termios->c_cflag & CRTSCTS)) {
@@ -1469,11 +1474,15 @@ static void do_isicom_hangup(struct work_struct *work)
1469static void isicom_hangup(struct tty_struct *tty) 1474static void isicom_hangup(struct tty_struct *tty)
1470{ 1475{
1471 struct isi_port *port = tty->driver_data; 1476 struct isi_port *port = tty->driver_data;
1477 unsigned long flags;
1472 1478
1473 if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) 1479 if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
1474 return; 1480 return;
1475 1481
1482 spin_lock_irqsave(&port->card->card_lock, flags);
1476 isicom_shutdown_port(port); 1483 isicom_shutdown_port(port);
1484 spin_unlock_irqrestore(&port->card->card_lock, flags);
1485
1477 port->count = 0; 1486 port->count = 0;
1478 port->flags &= ~ASYNC_NORMAL_ACTIVE; 1487 port->flags &= ~ASYNC_NORMAL_ACTIVE;
1479 port->tty = NULL; 1488 port->tty = NULL;
@@ -1578,16 +1587,6 @@ end:
1578 return retval; 1587 return retval;
1579} 1588}
1580 1589
1581static inline int WaitTillCardIsFree(u16 base)
1582{
1583 unsigned long count = 0;
1584
1585 while (!(inw(base + 0xe) & 0x1) && count++ < 100)
1586 msleep(5);
1587
1588 return !(inw(base + 0xe) & 0x1);
1589}
1590
1591static int __devinit load_firmware(struct pci_dev *pdev, 1590static int __devinit load_firmware(struct pci_dev *pdev,
1592 const unsigned int index, const unsigned int signature) 1591 const unsigned int index, const unsigned int signature)
1593{ 1592{