brintos

brintos / linux-shallow public Read only

0
0
Text · 8.3 KiB · 03633cc Raw
345 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright 2015 IBM Corp.4 */5 6#include <linux/kernel.h>7#include <linux/module.h>8#include <linux/platform_device.h>9#include <linux/slab.h>10#include <linux/of.h>11#include <linux/of_address.h>12#include <linux/of_platform.h>13 14#include "cxl.h"15 16static int read_phys_addr(struct device_node *np, char *prop_name,17			struct cxl_afu *afu)18{19	int i, len, entry_size, naddr, nsize, type;20	u64 addr, size;21	const __be32 *prop;22 23	naddr = of_n_addr_cells(np);24	nsize = of_n_size_cells(np);25 26	prop = of_get_property(np, prop_name, &len);27	if (prop) {28		entry_size = naddr + nsize;29		for (i = 0; i < (len / 4); i += entry_size, prop += entry_size) {30			type = be32_to_cpu(prop[0]);31			addr = of_read_number(prop, naddr);32			size = of_read_number(&prop[naddr], nsize);33			switch (type) {34			case 0: /* unit address */35				afu->guest->handle = addr;36				break;37			case 1: /* p2 area */38				afu->guest->p2n_phys += addr;39				afu->guest->p2n_size = size;40				break;41			case 2: /* problem state area */42				afu->psn_phys += addr;43				afu->adapter->ps_size = size;44				break;45			default:46				pr_err("Invalid address type %d found in %s property of AFU\n",47					type, prop_name);48				return -EINVAL;49			}50		}51	}52	return 0;53}54 55static int read_vpd(struct cxl *adapter, struct cxl_afu *afu)56{57	char vpd[256];58	int rc;59	size_t len = sizeof(vpd);60 61	memset(vpd, 0, len);62 63	if (adapter)64		rc = cxl_guest_read_adapter_vpd(adapter, vpd, len);65	else66		rc = cxl_guest_read_afu_vpd(afu, vpd, len);67 68	if (rc > 0) {69		cxl_dump_debug_buffer(vpd, rc);70		rc = 0;71	}72	return rc;73}74 75int cxl_of_read_afu_handle(struct cxl_afu *afu, struct device_node *afu_np)76{77	return of_property_read_reg(afu_np, 0, &afu->guest->handle, NULL);78}79 80int cxl_of_read_afu_properties(struct cxl_afu *afu, struct device_node *np)81{82	int i, rc;83	u16 device_id, vendor_id;84	u32 val = 0, class_code;85 86	/* Properties are read in the same order as listed in PAPR */87 88	rc = read_phys_addr(np, "reg", afu);89	if (rc)90		return rc;91 92	rc = read_phys_addr(np, "assigned-addresses", afu);93	if (rc)94		return rc;95 96	if (afu->psn_phys == 0)97		afu->psa = false;98	else99		afu->psa = true;100 101	of_property_read_u32(np, "ibm,#processes", &afu->max_procs_virtualised);102 103	if (cxl_verbose)104		read_vpd(NULL, afu);105 106	of_property_read_u32(np, "ibm,max-ints-per-process", &afu->guest->max_ints);107	afu->irqs_max = afu->guest->max_ints;108 109	if (!of_property_read_u32(np, "ibm,min-ints-per-process", &afu->pp_irqs)) {110		/* One extra interrupt for the PSL interrupt is already111		 * included. Remove it now to keep only AFU interrupts and112		 * match the native case.113		 */114		afu->pp_irqs--;115	}116 117	of_property_read_u64(np, "ibm,error-buffer-size", &afu->eb_len);118	afu->eb_offset = 0;119 120	of_property_read_u64(np, "ibm,config-record-size", &afu->crs_len);121	afu->crs_offset = 0;122 123	of_property_read_u32(np, "ibm,#config-records", &afu->crs_num);124 125	if (cxl_verbose) {126		for (i = 0; i < afu->crs_num; i++) {127			rc = cxl_ops->afu_cr_read16(afu, i, PCI_DEVICE_ID,128						&device_id);129			if (!rc)130				pr_info("record %d - device-id: %#x\n",131					i, device_id);132			rc = cxl_ops->afu_cr_read16(afu, i, PCI_VENDOR_ID,133						&vendor_id);134			if (!rc)135				pr_info("record %d - vendor-id: %#x\n",136					i, vendor_id);137			rc = cxl_ops->afu_cr_read32(afu, i, PCI_CLASS_REVISION,138						&class_code);139			if (!rc) {140				class_code >>= 8;141				pr_info("record %d - class-code: %#x\n",142					i, class_code);143			}144		}145	}146	/*147	 * if "ibm,process-mmio" doesn't exist then per-process mmio is148	 * not supported149	 */150	val = 0;151	if (!of_property_read_u32(np, "ibm,process-mmio", &val) && val == 1)152		afu->pp_psa = true;153	else154		afu->pp_psa = false;155 156	if (!of_property_read_u32(np, "ibm,function-error-interrupt", &val))157		afu->serr_hwirq = val;158 159	pr_devel("AFU handle: %#llx\n", afu->guest->handle);160	pr_devel("p2n_phys: %#llx (size %#llx)\n",161		afu->guest->p2n_phys, afu->guest->p2n_size);162	pr_devel("psn_phys: %#llx (size %#llx)\n",163		afu->psn_phys, afu->adapter->ps_size);164	pr_devel("Max number of processes virtualised=%i\n",165		afu->max_procs_virtualised);166	pr_devel("Per-process irqs min=%i, max=%i\n", afu->pp_irqs,167		 afu->irqs_max);168	pr_devel("Slice error interrupt=%#lx\n", afu->serr_hwirq);169 170	return 0;171}172 173static int read_adapter_irq_config(struct cxl *adapter, struct device_node *np)174{175	const __be32 *ranges;176	int len, nranges, i;177	struct irq_avail *cur;178 179	ranges = of_get_property(np, "interrupt-ranges", &len);180	if (ranges == NULL || len < (2 * sizeof(int)))181		return -EINVAL;182 183	/*184	 * encoded array of two cells per entry, each cell encoded as185	 * with encode-int186	 */187	nranges = len / (2 * sizeof(int));188	if (nranges == 0 || (nranges * 2 * sizeof(int)) != len)189		return -EINVAL;190 191	adapter->guest->irq_avail = kcalloc(nranges, sizeof(struct irq_avail),192					    GFP_KERNEL);193	if (adapter->guest->irq_avail == NULL)194		return -ENOMEM;195 196	adapter->guest->irq_base_offset = be32_to_cpu(ranges[0]);197	for (i = 0; i < nranges; i++) {198		cur = &adapter->guest->irq_avail[i];199		cur->offset = be32_to_cpu(ranges[i * 2]);200		cur->range  = be32_to_cpu(ranges[i * 2 + 1]);201		cur->bitmap = bitmap_zalloc(cur->range, GFP_KERNEL);202		if (cur->bitmap == NULL)203			goto err;204		if (cur->offset < adapter->guest->irq_base_offset)205			adapter->guest->irq_base_offset = cur->offset;206		if (cxl_verbose)207			pr_info("available IRQ range: %#lx-%#lx (%lu)\n",208				cur->offset, cur->offset + cur->range - 1,209				cur->range);210	}211	adapter->guest->irq_nranges = nranges;212	spin_lock_init(&adapter->guest->irq_alloc_lock);213 214	return 0;215err:216	for (i--; i >= 0; i--) {217		cur = &adapter->guest->irq_avail[i];218		bitmap_free(cur->bitmap);219	}220	kfree(adapter->guest->irq_avail);221	adapter->guest->irq_avail = NULL;222	return -ENOMEM;223}224 225int cxl_of_read_adapter_handle(struct cxl *adapter, struct device_node *np)226{227	return of_property_read_reg(np, 0, &adapter->guest->handle, NULL);228}229 230int cxl_of_read_adapter_properties(struct cxl *adapter, struct device_node *np)231{232	int rc;233	const char *p;234	u32 val = 0;235 236	/* Properties are read in the same order as listed in PAPR */237 238	if ((rc = read_adapter_irq_config(adapter, np)))239		return rc;240 241	if (!of_property_read_u32(np, "ibm,caia-version", &val)) {242		adapter->caia_major = (val & 0xFF00) >> 8;243		adapter->caia_minor = val & 0xFF;244	}245 246	if (!of_property_read_u32(np, "ibm,psl-revision", &val))247		adapter->psl_rev = val;248 249	if (!of_property_read_string(np, "status", &p)) {250		adapter->guest->status = kasprintf(GFP_KERNEL, "%s", p);251		if (adapter->guest->status == NULL)252			return -ENOMEM;253	}254 255	if (!of_property_read_u32(np, "vendor-id", &val))256		adapter->guest->vendor = val;257 258	if (!of_property_read_u32(np, "device-id", &val))259		adapter->guest->device = val;260 261	if (!of_property_read_u32(np, "subsystem-vendor-id", &val))262		adapter->guest->subsystem_vendor = val;263 264	if (!of_property_read_u32(np, "subsystem-id", &val))265		adapter->guest->subsystem = val;266 267	if (cxl_verbose)268		read_vpd(adapter, NULL);269 270	return 0;271}272 273static void cxl_of_remove(struct platform_device *pdev)274{275	struct cxl *adapter;276	int afu;277 278	adapter = dev_get_drvdata(&pdev->dev);279	for (afu = 0; afu < adapter->slices; afu++)280		cxl_guest_remove_afu(adapter->afu[afu]);281 282	cxl_guest_remove_adapter(adapter);283}284 285static void cxl_of_shutdown(struct platform_device *pdev)286{287	cxl_of_remove(pdev);288}289 290int cxl_of_probe(struct platform_device *pdev)291{292	struct device_node *np = NULL;293	struct device_node *afu_np = NULL;294	struct cxl *adapter = NULL;295	int ret;296	int slice = 0, slice_ok = 0;297 298	pr_devel("in %s\n", __func__);299 300	np = pdev->dev.of_node;301	if (np == NULL)302		return -ENODEV;303 304	/* init adapter */305	adapter = cxl_guest_init_adapter(np, pdev);306	if (IS_ERR(adapter)) {307		dev_err(&pdev->dev, "guest_init_adapter failed: %li\n", PTR_ERR(adapter));308		return PTR_ERR(adapter);309	}310 311	/* init afu */312	for_each_child_of_node(np, afu_np) {313		if ((ret = cxl_guest_init_afu(adapter, slice, afu_np)))314			dev_err(&pdev->dev, "AFU %i failed to initialise: %i\n",315				slice, ret);316		else317			slice_ok++;318		slice++;319	}320 321	if (slice_ok == 0) {322		dev_info(&pdev->dev, "No active AFU");323		adapter->slices = 0;324	}325 326	return 0;327}328 329static const struct of_device_id cxl_of_match[] = {330	{ .compatible = "ibm,coherent-platform-facility",},331	{},332};333MODULE_DEVICE_TABLE(of, cxl_of_match);334 335struct platform_driver cxl_of_driver = {336	.driver = {337		.name = "cxl_of",338		.of_match_table = cxl_of_match,339		.owner = THIS_MODULE340	},341	.probe = cxl_of_probe,342	.remove_new = cxl_of_remove,343	.shutdown = cxl_of_shutdown,344};345