xref: /kernel/linux/linux-6.6/drivers/misc/cxl/native.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2014 IBM Corp.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/spinlock.h>
762306a36Sopenharmony_ci#include <linux/sched.h>
862306a36Sopenharmony_ci#include <linux/sched/clock.h>
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/mutex.h>
1162306a36Sopenharmony_ci#include <linux/mm.h>
1262306a36Sopenharmony_ci#include <linux/uaccess.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/irqdomain.h>
1562306a36Sopenharmony_ci#include <asm/synch.h>
1662306a36Sopenharmony_ci#include <asm/switch_to.h>
1762306a36Sopenharmony_ci#include <misc/cxl-base.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "cxl.h"
2062306a36Sopenharmony_ci#include "trace.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic int afu_control(struct cxl_afu *afu, u64 command, u64 clear,
2362306a36Sopenharmony_ci		       u64 result, u64 mask, bool enabled)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	u64 AFU_Cntl;
2662306a36Sopenharmony_ci	unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
2762306a36Sopenharmony_ci	int rc = 0;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	spin_lock(&afu->afu_cntl_lock);
3062306a36Sopenharmony_ci	pr_devel("AFU command starting: %llx\n", command);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	trace_cxl_afu_ctrl(afu, command);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
3562306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_AFU_Cntl_An, (AFU_Cntl & ~clear) | command);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
3862306a36Sopenharmony_ci	while ((AFU_Cntl & mask) != result) {
3962306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
4062306a36Sopenharmony_ci			dev_warn(&afu->dev, "WARNING: AFU control timed out!\n");
4162306a36Sopenharmony_ci			rc = -EBUSY;
4262306a36Sopenharmony_ci			goto out;
4362306a36Sopenharmony_ci		}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci		if (!cxl_ops->link_ok(afu->adapter, afu)) {
4662306a36Sopenharmony_ci			afu->enabled = enabled;
4762306a36Sopenharmony_ci			rc = -EIO;
4862306a36Sopenharmony_ci			goto out;
4962306a36Sopenharmony_ci		}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		pr_devel_ratelimited("AFU control... (0x%016llx)\n",
5262306a36Sopenharmony_ci				     AFU_Cntl | command);
5362306a36Sopenharmony_ci		cpu_relax();
5462306a36Sopenharmony_ci		AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (AFU_Cntl & CXL_AFU_Cntl_An_RA) {
5862306a36Sopenharmony_ci		/*
5962306a36Sopenharmony_ci		 * Workaround for a bug in the XSL used in the Mellanox CX4
6062306a36Sopenharmony_ci		 * that fails to clear the RA bit after an AFU reset,
6162306a36Sopenharmony_ci		 * preventing subsequent AFU resets from working.
6262306a36Sopenharmony_ci		 */
6362306a36Sopenharmony_ci		cxl_p2n_write(afu, CXL_AFU_Cntl_An, AFU_Cntl & ~CXL_AFU_Cntl_An_RA);
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	pr_devel("AFU command complete: %llx\n", command);
6762306a36Sopenharmony_ci	afu->enabled = enabled;
6862306a36Sopenharmony_ciout:
6962306a36Sopenharmony_ci	trace_cxl_afu_ctrl_done(afu, command, rc);
7062306a36Sopenharmony_ci	spin_unlock(&afu->afu_cntl_lock);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return rc;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic int afu_enable(struct cxl_afu *afu)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	pr_devel("AFU enable request\n");
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return afu_control(afu, CXL_AFU_Cntl_An_E, 0,
8062306a36Sopenharmony_ci			   CXL_AFU_Cntl_An_ES_Enabled,
8162306a36Sopenharmony_ci			   CXL_AFU_Cntl_An_ES_MASK, true);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ciint cxl_afu_disable(struct cxl_afu *afu)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	pr_devel("AFU disable request\n");
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return afu_control(afu, 0, CXL_AFU_Cntl_An_E,
8962306a36Sopenharmony_ci			   CXL_AFU_Cntl_An_ES_Disabled,
9062306a36Sopenharmony_ci			   CXL_AFU_Cntl_An_ES_MASK, false);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* This will disable as well as reset */
9462306a36Sopenharmony_cistatic int native_afu_reset(struct cxl_afu *afu)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	int rc;
9762306a36Sopenharmony_ci	u64 serr;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	pr_devel("AFU reset request\n");
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	rc = afu_control(afu, CXL_AFU_Cntl_An_RA, 0,
10262306a36Sopenharmony_ci			   CXL_AFU_Cntl_An_RS_Complete | CXL_AFU_Cntl_An_ES_Disabled,
10362306a36Sopenharmony_ci			   CXL_AFU_Cntl_An_RS_MASK | CXL_AFU_Cntl_An_ES_MASK,
10462306a36Sopenharmony_ci			   false);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/*
10762306a36Sopenharmony_ci	 * Re-enable any masked interrupts when the AFU is not
10862306a36Sopenharmony_ci	 * activated to avoid side effects after attaching a process
10962306a36Sopenharmony_ci	 * in dedicated mode.
11062306a36Sopenharmony_ci	 */
11162306a36Sopenharmony_ci	if (afu->current_mode == 0) {
11262306a36Sopenharmony_ci		serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
11362306a36Sopenharmony_ci		serr &= ~CXL_PSL_SERR_An_IRQ_MASKS;
11462306a36Sopenharmony_ci		cxl_p1n_write(afu, CXL_PSL_SERR_An, serr);
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return rc;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int native_afu_check_and_enable(struct cxl_afu *afu)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	if (!cxl_ops->link_ok(afu->adapter, afu)) {
12362306a36Sopenharmony_ci		WARN(1, "Refusing to enable afu while link down!\n");
12462306a36Sopenharmony_ci		return -EIO;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci	if (afu->enabled)
12762306a36Sopenharmony_ci		return 0;
12862306a36Sopenharmony_ci	return afu_enable(afu);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciint cxl_psl_purge(struct cxl_afu *afu)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	u64 PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An);
13462306a36Sopenharmony_ci	u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
13562306a36Sopenharmony_ci	u64 dsisr, dar;
13662306a36Sopenharmony_ci	u64 start, end;
13762306a36Sopenharmony_ci	u64 trans_fault = 0x0ULL;
13862306a36Sopenharmony_ci	unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
13962306a36Sopenharmony_ci	int rc = 0;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	trace_cxl_psl_ctrl(afu, CXL_PSL_SCNTL_An_Pc);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	pr_devel("PSL purge request\n");
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (cxl_is_power8())
14662306a36Sopenharmony_ci		trans_fault = CXL_PSL_DSISR_TRANS;
14762306a36Sopenharmony_ci	if (cxl_is_power9())
14862306a36Sopenharmony_ci		trans_fault = CXL_PSL9_DSISR_An_TF;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (!cxl_ops->link_ok(afu->adapter, afu)) {
15162306a36Sopenharmony_ci		dev_warn(&afu->dev, "PSL Purge called with link down, ignoring\n");
15262306a36Sopenharmony_ci		rc = -EIO;
15362306a36Sopenharmony_ci		goto out;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if ((AFU_Cntl & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) {
15762306a36Sopenharmony_ci		WARN(1, "psl_purge request while AFU not disabled!\n");
15862306a36Sopenharmony_ci		cxl_afu_disable(afu);
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SCNTL_An,
16262306a36Sopenharmony_ci		       PSL_CNTL | CXL_PSL_SCNTL_An_Pc);
16362306a36Sopenharmony_ci	start = local_clock();
16462306a36Sopenharmony_ci	PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An);
16562306a36Sopenharmony_ci	while ((PSL_CNTL &  CXL_PSL_SCNTL_An_Ps_MASK)
16662306a36Sopenharmony_ci			== CXL_PSL_SCNTL_An_Ps_Pending) {
16762306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
16862306a36Sopenharmony_ci			dev_warn(&afu->dev, "WARNING: PSL Purge timed out!\n");
16962306a36Sopenharmony_ci			rc = -EBUSY;
17062306a36Sopenharmony_ci			goto out;
17162306a36Sopenharmony_ci		}
17262306a36Sopenharmony_ci		if (!cxl_ops->link_ok(afu->adapter, afu)) {
17362306a36Sopenharmony_ci			rc = -EIO;
17462306a36Sopenharmony_ci			goto out;
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci		dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
17862306a36Sopenharmony_ci		pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%016llx  PSL_DSISR: 0x%016llx\n",
17962306a36Sopenharmony_ci				     PSL_CNTL, dsisr);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		if (dsisr & trans_fault) {
18262306a36Sopenharmony_ci			dar = cxl_p2n_read(afu, CXL_PSL_DAR_An);
18362306a36Sopenharmony_ci			dev_notice(&afu->dev, "PSL purge terminating pending translation, DSISR: 0x%016llx, DAR: 0x%016llx\n",
18462306a36Sopenharmony_ci				   dsisr, dar);
18562306a36Sopenharmony_ci			cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);
18662306a36Sopenharmony_ci		} else if (dsisr) {
18762306a36Sopenharmony_ci			dev_notice(&afu->dev, "PSL purge acknowledging pending non-translation fault, DSISR: 0x%016llx\n",
18862306a36Sopenharmony_ci				   dsisr);
18962306a36Sopenharmony_ci			cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);
19062306a36Sopenharmony_ci		} else {
19162306a36Sopenharmony_ci			cpu_relax();
19262306a36Sopenharmony_ci		}
19362306a36Sopenharmony_ci		PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An);
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci	end = local_clock();
19662306a36Sopenharmony_ci	pr_devel("PSL purged in %lld ns\n", end - start);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SCNTL_An,
19962306a36Sopenharmony_ci		       PSL_CNTL & ~CXL_PSL_SCNTL_An_Pc);
20062306a36Sopenharmony_ciout:
20162306a36Sopenharmony_ci	trace_cxl_psl_ctrl_done(afu, CXL_PSL_SCNTL_An_Pc, rc);
20262306a36Sopenharmony_ci	return rc;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int spa_max_procs(int spa_size)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	/*
20862306a36Sopenharmony_ci	 * From the CAIA:
20962306a36Sopenharmony_ci	 *    end_of_SPA_area = SPA_Base + ((n+4) * 128) + (( ((n*8) + 127) >> 7) * 128) + 255
21062306a36Sopenharmony_ci	 * Most of that junk is really just an overly-complicated way of saying
21162306a36Sopenharmony_ci	 * the last 256 bytes are __aligned(128), so it's really:
21262306a36Sopenharmony_ci	 *    end_of_SPA_area = end_of_PSL_queue_area + __aligned(128) 255
21362306a36Sopenharmony_ci	 * and
21462306a36Sopenharmony_ci	 *    end_of_PSL_queue_area = SPA_Base + ((n+4) * 128) + (n*8) - 1
21562306a36Sopenharmony_ci	 * so
21662306a36Sopenharmony_ci	 *    sizeof(SPA) = ((n+4) * 128) + (n*8) + __aligned(128) 256
21762306a36Sopenharmony_ci	 * Ignore the alignment (which is safe in this case as long as we are
21862306a36Sopenharmony_ci	 * careful with our rounding) and solve for n:
21962306a36Sopenharmony_ci	 */
22062306a36Sopenharmony_ci	return ((spa_size / 8) - 96) / 17;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic int cxl_alloc_spa(struct cxl_afu *afu, int mode)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	unsigned spa_size;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/* Work out how many pages to allocate */
22862306a36Sopenharmony_ci	afu->native->spa_order = -1;
22962306a36Sopenharmony_ci	do {
23062306a36Sopenharmony_ci		afu->native->spa_order++;
23162306a36Sopenharmony_ci		spa_size = (1 << afu->native->spa_order) * PAGE_SIZE;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		if (spa_size > 0x100000) {
23462306a36Sopenharmony_ci			dev_warn(&afu->dev, "num_of_processes too large for the SPA, limiting to %i (0x%x)\n",
23562306a36Sopenharmony_ci					afu->native->spa_max_procs, afu->native->spa_size);
23662306a36Sopenharmony_ci			if (mode != CXL_MODE_DEDICATED)
23762306a36Sopenharmony_ci				afu->num_procs = afu->native->spa_max_procs;
23862306a36Sopenharmony_ci			break;
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci		afu->native->spa_size = spa_size;
24262306a36Sopenharmony_ci		afu->native->spa_max_procs = spa_max_procs(afu->native->spa_size);
24362306a36Sopenharmony_ci	} while (afu->native->spa_max_procs < afu->num_procs);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (!(afu->native->spa = (struct cxl_process_element *)
24662306a36Sopenharmony_ci	      __get_free_pages(GFP_KERNEL | __GFP_ZERO, afu->native->spa_order))) {
24762306a36Sopenharmony_ci		pr_err("cxl_alloc_spa: Unable to allocate scheduled process area\n");
24862306a36Sopenharmony_ci		return -ENOMEM;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci	pr_devel("spa pages: %i afu->spa_max_procs: %i   afu->num_procs: %i\n",
25162306a36Sopenharmony_ci		 1<<afu->native->spa_order, afu->native->spa_max_procs, afu->num_procs);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	return 0;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic void attach_spa(struct cxl_afu *afu)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	u64 spap;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	afu->native->sw_command_status = (__be64 *)((char *)afu->native->spa +
26162306a36Sopenharmony_ci					    ((afu->native->spa_max_procs + 3) * 128));
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	spap = virt_to_phys(afu->native->spa) & CXL_PSL_SPAP_Addr;
26462306a36Sopenharmony_ci	spap |= ((afu->native->spa_size >> (12 - CXL_PSL_SPAP_Size_Shift)) - 1) & CXL_PSL_SPAP_Size;
26562306a36Sopenharmony_ci	spap |= CXL_PSL_SPAP_V;
26662306a36Sopenharmony_ci	pr_devel("cxl: SPA allocated at 0x%p. Max processes: %i, sw_command_status: 0x%p CXL_PSL_SPAP_An=0x%016llx\n",
26762306a36Sopenharmony_ci		afu->native->spa, afu->native->spa_max_procs,
26862306a36Sopenharmony_ci		afu->native->sw_command_status, spap);
26962306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SPAP_An, spap);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_civoid cxl_release_spa(struct cxl_afu *afu)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	if (afu->native->spa) {
27562306a36Sopenharmony_ci		free_pages((unsigned long) afu->native->spa,
27662306a36Sopenharmony_ci			afu->native->spa_order);
27762306a36Sopenharmony_ci		afu->native->spa = NULL;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/*
28262306a36Sopenharmony_ci * Invalidation of all ERAT entries is no longer required by CAIA2. Use
28362306a36Sopenharmony_ci * only for debug.
28462306a36Sopenharmony_ci */
28562306a36Sopenharmony_ciint cxl_invalidate_all_psl9(struct cxl *adapter)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
28862306a36Sopenharmony_ci	u64 ierat;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	pr_devel("CXL adapter - invalidation of all ERAT entries\n");
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/* Invalidates all ERAT entries for Radix or HPT */
29362306a36Sopenharmony_ci	ierat = CXL_XSL9_IERAT_IALL;
29462306a36Sopenharmony_ci	if (radix_enabled())
29562306a36Sopenharmony_ci		ierat |= CXL_XSL9_IERAT_INVR;
29662306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_XSL9_IERAT, ierat);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	while (cxl_p1_read(adapter, CXL_XSL9_IERAT) & CXL_XSL9_IERAT_IINPROG) {
29962306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
30062306a36Sopenharmony_ci			dev_warn(&adapter->dev,
30162306a36Sopenharmony_ci			"WARNING: CXL adapter invalidation of all ERAT entries timed out!\n");
30262306a36Sopenharmony_ci			return -EBUSY;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci		if (!cxl_ops->link_ok(adapter, NULL))
30562306a36Sopenharmony_ci			return -EIO;
30662306a36Sopenharmony_ci		cpu_relax();
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci	return 0;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ciint cxl_invalidate_all_psl8(struct cxl *adapter)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	pr_devel("CXL adapter wide TLBIA & SLBIA\n");
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_PSL_AFUSEL, CXL_PSL_AFUSEL_A);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_PSL_TLBIA, CXL_TLB_SLB_IQ_ALL);
32062306a36Sopenharmony_ci	while (cxl_p1_read(adapter, CXL_PSL_TLBIA) & CXL_TLB_SLB_P) {
32162306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
32262306a36Sopenharmony_ci			dev_warn(&adapter->dev, "WARNING: CXL adapter wide TLBIA timed out!\n");
32362306a36Sopenharmony_ci			return -EBUSY;
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci		if (!cxl_ops->link_ok(adapter, NULL))
32662306a36Sopenharmony_ci			return -EIO;
32762306a36Sopenharmony_ci		cpu_relax();
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_PSL_SLBIA, CXL_TLB_SLB_IQ_ALL);
33162306a36Sopenharmony_ci	while (cxl_p1_read(adapter, CXL_PSL_SLBIA) & CXL_TLB_SLB_P) {
33262306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
33362306a36Sopenharmony_ci			dev_warn(&adapter->dev, "WARNING: CXL adapter wide SLBIA timed out!\n");
33462306a36Sopenharmony_ci			return -EBUSY;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci		if (!cxl_ops->link_ok(adapter, NULL))
33762306a36Sopenharmony_ci			return -EIO;
33862306a36Sopenharmony_ci		cpu_relax();
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci	return 0;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ciint cxl_data_cache_flush(struct cxl *adapter)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	u64 reg;
34662306a36Sopenharmony_ci	unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/*
34962306a36Sopenharmony_ci	 * Do a datacache flush only if datacache is available.
35062306a36Sopenharmony_ci	 * In case of PSL9D datacache absent hence flush operation.
35162306a36Sopenharmony_ci	 * would timeout.
35262306a36Sopenharmony_ci	 */
35362306a36Sopenharmony_ci	if (adapter->native->no_data_cache) {
35462306a36Sopenharmony_ci		pr_devel("No PSL data cache. Ignoring cache flush req.\n");
35562306a36Sopenharmony_ci		return 0;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	pr_devel("Flushing data cache\n");
35962306a36Sopenharmony_ci	reg = cxl_p1_read(adapter, CXL_PSL_Control);
36062306a36Sopenharmony_ci	reg |= CXL_PSL_Control_Fr;
36162306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_PSL_Control, reg);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	reg = cxl_p1_read(adapter, CXL_PSL_Control);
36462306a36Sopenharmony_ci	while ((reg & CXL_PSL_Control_Fs_MASK) != CXL_PSL_Control_Fs_Complete) {
36562306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
36662306a36Sopenharmony_ci			dev_warn(&adapter->dev, "WARNING: cache flush timed out!\n");
36762306a36Sopenharmony_ci			return -EBUSY;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		if (!cxl_ops->link_ok(adapter, NULL)) {
37162306a36Sopenharmony_ci			dev_warn(&adapter->dev, "WARNING: link down when flushing cache\n");
37262306a36Sopenharmony_ci			return -EIO;
37362306a36Sopenharmony_ci		}
37462306a36Sopenharmony_ci		cpu_relax();
37562306a36Sopenharmony_ci		reg = cxl_p1_read(adapter, CXL_PSL_Control);
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	reg &= ~CXL_PSL_Control_Fr;
37962306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_PSL_Control, reg);
38062306a36Sopenharmony_ci	return 0;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic int cxl_write_sstp(struct cxl_afu *afu, u64 sstp0, u64 sstp1)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	int rc;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* 1. Disable SSTP by writing 0 to SSTP1[V] */
38862306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_SSTP1_An, 0);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	/* 2. Invalidate all SLB entries */
39162306a36Sopenharmony_ci	if ((rc = cxl_afu_slbia(afu)))
39262306a36Sopenharmony_ci		return rc;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/* 3. Set SSTP0_An */
39562306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_SSTP0_An, sstp0);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* 4. Set SSTP1_An */
39862306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_SSTP1_An, sstp1);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci/* Using per slice version may improve performance here. (ie. SLBIA_An) */
40462306a36Sopenharmony_cistatic void slb_invalid(struct cxl_context *ctx)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct cxl *adapter = ctx->afu->adapter;
40762306a36Sopenharmony_ci	u64 slbia;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	WARN_ON(!mutex_is_locked(&ctx->afu->native->spa_mutex));
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_PSL_LBISEL,
41262306a36Sopenharmony_ci			((u64)be32_to_cpu(ctx->elem->common.pid) << 32) |
41362306a36Sopenharmony_ci			be32_to_cpu(ctx->elem->lpid));
41462306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_PSL_SLBIA, CXL_TLB_SLB_IQ_LPIDPID);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	while (1) {
41762306a36Sopenharmony_ci		if (!cxl_ops->link_ok(adapter, NULL))
41862306a36Sopenharmony_ci			break;
41962306a36Sopenharmony_ci		slbia = cxl_p1_read(adapter, CXL_PSL_SLBIA);
42062306a36Sopenharmony_ci		if (!(slbia & CXL_TLB_SLB_P))
42162306a36Sopenharmony_ci			break;
42262306a36Sopenharmony_ci		cpu_relax();
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic int do_process_element_cmd(struct cxl_context *ctx,
42762306a36Sopenharmony_ci				  u64 cmd, u64 pe_state)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	u64 state;
43062306a36Sopenharmony_ci	unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
43162306a36Sopenharmony_ci	int rc = 0;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	trace_cxl_llcmd(ctx, cmd);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	WARN_ON(!ctx->afu->enabled);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	ctx->elem->software_state = cpu_to_be32(pe_state);
43862306a36Sopenharmony_ci	smp_wmb();
43962306a36Sopenharmony_ci	*(ctx->afu->native->sw_command_status) = cpu_to_be64(cmd | 0 | ctx->pe);
44062306a36Sopenharmony_ci	smp_mb();
44162306a36Sopenharmony_ci	cxl_p1n_write(ctx->afu, CXL_PSL_LLCMD_An, cmd | ctx->pe);
44262306a36Sopenharmony_ci	while (1) {
44362306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
44462306a36Sopenharmony_ci			dev_warn(&ctx->afu->dev, "WARNING: Process Element Command timed out!\n");
44562306a36Sopenharmony_ci			rc = -EBUSY;
44662306a36Sopenharmony_ci			goto out;
44762306a36Sopenharmony_ci		}
44862306a36Sopenharmony_ci		if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)) {
44962306a36Sopenharmony_ci			dev_warn(&ctx->afu->dev, "WARNING: Device link down, aborting Process Element Command!\n");
45062306a36Sopenharmony_ci			rc = -EIO;
45162306a36Sopenharmony_ci			goto out;
45262306a36Sopenharmony_ci		}
45362306a36Sopenharmony_ci		state = be64_to_cpup(ctx->afu->native->sw_command_status);
45462306a36Sopenharmony_ci		if (state == ~0ULL) {
45562306a36Sopenharmony_ci			pr_err("cxl: Error adding process element to AFU\n");
45662306a36Sopenharmony_ci			rc = -1;
45762306a36Sopenharmony_ci			goto out;
45862306a36Sopenharmony_ci		}
45962306a36Sopenharmony_ci		if ((state & (CXL_SPA_SW_CMD_MASK | CXL_SPA_SW_STATE_MASK  | CXL_SPA_SW_LINK_MASK)) ==
46062306a36Sopenharmony_ci		    (cmd | (cmd >> 16) | ctx->pe))
46162306a36Sopenharmony_ci			break;
46262306a36Sopenharmony_ci		/*
46362306a36Sopenharmony_ci		 * The command won't finish in the PSL if there are
46462306a36Sopenharmony_ci		 * outstanding DSIs.  Hence we need to yield here in
46562306a36Sopenharmony_ci		 * case there are outstanding DSIs that we need to
46662306a36Sopenharmony_ci		 * service.  Tuning possiblity: we could wait for a
46762306a36Sopenharmony_ci		 * while before sched
46862306a36Sopenharmony_ci		 */
46962306a36Sopenharmony_ci		schedule();
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ciout:
47362306a36Sopenharmony_ci	trace_cxl_llcmd_done(ctx, cmd, rc);
47462306a36Sopenharmony_ci	return rc;
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic int add_process_element(struct cxl_context *ctx)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	int rc = 0;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	mutex_lock(&ctx->afu->native->spa_mutex);
48262306a36Sopenharmony_ci	pr_devel("%s Adding pe: %i started\n", __func__, ctx->pe);
48362306a36Sopenharmony_ci	if (!(rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_ADD, CXL_PE_SOFTWARE_STATE_V)))
48462306a36Sopenharmony_ci		ctx->pe_inserted = true;
48562306a36Sopenharmony_ci	pr_devel("%s Adding pe: %i finished\n", __func__, ctx->pe);
48662306a36Sopenharmony_ci	mutex_unlock(&ctx->afu->native->spa_mutex);
48762306a36Sopenharmony_ci	return rc;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic int terminate_process_element(struct cxl_context *ctx)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	int rc = 0;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	/* fast path terminate if it's already invalid */
49562306a36Sopenharmony_ci	if (!(ctx->elem->software_state & cpu_to_be32(CXL_PE_SOFTWARE_STATE_V)))
49662306a36Sopenharmony_ci		return rc;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	mutex_lock(&ctx->afu->native->spa_mutex);
49962306a36Sopenharmony_ci	pr_devel("%s Terminate pe: %i started\n", __func__, ctx->pe);
50062306a36Sopenharmony_ci	/* We could be asked to terminate when the hw is down. That
50162306a36Sopenharmony_ci	 * should always succeed: it's not running if the hw has gone
50262306a36Sopenharmony_ci	 * away and is being reset.
50362306a36Sopenharmony_ci	 */
50462306a36Sopenharmony_ci	if (cxl_ops->link_ok(ctx->afu->adapter, ctx->afu))
50562306a36Sopenharmony_ci		rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_TERMINATE,
50662306a36Sopenharmony_ci					    CXL_PE_SOFTWARE_STATE_V | CXL_PE_SOFTWARE_STATE_T);
50762306a36Sopenharmony_ci	ctx->elem->software_state = 0;	/* Remove Valid bit */
50862306a36Sopenharmony_ci	pr_devel("%s Terminate pe: %i finished\n", __func__, ctx->pe);
50962306a36Sopenharmony_ci	mutex_unlock(&ctx->afu->native->spa_mutex);
51062306a36Sopenharmony_ci	return rc;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic int remove_process_element(struct cxl_context *ctx)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	int rc = 0;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	mutex_lock(&ctx->afu->native->spa_mutex);
51862306a36Sopenharmony_ci	pr_devel("%s Remove pe: %i started\n", __func__, ctx->pe);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/* We could be asked to remove when the hw is down. Again, if
52162306a36Sopenharmony_ci	 * the hw is down, the PE is gone, so we succeed.
52262306a36Sopenharmony_ci	 */
52362306a36Sopenharmony_ci	if (cxl_ops->link_ok(ctx->afu->adapter, ctx->afu))
52462306a36Sopenharmony_ci		rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_REMOVE, 0);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (!rc)
52762306a36Sopenharmony_ci		ctx->pe_inserted = false;
52862306a36Sopenharmony_ci	if (cxl_is_power8())
52962306a36Sopenharmony_ci		slb_invalid(ctx);
53062306a36Sopenharmony_ci	pr_devel("%s Remove pe: %i finished\n", __func__, ctx->pe);
53162306a36Sopenharmony_ci	mutex_unlock(&ctx->afu->native->spa_mutex);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	return rc;
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_civoid cxl_assign_psn_space(struct cxl_context *ctx)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	if (!ctx->afu->pp_size || ctx->master) {
53962306a36Sopenharmony_ci		ctx->psn_phys = ctx->afu->psn_phys;
54062306a36Sopenharmony_ci		ctx->psn_size = ctx->afu->adapter->ps_size;
54162306a36Sopenharmony_ci	} else {
54262306a36Sopenharmony_ci		ctx->psn_phys = ctx->afu->psn_phys +
54362306a36Sopenharmony_ci			(ctx->afu->native->pp_offset + ctx->afu->pp_size * ctx->pe);
54462306a36Sopenharmony_ci		ctx->psn_size = ctx->afu->pp_size;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic int activate_afu_directed(struct cxl_afu *afu)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	int rc;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	dev_info(&afu->dev, "Activating AFU directed mode\n");
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	afu->num_procs = afu->max_procs_virtualised;
55562306a36Sopenharmony_ci	if (afu->native->spa == NULL) {
55662306a36Sopenharmony_ci		if (cxl_alloc_spa(afu, CXL_MODE_DIRECTED))
55762306a36Sopenharmony_ci			return -ENOMEM;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci	attach_spa(afu);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SCNTL_An, CXL_PSL_SCNTL_An_PM_AFU);
56262306a36Sopenharmony_ci	if (cxl_is_power8())
56362306a36Sopenharmony_ci		cxl_p1n_write(afu, CXL_PSL_AMOR_An, 0xFFFFFFFFFFFFFFFFULL);
56462306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_ID_An, CXL_PSL_ID_An_F | CXL_PSL_ID_An_L);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	afu->current_mode = CXL_MODE_DIRECTED;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	if ((rc = cxl_chardev_m_afu_add(afu)))
56962306a36Sopenharmony_ci		return rc;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if ((rc = cxl_sysfs_afu_m_add(afu)))
57262306a36Sopenharmony_ci		goto err;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if ((rc = cxl_chardev_s_afu_add(afu)))
57562306a36Sopenharmony_ci		goto err1;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	return 0;
57862306a36Sopenharmony_cierr1:
57962306a36Sopenharmony_ci	cxl_sysfs_afu_m_remove(afu);
58062306a36Sopenharmony_cierr:
58162306a36Sopenharmony_ci	cxl_chardev_afu_remove(afu);
58262306a36Sopenharmony_ci	return rc;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci#ifdef CONFIG_CPU_LITTLE_ENDIAN
58662306a36Sopenharmony_ci#define set_endian(sr) ((sr) |= CXL_PSL_SR_An_LE)
58762306a36Sopenharmony_ci#else
58862306a36Sopenharmony_ci#define set_endian(sr) ((sr) &= ~(CXL_PSL_SR_An_LE))
58962306a36Sopenharmony_ci#endif
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ciu64 cxl_calculate_sr(bool master, bool kernel, bool real_mode, bool p9)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	u64 sr = 0;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	set_endian(sr);
59662306a36Sopenharmony_ci	if (master)
59762306a36Sopenharmony_ci		sr |= CXL_PSL_SR_An_MP;
59862306a36Sopenharmony_ci	if (mfspr(SPRN_LPCR) & LPCR_TC)
59962306a36Sopenharmony_ci		sr |= CXL_PSL_SR_An_TC;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (kernel) {
60262306a36Sopenharmony_ci		if (!real_mode)
60362306a36Sopenharmony_ci			sr |= CXL_PSL_SR_An_R;
60462306a36Sopenharmony_ci		sr |= (mfmsr() & MSR_SF) | CXL_PSL_SR_An_HV;
60562306a36Sopenharmony_ci	} else {
60662306a36Sopenharmony_ci		sr |= CXL_PSL_SR_An_PR | CXL_PSL_SR_An_R;
60762306a36Sopenharmony_ci		if (radix_enabled())
60862306a36Sopenharmony_ci			sr |= CXL_PSL_SR_An_HV;
60962306a36Sopenharmony_ci		else
61062306a36Sopenharmony_ci			sr &= ~(CXL_PSL_SR_An_HV);
61162306a36Sopenharmony_ci		if (!test_tsk_thread_flag(current, TIF_32BIT))
61262306a36Sopenharmony_ci			sr |= CXL_PSL_SR_An_SF;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci	if (p9) {
61562306a36Sopenharmony_ci		if (radix_enabled())
61662306a36Sopenharmony_ci			sr |= CXL_PSL_SR_An_XLAT_ror;
61762306a36Sopenharmony_ci		else
61862306a36Sopenharmony_ci			sr |= CXL_PSL_SR_An_XLAT_hpt;
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci	return sr;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic u64 calculate_sr(struct cxl_context *ctx)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	return cxl_calculate_sr(ctx->master, ctx->kernel, false,
62662306a36Sopenharmony_ci				cxl_is_power9());
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cistatic void update_ivtes_directed(struct cxl_context *ctx)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	bool need_update = (ctx->status == STARTED);
63262306a36Sopenharmony_ci	int r;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (need_update) {
63562306a36Sopenharmony_ci		WARN_ON(terminate_process_element(ctx));
63662306a36Sopenharmony_ci		WARN_ON(remove_process_element(ctx));
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	for (r = 0; r < CXL_IRQ_RANGES; r++) {
64062306a36Sopenharmony_ci		ctx->elem->ivte_offsets[r] = cpu_to_be16(ctx->irqs.offset[r]);
64162306a36Sopenharmony_ci		ctx->elem->ivte_ranges[r] = cpu_to_be16(ctx->irqs.range[r]);
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	/*
64562306a36Sopenharmony_ci	 * Theoretically we could use the update llcmd, instead of a
64662306a36Sopenharmony_ci	 * terminate/remove/add (or if an atomic update was required we could
64762306a36Sopenharmony_ci	 * do a suspend/update/resume), however it seems there might be issues
64862306a36Sopenharmony_ci	 * with the update llcmd on some cards (including those using an XSL on
64962306a36Sopenharmony_ci	 * an ASIC) so for now it's safest to go with the commands that are
65062306a36Sopenharmony_ci	 * known to work. In the future if we come across a situation where the
65162306a36Sopenharmony_ci	 * card may be performing transactions using the same PE while we are
65262306a36Sopenharmony_ci	 * doing this update we might need to revisit this.
65362306a36Sopenharmony_ci	 */
65462306a36Sopenharmony_ci	if (need_update)
65562306a36Sopenharmony_ci		WARN_ON(add_process_element(ctx));
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic int process_element_entry_psl9(struct cxl_context *ctx, u64 wed, u64 amr)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	u32 pid;
66162306a36Sopenharmony_ci	int rc;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	cxl_assign_psn_space(ctx);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	ctx->elem->ctxtime = 0; /* disable */
66662306a36Sopenharmony_ci	ctx->elem->lpid = cpu_to_be32(mfspr(SPRN_LPID));
66762306a36Sopenharmony_ci	ctx->elem->haurp = 0; /* disable */
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	if (ctx->kernel)
67062306a36Sopenharmony_ci		pid = 0;
67162306a36Sopenharmony_ci	else {
67262306a36Sopenharmony_ci		if (ctx->mm == NULL) {
67362306a36Sopenharmony_ci			pr_devel("%s: unable to get mm for pe=%d pid=%i\n",
67462306a36Sopenharmony_ci				__func__, ctx->pe, pid_nr(ctx->pid));
67562306a36Sopenharmony_ci			return -EINVAL;
67662306a36Sopenharmony_ci		}
67762306a36Sopenharmony_ci		pid = ctx->mm->context.id;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/* Assign a unique TIDR (thread id) for the current thread */
68162306a36Sopenharmony_ci	if (!(ctx->tidr) && (ctx->assign_tidr)) {
68262306a36Sopenharmony_ci		rc = set_thread_tidr(current);
68362306a36Sopenharmony_ci		if (rc)
68462306a36Sopenharmony_ci			return -ENODEV;
68562306a36Sopenharmony_ci		ctx->tidr = current->thread.tidr;
68662306a36Sopenharmony_ci		pr_devel("%s: current tidr: %d\n", __func__, ctx->tidr);
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	ctx->elem->common.tid = cpu_to_be32(ctx->tidr);
69062306a36Sopenharmony_ci	ctx->elem->common.pid = cpu_to_be32(pid);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	ctx->elem->sr = cpu_to_be64(calculate_sr(ctx));
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	ctx->elem->common.csrp = 0; /* disable */
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	cxl_prefault(ctx, wed);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/*
69962306a36Sopenharmony_ci	 * Ensure we have the multiplexed PSL interrupt set up to take faults
70062306a36Sopenharmony_ci	 * for kernel contexts that may not have allocated any AFU IRQs at all:
70162306a36Sopenharmony_ci	 */
70262306a36Sopenharmony_ci	if (ctx->irqs.range[0] == 0) {
70362306a36Sopenharmony_ci		ctx->irqs.offset[0] = ctx->afu->native->psl_hwirq;
70462306a36Sopenharmony_ci		ctx->irqs.range[0] = 1;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	ctx->elem->common.amr = cpu_to_be64(amr);
70862306a36Sopenharmony_ci	ctx->elem->common.wed = cpu_to_be64(wed);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	return 0;
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ciint cxl_attach_afu_directed_psl9(struct cxl_context *ctx, u64 wed, u64 amr)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	int result;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* fill the process element entry */
71862306a36Sopenharmony_ci	result = process_element_entry_psl9(ctx, wed, amr);
71962306a36Sopenharmony_ci	if (result)
72062306a36Sopenharmony_ci		return result;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	update_ivtes_directed(ctx);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* first guy needs to enable */
72562306a36Sopenharmony_ci	result = cxl_ops->afu_check_and_enable(ctx->afu);
72662306a36Sopenharmony_ci	if (result)
72762306a36Sopenharmony_ci		return result;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	return add_process_element(ctx);
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ciint cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, u64 amr)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	u32 pid;
73562306a36Sopenharmony_ci	int result;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	cxl_assign_psn_space(ctx);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	ctx->elem->ctxtime = 0; /* disable */
74062306a36Sopenharmony_ci	ctx->elem->lpid = cpu_to_be32(mfspr(SPRN_LPID));
74162306a36Sopenharmony_ci	ctx->elem->haurp = 0; /* disable */
74262306a36Sopenharmony_ci	ctx->elem->u.sdr = cpu_to_be64(mfspr(SPRN_SDR1));
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	pid = current->pid;
74562306a36Sopenharmony_ci	if (ctx->kernel)
74662306a36Sopenharmony_ci		pid = 0;
74762306a36Sopenharmony_ci	ctx->elem->common.tid = 0;
74862306a36Sopenharmony_ci	ctx->elem->common.pid = cpu_to_be32(pid);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	ctx->elem->sr = cpu_to_be64(calculate_sr(ctx));
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	ctx->elem->common.csrp = 0; /* disable */
75362306a36Sopenharmony_ci	ctx->elem->common.u.psl8.aurp0 = 0; /* disable */
75462306a36Sopenharmony_ci	ctx->elem->common.u.psl8.aurp1 = 0; /* disable */
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	cxl_prefault(ctx, wed);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	ctx->elem->common.u.psl8.sstp0 = cpu_to_be64(ctx->sstp0);
75962306a36Sopenharmony_ci	ctx->elem->common.u.psl8.sstp1 = cpu_to_be64(ctx->sstp1);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	/*
76262306a36Sopenharmony_ci	 * Ensure we have the multiplexed PSL interrupt set up to take faults
76362306a36Sopenharmony_ci	 * for kernel contexts that may not have allocated any AFU IRQs at all:
76462306a36Sopenharmony_ci	 */
76562306a36Sopenharmony_ci	if (ctx->irqs.range[0] == 0) {
76662306a36Sopenharmony_ci		ctx->irqs.offset[0] = ctx->afu->native->psl_hwirq;
76762306a36Sopenharmony_ci		ctx->irqs.range[0] = 1;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	update_ivtes_directed(ctx);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	ctx->elem->common.amr = cpu_to_be64(amr);
77362306a36Sopenharmony_ci	ctx->elem->common.wed = cpu_to_be64(wed);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* first guy needs to enable */
77662306a36Sopenharmony_ci	if ((result = cxl_ops->afu_check_and_enable(ctx->afu)))
77762306a36Sopenharmony_ci		return result;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	return add_process_element(ctx);
78062306a36Sopenharmony_ci}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistatic int deactivate_afu_directed(struct cxl_afu *afu)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	dev_info(&afu->dev, "Deactivating AFU directed mode\n");
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	afu->current_mode = 0;
78762306a36Sopenharmony_ci	afu->num_procs = 0;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	cxl_sysfs_afu_m_remove(afu);
79062306a36Sopenharmony_ci	cxl_chardev_afu_remove(afu);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	/*
79362306a36Sopenharmony_ci	 * The CAIA section 2.2.1 indicates that the procedure for starting and
79462306a36Sopenharmony_ci	 * stopping an AFU in AFU directed mode is AFU specific, which is not
79562306a36Sopenharmony_ci	 * ideal since this code is generic and with one exception has no
79662306a36Sopenharmony_ci	 * knowledge of the AFU. This is in contrast to the procedure for
79762306a36Sopenharmony_ci	 * disabling a dedicated process AFU, which is documented to just
79862306a36Sopenharmony_ci	 * require a reset. The architecture does indicate that both an AFU
79962306a36Sopenharmony_ci	 * reset and an AFU disable should result in the AFU being disabled and
80062306a36Sopenharmony_ci	 * we do both followed by a PSL purge for safety.
80162306a36Sopenharmony_ci	 *
80262306a36Sopenharmony_ci	 * Notably we used to have some issues with the disable sequence on PSL
80362306a36Sopenharmony_ci	 * cards, which is why we ended up using this heavy weight procedure in
80462306a36Sopenharmony_ci	 * the first place, however a bug was discovered that had rendered the
80562306a36Sopenharmony_ci	 * disable operation ineffective, so it is conceivable that was the
80662306a36Sopenharmony_ci	 * sole explanation for those difficulties. Careful regression testing
80762306a36Sopenharmony_ci	 * is recommended if anyone attempts to remove or reorder these
80862306a36Sopenharmony_ci	 * operations.
80962306a36Sopenharmony_ci	 *
81062306a36Sopenharmony_ci	 * The XSL on the Mellanox CX4 behaves a little differently from the
81162306a36Sopenharmony_ci	 * PSL based cards and will time out an AFU reset if the AFU is still
81262306a36Sopenharmony_ci	 * enabled. That card is special in that we do have a means to identify
81362306a36Sopenharmony_ci	 * it from this code, so in that case we skip the reset and just use a
81462306a36Sopenharmony_ci	 * disable/purge to avoid the timeout and corresponding noise in the
81562306a36Sopenharmony_ci	 * kernel log.
81662306a36Sopenharmony_ci	 */
81762306a36Sopenharmony_ci	if (afu->adapter->native->sl_ops->needs_reset_before_disable)
81862306a36Sopenharmony_ci		cxl_ops->afu_reset(afu);
81962306a36Sopenharmony_ci	cxl_afu_disable(afu);
82062306a36Sopenharmony_ci	cxl_psl_purge(afu);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	return 0;
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ciint cxl_activate_dedicated_process_psl9(struct cxl_afu *afu)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	dev_info(&afu->dev, "Activating dedicated process mode\n");
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/*
83062306a36Sopenharmony_ci	 * If XSL is set to dedicated mode (Set in PSL_SCNTL reg), the
83162306a36Sopenharmony_ci	 * XSL and AFU are programmed to work with a single context.
83262306a36Sopenharmony_ci	 * The context information should be configured in the SPA area
83362306a36Sopenharmony_ci	 * index 0 (so PSL_SPAP must be configured before enabling the
83462306a36Sopenharmony_ci	 * AFU).
83562306a36Sopenharmony_ci	 */
83662306a36Sopenharmony_ci	afu->num_procs = 1;
83762306a36Sopenharmony_ci	if (afu->native->spa == NULL) {
83862306a36Sopenharmony_ci		if (cxl_alloc_spa(afu, CXL_MODE_DEDICATED))
83962306a36Sopenharmony_ci			return -ENOMEM;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci	attach_spa(afu);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SCNTL_An, CXL_PSL_SCNTL_An_PM_Process);
84462306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_ID_An, CXL_PSL_ID_An_F | CXL_PSL_ID_An_L);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	afu->current_mode = CXL_MODE_DEDICATED;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	return cxl_chardev_d_afu_add(afu);
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ciint cxl_activate_dedicated_process_psl8(struct cxl_afu *afu)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	dev_info(&afu->dev, "Activating dedicated process mode\n");
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SCNTL_An, CXL_PSL_SCNTL_An_PM_Process);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_CtxTime_An, 0); /* disable */
85862306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0);    /* disable */
85962306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_AMOR_An, 0xFFFFFFFFFFFFFFFFULL);
86062306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_LPID_An, mfspr(SPRN_LPID));
86162306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_HAURP_An, 0);       /* disable */
86262306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SDR_An, mfspr(SPRN_SDR1));
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_CSRP_An, 0);        /* disable */
86562306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_AURP0_An, 0);       /* disable */
86662306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_AURP1_An, 0);       /* disable */
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	afu->current_mode = CXL_MODE_DEDICATED;
86962306a36Sopenharmony_ci	afu->num_procs = 1;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	return cxl_chardev_d_afu_add(afu);
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_civoid cxl_update_dedicated_ivtes_psl9(struct cxl_context *ctx)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	int r;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	for (r = 0; r < CXL_IRQ_RANGES; r++) {
87962306a36Sopenharmony_ci		ctx->elem->ivte_offsets[r] = cpu_to_be16(ctx->irqs.offset[r]);
88062306a36Sopenharmony_ci		ctx->elem->ivte_ranges[r] = cpu_to_be16(ctx->irqs.range[r]);
88162306a36Sopenharmony_ci	}
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_civoid cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx)
88562306a36Sopenharmony_ci{
88662306a36Sopenharmony_ci	struct cxl_afu *afu = ctx->afu;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_IVTE_Offset_An,
88962306a36Sopenharmony_ci		       (((u64)ctx->irqs.offset[0] & 0xffff) << 48) |
89062306a36Sopenharmony_ci		       (((u64)ctx->irqs.offset[1] & 0xffff) << 32) |
89162306a36Sopenharmony_ci		       (((u64)ctx->irqs.offset[2] & 0xffff) << 16) |
89262306a36Sopenharmony_ci			((u64)ctx->irqs.offset[3] & 0xffff));
89362306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_IVTE_Limit_An, (u64)
89462306a36Sopenharmony_ci		       (((u64)ctx->irqs.range[0] & 0xffff) << 48) |
89562306a36Sopenharmony_ci		       (((u64)ctx->irqs.range[1] & 0xffff) << 32) |
89662306a36Sopenharmony_ci		       (((u64)ctx->irqs.range[2] & 0xffff) << 16) |
89762306a36Sopenharmony_ci			((u64)ctx->irqs.range[3] & 0xffff));
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ciint cxl_attach_dedicated_process_psl9(struct cxl_context *ctx, u64 wed, u64 amr)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	struct cxl_afu *afu = ctx->afu;
90362306a36Sopenharmony_ci	int result;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	/* fill the process element entry */
90662306a36Sopenharmony_ci	result = process_element_entry_psl9(ctx, wed, amr);
90762306a36Sopenharmony_ci	if (result)
90862306a36Sopenharmony_ci		return result;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (ctx->afu->adapter->native->sl_ops->update_dedicated_ivtes)
91162306a36Sopenharmony_ci		afu->adapter->native->sl_ops->update_dedicated_ivtes(ctx);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	ctx->elem->software_state = cpu_to_be32(CXL_PE_SOFTWARE_STATE_V);
91462306a36Sopenharmony_ci	/*
91562306a36Sopenharmony_ci	 * Ideally we should do a wmb() here to make sure the changes to the
91662306a36Sopenharmony_ci	 * PE are visible to the card before we call afu_enable.
91762306a36Sopenharmony_ci	 * On ppc64 though all mmios are preceded by a 'sync' instruction hence
91862306a36Sopenharmony_ci	 * we dont dont need one here.
91962306a36Sopenharmony_ci	 */
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	result = cxl_ops->afu_reset(afu);
92262306a36Sopenharmony_ci	if (result)
92362306a36Sopenharmony_ci		return result;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	return afu_enable(afu);
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ciint cxl_attach_dedicated_process_psl8(struct cxl_context *ctx, u64 wed, u64 amr)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	struct cxl_afu *afu = ctx->afu;
93162306a36Sopenharmony_ci	u64 pid;
93262306a36Sopenharmony_ci	int rc;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	pid = (u64)current->pid << 32;
93562306a36Sopenharmony_ci	if (ctx->kernel)
93662306a36Sopenharmony_ci		pid = 0;
93762306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_PSL_PID_TID_An, pid);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SR_An, calculate_sr(ctx));
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if ((rc = cxl_write_sstp(afu, ctx->sstp0, ctx->sstp1)))
94262306a36Sopenharmony_ci		return rc;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	cxl_prefault(ctx, wed);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	if (ctx->afu->adapter->native->sl_ops->update_dedicated_ivtes)
94762306a36Sopenharmony_ci		afu->adapter->native->sl_ops->update_dedicated_ivtes(ctx);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_PSL_AMR_An, amr);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	/* master only context for dedicated */
95262306a36Sopenharmony_ci	cxl_assign_psn_space(ctx);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	if ((rc = cxl_ops->afu_reset(afu)))
95562306a36Sopenharmony_ci		return rc;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_PSL_WED_An, wed);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	return afu_enable(afu);
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic int deactivate_dedicated_process(struct cxl_afu *afu)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	dev_info(&afu->dev, "Deactivating dedicated process mode\n");
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	afu->current_mode = 0;
96762306a36Sopenharmony_ci	afu->num_procs = 0;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	cxl_chardev_afu_remove(afu);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	return 0;
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_cistatic int native_afu_deactivate_mode(struct cxl_afu *afu, int mode)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	if (mode == CXL_MODE_DIRECTED)
97762306a36Sopenharmony_ci		return deactivate_afu_directed(afu);
97862306a36Sopenharmony_ci	if (mode == CXL_MODE_DEDICATED)
97962306a36Sopenharmony_ci		return deactivate_dedicated_process(afu);
98062306a36Sopenharmony_ci	return 0;
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cistatic int native_afu_activate_mode(struct cxl_afu *afu, int mode)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	if (!mode)
98662306a36Sopenharmony_ci		return 0;
98762306a36Sopenharmony_ci	if (!(mode & afu->modes_supported))
98862306a36Sopenharmony_ci		return -EINVAL;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (!cxl_ops->link_ok(afu->adapter, afu)) {
99162306a36Sopenharmony_ci		WARN(1, "Device link is down, refusing to activate!\n");
99262306a36Sopenharmony_ci		return -EIO;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (mode == CXL_MODE_DIRECTED)
99662306a36Sopenharmony_ci		return activate_afu_directed(afu);
99762306a36Sopenharmony_ci	if ((mode == CXL_MODE_DEDICATED) &&
99862306a36Sopenharmony_ci	    (afu->adapter->native->sl_ops->activate_dedicated_process))
99962306a36Sopenharmony_ci		return afu->adapter->native->sl_ops->activate_dedicated_process(afu);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	return -EINVAL;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic int native_attach_process(struct cxl_context *ctx, bool kernel,
100562306a36Sopenharmony_ci				u64 wed, u64 amr)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)) {
100862306a36Sopenharmony_ci		WARN(1, "Device link is down, refusing to attach process!\n");
100962306a36Sopenharmony_ci		return -EIO;
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	ctx->kernel = kernel;
101362306a36Sopenharmony_ci	if ((ctx->afu->current_mode == CXL_MODE_DIRECTED) &&
101462306a36Sopenharmony_ci	    (ctx->afu->adapter->native->sl_ops->attach_afu_directed))
101562306a36Sopenharmony_ci		return ctx->afu->adapter->native->sl_ops->attach_afu_directed(ctx, wed, amr);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if ((ctx->afu->current_mode == CXL_MODE_DEDICATED) &&
101862306a36Sopenharmony_ci	    (ctx->afu->adapter->native->sl_ops->attach_dedicated_process))
101962306a36Sopenharmony_ci		return ctx->afu->adapter->native->sl_ops->attach_dedicated_process(ctx, wed, amr);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	return -EINVAL;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic inline int detach_process_native_dedicated(struct cxl_context *ctx)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	/*
102762306a36Sopenharmony_ci	 * The CAIA section 2.1.1 indicates that we need to do an AFU reset to
102862306a36Sopenharmony_ci	 * stop the AFU in dedicated mode (we therefore do not make that
102962306a36Sopenharmony_ci	 * optional like we do in the afu directed path). It does not indicate
103062306a36Sopenharmony_ci	 * that we need to do an explicit disable (which should occur
103162306a36Sopenharmony_ci	 * implicitly as part of the reset) or purge, but we do these as well
103262306a36Sopenharmony_ci	 * to be on the safe side.
103362306a36Sopenharmony_ci	 *
103462306a36Sopenharmony_ci	 * Notably we used to have some issues with the disable sequence
103562306a36Sopenharmony_ci	 * (before the sequence was spelled out in the architecture) which is
103662306a36Sopenharmony_ci	 * why we were so heavy weight in the first place, however a bug was
103762306a36Sopenharmony_ci	 * discovered that had rendered the disable operation ineffective, so
103862306a36Sopenharmony_ci	 * it is conceivable that was the sole explanation for those
103962306a36Sopenharmony_ci	 * difficulties. Point is, we should be careful and do some regression
104062306a36Sopenharmony_ci	 * testing if we ever attempt to remove any part of this procedure.
104162306a36Sopenharmony_ci	 */
104262306a36Sopenharmony_ci	cxl_ops->afu_reset(ctx->afu);
104362306a36Sopenharmony_ci	cxl_afu_disable(ctx->afu);
104462306a36Sopenharmony_ci	cxl_psl_purge(ctx->afu);
104562306a36Sopenharmony_ci	return 0;
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic void native_update_ivtes(struct cxl_context *ctx)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	if (ctx->afu->current_mode == CXL_MODE_DIRECTED)
105162306a36Sopenharmony_ci		return update_ivtes_directed(ctx);
105262306a36Sopenharmony_ci	if ((ctx->afu->current_mode == CXL_MODE_DEDICATED) &&
105362306a36Sopenharmony_ci	    (ctx->afu->adapter->native->sl_ops->update_dedicated_ivtes))
105462306a36Sopenharmony_ci		return ctx->afu->adapter->native->sl_ops->update_dedicated_ivtes(ctx);
105562306a36Sopenharmony_ci	WARN(1, "native_update_ivtes: Bad mode\n");
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_cistatic inline int detach_process_native_afu_directed(struct cxl_context *ctx)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	if (!ctx->pe_inserted)
106162306a36Sopenharmony_ci		return 0;
106262306a36Sopenharmony_ci	if (terminate_process_element(ctx))
106362306a36Sopenharmony_ci		return -1;
106462306a36Sopenharmony_ci	if (remove_process_element(ctx))
106562306a36Sopenharmony_ci		return -1;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	return 0;
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic int native_detach_process(struct cxl_context *ctx)
107162306a36Sopenharmony_ci{
107262306a36Sopenharmony_ci	trace_cxl_detach(ctx);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (ctx->afu->current_mode == CXL_MODE_DEDICATED)
107562306a36Sopenharmony_ci		return detach_process_native_dedicated(ctx);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	return detach_process_native_afu_directed(ctx);
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic int native_get_irq_info(struct cxl_afu *afu, struct cxl_irq_info *info)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	/* If the adapter has gone away, we can't get any meaningful
108362306a36Sopenharmony_ci	 * information.
108462306a36Sopenharmony_ci	 */
108562306a36Sopenharmony_ci	if (!cxl_ops->link_ok(afu->adapter, afu))
108662306a36Sopenharmony_ci		return -EIO;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	info->dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
108962306a36Sopenharmony_ci	info->dar = cxl_p2n_read(afu, CXL_PSL_DAR_An);
109062306a36Sopenharmony_ci	if (cxl_is_power8())
109162306a36Sopenharmony_ci		info->dsr = cxl_p2n_read(afu, CXL_PSL_DSR_An);
109262306a36Sopenharmony_ci	info->afu_err = cxl_p2n_read(afu, CXL_AFU_ERR_An);
109362306a36Sopenharmony_ci	info->errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An);
109462306a36Sopenharmony_ci	info->proc_handle = 0;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	return 0;
109762306a36Sopenharmony_ci}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_civoid cxl_native_irq_dump_regs_psl9(struct cxl_context *ctx)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	u64 fir1, serr;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL9_FIR1);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1);
110662306a36Sopenharmony_ci	if (ctx->afu->adapter->native->sl_ops->register_serr_irq) {
110762306a36Sopenharmony_ci		serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An);
110862306a36Sopenharmony_ci		cxl_afu_decode_psl_serr(ctx->afu, serr);
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_civoid cxl_native_irq_dump_regs_psl8(struct cxl_context *ctx)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	u64 fir1, fir2, fir_slice, serr, afu_debug;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR1);
111762306a36Sopenharmony_ci	fir2 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR2);
111862306a36Sopenharmony_ci	fir_slice = cxl_p1n_read(ctx->afu, CXL_PSL_FIR_SLICE_An);
111962306a36Sopenharmony_ci	afu_debug = cxl_p1n_read(ctx->afu, CXL_AFU_DEBUG_An);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1);
112262306a36Sopenharmony_ci	dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2);
112362306a36Sopenharmony_ci	if (ctx->afu->adapter->native->sl_ops->register_serr_irq) {
112462306a36Sopenharmony_ci		serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An);
112562306a36Sopenharmony_ci		cxl_afu_decode_psl_serr(ctx->afu, serr);
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci	dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice);
112862306a36Sopenharmony_ci	dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug);
112962306a36Sopenharmony_ci}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_cistatic irqreturn_t native_handle_psl_slice_error(struct cxl_context *ctx,
113262306a36Sopenharmony_ci						u64 dsisr, u64 errstat)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%016llx\n", errstat);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (ctx->afu->adapter->native->sl_ops->psl_irq_dump_registers)
113862306a36Sopenharmony_ci		ctx->afu->adapter->native->sl_ops->psl_irq_dump_registers(ctx);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	if (ctx->afu->adapter->native->sl_ops->debugfs_stop_trace) {
114162306a36Sopenharmony_ci		dev_crit(&ctx->afu->dev, "STOPPING CXL TRACE\n");
114262306a36Sopenharmony_ci		ctx->afu->adapter->native->sl_ops->debugfs_stop_trace(ctx->afu->adapter);
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	return cxl_ops->ack_irq(ctx, 0, errstat);
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistatic bool cxl_is_translation_fault(struct cxl_afu *afu, u64 dsisr)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	if ((cxl_is_power8()) && (dsisr & CXL_PSL_DSISR_TRANS))
115162306a36Sopenharmony_ci		return true;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if ((cxl_is_power9()) && (dsisr & CXL_PSL9_DSISR_An_TF))
115462306a36Sopenharmony_ci		return true;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	return false;
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ciirqreturn_t cxl_fail_irq_psl(struct cxl_afu *afu, struct cxl_irq_info *irq_info)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	if (cxl_is_translation_fault(afu, irq_info->dsisr))
116262306a36Sopenharmony_ci		cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);
116362306a36Sopenharmony_ci	else
116462306a36Sopenharmony_ci		cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	return IRQ_HANDLED;
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic irqreturn_t native_irq_multiplexed(int irq, void *data)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	struct cxl_afu *afu = data;
117262306a36Sopenharmony_ci	struct cxl_context *ctx;
117362306a36Sopenharmony_ci	struct cxl_irq_info irq_info;
117462306a36Sopenharmony_ci	u64 phreg = cxl_p2n_read(afu, CXL_PSL_PEHandle_An);
117562306a36Sopenharmony_ci	int ph, ret = IRQ_HANDLED, res;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	/* check if eeh kicked in while the interrupt was in flight */
117862306a36Sopenharmony_ci	if (unlikely(phreg == ~0ULL)) {
117962306a36Sopenharmony_ci		dev_warn(&afu->dev,
118062306a36Sopenharmony_ci			 "Ignoring slice interrupt(%d) due to fenced card",
118162306a36Sopenharmony_ci			 irq);
118262306a36Sopenharmony_ci		return IRQ_HANDLED;
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci	/* Mask the pe-handle from register value */
118562306a36Sopenharmony_ci	ph = phreg & 0xffff;
118662306a36Sopenharmony_ci	if ((res = native_get_irq_info(afu, &irq_info))) {
118762306a36Sopenharmony_ci		WARN(1, "Unable to get CXL IRQ Info: %i\n", res);
118862306a36Sopenharmony_ci		if (afu->adapter->native->sl_ops->fail_irq)
118962306a36Sopenharmony_ci			return afu->adapter->native->sl_ops->fail_irq(afu, &irq_info);
119062306a36Sopenharmony_ci		return ret;
119162306a36Sopenharmony_ci	}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	rcu_read_lock();
119462306a36Sopenharmony_ci	ctx = idr_find(&afu->contexts_idr, ph);
119562306a36Sopenharmony_ci	if (ctx) {
119662306a36Sopenharmony_ci		if (afu->adapter->native->sl_ops->handle_interrupt)
119762306a36Sopenharmony_ci			ret = afu->adapter->native->sl_ops->handle_interrupt(irq, ctx, &irq_info);
119862306a36Sopenharmony_ci		rcu_read_unlock();
119962306a36Sopenharmony_ci		return ret;
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci	rcu_read_unlock();
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	WARN(1, "Unable to demultiplex CXL PSL IRQ for PE %i DSISR %016llx DAR"
120462306a36Sopenharmony_ci		" %016llx\n(Possible AFU HW issue - was a term/remove acked"
120562306a36Sopenharmony_ci		" with outstanding transactions?)\n", ph, irq_info.dsisr,
120662306a36Sopenharmony_ci		irq_info.dar);
120762306a36Sopenharmony_ci	if (afu->adapter->native->sl_ops->fail_irq)
120862306a36Sopenharmony_ci		ret = afu->adapter->native->sl_ops->fail_irq(afu, &irq_info);
120962306a36Sopenharmony_ci	return ret;
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_cistatic void native_irq_wait(struct cxl_context *ctx)
121362306a36Sopenharmony_ci{
121462306a36Sopenharmony_ci	u64 dsisr;
121562306a36Sopenharmony_ci	int timeout = 1000;
121662306a36Sopenharmony_ci	int ph;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	/*
121962306a36Sopenharmony_ci	 * Wait until no further interrupts are presented by the PSL
122062306a36Sopenharmony_ci	 * for this context.
122162306a36Sopenharmony_ci	 */
122262306a36Sopenharmony_ci	while (timeout--) {
122362306a36Sopenharmony_ci		ph = cxl_p2n_read(ctx->afu, CXL_PSL_PEHandle_An) & 0xffff;
122462306a36Sopenharmony_ci		if (ph != ctx->pe)
122562306a36Sopenharmony_ci			return;
122662306a36Sopenharmony_ci		dsisr = cxl_p2n_read(ctx->afu, CXL_PSL_DSISR_An);
122762306a36Sopenharmony_ci		if (cxl_is_power8() &&
122862306a36Sopenharmony_ci		   ((dsisr & CXL_PSL_DSISR_PENDING) == 0))
122962306a36Sopenharmony_ci			return;
123062306a36Sopenharmony_ci		if (cxl_is_power9() &&
123162306a36Sopenharmony_ci		   ((dsisr & CXL_PSL9_DSISR_PENDING) == 0))
123262306a36Sopenharmony_ci			return;
123362306a36Sopenharmony_ci		/*
123462306a36Sopenharmony_ci		 * We are waiting for the workqueue to process our
123562306a36Sopenharmony_ci		 * irq, so need to let that run here.
123662306a36Sopenharmony_ci		 */
123762306a36Sopenharmony_ci		msleep(1);
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	dev_warn(&ctx->afu->dev, "WARNING: waiting on DSI for PE %i"
124162306a36Sopenharmony_ci		 " DSISR %016llx!\n", ph, dsisr);
124262306a36Sopenharmony_ci	return;
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_cistatic irqreturn_t native_slice_irq_err(int irq, void *data)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	struct cxl_afu *afu = data;
124862306a36Sopenharmony_ci	u64 errstat, serr, afu_error, dsisr;
124962306a36Sopenharmony_ci	u64 fir_slice, afu_debug, irq_mask;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	/*
125262306a36Sopenharmony_ci	 * slice err interrupt is only used with full PSL (no XSL)
125362306a36Sopenharmony_ci	 */
125462306a36Sopenharmony_ci	serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
125562306a36Sopenharmony_ci	errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An);
125662306a36Sopenharmony_ci	afu_error = cxl_p2n_read(afu, CXL_AFU_ERR_An);
125762306a36Sopenharmony_ci	dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
125862306a36Sopenharmony_ci	cxl_afu_decode_psl_serr(afu, serr);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	if (cxl_is_power8()) {
126162306a36Sopenharmony_ci		fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An);
126262306a36Sopenharmony_ci		afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An);
126362306a36Sopenharmony_ci		dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice);
126462306a36Sopenharmony_ci		dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug);
126562306a36Sopenharmony_ci	}
126662306a36Sopenharmony_ci	dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%016llx\n", errstat);
126762306a36Sopenharmony_ci	dev_crit(&afu->dev, "AFU_ERR_An: 0x%.16llx\n", afu_error);
126862306a36Sopenharmony_ci	dev_crit(&afu->dev, "PSL_DSISR_An: 0x%.16llx\n", dsisr);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	/* mask off the IRQ so it won't retrigger until the AFU is reset */
127162306a36Sopenharmony_ci	irq_mask = (serr & CXL_PSL_SERR_An_IRQS) >> 32;
127262306a36Sopenharmony_ci	serr |= irq_mask;
127362306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SERR_An, serr);
127462306a36Sopenharmony_ci	dev_info(&afu->dev, "Further such interrupts will be masked until the AFU is reset\n");
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	return IRQ_HANDLED;
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_civoid cxl_native_err_irq_dump_regs_psl9(struct cxl *adapter)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	u64 fir1;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	fir1 = cxl_p1_read(adapter, CXL_PSL9_FIR1);
128462306a36Sopenharmony_ci	dev_crit(&adapter->dev, "PSL_FIR: 0x%016llx\n", fir1);
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_civoid cxl_native_err_irq_dump_regs_psl8(struct cxl *adapter)
128862306a36Sopenharmony_ci{
128962306a36Sopenharmony_ci	u64 fir1, fir2;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	fir1 = cxl_p1_read(adapter, CXL_PSL_FIR1);
129262306a36Sopenharmony_ci	fir2 = cxl_p1_read(adapter, CXL_PSL_FIR2);
129362306a36Sopenharmony_ci	dev_crit(&adapter->dev,
129462306a36Sopenharmony_ci		 "PSL_FIR1: 0x%016llx\nPSL_FIR2: 0x%016llx\n",
129562306a36Sopenharmony_ci		 fir1, fir2);
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cistatic irqreturn_t native_irq_err(int irq, void *data)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	struct cxl *adapter = data;
130162306a36Sopenharmony_ci	u64 err_ivte;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	WARN(1, "CXL ERROR interrupt %i\n", irq);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	err_ivte = cxl_p1_read(adapter, CXL_PSL_ErrIVTE);
130662306a36Sopenharmony_ci	dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%016llx\n", err_ivte);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (adapter->native->sl_ops->debugfs_stop_trace) {
130962306a36Sopenharmony_ci		dev_crit(&adapter->dev, "STOPPING CXL TRACE\n");
131062306a36Sopenharmony_ci		adapter->native->sl_ops->debugfs_stop_trace(adapter);
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	if (adapter->native->sl_ops->err_irq_dump_registers)
131462306a36Sopenharmony_ci		adapter->native->sl_ops->err_irq_dump_registers(adapter);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	return IRQ_HANDLED;
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ciint cxl_native_register_psl_err_irq(struct cxl *adapter)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	int rc;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	adapter->irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
132462306a36Sopenharmony_ci				      dev_name(&adapter->dev));
132562306a36Sopenharmony_ci	if (!adapter->irq_name)
132662306a36Sopenharmony_ci		return -ENOMEM;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if ((rc = cxl_register_one_irq(adapter, native_irq_err, adapter,
132962306a36Sopenharmony_ci				       &adapter->native->err_hwirq,
133062306a36Sopenharmony_ci				       &adapter->native->err_virq,
133162306a36Sopenharmony_ci				       adapter->irq_name))) {
133262306a36Sopenharmony_ci		kfree(adapter->irq_name);
133362306a36Sopenharmony_ci		adapter->irq_name = NULL;
133462306a36Sopenharmony_ci		return rc;
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->native->err_hwirq & 0xffff);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	return 0;
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_civoid cxl_native_release_psl_err_irq(struct cxl *adapter)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	if (adapter->native->err_virq == 0 ||
134562306a36Sopenharmony_ci	    adapter->native->err_virq !=
134662306a36Sopenharmony_ci	    irq_find_mapping(NULL, adapter->native->err_hwirq))
134762306a36Sopenharmony_ci		return;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000);
135062306a36Sopenharmony_ci	cxl_unmap_irq(adapter->native->err_virq, adapter);
135162306a36Sopenharmony_ci	cxl_ops->release_one_irq(adapter, adapter->native->err_hwirq);
135262306a36Sopenharmony_ci	kfree(adapter->irq_name);
135362306a36Sopenharmony_ci	adapter->native->err_virq = 0;
135462306a36Sopenharmony_ci}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ciint cxl_native_register_serr_irq(struct cxl_afu *afu)
135762306a36Sopenharmony_ci{
135862306a36Sopenharmony_ci	u64 serr;
135962306a36Sopenharmony_ci	int rc;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	afu->err_irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
136262306a36Sopenharmony_ci				      dev_name(&afu->dev));
136362306a36Sopenharmony_ci	if (!afu->err_irq_name)
136462306a36Sopenharmony_ci		return -ENOMEM;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	if ((rc = cxl_register_one_irq(afu->adapter, native_slice_irq_err, afu,
136762306a36Sopenharmony_ci				       &afu->serr_hwirq,
136862306a36Sopenharmony_ci				       &afu->serr_virq, afu->err_irq_name))) {
136962306a36Sopenharmony_ci		kfree(afu->err_irq_name);
137062306a36Sopenharmony_ci		afu->err_irq_name = NULL;
137162306a36Sopenharmony_ci		return rc;
137262306a36Sopenharmony_ci	}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
137562306a36Sopenharmony_ci	if (cxl_is_power8())
137662306a36Sopenharmony_ci		serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff);
137762306a36Sopenharmony_ci	if (cxl_is_power9()) {
137862306a36Sopenharmony_ci		/*
137962306a36Sopenharmony_ci		 * By default, all errors are masked. So don't set all masks.
138062306a36Sopenharmony_ci		 * Slice errors will be transfered.
138162306a36Sopenharmony_ci		 */
138262306a36Sopenharmony_ci		serr = (serr & ~0xff0000007fffffffULL) | (afu->serr_hwirq & 0xffff);
138362306a36Sopenharmony_ci	}
138462306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SERR_An, serr);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	return 0;
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_civoid cxl_native_release_serr_irq(struct cxl_afu *afu)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	if (afu->serr_virq == 0 ||
139262306a36Sopenharmony_ci	    afu->serr_virq != irq_find_mapping(NULL, afu->serr_hwirq))
139362306a36Sopenharmony_ci		return;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000);
139662306a36Sopenharmony_ci	cxl_unmap_irq(afu->serr_virq, afu);
139762306a36Sopenharmony_ci	cxl_ops->release_one_irq(afu->adapter, afu->serr_hwirq);
139862306a36Sopenharmony_ci	kfree(afu->err_irq_name);
139962306a36Sopenharmony_ci	afu->serr_virq = 0;
140062306a36Sopenharmony_ci}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ciint cxl_native_register_psl_irq(struct cxl_afu *afu)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	int rc;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	afu->psl_irq_name = kasprintf(GFP_KERNEL, "cxl-%s",
140762306a36Sopenharmony_ci				      dev_name(&afu->dev));
140862306a36Sopenharmony_ci	if (!afu->psl_irq_name)
140962306a36Sopenharmony_ci		return -ENOMEM;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	if ((rc = cxl_register_one_irq(afu->adapter, native_irq_multiplexed,
141262306a36Sopenharmony_ci				    afu, &afu->native->psl_hwirq, &afu->native->psl_virq,
141362306a36Sopenharmony_ci				    afu->psl_irq_name))) {
141462306a36Sopenharmony_ci		kfree(afu->psl_irq_name);
141562306a36Sopenharmony_ci		afu->psl_irq_name = NULL;
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci	return rc;
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_civoid cxl_native_release_psl_irq(struct cxl_afu *afu)
142162306a36Sopenharmony_ci{
142262306a36Sopenharmony_ci	if (afu->native->psl_virq == 0 ||
142362306a36Sopenharmony_ci	    afu->native->psl_virq !=
142462306a36Sopenharmony_ci	    irq_find_mapping(NULL, afu->native->psl_hwirq))
142562306a36Sopenharmony_ci		return;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	cxl_unmap_irq(afu->native->psl_virq, afu);
142862306a36Sopenharmony_ci	cxl_ops->release_one_irq(afu->adapter, afu->native->psl_hwirq);
142962306a36Sopenharmony_ci	kfree(afu->psl_irq_name);
143062306a36Sopenharmony_ci	afu->native->psl_virq = 0;
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_cistatic void recover_psl_err(struct cxl_afu *afu, u64 errstat)
143462306a36Sopenharmony_ci{
143562306a36Sopenharmony_ci	u64 dsisr;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	pr_devel("RECOVERING FROM PSL ERROR... (0x%016llx)\n", errstat);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	/* Clear PSL_DSISR[PE] */
144062306a36Sopenharmony_ci	dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
144162306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_PSL_DSISR_An, dsisr & ~CXL_PSL_DSISR_An_PE);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	/* Write 1s to clear error status bits */
144462306a36Sopenharmony_ci	cxl_p2n_write(afu, CXL_PSL_ErrStat_An, errstat);
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic int native_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask)
144862306a36Sopenharmony_ci{
144962306a36Sopenharmony_ci	trace_cxl_psl_irq_ack(ctx, tfc);
145062306a36Sopenharmony_ci	if (tfc)
145162306a36Sopenharmony_ci		cxl_p2n_write(ctx->afu, CXL_PSL_TFC_An, tfc);
145262306a36Sopenharmony_ci	if (psl_reset_mask)
145362306a36Sopenharmony_ci		recover_psl_err(ctx->afu, psl_reset_mask);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	return 0;
145662306a36Sopenharmony_ci}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ciint cxl_check_error(struct cxl_afu *afu)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	return (cxl_p1n_read(afu, CXL_PSL_SCNTL_An) == ~0ULL);
146162306a36Sopenharmony_ci}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_cistatic bool native_support_attributes(const char *attr_name,
146462306a36Sopenharmony_ci				      enum cxl_attrs type)
146562306a36Sopenharmony_ci{
146662306a36Sopenharmony_ci	return true;
146762306a36Sopenharmony_ci}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cistatic int native_afu_cr_read64(struct cxl_afu *afu, int cr, u64 off, u64 *out)
147062306a36Sopenharmony_ci{
147162306a36Sopenharmony_ci	if (unlikely(!cxl_ops->link_ok(afu->adapter, afu)))
147262306a36Sopenharmony_ci		return -EIO;
147362306a36Sopenharmony_ci	if (unlikely(off >= afu->crs_len))
147462306a36Sopenharmony_ci		return -ERANGE;
147562306a36Sopenharmony_ci	*out = in_le64(afu->native->afu_desc_mmio + afu->crs_offset +
147662306a36Sopenharmony_ci		(cr * afu->crs_len) + off);
147762306a36Sopenharmony_ci	return 0;
147862306a36Sopenharmony_ci}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_cistatic int native_afu_cr_read32(struct cxl_afu *afu, int cr, u64 off, u32 *out)
148162306a36Sopenharmony_ci{
148262306a36Sopenharmony_ci	if (unlikely(!cxl_ops->link_ok(afu->adapter, afu)))
148362306a36Sopenharmony_ci		return -EIO;
148462306a36Sopenharmony_ci	if (unlikely(off >= afu->crs_len))
148562306a36Sopenharmony_ci		return -ERANGE;
148662306a36Sopenharmony_ci	*out = in_le32(afu->native->afu_desc_mmio + afu->crs_offset +
148762306a36Sopenharmony_ci		(cr * afu->crs_len) + off);
148862306a36Sopenharmony_ci	return 0;
148962306a36Sopenharmony_ci}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_cistatic int native_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off, u16 *out)
149262306a36Sopenharmony_ci{
149362306a36Sopenharmony_ci	u64 aligned_off = off & ~0x3L;
149462306a36Sopenharmony_ci	u32 val;
149562306a36Sopenharmony_ci	int rc;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	rc = native_afu_cr_read32(afu, cr, aligned_off, &val);
149862306a36Sopenharmony_ci	if (!rc)
149962306a36Sopenharmony_ci		*out = (val >> ((off & 0x3) * 8)) & 0xffff;
150062306a36Sopenharmony_ci	return rc;
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_cistatic int native_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off, u8 *out)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	u64 aligned_off = off & ~0x3L;
150662306a36Sopenharmony_ci	u32 val;
150762306a36Sopenharmony_ci	int rc;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	rc = native_afu_cr_read32(afu, cr, aligned_off, &val);
151062306a36Sopenharmony_ci	if (!rc)
151162306a36Sopenharmony_ci		*out = (val >> ((off & 0x3) * 8)) & 0xff;
151262306a36Sopenharmony_ci	return rc;
151362306a36Sopenharmony_ci}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_cistatic int native_afu_cr_write32(struct cxl_afu *afu, int cr, u64 off, u32 in)
151662306a36Sopenharmony_ci{
151762306a36Sopenharmony_ci	if (unlikely(!cxl_ops->link_ok(afu->adapter, afu)))
151862306a36Sopenharmony_ci		return -EIO;
151962306a36Sopenharmony_ci	if (unlikely(off >= afu->crs_len))
152062306a36Sopenharmony_ci		return -ERANGE;
152162306a36Sopenharmony_ci	out_le32(afu->native->afu_desc_mmio + afu->crs_offset +
152262306a36Sopenharmony_ci		(cr * afu->crs_len) + off, in);
152362306a36Sopenharmony_ci	return 0;
152462306a36Sopenharmony_ci}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cistatic int native_afu_cr_write16(struct cxl_afu *afu, int cr, u64 off, u16 in)
152762306a36Sopenharmony_ci{
152862306a36Sopenharmony_ci	u64 aligned_off = off & ~0x3L;
152962306a36Sopenharmony_ci	u32 val32, mask, shift;
153062306a36Sopenharmony_ci	int rc;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	rc = native_afu_cr_read32(afu, cr, aligned_off, &val32);
153362306a36Sopenharmony_ci	if (rc)
153462306a36Sopenharmony_ci		return rc;
153562306a36Sopenharmony_ci	shift = (off & 0x3) * 8;
153662306a36Sopenharmony_ci	WARN_ON(shift == 24);
153762306a36Sopenharmony_ci	mask = 0xffff << shift;
153862306a36Sopenharmony_ci	val32 = (val32 & ~mask) | (in << shift);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	rc = native_afu_cr_write32(afu, cr, aligned_off, val32);
154162306a36Sopenharmony_ci	return rc;
154262306a36Sopenharmony_ci}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_cistatic int native_afu_cr_write8(struct cxl_afu *afu, int cr, u64 off, u8 in)
154562306a36Sopenharmony_ci{
154662306a36Sopenharmony_ci	u64 aligned_off = off & ~0x3L;
154762306a36Sopenharmony_ci	u32 val32, mask, shift;
154862306a36Sopenharmony_ci	int rc;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	rc = native_afu_cr_read32(afu, cr, aligned_off, &val32);
155162306a36Sopenharmony_ci	if (rc)
155262306a36Sopenharmony_ci		return rc;
155362306a36Sopenharmony_ci	shift = (off & 0x3) * 8;
155462306a36Sopenharmony_ci	mask = 0xff << shift;
155562306a36Sopenharmony_ci	val32 = (val32 & ~mask) | (in << shift);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	rc = native_afu_cr_write32(afu, cr, aligned_off, val32);
155862306a36Sopenharmony_ci	return rc;
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ciconst struct cxl_backend_ops cxl_native_ops = {
156262306a36Sopenharmony_ci	.module = THIS_MODULE,
156362306a36Sopenharmony_ci	.adapter_reset = cxl_pci_reset,
156462306a36Sopenharmony_ci	.alloc_one_irq = cxl_pci_alloc_one_irq,
156562306a36Sopenharmony_ci	.release_one_irq = cxl_pci_release_one_irq,
156662306a36Sopenharmony_ci	.alloc_irq_ranges = cxl_pci_alloc_irq_ranges,
156762306a36Sopenharmony_ci	.release_irq_ranges = cxl_pci_release_irq_ranges,
156862306a36Sopenharmony_ci	.setup_irq = cxl_pci_setup_irq,
156962306a36Sopenharmony_ci	.handle_psl_slice_error = native_handle_psl_slice_error,
157062306a36Sopenharmony_ci	.psl_interrupt = NULL,
157162306a36Sopenharmony_ci	.ack_irq = native_ack_irq,
157262306a36Sopenharmony_ci	.irq_wait = native_irq_wait,
157362306a36Sopenharmony_ci	.attach_process = native_attach_process,
157462306a36Sopenharmony_ci	.detach_process = native_detach_process,
157562306a36Sopenharmony_ci	.update_ivtes = native_update_ivtes,
157662306a36Sopenharmony_ci	.support_attributes = native_support_attributes,
157762306a36Sopenharmony_ci	.link_ok = cxl_adapter_link_ok,
157862306a36Sopenharmony_ci	.release_afu = cxl_pci_release_afu,
157962306a36Sopenharmony_ci	.afu_read_err_buffer = cxl_pci_afu_read_err_buffer,
158062306a36Sopenharmony_ci	.afu_check_and_enable = native_afu_check_and_enable,
158162306a36Sopenharmony_ci	.afu_activate_mode = native_afu_activate_mode,
158262306a36Sopenharmony_ci	.afu_deactivate_mode = native_afu_deactivate_mode,
158362306a36Sopenharmony_ci	.afu_reset = native_afu_reset,
158462306a36Sopenharmony_ci	.afu_cr_read8 = native_afu_cr_read8,
158562306a36Sopenharmony_ci	.afu_cr_read16 = native_afu_cr_read16,
158662306a36Sopenharmony_ci	.afu_cr_read32 = native_afu_cr_read32,
158762306a36Sopenharmony_ci	.afu_cr_read64 = native_afu_cr_read64,
158862306a36Sopenharmony_ci	.afu_cr_write8 = native_afu_cr_write8,
158962306a36Sopenharmony_ci	.afu_cr_write16 = native_afu_cr_write16,
159062306a36Sopenharmony_ci	.afu_cr_write32 = native_afu_cr_write32,
159162306a36Sopenharmony_ci	.read_adapter_vpd = cxl_pci_read_adapter_vpd,
159262306a36Sopenharmony_ci};
1593