xref: /kernel/linux/linux-6.6/drivers/misc/cxl/of.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2015 IBM Corp.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/kernel.h>
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/platform_device.h>
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/of_address.h>
1162306a36Sopenharmony_ci#include <linux/of_platform.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "cxl.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic const __be32 *read_prop_string(const struct device_node *np,
1762306a36Sopenharmony_ci				const char *prop_name)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	const __be32 *prop;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	prop = of_get_property(np, prop_name, NULL);
2262306a36Sopenharmony_ci	if (cxl_verbose && prop)
2362306a36Sopenharmony_ci		pr_info("%s: %s\n", prop_name, (char *) prop);
2462306a36Sopenharmony_ci	return prop;
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic const __be32 *read_prop_dword(const struct device_node *np,
2862306a36Sopenharmony_ci				const char *prop_name, u32 *val)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	const __be32 *prop;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	prop = of_get_property(np, prop_name, NULL);
3362306a36Sopenharmony_ci	if (prop)
3462306a36Sopenharmony_ci		*val = be32_to_cpu(prop[0]);
3562306a36Sopenharmony_ci	if (cxl_verbose && prop)
3662306a36Sopenharmony_ci		pr_info("%s: %#x (%u)\n", prop_name, *val, *val);
3762306a36Sopenharmony_ci	return prop;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic const __be64 *read_prop64_dword(const struct device_node *np,
4162306a36Sopenharmony_ci				const char *prop_name, u64 *val)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	const __be64 *prop;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	prop = of_get_property(np, prop_name, NULL);
4662306a36Sopenharmony_ci	if (prop)
4762306a36Sopenharmony_ci		*val = be64_to_cpu(prop[0]);
4862306a36Sopenharmony_ci	if (cxl_verbose && prop)
4962306a36Sopenharmony_ci		pr_info("%s: %#llx (%llu)\n", prop_name, *val, *val);
5062306a36Sopenharmony_ci	return prop;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic int read_handle(struct device_node *np, u64 *handle)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	const __be32 *prop;
5762306a36Sopenharmony_ci	u64 size;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/* Get address and size of the node */
6062306a36Sopenharmony_ci	prop = of_get_address(np, 0, &size, NULL);
6162306a36Sopenharmony_ci	if (size)
6262306a36Sopenharmony_ci		return -EINVAL;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	/* Helper to read a big number; size is in cells (not bytes) */
6562306a36Sopenharmony_ci	*handle = of_read_number(prop, of_n_addr_cells(np));
6662306a36Sopenharmony_ci	return 0;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int read_phys_addr(struct device_node *np, char *prop_name,
7062306a36Sopenharmony_ci			struct cxl_afu *afu)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	int i, len, entry_size, naddr, nsize, type;
7362306a36Sopenharmony_ci	u64 addr, size;
7462306a36Sopenharmony_ci	const __be32 *prop;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	naddr = of_n_addr_cells(np);
7762306a36Sopenharmony_ci	nsize = of_n_size_cells(np);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	prop = of_get_property(np, prop_name, &len);
8062306a36Sopenharmony_ci	if (prop) {
8162306a36Sopenharmony_ci		entry_size = naddr + nsize;
8262306a36Sopenharmony_ci		for (i = 0; i < (len / 4); i += entry_size, prop += entry_size) {
8362306a36Sopenharmony_ci			type = be32_to_cpu(prop[0]);
8462306a36Sopenharmony_ci			addr = of_read_number(prop, naddr);
8562306a36Sopenharmony_ci			size = of_read_number(&prop[naddr], nsize);
8662306a36Sopenharmony_ci			switch (type) {
8762306a36Sopenharmony_ci			case 0: /* unit address */
8862306a36Sopenharmony_ci				afu->guest->handle = addr;
8962306a36Sopenharmony_ci				break;
9062306a36Sopenharmony_ci			case 1: /* p2 area */
9162306a36Sopenharmony_ci				afu->guest->p2n_phys += addr;
9262306a36Sopenharmony_ci				afu->guest->p2n_size = size;
9362306a36Sopenharmony_ci				break;
9462306a36Sopenharmony_ci			case 2: /* problem state area */
9562306a36Sopenharmony_ci				afu->psn_phys += addr;
9662306a36Sopenharmony_ci				afu->adapter->ps_size = size;
9762306a36Sopenharmony_ci				break;
9862306a36Sopenharmony_ci			default:
9962306a36Sopenharmony_ci				pr_err("Invalid address type %d found in %s property of AFU\n",
10062306a36Sopenharmony_ci					type, prop_name);
10162306a36Sopenharmony_ci				return -EINVAL;
10262306a36Sopenharmony_ci			}
10362306a36Sopenharmony_ci			if (cxl_verbose)
10462306a36Sopenharmony_ci				pr_info("%s: %#x %#llx (size %#llx)\n",
10562306a36Sopenharmony_ci					prop_name, type, addr, size);
10662306a36Sopenharmony_ci		}
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci	return 0;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int read_vpd(struct cxl *adapter, struct cxl_afu *afu)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	char vpd[256];
11462306a36Sopenharmony_ci	int rc;
11562306a36Sopenharmony_ci	size_t len = sizeof(vpd);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	memset(vpd, 0, len);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (adapter)
12062306a36Sopenharmony_ci		rc = cxl_guest_read_adapter_vpd(adapter, vpd, len);
12162306a36Sopenharmony_ci	else
12262306a36Sopenharmony_ci		rc = cxl_guest_read_afu_vpd(afu, vpd, len);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (rc > 0) {
12562306a36Sopenharmony_ci		cxl_dump_debug_buffer(vpd, rc);
12662306a36Sopenharmony_ci		rc = 0;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci	return rc;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciint cxl_of_read_afu_handle(struct cxl_afu *afu, struct device_node *afu_np)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	if (read_handle(afu_np, &afu->guest->handle))
13462306a36Sopenharmony_ci		return -EINVAL;
13562306a36Sopenharmony_ci	pr_devel("AFU handle: 0x%.16llx\n", afu->guest->handle);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	return 0;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciint cxl_of_read_afu_properties(struct cxl_afu *afu, struct device_node *np)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	int i, len, rc;
14362306a36Sopenharmony_ci	char *p;
14462306a36Sopenharmony_ci	const __be32 *prop;
14562306a36Sopenharmony_ci	u16 device_id, vendor_id;
14662306a36Sopenharmony_ci	u32 val = 0, class_code;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* Properties are read in the same order as listed in PAPR */
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (cxl_verbose) {
15162306a36Sopenharmony_ci		pr_info("Dump of the 'ibm,coherent-platform-function' node properties:\n");
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		prop = of_get_property(np, "compatible", &len);
15462306a36Sopenharmony_ci		i = 0;
15562306a36Sopenharmony_ci		while (i < len) {
15662306a36Sopenharmony_ci			p = (char *) prop + i;
15762306a36Sopenharmony_ci			pr_info("compatible: %s\n", p);
15862306a36Sopenharmony_ci			i += strlen(p) + 1;
15962306a36Sopenharmony_ci		}
16062306a36Sopenharmony_ci		read_prop_string(np, "name");
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	rc = read_phys_addr(np, "reg", afu);
16462306a36Sopenharmony_ci	if (rc)
16562306a36Sopenharmony_ci		return rc;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	rc = read_phys_addr(np, "assigned-addresses", afu);
16862306a36Sopenharmony_ci	if (rc)
16962306a36Sopenharmony_ci		return rc;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (afu->psn_phys == 0)
17262306a36Sopenharmony_ci		afu->psa = false;
17362306a36Sopenharmony_ci	else
17462306a36Sopenharmony_ci		afu->psa = true;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (cxl_verbose) {
17762306a36Sopenharmony_ci		read_prop_string(np, "ibm,loc-code");
17862306a36Sopenharmony_ci		read_prop_string(np, "device_type");
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	read_prop_dword(np, "ibm,#processes", &afu->max_procs_virtualised);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (cxl_verbose) {
18462306a36Sopenharmony_ci		read_prop_dword(np, "ibm,scratchpad-size", &val);
18562306a36Sopenharmony_ci		read_prop_dword(np, "ibm,programmable", &val);
18662306a36Sopenharmony_ci		read_prop_string(np, "ibm,phandle");
18762306a36Sopenharmony_ci		read_vpd(NULL, afu);
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	read_prop_dword(np, "ibm,max-ints-per-process", &afu->guest->max_ints);
19162306a36Sopenharmony_ci	afu->irqs_max = afu->guest->max_ints;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	prop = read_prop_dword(np, "ibm,min-ints-per-process", &afu->pp_irqs);
19462306a36Sopenharmony_ci	if (prop) {
19562306a36Sopenharmony_ci		/* One extra interrupt for the PSL interrupt is already
19662306a36Sopenharmony_ci		 * included. Remove it now to keep only AFU interrupts and
19762306a36Sopenharmony_ci		 * match the native case.
19862306a36Sopenharmony_ci		 */
19962306a36Sopenharmony_ci		afu->pp_irqs--;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (cxl_verbose) {
20362306a36Sopenharmony_ci		read_prop_dword(np, "ibm,max-ints", &val);
20462306a36Sopenharmony_ci		read_prop_dword(np, "ibm,vpd-size", &val);
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	read_prop64_dword(np, "ibm,error-buffer-size", &afu->eb_len);
20862306a36Sopenharmony_ci	afu->eb_offset = 0;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (cxl_verbose)
21162306a36Sopenharmony_ci		read_prop_dword(np, "ibm,config-record-type", &val);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	read_prop64_dword(np, "ibm,config-record-size", &afu->crs_len);
21462306a36Sopenharmony_ci	afu->crs_offset = 0;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	read_prop_dword(np, "ibm,#config-records", &afu->crs_num);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (cxl_verbose) {
21962306a36Sopenharmony_ci		for (i = 0; i < afu->crs_num; i++) {
22062306a36Sopenharmony_ci			rc = cxl_ops->afu_cr_read16(afu, i, PCI_DEVICE_ID,
22162306a36Sopenharmony_ci						&device_id);
22262306a36Sopenharmony_ci			if (!rc)
22362306a36Sopenharmony_ci				pr_info("record %d - device-id: %#x\n",
22462306a36Sopenharmony_ci					i, device_id);
22562306a36Sopenharmony_ci			rc = cxl_ops->afu_cr_read16(afu, i, PCI_VENDOR_ID,
22662306a36Sopenharmony_ci						&vendor_id);
22762306a36Sopenharmony_ci			if (!rc)
22862306a36Sopenharmony_ci				pr_info("record %d - vendor-id: %#x\n",
22962306a36Sopenharmony_ci					i, vendor_id);
23062306a36Sopenharmony_ci			rc = cxl_ops->afu_cr_read32(afu, i, PCI_CLASS_REVISION,
23162306a36Sopenharmony_ci						&class_code);
23262306a36Sopenharmony_ci			if (!rc) {
23362306a36Sopenharmony_ci				class_code >>= 8;
23462306a36Sopenharmony_ci				pr_info("record %d - class-code: %#x\n",
23562306a36Sopenharmony_ci					i, class_code);
23662306a36Sopenharmony_ci			}
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		read_prop_dword(np, "ibm,function-number", &val);
24062306a36Sopenharmony_ci		read_prop_dword(np, "ibm,privileged-function", &val);
24162306a36Sopenharmony_ci		read_prop_dword(np, "vendor-id", &val);
24262306a36Sopenharmony_ci		read_prop_dword(np, "device-id", &val);
24362306a36Sopenharmony_ci		read_prop_dword(np, "revision-id", &val);
24462306a36Sopenharmony_ci		read_prop_dword(np, "class-code", &val);
24562306a36Sopenharmony_ci		read_prop_dword(np, "subsystem-vendor-id", &val);
24662306a36Sopenharmony_ci		read_prop_dword(np, "subsystem-id", &val);
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci	/*
24962306a36Sopenharmony_ci	 * if "ibm,process-mmio" doesn't exist then per-process mmio is
25062306a36Sopenharmony_ci	 * not supported
25162306a36Sopenharmony_ci	 */
25262306a36Sopenharmony_ci	val = 0;
25362306a36Sopenharmony_ci	prop = read_prop_dword(np, "ibm,process-mmio", &val);
25462306a36Sopenharmony_ci	if (prop && val == 1)
25562306a36Sopenharmony_ci		afu->pp_psa = true;
25662306a36Sopenharmony_ci	else
25762306a36Sopenharmony_ci		afu->pp_psa = false;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (cxl_verbose) {
26062306a36Sopenharmony_ci		read_prop_dword(np, "ibm,supports-aur", &val);
26162306a36Sopenharmony_ci		read_prop_dword(np, "ibm,supports-csrp", &val);
26262306a36Sopenharmony_ci		read_prop_dword(np, "ibm,supports-prr", &val);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	prop = read_prop_dword(np, "ibm,function-error-interrupt", &val);
26662306a36Sopenharmony_ci	if (prop)
26762306a36Sopenharmony_ci		afu->serr_hwirq = val;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	pr_devel("AFU handle: %#llx\n", afu->guest->handle);
27062306a36Sopenharmony_ci	pr_devel("p2n_phys: %#llx (size %#llx)\n",
27162306a36Sopenharmony_ci		afu->guest->p2n_phys, afu->guest->p2n_size);
27262306a36Sopenharmony_ci	pr_devel("psn_phys: %#llx (size %#llx)\n",
27362306a36Sopenharmony_ci		afu->psn_phys, afu->adapter->ps_size);
27462306a36Sopenharmony_ci	pr_devel("Max number of processes virtualised=%i\n",
27562306a36Sopenharmony_ci		afu->max_procs_virtualised);
27662306a36Sopenharmony_ci	pr_devel("Per-process irqs min=%i, max=%i\n", afu->pp_irqs,
27762306a36Sopenharmony_ci		 afu->irqs_max);
27862306a36Sopenharmony_ci	pr_devel("Slice error interrupt=%#lx\n", afu->serr_hwirq);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	return 0;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int read_adapter_irq_config(struct cxl *adapter, struct device_node *np)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	const __be32 *ranges;
28662306a36Sopenharmony_ci	int len, nranges, i;
28762306a36Sopenharmony_ci	struct irq_avail *cur;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ranges = of_get_property(np, "interrupt-ranges", &len);
29062306a36Sopenharmony_ci	if (ranges == NULL || len < (2 * sizeof(int)))
29162306a36Sopenharmony_ci		return -EINVAL;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/*
29462306a36Sopenharmony_ci	 * encoded array of two cells per entry, each cell encoded as
29562306a36Sopenharmony_ci	 * with encode-int
29662306a36Sopenharmony_ci	 */
29762306a36Sopenharmony_ci	nranges = len / (2 * sizeof(int));
29862306a36Sopenharmony_ci	if (nranges == 0 || (nranges * 2 * sizeof(int)) != len)
29962306a36Sopenharmony_ci		return -EINVAL;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	adapter->guest->irq_avail = kcalloc(nranges, sizeof(struct irq_avail),
30262306a36Sopenharmony_ci					    GFP_KERNEL);
30362306a36Sopenharmony_ci	if (adapter->guest->irq_avail == NULL)
30462306a36Sopenharmony_ci		return -ENOMEM;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	adapter->guest->irq_base_offset = be32_to_cpu(ranges[0]);
30762306a36Sopenharmony_ci	for (i = 0; i < nranges; i++) {
30862306a36Sopenharmony_ci		cur = &adapter->guest->irq_avail[i];
30962306a36Sopenharmony_ci		cur->offset = be32_to_cpu(ranges[i * 2]);
31062306a36Sopenharmony_ci		cur->range  = be32_to_cpu(ranges[i * 2 + 1]);
31162306a36Sopenharmony_ci		cur->bitmap = bitmap_zalloc(cur->range, GFP_KERNEL);
31262306a36Sopenharmony_ci		if (cur->bitmap == NULL)
31362306a36Sopenharmony_ci			goto err;
31462306a36Sopenharmony_ci		if (cur->offset < adapter->guest->irq_base_offset)
31562306a36Sopenharmony_ci			adapter->guest->irq_base_offset = cur->offset;
31662306a36Sopenharmony_ci		if (cxl_verbose)
31762306a36Sopenharmony_ci			pr_info("available IRQ range: %#lx-%#lx (%lu)\n",
31862306a36Sopenharmony_ci				cur->offset, cur->offset + cur->range - 1,
31962306a36Sopenharmony_ci				cur->range);
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci	adapter->guest->irq_nranges = nranges;
32262306a36Sopenharmony_ci	spin_lock_init(&adapter->guest->irq_alloc_lock);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	return 0;
32562306a36Sopenharmony_cierr:
32662306a36Sopenharmony_ci	for (i--; i >= 0; i--) {
32762306a36Sopenharmony_ci		cur = &adapter->guest->irq_avail[i];
32862306a36Sopenharmony_ci		bitmap_free(cur->bitmap);
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci	kfree(adapter->guest->irq_avail);
33162306a36Sopenharmony_ci	adapter->guest->irq_avail = NULL;
33262306a36Sopenharmony_ci	return -ENOMEM;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciint cxl_of_read_adapter_handle(struct cxl *adapter, struct device_node *np)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	if (read_handle(np, &adapter->guest->handle))
33862306a36Sopenharmony_ci		return -EINVAL;
33962306a36Sopenharmony_ci	pr_devel("Adapter handle: 0x%.16llx\n", adapter->guest->handle);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	return 0;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ciint cxl_of_read_adapter_properties(struct cxl *adapter, struct device_node *np)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	int rc, len, naddr, i;
34762306a36Sopenharmony_ci	char *p;
34862306a36Sopenharmony_ci	const __be32 *prop;
34962306a36Sopenharmony_ci	u32 val = 0;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Properties are read in the same order as listed in PAPR */
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	naddr = of_n_addr_cells(np);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (cxl_verbose) {
35662306a36Sopenharmony_ci		pr_info("Dump of the 'ibm,coherent-platform-facility' node properties:\n");
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		read_prop_dword(np, "#address-cells", &val);
35962306a36Sopenharmony_ci		read_prop_dword(np, "#size-cells", &val);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		prop = of_get_property(np, "compatible", &len);
36262306a36Sopenharmony_ci		i = 0;
36362306a36Sopenharmony_ci		while (i < len) {
36462306a36Sopenharmony_ci			p = (char *) prop + i;
36562306a36Sopenharmony_ci			pr_info("compatible: %s\n", p);
36662306a36Sopenharmony_ci			i += strlen(p) + 1;
36762306a36Sopenharmony_ci		}
36862306a36Sopenharmony_ci		read_prop_string(np, "name");
36962306a36Sopenharmony_ci		read_prop_string(np, "model");
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		prop = of_get_property(np, "reg", NULL);
37262306a36Sopenharmony_ci		if (prop) {
37362306a36Sopenharmony_ci			pr_info("reg: addr:%#llx size:%#x\n",
37462306a36Sopenharmony_ci				of_read_number(prop, naddr),
37562306a36Sopenharmony_ci				be32_to_cpu(prop[naddr]));
37662306a36Sopenharmony_ci		}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		read_prop_string(np, "ibm,loc-code");
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	if ((rc = read_adapter_irq_config(adapter, np)))
38262306a36Sopenharmony_ci		return rc;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (cxl_verbose) {
38562306a36Sopenharmony_ci		read_prop_string(np, "device_type");
38662306a36Sopenharmony_ci		read_prop_string(np, "ibm,phandle");
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	prop = read_prop_dword(np, "ibm,caia-version", &val);
39062306a36Sopenharmony_ci	if (prop) {
39162306a36Sopenharmony_ci		adapter->caia_major = (val & 0xFF00) >> 8;
39262306a36Sopenharmony_ci		adapter->caia_minor = val & 0xFF;
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	prop = read_prop_dword(np, "ibm,psl-revision", &val);
39662306a36Sopenharmony_ci	if (prop)
39762306a36Sopenharmony_ci		adapter->psl_rev = val;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	prop = read_prop_string(np, "status");
40062306a36Sopenharmony_ci	if (prop) {
40162306a36Sopenharmony_ci		adapter->guest->status = kasprintf(GFP_KERNEL, "%s", (char *) prop);
40262306a36Sopenharmony_ci		if (adapter->guest->status == NULL)
40362306a36Sopenharmony_ci			return -ENOMEM;
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	prop = read_prop_dword(np, "vendor-id", &val);
40762306a36Sopenharmony_ci	if (prop)
40862306a36Sopenharmony_ci		adapter->guest->vendor = val;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	prop = read_prop_dword(np, "device-id", &val);
41162306a36Sopenharmony_ci	if (prop)
41262306a36Sopenharmony_ci		adapter->guest->device = val;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (cxl_verbose) {
41562306a36Sopenharmony_ci		read_prop_dword(np, "ibm,privileged-facility", &val);
41662306a36Sopenharmony_ci		read_prop_dword(np, "revision-id", &val);
41762306a36Sopenharmony_ci		read_prop_dword(np, "class-code", &val);
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	prop = read_prop_dword(np, "subsystem-vendor-id", &val);
42162306a36Sopenharmony_ci	if (prop)
42262306a36Sopenharmony_ci		adapter->guest->subsystem_vendor = val;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	prop = read_prop_dword(np, "subsystem-id", &val);
42562306a36Sopenharmony_ci	if (prop)
42662306a36Sopenharmony_ci		adapter->guest->subsystem = val;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (cxl_verbose)
42962306a36Sopenharmony_ci		read_vpd(adapter, NULL);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic int cxl_of_remove(struct platform_device *pdev)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct cxl *adapter;
43762306a36Sopenharmony_ci	int afu;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	adapter = dev_get_drvdata(&pdev->dev);
44062306a36Sopenharmony_ci	for (afu = 0; afu < adapter->slices; afu++)
44162306a36Sopenharmony_ci		cxl_guest_remove_afu(adapter->afu[afu]);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	cxl_guest_remove_adapter(adapter);
44462306a36Sopenharmony_ci	return 0;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic void cxl_of_shutdown(struct platform_device *pdev)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	cxl_of_remove(pdev);
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ciint cxl_of_probe(struct platform_device *pdev)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct device_node *np = NULL;
45562306a36Sopenharmony_ci	struct device_node *afu_np = NULL;
45662306a36Sopenharmony_ci	struct cxl *adapter = NULL;
45762306a36Sopenharmony_ci	int ret;
45862306a36Sopenharmony_ci	int slice = 0, slice_ok = 0;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	pr_devel("in %s\n", __func__);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	np = pdev->dev.of_node;
46362306a36Sopenharmony_ci	if (np == NULL)
46462306a36Sopenharmony_ci		return -ENODEV;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* init adapter */
46762306a36Sopenharmony_ci	adapter = cxl_guest_init_adapter(np, pdev);
46862306a36Sopenharmony_ci	if (IS_ERR(adapter)) {
46962306a36Sopenharmony_ci		dev_err(&pdev->dev, "guest_init_adapter failed: %li\n", PTR_ERR(adapter));
47062306a36Sopenharmony_ci		return PTR_ERR(adapter);
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	/* init afu */
47462306a36Sopenharmony_ci	for_each_child_of_node(np, afu_np) {
47562306a36Sopenharmony_ci		if ((ret = cxl_guest_init_afu(adapter, slice, afu_np)))
47662306a36Sopenharmony_ci			dev_err(&pdev->dev, "AFU %i failed to initialise: %i\n",
47762306a36Sopenharmony_ci				slice, ret);
47862306a36Sopenharmony_ci		else
47962306a36Sopenharmony_ci			slice_ok++;
48062306a36Sopenharmony_ci		slice++;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (slice_ok == 0) {
48462306a36Sopenharmony_ci		dev_info(&pdev->dev, "No active AFU");
48562306a36Sopenharmony_ci		adapter->slices = 0;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	return 0;
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic const struct of_device_id cxl_of_match[] = {
49262306a36Sopenharmony_ci	{ .compatible = "ibm,coherent-platform-facility",},
49362306a36Sopenharmony_ci	{},
49462306a36Sopenharmony_ci};
49562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cxl_of_match);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistruct platform_driver cxl_of_driver = {
49862306a36Sopenharmony_ci	.driver = {
49962306a36Sopenharmony_ci		.name = "cxl_of",
50062306a36Sopenharmony_ci		.of_match_table = cxl_of_match,
50162306a36Sopenharmony_ci		.owner = THIS_MODULE
50262306a36Sopenharmony_ci	},
50362306a36Sopenharmony_ci	.probe = cxl_of_probe,
50462306a36Sopenharmony_ci	.remove = cxl_of_remove,
50562306a36Sopenharmony_ci	.shutdown = cxl_of_shutdown,
50662306a36Sopenharmony_ci};
507