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: 62fa19d4b4
("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>
This commit is contained in:

committed by
Michael Ellerman

parent
65bc3ece84
commit
70b565bbdb
@@ -243,8 +243,10 @@ struct cxl *cxl_alloc_adapter(void)
|
||||
if (dev_set_name(&adapter->dev, "card%i", adapter->adapter_num))
|
||||
goto err2;
|
||||
|
||||
return adapter;
|
||||
/* start with context lock taken */
|
||||
atomic_set(&adapter->contexts_num, -1);
|
||||
|
||||
return adapter;
|
||||
err2:
|
||||
cxl_remove_adapter_nr(adapter);
|
||||
err1:
|
||||
@@ -286,6 +288,44 @@ int cxl_afu_select_best_mode(struct cxl_afu *afu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cxl_adapter_context_get(struct cxl *adapter)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = atomic_inc_unless_negative(&adapter->contexts_num);
|
||||
return rc >= 0 ? 0 : -EBUSY;
|
||||
}
|
||||
|
||||
void cxl_adapter_context_put(struct cxl *adapter)
|
||||
{
|
||||
atomic_dec_if_positive(&adapter->contexts_num);
|
||||
}
|
||||
|
||||
int cxl_adapter_context_lock(struct cxl *adapter)
|
||||
{
|
||||
int rc;
|
||||
/* no active contexts -> contexts_num == 0 */
|
||||
rc = atomic_cmpxchg(&adapter->contexts_num, 0, -1);
|
||||
return rc ? -EBUSY : 0;
|
||||
}
|
||||
|
||||
void cxl_adapter_context_unlock(struct cxl *adapter)
|
||||
{
|
||||
int val = atomic_cmpxchg(&adapter->contexts_num, -1, 0);
|
||||
|
||||
/*
|
||||
* contexts lock taken -> contexts_num == -1
|
||||
* If not true then show a warning and force reset the lock.
|
||||
* This will happen when context_unlock was requested without
|
||||
* doing a context_lock.
|
||||
*/
|
||||
if (val != -1) {
|
||||
atomic_set(&adapter->contexts_num, 0);
|
||||
WARN(1, "Adapter context unlocked with %d active contexts",
|
||||
val);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init init_cxl(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
Reference in New Issue
Block a user