Quick fix for bitrot in locking in the SMP case. cd_getreg() and
cd_setreg() were still using !(read_eflags() & PSL_I) as the condition for the lock hidden by COM_LOCK() (if any) being held. This worked when spin mutexes and/or critical_enter() used hard interrupt disablement, but it has caused recursion on the non-recursive mutex com_mtx since all relevant interrupt disablement became soft. The recursion is harmless unless there are other bugs, but it breaks an invariant so it is fatal if spinlocks are witnessed.
This commit is contained in:
parent
573654b93e
commit
6d69006c55
@ -2852,6 +2852,9 @@ cd_getreg(com, reg)
|
||||
int cy_align;
|
||||
register_t eflags;
|
||||
cy_addr iobase;
|
||||
#ifdef SMP
|
||||
int need_unlock;
|
||||
#endif
|
||||
int val;
|
||||
|
||||
basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
|
||||
@ -2860,13 +2863,20 @@ cd_getreg(com, reg)
|
||||
iobase = com->iobase;
|
||||
eflags = read_eflags();
|
||||
critical_enter();
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
need_unlock = 0;
|
||||
if (!mtx_owned(&com_mtx)) {
|
||||
COM_LOCK();
|
||||
need_unlock = 1;
|
||||
}
|
||||
#endif
|
||||
if (basecom->car != car)
|
||||
cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
|
||||
val = cd_inb(iobase, reg, cy_align);
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
if (need_unlock)
|
||||
COM_UNLOCK();
|
||||
#endif
|
||||
critical_exit();
|
||||
return (val);
|
||||
}
|
||||
@ -2882,6 +2892,9 @@ cd_setreg(com, reg, val)
|
||||
int cy_align;
|
||||
register_t eflags;
|
||||
cy_addr iobase;
|
||||
#ifdef SMP
|
||||
int need_unlock;
|
||||
#endif
|
||||
|
||||
basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
|
||||
car = com->unit & CD1400_CAR_CHAN;
|
||||
@ -2889,13 +2902,20 @@ cd_setreg(com, reg, val)
|
||||
iobase = com->iobase;
|
||||
eflags = read_eflags();
|
||||
critical_enter();
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
need_unlock = 0;
|
||||
if (!mtx_owned(&com_mtx)) {
|
||||
COM_LOCK();
|
||||
need_unlock = 1;
|
||||
}
|
||||
#endif
|
||||
if (basecom->car != car)
|
||||
cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
|
||||
cd_outb(iobase, reg, cy_align, val);
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
if (need_unlock)
|
||||
COM_UNLOCK();
|
||||
#endif
|
||||
critical_exit();
|
||||
}
|
||||
|
||||
|
@ -2852,6 +2852,9 @@ cd_getreg(com, reg)
|
||||
int cy_align;
|
||||
register_t eflags;
|
||||
cy_addr iobase;
|
||||
#ifdef SMP
|
||||
int need_unlock;
|
||||
#endif
|
||||
int val;
|
||||
|
||||
basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
|
||||
@ -2860,13 +2863,20 @@ cd_getreg(com, reg)
|
||||
iobase = com->iobase;
|
||||
eflags = read_eflags();
|
||||
critical_enter();
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
need_unlock = 0;
|
||||
if (!mtx_owned(&com_mtx)) {
|
||||
COM_LOCK();
|
||||
need_unlock = 1;
|
||||
}
|
||||
#endif
|
||||
if (basecom->car != car)
|
||||
cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
|
||||
val = cd_inb(iobase, reg, cy_align);
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
if (need_unlock)
|
||||
COM_UNLOCK();
|
||||
#endif
|
||||
critical_exit();
|
||||
return (val);
|
||||
}
|
||||
@ -2882,6 +2892,9 @@ cd_setreg(com, reg, val)
|
||||
int cy_align;
|
||||
register_t eflags;
|
||||
cy_addr iobase;
|
||||
#ifdef SMP
|
||||
int need_unlock;
|
||||
#endif
|
||||
|
||||
basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
|
||||
car = com->unit & CD1400_CAR_CHAN;
|
||||
@ -2889,13 +2902,20 @@ cd_setreg(com, reg, val)
|
||||
iobase = com->iobase;
|
||||
eflags = read_eflags();
|
||||
critical_enter();
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
need_unlock = 0;
|
||||
if (!mtx_owned(&com_mtx)) {
|
||||
COM_LOCK();
|
||||
need_unlock = 1;
|
||||
}
|
||||
#endif
|
||||
if (basecom->car != car)
|
||||
cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
|
||||
cd_outb(iobase, reg, cy_align, val);
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
if (need_unlock)
|
||||
COM_UNLOCK();
|
||||
#endif
|
||||
critical_exit();
|
||||
}
|
||||
|
||||
|
@ -2852,6 +2852,9 @@ cd_getreg(com, reg)
|
||||
int cy_align;
|
||||
register_t eflags;
|
||||
cy_addr iobase;
|
||||
#ifdef SMP
|
||||
int need_unlock;
|
||||
#endif
|
||||
int val;
|
||||
|
||||
basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
|
||||
@ -2860,13 +2863,20 @@ cd_getreg(com, reg)
|
||||
iobase = com->iobase;
|
||||
eflags = read_eflags();
|
||||
critical_enter();
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
need_unlock = 0;
|
||||
if (!mtx_owned(&com_mtx)) {
|
||||
COM_LOCK();
|
||||
need_unlock = 1;
|
||||
}
|
||||
#endif
|
||||
if (basecom->car != car)
|
||||
cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
|
||||
val = cd_inb(iobase, reg, cy_align);
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
if (need_unlock)
|
||||
COM_UNLOCK();
|
||||
#endif
|
||||
critical_exit();
|
||||
return (val);
|
||||
}
|
||||
@ -2882,6 +2892,9 @@ cd_setreg(com, reg, val)
|
||||
int cy_align;
|
||||
register_t eflags;
|
||||
cy_addr iobase;
|
||||
#ifdef SMP
|
||||
int need_unlock;
|
||||
#endif
|
||||
|
||||
basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
|
||||
car = com->unit & CD1400_CAR_CHAN;
|
||||
@ -2889,13 +2902,20 @@ cd_setreg(com, reg, val)
|
||||
iobase = com->iobase;
|
||||
eflags = read_eflags();
|
||||
critical_enter();
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
need_unlock = 0;
|
||||
if (!mtx_owned(&com_mtx)) {
|
||||
COM_LOCK();
|
||||
need_unlock = 1;
|
||||
}
|
||||
#endif
|
||||
if (basecom->car != car)
|
||||
cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
|
||||
cd_outb(iobase, reg, cy_align, val);
|
||||
if (eflags & PSL_I)
|
||||
#ifdef SMP
|
||||
if (need_unlock)
|
||||
COM_UNLOCK();
|
||||
#endif
|
||||
critical_exit();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user