18c2ecf20Sopenharmony_ci/* Copyright 2008 - 2016 Freescale Semiconductor, Inc.
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
48c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
58c2ecf20Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
68c2ecf20Sopenharmony_ci *	 notice, this list of conditions and the following disclaimer.
78c2ecf20Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
88c2ecf20Sopenharmony_ci *	 notice, this list of conditions and the following disclaimer in the
98c2ecf20Sopenharmony_ci *	 documentation and/or other materials provided with the distribution.
108c2ecf20Sopenharmony_ci *     * Neither the name of Freescale Semiconductor nor the
118c2ecf20Sopenharmony_ci *	 names of its contributors may be used to endorse or promote products
128c2ecf20Sopenharmony_ci *	 derived from this software without specific prior written permission.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the
158c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software
168c2ecf20Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any
178c2ecf20Sopenharmony_ci * later version.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
208c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
218c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
228c2ecf20Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
238c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
248c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
258c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
268c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
278c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
288c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "bman_priv.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic struct bman_portal *affine_bportals[NR_CPUS];
348c2ecf20Sopenharmony_cistatic struct cpumask portal_cpus;
358c2ecf20Sopenharmony_cistatic int __bman_portals_probed;
368c2ecf20Sopenharmony_ci/* protect bman global registers and global data shared among portals */
378c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(bman_lock);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic struct bman_portal *init_pcfg(struct bm_portal_config *pcfg)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct bman_portal *p = bman_create_affine_portal(pcfg);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (!p) {
448c2ecf20Sopenharmony_ci		dev_crit(pcfg->dev, "%s: Portal failure on cpu %d\n",
458c2ecf20Sopenharmony_ci			 __func__, pcfg->cpu);
468c2ecf20Sopenharmony_ci		return NULL;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	bman_p_irqsource_add(p, BM_PIRQ_RCRI);
508c2ecf20Sopenharmony_ci	affine_bportals[pcfg->cpu] = p;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	dev_info(pcfg->dev, "Portal initialised, cpu %d\n", pcfg->cpu);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	return p;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic int bman_offline_cpu(unsigned int cpu)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct bman_portal *p = affine_bportals[cpu];
608c2ecf20Sopenharmony_ci	const struct bm_portal_config *pcfg;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (!p)
638c2ecf20Sopenharmony_ci		return 0;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	pcfg = bman_get_bm_portal_config(p);
668c2ecf20Sopenharmony_ci	if (!pcfg)
678c2ecf20Sopenharmony_ci		return 0;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* use any other online CPU */
708c2ecf20Sopenharmony_ci	cpu = cpumask_any_but(cpu_online_mask, cpu);
718c2ecf20Sopenharmony_ci	irq_set_affinity(pcfg->irq, cpumask_of(cpu));
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic int bman_online_cpu(unsigned int cpu)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct bman_portal *p = affine_bportals[cpu];
788c2ecf20Sopenharmony_ci	const struct bm_portal_config *pcfg;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (!p)
818c2ecf20Sopenharmony_ci		return 0;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	pcfg = bman_get_bm_portal_config(p);
848c2ecf20Sopenharmony_ci	if (!pcfg)
858c2ecf20Sopenharmony_ci		return 0;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	irq_set_affinity(pcfg->irq, cpumask_of(cpu));
888c2ecf20Sopenharmony_ci	return 0;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ciint bman_portals_probed(void)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	return __bman_portals_probed;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bman_portals_probed);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic int bman_portal_probe(struct platform_device *pdev)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
1008c2ecf20Sopenharmony_ci	struct device_node *node = dev->of_node;
1018c2ecf20Sopenharmony_ci	struct bm_portal_config *pcfg;
1028c2ecf20Sopenharmony_ci	struct resource *addr_phys[2];
1038c2ecf20Sopenharmony_ci	int irq, cpu, err, i;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	err = bman_is_probed();
1068c2ecf20Sopenharmony_ci	if (!err)
1078c2ecf20Sopenharmony_ci		return -EPROBE_DEFER;
1088c2ecf20Sopenharmony_ci	if (err < 0) {
1098c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failing probe due to bman probe error\n");
1108c2ecf20Sopenharmony_ci		return -ENODEV;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
1148c2ecf20Sopenharmony_ci	if (!pcfg) {
1158c2ecf20Sopenharmony_ci		__bman_portals_probed = -1;
1168c2ecf20Sopenharmony_ci		return -ENOMEM;
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	pcfg->dev = dev;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	addr_phys[0] = platform_get_resource(pdev, IORESOURCE_MEM,
1228c2ecf20Sopenharmony_ci					     DPAA_PORTAL_CE);
1238c2ecf20Sopenharmony_ci	if (!addr_phys[0]) {
1248c2ecf20Sopenharmony_ci		dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node);
1258c2ecf20Sopenharmony_ci		goto err_ioremap1;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM,
1298c2ecf20Sopenharmony_ci					     DPAA_PORTAL_CI);
1308c2ecf20Sopenharmony_ci	if (!addr_phys[1]) {
1318c2ecf20Sopenharmony_ci		dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node);
1328c2ecf20Sopenharmony_ci		goto err_ioremap1;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	pcfg->cpu = -1;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
1388c2ecf20Sopenharmony_ci	if (irq <= 0)
1398c2ecf20Sopenharmony_ci		goto err_ioremap1;
1408c2ecf20Sopenharmony_ci	pcfg->irq = irq;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	pcfg->addr_virt_ce = memremap(addr_phys[0]->start,
1438c2ecf20Sopenharmony_ci					resource_size(addr_phys[0]),
1448c2ecf20Sopenharmony_ci					QBMAN_MEMREMAP_ATTR);
1458c2ecf20Sopenharmony_ci	if (!pcfg->addr_virt_ce) {
1468c2ecf20Sopenharmony_ci		dev_err(dev, "memremap::CE failed\n");
1478c2ecf20Sopenharmony_ci		goto err_ioremap1;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	pcfg->addr_virt_ci = ioremap(addr_phys[1]->start,
1518c2ecf20Sopenharmony_ci					resource_size(addr_phys[1]));
1528c2ecf20Sopenharmony_ci	if (!pcfg->addr_virt_ci) {
1538c2ecf20Sopenharmony_ci		dev_err(dev, "ioremap::CI failed\n");
1548c2ecf20Sopenharmony_ci		goto err_ioremap2;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	spin_lock(&bman_lock);
1588c2ecf20Sopenharmony_ci	cpu = cpumask_next_zero(-1, &portal_cpus);
1598c2ecf20Sopenharmony_ci	if (cpu >= nr_cpu_ids) {
1608c2ecf20Sopenharmony_ci		__bman_portals_probed = 1;
1618c2ecf20Sopenharmony_ci		/* unassigned portal, skip init */
1628c2ecf20Sopenharmony_ci		spin_unlock(&bman_lock);
1638c2ecf20Sopenharmony_ci		return 0;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	cpumask_set_cpu(cpu, &portal_cpus);
1678c2ecf20Sopenharmony_ci	spin_unlock(&bman_lock);
1688c2ecf20Sopenharmony_ci	pcfg->cpu = cpu;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (!init_pcfg(pcfg)) {
1718c2ecf20Sopenharmony_ci		dev_err(dev, "portal init failed\n");
1728c2ecf20Sopenharmony_ci		goto err_portal_init;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/* clear irq affinity if assigned cpu is offline */
1768c2ecf20Sopenharmony_ci	if (!cpu_online(cpu))
1778c2ecf20Sopenharmony_ci		bman_offline_cpu(cpu);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (__bman_portals_probed == 1 && bman_requires_cleanup()) {
1808c2ecf20Sopenharmony_ci		/*
1818c2ecf20Sopenharmony_ci		 * BMan wasn't reset prior to boot (Kexec for example)
1828c2ecf20Sopenharmony_ci		 * Empty all the buffer pools so they are in reset state
1838c2ecf20Sopenharmony_ci		 */
1848c2ecf20Sopenharmony_ci		for (i = 0; i < BM_POOL_MAX; i++) {
1858c2ecf20Sopenharmony_ci			err =  bm_shutdown_pool(i);
1868c2ecf20Sopenharmony_ci			if (err) {
1878c2ecf20Sopenharmony_ci				dev_err(dev, "Failed to shutdown bpool %d\n",
1888c2ecf20Sopenharmony_ci					i);
1898c2ecf20Sopenharmony_ci				goto err_portal_init;
1908c2ecf20Sopenharmony_ci			}
1918c2ecf20Sopenharmony_ci		}
1928c2ecf20Sopenharmony_ci		bman_done_cleanup();
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return 0;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cierr_portal_init:
1988c2ecf20Sopenharmony_ci	iounmap(pcfg->addr_virt_ci);
1998c2ecf20Sopenharmony_cierr_ioremap2:
2008c2ecf20Sopenharmony_ci	memunmap(pcfg->addr_virt_ce);
2018c2ecf20Sopenharmony_cierr_ioremap1:
2028c2ecf20Sopenharmony_ci	 __bman_portals_probed = -1;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return -ENXIO;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic const struct of_device_id bman_portal_ids[] = {
2088c2ecf20Sopenharmony_ci	{
2098c2ecf20Sopenharmony_ci		.compatible = "fsl,bman-portal",
2108c2ecf20Sopenharmony_ci	},
2118c2ecf20Sopenharmony_ci	{}
2128c2ecf20Sopenharmony_ci};
2138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bman_portal_ids);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic struct platform_driver bman_portal_driver = {
2168c2ecf20Sopenharmony_ci	.driver = {
2178c2ecf20Sopenharmony_ci		.name = KBUILD_MODNAME,
2188c2ecf20Sopenharmony_ci		.of_match_table = bman_portal_ids,
2198c2ecf20Sopenharmony_ci	},
2208c2ecf20Sopenharmony_ci	.probe = bman_portal_probe,
2218c2ecf20Sopenharmony_ci};
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int __init bman_portal_driver_register(struct platform_driver *drv)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	int ret;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	ret = platform_driver_register(drv);
2288c2ecf20Sopenharmony_ci	if (ret < 0)
2298c2ecf20Sopenharmony_ci		return ret;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
2328c2ecf20Sopenharmony_ci					"soc/qbman_portal:online",
2338c2ecf20Sopenharmony_ci					bman_online_cpu, bman_offline_cpu);
2348c2ecf20Sopenharmony_ci	if (ret < 0) {
2358c2ecf20Sopenharmony_ci		pr_err("bman: failed to register hotplug callbacks.\n");
2368c2ecf20Sopenharmony_ci		platform_driver_unregister(drv);
2378c2ecf20Sopenharmony_ci		return ret;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci	return 0;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cimodule_driver(bman_portal_driver,
2438c2ecf20Sopenharmony_ci	      bman_portal_driver_register, platform_driver_unregister);
244