diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-10-19 18:32:35 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-10-19 18:32:35 -0400 |
commit | 5bbcf9242d4d15027cbee9618fca4b88b7327c28 (patch) | |
tree | ea5ce460326ae3e4061e707de9a4f8bd7e1e13fa /drivers/ide/pci | |
parent | a482958bf60c434dc12ea0491938c8853d9774fb (diff) |
cmd640: fix deadlock on error handling
Stop abusing ide_lock lock (switch to a private locking).
Fixes same issue as fixed by Alan Cox in atiixp host driver with
commit 6c5f8cc33eb2e10b6ab788bbe259fc142a068627.
cmd640 is a bit special cause we still need to leave ide_lock for
->set_pio_mode with 'pio' argument == 8/9 (prefetch disable/enable).
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/pci')
-rw-r--r-- | drivers/ide/pci/cmd640.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index f369645e4d16..0e9275d7459c 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c | |||
@@ -185,6 +185,8 @@ static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */ | |||
185 | 185 | ||
186 | #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ | 186 | #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ |
187 | 187 | ||
188 | static DEFINE_SPINLOCK(cmd640_lock); | ||
189 | |||
188 | /* | 190 | /* |
189 | * These are initialized to point at the devices we control | 191 | * These are initialized to point at the devices we control |
190 | */ | 192 | */ |
@@ -258,12 +260,12 @@ static u8 get_cmd640_reg_vlb (u16 reg) | |||
258 | 260 | ||
259 | static u8 get_cmd640_reg(u16 reg) | 261 | static u8 get_cmd640_reg(u16 reg) |
260 | { | 262 | { |
261 | u8 b; | ||
262 | unsigned long flags; | 263 | unsigned long flags; |
264 | u8 b; | ||
263 | 265 | ||
264 | spin_lock_irqsave(&ide_lock, flags); | 266 | spin_lock_irqsave(&cmd640_lock, flags); |
265 | b = __get_cmd640_reg(reg); | 267 | b = __get_cmd640_reg(reg); |
266 | spin_unlock_irqrestore(&ide_lock, flags); | 268 | spin_unlock_irqrestore(&cmd640_lock, flags); |
267 | return b; | 269 | return b; |
268 | } | 270 | } |
269 | 271 | ||
@@ -271,9 +273,9 @@ static void put_cmd640_reg(u16 reg, u8 val) | |||
271 | { | 273 | { |
272 | unsigned long flags; | 274 | unsigned long flags; |
273 | 275 | ||
274 | spin_lock_irqsave(&ide_lock, flags); | 276 | spin_lock_irqsave(&cmd640_lock, flags); |
275 | __put_cmd640_reg(reg,val); | 277 | __put_cmd640_reg(reg,val); |
276 | spin_unlock_irqrestore(&ide_lock, flags); | 278 | spin_unlock_irqrestore(&cmd640_lock, flags); |
277 | } | 279 | } |
278 | 280 | ||
279 | static int __init match_pci_cmd640_device (void) | 281 | static int __init match_pci_cmd640_device (void) |
@@ -351,7 +353,7 @@ static int __init secondary_port_responding (void) | |||
351 | { | 353 | { |
352 | unsigned long flags; | 354 | unsigned long flags; |
353 | 355 | ||
354 | spin_lock_irqsave(&ide_lock, flags); | 356 | spin_lock_irqsave(&cmd640_lock, flags); |
355 | 357 | ||
356 | outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */ | 358 | outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */ |
357 | udelay(100); | 359 | udelay(100); |
@@ -359,11 +361,11 @@ static int __init secondary_port_responding (void) | |||
359 | outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */ | 361 | outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */ |
360 | udelay(100); | 362 | udelay(100); |
361 | if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) { | 363 | if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) { |
362 | spin_unlock_irqrestore(&ide_lock, flags); | 364 | spin_unlock_irqrestore(&cmd640_lock, flags); |
363 | return 0; /* nothing responded */ | 365 | return 0; /* nothing responded */ |
364 | } | 366 | } |
365 | } | 367 | } |
366 | spin_unlock_irqrestore(&ide_lock, flags); | 368 | spin_unlock_irqrestore(&cmd640_lock, flags); |
367 | return 1; /* success */ | 369 | return 1; /* success */ |
368 | } | 370 | } |
369 | 371 | ||
@@ -440,11 +442,11 @@ static void __init setup_device_ptrs (void) | |||
440 | static void set_prefetch_mode (unsigned int index, int mode) | 442 | static void set_prefetch_mode (unsigned int index, int mode) |
441 | { | 443 | { |
442 | ide_drive_t *drive = cmd_drives[index]; | 444 | ide_drive_t *drive = cmd_drives[index]; |
445 | unsigned long flags; | ||
443 | int reg = prefetch_regs[index]; | 446 | int reg = prefetch_regs[index]; |
444 | u8 b; | 447 | u8 b; |
445 | unsigned long flags; | ||
446 | 448 | ||
447 | spin_lock_irqsave(&ide_lock, flags); | 449 | spin_lock_irqsave(&cmd640_lock, flags); |
448 | b = __get_cmd640_reg(reg); | 450 | b = __get_cmd640_reg(reg); |
449 | if (mode) { /* want prefetch on? */ | 451 | if (mode) { /* want prefetch on? */ |
450 | #if CMD640_PREFETCH_MASKS | 452 | #if CMD640_PREFETCH_MASKS |
@@ -460,7 +462,7 @@ static void set_prefetch_mode (unsigned int index, int mode) | |||
460 | b |= prefetch_masks[index]; /* disable prefetch */ | 462 | b |= prefetch_masks[index]; /* disable prefetch */ |
461 | } | 463 | } |
462 | __put_cmd640_reg(reg, b); | 464 | __put_cmd640_reg(reg, b); |
463 | spin_unlock_irqrestore(&ide_lock, flags); | 465 | spin_unlock_irqrestore(&cmd640_lock, flags); |
464 | } | 466 | } |
465 | 467 | ||
466 | /* | 468 | /* |
@@ -561,7 +563,7 @@ static void program_drive_counts (unsigned int index) | |||
561 | /* | 563 | /* |
562 | * Now that everything is ready, program the new timings | 564 | * Now that everything is ready, program the new timings |
563 | */ | 565 | */ |
564 | spin_lock_irqsave(&ide_lock, flags); | 566 | spin_lock_irqsave(&cmd640_lock, flags); |
565 | /* | 567 | /* |
566 | * Program the address_setup clocks into ARTTIM reg, | 568 | * Program the address_setup clocks into ARTTIM reg, |
567 | * and then the active/recovery counts into the DRWTIM reg | 569 | * and then the active/recovery counts into the DRWTIM reg |
@@ -570,7 +572,7 @@ static void program_drive_counts (unsigned int index) | |||
570 | setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f; | 572 | setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f; |
571 | __put_cmd640_reg(arttim_regs[index], setup_count); | 573 | __put_cmd640_reg(arttim_regs[index], setup_count); |
572 | __put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count)); | 574 | __put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count)); |
573 | spin_unlock_irqrestore(&ide_lock, flags); | 575 | spin_unlock_irqrestore(&cmd640_lock, flags); |
574 | } | 576 | } |
575 | 577 | ||
576 | /* | 578 | /* |
@@ -630,6 +632,7 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle | |||
630 | 632 | ||
631 | static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) | 633 | static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) |
632 | { | 634 | { |
635 | unsigned long flags; | ||
633 | unsigned int index = 0, cycle_time; | 636 | unsigned int index = 0, cycle_time; |
634 | u8 b; | 637 | u8 b; |
635 | 638 | ||
@@ -652,7 +655,12 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) | |||
652 | 655 | ||
653 | case 8: /* set prefetch off */ | 656 | case 8: /* set prefetch off */ |
654 | case 9: /* set prefetch on */ | 657 | case 9: /* set prefetch on */ |
658 | /* | ||
659 | * take ide_lock for drive->[no_]unmask/[no_]io_32bit | ||
660 | */ | ||
661 | spin_lock_irqsave(&ide_lock, flags); | ||
655 | set_prefetch_mode(index, pio & 1); | 662 | set_prefetch_mode(index, pio & 1); |
663 | spin_unlock_irqrestore(&ide_lock, flags); | ||
656 | printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis"); | 664 | printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis"); |
657 | return; | 665 | return; |
658 | } | 666 | } |
@@ -670,20 +678,20 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) | |||
670 | 678 | ||
671 | static int pci_conf1(void) | 679 | static int pci_conf1(void) |
672 | { | 680 | { |
673 | u32 tmp; | ||
674 | unsigned long flags; | 681 | unsigned long flags; |
682 | u32 tmp; | ||
675 | 683 | ||
676 | spin_lock_irqsave(&ide_lock, flags); | 684 | spin_lock_irqsave(&cmd640_lock, flags); |
677 | outb(0x01, 0xCFB); | 685 | outb(0x01, 0xCFB); |
678 | tmp = inl(0xCF8); | 686 | tmp = inl(0xCF8); |
679 | outl(0x80000000, 0xCF8); | 687 | outl(0x80000000, 0xCF8); |
680 | if (inl(0xCF8) == 0x80000000) { | 688 | if (inl(0xCF8) == 0x80000000) { |
681 | outl(tmp, 0xCF8); | 689 | outl(tmp, 0xCF8); |
682 | spin_unlock_irqrestore(&ide_lock, flags); | 690 | spin_unlock_irqrestore(&cmd640_lock, flags); |
683 | return 1; | 691 | return 1; |
684 | } | 692 | } |
685 | outl(tmp, 0xCF8); | 693 | outl(tmp, 0xCF8); |
686 | spin_unlock_irqrestore(&ide_lock, flags); | 694 | spin_unlock_irqrestore(&cmd640_lock, flags); |
687 | return 0; | 695 | return 0; |
688 | } | 696 | } |
689 | 697 | ||
@@ -691,15 +699,15 @@ static int pci_conf2(void) | |||
691 | { | 699 | { |
692 | unsigned long flags; | 700 | unsigned long flags; |
693 | 701 | ||
694 | spin_lock_irqsave(&ide_lock, flags); | 702 | spin_lock_irqsave(&cmd640_lock, flags); |
695 | outb(0x00, 0xCFB); | 703 | outb(0x00, 0xCFB); |
696 | outb(0x00, 0xCF8); | 704 | outb(0x00, 0xCF8); |
697 | outb(0x00, 0xCFA); | 705 | outb(0x00, 0xCFA); |
698 | if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) { | 706 | if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) { |
699 | spin_unlock_irqrestore(&ide_lock, flags); | 707 | spin_unlock_irqrestore(&cmd640_lock, flags); |
700 | return 1; | 708 | return 1; |
701 | } | 709 | } |
702 | spin_unlock_irqrestore(&ide_lock, flags); | 710 | spin_unlock_irqrestore(&cmd640_lock, flags); |
703 | return 0; | 711 | return 0; |
704 | } | 712 | } |
705 | 713 | ||