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