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 "qman_priv.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct qman_portal *qman_dma_portal; 348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qman_dma_portal); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* Enable portal interupts (as opposed to polling mode) */ 378c2ecf20Sopenharmony_ci#define CONFIG_FSL_DPA_PIRQ_SLOW 1 388c2ecf20Sopenharmony_ci#define CONFIG_FSL_DPA_PIRQ_FAST 1 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic struct cpumask portal_cpus; 418c2ecf20Sopenharmony_cistatic int __qman_portals_probed; 428c2ecf20Sopenharmony_ci/* protect qman global registers and global data shared among portals */ 438c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(qman_lock); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void portal_set_cpu(struct qm_portal_config *pcfg, int cpu) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_PAMU 488c2ecf20Sopenharmony_ci struct device *dev = pcfg->dev; 498c2ecf20Sopenharmony_ci int window_count = 1; 508c2ecf20Sopenharmony_ci struct iommu_domain_geometry geom_attr; 518c2ecf20Sopenharmony_ci struct pamu_stash_attribute stash_attr; 528c2ecf20Sopenharmony_ci int ret; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type); 558c2ecf20Sopenharmony_ci if (!pcfg->iommu_domain) { 568c2ecf20Sopenharmony_ci dev_err(dev, "%s(): iommu_domain_alloc() failed", __func__); 578c2ecf20Sopenharmony_ci goto no_iommu; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci geom_attr.aperture_start = 0; 608c2ecf20Sopenharmony_ci geom_attr.aperture_end = 618c2ecf20Sopenharmony_ci ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1; 628c2ecf20Sopenharmony_ci geom_attr.force_aperture = true; 638c2ecf20Sopenharmony_ci ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY, 648c2ecf20Sopenharmony_ci &geom_attr); 658c2ecf20Sopenharmony_ci if (ret < 0) { 668c2ecf20Sopenharmony_ci dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__, 678c2ecf20Sopenharmony_ci ret); 688c2ecf20Sopenharmony_ci goto out_domain_free; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS, 718c2ecf20Sopenharmony_ci &window_count); 728c2ecf20Sopenharmony_ci if (ret < 0) { 738c2ecf20Sopenharmony_ci dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__, 748c2ecf20Sopenharmony_ci ret); 758c2ecf20Sopenharmony_ci goto out_domain_free; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci stash_attr.cpu = cpu; 788c2ecf20Sopenharmony_ci stash_attr.cache = PAMU_ATTR_CACHE_L1; 798c2ecf20Sopenharmony_ci ret = iommu_domain_set_attr(pcfg->iommu_domain, 808c2ecf20Sopenharmony_ci DOMAIN_ATTR_FSL_PAMU_STASH, 818c2ecf20Sopenharmony_ci &stash_attr); 828c2ecf20Sopenharmony_ci if (ret < 0) { 838c2ecf20Sopenharmony_ci dev_err(dev, "%s(): iommu_domain_set_attr() = %d", 848c2ecf20Sopenharmony_ci __func__, ret); 858c2ecf20Sopenharmony_ci goto out_domain_free; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36, 888c2ecf20Sopenharmony_ci IOMMU_READ | IOMMU_WRITE); 898c2ecf20Sopenharmony_ci if (ret < 0) { 908c2ecf20Sopenharmony_ci dev_err(dev, "%s(): iommu_domain_window_enable() = %d", 918c2ecf20Sopenharmony_ci __func__, ret); 928c2ecf20Sopenharmony_ci goto out_domain_free; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci ret = iommu_attach_device(pcfg->iommu_domain, dev); 958c2ecf20Sopenharmony_ci if (ret < 0) { 968c2ecf20Sopenharmony_ci dev_err(dev, "%s(): iommu_device_attach() = %d", __func__, 978c2ecf20Sopenharmony_ci ret); 988c2ecf20Sopenharmony_ci goto out_domain_free; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci ret = iommu_domain_set_attr(pcfg->iommu_domain, 1018c2ecf20Sopenharmony_ci DOMAIN_ATTR_FSL_PAMU_ENABLE, 1028c2ecf20Sopenharmony_ci &window_count); 1038c2ecf20Sopenharmony_ci if (ret < 0) { 1048c2ecf20Sopenharmony_ci dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__, 1058c2ecf20Sopenharmony_ci ret); 1068c2ecf20Sopenharmony_ci goto out_detach_device; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cino_iommu: 1108c2ecf20Sopenharmony_ci#endif 1118c2ecf20Sopenharmony_ci qman_set_sdest(pcfg->channel, cpu); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_PAMU 1168c2ecf20Sopenharmony_ciout_detach_device: 1178c2ecf20Sopenharmony_ci iommu_detach_device(pcfg->iommu_domain, NULL); 1188c2ecf20Sopenharmony_ciout_domain_free: 1198c2ecf20Sopenharmony_ci iommu_domain_free(pcfg->iommu_domain); 1208c2ecf20Sopenharmony_ci pcfg->iommu_domain = NULL; 1218c2ecf20Sopenharmony_ci#endif 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic struct qman_portal *init_pcfg(struct qm_portal_config *pcfg) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct qman_portal *p; 1278c2ecf20Sopenharmony_ci u32 irq_sources = 0; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* We need the same LIODN offset for all portals */ 1308c2ecf20Sopenharmony_ci qman_liodn_fixup(pcfg->channel); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci pcfg->iommu_domain = NULL; 1338c2ecf20Sopenharmony_ci portal_set_cpu(pcfg, pcfg->cpu); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci p = qman_create_affine_portal(pcfg, NULL); 1368c2ecf20Sopenharmony_ci if (!p) { 1378c2ecf20Sopenharmony_ci dev_crit(pcfg->dev, "%s: Portal failure on cpu %d\n", 1388c2ecf20Sopenharmony_ci __func__, pcfg->cpu); 1398c2ecf20Sopenharmony_ci return NULL; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* Determine what should be interrupt-vs-poll driven */ 1438c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPA_PIRQ_SLOW 1448c2ecf20Sopenharmony_ci irq_sources |= QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI | 1458c2ecf20Sopenharmony_ci QM_PIRQ_CSCI; 1468c2ecf20Sopenharmony_ci#endif 1478c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPA_PIRQ_FAST 1488c2ecf20Sopenharmony_ci irq_sources |= QM_PIRQ_DQRI; 1498c2ecf20Sopenharmony_ci#endif 1508c2ecf20Sopenharmony_ci qman_p_irqsource_add(p, irq_sources); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci spin_lock(&qman_lock); 1538c2ecf20Sopenharmony_ci if (cpumask_equal(&portal_cpus, cpu_possible_mask)) { 1548c2ecf20Sopenharmony_ci /* all assigned portals are initialized now */ 1558c2ecf20Sopenharmony_ci qman_init_cgr_all(); 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (!qman_dma_portal) 1598c2ecf20Sopenharmony_ci qman_dma_portal = p; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci spin_unlock(&qman_lock); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci dev_info(pcfg->dev, "Portal initialised, cpu %d\n", pcfg->cpu); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return p; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void qman_portal_update_sdest(const struct qm_portal_config *pcfg, 1698c2ecf20Sopenharmony_ci unsigned int cpu) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_PAMU /* TODO */ 1728c2ecf20Sopenharmony_ci struct pamu_stash_attribute stash_attr; 1738c2ecf20Sopenharmony_ci int ret; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (pcfg->iommu_domain) { 1768c2ecf20Sopenharmony_ci stash_attr.cpu = cpu; 1778c2ecf20Sopenharmony_ci stash_attr.cache = PAMU_ATTR_CACHE_L1; 1788c2ecf20Sopenharmony_ci ret = iommu_domain_set_attr(pcfg->iommu_domain, 1798c2ecf20Sopenharmony_ci DOMAIN_ATTR_FSL_PAMU_STASH, &stash_attr); 1808c2ecf20Sopenharmony_ci if (ret < 0) { 1818c2ecf20Sopenharmony_ci dev_err(pcfg->dev, 1828c2ecf20Sopenharmony_ci "Failed to update pamu stash setting\n"); 1838c2ecf20Sopenharmony_ci return; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci#endif 1878c2ecf20Sopenharmony_ci qman_set_sdest(pcfg->channel, cpu); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int qman_offline_cpu(unsigned int cpu) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct qman_portal *p; 1938c2ecf20Sopenharmony_ci const struct qm_portal_config *pcfg; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci p = affine_portals[cpu]; 1968c2ecf20Sopenharmony_ci if (p) { 1978c2ecf20Sopenharmony_ci pcfg = qman_get_qm_portal_config(p); 1988c2ecf20Sopenharmony_ci if (pcfg) { 1998c2ecf20Sopenharmony_ci /* select any other online CPU */ 2008c2ecf20Sopenharmony_ci cpu = cpumask_any_but(cpu_online_mask, cpu); 2018c2ecf20Sopenharmony_ci irq_set_affinity(pcfg->irq, cpumask_of(cpu)); 2028c2ecf20Sopenharmony_ci qman_portal_update_sdest(pcfg, cpu); 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int qman_online_cpu(unsigned int cpu) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct qman_portal *p; 2118c2ecf20Sopenharmony_ci const struct qm_portal_config *pcfg; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci p = affine_portals[cpu]; 2148c2ecf20Sopenharmony_ci if (p) { 2158c2ecf20Sopenharmony_ci pcfg = qman_get_qm_portal_config(p); 2168c2ecf20Sopenharmony_ci if (pcfg) { 2178c2ecf20Sopenharmony_ci irq_set_affinity(pcfg->irq, cpumask_of(cpu)); 2188c2ecf20Sopenharmony_ci qman_portal_update_sdest(pcfg, cpu); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciint qman_portals_probed(void) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci return __qman_portals_probed; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qman_portals_probed); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int qman_portal_probe(struct platform_device *pdev) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2338c2ecf20Sopenharmony_ci struct device_node *node = dev->of_node; 2348c2ecf20Sopenharmony_ci struct qm_portal_config *pcfg; 2358c2ecf20Sopenharmony_ci struct resource *addr_phys[2]; 2368c2ecf20Sopenharmony_ci int irq, cpu, err, i; 2378c2ecf20Sopenharmony_ci u32 val; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci err = qman_is_probed(); 2408c2ecf20Sopenharmony_ci if (!err) 2418c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 2428c2ecf20Sopenharmony_ci if (err < 0) { 2438c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failing probe due to qman probe error\n"); 2448c2ecf20Sopenharmony_ci return -ENODEV; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL); 2488c2ecf20Sopenharmony_ci if (!pcfg) { 2498c2ecf20Sopenharmony_ci __qman_portals_probed = -1; 2508c2ecf20Sopenharmony_ci return -ENOMEM; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci pcfg->dev = dev; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci addr_phys[0] = platform_get_resource(pdev, IORESOURCE_MEM, 2568c2ecf20Sopenharmony_ci DPAA_PORTAL_CE); 2578c2ecf20Sopenharmony_ci if (!addr_phys[0]) { 2588c2ecf20Sopenharmony_ci dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node); 2598c2ecf20Sopenharmony_ci goto err_ioremap1; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM, 2638c2ecf20Sopenharmony_ci DPAA_PORTAL_CI); 2648c2ecf20Sopenharmony_ci if (!addr_phys[1]) { 2658c2ecf20Sopenharmony_ci dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node); 2668c2ecf20Sopenharmony_ci goto err_ioremap1; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci err = of_property_read_u32(node, "cell-index", &val); 2708c2ecf20Sopenharmony_ci if (err) { 2718c2ecf20Sopenharmony_ci dev_err(dev, "Can't get %pOF property 'cell-index'\n", node); 2728c2ecf20Sopenharmony_ci __qman_portals_probed = -1; 2738c2ecf20Sopenharmony_ci return err; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci pcfg->channel = val; 2768c2ecf20Sopenharmony_ci pcfg->cpu = -1; 2778c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 2788c2ecf20Sopenharmony_ci if (irq <= 0) 2798c2ecf20Sopenharmony_ci goto err_ioremap1; 2808c2ecf20Sopenharmony_ci pcfg->irq = irq; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci pcfg->addr_virt_ce = memremap(addr_phys[0]->start, 2838c2ecf20Sopenharmony_ci resource_size(addr_phys[0]), 2848c2ecf20Sopenharmony_ci QBMAN_MEMREMAP_ATTR); 2858c2ecf20Sopenharmony_ci if (!pcfg->addr_virt_ce) { 2868c2ecf20Sopenharmony_ci dev_err(dev, "memremap::CE failed\n"); 2878c2ecf20Sopenharmony_ci goto err_ioremap1; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci pcfg->addr_virt_ci = ioremap(addr_phys[1]->start, 2918c2ecf20Sopenharmony_ci resource_size(addr_phys[1])); 2928c2ecf20Sopenharmony_ci if (!pcfg->addr_virt_ci) { 2938c2ecf20Sopenharmony_ci dev_err(dev, "ioremap::CI failed\n"); 2948c2ecf20Sopenharmony_ci goto err_ioremap2; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci pcfg->pools = qm_get_pools_sdqcr(); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci spin_lock(&qman_lock); 3008c2ecf20Sopenharmony_ci cpu = cpumask_next_zero(-1, &portal_cpus); 3018c2ecf20Sopenharmony_ci if (cpu >= nr_cpu_ids) { 3028c2ecf20Sopenharmony_ci __qman_portals_probed = 1; 3038c2ecf20Sopenharmony_ci /* unassigned portal, skip init */ 3048c2ecf20Sopenharmony_ci spin_unlock(&qman_lock); 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci cpumask_set_cpu(cpu, &portal_cpus); 3098c2ecf20Sopenharmony_ci spin_unlock(&qman_lock); 3108c2ecf20Sopenharmony_ci pcfg->cpu = cpu; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (dma_set_mask(dev, DMA_BIT_MASK(40))) { 3138c2ecf20Sopenharmony_ci dev_err(dev, "dma_set_mask() failed\n"); 3148c2ecf20Sopenharmony_ci goto err_portal_init; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (!init_pcfg(pcfg)) { 3188c2ecf20Sopenharmony_ci dev_err(dev, "portal init failed\n"); 3198c2ecf20Sopenharmony_ci goto err_portal_init; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* clear irq affinity if assigned cpu is offline */ 3238c2ecf20Sopenharmony_ci if (!cpu_online(cpu)) 3248c2ecf20Sopenharmony_ci qman_offline_cpu(cpu); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (__qman_portals_probed == 1 && qman_requires_cleanup()) { 3278c2ecf20Sopenharmony_ci /* 3288c2ecf20Sopenharmony_ci * QMan wasn't reset prior to boot (Kexec for example) 3298c2ecf20Sopenharmony_ci * Empty all the frame queues so they are in reset state 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ci for (i = 0; i < qm_get_fqid_maxcnt(); i++) { 3328c2ecf20Sopenharmony_ci err = qman_shutdown_fq(i); 3338c2ecf20Sopenharmony_ci if (err) { 3348c2ecf20Sopenharmony_ci dev_err(dev, "Failed to shutdown frame queue %d\n", 3358c2ecf20Sopenharmony_ci i); 3368c2ecf20Sopenharmony_ci goto err_portal_init; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci qman_done_cleanup(); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cierr_portal_init: 3458c2ecf20Sopenharmony_ci iounmap(pcfg->addr_virt_ci); 3468c2ecf20Sopenharmony_cierr_ioremap2: 3478c2ecf20Sopenharmony_ci memunmap(pcfg->addr_virt_ce); 3488c2ecf20Sopenharmony_cierr_ioremap1: 3498c2ecf20Sopenharmony_ci __qman_portals_probed = -1; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return -ENXIO; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic const struct of_device_id qman_portal_ids[] = { 3558c2ecf20Sopenharmony_ci { 3568c2ecf20Sopenharmony_ci .compatible = "fsl,qman-portal", 3578c2ecf20Sopenharmony_ci }, 3588c2ecf20Sopenharmony_ci {} 3598c2ecf20Sopenharmony_ci}; 3608c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, qman_portal_ids); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic struct platform_driver qman_portal_driver = { 3638c2ecf20Sopenharmony_ci .driver = { 3648c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 3658c2ecf20Sopenharmony_ci .of_match_table = qman_portal_ids, 3668c2ecf20Sopenharmony_ci }, 3678c2ecf20Sopenharmony_ci .probe = qman_portal_probe, 3688c2ecf20Sopenharmony_ci}; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int __init qman_portal_driver_register(struct platform_driver *drv) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci int ret; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci ret = platform_driver_register(drv); 3758c2ecf20Sopenharmony_ci if (ret < 0) 3768c2ecf20Sopenharmony_ci return ret; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, 3798c2ecf20Sopenharmony_ci "soc/qman_portal:online", 3808c2ecf20Sopenharmony_ci qman_online_cpu, qman_offline_cpu); 3818c2ecf20Sopenharmony_ci if (ret < 0) { 3828c2ecf20Sopenharmony_ci pr_err("qman: failed to register hotplug callbacks.\n"); 3838c2ecf20Sopenharmony_ci platform_driver_unregister(drv); 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci return 0; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cimodule_driver(qman_portal_driver, 3908c2ecf20Sopenharmony_ci qman_portal_driver_register, platform_driver_unregister); 391