diff options
author | Joachim Fenkes <fenkes@de.ibm.com> | 2007-09-11 09:34:35 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-10-09 22:59:11 -0400 |
commit | 0b5de96858e516311f2d3ca45073c2afd2eb5d94 (patch) | |
tree | 83fbe9083a68e5a1456a44111dd823b49c71e69a /drivers/infiniband/hw/ehca | |
parent | e90d0b3daede2bae2e78f8bf88c19182961cd19d (diff) |
IB/ehca: Serialize MR alloc and MR free hvCalls
Some firmware levels exhibit a race condition between H_ALLOC_RESOURCE(MR)
and H_FREE_RESOURCE(MR). Work around this problem by locking these hvCalls
against each other.
Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ehca')
-rw-r--r-- | drivers/infiniband/hw/ehca/hcp_if.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index 3d68f6536f9c..c16a21374bb5 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c | |||
@@ -120,15 +120,28 @@ static long ehca_plpar_hcall_norets(unsigned long opcode, | |||
120 | unsigned long arg7) | 120 | unsigned long arg7) |
121 | { | 121 | { |
122 | long ret; | 122 | long ret; |
123 | int i, sleep_msecs; | 123 | int i, sleep_msecs, do_lock; |
124 | unsigned long flags; | ||
124 | 125 | ||
125 | ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, | 126 | ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, |
126 | opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); | 127 | opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); |
127 | 128 | ||
129 | /* lock H_FREE_RESOURCE(MR) against itself and H_ALLOC_RESOURCE(MR) */ | ||
130 | if ((opcode == H_FREE_RESOURCE) && (arg7 == 5)) { | ||
131 | arg7 = 0; /* better not upset firmware */ | ||
132 | do_lock = 1; | ||
133 | } | ||
134 | |||
128 | for (i = 0; i < 5; i++) { | 135 | for (i = 0; i < 5; i++) { |
136 | if (do_lock) | ||
137 | spin_lock_irqsave(&hcall_lock, flags); | ||
138 | |||
129 | ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, | 139 | ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, |
130 | arg5, arg6, arg7); | 140 | arg5, arg6, arg7); |
131 | 141 | ||
142 | if (do_lock) | ||
143 | spin_unlock_irqrestore(&hcall_lock, flags); | ||
144 | |||
132 | if (H_IS_LONG_BUSY(ret)) { | 145 | if (H_IS_LONG_BUSY(ret)) { |
133 | sleep_msecs = get_longbusy_msecs(ret); | 146 | sleep_msecs = get_longbusy_msecs(ret); |
134 | msleep_interruptible(sleep_msecs); | 147 | msleep_interruptible(sleep_msecs); |
@@ -161,23 +174,24 @@ static long ehca_plpar_hcall9(unsigned long opcode, | |||
161 | unsigned long arg9) | 174 | unsigned long arg9) |
162 | { | 175 | { |
163 | long ret; | 176 | long ret; |
164 | int i, sleep_msecs, lock_is_set = 0; | 177 | int i, sleep_msecs, do_lock; |
165 | unsigned long flags = 0; | 178 | unsigned long flags = 0; |
166 | 179 | ||
167 | ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, | 180 | ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, |
168 | arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); | 181 | arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); |
169 | 182 | ||
183 | /* lock H_ALLOC_RESOURCE(MR) against itself and H_FREE_RESOURCE(MR) */ | ||
184 | do_lock = ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)); | ||
185 | |||
170 | for (i = 0; i < 5; i++) { | 186 | for (i = 0; i < 5; i++) { |
171 | if ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)) { | 187 | if (do_lock) |
172 | spin_lock_irqsave(&hcall_lock, flags); | 188 | spin_lock_irqsave(&hcall_lock, flags); |
173 | lock_is_set = 1; | ||
174 | } | ||
175 | 189 | ||
176 | ret = plpar_hcall9(opcode, outs, | 190 | ret = plpar_hcall9(opcode, outs, |
177 | arg1, arg2, arg3, arg4, arg5, | 191 | arg1, arg2, arg3, arg4, arg5, |
178 | arg6, arg7, arg8, arg9); | 192 | arg6, arg7, arg8, arg9); |
179 | 193 | ||
180 | if (lock_is_set) | 194 | if (do_lock) |
181 | spin_unlock_irqrestore(&hcall_lock, flags); | 195 | spin_unlock_irqrestore(&hcall_lock, flags); |
182 | 196 | ||
183 | if (H_IS_LONG_BUSY(ret)) { | 197 | if (H_IS_LONG_BUSY(ret)) { |
@@ -807,7 +821,7 @@ u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle, | |||
807 | return ehca_plpar_hcall_norets(H_FREE_RESOURCE, | 821 | return ehca_plpar_hcall_norets(H_FREE_RESOURCE, |
808 | adapter_handle.handle, /* r4 */ | 822 | adapter_handle.handle, /* r4 */ |
809 | mr->ipz_mr_handle.handle, /* r5 */ | 823 | mr->ipz_mr_handle.handle, /* r5 */ |
810 | 0, 0, 0, 0, 0); | 824 | 0, 0, 0, 0, 5); |
811 | } | 825 | } |
812 | 826 | ||
813 | u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle, | 827 | u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle, |