xref: /openbmc/linux/arch/alpha/kernel/irq_srm.c (revision 498495dba268b20e8eadd7fe93c140c68b6cc9d2)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Handle interrupts from the SRM, assuming no additional weirdness.
4   */
5  
6  #include <linux/init.h>
7  #include <linux/sched.h>
8  #include <linux/irq.h>
9  
10  #include "proto.h"
11  #include "irq_impl.h"
12  
13  
14  /*
15   * Is the palcode SMP safe? In other words: can we call cserve_ena/dis
16   * at the same time in multiple CPUs? To be safe I added a spinlock
17   * but it can be removed trivially if the palcode is robust against smp.
18   */
19  DEFINE_SPINLOCK(srm_irq_lock);
20  
21  static inline void
srm_enable_irq(struct irq_data * d)22  srm_enable_irq(struct irq_data *d)
23  {
24  	spin_lock(&srm_irq_lock);
25  	cserve_ena(d->irq - 16);
26  	spin_unlock(&srm_irq_lock);
27  }
28  
29  static void
srm_disable_irq(struct irq_data * d)30  srm_disable_irq(struct irq_data *d)
31  {
32  	spin_lock(&srm_irq_lock);
33  	cserve_dis(d->irq - 16);
34  	spin_unlock(&srm_irq_lock);
35  }
36  
37  /* Handle interrupts from the SRM, assuming no additional weirdness.  */
38  static struct irq_chip srm_irq_type = {
39  	.name		= "SRM",
40  	.irq_unmask	= srm_enable_irq,
41  	.irq_mask	= srm_disable_irq,
42  	.irq_mask_ack	= srm_disable_irq,
43  };
44  
45  void __init
init_srm_irqs(long max,unsigned long ignore_mask)46  init_srm_irqs(long max, unsigned long ignore_mask)
47  {
48  	long i;
49  
50  	if (NR_IRQS <= 16)
51  		return;
52  	for (i = 16; i < max; ++i) {
53  		if (i < 64 && ((ignore_mask >> i) & 1))
54  			continue;
55  		irq_set_chip_and_handler(i, &srm_irq_type, handle_level_irq);
56  		irq_set_status_flags(i, IRQ_LEVEL);
57  	}
58  }
59  
60  void
srm_device_interrupt(unsigned long vector)61  srm_device_interrupt(unsigned long vector)
62  {
63  	int irq = (vector - 0x800) >> 4;
64  	handle_irq(irq);
65  }
66