aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/cxl
diff options
context:
space:
mode:
authorVaibhav Jain <vaibhav@linux.vnet.ibm.com>2016-10-14 05:38:36 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2016-10-19 05:35:39 -0400
commit70b565bbdb911023373e035225ab10077e4ab937 (patch)
treecc2d84c644b647a89b3ffa26953e4194127a95f4 /drivers/misc/cxl
parent65bc3ece84ef6340cbd80eec10ab9be3426e1149 (diff)
cxl: Prevent adapter reset if an active context exists
This patch prevents resetting the cxl adapter via sysfs in presence of one or more active cxl_context on it. This protects against an unrecoverable error caused by PSL owning a dirty cache line even after reset and host tries to touch the same cache line. In case a force reset of the card is required irrespective of any active contexts, the int value -1 can be stored in the 'reset' sysfs attribute of the card. The patch introduces a new atomic_t member named contexts_num inside struct cxl that holds the number of active context attached to the card , which is checked against '0' before proceeding with the reset. To prevent against a race condition where a context is activated just after reset check is performed, the contexts_num is atomically set to '-1' after reset-check to indicate that no more contexts can be activated on the card anymore. Before activating a context we atomically test if contexts_num is non-negative and if so, increment its value by one. In case the value of contexts_num is negative then it indicates that the card is about to be reset and context activation is error-ed out at that point. Fixes: 62fa19d4b4fd ("cxl: Add ability to reset the card") Cc: stable@vger.kernel.org # v4.0+ Acked-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com> Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> Signed-off-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/misc/cxl')
-rw-r--r--drivers/misc/cxl/api.c9
-rw-r--r--drivers/misc/cxl/context.c3
-rw-r--r--drivers/misc/cxl/cxl.h24
-rw-r--r--drivers/misc/cxl/file.c11
-rw-r--r--drivers/misc/cxl/guest.c3
-rw-r--r--drivers/misc/cxl/main.c42
-rw-r--r--drivers/misc/cxl/pci.c2
-rw-r--r--drivers/misc/cxl/sysfs.c27
8 files changed, 116 insertions, 5 deletions
diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c
index f3d34b941f85..af23d7dfe752 100644
--- a/drivers/misc/cxl/api.c
+++ b/drivers/misc/cxl/api.c
@@ -229,6 +229,14 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed,
229 if (ctx->status == STARTED) 229 if (ctx->status == STARTED)
230 goto out; /* already started */ 230 goto out; /* already started */
231 231
232 /*
233 * Increment the mapped context count for adapter. This also checks
234 * if adapter_context_lock is taken.
235 */
236 rc = cxl_adapter_context_get(ctx->afu->adapter);
237 if (rc)
238 goto out;
239
232 if (task) { 240 if (task) {
233 ctx->pid = get_task_pid(task, PIDTYPE_PID); 241 ctx->pid = get_task_pid(task, PIDTYPE_PID);
234 ctx->glpid = get_task_pid(task->group_leader, PIDTYPE_PID); 242 ctx->glpid = get_task_pid(task->group_leader, PIDTYPE_PID);
@@ -240,6 +248,7 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed,
240 248
241 if ((rc = cxl_ops->attach_process(ctx, kernel, wed, 0))) { 249 if ((rc = cxl_ops->attach_process(ctx, kernel, wed, 0))) {
242 put_pid(ctx->pid); 250 put_pid(ctx->pid);
251 cxl_adapter_context_put(ctx->afu->adapter);
243 cxl_ctx_put(); 252 cxl_ctx_put();
244 goto out; 253 goto out;
245 } 254 }
diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c
index c466ee2b0c97..5e506c19108a 100644
--- a/drivers/misc/cxl/context.c
+++ b/drivers/misc/cxl/context.c
@@ -238,6 +238,9 @@ int __detach_context(struct cxl_context *ctx)
238 put_pid(ctx->glpid); 238 put_pid(ctx->glpid);
239 239
240 cxl_ctx_put(); 240 cxl_ctx_put();
241
242 /* Decrease the attached context count on the adapter */
243 cxl_adapter_context_put(ctx->afu->adapter);
241 return 0; 244 return 0;
242} 245}
243 246
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
index 01d372aba131..a144073593fa 100644
--- a/drivers/misc/cxl/cxl.h
+++ b/drivers/misc/cxl/cxl.h
@@ -618,6 +618,14 @@ struct cxl {
618 bool perst_select_user; 618 bool perst_select_user;
619 bool perst_same_image; 619 bool perst_same_image;
620 bool psl_timebase_synced; 620 bool psl_timebase_synced;
621
622 /*
623 * number of contexts mapped on to this card. Possible values are:
624 * >0: Number of contexts mapped and new one can be mapped.
625 * 0: No active contexts and new ones can be mapped.
626 * -1: No contexts mapped and new ones cannot be mapped.
627 */
628 atomic_t contexts_num;
621}; 629};
622 630
623int cxl_pci_alloc_one_irq(struct cxl *adapter); 631int cxl_pci_alloc_one_irq(struct cxl *adapter);
@@ -944,4 +952,20 @@ bool cxl_pci_is_vphb_device(struct pci_dev *dev);
944 952
945/* decode AFU error bits in the PSL register PSL_SERR_An */ 953/* decode AFU error bits in the PSL register PSL_SERR_An */
946void cxl_afu_decode_psl_serr(struct cxl_afu *afu, u64 serr); 954void cxl_afu_decode_psl_serr(struct cxl_afu *afu, u64 serr);
955
956/*
957 * Increments the number of attached contexts on an adapter.
958 * In case an adapter_context_lock is taken the return -EBUSY.
959 */
960int cxl_adapter_context_get(struct cxl *adapter);
961
962/* Decrements the number of attached contexts on an adapter */
963void cxl_adapter_context_put(struct cxl *adapter);
964
965/* If no active contexts then prevents contexts from being attached */
966int cxl_adapter_context_lock(struct cxl *adapter);
967
968/* Unlock the contexts-lock if taken. Warn and force unlock otherwise */
969void cxl_adapter_context_unlock(struct cxl *adapter);
970
947#endif 971#endif
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
index 5fb9894b157f..d0b421f49b39 100644
--- a/drivers/misc/cxl/file.c
+++ b/drivers/misc/cxl/file.c
@@ -205,11 +205,22 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
205 ctx->pid = get_task_pid(current, PIDTYPE_PID); 205 ctx->pid = get_task_pid(current, PIDTYPE_PID);
206 ctx->glpid = get_task_pid(current->group_leader, PIDTYPE_PID); 206 ctx->glpid = get_task_pid(current->group_leader, PIDTYPE_PID);
207 207
208 /*
209 * Increment the mapped context count for adapter. This also checks
210 * if adapter_context_lock is taken.
211 */
212 rc = cxl_adapter_context_get(ctx->afu->adapter);
213 if (rc) {
214 afu_release_irqs(ctx, ctx);
215 goto out;
216 }
217
208 trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr); 218 trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr);
209 219
210 if ((rc = cxl_ops->attach_process(ctx, false, work.work_element_descriptor, 220 if ((rc = cxl_ops->attach_process(ctx, false, work.work_element_descriptor,
211 amr))) { 221 amr))) {
212 afu_release_irqs(ctx, ctx); 222 afu_release_irqs(ctx, ctx);
223 cxl_adapter_context_put(ctx->afu->adapter);
213 goto out; 224 goto out;
214 } 225 }
215 226
diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c
index 9aa58a77a24d..3e102cd6ed91 100644
--- a/drivers/misc/cxl/guest.c
+++ b/drivers/misc/cxl/guest.c
@@ -1152,6 +1152,9 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic
1152 if ((rc = cxl_sysfs_adapter_add(adapter))) 1152 if ((rc = cxl_sysfs_adapter_add(adapter)))
1153 goto err_put1; 1153 goto err_put1;
1154 1154
1155 /* release the context lock as the adapter is configured */
1156 cxl_adapter_context_unlock(adapter);
1157
1155 return adapter; 1158 return adapter;
1156 1159
1157err_put1: 1160err_put1:
diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c
index d9be23b24aa3..62e0dfb5f15b 100644
--- a/drivers/misc/cxl/main.c
+++ b/drivers/misc/cxl/main.c
@@ -243,8 +243,10 @@ struct cxl *cxl_alloc_adapter(void)
243 if (dev_set_name(&adapter->dev, "card%i", adapter->adapter_num)) 243 if (dev_set_name(&adapter->dev, "card%i", adapter->adapter_num))
244 goto err2; 244 goto err2;
245 245
246 return adapter; 246 /* start with context lock taken */
247 atomic_set(&adapter->contexts_num, -1);
247 248
249 return adapter;
248err2: 250err2:
249 cxl_remove_adapter_nr(adapter); 251 cxl_remove_adapter_nr(adapter);
250err1: 252err1:
@@ -286,6 +288,44 @@ int cxl_afu_select_best_mode(struct cxl_afu *afu)
286 return 0; 288 return 0;
287} 289}
288 290
291int cxl_adapter_context_get(struct cxl *adapter)
292{
293 int rc;
294
295 rc = atomic_inc_unless_negative(&adapter->contexts_num);
296 return rc >= 0 ? 0 : -EBUSY;
297}
298
299void cxl_adapter_context_put(struct cxl *adapter)
300{
301 atomic_dec_if_positive(&adapter->contexts_num);
302}
303
304int cxl_adapter_context_lock(struct cxl *adapter)
305{
306 int rc;
307 /* no active contexts -> contexts_num == 0 */
308 rc = atomic_cmpxchg(&adapter->contexts_num, 0, -1);
309 return rc ? -EBUSY : 0;
310}
311
312void cxl_adapter_context_unlock(struct cxl *adapter)
313{
314 int val = atomic_cmpxchg(&adapter->contexts_num, -1, 0);
315
316 /*
317 * contexts lock taken -> contexts_num == -1
318 * If not true then show a warning and force reset the lock.
319 * This will happen when context_unlock was requested without
320 * doing a context_lock.
321 */
322 if (val != -1) {
323 atomic_set(&adapter->contexts_num, 0);
324 WARN(1, "Adapter context unlocked with %d active contexts",
325 val);
326 }
327}
328
289static int __init init_cxl(void) 329static int __init init_cxl(void)
290{ 330{
291 int rc = 0; 331 int rc = 0;
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index 7afad8477ad5..e96be9ca4e60 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -1487,6 +1487,8 @@ static int cxl_configure_adapter(struct cxl *adapter, struct pci_dev *dev)
1487 if ((rc = cxl_native_register_psl_err_irq(adapter))) 1487 if ((rc = cxl_native_register_psl_err_irq(adapter)))
1488 goto err; 1488 goto err;
1489 1489
1490 /* Release the context lock as adapter is configured */
1491 cxl_adapter_context_unlock(adapter);
1490 return 0; 1492 return 0;
1491 1493
1492err: 1494err:
diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c
index b043c20f158f..a8b6d6a635e9 100644
--- a/drivers/misc/cxl/sysfs.c
+++ b/drivers/misc/cxl/sysfs.c
@@ -75,12 +75,31 @@ static ssize_t reset_adapter_store(struct device *device,
75 int val; 75 int val;
76 76
77 rc = sscanf(buf, "%i", &val); 77 rc = sscanf(buf, "%i", &val);
78 if ((rc != 1) || (val != 1)) 78 if ((rc != 1) || (val != 1 && val != -1))
79 return -EINVAL; 79 return -EINVAL;
80 80
81 if ((rc = cxl_ops->adapter_reset(adapter))) 81 /*
82 return rc; 82 * See if we can lock the context mapping that's only allowed
83 return count; 83 * when there are no contexts attached to the adapter. Once
84 * taken this will also prevent any context from getting activated.
85 */
86 if (val == 1) {
87 rc = cxl_adapter_context_lock(adapter);
88 if (rc)
89 goto out;
90
91 rc = cxl_ops->adapter_reset(adapter);
92 /* In case reset failed release context lock */
93 if (rc)
94 cxl_adapter_context_unlock(adapter);
95
96 } else if (val == -1) {
97 /* Perform a forced adapter reset */
98 rc = cxl_ops->adapter_reset(adapter);
99 }
100
101out:
102 return rc ? rc : count;
84} 103}
85 104
86static ssize_t load_image_on_perst_show(struct device *device, 105static ssize_t load_image_on_perst_show(struct device *device,