aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/ipath/ipath_driver.c
diff options
context:
space:
mode:
authorJohn Gregor <john.gregor@qlogic.com>2007-09-05 01:57:14 -0700
committerRoland Dreier <rolandd@cisco.com>2008-01-25 14:15:27 -0800
commite342c119172f87f2d812bccfd0283f62e1bc1c2a (patch)
tree52eb0e75f5f894ab7f0f3c755f0876f18637e5a9 /drivers/infiniband/hw/ipath/ipath_driver.c
parent9ab4295d1d9ab10a249aea002060685f935a528c (diff)
downloadkernel_samsung_smdk4412-e342c119172f87f2d812bccfd0283f62e1bc1c2a.zip
kernel_samsung_smdk4412-e342c119172f87f2d812bccfd0283f62e1bc1c2a.tar.gz
kernel_samsung_smdk4412-e342c119172f87f2d812bccfd0283f62e1bc1c2a.tar.bz2
IB/ipath: Fix sendctrl locking
Code review pointed out that the locking around uses of ipath_sendctrl and kr_sendctrl were, in several places, incorrect and/or inconsistent. Signed-off-by: John Gregor <john.gregor@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_driver.c')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c40
1 files changed, 26 insertions, 14 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index fc35598..6a48442 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -803,31 +803,37 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
unsigned cnt)
{
unsigned i, last = first + cnt;
- u64 sendctrl, sendorig;
+ unsigned long flags;
ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first);
- sendorig = dd->ipath_sendctrl;
for (i = first; i < last; i++) {
- sendctrl = sendorig | INFINIPATH_S_DISARM |
- (i << INFINIPATH_S_DISARMPIOBUF_SHIFT);
+ spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+ /*
+ * The disarm-related bits are write-only, so it
+ * is ok to OR them in with our copy of sendctrl
+ * while we hold the lock.
+ */
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- sendctrl);
+ dd->ipath_sendctrl | INFINIPATH_S_DISARM |
+ (i << INFINIPATH_S_DISARMPIOBUF_SHIFT));
+ /* can't disarm bufs back-to-back per iba7220 spec */
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
}
/*
- * Write it again with current value, in case ipath_sendctrl changed
- * while we were looping; no critical bits that would require
- * locking.
- *
- * disable PIOAVAILUPD, then re-enable, reading scratch in
+ * Disable PIOAVAILUPD, then re-enable, reading scratch in
* between. This seems to avoid a chip timing race that causes
- * pioavail updates to memory to stop.
+ * pioavail updates to memory to stop. We xor as we don't
+ * know the state of the bit when we're called.
*/
+ spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD);
- sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ dd->ipath_sendctrl ^ INFINIPATH_S_PIOBUFAVAILUPD);
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
+ spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
}
/**
@@ -2056,6 +2062,8 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val)
*/
void ipath_shutdown_device(struct ipath_devdata *dd)
{
+ unsigned long flags;
+
ipath_dbg("Shutting down the device\n");
dd->ipath_flags |= IPATH_LINKUNK;
@@ -2076,9 +2084,13 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
* gracefully stop all sends allowing any in progress to trickle out
* first.
*/
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL);
+ spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+ dd->ipath_sendctrl = 0;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
/* flush it */
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+
/*
* enough for anything that's going to trickle out to have actually
* done so.