aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorBruce Evans <bde@FreeBSD.org>2003-09-27 10:30:03 +0000
committerBruce Evans <bde@FreeBSD.org>2003-09-27 10:30:03 +0000
commit7872ac5542de71f23067b1edf488d9bcd3aa1748 (patch)
tree623e2b5eb5fd85613c96788340a532932e53dac4 /sys/dev
parent5192cc94697428324f4da8e46a96a250e6e9d324 (diff)
downloadsrc-7872ac5542de71f23067b1edf488d9bcd3aa1748.tar.gz
src-7872ac5542de71f23067b1edf488d9bcd3aa1748.zip
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.
Notes
Notes: svn path=/head/; revision=120504
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/cy/cy.c28
-rw-r--r--sys/dev/cy/cy_isa.c28
2 files changed, 48 insertions, 8 deletions
diff --git a/sys/dev/cy/cy.c b/sys/dev/cy/cy.c
index c8f24599352b..4bbedba65fec 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 c8f24599352b..4bbedba65fec 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();
}