18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/irq.h>
78c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
88c2ecf20Sopenharmony_ci#include <linux/msi.h>
98c2ecf20Sopenharmony_ci#include <asm/mpic.h>
108c2ecf20Sopenharmony_ci#include <asm/prom.h>
118c2ecf20Sopenharmony_ci#include <asm/hw_irq.h>
128c2ecf20Sopenharmony_ci#include <asm/ppc-pci.h>
138c2ecf20Sopenharmony_ci#include <asm/msi_bitmap.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <sysdev/mpic.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_civoid mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	/* The mpic calls this even when there is no allocator setup */
208c2ecf20Sopenharmony_ci	if (!mpic->msi_bitmap.bitmap)
218c2ecf20Sopenharmony_ci		return;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#ifdef CONFIG_MPIC_U3_HT_IRQS
278c2ecf20Sopenharmony_cistatic int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	irq_hw_number_t hwirq;
308c2ecf20Sopenharmony_ci	const struct irq_domain_ops *ops = mpic->irqhost->ops;
318c2ecf20Sopenharmony_ci	struct device_node *np;
328c2ecf20Sopenharmony_ci	int flags, index, i;
338c2ecf20Sopenharmony_ci	struct of_phandle_args oirq;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	pr_debug("mpic: found U3, guessing msi allocator setup\n");
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	/* Reserve source numbers we know are reserved in the HW.
388c2ecf20Sopenharmony_ci	 *
398c2ecf20Sopenharmony_ci	 * This is a bit of a mix of U3 and U4 reserves but that's going
408c2ecf20Sopenharmony_ci	 * to work fine, we have plenty enugh numbers left so let's just
418c2ecf20Sopenharmony_ci	 * mark anything we don't like reserved.
428c2ecf20Sopenharmony_ci	 */
438c2ecf20Sopenharmony_ci	for (i = 0;   i < 8;   i++)
448c2ecf20Sopenharmony_ci		msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	for (i = 42;  i < 46;  i++)
478c2ecf20Sopenharmony_ci		msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	for (i = 100; i < 105; i++)
508c2ecf20Sopenharmony_ci		msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	for (i = 124; i < mpic->num_sources; i++)
538c2ecf20Sopenharmony_ci		msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	np = NULL;
578c2ecf20Sopenharmony_ci	while ((np = of_find_all_nodes(np))) {
588c2ecf20Sopenharmony_ci		pr_debug("mpic: mapping hwirqs for %pOF\n", np);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		index = 0;
618c2ecf20Sopenharmony_ci		while (of_irq_parse_one(np, index++, &oirq) == 0) {
628c2ecf20Sopenharmony_ci			ops->xlate(mpic->irqhost, NULL, oirq.args,
638c2ecf20Sopenharmony_ci						oirq.args_count, &hwirq, &flags);
648c2ecf20Sopenharmony_ci			msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
658c2ecf20Sopenharmony_ci		}
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return 0;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci#else
718c2ecf20Sopenharmony_cistatic int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	return -1;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci#endif
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ciint mpic_msi_init_allocator(struct mpic *mpic)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	int rc;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->num_sources,
828c2ecf20Sopenharmony_ci			      irq_domain_get_of_node(mpic->irqhost));
838c2ecf20Sopenharmony_ci	if (rc)
848c2ecf20Sopenharmony_ci		return rc;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	rc = msi_bitmap_reserve_dt_hwirqs(&mpic->msi_bitmap);
878c2ecf20Sopenharmony_ci	if (rc > 0) {
888c2ecf20Sopenharmony_ci		if (mpic->flags & MPIC_U3_HT_IRQS)
898c2ecf20Sopenharmony_ci			rc = mpic_msi_reserve_u3_hwirqs(mpic);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		if (rc) {
928c2ecf20Sopenharmony_ci			msi_bitmap_free(&mpic->msi_bitmap);
938c2ecf20Sopenharmony_ci			return rc;
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return 0;
988c2ecf20Sopenharmony_ci}
99