diff options
author | John Gregor <john.gregor@qlogic.com> | 2007-09-05 04:57:14 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-01-25 17:15:27 -0500 |
commit | e342c119172f87f2d812bccfd0283f62e1bc1c2a (patch) | |
tree | 52eb0e75f5f894ab7f0f3c755f0876f18637e5a9 /drivers/infiniband/hw/ipath/ipath_driver.c | |
parent | 9ab4295d1d9ab10a249aea002060685f935a528c (diff) |
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.c | 40 |
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 fc355981bba..6a48442a8d5 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, | |||
803 | unsigned cnt) | 803 | unsigned cnt) |
804 | { | 804 | { |
805 | unsigned i, last = first + cnt; | 805 | unsigned i, last = first + cnt; |
806 | u64 sendctrl, sendorig; | 806 | unsigned long flags; |
807 | 807 | ||
808 | ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first); | 808 | ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first); |
809 | sendorig = dd->ipath_sendctrl; | ||
810 | for (i = first; i < last; i++) { | 809 | for (i = first; i < last; i++) { |
811 | sendctrl = sendorig | INFINIPATH_S_DISARM | | 810 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); |
812 | (i << INFINIPATH_S_DISARMPIOBUF_SHIFT); | 811 | /* |
812 | * The disarm-related bits are write-only, so it | ||
813 | * is ok to OR them in with our copy of sendctrl | ||
814 | * while we hold the lock. | ||
815 | */ | ||
813 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 816 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
814 | sendctrl); | 817 | dd->ipath_sendctrl | INFINIPATH_S_DISARM | |
818 | (i << INFINIPATH_S_DISARMPIOBUF_SHIFT)); | ||
819 | /* can't disarm bufs back-to-back per iba7220 spec */ | ||
820 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | ||
821 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
815 | } | 822 | } |
816 | 823 | ||
817 | /* | 824 | /* |
818 | * Write it again with current value, in case ipath_sendctrl changed | 825 | * Disable PIOAVAILUPD, then re-enable, reading scratch in |
819 | * while we were looping; no critical bits that would require | ||
820 | * locking. | ||
821 | * | ||
822 | * disable PIOAVAILUPD, then re-enable, reading scratch in | ||
823 | * between. This seems to avoid a chip timing race that causes | 826 | * between. This seems to avoid a chip timing race that causes |
824 | * pioavail updates to memory to stop. | 827 | * pioavail updates to memory to stop. We xor as we don't |
828 | * know the state of the bit when we're called. | ||
825 | */ | 829 | */ |
830 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); | ||
826 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 831 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
827 | sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD); | 832 | dd->ipath_sendctrl ^ INFINIPATH_S_PIOBUFAVAILUPD); |
828 | sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | 833 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); |
829 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 834 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
830 | dd->ipath_sendctrl); | 835 | dd->ipath_sendctrl); |
836 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
831 | } | 837 | } |
832 | 838 | ||
833 | /** | 839 | /** |
@@ -2056,6 +2062,8 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val) | |||
2056 | */ | 2062 | */ |
2057 | void ipath_shutdown_device(struct ipath_devdata *dd) | 2063 | void ipath_shutdown_device(struct ipath_devdata *dd) |
2058 | { | 2064 | { |
2065 | unsigned long flags; | ||
2066 | |||
2059 | ipath_dbg("Shutting down the device\n"); | 2067 | ipath_dbg("Shutting down the device\n"); |
2060 | 2068 | ||
2061 | dd->ipath_flags |= IPATH_LINKUNK; | 2069 | dd->ipath_flags |= IPATH_LINKUNK; |
@@ -2076,9 +2084,13 @@ void ipath_shutdown_device(struct ipath_devdata *dd) | |||
2076 | * gracefully stop all sends allowing any in progress to trickle out | 2084 | * gracefully stop all sends allowing any in progress to trickle out |
2077 | * first. | 2085 | * first. |
2078 | */ | 2086 | */ |
2079 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL); | 2087 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); |
2088 | dd->ipath_sendctrl = 0; | ||
2089 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); | ||
2080 | /* flush it */ | 2090 | /* flush it */ |
2081 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | 2091 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); |
2092 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
2093 | |||
2082 | /* | 2094 | /* |
2083 | * enough for anything that's going to trickle out to have actually | 2095 | * enough for anything that's going to trickle out to have actually |
2084 | * done so. | 2096 | * done so. |