diff options
author | Joachim Fenkes <fenkes@de.ibm.com> | 2007-12-10 12:59:10 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-12-12 17:09:43 -0500 |
commit | 4faf7757955239c1b259e7dab224d4638a99b456 (patch) | |
tree | d6e56aef1706cf26c0daa67bad150cb88ad7f52f | |
parent | 1457edc72d187f452be1374c7d9281f1dfa16f32 (diff) |
IB/ehca: Serialize HCA-related hCalls if necessary
Several pSeries firmware versions share a rare locking issue in the
HCA-related hCalls. Check for a feature flag that indicates the issue
being fixed and serialize all HCA hCalls if not.
Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_main.c | 13 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/hcp_if.c | 28 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/hipz_hw.h | 1 |
3 files changed, 25 insertions, 17 deletions
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 90d4334179bf..c7bff3ee9ab9 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #ifdef CONFIG_PPC_64K_PAGES | 43 | #ifdef CONFIG_PPC_64K_PAGES |
44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
45 | #endif | 45 | #endif |
46 | |||
46 | #include "ehca_classes.h" | 47 | #include "ehca_classes.h" |
47 | #include "ehca_iverbs.h" | 48 | #include "ehca_iverbs.h" |
48 | #include "ehca_mrmw.h" | 49 | #include "ehca_mrmw.h" |
@@ -66,6 +67,7 @@ int ehca_poll_all_eqs = 1; | |||
66 | int ehca_static_rate = -1; | 67 | int ehca_static_rate = -1; |
67 | int ehca_scaling_code = 0; | 68 | int ehca_scaling_code = 0; |
68 | int ehca_mr_largepage = 1; | 69 | int ehca_mr_largepage = 1; |
70 | int ehca_lock_hcalls = -1; | ||
69 | 71 | ||
70 | module_param_named(open_aqp1, ehca_open_aqp1, int, S_IRUGO); | 72 | module_param_named(open_aqp1, ehca_open_aqp1, int, S_IRUGO); |
71 | module_param_named(debug_level, ehca_debug_level, int, S_IRUGO); | 73 | module_param_named(debug_level, ehca_debug_level, int, S_IRUGO); |
@@ -77,6 +79,7 @@ module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, S_IRUGO); | |||
77 | module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); | 79 | module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); |
78 | module_param_named(scaling_code, ehca_scaling_code, int, S_IRUGO); | 80 | module_param_named(scaling_code, ehca_scaling_code, int, S_IRUGO); |
79 | module_param_named(mr_largepage, ehca_mr_largepage, int, S_IRUGO); | 81 | module_param_named(mr_largepage, ehca_mr_largepage, int, S_IRUGO); |
82 | module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO); | ||
80 | 83 | ||
81 | MODULE_PARM_DESC(open_aqp1, | 84 | MODULE_PARM_DESC(open_aqp1, |
82 | "AQP1 on startup (0: no (default), 1: yes)"); | 85 | "AQP1 on startup (0: no (default), 1: yes)"); |
@@ -102,6 +105,9 @@ MODULE_PARM_DESC(scaling_code, | |||
102 | MODULE_PARM_DESC(mr_largepage, | 105 | MODULE_PARM_DESC(mr_largepage, |
103 | "use large page for MR (0: use PAGE_SIZE (default), " | 106 | "use large page for MR (0: use PAGE_SIZE (default), " |
104 | "1: use large page depending on MR size"); | 107 | "1: use large page depending on MR size"); |
108 | MODULE_PARM_DESC(lock_hcalls, | ||
109 | "serialize all hCalls made by the driver " | ||
110 | "(default: autodetect)"); | ||
105 | 111 | ||
106 | DEFINE_RWLOCK(ehca_qp_idr_lock); | 112 | DEFINE_RWLOCK(ehca_qp_idr_lock); |
107 | DEFINE_RWLOCK(ehca_cq_idr_lock); | 113 | DEFINE_RWLOCK(ehca_cq_idr_lock); |
@@ -258,6 +264,7 @@ static struct cap_descr { | |||
258 | { HCA_CAP_UD_LL_QP, "HCA_CAP_UD_LL_QP" }, | 264 | { HCA_CAP_UD_LL_QP, "HCA_CAP_UD_LL_QP" }, |
259 | { HCA_CAP_RESIZE_MR, "HCA_CAP_RESIZE_MR" }, | 265 | { HCA_CAP_RESIZE_MR, "HCA_CAP_RESIZE_MR" }, |
260 | { HCA_CAP_MINI_QP, "HCA_CAP_MINI_QP" }, | 266 | { HCA_CAP_MINI_QP, "HCA_CAP_MINI_QP" }, |
267 | { HCA_CAP_H_ALLOC_RES_SYNC, "HCA_CAP_H_ALLOC_RES_SYNC" }, | ||
261 | }; | 268 | }; |
262 | 269 | ||
263 | static int ehca_sense_attributes(struct ehca_shca *shca) | 270 | static int ehca_sense_attributes(struct ehca_shca *shca) |
@@ -333,6 +340,12 @@ static int ehca_sense_attributes(struct ehca_shca *shca) | |||
333 | if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap)) | 340 | if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap)) |
334 | ehca_gen_dbg(" %s", hca_cap_descr[i].descr); | 341 | ehca_gen_dbg(" %s", hca_cap_descr[i].descr); |
335 | 342 | ||
343 | /* Autodetect hCall locking -- the "H_ALLOC_RESOURCE synced" flag is | ||
344 | * a firmware property, so it's valid across all adapters | ||
345 | */ | ||
346 | if (ehca_lock_hcalls == -1) | ||
347 | ehca_lock_hcalls = !(shca->hca_cap & HCA_CAP_H_ALLOC_RES_SYNC); | ||
348 | |||
336 | /* translate supported MR page sizes; always support 4K */ | 349 | /* translate supported MR page sizes; always support 4K */ |
337 | shca->hca_cap_mr_pgsize = EHCA_PAGESIZE; | 350 | shca->hca_cap_mr_pgsize = EHCA_PAGESIZE; |
338 | if (ehca_mr_largepage) { /* support extra sizes only if enabled */ | 351 | if (ehca_mr_largepage) { /* support extra sizes only if enabled */ |
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index c16a21374bb5..331b5e82ef77 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c | |||
@@ -89,6 +89,7 @@ | |||
89 | #define HCALL9_REGS_FORMAT HCALL7_REGS_FORMAT " r11=%lx r12=%lx" | 89 | #define HCALL9_REGS_FORMAT HCALL7_REGS_FORMAT " r11=%lx r12=%lx" |
90 | 90 | ||
91 | static DEFINE_SPINLOCK(hcall_lock); | 91 | static DEFINE_SPINLOCK(hcall_lock); |
92 | extern int ehca_lock_hcalls; | ||
92 | 93 | ||
93 | static u32 get_longbusy_msecs(int longbusy_rc) | 94 | static u32 get_longbusy_msecs(int longbusy_rc) |
94 | { | 95 | { |
@@ -120,26 +121,21 @@ static long ehca_plpar_hcall_norets(unsigned long opcode, | |||
120 | unsigned long arg7) | 121 | unsigned long arg7) |
121 | { | 122 | { |
122 | long ret; | 123 | long ret; |
123 | int i, sleep_msecs, do_lock; | 124 | int i, sleep_msecs; |
124 | unsigned long flags; | 125 | unsigned long flags = 0; |
125 | 126 | ||
126 | ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, | 127 | ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, |
127 | opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); | 128 | opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); |
128 | 129 | ||
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 | |||
135 | for (i = 0; i < 5; i++) { | 130 | for (i = 0; i < 5; i++) { |
136 | if (do_lock) | 131 | /* serialize hCalls to work around firmware issue */ |
132 | if (ehca_lock_hcalls) | ||
137 | spin_lock_irqsave(&hcall_lock, flags); | 133 | spin_lock_irqsave(&hcall_lock, flags); |
138 | 134 | ||
139 | ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, | 135 | ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, |
140 | arg5, arg6, arg7); | 136 | arg5, arg6, arg7); |
141 | 137 | ||
142 | if (do_lock) | 138 | if (ehca_lock_hcalls) |
143 | spin_unlock_irqrestore(&hcall_lock, flags); | 139 | spin_unlock_irqrestore(&hcall_lock, flags); |
144 | 140 | ||
145 | if (H_IS_LONG_BUSY(ret)) { | 141 | if (H_IS_LONG_BUSY(ret)) { |
@@ -174,24 +170,22 @@ static long ehca_plpar_hcall9(unsigned long opcode, | |||
174 | unsigned long arg9) | 170 | unsigned long arg9) |
175 | { | 171 | { |
176 | long ret; | 172 | long ret; |
177 | int i, sleep_msecs, do_lock; | 173 | int i, sleep_msecs; |
178 | unsigned long flags = 0; | 174 | unsigned long flags = 0; |
179 | 175 | ||
180 | ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, | 176 | ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, |
181 | arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); | 177 | arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); |
182 | 178 | ||
183 | /* lock H_ALLOC_RESOURCE(MR) against itself and H_FREE_RESOURCE(MR) */ | ||
184 | do_lock = ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)); | ||
185 | |||
186 | for (i = 0; i < 5; i++) { | 179 | for (i = 0; i < 5; i++) { |
187 | if (do_lock) | 180 | /* serialize hCalls to work around firmware issue */ |
181 | if (ehca_lock_hcalls) | ||
188 | spin_lock_irqsave(&hcall_lock, flags); | 182 | spin_lock_irqsave(&hcall_lock, flags); |
189 | 183 | ||
190 | ret = plpar_hcall9(opcode, outs, | 184 | ret = plpar_hcall9(opcode, outs, |
191 | arg1, arg2, arg3, arg4, arg5, | 185 | arg1, arg2, arg3, arg4, arg5, |
192 | arg6, arg7, arg8, arg9); | 186 | arg6, arg7, arg8, arg9); |
193 | 187 | ||
194 | if (do_lock) | 188 | if (ehca_lock_hcalls) |
195 | spin_unlock_irqrestore(&hcall_lock, flags); | 189 | spin_unlock_irqrestore(&hcall_lock, flags); |
196 | 190 | ||
197 | if (H_IS_LONG_BUSY(ret)) { | 191 | if (H_IS_LONG_BUSY(ret)) { |
@@ -821,7 +815,7 @@ u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle, | |||
821 | return ehca_plpar_hcall_norets(H_FREE_RESOURCE, | 815 | return ehca_plpar_hcall_norets(H_FREE_RESOURCE, |
822 | adapter_handle.handle, /* r4 */ | 816 | adapter_handle.handle, /* r4 */ |
823 | mr->ipz_mr_handle.handle, /* r5 */ | 817 | mr->ipz_mr_handle.handle, /* r5 */ |
824 | 0, 0, 0, 0, 5); | 818 | 0, 0, 0, 0, 0); |
825 | } | 819 | } |
826 | 820 | ||
827 | u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle, | 821 | u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle, |
diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h index 485b8400359e..bf996c7acc42 100644 --- a/drivers/infiniband/hw/ehca/hipz_hw.h +++ b/drivers/infiniband/hw/ehca/hipz_hw.h | |||
@@ -378,6 +378,7 @@ struct hipz_query_hca { | |||
378 | #define HCA_CAP_UD_LL_QP EHCA_BMASK_IBM(16, 16) | 378 | #define HCA_CAP_UD_LL_QP EHCA_BMASK_IBM(16, 16) |
379 | #define HCA_CAP_RESIZE_MR EHCA_BMASK_IBM(17, 17) | 379 | #define HCA_CAP_RESIZE_MR EHCA_BMASK_IBM(17, 17) |
380 | #define HCA_CAP_MINI_QP EHCA_BMASK_IBM(18, 18) | 380 | #define HCA_CAP_MINI_QP EHCA_BMASK_IBM(18, 18) |
381 | #define HCA_CAP_H_ALLOC_RES_SYNC EHCA_BMASK_IBM(19, 19) | ||
381 | 382 | ||
382 | /* query port response block */ | 383 | /* query port response block */ |
383 | struct hipz_query_port { | 384 | struct hipz_query_port { |