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