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