162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2006-2007, Michael Ellerman, IBM Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/irq.h> 762306a36Sopenharmony_ci#include <linux/irqdomain.h> 862306a36Sopenharmony_ci#include <linux/of_irq.h> 962306a36Sopenharmony_ci#include <linux/bitmap.h> 1062306a36Sopenharmony_ci#include <linux/msi.h> 1162306a36Sopenharmony_ci#include <asm/mpic.h> 1262306a36Sopenharmony_ci#include <asm/hw_irq.h> 1362306a36Sopenharmony_ci#include <asm/ppc-pci.h> 1462306a36Sopenharmony_ci#include <asm/msi_bitmap.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <sysdev/mpic.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_civoid mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci /* The mpic calls this even when there is no allocator setup */ 2162306a36Sopenharmony_ci if (!mpic->msi_bitmap.bitmap) 2262306a36Sopenharmony_ci return; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#ifdef CONFIG_MPIC_U3_HT_IRQS 2862306a36Sopenharmony_cistatic int __init mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci irq_hw_number_t hwirq; 3162306a36Sopenharmony_ci const struct irq_domain_ops *ops = mpic->irqhost->ops; 3262306a36Sopenharmony_ci struct device_node *np; 3362306a36Sopenharmony_ci int flags, index, i; 3462306a36Sopenharmony_ci struct of_phandle_args oirq; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci pr_debug("mpic: found U3, guessing msi allocator setup\n"); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* Reserve source numbers we know are reserved in the HW. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * This is a bit of a mix of U3 and U4 reserves but that's going 4162306a36Sopenharmony_ci * to work fine, we have plenty enough numbers left so let's just 4262306a36Sopenharmony_ci * mark anything we don't like reserved. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci for (i = 0; i < 8; i++) 4562306a36Sopenharmony_ci msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci for (i = 42; i < 46; i++) 4862306a36Sopenharmony_ci msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci for (i = 100; i < 105; i++) 5162306a36Sopenharmony_ci msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci for (i = 124; i < mpic->num_sources; i++) 5462306a36Sopenharmony_ci msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci np = NULL; 5862306a36Sopenharmony_ci while ((np = of_find_all_nodes(np))) { 5962306a36Sopenharmony_ci pr_debug("mpic: mapping hwirqs for %pOF\n", np); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci index = 0; 6262306a36Sopenharmony_ci while (of_irq_parse_one(np, index++, &oirq) == 0) { 6362306a36Sopenharmony_ci ops->xlate(mpic->irqhost, NULL, oirq.args, 6462306a36Sopenharmony_ci oirq.args_count, &hwirq, &flags); 6562306a36Sopenharmony_ci msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci#else 7262306a36Sopenharmony_cistatic int __init mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci return -1; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci#endif 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciint __init mpic_msi_init_allocator(struct mpic *mpic) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci int rc; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->num_sources, 8362306a36Sopenharmony_ci irq_domain_get_of_node(mpic->irqhost)); 8462306a36Sopenharmony_ci if (rc) 8562306a36Sopenharmony_ci return rc; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci rc = msi_bitmap_reserve_dt_hwirqs(&mpic->msi_bitmap); 8862306a36Sopenharmony_ci if (rc > 0) { 8962306a36Sopenharmony_ci if (mpic->flags & MPIC_U3_HT_IRQS) 9062306a36Sopenharmony_ci rc = mpic_msi_reserve_u3_hwirqs(mpic); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (rc) { 9362306a36Sopenharmony_ci msi_bitmap_free(&mpic->msi_bitmap); 9462306a36Sopenharmony_ci return rc; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 100