18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Xen event channels (2-level ABI) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/linkage.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/irq.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <asm/sync_bitops.h> 158c2ecf20Sopenharmony_ci#include <asm/xen/hypercall.h> 168c2ecf20Sopenharmony_ci#include <asm/xen/hypervisor.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <xen/xen.h> 198c2ecf20Sopenharmony_ci#include <xen/xen-ops.h> 208c2ecf20Sopenharmony_ci#include <xen/events.h> 218c2ecf20Sopenharmony_ci#include <xen/interface/xen.h> 228c2ecf20Sopenharmony_ci#include <xen/interface/event_channel.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "events_internal.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * Note sizeof(xen_ulong_t) can be more than sizeof(unsigned long). Be 288c2ecf20Sopenharmony_ci * careful to only use bitops which allow for this (e.g 298c2ecf20Sopenharmony_ci * test_bit/find_first_bit and friends but not __ffs) and to pass 308c2ecf20Sopenharmony_ci * BITS_PER_EVTCHN_WORD as the bitmask length. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#define BITS_PER_EVTCHN_WORD (sizeof(xen_ulong_t)*8) 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * Make a bitmask (i.e. unsigned long *) of a xen_ulong_t 358c2ecf20Sopenharmony_ci * array. Primarily to avoid long lines (hence the terse name). 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci#define BM(x) (unsigned long *)(x) 388c2ecf20Sopenharmony_ci/* Find the first set bit in a evtchn mask */ 398c2ecf20Sopenharmony_ci#define EVTCHN_FIRST_BIT(w) find_first_bit(BM(&(w)), BITS_PER_EVTCHN_WORD) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define EVTCHN_MASK_SIZE (EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(xen_ulong_t [EVTCHN_MASK_SIZE], cpu_evtchn_mask); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic unsigned evtchn_2l_max_channels(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return EVTCHN_2L_NR_CHANNELS; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void evtchn_2l_remove(evtchn_port_t evtchn, unsigned int cpu) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci clear_bit(evtchn, BM(per_cpu(cpu_evtchn_mask, cpu))); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void evtchn_2l_bind_to_cpu(evtchn_port_t evtchn, unsigned int cpu, 568c2ecf20Sopenharmony_ci unsigned int old_cpu) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci clear_bit(evtchn, BM(per_cpu(cpu_evtchn_mask, old_cpu))); 598c2ecf20Sopenharmony_ci set_bit(evtchn, BM(per_cpu(cpu_evtchn_mask, cpu))); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void evtchn_2l_clear_pending(evtchn_port_t port) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct shared_info *s = HYPERVISOR_shared_info; 658c2ecf20Sopenharmony_ci sync_clear_bit(port, BM(&s->evtchn_pending[0])); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void evtchn_2l_set_pending(evtchn_port_t port) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct shared_info *s = HYPERVISOR_shared_info; 718c2ecf20Sopenharmony_ci sync_set_bit(port, BM(&s->evtchn_pending[0])); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic bool evtchn_2l_is_pending(evtchn_port_t port) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct shared_info *s = HYPERVISOR_shared_info; 778c2ecf20Sopenharmony_ci return sync_test_bit(port, BM(&s->evtchn_pending[0])); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void evtchn_2l_mask(evtchn_port_t port) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct shared_info *s = HYPERVISOR_shared_info; 838c2ecf20Sopenharmony_ci sync_set_bit(port, BM(&s->evtchn_mask[0])); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void evtchn_2l_unmask(evtchn_port_t port) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct shared_info *s = HYPERVISOR_shared_info; 898c2ecf20Sopenharmony_ci unsigned int cpu = get_cpu(); 908c2ecf20Sopenharmony_ci int do_hypercall = 0, evtchn_pending = 0; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci BUG_ON(!irqs_disabled()); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci smp_wmb(); /* All writes before unmask must be visible. */ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (unlikely((cpu != cpu_from_evtchn(port)))) 978c2ecf20Sopenharmony_ci do_hypercall = 1; 988c2ecf20Sopenharmony_ci else { 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * Need to clear the mask before checking pending to 1018c2ecf20Sopenharmony_ci * avoid a race with an event becoming pending. 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * EVTCHNOP_unmask will only trigger an upcall if the 1048c2ecf20Sopenharmony_ci * mask bit was set, so if a hypercall is needed 1058c2ecf20Sopenharmony_ci * remask the event. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci sync_clear_bit(port, BM(&s->evtchn_mask[0])); 1088c2ecf20Sopenharmony_ci evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0])); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (unlikely(evtchn_pending && xen_hvm_domain())) { 1118c2ecf20Sopenharmony_ci sync_set_bit(port, BM(&s->evtchn_mask[0])); 1128c2ecf20Sopenharmony_ci do_hypercall = 1; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* Slow path (hypercall) if this is a non-local port or if this is 1178c2ecf20Sopenharmony_ci * an hvm domain and an event is pending (hvm domains don't have 1188c2ecf20Sopenharmony_ci * their own implementation of irq_enable). */ 1198c2ecf20Sopenharmony_ci if (do_hypercall) { 1208c2ecf20Sopenharmony_ci struct evtchn_unmask unmask = { .port = port }; 1218c2ecf20Sopenharmony_ci (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask); 1228c2ecf20Sopenharmony_ci } else { 1238c2ecf20Sopenharmony_ci struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* 1268c2ecf20Sopenharmony_ci * The following is basically the equivalent of 1278c2ecf20Sopenharmony_ci * 'hw_resend_irq'. Just like a real IO-APIC we 'lose 1288c2ecf20Sopenharmony_ci * the interrupt edge' if the channel is masked. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci if (evtchn_pending && 1318c2ecf20Sopenharmony_ci !sync_test_and_set_bit(port / BITS_PER_EVTCHN_WORD, 1328c2ecf20Sopenharmony_ci BM(&vcpu_info->evtchn_pending_sel))) 1338c2ecf20Sopenharmony_ci vcpu_info->evtchn_upcall_pending = 1; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci put_cpu(); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(unsigned int, current_word_idx); 1408c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(unsigned int, current_bit_idx); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* 1438c2ecf20Sopenharmony_ci * Mask out the i least significant bits of w 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci#define MASK_LSBS(w, i) (w & ((~((xen_ulong_t)0UL)) << i)) 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic inline xen_ulong_t active_evtchns(unsigned int cpu, 1488c2ecf20Sopenharmony_ci struct shared_info *sh, 1498c2ecf20Sopenharmony_ci unsigned int idx) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci return sh->evtchn_pending[idx] & 1528c2ecf20Sopenharmony_ci per_cpu(cpu_evtchn_mask, cpu)[idx] & 1538c2ecf20Sopenharmony_ci ~sh->evtchn_mask[idx]; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* 1578c2ecf20Sopenharmony_ci * Search the CPU's pending events bitmasks. For each one found, map 1588c2ecf20Sopenharmony_ci * the event number to an irq, and feed it into do_IRQ() for handling. 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * Xen uses a two-level bitmap to speed searching. The first level is 1618c2ecf20Sopenharmony_ci * a bitset of words which contain pending event bits. The second 1628c2ecf20Sopenharmony_ci * level is a bitset of pending events themselves. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_cistatic void evtchn_2l_handle_events(unsigned cpu, struct evtchn_loop_ctrl *ctrl) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci int irq; 1678c2ecf20Sopenharmony_ci xen_ulong_t pending_words; 1688c2ecf20Sopenharmony_ci xen_ulong_t pending_bits; 1698c2ecf20Sopenharmony_ci int start_word_idx, start_bit_idx; 1708c2ecf20Sopenharmony_ci int word_idx, bit_idx; 1718c2ecf20Sopenharmony_ci int i; 1728c2ecf20Sopenharmony_ci struct shared_info *s = HYPERVISOR_shared_info; 1738c2ecf20Sopenharmony_ci struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Timer interrupt has highest priority. */ 1768c2ecf20Sopenharmony_ci irq = irq_from_virq(cpu, VIRQ_TIMER); 1778c2ecf20Sopenharmony_ci if (irq != -1) { 1788c2ecf20Sopenharmony_ci evtchn_port_t evtchn = evtchn_from_irq(irq); 1798c2ecf20Sopenharmony_ci word_idx = evtchn / BITS_PER_LONG; 1808c2ecf20Sopenharmony_ci bit_idx = evtchn % BITS_PER_LONG; 1818c2ecf20Sopenharmony_ci if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx)) 1828c2ecf20Sopenharmony_ci generic_handle_irq(irq); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * Master flag must be cleared /before/ clearing 1878c2ecf20Sopenharmony_ci * selector flag. xchg_xen_ulong must contain an 1888c2ecf20Sopenharmony_ci * appropriate barrier. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci pending_words = xchg_xen_ulong(&vcpu_info->evtchn_pending_sel, 0); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci start_word_idx = __this_cpu_read(current_word_idx); 1938c2ecf20Sopenharmony_ci start_bit_idx = __this_cpu_read(current_bit_idx); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci word_idx = start_word_idx; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci for (i = 0; pending_words != 0; i++) { 1988c2ecf20Sopenharmony_ci xen_ulong_t words; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci words = MASK_LSBS(pending_words, word_idx); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * If we masked out all events, wrap to beginning. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci if (words == 0) { 2068c2ecf20Sopenharmony_ci word_idx = 0; 2078c2ecf20Sopenharmony_ci bit_idx = 0; 2088c2ecf20Sopenharmony_ci continue; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci word_idx = EVTCHN_FIRST_BIT(words); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci pending_bits = active_evtchns(cpu, s, word_idx); 2138c2ecf20Sopenharmony_ci bit_idx = 0; /* usually scan entire word from start */ 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * We scan the starting word in two parts. 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * 1st time: start in the middle, scanning the 2188c2ecf20Sopenharmony_ci * upper bits. 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * 2nd time: scan the whole word (not just the 2218c2ecf20Sopenharmony_ci * parts skipped in the first pass) -- if an 2228c2ecf20Sopenharmony_ci * event in the previously scanned bits is 2238c2ecf20Sopenharmony_ci * pending again it would just be scanned on 2248c2ecf20Sopenharmony_ci * the next loop anyway. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci if (word_idx == start_word_idx) { 2278c2ecf20Sopenharmony_ci if (i == 0) 2288c2ecf20Sopenharmony_ci bit_idx = start_bit_idx; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci do { 2328c2ecf20Sopenharmony_ci xen_ulong_t bits; 2338c2ecf20Sopenharmony_ci evtchn_port_t port; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci bits = MASK_LSBS(pending_bits, bit_idx); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* If we masked out all events, move on. */ 2388c2ecf20Sopenharmony_ci if (bits == 0) 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci bit_idx = EVTCHN_FIRST_BIT(bits); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Process port. */ 2448c2ecf20Sopenharmony_ci port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx; 2458c2ecf20Sopenharmony_ci handle_irq_for_port(port, ctrl); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci bit_idx = (bit_idx + 1) % BITS_PER_EVTCHN_WORD; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* Next caller starts at last processed + 1 */ 2508c2ecf20Sopenharmony_ci __this_cpu_write(current_word_idx, 2518c2ecf20Sopenharmony_ci bit_idx ? word_idx : 2528c2ecf20Sopenharmony_ci (word_idx+1) % BITS_PER_EVTCHN_WORD); 2538c2ecf20Sopenharmony_ci __this_cpu_write(current_bit_idx, bit_idx); 2548c2ecf20Sopenharmony_ci } while (bit_idx != 0); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* Scan start_l1i twice; all others once. */ 2578c2ecf20Sopenharmony_ci if ((word_idx != start_word_idx) || (i != 0)) 2588c2ecf20Sopenharmony_ci pending_words &= ~(1UL << word_idx); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci word_idx = (word_idx + 1) % BITS_PER_EVTCHN_WORD; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciirqreturn_t xen_debug_interrupt(int irq, void *dev_id) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct shared_info *sh = HYPERVISOR_shared_info; 2678c2ecf20Sopenharmony_ci int cpu = smp_processor_id(); 2688c2ecf20Sopenharmony_ci xen_ulong_t *cpu_evtchn = per_cpu(cpu_evtchn_mask, cpu); 2698c2ecf20Sopenharmony_ci int i; 2708c2ecf20Sopenharmony_ci unsigned long flags; 2718c2ecf20Sopenharmony_ci static DEFINE_SPINLOCK(debug_lock); 2728c2ecf20Sopenharmony_ci struct vcpu_info *v; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci spin_lock_irqsave(&debug_lock, flags); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci printk("\nvcpu %d\n ", cpu); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci for_each_online_cpu(i) { 2798c2ecf20Sopenharmony_ci int pending; 2808c2ecf20Sopenharmony_ci v = per_cpu(xen_vcpu, i); 2818c2ecf20Sopenharmony_ci pending = (get_irq_regs() && i == cpu) 2828c2ecf20Sopenharmony_ci ? xen_irqs_disabled(get_irq_regs()) 2838c2ecf20Sopenharmony_ci : v->evtchn_upcall_mask; 2848c2ecf20Sopenharmony_ci printk("%d: masked=%d pending=%d event_sel %0*"PRI_xen_ulong"\n ", i, 2858c2ecf20Sopenharmony_ci pending, v->evtchn_upcall_pending, 2868c2ecf20Sopenharmony_ci (int)(sizeof(v->evtchn_pending_sel)*2), 2878c2ecf20Sopenharmony_ci v->evtchn_pending_sel); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci v = per_cpu(xen_vcpu, cpu); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci printk("\npending:\n "); 2928c2ecf20Sopenharmony_ci for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--) 2938c2ecf20Sopenharmony_ci printk("%0*"PRI_xen_ulong"%s", 2948c2ecf20Sopenharmony_ci (int)sizeof(sh->evtchn_pending[0])*2, 2958c2ecf20Sopenharmony_ci sh->evtchn_pending[i], 2968c2ecf20Sopenharmony_ci i % 8 == 0 ? "\n " : " "); 2978c2ecf20Sopenharmony_ci printk("\nglobal mask:\n "); 2988c2ecf20Sopenharmony_ci for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) 2998c2ecf20Sopenharmony_ci printk("%0*"PRI_xen_ulong"%s", 3008c2ecf20Sopenharmony_ci (int)(sizeof(sh->evtchn_mask[0])*2), 3018c2ecf20Sopenharmony_ci sh->evtchn_mask[i], 3028c2ecf20Sopenharmony_ci i % 8 == 0 ? "\n " : " "); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci printk("\nglobally unmasked:\n "); 3058c2ecf20Sopenharmony_ci for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) 3068c2ecf20Sopenharmony_ci printk("%0*"PRI_xen_ulong"%s", 3078c2ecf20Sopenharmony_ci (int)(sizeof(sh->evtchn_mask[0])*2), 3088c2ecf20Sopenharmony_ci sh->evtchn_pending[i] & ~sh->evtchn_mask[i], 3098c2ecf20Sopenharmony_ci i % 8 == 0 ? "\n " : " "); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci printk("\nlocal cpu%d mask:\n ", cpu); 3128c2ecf20Sopenharmony_ci for (i = (EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD)-1; i >= 0; i--) 3138c2ecf20Sopenharmony_ci printk("%0*"PRI_xen_ulong"%s", (int)(sizeof(cpu_evtchn[0])*2), 3148c2ecf20Sopenharmony_ci cpu_evtchn[i], 3158c2ecf20Sopenharmony_ci i % 8 == 0 ? "\n " : " "); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci printk("\nlocally unmasked:\n "); 3188c2ecf20Sopenharmony_ci for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) { 3198c2ecf20Sopenharmony_ci xen_ulong_t pending = sh->evtchn_pending[i] 3208c2ecf20Sopenharmony_ci & ~sh->evtchn_mask[i] 3218c2ecf20Sopenharmony_ci & cpu_evtchn[i]; 3228c2ecf20Sopenharmony_ci printk("%0*"PRI_xen_ulong"%s", 3238c2ecf20Sopenharmony_ci (int)(sizeof(sh->evtchn_mask[0])*2), 3248c2ecf20Sopenharmony_ci pending, i % 8 == 0 ? "\n " : " "); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci printk("\npending list:\n"); 3288c2ecf20Sopenharmony_ci for (i = 0; i < EVTCHN_2L_NR_CHANNELS; i++) { 3298c2ecf20Sopenharmony_ci if (sync_test_bit(i, BM(sh->evtchn_pending))) { 3308c2ecf20Sopenharmony_ci int word_idx = i / BITS_PER_EVTCHN_WORD; 3318c2ecf20Sopenharmony_ci printk(" %d: event %d -> irq %d%s%s%s\n", 3328c2ecf20Sopenharmony_ci cpu_from_evtchn(i), i, 3338c2ecf20Sopenharmony_ci get_evtchn_to_irq(i), 3348c2ecf20Sopenharmony_ci sync_test_bit(word_idx, BM(&v->evtchn_pending_sel)) 3358c2ecf20Sopenharmony_ci ? "" : " l2-clear", 3368c2ecf20Sopenharmony_ci !sync_test_bit(i, BM(sh->evtchn_mask)) 3378c2ecf20Sopenharmony_ci ? "" : " globally-masked", 3388c2ecf20Sopenharmony_ci sync_test_bit(i, BM(cpu_evtchn)) 3398c2ecf20Sopenharmony_ci ? "" : " locally-masked"); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&debug_lock, flags); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic void evtchn_2l_resume(void) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci int i; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci for_each_online_cpu(i) 3538c2ecf20Sopenharmony_ci memset(per_cpu(cpu_evtchn_mask, i), 0, sizeof(xen_ulong_t) * 3548c2ecf20Sopenharmony_ci EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int evtchn_2l_percpu_deinit(unsigned int cpu) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci memset(per_cpu(cpu_evtchn_mask, cpu), 0, sizeof(xen_ulong_t) * 3608c2ecf20Sopenharmony_ci EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic const struct evtchn_ops evtchn_ops_2l = { 3668c2ecf20Sopenharmony_ci .max_channels = evtchn_2l_max_channels, 3678c2ecf20Sopenharmony_ci .nr_channels = evtchn_2l_max_channels, 3688c2ecf20Sopenharmony_ci .remove = evtchn_2l_remove, 3698c2ecf20Sopenharmony_ci .bind_to_cpu = evtchn_2l_bind_to_cpu, 3708c2ecf20Sopenharmony_ci .clear_pending = evtchn_2l_clear_pending, 3718c2ecf20Sopenharmony_ci .set_pending = evtchn_2l_set_pending, 3728c2ecf20Sopenharmony_ci .is_pending = evtchn_2l_is_pending, 3738c2ecf20Sopenharmony_ci .mask = evtchn_2l_mask, 3748c2ecf20Sopenharmony_ci .unmask = evtchn_2l_unmask, 3758c2ecf20Sopenharmony_ci .handle_events = evtchn_2l_handle_events, 3768c2ecf20Sopenharmony_ci .resume = evtchn_2l_resume, 3778c2ecf20Sopenharmony_ci .percpu_deinit = evtchn_2l_percpu_deinit, 3788c2ecf20Sopenharmony_ci}; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_civoid __init xen_evtchn_2l_init(void) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci pr_info("Using 2-level ABI\n"); 3838c2ecf20Sopenharmony_ci evtchn_ops = &evtchn_ops_2l; 3848c2ecf20Sopenharmony_ci} 385