162306a36Sopenharmony_ci/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 462306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 562306a36Sopenharmony_ci * * Redistributions of source code must retain the above copyright 662306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 762306a36Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 862306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 962306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1062306a36Sopenharmony_ci * * Neither the name of Freescale Semiconductor nor the 1162306a36Sopenharmony_ci * names of its contributors may be used to endorse or promote products 1262306a36Sopenharmony_ci * derived from this software without specific prior written permission. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the 1562306a36Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software 1662306a36Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any 1762306a36Sopenharmony_ci * later version. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY 2062306a36Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2162306a36Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2262306a36Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY 2362306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2462306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2562306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2662306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2762306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2862306a36Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "bman_priv.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic struct bman_portal *affine_bportals[NR_CPUS]; 3462306a36Sopenharmony_cistatic struct cpumask portal_cpus; 3562306a36Sopenharmony_cistatic int __bman_portals_probed; 3662306a36Sopenharmony_ci/* protect bman global registers and global data shared among portals */ 3762306a36Sopenharmony_cistatic DEFINE_SPINLOCK(bman_lock); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic struct bman_portal *init_pcfg(struct bm_portal_config *pcfg) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct bman_portal *p = bman_create_affine_portal(pcfg); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!p) { 4462306a36Sopenharmony_ci dev_crit(pcfg->dev, "%s: Portal failure on cpu %d\n", 4562306a36Sopenharmony_ci __func__, pcfg->cpu); 4662306a36Sopenharmony_ci return NULL; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci bman_p_irqsource_add(p, BM_PIRQ_RCRI); 5062306a36Sopenharmony_ci affine_bportals[pcfg->cpu] = p; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci dev_info(pcfg->dev, "Portal initialised, cpu %d\n", pcfg->cpu); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return p; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int bman_offline_cpu(unsigned int cpu) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct bman_portal *p = affine_bportals[cpu]; 6062306a36Sopenharmony_ci const struct bm_portal_config *pcfg; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (!p) 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci pcfg = bman_get_bm_portal_config(p); 6662306a36Sopenharmony_ci if (!pcfg) 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* use any other online CPU */ 7062306a36Sopenharmony_ci cpu = cpumask_any_but(cpu_online_mask, cpu); 7162306a36Sopenharmony_ci irq_set_affinity(pcfg->irq, cpumask_of(cpu)); 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int bman_online_cpu(unsigned int cpu) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct bman_portal *p = affine_bportals[cpu]; 7862306a36Sopenharmony_ci const struct bm_portal_config *pcfg; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (!p) 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci pcfg = bman_get_bm_portal_config(p); 8462306a36Sopenharmony_ci if (!pcfg) 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci irq_set_affinity(pcfg->irq, cpumask_of(cpu)); 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciint bman_portals_probed(void) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci return __bman_portals_probed; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bman_portals_probed); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int bman_portal_probe(struct platform_device *pdev) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 10062306a36Sopenharmony_ci struct device_node *node = dev->of_node; 10162306a36Sopenharmony_ci struct bm_portal_config *pcfg; 10262306a36Sopenharmony_ci struct resource *addr_phys[2]; 10362306a36Sopenharmony_ci int irq, cpu, err, i; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci err = bman_is_probed(); 10662306a36Sopenharmony_ci if (!err) 10762306a36Sopenharmony_ci return -EPROBE_DEFER; 10862306a36Sopenharmony_ci if (err < 0) { 10962306a36Sopenharmony_ci dev_err(&pdev->dev, "failing probe due to bman probe error\n"); 11062306a36Sopenharmony_ci return -ENODEV; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL); 11462306a36Sopenharmony_ci if (!pcfg) { 11562306a36Sopenharmony_ci __bman_portals_probed = -1; 11662306a36Sopenharmony_ci return -ENOMEM; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci pcfg->dev = dev; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci addr_phys[0] = platform_get_resource(pdev, IORESOURCE_MEM, 12262306a36Sopenharmony_ci DPAA_PORTAL_CE); 12362306a36Sopenharmony_ci if (!addr_phys[0]) { 12462306a36Sopenharmony_ci dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node); 12562306a36Sopenharmony_ci goto err_ioremap1; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM, 12962306a36Sopenharmony_ci DPAA_PORTAL_CI); 13062306a36Sopenharmony_ci if (!addr_phys[1]) { 13162306a36Sopenharmony_ci dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node); 13262306a36Sopenharmony_ci goto err_ioremap1; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci pcfg->cpu = -1; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 13862306a36Sopenharmony_ci if (irq <= 0) 13962306a36Sopenharmony_ci goto err_ioremap1; 14062306a36Sopenharmony_ci pcfg->irq = irq; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci pcfg->addr_virt_ce = memremap(addr_phys[0]->start, 14362306a36Sopenharmony_ci resource_size(addr_phys[0]), 14462306a36Sopenharmony_ci QBMAN_MEMREMAP_ATTR); 14562306a36Sopenharmony_ci if (!pcfg->addr_virt_ce) { 14662306a36Sopenharmony_ci dev_err(dev, "memremap::CE failed\n"); 14762306a36Sopenharmony_ci goto err_ioremap1; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci pcfg->addr_virt_ci = ioremap(addr_phys[1]->start, 15162306a36Sopenharmony_ci resource_size(addr_phys[1])); 15262306a36Sopenharmony_ci if (!pcfg->addr_virt_ci) { 15362306a36Sopenharmony_ci dev_err(dev, "ioremap::CI failed\n"); 15462306a36Sopenharmony_ci goto err_ioremap2; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci spin_lock(&bman_lock); 15862306a36Sopenharmony_ci cpu = cpumask_first_zero(&portal_cpus); 15962306a36Sopenharmony_ci if (cpu >= nr_cpu_ids) { 16062306a36Sopenharmony_ci __bman_portals_probed = 1; 16162306a36Sopenharmony_ci /* unassigned portal, skip init */ 16262306a36Sopenharmony_ci spin_unlock(&bman_lock); 16362306a36Sopenharmony_ci goto check_cleanup; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci cpumask_set_cpu(cpu, &portal_cpus); 16762306a36Sopenharmony_ci spin_unlock(&bman_lock); 16862306a36Sopenharmony_ci pcfg->cpu = cpu; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (!init_pcfg(pcfg)) { 17162306a36Sopenharmony_ci dev_err(dev, "portal init failed\n"); 17262306a36Sopenharmony_ci goto err_portal_init; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* clear irq affinity if assigned cpu is offline */ 17662306a36Sopenharmony_ci if (!cpu_online(cpu)) 17762306a36Sopenharmony_ci bman_offline_cpu(cpu); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cicheck_cleanup: 18062306a36Sopenharmony_ci if (__bman_portals_probed == 1 && bman_requires_cleanup()) { 18162306a36Sopenharmony_ci /* 18262306a36Sopenharmony_ci * BMan wasn't reset prior to boot (Kexec for example) 18362306a36Sopenharmony_ci * Empty all the buffer pools so they are in reset state 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ci for (i = 0; i < BM_POOL_MAX; i++) { 18662306a36Sopenharmony_ci err = bm_shutdown_pool(i); 18762306a36Sopenharmony_ci if (err) { 18862306a36Sopenharmony_ci dev_err(dev, "Failed to shutdown bpool %d\n", 18962306a36Sopenharmony_ci i); 19062306a36Sopenharmony_ci goto err_portal_init; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci bman_done_cleanup(); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cierr_portal_init: 19962306a36Sopenharmony_ci iounmap(pcfg->addr_virt_ci); 20062306a36Sopenharmony_cierr_ioremap2: 20162306a36Sopenharmony_ci memunmap(pcfg->addr_virt_ce); 20262306a36Sopenharmony_cierr_ioremap1: 20362306a36Sopenharmony_ci __bman_portals_probed = -1; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return -ENXIO; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic const struct of_device_id bman_portal_ids[] = { 20962306a36Sopenharmony_ci { 21062306a36Sopenharmony_ci .compatible = "fsl,bman-portal", 21162306a36Sopenharmony_ci }, 21262306a36Sopenharmony_ci {} 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, bman_portal_ids); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic struct platform_driver bman_portal_driver = { 21762306a36Sopenharmony_ci .driver = { 21862306a36Sopenharmony_ci .name = KBUILD_MODNAME, 21962306a36Sopenharmony_ci .of_match_table = bman_portal_ids, 22062306a36Sopenharmony_ci }, 22162306a36Sopenharmony_ci .probe = bman_portal_probe, 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int __init bman_portal_driver_register(struct platform_driver *drv) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci int ret; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ret = platform_driver_register(drv); 22962306a36Sopenharmony_ci if (ret < 0) 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, 23362306a36Sopenharmony_ci "soc/qbman_portal:online", 23462306a36Sopenharmony_ci bman_online_cpu, bman_offline_cpu); 23562306a36Sopenharmony_ci if (ret < 0) { 23662306a36Sopenharmony_ci pr_err("bman: failed to register hotplug callbacks.\n"); 23762306a36Sopenharmony_ci platform_driver_unregister(drv); 23862306a36Sopenharmony_ci return ret; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci return 0; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cimodule_driver(bman_portal_driver, 24462306a36Sopenharmony_ci bman_portal_driver_register, platform_driver_unregister); 245