diff options
Diffstat (limited to 'drivers/misc/cxl/native.c')
| -rw-r--r-- | drivers/misc/cxl/native.c | 119 | 
1 files changed, 97 insertions, 22 deletions
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 10567f245818..b37f2e8004f5 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -41,7 +41,14 @@ static int afu_control(struct cxl_afu *afu, u64 command,  			rc = -EBUSY;  			goto out;  		} -		pr_devel_ratelimited("AFU control... (0x%.16llx)\n", + +		if (!cxl_adapter_link_ok(afu->adapter)) { +			afu->enabled = enabled; +			rc = -EIO; +			goto out; +		} + +		pr_devel_ratelimited("AFU control... (0x%016llx)\n",  				     AFU_Cntl | command);  		cpu_relax();  		AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); @@ -85,6 +92,10 @@ int __cxl_afu_reset(struct cxl_afu *afu)  int cxl_afu_check_and_enable(struct cxl_afu *afu)  { +	if (!cxl_adapter_link_ok(afu->adapter)) { +		WARN(1, "Refusing to enable afu while link down!\n"); +		return -EIO; +	}  	if (afu->enabled)  		return 0;  	return afu_enable(afu); @@ -103,6 +114,12 @@ int cxl_psl_purge(struct cxl_afu *afu)  	pr_devel("PSL purge request\n"); +	if (!cxl_adapter_link_ok(afu->adapter)) { +		dev_warn(&afu->dev, "PSL Purge called with link down, ignoring\n"); +		rc = -EIO; +		goto out; +	} +  	if ((AFU_Cntl & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) {  		WARN(1, "psl_purge request while AFU not disabled!\n");  		cxl_afu_disable(afu); @@ -119,14 +136,19 @@ int cxl_psl_purge(struct cxl_afu *afu)  			rc = -EBUSY;  			goto out;  		} +		if (!cxl_adapter_link_ok(afu->adapter)) { +			rc = -EIO; +			goto out; +		} +  		dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An); -		pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%.16llx  PSL_DSISR: 0x%.16llx\n", PSL_CNTL, dsisr); +		pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%016llx  PSL_DSISR: 0x%016llx\n", PSL_CNTL, dsisr);  		if (dsisr & CXL_PSL_DSISR_TRANS) {  			dar = cxl_p2n_read(afu, CXL_PSL_DAR_An); -			dev_notice(&afu->dev, "PSL purge terminating pending translation, DSISR: 0x%.16llx, DAR: 0x%.16llx\n", dsisr, dar); +			dev_notice(&afu->dev, "PSL purge terminating pending translation, DSISR: 0x%016llx, DAR: 0x%016llx\n", dsisr, dar);  			cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);  		} else if (dsisr) { -			dev_notice(&afu->dev, "PSL purge acknowledging pending non-translation fault, DSISR: 0x%.16llx\n", dsisr); +			dev_notice(&afu->dev, "PSL purge acknowledging pending non-translation fault, DSISR: 0x%016llx\n", dsisr);  			cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);  		} else {  			cpu_relax(); @@ -161,10 +183,8 @@ static int spa_max_procs(int spa_size)  	return ((spa_size / 8) - 96) / 17;  } -static int alloc_spa(struct cxl_afu *afu) +int cxl_alloc_spa(struct cxl_afu *afu)  { -	u64 spap; -  	/* Work out how many pages to allocate */  	afu->spa_order = 0;  	do { @@ -183,6 +203,13 @@ static int alloc_spa(struct cxl_afu *afu)  	pr_devel("spa pages: %i afu->spa_max_procs: %i   afu->num_procs: %i\n",  		 1<<afu->spa_order, afu->spa_max_procs, afu->num_procs); +	return 0; +} + +static void attach_spa(struct cxl_afu *afu) +{ +	u64 spap; +  	afu->sw_command_status = (__be64 *)((char *)afu->spa +  					    ((afu->spa_max_procs + 3) * 128)); @@ -191,14 +218,19 @@ static int alloc_spa(struct cxl_afu *afu)  	spap |= CXL_PSL_SPAP_V;  	pr_devel("cxl: SPA allocated at 0x%p. Max processes: %i, sw_command_status: 0x%p CXL_PSL_SPAP_An=0x%016llx\n", afu->spa, afu->spa_max_procs, afu->sw_command_status, spap);  	cxl_p1n_write(afu, CXL_PSL_SPAP_An, spap); - -	return 0;  } -static void release_spa(struct cxl_afu *afu) +static inline void detach_spa(struct cxl_afu *afu)  {  	cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0); -	free_pages((unsigned long) afu->spa, afu->spa_order); +} + +void cxl_release_spa(struct cxl_afu *afu) +{ +	if (afu->spa) { +		free_pages((unsigned long) afu->spa, afu->spa_order); +		afu->spa = NULL; +	}  }  int cxl_tlb_slb_invalidate(struct cxl *adapter) @@ -215,6 +247,8 @@ int cxl_tlb_slb_invalidate(struct cxl *adapter)  			dev_warn(&adapter->dev, "WARNING: CXL adapter wide TLBIA timed out!\n");  			return -EBUSY;  		} +		if (!cxl_adapter_link_ok(adapter)) +			return -EIO;  		cpu_relax();  	} @@ -224,6 +258,8 @@ int cxl_tlb_slb_invalidate(struct cxl *adapter)  			dev_warn(&adapter->dev, "WARNING: CXL adapter wide SLBIA timed out!\n");  			return -EBUSY;  		} +		if (!cxl_adapter_link_ok(adapter)) +			return -EIO;  		cpu_relax();  	}  	return 0; @@ -240,6 +276,11 @@ int cxl_afu_slbia(struct cxl_afu *afu)  			dev_warn(&afu->dev, "WARNING: CXL AFU SLBIA timed out!\n");  			return -EBUSY;  		} +		/* If the adapter has gone down, we can assume that we +		 * will PERST it and that will invalidate everything. +		 */ +		if (!cxl_adapter_link_ok(afu->adapter)) +			return -EIO;  		cpu_relax();  	}  	return 0; @@ -279,6 +320,8 @@ static void slb_invalid(struct cxl_context *ctx)  	cxl_p1_write(adapter, CXL_PSL_SLBIA, CXL_TLB_SLB_IQ_LPIDPID);  	while (1) { +		if (!cxl_adapter_link_ok(adapter)) +			break;  		slbia = cxl_p1_read(adapter, CXL_PSL_SLBIA);  		if (!(slbia & CXL_TLB_SLB_P))  			break; @@ -308,6 +351,11 @@ static int do_process_element_cmd(struct cxl_context *ctx,  			rc = -EBUSY;  			goto out;  		} +		if (!cxl_adapter_link_ok(ctx->afu->adapter)) { +			dev_warn(&ctx->afu->dev, "WARNING: Device link down, aborting Process Element Command!\n"); +			rc = -EIO; +			goto out; +		}  		state = be64_to_cpup(ctx->afu->sw_command_status);  		if (state == ~0ULL) {  			pr_err("cxl: Error adding process element to AFU\n"); @@ -355,8 +403,13 @@ static int terminate_process_element(struct cxl_context *ctx)  	mutex_lock(&ctx->afu->spa_mutex);  	pr_devel("%s Terminate pe: %i started\n", __func__, ctx->pe); -	rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_TERMINATE, -				    CXL_PE_SOFTWARE_STATE_V | CXL_PE_SOFTWARE_STATE_T); +	/* We could be asked to terminate when the hw is down. That +	 * should always succeed: it's not running if the hw has gone +	 * away and is being reset. +	 */ +	if (cxl_adapter_link_ok(ctx->afu->adapter)) +		rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_TERMINATE, +					    CXL_PE_SOFTWARE_STATE_V | CXL_PE_SOFTWARE_STATE_T);  	ctx->elem->software_state = 0;	/* Remove Valid bit */  	pr_devel("%s Terminate pe: %i finished\n", __func__, ctx->pe);  	mutex_unlock(&ctx->afu->spa_mutex); @@ -369,7 +422,14 @@ static int remove_process_element(struct cxl_context *ctx)  	mutex_lock(&ctx->afu->spa_mutex);  	pr_devel("%s Remove pe: %i started\n", __func__, ctx->pe); -	if (!(rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_REMOVE, 0))) + +	/* We could be asked to remove when the hw is down. Again, if +	 * the hw is down, the PE is gone, so we succeed. +	 */ +	if (cxl_adapter_link_ok(ctx->afu->adapter)) +		rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_REMOVE, 0); + +	if (!rc)  		ctx->pe_inserted = false;  	slb_invalid(ctx);  	pr_devel("%s Remove pe: %i finished\n", __func__, ctx->pe); @@ -397,8 +457,11 @@ static int activate_afu_directed(struct cxl_afu *afu)  	dev_info(&afu->dev, "Activating AFU directed mode\n"); -	if (alloc_spa(afu)) -		return -ENOMEM; +	if (afu->spa == NULL) { +		if (cxl_alloc_spa(afu)) +			return -ENOMEM; +	} +	attach_spa(afu);  	cxl_p1n_write(afu, CXL_PSL_SCNTL_An, CXL_PSL_SCNTL_An_PM_AFU);  	cxl_p1n_write(afu, CXL_PSL_AMOR_An, 0xFFFFFFFFFFFFFFFFULL); @@ -492,9 +555,7 @@ static int attach_afu_directed(struct cxl_context *ctx, u64 wed, u64 amr)  	if ((result = cxl_afu_check_and_enable(ctx->afu)))  		return result; -	add_process_element(ctx); - -	return 0; +	return add_process_element(ctx);  }  static int deactivate_afu_directed(struct cxl_afu *afu) @@ -511,8 +572,6 @@ static int deactivate_afu_directed(struct cxl_afu *afu)  	cxl_afu_disable(afu);  	cxl_psl_purge(afu); -	release_spa(afu); -  	return 0;  } @@ -614,6 +673,11 @@ int cxl_afu_activate_mode(struct cxl_afu *afu, int mode)  	if (!(mode & afu->modes_supported))  		return -EINVAL; +	if (!cxl_adapter_link_ok(afu->adapter)) { +		WARN(1, "Device link is down, refusing to activate!\n"); +		return -EIO; +	} +  	if (mode == CXL_MODE_DIRECTED)  		return activate_afu_directed(afu);  	if (mode == CXL_MODE_DEDICATED) @@ -624,6 +688,11 @@ int cxl_afu_activate_mode(struct cxl_afu *afu, int mode)  int cxl_attach_process(struct cxl_context *ctx, bool kernel, u64 wed, u64 amr)  { +	if (!cxl_adapter_link_ok(ctx->afu->adapter)) { +		WARN(1, "Device link is down, refusing to attach process!\n"); +		return -EIO; +	} +  	ctx->kernel = kernel;  	if (ctx->afu->current_mode == CXL_MODE_DIRECTED)  		return attach_afu_directed(ctx, wed, amr); @@ -668,6 +737,12 @@ int cxl_get_irq(struct cxl_afu *afu, struct cxl_irq_info *info)  {  	u64 pidtid; +	/* If the adapter has gone away, we can't get any meaningful +	 * information. +	 */ +	if (!cxl_adapter_link_ok(afu->adapter)) +		return -EIO; +  	info->dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);  	info->dar = cxl_p2n_read(afu, CXL_PSL_DAR_An);  	info->dsr = cxl_p2n_read(afu, CXL_PSL_DSR_An); @@ -684,7 +759,7 @@ static void recover_psl_err(struct cxl_afu *afu, u64 errstat)  {  	u64 dsisr; -	pr_devel("RECOVERING FROM PSL ERROR... (0x%.16llx)\n", errstat); +	pr_devel("RECOVERING FROM PSL ERROR... (0x%016llx)\n", errstat);  	/* Clear PSL_DSISR[PE] */  	dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);  |