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 | |
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')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_driver.c | 40 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_file_ops.c | 10 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_init_chip.c | 24 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_intr.c | 19 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_ruc.c | 7 |
6 files changed, 72 insertions, 29 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index fc355981bbab..6a48442a8d59 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. |
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 5de3243a47c3..92dae6f5b395 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c | |||
@@ -2149,11 +2149,15 @@ static int ipath_get_slave_info(struct ipath_portdata *pd, | |||
2149 | 2149 | ||
2150 | static int ipath_force_pio_avail_update(struct ipath_devdata *dd) | 2150 | static int ipath_force_pio_avail_update(struct ipath_devdata *dd) |
2151 | { | 2151 | { |
2152 | u64 reg = dd->ipath_sendctrl; | 2152 | unsigned long flags; |
2153 | 2153 | ||
2154 | clear_bit(IPATH_S_PIOBUFAVAILUPD, ®); | 2154 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); |
2155 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg); | 2155 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
2156 | dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD); | ||
2157 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | ||
2156 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); | 2158 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); |
2159 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | ||
2160 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
2157 | 2161 | ||
2158 | return 0; | 2162 | return 0; |
2159 | } | 2163 | } |
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 9e9d6fafcf0d..1c65ab907a33 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c | |||
@@ -345,7 +345,7 @@ static int init_chip_first(struct ipath_devdata *dd, | |||
345 | dd->ipath_piobcnt2k, dd->ipath_pio2kbase); | 345 | dd->ipath_piobcnt2k, dd->ipath_pio2kbase); |
346 | 346 | ||
347 | spin_lock_init(&dd->ipath_tid_lock); | 347 | spin_lock_init(&dd->ipath_tid_lock); |
348 | 348 | spin_lock_init(&dd->ipath_sendctrl_lock); | |
349 | spin_lock_init(&dd->ipath_gpio_lock); | 349 | spin_lock_init(&dd->ipath_gpio_lock); |
350 | spin_lock_init(&dd->ipath_eep_st_lock); | 350 | spin_lock_init(&dd->ipath_eep_st_lock); |
351 | mutex_init(&dd->ipath_eep_lock); | 351 | mutex_init(&dd->ipath_eep_lock); |
@@ -372,9 +372,9 @@ static int init_chip_reset(struct ipath_devdata *dd, | |||
372 | *pdp = dd->ipath_pd[0]; | 372 | *pdp = dd->ipath_pd[0]; |
373 | /* ensure chip does no sends or receives while we re-initialize */ | 373 | /* ensure chip does no sends or receives while we re-initialize */ |
374 | dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U; | 374 | dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U; |
375 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0); | 375 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); |
376 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0); | 376 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); |
377 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0); | 377 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, dd->ipath_control); |
378 | 378 | ||
379 | rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); | 379 | rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); |
380 | if (dd->ipath_portcnt != rtmp) | 380 | if (dd->ipath_portcnt != rtmp) |
@@ -487,6 +487,7 @@ static void enable_chip(struct ipath_devdata *dd, | |||
487 | struct ipath_portdata *pd, int reinit) | 487 | struct ipath_portdata *pd, int reinit) |
488 | { | 488 | { |
489 | u32 val; | 489 | u32 val; |
490 | unsigned long flags; | ||
490 | int i; | 491 | int i; |
491 | 492 | ||
492 | if (!reinit) | 493 | if (!reinit) |
@@ -495,11 +496,13 @@ static void enable_chip(struct ipath_devdata *dd, | |||
495 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, | 496 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, |
496 | dd->ipath_rcvctrl); | 497 | dd->ipath_rcvctrl); |
497 | 498 | ||
499 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); | ||
498 | /* Enable PIO send, and update of PIOavail regs to memory. */ | 500 | /* Enable PIO send, and update of PIOavail regs to memory. */ |
499 | dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE | | 501 | dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE | |
500 | INFINIPATH_S_PIOBUFAVAILUPD; | 502 | INFINIPATH_S_PIOBUFAVAILUPD; |
501 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 503 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); |
502 | dd->ipath_sendctrl); | 504 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); |
505 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
503 | 506 | ||
504 | /* | 507 | /* |
505 | * enable port 0 receive, and receive interrupt. other ports | 508 | * enable port 0 receive, and receive interrupt. other ports |
@@ -696,6 +699,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) | |||
696 | u64 val; | 699 | u64 val; |
697 | struct ipath_portdata *pd = NULL; /* keep gcc4 happy */ | 700 | struct ipath_portdata *pd = NULL; /* keep gcc4 happy */ |
698 | gfp_t gfp_flags = GFP_USER | __GFP_COMP; | 701 | gfp_t gfp_flags = GFP_USER | __GFP_COMP; |
702 | unsigned long flags; | ||
699 | 703 | ||
700 | ret = init_housekeeping(dd, &pd, reinit); | 704 | ret = init_housekeeping(dd, &pd, reinit); |
701 | if (ret) | 705 | if (ret) |
@@ -827,8 +831,12 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) | |||
827 | ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, | 831 | ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, |
828 | ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED); | 832 | ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED); |
829 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL); | 833 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL); |
830 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 834 | |
831 | INFINIPATH_S_PIOENABLE); | 835 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); |
836 | dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE; | ||
837 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); | ||
838 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | ||
839 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
832 | 840 | ||
833 | /* | 841 | /* |
834 | * before error clears, since we expect serdes pll errors during | 842 | * before error clears, since we expect serdes pll errors during |
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index ad41cccd2e9f..eac2e9c55281 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c | |||
@@ -795,6 +795,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd) | |||
795 | { | 795 | { |
796 | int i, im; | 796 | int i, im; |
797 | __le64 val; | 797 | __le64 val; |
798 | unsigned long flags; | ||
798 | 799 | ||
799 | /* disable error interrupts, to avoid confusion */ | 800 | /* disable error interrupts, to avoid confusion */ |
800 | ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL); | 801 | ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL); |
@@ -813,11 +814,14 @@ void ipath_clear_freeze(struct ipath_devdata *dd) | |||
813 | dd->ipath_control); | 814 | dd->ipath_control); |
814 | 815 | ||
815 | /* ensure pio avail updates continue */ | 816 | /* ensure pio avail updates continue */ |
817 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); | ||
816 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 818 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
817 | dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD); | 819 | dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD); |
818 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | 820 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); |
819 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 821 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
820 | dd->ipath_sendctrl); | 822 | dd->ipath_sendctrl); |
823 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | ||
824 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
821 | 825 | ||
822 | /* | 826 | /* |
823 | * We just enabled pioavailupdate, so dma copy is almost certainly | 827 | * We just enabled pioavailupdate, so dma copy is almost certainly |
@@ -922,6 +926,7 @@ static noinline void ipath_bad_regread(struct ipath_devdata *dd) | |||
922 | 926 | ||
923 | static void handle_layer_pioavail(struct ipath_devdata *dd) | 927 | static void handle_layer_pioavail(struct ipath_devdata *dd) |
924 | { | 928 | { |
929 | unsigned long flags; | ||
925 | int ret; | 930 | int ret; |
926 | 931 | ||
927 | ret = ipath_ib_piobufavail(dd->verbs_dev); | 932 | ret = ipath_ib_piobufavail(dd->verbs_dev); |
@@ -930,9 +935,12 @@ static void handle_layer_pioavail(struct ipath_devdata *dd) | |||
930 | 935 | ||
931 | return; | 936 | return; |
932 | set: | 937 | set: |
933 | set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); | 938 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); |
939 | dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL; | ||
934 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 940 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
935 | dd->ipath_sendctrl); | 941 | dd->ipath_sendctrl); |
942 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | ||
943 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
936 | } | 944 | } |
937 | 945 | ||
938 | /* | 946 | /* |
@@ -1168,9 +1176,14 @@ irqreturn_t ipath_intr(int irq, void *data) | |||
1168 | handle_urcv(dd, istat); | 1176 | handle_urcv(dd, istat); |
1169 | 1177 | ||
1170 | if (istat & INFINIPATH_I_SPIOBUFAVAIL) { | 1178 | if (istat & INFINIPATH_I_SPIOBUFAVAIL) { |
1171 | clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); | 1179 | unsigned long flags; |
1180 | |||
1181 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); | ||
1182 | dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL; | ||
1172 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 1183 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
1173 | dd->ipath_sendctrl); | 1184 | dd->ipath_sendctrl); |
1185 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | ||
1186 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
1174 | 1187 | ||
1175 | handle_layer_pioavail(dd); | 1188 | handle_layer_pioavail(dd); |
1176 | } | 1189 | } |
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 65f7c7f7b5d9..81759c2031f9 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -376,6 +376,7 @@ struct ipath_devdata { | |||
376 | dma_addr_t *ipath_physshadow; | 376 | dma_addr_t *ipath_physshadow; |
377 | /* lock to workaround chip bug 9437 */ | 377 | /* lock to workaround chip bug 9437 */ |
378 | spinlock_t ipath_tid_lock; | 378 | spinlock_t ipath_tid_lock; |
379 | spinlock_t ipath_sendctrl_lock; | ||
379 | 380 | ||
380 | /* | 381 | /* |
381 | * IPATH_STATUS_*, | 382 | * IPATH_STATUS_*, |
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index 54c61a972de2..1b4f7e113b21 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c | |||
@@ -479,9 +479,14 @@ done: | |||
479 | 479 | ||
480 | static void want_buffer(struct ipath_devdata *dd) | 480 | static void want_buffer(struct ipath_devdata *dd) |
481 | { | 481 | { |
482 | set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); | 482 | unsigned long flags; |
483 | |||
484 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); | ||
485 | dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL; | ||
483 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, | 486 | ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, |
484 | dd->ipath_sendctrl); | 487 | dd->ipath_sendctrl); |
488 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | ||
489 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | ||
485 | } | 490 | } |
486 | 491 | ||
487 | /** | 492 | /** |