18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2014-2016 Freescale Semiconductor Inc.
48c2ecf20Sopenharmony_ci * Copyright NXP 2016
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/types.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/msi.h>
148c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci#include <linux/sys_soc.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/fsl/mc.h>
208c2ecf20Sopenharmony_ci#include <soc/fsl/dpaa2-io.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "qbman-portal.h"
238c2ecf20Sopenharmony_ci#include "dpio.h"
248c2ecf20Sopenharmony_ci#include "dpio-cmd.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
278c2ecf20Sopenharmony_ciMODULE_AUTHOR("Freescale Semiconductor, Inc");
288c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DPIO Driver");
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct dpio_priv {
318c2ecf20Sopenharmony_ci	struct dpaa2_io *io;
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic cpumask_var_t cpus_unused_mask;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic const struct soc_device_attribute ls1088a_soc[] = {
378c2ecf20Sopenharmony_ci	{.family = "QorIQ LS1088A"},
388c2ecf20Sopenharmony_ci	{ /* sentinel */ }
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic const struct soc_device_attribute ls2080a_soc[] = {
428c2ecf20Sopenharmony_ci	{.family = "QorIQ LS2080A"},
438c2ecf20Sopenharmony_ci	{ /* sentinel */ }
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic const struct soc_device_attribute ls2088a_soc[] = {
478c2ecf20Sopenharmony_ci	{.family = "QorIQ LS2088A"},
488c2ecf20Sopenharmony_ci	{ /* sentinel */ }
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const struct soc_device_attribute lx2160a_soc[] = {
528c2ecf20Sopenharmony_ci	{.family = "QorIQ LX2160A"},
538c2ecf20Sopenharmony_ci	{ /* sentinel */ }
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int dpaa2_dpio_get_cluster_sdest(struct fsl_mc_device *dpio_dev, int cpu)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	int cluster_base, cluster_size;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (soc_device_match(ls1088a_soc)) {
618c2ecf20Sopenharmony_ci		cluster_base = 2;
628c2ecf20Sopenharmony_ci		cluster_size = 4;
638c2ecf20Sopenharmony_ci	} else if (soc_device_match(ls2080a_soc) ||
648c2ecf20Sopenharmony_ci		   soc_device_match(ls2088a_soc) ||
658c2ecf20Sopenharmony_ci		   soc_device_match(lx2160a_soc)) {
668c2ecf20Sopenharmony_ci		cluster_base = 0;
678c2ecf20Sopenharmony_ci		cluster_size = 2;
688c2ecf20Sopenharmony_ci	} else {
698c2ecf20Sopenharmony_ci		dev_err(&dpio_dev->dev, "unknown SoC version\n");
708c2ecf20Sopenharmony_ci		return -1;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return cluster_base + cpu / cluster_size;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic irqreturn_t dpio_irq_handler(int irq_num, void *arg)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct device *dev = (struct device *)arg;
798c2ecf20Sopenharmony_ci	struct dpio_priv *priv = dev_get_drvdata(dev);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	return dpaa2_io_irq(priv->io);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic void unregister_dpio_irq_handlers(struct fsl_mc_device *dpio_dev)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct fsl_mc_device_irq *irq;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	irq = dpio_dev->irqs[0];
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	/* clear the affinity hint */
918c2ecf20Sopenharmony_ci	irq_set_affinity_hint(irq->msi_desc->irq, NULL);
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	int error;
978c2ecf20Sopenharmony_ci	struct fsl_mc_device_irq *irq;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	irq = dpio_dev->irqs[0];
1008c2ecf20Sopenharmony_ci	error = devm_request_irq(&dpio_dev->dev,
1018c2ecf20Sopenharmony_ci				 irq->msi_desc->irq,
1028c2ecf20Sopenharmony_ci				 dpio_irq_handler,
1038c2ecf20Sopenharmony_ci				 0,
1048c2ecf20Sopenharmony_ci				 dev_name(&dpio_dev->dev),
1058c2ecf20Sopenharmony_ci				 &dpio_dev->dev);
1068c2ecf20Sopenharmony_ci	if (error < 0) {
1078c2ecf20Sopenharmony_ci		dev_err(&dpio_dev->dev,
1088c2ecf20Sopenharmony_ci			"devm_request_irq() failed: %d\n",
1098c2ecf20Sopenharmony_ci			error);
1108c2ecf20Sopenharmony_ci		return error;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* set the affinity hint */
1148c2ecf20Sopenharmony_ci	if (irq_set_affinity_hint(irq->msi_desc->irq, cpumask_of(cpu)))
1158c2ecf20Sopenharmony_ci		dev_err(&dpio_dev->dev,
1168c2ecf20Sopenharmony_ci			"irq_set_affinity failed irq %d cpu %d\n",
1178c2ecf20Sopenharmony_ci			irq->msi_desc->irq, cpu);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct dpio_attr dpio_attrs;
1258c2ecf20Sopenharmony_ci	struct dpaa2_io_desc desc;
1268c2ecf20Sopenharmony_ci	struct dpio_priv *priv;
1278c2ecf20Sopenharmony_ci	int err = -ENOMEM;
1288c2ecf20Sopenharmony_ci	struct device *dev = &dpio_dev->dev;
1298c2ecf20Sopenharmony_ci	int possible_next_cpu;
1308c2ecf20Sopenharmony_ci	int sdest;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1338c2ecf20Sopenharmony_ci	if (!priv)
1348c2ecf20Sopenharmony_ci		goto err_priv_alloc;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, priv);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	err = fsl_mc_portal_allocate(dpio_dev, 0, &dpio_dev->mc_io);
1398c2ecf20Sopenharmony_ci	if (err) {
1408c2ecf20Sopenharmony_ci		dev_dbg(dev, "MC portal allocation failed\n");
1418c2ecf20Sopenharmony_ci		err = -EPROBE_DEFER;
1428c2ecf20Sopenharmony_ci		goto err_priv_alloc;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	err = dpio_open(dpio_dev->mc_io, 0, dpio_dev->obj_desc.id,
1468c2ecf20Sopenharmony_ci			&dpio_dev->mc_handle);
1478c2ecf20Sopenharmony_ci	if (err) {
1488c2ecf20Sopenharmony_ci		dev_err(dev, "dpio_open() failed\n");
1498c2ecf20Sopenharmony_ci		goto err_open;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	err = dpio_reset(dpio_dev->mc_io, 0, dpio_dev->mc_handle);
1538c2ecf20Sopenharmony_ci	if (err) {
1548c2ecf20Sopenharmony_ci		dev_err(dev, "dpio_reset() failed\n");
1558c2ecf20Sopenharmony_ci		goto err_reset;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	err = dpio_get_attributes(dpio_dev->mc_io, 0, dpio_dev->mc_handle,
1598c2ecf20Sopenharmony_ci				  &dpio_attrs);
1608c2ecf20Sopenharmony_ci	if (err) {
1618c2ecf20Sopenharmony_ci		dev_err(dev, "dpio_get_attributes() failed %d\n", err);
1628c2ecf20Sopenharmony_ci		goto err_get_attr;
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci	desc.qman_version = dpio_attrs.qbman_version;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	err = dpio_enable(dpio_dev->mc_io, 0, dpio_dev->mc_handle);
1678c2ecf20Sopenharmony_ci	if (err) {
1688c2ecf20Sopenharmony_ci		dev_err(dev, "dpio_enable() failed %d\n", err);
1698c2ecf20Sopenharmony_ci		goto err_get_attr;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/* initialize DPIO descriptor */
1738c2ecf20Sopenharmony_ci	desc.receives_notifications = dpio_attrs.num_priorities ? 1 : 0;
1748c2ecf20Sopenharmony_ci	desc.has_8prio = dpio_attrs.num_priorities == 8 ? 1 : 0;
1758c2ecf20Sopenharmony_ci	desc.dpio_id = dpio_dev->obj_desc.id;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* get the cpu to use for the affinity hint */
1788c2ecf20Sopenharmony_ci	possible_next_cpu = cpumask_first(cpus_unused_mask);
1798c2ecf20Sopenharmony_ci	if (possible_next_cpu >= nr_cpu_ids) {
1808c2ecf20Sopenharmony_ci		dev_err(dev, "probe failed. Number of DPIOs exceeds NR_CPUS.\n");
1818c2ecf20Sopenharmony_ci		err = -ERANGE;
1828c2ecf20Sopenharmony_ci		goto err_allocate_irqs;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci	desc.cpu = possible_next_cpu;
1858c2ecf20Sopenharmony_ci	cpumask_clear_cpu(possible_next_cpu, cpus_unused_mask);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	sdest = dpaa2_dpio_get_cluster_sdest(dpio_dev, desc.cpu);
1888c2ecf20Sopenharmony_ci	if (sdest >= 0) {
1898c2ecf20Sopenharmony_ci		err = dpio_set_stashing_destination(dpio_dev->mc_io, 0,
1908c2ecf20Sopenharmony_ci						    dpio_dev->mc_handle,
1918c2ecf20Sopenharmony_ci						    sdest);
1928c2ecf20Sopenharmony_ci		if (err)
1938c2ecf20Sopenharmony_ci			dev_err(dev, "dpio_set_stashing_destination failed for cpu%d\n",
1948c2ecf20Sopenharmony_ci				desc.cpu);
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (dpio_dev->obj_desc.region_count < 3) {
1988c2ecf20Sopenharmony_ci		/* No support for DDR backed portals, use classic mapping */
1998c2ecf20Sopenharmony_ci		/*
2008c2ecf20Sopenharmony_ci		 * Set the CENA regs to be the cache inhibited area of the
2018c2ecf20Sopenharmony_ci		 * portal to avoid coherency issues if a user migrates to
2028c2ecf20Sopenharmony_ci		 * another core.
2038c2ecf20Sopenharmony_ci		 */
2048c2ecf20Sopenharmony_ci		desc.regs_cena = devm_memremap(dev, dpio_dev->regions[1].start,
2058c2ecf20Sopenharmony_ci					resource_size(&dpio_dev->regions[1]),
2068c2ecf20Sopenharmony_ci					MEMREMAP_WC);
2078c2ecf20Sopenharmony_ci	} else {
2088c2ecf20Sopenharmony_ci		desc.regs_cena = devm_memremap(dev, dpio_dev->regions[2].start,
2098c2ecf20Sopenharmony_ci					resource_size(&dpio_dev->regions[2]),
2108c2ecf20Sopenharmony_ci					MEMREMAP_WB);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (IS_ERR(desc.regs_cena)) {
2148c2ecf20Sopenharmony_ci		dev_err(dev, "devm_memremap failed\n");
2158c2ecf20Sopenharmony_ci		err = PTR_ERR(desc.regs_cena);
2168c2ecf20Sopenharmony_ci		goto err_allocate_irqs;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	desc.regs_cinh = devm_ioremap(dev, dpio_dev->regions[1].start,
2208c2ecf20Sopenharmony_ci				      resource_size(&dpio_dev->regions[1]));
2218c2ecf20Sopenharmony_ci	if (!desc.regs_cinh) {
2228c2ecf20Sopenharmony_ci		err = -ENOMEM;
2238c2ecf20Sopenharmony_ci		dev_err(dev, "devm_ioremap failed\n");
2248c2ecf20Sopenharmony_ci		goto err_allocate_irqs;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	err = fsl_mc_allocate_irqs(dpio_dev);
2288c2ecf20Sopenharmony_ci	if (err) {
2298c2ecf20Sopenharmony_ci		dev_err(dev, "fsl_mc_allocate_irqs failed. err=%d\n", err);
2308c2ecf20Sopenharmony_ci		goto err_allocate_irqs;
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	priv->io = dpaa2_io_create(&desc, dev);
2348c2ecf20Sopenharmony_ci	if (!priv->io) {
2358c2ecf20Sopenharmony_ci		dev_err(dev, "dpaa2_io_create failed\n");
2368c2ecf20Sopenharmony_ci		err = -ENOMEM;
2378c2ecf20Sopenharmony_ci		goto err_dpaa2_io_create;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	err = register_dpio_irq_handlers(dpio_dev, desc.cpu);
2418c2ecf20Sopenharmony_ci	if (err)
2428c2ecf20Sopenharmony_ci		goto err_register_dpio_irq;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	dev_info(dev, "probed\n");
2458c2ecf20Sopenharmony_ci	dev_dbg(dev, "   receives_notifications = %d\n",
2468c2ecf20Sopenharmony_ci		desc.receives_notifications);
2478c2ecf20Sopenharmony_ci	dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return 0;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cierr_dpaa2_io_create:
2528c2ecf20Sopenharmony_ci	unregister_dpio_irq_handlers(dpio_dev);
2538c2ecf20Sopenharmony_cierr_register_dpio_irq:
2548c2ecf20Sopenharmony_ci	fsl_mc_free_irqs(dpio_dev);
2558c2ecf20Sopenharmony_cierr_allocate_irqs:
2568c2ecf20Sopenharmony_ci	dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle);
2578c2ecf20Sopenharmony_cierr_get_attr:
2588c2ecf20Sopenharmony_cierr_reset:
2598c2ecf20Sopenharmony_ci	dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle);
2608c2ecf20Sopenharmony_cierr_open:
2618c2ecf20Sopenharmony_ci	fsl_mc_portal_free(dpio_dev->mc_io);
2628c2ecf20Sopenharmony_cierr_priv_alloc:
2638c2ecf20Sopenharmony_ci	return err;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci/* Tear down interrupts for a given DPIO object */
2678c2ecf20Sopenharmony_cistatic void dpio_teardown_irqs(struct fsl_mc_device *dpio_dev)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	unregister_dpio_irq_handlers(dpio_dev);
2708c2ecf20Sopenharmony_ci	fsl_mc_free_irqs(dpio_dev);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct device *dev;
2768c2ecf20Sopenharmony_ci	struct dpio_priv *priv;
2778c2ecf20Sopenharmony_ci	int err = 0, cpu;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	dev = &dpio_dev->dev;
2808c2ecf20Sopenharmony_ci	priv = dev_get_drvdata(dev);
2818c2ecf20Sopenharmony_ci	cpu = dpaa2_io_get_cpu(priv->io);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	dpaa2_io_down(priv->io);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	dpio_teardown_irqs(dpio_dev);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	cpumask_set_cpu(cpu, cpus_unused_mask);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	err = dpio_open(dpio_dev->mc_io, 0, dpio_dev->obj_desc.id,
2908c2ecf20Sopenharmony_ci			&dpio_dev->mc_handle);
2918c2ecf20Sopenharmony_ci	if (err) {
2928c2ecf20Sopenharmony_ci		dev_err(dev, "dpio_open() failed\n");
2938c2ecf20Sopenharmony_ci		goto err_open;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	fsl_mc_portal_free(dpio_dev->mc_io);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	return 0;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cierr_open:
3058c2ecf20Sopenharmony_ci	fsl_mc_portal_free(dpio_dev->mc_io);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return err;
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic const struct fsl_mc_device_id dpaa2_dpio_match_id_table[] = {
3118c2ecf20Sopenharmony_ci	{
3128c2ecf20Sopenharmony_ci		.vendor = FSL_MC_VENDOR_FREESCALE,
3138c2ecf20Sopenharmony_ci		.obj_type = "dpio",
3148c2ecf20Sopenharmony_ci	},
3158c2ecf20Sopenharmony_ci	{ .vendor = 0x0 }
3168c2ecf20Sopenharmony_ci};
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic struct fsl_mc_driver dpaa2_dpio_driver = {
3198c2ecf20Sopenharmony_ci	.driver = {
3208c2ecf20Sopenharmony_ci		.name		= KBUILD_MODNAME,
3218c2ecf20Sopenharmony_ci		.owner		= THIS_MODULE,
3228c2ecf20Sopenharmony_ci	},
3238c2ecf20Sopenharmony_ci	.probe		= dpaa2_dpio_probe,
3248c2ecf20Sopenharmony_ci	.remove		= dpaa2_dpio_remove,
3258c2ecf20Sopenharmony_ci	.match_id_table = dpaa2_dpio_match_id_table
3268c2ecf20Sopenharmony_ci};
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic int dpio_driver_init(void)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	if (!zalloc_cpumask_var(&cpus_unused_mask, GFP_KERNEL))
3318c2ecf20Sopenharmony_ci		return -ENOMEM;
3328c2ecf20Sopenharmony_ci	cpumask_copy(cpus_unused_mask, cpu_online_mask);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return fsl_mc_driver_register(&dpaa2_dpio_driver);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic void dpio_driver_exit(void)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	free_cpumask_var(cpus_unused_mask);
3408c2ecf20Sopenharmony_ci	fsl_mc_driver_unregister(&dpaa2_dpio_driver);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_cimodule_init(dpio_driver_init);
3438c2ecf20Sopenharmony_cimodule_exit(dpio_driver_exit);
344