162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Xen event channels (2-level ABI)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/linkage.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/irq.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <asm/sync_bitops.h>
1562306a36Sopenharmony_ci#include <asm/xen/hypercall.h>
1662306a36Sopenharmony_ci#include <asm/xen/hypervisor.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <xen/xen.h>
1962306a36Sopenharmony_ci#include <xen/xen-ops.h>
2062306a36Sopenharmony_ci#include <xen/events.h>
2162306a36Sopenharmony_ci#include <xen/interface/xen.h>
2262306a36Sopenharmony_ci#include <xen/interface/event_channel.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "events_internal.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * Note sizeof(xen_ulong_t) can be more than sizeof(unsigned long). Be
2862306a36Sopenharmony_ci * careful to only use bitops which allow for this (e.g
2962306a36Sopenharmony_ci * test_bit/find_first_bit and friends but not __ffs) and to pass
3062306a36Sopenharmony_ci * BITS_PER_EVTCHN_WORD as the bitmask length.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci#define BITS_PER_EVTCHN_WORD (sizeof(xen_ulong_t)*8)
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * Make a bitmask (i.e. unsigned long *) of a xen_ulong_t
3562306a36Sopenharmony_ci * array. Primarily to avoid long lines (hence the terse name).
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci#define BM(x) (unsigned long *)(x)
3862306a36Sopenharmony_ci/* Find the first set bit in a evtchn mask */
3962306a36Sopenharmony_ci#define EVTCHN_FIRST_BIT(w) find_first_bit(BM(&(w)), BITS_PER_EVTCHN_WORD)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define EVTCHN_MASK_SIZE (EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic DEFINE_PER_CPU(xen_ulong_t [EVTCHN_MASK_SIZE], cpu_evtchn_mask);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic unsigned evtchn_2l_max_channels(void)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	return EVTCHN_2L_NR_CHANNELS;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic void evtchn_2l_remove(evtchn_port_t evtchn, unsigned int cpu)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	clear_bit(evtchn, BM(per_cpu(cpu_evtchn_mask, cpu)));
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic void evtchn_2l_bind_to_cpu(evtchn_port_t evtchn, unsigned int cpu,
5662306a36Sopenharmony_ci				  unsigned int old_cpu)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	clear_bit(evtchn, BM(per_cpu(cpu_evtchn_mask, old_cpu)));
5962306a36Sopenharmony_ci	set_bit(evtchn, BM(per_cpu(cpu_evtchn_mask, cpu)));
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic void evtchn_2l_clear_pending(evtchn_port_t port)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct shared_info *s = HYPERVISOR_shared_info;
6562306a36Sopenharmony_ci	sync_clear_bit(port, BM(&s->evtchn_pending[0]));
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic void evtchn_2l_set_pending(evtchn_port_t port)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct shared_info *s = HYPERVISOR_shared_info;
7162306a36Sopenharmony_ci	sync_set_bit(port, BM(&s->evtchn_pending[0]));
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic bool evtchn_2l_is_pending(evtchn_port_t port)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct shared_info *s = HYPERVISOR_shared_info;
7762306a36Sopenharmony_ci	return sync_test_bit(port, BM(&s->evtchn_pending[0]));
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void evtchn_2l_mask(evtchn_port_t port)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct shared_info *s = HYPERVISOR_shared_info;
8362306a36Sopenharmony_ci	sync_set_bit(port, BM(&s->evtchn_mask[0]));
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic void evtchn_2l_unmask(evtchn_port_t port)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct shared_info *s = HYPERVISOR_shared_info;
8962306a36Sopenharmony_ci	unsigned int cpu = get_cpu();
9062306a36Sopenharmony_ci	int do_hypercall = 0, evtchn_pending = 0;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	BUG_ON(!irqs_disabled());
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	smp_wmb();	/* All writes before unmask must be visible. */
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (unlikely((cpu != cpu_from_evtchn(port))))
9762306a36Sopenharmony_ci		do_hypercall = 1;
9862306a36Sopenharmony_ci	else {
9962306a36Sopenharmony_ci		/*
10062306a36Sopenharmony_ci		 * Need to clear the mask before checking pending to
10162306a36Sopenharmony_ci		 * avoid a race with an event becoming pending.
10262306a36Sopenharmony_ci		 *
10362306a36Sopenharmony_ci		 * EVTCHNOP_unmask will only trigger an upcall if the
10462306a36Sopenharmony_ci		 * mask bit was set, so if a hypercall is needed
10562306a36Sopenharmony_ci		 * remask the event.
10662306a36Sopenharmony_ci		 */
10762306a36Sopenharmony_ci		sync_clear_bit(port, BM(&s->evtchn_mask[0]));
10862306a36Sopenharmony_ci		evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0]));
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		if (unlikely(evtchn_pending && xen_hvm_domain())) {
11162306a36Sopenharmony_ci			sync_set_bit(port, BM(&s->evtchn_mask[0]));
11262306a36Sopenharmony_ci			do_hypercall = 1;
11362306a36Sopenharmony_ci		}
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Slow path (hypercall) if this is a non-local port or if this is
11762306a36Sopenharmony_ci	 * an hvm domain and an event is pending (hvm domains don't have
11862306a36Sopenharmony_ci	 * their own implementation of irq_enable). */
11962306a36Sopenharmony_ci	if (do_hypercall) {
12062306a36Sopenharmony_ci		struct evtchn_unmask unmask = { .port = port };
12162306a36Sopenharmony_ci		(void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
12262306a36Sopenharmony_ci	} else {
12362306a36Sopenharmony_ci		struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		/*
12662306a36Sopenharmony_ci		 * The following is basically the equivalent of
12762306a36Sopenharmony_ci		 * 'hw_resend_irq'. Just like a real IO-APIC we 'lose
12862306a36Sopenharmony_ci		 * the interrupt edge' if the channel is masked.
12962306a36Sopenharmony_ci		 */
13062306a36Sopenharmony_ci		if (evtchn_pending &&
13162306a36Sopenharmony_ci		    !sync_test_and_set_bit(port / BITS_PER_EVTCHN_WORD,
13262306a36Sopenharmony_ci					   BM(&vcpu_info->evtchn_pending_sel)))
13362306a36Sopenharmony_ci			vcpu_info->evtchn_upcall_pending = 1;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	put_cpu();
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic DEFINE_PER_CPU(unsigned int, current_word_idx);
14062306a36Sopenharmony_cistatic DEFINE_PER_CPU(unsigned int, current_bit_idx);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/*
14362306a36Sopenharmony_ci * Mask out the i least significant bits of w
14462306a36Sopenharmony_ci */
14562306a36Sopenharmony_ci#define MASK_LSBS(w, i) (w & ((~((xen_ulong_t)0UL)) << i))
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic inline xen_ulong_t active_evtchns(unsigned int cpu,
14862306a36Sopenharmony_ci					 struct shared_info *sh,
14962306a36Sopenharmony_ci					 unsigned int idx)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	return sh->evtchn_pending[idx] &
15262306a36Sopenharmony_ci		per_cpu(cpu_evtchn_mask, cpu)[idx] &
15362306a36Sopenharmony_ci		~sh->evtchn_mask[idx];
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*
15762306a36Sopenharmony_ci * Search the CPU's pending events bitmasks.  For each one found, map
15862306a36Sopenharmony_ci * the event number to an irq, and feed it into do_IRQ() for handling.
15962306a36Sopenharmony_ci *
16062306a36Sopenharmony_ci * Xen uses a two-level bitmap to speed searching.  The first level is
16162306a36Sopenharmony_ci * a bitset of words which contain pending event bits.  The second
16262306a36Sopenharmony_ci * level is a bitset of pending events themselves.
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_cistatic void evtchn_2l_handle_events(unsigned cpu, struct evtchn_loop_ctrl *ctrl)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	int irq;
16762306a36Sopenharmony_ci	xen_ulong_t pending_words;
16862306a36Sopenharmony_ci	xen_ulong_t pending_bits;
16962306a36Sopenharmony_ci	int start_word_idx, start_bit_idx;
17062306a36Sopenharmony_ci	int word_idx, bit_idx;
17162306a36Sopenharmony_ci	int i;
17262306a36Sopenharmony_ci	struct shared_info *s = HYPERVISOR_shared_info;
17362306a36Sopenharmony_ci	struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
17462306a36Sopenharmony_ci	evtchn_port_t evtchn;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* Timer interrupt has highest priority. */
17762306a36Sopenharmony_ci	irq = irq_evtchn_from_virq(cpu, VIRQ_TIMER, &evtchn);
17862306a36Sopenharmony_ci	if (irq != -1) {
17962306a36Sopenharmony_ci		word_idx = evtchn / BITS_PER_LONG;
18062306a36Sopenharmony_ci		bit_idx = evtchn % BITS_PER_LONG;
18162306a36Sopenharmony_ci		if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx))
18262306a36Sopenharmony_ci			generic_handle_irq(irq);
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/*
18662306a36Sopenharmony_ci	 * Master flag must be cleared /before/ clearing
18762306a36Sopenharmony_ci	 * selector flag. xchg_xen_ulong must contain an
18862306a36Sopenharmony_ci	 * appropriate barrier.
18962306a36Sopenharmony_ci	 */
19062306a36Sopenharmony_ci	pending_words = xchg_xen_ulong(&vcpu_info->evtchn_pending_sel, 0);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	start_word_idx = __this_cpu_read(current_word_idx);
19362306a36Sopenharmony_ci	start_bit_idx = __this_cpu_read(current_bit_idx);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	word_idx = start_word_idx;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	for (i = 0; pending_words != 0; i++) {
19862306a36Sopenharmony_ci		xen_ulong_t words;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		words = MASK_LSBS(pending_words, word_idx);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		/*
20362306a36Sopenharmony_ci		 * If we masked out all events, wrap to beginning.
20462306a36Sopenharmony_ci		 */
20562306a36Sopenharmony_ci		if (words == 0) {
20662306a36Sopenharmony_ci			word_idx = 0;
20762306a36Sopenharmony_ci			bit_idx = 0;
20862306a36Sopenharmony_ci			continue;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci		word_idx = EVTCHN_FIRST_BIT(words);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		pending_bits = active_evtchns(cpu, s, word_idx);
21362306a36Sopenharmony_ci		bit_idx = 0; /* usually scan entire word from start */
21462306a36Sopenharmony_ci		/*
21562306a36Sopenharmony_ci		 * We scan the starting word in two parts.
21662306a36Sopenharmony_ci		 *
21762306a36Sopenharmony_ci		 * 1st time: start in the middle, scanning the
21862306a36Sopenharmony_ci		 * upper bits.
21962306a36Sopenharmony_ci		 *
22062306a36Sopenharmony_ci		 * 2nd time: scan the whole word (not just the
22162306a36Sopenharmony_ci		 * parts skipped in the first pass) -- if an
22262306a36Sopenharmony_ci		 * event in the previously scanned bits is
22362306a36Sopenharmony_ci		 * pending again it would just be scanned on
22462306a36Sopenharmony_ci		 * the next loop anyway.
22562306a36Sopenharmony_ci		 */
22662306a36Sopenharmony_ci		if (word_idx == start_word_idx) {
22762306a36Sopenharmony_ci			if (i == 0)
22862306a36Sopenharmony_ci				bit_idx = start_bit_idx;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		do {
23262306a36Sopenharmony_ci			xen_ulong_t bits;
23362306a36Sopenharmony_ci			evtchn_port_t port;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci			bits = MASK_LSBS(pending_bits, bit_idx);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci			/* If we masked out all events, move on. */
23862306a36Sopenharmony_ci			if (bits == 0)
23962306a36Sopenharmony_ci				break;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci			bit_idx = EVTCHN_FIRST_BIT(bits);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci			/* Process port. */
24462306a36Sopenharmony_ci			port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx;
24562306a36Sopenharmony_ci			handle_irq_for_port(port, ctrl);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci			bit_idx = (bit_idx + 1) % BITS_PER_EVTCHN_WORD;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci			/* Next caller starts at last processed + 1 */
25062306a36Sopenharmony_ci			__this_cpu_write(current_word_idx,
25162306a36Sopenharmony_ci					 bit_idx ? word_idx :
25262306a36Sopenharmony_ci					 (word_idx+1) % BITS_PER_EVTCHN_WORD);
25362306a36Sopenharmony_ci			__this_cpu_write(current_bit_idx, bit_idx);
25462306a36Sopenharmony_ci		} while (bit_idx != 0);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		/* Scan start_l1i twice; all others once. */
25762306a36Sopenharmony_ci		if ((word_idx != start_word_idx) || (i != 0))
25862306a36Sopenharmony_ci			pending_words &= ~(1UL << word_idx);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci		word_idx = (word_idx + 1) % BITS_PER_EVTCHN_WORD;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ciirqreturn_t xen_debug_interrupt(int irq, void *dev_id)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct shared_info *sh = HYPERVISOR_shared_info;
26762306a36Sopenharmony_ci	int cpu = smp_processor_id();
26862306a36Sopenharmony_ci	xen_ulong_t *cpu_evtchn = per_cpu(cpu_evtchn_mask, cpu);
26962306a36Sopenharmony_ci	int i;
27062306a36Sopenharmony_ci	unsigned long flags;
27162306a36Sopenharmony_ci	static DEFINE_SPINLOCK(debug_lock);
27262306a36Sopenharmony_ci	struct vcpu_info *v;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	spin_lock_irqsave(&debug_lock, flags);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	printk("\nvcpu %d\n  ", cpu);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	for_each_online_cpu(i) {
27962306a36Sopenharmony_ci		int pending;
28062306a36Sopenharmony_ci		v = per_cpu(xen_vcpu, i);
28162306a36Sopenharmony_ci		pending = (get_irq_regs() && i == cpu)
28262306a36Sopenharmony_ci			? xen_irqs_disabled(get_irq_regs())
28362306a36Sopenharmony_ci			: v->evtchn_upcall_mask;
28462306a36Sopenharmony_ci		printk("%d: masked=%d pending=%d event_sel %0*"PRI_xen_ulong"\n  ", i,
28562306a36Sopenharmony_ci		       pending, v->evtchn_upcall_pending,
28662306a36Sopenharmony_ci		       (int)(sizeof(v->evtchn_pending_sel)*2),
28762306a36Sopenharmony_ci		       v->evtchn_pending_sel);
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci	v = per_cpu(xen_vcpu, cpu);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	printk("\npending:\n   ");
29262306a36Sopenharmony_ci	for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
29362306a36Sopenharmony_ci		printk("%0*"PRI_xen_ulong"%s",
29462306a36Sopenharmony_ci		       (int)sizeof(sh->evtchn_pending[0])*2,
29562306a36Sopenharmony_ci		       sh->evtchn_pending[i],
29662306a36Sopenharmony_ci		       i % 8 == 0 ? "\n   " : " ");
29762306a36Sopenharmony_ci	printk("\nglobal mask:\n   ");
29862306a36Sopenharmony_ci	for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
29962306a36Sopenharmony_ci		printk("%0*"PRI_xen_ulong"%s",
30062306a36Sopenharmony_ci		       (int)(sizeof(sh->evtchn_mask[0])*2),
30162306a36Sopenharmony_ci		       sh->evtchn_mask[i],
30262306a36Sopenharmony_ci		       i % 8 == 0 ? "\n   " : " ");
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	printk("\nglobally unmasked:\n   ");
30562306a36Sopenharmony_ci	for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
30662306a36Sopenharmony_ci		printk("%0*"PRI_xen_ulong"%s",
30762306a36Sopenharmony_ci		       (int)(sizeof(sh->evtchn_mask[0])*2),
30862306a36Sopenharmony_ci		       sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
30962306a36Sopenharmony_ci		       i % 8 == 0 ? "\n   " : " ");
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	printk("\nlocal cpu%d mask:\n   ", cpu);
31262306a36Sopenharmony_ci	for (i = (EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD)-1; i >= 0; i--)
31362306a36Sopenharmony_ci		printk("%0*"PRI_xen_ulong"%s", (int)(sizeof(cpu_evtchn[0])*2),
31462306a36Sopenharmony_ci		       cpu_evtchn[i],
31562306a36Sopenharmony_ci		       i % 8 == 0 ? "\n   " : " ");
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	printk("\nlocally unmasked:\n   ");
31862306a36Sopenharmony_ci	for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) {
31962306a36Sopenharmony_ci		xen_ulong_t pending = sh->evtchn_pending[i]
32062306a36Sopenharmony_ci			& ~sh->evtchn_mask[i]
32162306a36Sopenharmony_ci			& cpu_evtchn[i];
32262306a36Sopenharmony_ci		printk("%0*"PRI_xen_ulong"%s",
32362306a36Sopenharmony_ci		       (int)(sizeof(sh->evtchn_mask[0])*2),
32462306a36Sopenharmony_ci		       pending, i % 8 == 0 ? "\n   " : " ");
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	printk("\npending list:\n");
32862306a36Sopenharmony_ci	for (i = 0; i < EVTCHN_2L_NR_CHANNELS; i++) {
32962306a36Sopenharmony_ci		if (sync_test_bit(i, BM(sh->evtchn_pending))) {
33062306a36Sopenharmony_ci			int word_idx = i / BITS_PER_EVTCHN_WORD;
33162306a36Sopenharmony_ci			printk("  %d: event %d -> irq %u%s%s%s\n",
33262306a36Sopenharmony_ci			       cpu_from_evtchn(i), i,
33362306a36Sopenharmony_ci			       irq_from_evtchn(i),
33462306a36Sopenharmony_ci			       sync_test_bit(word_idx, BM(&v->evtchn_pending_sel))
33562306a36Sopenharmony_ci			       ? "" : " l2-clear",
33662306a36Sopenharmony_ci			       !sync_test_bit(i, BM(sh->evtchn_mask))
33762306a36Sopenharmony_ci			       ? "" : " globally-masked",
33862306a36Sopenharmony_ci			       sync_test_bit(i, BM(cpu_evtchn))
33962306a36Sopenharmony_ci			       ? "" : " locally-masked");
34062306a36Sopenharmony_ci		}
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	spin_unlock_irqrestore(&debug_lock, flags);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return IRQ_HANDLED;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic void evtchn_2l_resume(void)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	int i;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	for_each_online_cpu(i)
35362306a36Sopenharmony_ci		memset(per_cpu(cpu_evtchn_mask, i), 0, sizeof(xen_ulong_t) *
35462306a36Sopenharmony_ci				EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD);
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic int evtchn_2l_percpu_deinit(unsigned int cpu)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	memset(per_cpu(cpu_evtchn_mask, cpu), 0, sizeof(xen_ulong_t) *
36062306a36Sopenharmony_ci			EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return 0;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic const struct evtchn_ops evtchn_ops_2l = {
36662306a36Sopenharmony_ci	.max_channels      = evtchn_2l_max_channels,
36762306a36Sopenharmony_ci	.nr_channels       = evtchn_2l_max_channels,
36862306a36Sopenharmony_ci	.remove            = evtchn_2l_remove,
36962306a36Sopenharmony_ci	.bind_to_cpu       = evtchn_2l_bind_to_cpu,
37062306a36Sopenharmony_ci	.clear_pending     = evtchn_2l_clear_pending,
37162306a36Sopenharmony_ci	.set_pending       = evtchn_2l_set_pending,
37262306a36Sopenharmony_ci	.is_pending        = evtchn_2l_is_pending,
37362306a36Sopenharmony_ci	.mask              = evtchn_2l_mask,
37462306a36Sopenharmony_ci	.unmask            = evtchn_2l_unmask,
37562306a36Sopenharmony_ci	.handle_events     = evtchn_2l_handle_events,
37662306a36Sopenharmony_ci	.resume	           = evtchn_2l_resume,
37762306a36Sopenharmony_ci	.percpu_deinit     = evtchn_2l_percpu_deinit,
37862306a36Sopenharmony_ci};
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_civoid __init xen_evtchn_2l_init(void)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	pr_info("Using 2-level ABI\n");
38362306a36Sopenharmony_ci	evtchn_ops = &evtchn_ops_2l;
38462306a36Sopenharmony_ci}
385