diff options
-rw-r--r-- | drivers/char/isicom.c | 65 |
1 files changed, 27 insertions, 38 deletions
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 761f77740d67..b133b92a0ad5 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
@@ -243,17 +243,18 @@ static inline int WaitTillCardIsFree(u16 base) | |||
243 | 243 | ||
244 | static int lock_card(struct isi_board *card) | 244 | static int lock_card(struct isi_board *card) |
245 | { | 245 | { |
246 | char retries; | ||
247 | unsigned long base = card->base; | 246 | unsigned long base = card->base; |
247 | unsigned int retries, a; | ||
248 | 248 | ||
249 | for (retries = 0; retries < 100; retries++) { | 249 | for (retries = 0; retries < 10; retries++) { |
250 | spin_lock_irqsave(&card->card_lock, card->flags); | 250 | spin_lock_irqsave(&card->card_lock, card->flags); |
251 | if (inw(base + 0xe) & 0x1) { | 251 | for (a = 0; a < 10; a++) { |
252 | return 1; | 252 | if (inw(base + 0xe) & 0x1) |
253 | } else { | 253 | return 1; |
254 | spin_unlock_irqrestore(&card->card_lock, card->flags); | 254 | udelay(10); |
255 | udelay(1000); /* 1ms */ | ||
256 | } | 255 | } |
256 | spin_unlock_irqrestore(&card->card_lock, card->flags); | ||
257 | msleep(10); | ||
257 | } | 258 | } |
258 | printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n", | 259 | printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n", |
259 | card->base); | 260 | card->base); |
@@ -261,23 +262,6 @@ static int lock_card(struct isi_board *card) | |||
261 | return 0; /* Failed to acquire the card! */ | 262 | return 0; /* Failed to acquire the card! */ |
262 | } | 263 | } |
263 | 264 | ||
264 | static int lock_card_at_interrupt(struct isi_board *card) | ||
265 | { | ||
266 | unsigned char retries; | ||
267 | unsigned long base = card->base; | ||
268 | |||
269 | for (retries = 0; retries < 200; retries++) { | ||
270 | spin_lock_irqsave(&card->card_lock, card->flags); | ||
271 | |||
272 | if (inw(base + 0xe) & 0x1) | ||
273 | return 1; | ||
274 | else | ||
275 | spin_unlock_irqrestore(&card->card_lock, card->flags); | ||
276 | } | ||
277 | /* Failing in interrupt is an acceptable event */ | ||
278 | return 0; /* Failed to acquire the card! */ | ||
279 | } | ||
280 | |||
281 | static void unlock_card(struct isi_board *card) | 265 | static void unlock_card(struct isi_board *card) |
282 | { | 266 | { |
283 | spin_unlock_irqrestore(&card->card_lock, card->flags); | 267 | spin_unlock_irqrestore(&card->card_lock, card->flags); |
@@ -415,6 +399,8 @@ static inline int __isicom_paranoia_check(struct isi_port const *port, | |||
415 | 399 | ||
416 | static void isicom_tx(unsigned long _data) | 400 | static void isicom_tx(unsigned long _data) |
417 | { | 401 | { |
402 | unsigned long flags; | ||
403 | unsigned int retries; | ||
418 | short count = (BOARD_COUNT-1), card, base; | 404 | short count = (BOARD_COUNT-1), card, base; |
419 | short txcount, wrd, residue, word_count, cnt; | 405 | short txcount, wrd, residue, word_count, cnt; |
420 | struct isi_port *port; | 406 | struct isi_port *port; |
@@ -435,32 +421,34 @@ static void isicom_tx(unsigned long _data) | |||
435 | count = isi_card[card].port_count; | 421 | count = isi_card[card].port_count; |
436 | port = isi_card[card].ports; | 422 | port = isi_card[card].ports; |
437 | base = isi_card[card].base; | 423 | base = isi_card[card].base; |
424 | |||
425 | spin_lock_irqsave(&isi_card[card].card_lock, flags); | ||
426 | for (retries = 0; retries < 100; retries++) { | ||
427 | if (inw(base + 0xe) & 0x1) | ||
428 | break; | ||
429 | udelay(2); | ||
430 | } | ||
431 | if (retries >= 100) | ||
432 | goto unlock; | ||
433 | |||
438 | for (;count > 0;count--, port++) { | 434 | for (;count > 0;count--, port++) { |
439 | if (!lock_card_at_interrupt(&isi_card[card])) | ||
440 | continue; | ||
441 | /* port not active or tx disabled to force flow control */ | 435 | /* port not active or tx disabled to force flow control */ |
442 | if (!(port->flags & ASYNC_INITIALIZED) || | 436 | if (!(port->flags & ASYNC_INITIALIZED) || |
443 | !(port->status & ISI_TXOK)) | 437 | !(port->status & ISI_TXOK)) |
444 | unlock_card(&isi_card[card]); | ||
445 | continue; | 438 | continue; |
446 | 439 | ||
447 | tty = port->tty; | 440 | tty = port->tty; |
448 | 441 | ||
449 | 442 | if (tty == NULL) | |
450 | if (tty == NULL) { | ||
451 | unlock_card(&isi_card[card]); | ||
452 | continue; | 443 | continue; |
453 | } | ||
454 | 444 | ||
455 | txcount = min_t(short, TX_SIZE, port->xmit_cnt); | 445 | txcount = min_t(short, TX_SIZE, port->xmit_cnt); |
456 | if (txcount <= 0 || tty->stopped || tty->hw_stopped) { | 446 | if (txcount <= 0 || tty->stopped || tty->hw_stopped) |
457 | unlock_card(&isi_card[card]); | ||
458 | continue; | 447 | continue; |
459 | } | 448 | |
460 | if (!(inw(base + 0x02) & (1 << port->channel))) { | 449 | if (!(inw(base + 0x02) & (1 << port->channel))) |
461 | unlock_card(&isi_card[card]); | ||
462 | continue; | 450 | continue; |
463 | } | 451 | |
464 | pr_dbg("txing %d bytes, port%d.\n", txcount, | 452 | pr_dbg("txing %d bytes, port%d.\n", txcount, |
465 | port->channel + 1); | 453 | port->channel + 1); |
466 | outw((port->channel << isi_card[card].shift_count) | txcount, | 454 | outw((port->channel << isi_card[card].shift_count) | txcount, |
@@ -508,9 +496,10 @@ static void isicom_tx(unsigned long _data) | |||
508 | port->status &= ~ISI_TXOK; | 496 | port->status &= ~ISI_TXOK; |
509 | if (port->xmit_cnt <= WAKEUP_CHARS) | 497 | if (port->xmit_cnt <= WAKEUP_CHARS) |
510 | tty_wakeup(tty); | 498 | tty_wakeup(tty); |
511 | unlock_card(&isi_card[card]); | ||
512 | } | 499 | } |
513 | 500 | ||
501 | unlock: | ||
502 | spin_unlock_irqrestore(&isi_card[card].card_lock, flags); | ||
514 | /* schedule another tx for hopefully in about 10ms */ | 503 | /* schedule another tx for hopefully in about 10ms */ |
515 | sched_again: | 504 | sched_again: |
516 | if (!re_schedule) { | 505 | if (!re_schedule) { |