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 6c5f8cc3.

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: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent a482958b
...@@ -185,6 +185,8 @@ static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */ ...@@ -185,6 +185,8 @@ static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
static DEFINE_SPINLOCK(cmd640_lock);
/* /*
* These are initialized to point at the devices we control * These are initialized to point at the devices we control
*/ */
...@@ -258,12 +260,12 @@ static u8 get_cmd640_reg_vlb (u16 reg) ...@@ -258,12 +260,12 @@ static u8 get_cmd640_reg_vlb (u16 reg)
static u8 get_cmd640_reg(u16 reg) static u8 get_cmd640_reg(u16 reg)
{ {
u8 b;
unsigned long flags; unsigned long flags;
u8 b;
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&cmd640_lock, flags);
b = __get_cmd640_reg(reg); b = __get_cmd640_reg(reg);
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
return b; return b;
} }
...@@ -271,9 +273,9 @@ static void put_cmd640_reg(u16 reg, u8 val) ...@@ -271,9 +273,9 @@ static void put_cmd640_reg(u16 reg, u8 val)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&cmd640_lock, flags);
__put_cmd640_reg(reg,val); __put_cmd640_reg(reg,val);
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
} }
static int __init match_pci_cmd640_device (void) static int __init match_pci_cmd640_device (void)
...@@ -351,7 +353,7 @@ static int __init secondary_port_responding (void) ...@@ -351,7 +353,7 @@ static int __init secondary_port_responding (void)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&cmd640_lock, flags);
outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */ outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */
udelay(100); udelay(100);
...@@ -359,11 +361,11 @@ static int __init secondary_port_responding (void) ...@@ -359,11 +361,11 @@ static int __init secondary_port_responding (void)
outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */ outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
udelay(100); udelay(100);
if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) { if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
return 0; /* nothing responded */ return 0; /* nothing responded */
} }
} }
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
return 1; /* success */ return 1; /* success */
} }
...@@ -440,11 +442,11 @@ static void __init setup_device_ptrs (void) ...@@ -440,11 +442,11 @@ static void __init setup_device_ptrs (void)
static void set_prefetch_mode (unsigned int index, int mode) static void set_prefetch_mode (unsigned int index, int mode)
{ {
ide_drive_t *drive = cmd_drives[index]; ide_drive_t *drive = cmd_drives[index];
unsigned long flags;
int reg = prefetch_regs[index]; int reg = prefetch_regs[index];
u8 b; u8 b;
unsigned long flags;
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&cmd640_lock, flags);
b = __get_cmd640_reg(reg); b = __get_cmd640_reg(reg);
if (mode) { /* want prefetch on? */ if (mode) { /* want prefetch on? */
#if CMD640_PREFETCH_MASKS #if CMD640_PREFETCH_MASKS
...@@ -460,7 +462,7 @@ static void set_prefetch_mode (unsigned int index, int mode) ...@@ -460,7 +462,7 @@ static void set_prefetch_mode (unsigned int index, int mode)
b |= prefetch_masks[index]; /* disable prefetch */ b |= prefetch_masks[index]; /* disable prefetch */
} }
__put_cmd640_reg(reg, b); __put_cmd640_reg(reg, b);
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
} }
/* /*
...@@ -561,7 +563,7 @@ static void program_drive_counts (unsigned int index) ...@@ -561,7 +563,7 @@ static void program_drive_counts (unsigned int index)
/* /*
* Now that everything is ready, program the new timings * Now that everything is ready, program the new timings
*/ */
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&cmd640_lock, flags);
/* /*
* Program the address_setup clocks into ARTTIM reg, * Program the address_setup clocks into ARTTIM reg,
* and then the active/recovery counts into the DRWTIM reg * and then the active/recovery counts into the DRWTIM reg
...@@ -570,7 +572,7 @@ static void program_drive_counts (unsigned int index) ...@@ -570,7 +572,7 @@ static void program_drive_counts (unsigned int index)
setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f; setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f;
__put_cmd640_reg(arttim_regs[index], setup_count); __put_cmd640_reg(arttim_regs[index], setup_count);
__put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count)); __put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
} }
/* /*
...@@ -630,6 +632,7 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle ...@@ -630,6 +632,7 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle
static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
{ {
unsigned long flags;
unsigned int index = 0, cycle_time; unsigned int index = 0, cycle_time;
u8 b; u8 b;
...@@ -652,7 +655,12 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) ...@@ -652,7 +655,12 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
case 8: /* set prefetch off */ case 8: /* set prefetch off */
case 9: /* set prefetch on */ case 9: /* set prefetch on */
/*
* take ide_lock for drive->[no_]unmask/[no_]io_32bit
*/
spin_lock_irqsave(&ide_lock, flags);
set_prefetch_mode(index, pio & 1); set_prefetch_mode(index, pio & 1);
spin_unlock_irqrestore(&ide_lock, flags);
printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis"); printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis");
return; return;
} }
...@@ -670,20 +678,20 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) ...@@ -670,20 +678,20 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
static int pci_conf1(void) static int pci_conf1(void)
{ {
u32 tmp;
unsigned long flags; unsigned long flags;
u32 tmp;
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&cmd640_lock, flags);
outb(0x01, 0xCFB); outb(0x01, 0xCFB);
tmp = inl(0xCF8); tmp = inl(0xCF8);
outl(0x80000000, 0xCF8); outl(0x80000000, 0xCF8);
if (inl(0xCF8) == 0x80000000) { if (inl(0xCF8) == 0x80000000) {
outl(tmp, 0xCF8); outl(tmp, 0xCF8);
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
return 1; return 1;
} }
outl(tmp, 0xCF8); outl(tmp, 0xCF8);
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
return 0; return 0;
} }
...@@ -691,15 +699,15 @@ static int pci_conf2(void) ...@@ -691,15 +699,15 @@ static int pci_conf2(void)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&cmd640_lock, flags);
outb(0x00, 0xCFB); outb(0x00, 0xCFB);
outb(0x00, 0xCF8); outb(0x00, 0xCF8);
outb(0x00, 0xCFA); outb(0x00, 0xCFA);
if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) { if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
return 1; return 1;
} }
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&cmd640_lock, flags);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment