diff options
author | bde <bde@FreeBSD.org> | 2003-09-27 10:30:03 +0000 |
---|---|---|
committer | bde <bde@FreeBSD.org> | 2003-09-27 10:30:03 +0000 |
commit | 6d69006c55a01bc62f55b1d4623fc13457564a16 (patch) | |
tree | 623e2b5eb5fd85613c96788340a532932e53dac4 /sys/dev/cy | |
parent | 573654b93e7cd2a1ee0d02ce53d6025d43a4c277 (diff) | |
download | FreeBSD-src-6d69006c55a01bc62f55b1d4623fc13457564a16.zip FreeBSD-src-6d69006c55a01bc62f55b1d4623fc13457564a16.tar.gz |
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.
Diffstat (limited to 'sys/dev/cy')
-rw-r--r-- | sys/dev/cy/cy.c | 28 | ||||
-rw-r--r-- | sys/dev/cy/cy_isa.c | 28 |
2 files changed, 48 insertions, 8 deletions
diff --git a/sys/dev/cy/cy.c b/sys/dev/cy/cy.c index c8f2459..4bbedba 100644 --- a/sys/dev/cy/cy.c +++ b/sys/dev/cy/cy.c @@ -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(); } diff --git a/sys/dev/cy/cy_isa.c b/sys/dev/cy/cy_isa.c index c8f2459..4bbedba 100644 --- a/sys/dev/cy/cy_isa.c +++ b/sys/dev/cy/cy_isa.c @@ -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(); } |