18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Handle interrupts from the SRM, assuming no additional weirdness.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/init.h>
78c2ecf20Sopenharmony_ci#include <linux/sched.h>
88c2ecf20Sopenharmony_ci#include <linux/irq.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "proto.h"
118c2ecf20Sopenharmony_ci#include "irq_impl.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * Is the palcode SMP safe? In other words: can we call cserve_ena/dis
168c2ecf20Sopenharmony_ci * at the same time in multiple CPUs? To be safe I added a spinlock
178c2ecf20Sopenharmony_ci * but it can be removed trivially if the palcode is robust against smp.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ciDEFINE_SPINLOCK(srm_irq_lock);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic inline void
228c2ecf20Sopenharmony_cisrm_enable_irq(struct irq_data *d)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	spin_lock(&srm_irq_lock);
258c2ecf20Sopenharmony_ci	cserve_ena(d->irq - 16);
268c2ecf20Sopenharmony_ci	spin_unlock(&srm_irq_lock);
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void
308c2ecf20Sopenharmony_cisrm_disable_irq(struct irq_data *d)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	spin_lock(&srm_irq_lock);
338c2ecf20Sopenharmony_ci	cserve_dis(d->irq - 16);
348c2ecf20Sopenharmony_ci	spin_unlock(&srm_irq_lock);
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* Handle interrupts from the SRM, assuming no additional weirdness.  */
388c2ecf20Sopenharmony_cistatic struct irq_chip srm_irq_type = {
398c2ecf20Sopenharmony_ci	.name		= "SRM",
408c2ecf20Sopenharmony_ci	.irq_unmask	= srm_enable_irq,
418c2ecf20Sopenharmony_ci	.irq_mask	= srm_disable_irq,
428c2ecf20Sopenharmony_ci	.irq_mask_ack	= srm_disable_irq,
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_civoid __init
468c2ecf20Sopenharmony_ciinit_srm_irqs(long max, unsigned long ignore_mask)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	long i;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (NR_IRQS <= 16)
518c2ecf20Sopenharmony_ci		return;
528c2ecf20Sopenharmony_ci	for (i = 16; i < max; ++i) {
538c2ecf20Sopenharmony_ci		if (i < 64 && ((ignore_mask >> i) & 1))
548c2ecf20Sopenharmony_ci			continue;
558c2ecf20Sopenharmony_ci		irq_set_chip_and_handler(i, &srm_irq_type, handle_level_irq);
568c2ecf20Sopenharmony_ci		irq_set_status_flags(i, IRQ_LEVEL);
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_civoid
618c2ecf20Sopenharmony_cisrm_device_interrupt(unsigned long vector)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	int irq = (vector - 0x800) >> 4;
648c2ecf20Sopenharmony_ci	handle_irq(irq);
658c2ecf20Sopenharmony_ci}
66