1bc5ad3f3SBenjamin Herrenschmidt /* 2bc5ad3f3SBenjamin Herrenschmidt * Copyright 2012 Michael Ellerman, IBM Corporation. 3bc5ad3f3SBenjamin Herrenschmidt * Copyright 2012 Benjamin Herrenschmidt, IBM Corporation. 4bc5ad3f3SBenjamin Herrenschmidt * 5bc5ad3f3SBenjamin Herrenschmidt * This program is free software; you can redistribute it and/or modify 6bc5ad3f3SBenjamin Herrenschmidt * it under the terms of the GNU General Public License, version 2, as 7bc5ad3f3SBenjamin Herrenschmidt * published by the Free Software Foundation. 8bc5ad3f3SBenjamin Herrenschmidt */ 9bc5ad3f3SBenjamin Herrenschmidt 10bc5ad3f3SBenjamin Herrenschmidt #include <linux/kernel.h> 11bc5ad3f3SBenjamin Herrenschmidt #include <linux/kvm_host.h> 12bc5ad3f3SBenjamin Herrenschmidt #include <linux/err.h> 13bc5ad3f3SBenjamin Herrenschmidt #include <linux/gfp.h> 145975a2e0SPaul Mackerras #include <linux/anon_inodes.h> 15433c5c20SMichael Ellerman #include <linux/spinlock.h> 16bc5ad3f3SBenjamin Herrenschmidt 177c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 18bc5ad3f3SBenjamin Herrenschmidt #include <asm/kvm_book3s.h> 19bc5ad3f3SBenjamin Herrenschmidt #include <asm/kvm_ppc.h> 20bc5ad3f3SBenjamin Herrenschmidt #include <asm/hvcall.h> 21bc5ad3f3SBenjamin Herrenschmidt #include <asm/xics.h> 22bc5ad3f3SBenjamin Herrenschmidt #include <asm/debug.h> 237bfa9ad5SPaul Mackerras #include <asm/time.h> 24bc5ad3f3SBenjamin Herrenschmidt 25bc5ad3f3SBenjamin Herrenschmidt #include <linux/debugfs.h> 26bc5ad3f3SBenjamin Herrenschmidt #include <linux/seq_file.h> 27bc5ad3f3SBenjamin Herrenschmidt 28bc5ad3f3SBenjamin Herrenschmidt #include "book3s_xics.h" 29bc5ad3f3SBenjamin Herrenschmidt 30bc5ad3f3SBenjamin Herrenschmidt #if 1 31bc5ad3f3SBenjamin Herrenschmidt #define XICS_DBG(fmt...) do { } while (0) 32bc5ad3f3SBenjamin Herrenschmidt #else 33bc5ad3f3SBenjamin Herrenschmidt #define XICS_DBG(fmt...) trace_printk(fmt) 34bc5ad3f3SBenjamin Herrenschmidt #endif 35bc5ad3f3SBenjamin Herrenschmidt 36e7d26f28SBenjamin Herrenschmidt #define ENABLE_REALMODE true 37e7d26f28SBenjamin Herrenschmidt #define DEBUG_REALMODE false 38e7d26f28SBenjamin Herrenschmidt 39bc5ad3f3SBenjamin Herrenschmidt /* 40bc5ad3f3SBenjamin Herrenschmidt * LOCKING 41bc5ad3f3SBenjamin Herrenschmidt * ======= 42bc5ad3f3SBenjamin Herrenschmidt * 4334cb7954SSuresh Warrier * Each ICS has a spin lock protecting the information about the IRQ 444e33d1f0SGreg Kurz * sources and avoiding simultaneous deliveries of the same interrupt. 45bc5ad3f3SBenjamin Herrenschmidt * 46bc5ad3f3SBenjamin Herrenschmidt * ICP operations are done via a single compare & swap transaction 47bc5ad3f3SBenjamin Herrenschmidt * (most ICP state fits in the union kvmppc_icp_state) 48bc5ad3f3SBenjamin Herrenschmidt */ 49bc5ad3f3SBenjamin Herrenschmidt 50bc5ad3f3SBenjamin Herrenschmidt /* 51bc5ad3f3SBenjamin Herrenschmidt * TODO 52bc5ad3f3SBenjamin Herrenschmidt * ==== 53bc5ad3f3SBenjamin Herrenschmidt * 54bc5ad3f3SBenjamin Herrenschmidt * - To speed up resends, keep a bitmap of "resend" set bits in the 55bc5ad3f3SBenjamin Herrenschmidt * ICS 56bc5ad3f3SBenjamin Herrenschmidt * 57bc5ad3f3SBenjamin Herrenschmidt * - Speed up server# -> ICP lookup (array ? hash table ?) 58bc5ad3f3SBenjamin Herrenschmidt * 59bc5ad3f3SBenjamin Herrenschmidt * - Make ICS lockless as well, or at least a per-interrupt lock or hashed 60bc5ad3f3SBenjamin Herrenschmidt * locks array to improve scalability 61bc5ad3f3SBenjamin Herrenschmidt */ 62bc5ad3f3SBenjamin Herrenschmidt 63bc5ad3f3SBenjamin Herrenschmidt /* -- ICS routines -- */ 64bc5ad3f3SBenjamin Herrenschmidt 65bc5ad3f3SBenjamin Herrenschmidt static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, 66bc5ad3f3SBenjamin Herrenschmidt u32 new_irq); 67bc5ad3f3SBenjamin Herrenschmidt 6825a2150bSPaul Mackerras /* 6925a2150bSPaul Mackerras * Return value ideally indicates how the interrupt was handled, but no 7025a2150bSPaul Mackerras * callers look at it (given that we don't implement KVM_IRQ_LINE_STATUS), 7125a2150bSPaul Mackerras * so just return 0. 7225a2150bSPaul Mackerras */ 7325a2150bSPaul Mackerras static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level) 74bc5ad3f3SBenjamin Herrenschmidt { 75bc5ad3f3SBenjamin Herrenschmidt struct ics_irq_state *state; 76bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_ics *ics; 77bc5ad3f3SBenjamin Herrenschmidt u16 src; 78bc5ad3f3SBenjamin Herrenschmidt 79bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("ics deliver %#x (level: %d)\n", irq, level); 80bc5ad3f3SBenjamin Herrenschmidt 81bc5ad3f3SBenjamin Herrenschmidt ics = kvmppc_xics_find_ics(xics, irq, &src); 82bc5ad3f3SBenjamin Herrenschmidt if (!ics) { 83bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("ics_deliver_irq: IRQ 0x%06x not found !\n", irq); 84bc5ad3f3SBenjamin Herrenschmidt return -EINVAL; 85bc5ad3f3SBenjamin Herrenschmidt } 86bc5ad3f3SBenjamin Herrenschmidt state = &ics->irq_state[src]; 87bc5ad3f3SBenjamin Herrenschmidt if (!state->exists) 88bc5ad3f3SBenjamin Herrenschmidt return -EINVAL; 89bc5ad3f3SBenjamin Herrenschmidt 90bc5ad3f3SBenjamin Herrenschmidt /* 91bc5ad3f3SBenjamin Herrenschmidt * We set state->asserted locklessly. This should be fine as 92bc5ad3f3SBenjamin Herrenschmidt * we are the only setter, thus concurrent access is undefined 93bc5ad3f3SBenjamin Herrenschmidt * to begin with. 94bc5ad3f3SBenjamin Herrenschmidt */ 95b1a4286bSPaul Mackerras if ((level == 1 && state->lsi) || level == KVM_INTERRUPT_SET_LEVEL) 96bc5ad3f3SBenjamin Herrenschmidt state->asserted = 1; 9725a2150bSPaul Mackerras else if (level == 0 || level == KVM_INTERRUPT_UNSET) { 98bc5ad3f3SBenjamin Herrenschmidt state->asserted = 0; 99bc5ad3f3SBenjamin Herrenschmidt return 0; 100bc5ad3f3SBenjamin Herrenschmidt } 101bc5ad3f3SBenjamin Herrenschmidt 1025d375199SPaul Mackerras /* Record which CPU this arrived on for passed-through interrupts */ 1035d375199SPaul Mackerras if (state->host_irq) 1045d375199SPaul Mackerras state->intr_cpu = raw_smp_processor_id(); 1055d375199SPaul Mackerras 106bc5ad3f3SBenjamin Herrenschmidt /* Attempt delivery */ 107bc5ad3f3SBenjamin Herrenschmidt icp_deliver_irq(xics, NULL, irq); 108bc5ad3f3SBenjamin Herrenschmidt 10925a2150bSPaul Mackerras return 0; 110bc5ad3f3SBenjamin Herrenschmidt } 111bc5ad3f3SBenjamin Herrenschmidt 112bc5ad3f3SBenjamin Herrenschmidt static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics, 113bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_icp *icp) 114bc5ad3f3SBenjamin Herrenschmidt { 115bc5ad3f3SBenjamin Herrenschmidt int i; 116bc5ad3f3SBenjamin Herrenschmidt 11734cb7954SSuresh Warrier unsigned long flags; 11834cb7954SSuresh Warrier 11934cb7954SSuresh Warrier local_irq_save(flags); 12034cb7954SSuresh Warrier arch_spin_lock(&ics->lock); 121bc5ad3f3SBenjamin Herrenschmidt 122bc5ad3f3SBenjamin Herrenschmidt for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) { 123bc5ad3f3SBenjamin Herrenschmidt struct ics_irq_state *state = &ics->irq_state[i]; 124bc5ad3f3SBenjamin Herrenschmidt 125bc5ad3f3SBenjamin Herrenschmidt if (!state->resend) 126bc5ad3f3SBenjamin Herrenschmidt continue; 127bc5ad3f3SBenjamin Herrenschmidt 128*bf5a71d5SLi Zhong state->resend = 0; 129*bf5a71d5SLi Zhong 130bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("resend %#x prio %#x\n", state->number, 131bc5ad3f3SBenjamin Herrenschmidt state->priority); 132bc5ad3f3SBenjamin Herrenschmidt 13334cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 13434cb7954SSuresh Warrier local_irq_restore(flags); 135bc5ad3f3SBenjamin Herrenschmidt icp_deliver_irq(xics, icp, state->number); 13634cb7954SSuresh Warrier local_irq_save(flags); 13734cb7954SSuresh Warrier arch_spin_lock(&ics->lock); 138bc5ad3f3SBenjamin Herrenschmidt } 139bc5ad3f3SBenjamin Herrenschmidt 14034cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 14134cb7954SSuresh Warrier local_irq_restore(flags); 142bc5ad3f3SBenjamin Herrenschmidt } 143bc5ad3f3SBenjamin Herrenschmidt 144d19bd862SPaul Mackerras static bool write_xive(struct kvmppc_xics *xics, struct kvmppc_ics *ics, 145d19bd862SPaul Mackerras struct ics_irq_state *state, 146d19bd862SPaul Mackerras u32 server, u32 priority, u32 saved_priority) 147d19bd862SPaul Mackerras { 148d19bd862SPaul Mackerras bool deliver; 14934cb7954SSuresh Warrier unsigned long flags; 150d19bd862SPaul Mackerras 15134cb7954SSuresh Warrier local_irq_save(flags); 15234cb7954SSuresh Warrier arch_spin_lock(&ics->lock); 153d19bd862SPaul Mackerras 154d19bd862SPaul Mackerras state->server = server; 155d19bd862SPaul Mackerras state->priority = priority; 156d19bd862SPaul Mackerras state->saved_priority = saved_priority; 157d19bd862SPaul Mackerras deliver = false; 158d19bd862SPaul Mackerras if ((state->masked_pending || state->resend) && priority != MASKED) { 159d19bd862SPaul Mackerras state->masked_pending = 0; 160*bf5a71d5SLi Zhong state->resend = 0; 161d19bd862SPaul Mackerras deliver = true; 162d19bd862SPaul Mackerras } 163d19bd862SPaul Mackerras 16434cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 16534cb7954SSuresh Warrier local_irq_restore(flags); 166d19bd862SPaul Mackerras 167d19bd862SPaul Mackerras return deliver; 168d19bd862SPaul Mackerras } 169d19bd862SPaul Mackerras 170bc5ad3f3SBenjamin Herrenschmidt int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) 171bc5ad3f3SBenjamin Herrenschmidt { 172bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_xics *xics = kvm->arch.xics; 173bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_icp *icp; 174bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_ics *ics; 175bc5ad3f3SBenjamin Herrenschmidt struct ics_irq_state *state; 176bc5ad3f3SBenjamin Herrenschmidt u16 src; 177bc5ad3f3SBenjamin Herrenschmidt 178bc5ad3f3SBenjamin Herrenschmidt if (!xics) 179bc5ad3f3SBenjamin Herrenschmidt return -ENODEV; 180bc5ad3f3SBenjamin Herrenschmidt 181bc5ad3f3SBenjamin Herrenschmidt ics = kvmppc_xics_find_ics(xics, irq, &src); 182bc5ad3f3SBenjamin Herrenschmidt if (!ics) 183bc5ad3f3SBenjamin Herrenschmidt return -EINVAL; 184bc5ad3f3SBenjamin Herrenschmidt state = &ics->irq_state[src]; 185bc5ad3f3SBenjamin Herrenschmidt 186bc5ad3f3SBenjamin Herrenschmidt icp = kvmppc_xics_find_server(kvm, server); 187bc5ad3f3SBenjamin Herrenschmidt if (!icp) 188bc5ad3f3SBenjamin Herrenschmidt return -EINVAL; 189bc5ad3f3SBenjamin Herrenschmidt 190bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("set_xive %#x server %#x prio %#x MP:%d RS:%d\n", 191bc5ad3f3SBenjamin Herrenschmidt irq, server, priority, 192bc5ad3f3SBenjamin Herrenschmidt state->masked_pending, state->resend); 193bc5ad3f3SBenjamin Herrenschmidt 194d19bd862SPaul Mackerras if (write_xive(xics, ics, state, server, priority, priority)) 195bc5ad3f3SBenjamin Herrenschmidt icp_deliver_irq(xics, icp, irq); 196bc5ad3f3SBenjamin Herrenschmidt 197bc5ad3f3SBenjamin Herrenschmidt return 0; 198bc5ad3f3SBenjamin Herrenschmidt } 199bc5ad3f3SBenjamin Herrenschmidt 200bc5ad3f3SBenjamin Herrenschmidt int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, u32 *priority) 201bc5ad3f3SBenjamin Herrenschmidt { 202bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_xics *xics = kvm->arch.xics; 203bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_ics *ics; 204bc5ad3f3SBenjamin Herrenschmidt struct ics_irq_state *state; 205bc5ad3f3SBenjamin Herrenschmidt u16 src; 20634cb7954SSuresh Warrier unsigned long flags; 207bc5ad3f3SBenjamin Herrenschmidt 208bc5ad3f3SBenjamin Herrenschmidt if (!xics) 209bc5ad3f3SBenjamin Herrenschmidt return -ENODEV; 210bc5ad3f3SBenjamin Herrenschmidt 211bc5ad3f3SBenjamin Herrenschmidt ics = kvmppc_xics_find_ics(xics, irq, &src); 212bc5ad3f3SBenjamin Herrenschmidt if (!ics) 213bc5ad3f3SBenjamin Herrenschmidt return -EINVAL; 214bc5ad3f3SBenjamin Herrenschmidt state = &ics->irq_state[src]; 215bc5ad3f3SBenjamin Herrenschmidt 21634cb7954SSuresh Warrier local_irq_save(flags); 21734cb7954SSuresh Warrier arch_spin_lock(&ics->lock); 218bc5ad3f3SBenjamin Herrenschmidt *server = state->server; 219bc5ad3f3SBenjamin Herrenschmidt *priority = state->priority; 22034cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 22134cb7954SSuresh Warrier local_irq_restore(flags); 222bc5ad3f3SBenjamin Herrenschmidt 223bc5ad3f3SBenjamin Herrenschmidt return 0; 224bc5ad3f3SBenjamin Herrenschmidt } 225bc5ad3f3SBenjamin Herrenschmidt 226d19bd862SPaul Mackerras int kvmppc_xics_int_on(struct kvm *kvm, u32 irq) 227d19bd862SPaul Mackerras { 228d19bd862SPaul Mackerras struct kvmppc_xics *xics = kvm->arch.xics; 229d19bd862SPaul Mackerras struct kvmppc_icp *icp; 230d19bd862SPaul Mackerras struct kvmppc_ics *ics; 231d19bd862SPaul Mackerras struct ics_irq_state *state; 232d19bd862SPaul Mackerras u16 src; 233d19bd862SPaul Mackerras 234d19bd862SPaul Mackerras if (!xics) 235d19bd862SPaul Mackerras return -ENODEV; 236d19bd862SPaul Mackerras 237d19bd862SPaul Mackerras ics = kvmppc_xics_find_ics(xics, irq, &src); 238d19bd862SPaul Mackerras if (!ics) 239d19bd862SPaul Mackerras return -EINVAL; 240d19bd862SPaul Mackerras state = &ics->irq_state[src]; 241d19bd862SPaul Mackerras 242d19bd862SPaul Mackerras icp = kvmppc_xics_find_server(kvm, state->server); 243d19bd862SPaul Mackerras if (!icp) 244d19bd862SPaul Mackerras return -EINVAL; 245d19bd862SPaul Mackerras 246d19bd862SPaul Mackerras if (write_xive(xics, ics, state, state->server, state->saved_priority, 247d19bd862SPaul Mackerras state->saved_priority)) 248d19bd862SPaul Mackerras icp_deliver_irq(xics, icp, irq); 249d19bd862SPaul Mackerras 250d19bd862SPaul Mackerras return 0; 251d19bd862SPaul Mackerras } 252d19bd862SPaul Mackerras 253d19bd862SPaul Mackerras int kvmppc_xics_int_off(struct kvm *kvm, u32 irq) 254d19bd862SPaul Mackerras { 255d19bd862SPaul Mackerras struct kvmppc_xics *xics = kvm->arch.xics; 256d19bd862SPaul Mackerras struct kvmppc_ics *ics; 257d19bd862SPaul Mackerras struct ics_irq_state *state; 258d19bd862SPaul Mackerras u16 src; 259d19bd862SPaul Mackerras 260d19bd862SPaul Mackerras if (!xics) 261d19bd862SPaul Mackerras return -ENODEV; 262d19bd862SPaul Mackerras 263d19bd862SPaul Mackerras ics = kvmppc_xics_find_ics(xics, irq, &src); 264d19bd862SPaul Mackerras if (!ics) 265d19bd862SPaul Mackerras return -EINVAL; 266d19bd862SPaul Mackerras state = &ics->irq_state[src]; 267d19bd862SPaul Mackerras 268d19bd862SPaul Mackerras write_xive(xics, ics, state, state->server, MASKED, state->priority); 269d19bd862SPaul Mackerras 270d19bd862SPaul Mackerras return 0; 271d19bd862SPaul Mackerras } 272d19bd862SPaul Mackerras 273bc5ad3f3SBenjamin Herrenschmidt /* -- ICP routines, including hcalls -- */ 274bc5ad3f3SBenjamin Herrenschmidt 275bc5ad3f3SBenjamin Herrenschmidt static inline bool icp_try_update(struct kvmppc_icp *icp, 276bc5ad3f3SBenjamin Herrenschmidt union kvmppc_icp_state old, 277bc5ad3f3SBenjamin Herrenschmidt union kvmppc_icp_state new, 278bc5ad3f3SBenjamin Herrenschmidt bool change_self) 279bc5ad3f3SBenjamin Herrenschmidt { 280bc5ad3f3SBenjamin Herrenschmidt bool success; 281bc5ad3f3SBenjamin Herrenschmidt 282bc5ad3f3SBenjamin Herrenschmidt /* Calculate new output value */ 283bc5ad3f3SBenjamin Herrenschmidt new.out_ee = (new.xisr && (new.pending_pri < new.cppr)); 284bc5ad3f3SBenjamin Herrenschmidt 285bc5ad3f3SBenjamin Herrenschmidt /* Attempt atomic update */ 286bc5ad3f3SBenjamin Herrenschmidt success = cmpxchg64(&icp->state.raw, old.raw, new.raw) == old.raw; 287bc5ad3f3SBenjamin Herrenschmidt if (!success) 288bc5ad3f3SBenjamin Herrenschmidt goto bail; 289bc5ad3f3SBenjamin Herrenschmidt 290ade3ac66SAlexey Kardashevskiy XICS_DBG("UPD [%04lx] - C:%02x M:%02x PP: %02x PI:%06x R:%d O:%d\n", 291bc5ad3f3SBenjamin Herrenschmidt icp->server_num, 292bc5ad3f3SBenjamin Herrenschmidt old.cppr, old.mfrr, old.pending_pri, old.xisr, 293bc5ad3f3SBenjamin Herrenschmidt old.need_resend, old.out_ee); 294bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("UPD - C:%02x M:%02x PP: %02x PI:%06x R:%d O:%d\n", 295bc5ad3f3SBenjamin Herrenschmidt new.cppr, new.mfrr, new.pending_pri, new.xisr, 296bc5ad3f3SBenjamin Herrenschmidt new.need_resend, new.out_ee); 297bc5ad3f3SBenjamin Herrenschmidt /* 298bc5ad3f3SBenjamin Herrenschmidt * Check for output state update 299bc5ad3f3SBenjamin Herrenschmidt * 300bc5ad3f3SBenjamin Herrenschmidt * Note that this is racy since another processor could be updating 301bc5ad3f3SBenjamin Herrenschmidt * the state already. This is why we never clear the interrupt output 302bc5ad3f3SBenjamin Herrenschmidt * here, we only ever set it. The clear only happens prior to doing 303bc5ad3f3SBenjamin Herrenschmidt * an update and only by the processor itself. Currently we do it 304bc5ad3f3SBenjamin Herrenschmidt * in Accept (H_XIRR) and Up_Cppr (H_XPPR). 305bc5ad3f3SBenjamin Herrenschmidt * 306bc5ad3f3SBenjamin Herrenschmidt * We also do not try to figure out whether the EE state has changed, 307e7d26f28SBenjamin Herrenschmidt * we unconditionally set it if the new state calls for it. The reason 308e7d26f28SBenjamin Herrenschmidt * for that is that we opportunistically remove the pending interrupt 309e7d26f28SBenjamin Herrenschmidt * flag when raising CPPR, so we need to set it back here if an 310e7d26f28SBenjamin Herrenschmidt * interrupt is still pending. 311bc5ad3f3SBenjamin Herrenschmidt */ 312bc5ad3f3SBenjamin Herrenschmidt if (new.out_ee) { 313bc5ad3f3SBenjamin Herrenschmidt kvmppc_book3s_queue_irqprio(icp->vcpu, 314bc5ad3f3SBenjamin Herrenschmidt BOOK3S_INTERRUPT_EXTERNAL_LEVEL); 315bc5ad3f3SBenjamin Herrenschmidt if (!change_self) 31654695c30SBenjamin Herrenschmidt kvmppc_fast_vcpu_kick(icp->vcpu); 317bc5ad3f3SBenjamin Herrenschmidt } 318bc5ad3f3SBenjamin Herrenschmidt bail: 319bc5ad3f3SBenjamin Herrenschmidt return success; 320bc5ad3f3SBenjamin Herrenschmidt } 321bc5ad3f3SBenjamin Herrenschmidt 322bc5ad3f3SBenjamin Herrenschmidt static void icp_check_resend(struct kvmppc_xics *xics, 323bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_icp *icp) 324bc5ad3f3SBenjamin Herrenschmidt { 325bc5ad3f3SBenjamin Herrenschmidt u32 icsid; 326bc5ad3f3SBenjamin Herrenschmidt 327bc5ad3f3SBenjamin Herrenschmidt /* Order this load with the test for need_resend in the caller */ 328bc5ad3f3SBenjamin Herrenschmidt smp_rmb(); 329bc5ad3f3SBenjamin Herrenschmidt for_each_set_bit(icsid, icp->resend_map, xics->max_icsid + 1) { 330bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_ics *ics = xics->ics[icsid]; 331bc5ad3f3SBenjamin Herrenschmidt 332bc5ad3f3SBenjamin Herrenschmidt if (!test_and_clear_bit(icsid, icp->resend_map)) 333bc5ad3f3SBenjamin Herrenschmidt continue; 334bc5ad3f3SBenjamin Herrenschmidt if (!ics) 335bc5ad3f3SBenjamin Herrenschmidt continue; 336bc5ad3f3SBenjamin Herrenschmidt ics_check_resend(xics, ics, icp); 337bc5ad3f3SBenjamin Herrenschmidt } 338bc5ad3f3SBenjamin Herrenschmidt } 339bc5ad3f3SBenjamin Herrenschmidt 340bc5ad3f3SBenjamin Herrenschmidt static bool icp_try_to_deliver(struct kvmppc_icp *icp, u32 irq, u8 priority, 341bc5ad3f3SBenjamin Herrenschmidt u32 *reject) 342bc5ad3f3SBenjamin Herrenschmidt { 343bc5ad3f3SBenjamin Herrenschmidt union kvmppc_icp_state old_state, new_state; 344bc5ad3f3SBenjamin Herrenschmidt bool success; 345bc5ad3f3SBenjamin Herrenschmidt 346ade3ac66SAlexey Kardashevskiy XICS_DBG("try deliver %#x(P:%#x) to server %#lx\n", irq, priority, 347bc5ad3f3SBenjamin Herrenschmidt icp->server_num); 348bc5ad3f3SBenjamin Herrenschmidt 349bc5ad3f3SBenjamin Herrenschmidt do { 3505ee07612SChristian Borntraeger old_state = new_state = READ_ONCE(icp->state); 351bc5ad3f3SBenjamin Herrenschmidt 352bc5ad3f3SBenjamin Herrenschmidt *reject = 0; 353bc5ad3f3SBenjamin Herrenschmidt 354bc5ad3f3SBenjamin Herrenschmidt /* See if we can deliver */ 355bc5ad3f3SBenjamin Herrenschmidt success = new_state.cppr > priority && 356bc5ad3f3SBenjamin Herrenschmidt new_state.mfrr > priority && 357bc5ad3f3SBenjamin Herrenschmidt new_state.pending_pri > priority; 358bc5ad3f3SBenjamin Herrenschmidt 359bc5ad3f3SBenjamin Herrenschmidt /* 360bc5ad3f3SBenjamin Herrenschmidt * If we can, check for a rejection and perform the 361bc5ad3f3SBenjamin Herrenschmidt * delivery 362bc5ad3f3SBenjamin Herrenschmidt */ 363bc5ad3f3SBenjamin Herrenschmidt if (success) { 364bc5ad3f3SBenjamin Herrenschmidt *reject = new_state.xisr; 365bc5ad3f3SBenjamin Herrenschmidt new_state.xisr = irq; 366bc5ad3f3SBenjamin Herrenschmidt new_state.pending_pri = priority; 367bc5ad3f3SBenjamin Herrenschmidt } else { 368bc5ad3f3SBenjamin Herrenschmidt /* 369bc5ad3f3SBenjamin Herrenschmidt * If we failed to deliver we set need_resend 370bc5ad3f3SBenjamin Herrenschmidt * so a subsequent CPPR state change causes us 371bc5ad3f3SBenjamin Herrenschmidt * to try a new delivery. 372bc5ad3f3SBenjamin Herrenschmidt */ 373bc5ad3f3SBenjamin Herrenschmidt new_state.need_resend = true; 374bc5ad3f3SBenjamin Herrenschmidt } 375bc5ad3f3SBenjamin Herrenschmidt 376bc5ad3f3SBenjamin Herrenschmidt } while (!icp_try_update(icp, old_state, new_state, false)); 377bc5ad3f3SBenjamin Herrenschmidt 378bc5ad3f3SBenjamin Herrenschmidt return success; 379bc5ad3f3SBenjamin Herrenschmidt } 380bc5ad3f3SBenjamin Herrenschmidt 381bc5ad3f3SBenjamin Herrenschmidt static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, 382bc5ad3f3SBenjamin Herrenschmidt u32 new_irq) 383bc5ad3f3SBenjamin Herrenschmidt { 384bc5ad3f3SBenjamin Herrenschmidt struct ics_irq_state *state; 385bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_ics *ics; 386bc5ad3f3SBenjamin Herrenschmidt u32 reject; 387bc5ad3f3SBenjamin Herrenschmidt u16 src; 38834cb7954SSuresh Warrier unsigned long flags; 389bc5ad3f3SBenjamin Herrenschmidt 390bc5ad3f3SBenjamin Herrenschmidt /* 391bc5ad3f3SBenjamin Herrenschmidt * This is used both for initial delivery of an interrupt and 392bc5ad3f3SBenjamin Herrenschmidt * for subsequent rejection. 393bc5ad3f3SBenjamin Herrenschmidt * 394bc5ad3f3SBenjamin Herrenschmidt * Rejection can be racy vs. resends. We have evaluated the 395bc5ad3f3SBenjamin Herrenschmidt * rejection in an atomic ICP transaction which is now complete, 396bc5ad3f3SBenjamin Herrenschmidt * so potentially the ICP can already accept the interrupt again. 397bc5ad3f3SBenjamin Herrenschmidt * 398bc5ad3f3SBenjamin Herrenschmidt * So we need to retry the delivery. Essentially the reject path 399bc5ad3f3SBenjamin Herrenschmidt * boils down to a failed delivery. Always. 400bc5ad3f3SBenjamin Herrenschmidt * 401bc5ad3f3SBenjamin Herrenschmidt * Now the interrupt could also have moved to a different target, 402bc5ad3f3SBenjamin Herrenschmidt * thus we may need to re-do the ICP lookup as well 403bc5ad3f3SBenjamin Herrenschmidt */ 404bc5ad3f3SBenjamin Herrenschmidt 405bc5ad3f3SBenjamin Herrenschmidt again: 406bc5ad3f3SBenjamin Herrenschmidt /* Get the ICS state and lock it */ 407bc5ad3f3SBenjamin Herrenschmidt ics = kvmppc_xics_find_ics(xics, new_irq, &src); 408bc5ad3f3SBenjamin Herrenschmidt if (!ics) { 409bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("icp_deliver_irq: IRQ 0x%06x not found !\n", new_irq); 410bc5ad3f3SBenjamin Herrenschmidt return; 411bc5ad3f3SBenjamin Herrenschmidt } 412bc5ad3f3SBenjamin Herrenschmidt state = &ics->irq_state[src]; 413bc5ad3f3SBenjamin Herrenschmidt 414bc5ad3f3SBenjamin Herrenschmidt /* Get a lock on the ICS */ 41534cb7954SSuresh Warrier local_irq_save(flags); 41634cb7954SSuresh Warrier arch_spin_lock(&ics->lock); 417bc5ad3f3SBenjamin Herrenschmidt 418bc5ad3f3SBenjamin Herrenschmidt /* Get our server */ 419bc5ad3f3SBenjamin Herrenschmidt if (!icp || state->server != icp->server_num) { 420bc5ad3f3SBenjamin Herrenschmidt icp = kvmppc_xics_find_server(xics->kvm, state->server); 421bc5ad3f3SBenjamin Herrenschmidt if (!icp) { 422bc5ad3f3SBenjamin Herrenschmidt pr_warn("icp_deliver_irq: IRQ 0x%06x server 0x%x not found !\n", 423bc5ad3f3SBenjamin Herrenschmidt new_irq, state->server); 424bc5ad3f3SBenjamin Herrenschmidt goto out; 425bc5ad3f3SBenjamin Herrenschmidt } 426bc5ad3f3SBenjamin Herrenschmidt } 427bc5ad3f3SBenjamin Herrenschmidt 428bc5ad3f3SBenjamin Herrenschmidt /* Clear the resend bit of that interrupt */ 429bc5ad3f3SBenjamin Herrenschmidt state->resend = 0; 430bc5ad3f3SBenjamin Herrenschmidt 431bc5ad3f3SBenjamin Herrenschmidt /* 432bc5ad3f3SBenjamin Herrenschmidt * If masked, bail out 433bc5ad3f3SBenjamin Herrenschmidt * 434bc5ad3f3SBenjamin Herrenschmidt * Note: PAPR doesn't mention anything about masked pending 435bc5ad3f3SBenjamin Herrenschmidt * when doing a resend, only when doing a delivery. 436bc5ad3f3SBenjamin Herrenschmidt * 437bc5ad3f3SBenjamin Herrenschmidt * However that would have the effect of losing a masked 438bc5ad3f3SBenjamin Herrenschmidt * interrupt that was rejected and isn't consistent with 439bc5ad3f3SBenjamin Herrenschmidt * the whole masked_pending business which is about not 440bc5ad3f3SBenjamin Herrenschmidt * losing interrupts that occur while masked. 441bc5ad3f3SBenjamin Herrenschmidt * 442446957baSAdam Buchbinder * I don't differentiate normal deliveries and resends, this 443bc5ad3f3SBenjamin Herrenschmidt * implementation will differ from PAPR and not lose such 444bc5ad3f3SBenjamin Herrenschmidt * interrupts. 445bc5ad3f3SBenjamin Herrenschmidt */ 446bc5ad3f3SBenjamin Herrenschmidt if (state->priority == MASKED) { 447bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("irq %#x masked pending\n", new_irq); 448bc5ad3f3SBenjamin Herrenschmidt state->masked_pending = 1; 449bc5ad3f3SBenjamin Herrenschmidt goto out; 450bc5ad3f3SBenjamin Herrenschmidt } 451bc5ad3f3SBenjamin Herrenschmidt 452bc5ad3f3SBenjamin Herrenschmidt /* 453bc5ad3f3SBenjamin Herrenschmidt * Try the delivery, this will set the need_resend flag 454bc5ad3f3SBenjamin Herrenschmidt * in the ICP as part of the atomic transaction if the 455bc5ad3f3SBenjamin Herrenschmidt * delivery is not possible. 456bc5ad3f3SBenjamin Herrenschmidt * 457bc5ad3f3SBenjamin Herrenschmidt * Note that if successful, the new delivery might have itself 458bc5ad3f3SBenjamin Herrenschmidt * rejected an interrupt that was "delivered" before we took the 45934cb7954SSuresh Warrier * ics spin lock. 460bc5ad3f3SBenjamin Herrenschmidt * 461bc5ad3f3SBenjamin Herrenschmidt * In this case we do the whole sequence all over again for the 462bc5ad3f3SBenjamin Herrenschmidt * new guy. We cannot assume that the rejected interrupt is less 463bc5ad3f3SBenjamin Herrenschmidt * favored than the new one, and thus doesn't need to be delivered, 464bc5ad3f3SBenjamin Herrenschmidt * because by the time we exit icp_try_to_deliver() the target 465bc5ad3f3SBenjamin Herrenschmidt * processor may well have alrady consumed & completed it, and thus 466bc5ad3f3SBenjamin Herrenschmidt * the rejected interrupt might actually be already acceptable. 467bc5ad3f3SBenjamin Herrenschmidt */ 468bc5ad3f3SBenjamin Herrenschmidt if (icp_try_to_deliver(icp, new_irq, state->priority, &reject)) { 469bc5ad3f3SBenjamin Herrenschmidt /* 470bc5ad3f3SBenjamin Herrenschmidt * Delivery was successful, did we reject somebody else ? 471bc5ad3f3SBenjamin Herrenschmidt */ 472bc5ad3f3SBenjamin Herrenschmidt if (reject && reject != XICS_IPI) { 47334cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 47434cb7954SSuresh Warrier local_irq_restore(flags); 475bc5ad3f3SBenjamin Herrenschmidt new_irq = reject; 476bc5ad3f3SBenjamin Herrenschmidt goto again; 477bc5ad3f3SBenjamin Herrenschmidt } 478bc5ad3f3SBenjamin Herrenschmidt } else { 479bc5ad3f3SBenjamin Herrenschmidt /* 480bc5ad3f3SBenjamin Herrenschmidt * We failed to deliver the interrupt we need to set the 481bc5ad3f3SBenjamin Herrenschmidt * resend map bit and mark the ICS state as needing a resend 482bc5ad3f3SBenjamin Herrenschmidt */ 483bc5ad3f3SBenjamin Herrenschmidt set_bit(ics->icsid, icp->resend_map); 484bc5ad3f3SBenjamin Herrenschmidt state->resend = 1; 485bc5ad3f3SBenjamin Herrenschmidt 486bc5ad3f3SBenjamin Herrenschmidt /* 487bc5ad3f3SBenjamin Herrenschmidt * If the need_resend flag got cleared in the ICP some time 488bc5ad3f3SBenjamin Herrenschmidt * between icp_try_to_deliver() atomic update and now, then 489bc5ad3f3SBenjamin Herrenschmidt * we know it might have missed the resend_map bit. So we 490bc5ad3f3SBenjamin Herrenschmidt * retry 491bc5ad3f3SBenjamin Herrenschmidt */ 492bc5ad3f3SBenjamin Herrenschmidt smp_mb(); 493bc5ad3f3SBenjamin Herrenschmidt if (!icp->state.need_resend) { 494*bf5a71d5SLi Zhong state->resend = 0; 49534cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 49634cb7954SSuresh Warrier local_irq_restore(flags); 497bc5ad3f3SBenjamin Herrenschmidt goto again; 498bc5ad3f3SBenjamin Herrenschmidt } 499bc5ad3f3SBenjamin Herrenschmidt } 500bc5ad3f3SBenjamin Herrenschmidt out: 50134cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 50234cb7954SSuresh Warrier local_irq_restore(flags); 503bc5ad3f3SBenjamin Herrenschmidt } 504bc5ad3f3SBenjamin Herrenschmidt 505bc5ad3f3SBenjamin Herrenschmidt static void icp_down_cppr(struct kvmppc_xics *xics, struct kvmppc_icp *icp, 506bc5ad3f3SBenjamin Herrenschmidt u8 new_cppr) 507bc5ad3f3SBenjamin Herrenschmidt { 508bc5ad3f3SBenjamin Herrenschmidt union kvmppc_icp_state old_state, new_state; 509bc5ad3f3SBenjamin Herrenschmidt bool resend; 510bc5ad3f3SBenjamin Herrenschmidt 511bc5ad3f3SBenjamin Herrenschmidt /* 512bc5ad3f3SBenjamin Herrenschmidt * This handles several related states in one operation: 513bc5ad3f3SBenjamin Herrenschmidt * 514bc5ad3f3SBenjamin Herrenschmidt * ICP State: Down_CPPR 515bc5ad3f3SBenjamin Herrenschmidt * 516bc5ad3f3SBenjamin Herrenschmidt * Load CPPR with new value and if the XISR is 0 517bc5ad3f3SBenjamin Herrenschmidt * then check for resends: 518bc5ad3f3SBenjamin Herrenschmidt * 519bc5ad3f3SBenjamin Herrenschmidt * ICP State: Resend 520bc5ad3f3SBenjamin Herrenschmidt * 521bc5ad3f3SBenjamin Herrenschmidt * If MFRR is more favored than CPPR, check for IPIs 522bc5ad3f3SBenjamin Herrenschmidt * and notify ICS of a potential resend. This is done 523bc5ad3f3SBenjamin Herrenschmidt * asynchronously (when used in real mode, we will have 524bc5ad3f3SBenjamin Herrenschmidt * to exit here). 525bc5ad3f3SBenjamin Herrenschmidt * 526bc5ad3f3SBenjamin Herrenschmidt * We do not handle the complete Check_IPI as documented 527bc5ad3f3SBenjamin Herrenschmidt * here. In the PAPR, this state will be used for both 528bc5ad3f3SBenjamin Herrenschmidt * Set_MFRR and Down_CPPR. However, we know that we aren't 529bc5ad3f3SBenjamin Herrenschmidt * changing the MFRR state here so we don't need to handle 530bc5ad3f3SBenjamin Herrenschmidt * the case of an MFRR causing a reject of a pending irq, 531bc5ad3f3SBenjamin Herrenschmidt * this will have been handled when the MFRR was set in the 532bc5ad3f3SBenjamin Herrenschmidt * first place. 533bc5ad3f3SBenjamin Herrenschmidt * 534bc5ad3f3SBenjamin Herrenschmidt * Thus we don't have to handle rejects, only resends. 535bc5ad3f3SBenjamin Herrenschmidt * 536bc5ad3f3SBenjamin Herrenschmidt * When implementing real mode for HV KVM, resend will lead to 537bc5ad3f3SBenjamin Herrenschmidt * a H_TOO_HARD return and the whole transaction will be handled 538bc5ad3f3SBenjamin Herrenschmidt * in virtual mode. 539bc5ad3f3SBenjamin Herrenschmidt */ 540bc5ad3f3SBenjamin Herrenschmidt do { 5415ee07612SChristian Borntraeger old_state = new_state = READ_ONCE(icp->state); 542bc5ad3f3SBenjamin Herrenschmidt 543bc5ad3f3SBenjamin Herrenschmidt /* Down_CPPR */ 544bc5ad3f3SBenjamin Herrenschmidt new_state.cppr = new_cppr; 545bc5ad3f3SBenjamin Herrenschmidt 546bc5ad3f3SBenjamin Herrenschmidt /* 547bc5ad3f3SBenjamin Herrenschmidt * Cut down Resend / Check_IPI / IPI 548bc5ad3f3SBenjamin Herrenschmidt * 549bc5ad3f3SBenjamin Herrenschmidt * The logic is that we cannot have a pending interrupt 550bc5ad3f3SBenjamin Herrenschmidt * trumped by an IPI at this point (see above), so we 551bc5ad3f3SBenjamin Herrenschmidt * know that either the pending interrupt is already an 552bc5ad3f3SBenjamin Herrenschmidt * IPI (in which case we don't care to override it) or 553bc5ad3f3SBenjamin Herrenschmidt * it's either more favored than us or non existent 554bc5ad3f3SBenjamin Herrenschmidt */ 555bc5ad3f3SBenjamin Herrenschmidt if (new_state.mfrr < new_cppr && 556bc5ad3f3SBenjamin Herrenschmidt new_state.mfrr <= new_state.pending_pri) { 557bc5ad3f3SBenjamin Herrenschmidt WARN_ON(new_state.xisr != XICS_IPI && 558bc5ad3f3SBenjamin Herrenschmidt new_state.xisr != 0); 559bc5ad3f3SBenjamin Herrenschmidt new_state.pending_pri = new_state.mfrr; 560bc5ad3f3SBenjamin Herrenschmidt new_state.xisr = XICS_IPI; 561bc5ad3f3SBenjamin Herrenschmidt } 562bc5ad3f3SBenjamin Herrenschmidt 563bc5ad3f3SBenjamin Herrenschmidt /* Latch/clear resend bit */ 564bc5ad3f3SBenjamin Herrenschmidt resend = new_state.need_resend; 565bc5ad3f3SBenjamin Herrenschmidt new_state.need_resend = 0; 566bc5ad3f3SBenjamin Herrenschmidt 567bc5ad3f3SBenjamin Herrenschmidt } while (!icp_try_update(icp, old_state, new_state, true)); 568bc5ad3f3SBenjamin Herrenschmidt 569bc5ad3f3SBenjamin Herrenschmidt /* 570bc5ad3f3SBenjamin Herrenschmidt * Now handle resend checks. Those are asynchronous to the ICP 571bc5ad3f3SBenjamin Herrenschmidt * state update in HW (ie bus transactions) so we can handle them 572bc5ad3f3SBenjamin Herrenschmidt * separately here too 573bc5ad3f3SBenjamin Herrenschmidt */ 574bc5ad3f3SBenjamin Herrenschmidt if (resend) 575bc5ad3f3SBenjamin Herrenschmidt icp_check_resend(xics, icp); 576bc5ad3f3SBenjamin Herrenschmidt } 577bc5ad3f3SBenjamin Herrenschmidt 578e7d26f28SBenjamin Herrenschmidt static noinline unsigned long kvmppc_h_xirr(struct kvm_vcpu *vcpu) 579bc5ad3f3SBenjamin Herrenschmidt { 580bc5ad3f3SBenjamin Herrenschmidt union kvmppc_icp_state old_state, new_state; 581bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_icp *icp = vcpu->arch.icp; 582bc5ad3f3SBenjamin Herrenschmidt u32 xirr; 583bc5ad3f3SBenjamin Herrenschmidt 584bc5ad3f3SBenjamin Herrenschmidt /* First, remove EE from the processor */ 585bc5ad3f3SBenjamin Herrenschmidt kvmppc_book3s_dequeue_irqprio(icp->vcpu, 586bc5ad3f3SBenjamin Herrenschmidt BOOK3S_INTERRUPT_EXTERNAL_LEVEL); 587bc5ad3f3SBenjamin Herrenschmidt 588bc5ad3f3SBenjamin Herrenschmidt /* 589bc5ad3f3SBenjamin Herrenschmidt * ICP State: Accept_Interrupt 590bc5ad3f3SBenjamin Herrenschmidt * 591bc5ad3f3SBenjamin Herrenschmidt * Return the pending interrupt (if any) along with the 592bc5ad3f3SBenjamin Herrenschmidt * current CPPR, then clear the XISR & set CPPR to the 593bc5ad3f3SBenjamin Herrenschmidt * pending priority 594bc5ad3f3SBenjamin Herrenschmidt */ 595bc5ad3f3SBenjamin Herrenschmidt do { 5965ee07612SChristian Borntraeger old_state = new_state = READ_ONCE(icp->state); 597bc5ad3f3SBenjamin Herrenschmidt 598bc5ad3f3SBenjamin Herrenschmidt xirr = old_state.xisr | (((u32)old_state.cppr) << 24); 599bc5ad3f3SBenjamin Herrenschmidt if (!old_state.xisr) 600bc5ad3f3SBenjamin Herrenschmidt break; 601bc5ad3f3SBenjamin Herrenschmidt new_state.cppr = new_state.pending_pri; 602bc5ad3f3SBenjamin Herrenschmidt new_state.pending_pri = 0xff; 603bc5ad3f3SBenjamin Herrenschmidt new_state.xisr = 0; 604bc5ad3f3SBenjamin Herrenschmidt 605bc5ad3f3SBenjamin Herrenschmidt } while (!icp_try_update(icp, old_state, new_state, true)); 606bc5ad3f3SBenjamin Herrenschmidt 607bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("h_xirr vcpu %d xirr %#x\n", vcpu->vcpu_id, xirr); 608bc5ad3f3SBenjamin Herrenschmidt 609bc5ad3f3SBenjamin Herrenschmidt return xirr; 610bc5ad3f3SBenjamin Herrenschmidt } 611bc5ad3f3SBenjamin Herrenschmidt 612e7d26f28SBenjamin Herrenschmidt static noinline int kvmppc_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, 613bc5ad3f3SBenjamin Herrenschmidt unsigned long mfrr) 614bc5ad3f3SBenjamin Herrenschmidt { 615bc5ad3f3SBenjamin Herrenschmidt union kvmppc_icp_state old_state, new_state; 616bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_xics *xics = vcpu->kvm->arch.xics; 617bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_icp *icp; 618bc5ad3f3SBenjamin Herrenschmidt u32 reject; 619bc5ad3f3SBenjamin Herrenschmidt bool resend; 620bc5ad3f3SBenjamin Herrenschmidt bool local; 621bc5ad3f3SBenjamin Herrenschmidt 622bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("h_ipi vcpu %d to server %lu mfrr %#lx\n", 623bc5ad3f3SBenjamin Herrenschmidt vcpu->vcpu_id, server, mfrr); 624bc5ad3f3SBenjamin Herrenschmidt 625bc5ad3f3SBenjamin Herrenschmidt icp = vcpu->arch.icp; 626bc5ad3f3SBenjamin Herrenschmidt local = icp->server_num == server; 627bc5ad3f3SBenjamin Herrenschmidt if (!local) { 628bc5ad3f3SBenjamin Herrenschmidt icp = kvmppc_xics_find_server(vcpu->kvm, server); 629bc5ad3f3SBenjamin Herrenschmidt if (!icp) 630bc5ad3f3SBenjamin Herrenschmidt return H_PARAMETER; 631bc5ad3f3SBenjamin Herrenschmidt } 632bc5ad3f3SBenjamin Herrenschmidt 633bc5ad3f3SBenjamin Herrenschmidt /* 634bc5ad3f3SBenjamin Herrenschmidt * ICP state: Set_MFRR 635bc5ad3f3SBenjamin Herrenschmidt * 636bc5ad3f3SBenjamin Herrenschmidt * If the CPPR is more favored than the new MFRR, then 637bc5ad3f3SBenjamin Herrenschmidt * nothing needs to be rejected as there can be no XISR to 638bc5ad3f3SBenjamin Herrenschmidt * reject. If the MFRR is being made less favored then 639bc5ad3f3SBenjamin Herrenschmidt * there might be a previously-rejected interrupt needing 640bc5ad3f3SBenjamin Herrenschmidt * to be resent. 641bc5ad3f3SBenjamin Herrenschmidt * 642bc5ad3f3SBenjamin Herrenschmidt * ICP state: Check_IPI 6435b88cda6SSuresh E. Warrier * 6445b88cda6SSuresh E. Warrier * If the CPPR is less favored, then we might be replacing 6455b88cda6SSuresh E. Warrier * an interrupt, and thus need to possibly reject it. 6465b88cda6SSuresh E. Warrier * 6475b88cda6SSuresh E. Warrier * ICP State: IPI 6485b88cda6SSuresh E. Warrier * 6495b88cda6SSuresh E. Warrier * Besides rejecting any pending interrupts, we also 6505b88cda6SSuresh E. Warrier * update XISR and pending_pri to mark IPI as pending. 6515b88cda6SSuresh E. Warrier * 6525b88cda6SSuresh E. Warrier * PAPR does not describe this state, but if the MFRR is being 6535b88cda6SSuresh E. Warrier * made less favored than its earlier value, there might be 6545b88cda6SSuresh E. Warrier * a previously-rejected interrupt needing to be resent. 6555b88cda6SSuresh E. Warrier * Ideally, we would want to resend only if 6565b88cda6SSuresh E. Warrier * prio(pending_interrupt) < mfrr && 6575b88cda6SSuresh E. Warrier * prio(pending_interrupt) < cppr 6585b88cda6SSuresh E. Warrier * where pending interrupt is the one that was rejected. But 6595b88cda6SSuresh E. Warrier * we don't have that state, so we simply trigger a resend 6605b88cda6SSuresh E. Warrier * whenever the MFRR is made less favored. 661bc5ad3f3SBenjamin Herrenschmidt */ 662bc5ad3f3SBenjamin Herrenschmidt do { 6635ee07612SChristian Borntraeger old_state = new_state = READ_ONCE(icp->state); 664bc5ad3f3SBenjamin Herrenschmidt 665bc5ad3f3SBenjamin Herrenschmidt /* Set_MFRR */ 666bc5ad3f3SBenjamin Herrenschmidt new_state.mfrr = mfrr; 667bc5ad3f3SBenjamin Herrenschmidt 668bc5ad3f3SBenjamin Herrenschmidt /* Check_IPI */ 669bc5ad3f3SBenjamin Herrenschmidt reject = 0; 670bc5ad3f3SBenjamin Herrenschmidt resend = false; 671bc5ad3f3SBenjamin Herrenschmidt if (mfrr < new_state.cppr) { 672bc5ad3f3SBenjamin Herrenschmidt /* Reject a pending interrupt if not an IPI */ 6735b88cda6SSuresh E. Warrier if (mfrr <= new_state.pending_pri) { 674bc5ad3f3SBenjamin Herrenschmidt reject = new_state.xisr; 675bc5ad3f3SBenjamin Herrenschmidt new_state.pending_pri = mfrr; 676bc5ad3f3SBenjamin Herrenschmidt new_state.xisr = XICS_IPI; 677bc5ad3f3SBenjamin Herrenschmidt } 6785b88cda6SSuresh E. Warrier } 679bc5ad3f3SBenjamin Herrenschmidt 6805b88cda6SSuresh E. Warrier if (mfrr > old_state.mfrr) { 681bc5ad3f3SBenjamin Herrenschmidt resend = new_state.need_resend; 682bc5ad3f3SBenjamin Herrenschmidt new_state.need_resend = 0; 683bc5ad3f3SBenjamin Herrenschmidt } 684bc5ad3f3SBenjamin Herrenschmidt } while (!icp_try_update(icp, old_state, new_state, local)); 685bc5ad3f3SBenjamin Herrenschmidt 686bc5ad3f3SBenjamin Herrenschmidt /* Handle reject */ 687bc5ad3f3SBenjamin Herrenschmidt if (reject && reject != XICS_IPI) 688bc5ad3f3SBenjamin Herrenschmidt icp_deliver_irq(xics, icp, reject); 689bc5ad3f3SBenjamin Herrenschmidt 690bc5ad3f3SBenjamin Herrenschmidt /* Handle resend */ 691bc5ad3f3SBenjamin Herrenschmidt if (resend) 692bc5ad3f3SBenjamin Herrenschmidt icp_check_resend(xics, icp); 693bc5ad3f3SBenjamin Herrenschmidt 694bc5ad3f3SBenjamin Herrenschmidt return H_SUCCESS; 695bc5ad3f3SBenjamin Herrenschmidt } 696bc5ad3f3SBenjamin Herrenschmidt 6978e44ddc3SPaul Mackerras static int kvmppc_h_ipoll(struct kvm_vcpu *vcpu, unsigned long server) 6988e44ddc3SPaul Mackerras { 6998e44ddc3SPaul Mackerras union kvmppc_icp_state state; 7008e44ddc3SPaul Mackerras struct kvmppc_icp *icp; 7018e44ddc3SPaul Mackerras 7028e44ddc3SPaul Mackerras icp = vcpu->arch.icp; 7038e44ddc3SPaul Mackerras if (icp->server_num != server) { 7048e44ddc3SPaul Mackerras icp = kvmppc_xics_find_server(vcpu->kvm, server); 7058e44ddc3SPaul Mackerras if (!icp) 7068e44ddc3SPaul Mackerras return H_PARAMETER; 7078e44ddc3SPaul Mackerras } 7085ee07612SChristian Borntraeger state = READ_ONCE(icp->state); 7098e44ddc3SPaul Mackerras kvmppc_set_gpr(vcpu, 4, ((u32)state.cppr << 24) | state.xisr); 7108e44ddc3SPaul Mackerras kvmppc_set_gpr(vcpu, 5, state.mfrr); 7118e44ddc3SPaul Mackerras return H_SUCCESS; 7128e44ddc3SPaul Mackerras } 7138e44ddc3SPaul Mackerras 714e7d26f28SBenjamin Herrenschmidt static noinline void kvmppc_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr) 715bc5ad3f3SBenjamin Herrenschmidt { 716bc5ad3f3SBenjamin Herrenschmidt union kvmppc_icp_state old_state, new_state; 717bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_xics *xics = vcpu->kvm->arch.xics; 718bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_icp *icp = vcpu->arch.icp; 719bc5ad3f3SBenjamin Herrenschmidt u32 reject; 720bc5ad3f3SBenjamin Herrenschmidt 721bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("h_cppr vcpu %d cppr %#lx\n", vcpu->vcpu_id, cppr); 722bc5ad3f3SBenjamin Herrenschmidt 723bc5ad3f3SBenjamin Herrenschmidt /* 724bc5ad3f3SBenjamin Herrenschmidt * ICP State: Set_CPPR 725bc5ad3f3SBenjamin Herrenschmidt * 726bc5ad3f3SBenjamin Herrenschmidt * We can safely compare the new value with the current 727bc5ad3f3SBenjamin Herrenschmidt * value outside of the transaction as the CPPR is only 728bc5ad3f3SBenjamin Herrenschmidt * ever changed by the processor on itself 729bc5ad3f3SBenjamin Herrenschmidt */ 730bc5ad3f3SBenjamin Herrenschmidt if (cppr > icp->state.cppr) 731bc5ad3f3SBenjamin Herrenschmidt icp_down_cppr(xics, icp, cppr); 732bc5ad3f3SBenjamin Herrenschmidt else if (cppr == icp->state.cppr) 733bc5ad3f3SBenjamin Herrenschmidt return; 734bc5ad3f3SBenjamin Herrenschmidt 735bc5ad3f3SBenjamin Herrenschmidt /* 736bc5ad3f3SBenjamin Herrenschmidt * ICP State: Up_CPPR 737bc5ad3f3SBenjamin Herrenschmidt * 738bc5ad3f3SBenjamin Herrenschmidt * The processor is raising its priority, this can result 739bc5ad3f3SBenjamin Herrenschmidt * in a rejection of a pending interrupt: 740bc5ad3f3SBenjamin Herrenschmidt * 741bc5ad3f3SBenjamin Herrenschmidt * ICP State: Reject_Current 742bc5ad3f3SBenjamin Herrenschmidt * 743bc5ad3f3SBenjamin Herrenschmidt * We can remove EE from the current processor, the update 744bc5ad3f3SBenjamin Herrenschmidt * transaction will set it again if needed 745bc5ad3f3SBenjamin Herrenschmidt */ 746bc5ad3f3SBenjamin Herrenschmidt kvmppc_book3s_dequeue_irqprio(icp->vcpu, 747bc5ad3f3SBenjamin Herrenschmidt BOOK3S_INTERRUPT_EXTERNAL_LEVEL); 748bc5ad3f3SBenjamin Herrenschmidt 749bc5ad3f3SBenjamin Herrenschmidt do { 7505ee07612SChristian Borntraeger old_state = new_state = READ_ONCE(icp->state); 751bc5ad3f3SBenjamin Herrenschmidt 752bc5ad3f3SBenjamin Herrenschmidt reject = 0; 753bc5ad3f3SBenjamin Herrenschmidt new_state.cppr = cppr; 754bc5ad3f3SBenjamin Herrenschmidt 755bc5ad3f3SBenjamin Herrenschmidt if (cppr <= new_state.pending_pri) { 756bc5ad3f3SBenjamin Herrenschmidt reject = new_state.xisr; 757bc5ad3f3SBenjamin Herrenschmidt new_state.xisr = 0; 758bc5ad3f3SBenjamin Herrenschmidt new_state.pending_pri = 0xff; 759bc5ad3f3SBenjamin Herrenschmidt } 760bc5ad3f3SBenjamin Herrenschmidt 761bc5ad3f3SBenjamin Herrenschmidt } while (!icp_try_update(icp, old_state, new_state, true)); 762bc5ad3f3SBenjamin Herrenschmidt 763bc5ad3f3SBenjamin Herrenschmidt /* 764bc5ad3f3SBenjamin Herrenschmidt * Check for rejects. They are handled by doing a new delivery 765bc5ad3f3SBenjamin Herrenschmidt * attempt (see comments in icp_deliver_irq). 766bc5ad3f3SBenjamin Herrenschmidt */ 767bc5ad3f3SBenjamin Herrenschmidt if (reject && reject != XICS_IPI) 768bc5ad3f3SBenjamin Herrenschmidt icp_deliver_irq(xics, icp, reject); 769bc5ad3f3SBenjamin Herrenschmidt } 770bc5ad3f3SBenjamin Herrenschmidt 771e7d26f28SBenjamin Herrenschmidt static noinline int kvmppc_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr) 772bc5ad3f3SBenjamin Herrenschmidt { 773bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_xics *xics = vcpu->kvm->arch.xics; 774bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_icp *icp = vcpu->arch.icp; 775bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_ics *ics; 776bc5ad3f3SBenjamin Herrenschmidt struct ics_irq_state *state; 777bc5ad3f3SBenjamin Herrenschmidt u32 irq = xirr & 0x00ffffff; 778bc5ad3f3SBenjamin Herrenschmidt u16 src; 779bc5ad3f3SBenjamin Herrenschmidt 780bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("h_eoi vcpu %d eoi %#lx\n", vcpu->vcpu_id, xirr); 781bc5ad3f3SBenjamin Herrenschmidt 782bc5ad3f3SBenjamin Herrenschmidt /* 783bc5ad3f3SBenjamin Herrenschmidt * ICP State: EOI 784bc5ad3f3SBenjamin Herrenschmidt * 785bc5ad3f3SBenjamin Herrenschmidt * Note: If EOI is incorrectly used by SW to lower the CPPR 786bc5ad3f3SBenjamin Herrenschmidt * value (ie more favored), we do not check for rejection of 787bc5ad3f3SBenjamin Herrenschmidt * a pending interrupt, this is a SW error and PAPR sepcifies 788bc5ad3f3SBenjamin Herrenschmidt * that we don't have to deal with it. 789bc5ad3f3SBenjamin Herrenschmidt * 790bc5ad3f3SBenjamin Herrenschmidt * The sending of an EOI to the ICS is handled after the 791bc5ad3f3SBenjamin Herrenschmidt * CPPR update 792bc5ad3f3SBenjamin Herrenschmidt * 793bc5ad3f3SBenjamin Herrenschmidt * ICP State: Down_CPPR which we handle 794bc5ad3f3SBenjamin Herrenschmidt * in a separate function as it's shared with H_CPPR. 795bc5ad3f3SBenjamin Herrenschmidt */ 796bc5ad3f3SBenjamin Herrenschmidt icp_down_cppr(xics, icp, xirr >> 24); 797bc5ad3f3SBenjamin Herrenschmidt 798bc5ad3f3SBenjamin Herrenschmidt /* IPIs have no EOI */ 799bc5ad3f3SBenjamin Herrenschmidt if (irq == XICS_IPI) 800bc5ad3f3SBenjamin Herrenschmidt return H_SUCCESS; 801bc5ad3f3SBenjamin Herrenschmidt /* 802bc5ad3f3SBenjamin Herrenschmidt * EOI handling: If the interrupt is still asserted, we need to 803bc5ad3f3SBenjamin Herrenschmidt * resend it. We can take a lockless "peek" at the ICS state here. 804bc5ad3f3SBenjamin Herrenschmidt * 805bc5ad3f3SBenjamin Herrenschmidt * "Message" interrupts will never have "asserted" set 806bc5ad3f3SBenjamin Herrenschmidt */ 807bc5ad3f3SBenjamin Herrenschmidt ics = kvmppc_xics_find_ics(xics, irq, &src); 808bc5ad3f3SBenjamin Herrenschmidt if (!ics) { 809bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("h_eoi: IRQ 0x%06x not found !\n", irq); 810bc5ad3f3SBenjamin Herrenschmidt return H_PARAMETER; 811bc5ad3f3SBenjamin Herrenschmidt } 812bc5ad3f3SBenjamin Herrenschmidt state = &ics->irq_state[src]; 813bc5ad3f3SBenjamin Herrenschmidt 814bc5ad3f3SBenjamin Herrenschmidt /* Still asserted, resend it */ 815bc5ad3f3SBenjamin Herrenschmidt if (state->asserted) 816bc5ad3f3SBenjamin Herrenschmidt icp_deliver_irq(xics, icp, irq); 817bc5ad3f3SBenjamin Herrenschmidt 81825a2150bSPaul Mackerras kvm_notify_acked_irq(vcpu->kvm, 0, irq); 81925a2150bSPaul Mackerras 820bc5ad3f3SBenjamin Herrenschmidt return H_SUCCESS; 821bc5ad3f3SBenjamin Herrenschmidt } 822bc5ad3f3SBenjamin Herrenschmidt 823f7af5209SSuresh Warrier int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall) 824e7d26f28SBenjamin Herrenschmidt { 825e7d26f28SBenjamin Herrenschmidt struct kvmppc_xics *xics = vcpu->kvm->arch.xics; 826e7d26f28SBenjamin Herrenschmidt struct kvmppc_icp *icp = vcpu->arch.icp; 827e7d26f28SBenjamin Herrenschmidt 828e7d26f28SBenjamin Herrenschmidt XICS_DBG("XICS_RM: H_%x completing, act: %x state: %lx tgt: %p\n", 829e7d26f28SBenjamin Herrenschmidt hcall, icp->rm_action, icp->rm_dbgstate.raw, icp->rm_dbgtgt); 830e7d26f28SBenjamin Herrenschmidt 831878610feSSuresh E. Warrier if (icp->rm_action & XICS_RM_KICK_VCPU) { 832878610feSSuresh E. Warrier icp->n_rm_kick_vcpu++; 833e7d26f28SBenjamin Herrenschmidt kvmppc_fast_vcpu_kick(icp->rm_kick_target); 834878610feSSuresh E. Warrier } 835878610feSSuresh E. Warrier if (icp->rm_action & XICS_RM_CHECK_RESEND) { 836878610feSSuresh E. Warrier icp->n_rm_check_resend++; 8375b88cda6SSuresh E. Warrier icp_check_resend(xics, icp->rm_resend_icp); 838878610feSSuresh E. Warrier } 839878610feSSuresh E. Warrier if (icp->rm_action & XICS_RM_NOTIFY_EOI) { 840878610feSSuresh E. Warrier icp->n_rm_notify_eoi++; 84125a2150bSPaul Mackerras kvm_notify_acked_irq(vcpu->kvm, 0, icp->rm_eoied_irq); 842878610feSSuresh E. Warrier } 843e7d26f28SBenjamin Herrenschmidt 844e7d26f28SBenjamin Herrenschmidt icp->rm_action = 0; 845e7d26f28SBenjamin Herrenschmidt 846e7d26f28SBenjamin Herrenschmidt return H_SUCCESS; 847e7d26f28SBenjamin Herrenschmidt } 848f7af5209SSuresh Warrier EXPORT_SYMBOL_GPL(kvmppc_xics_rm_complete); 849e7d26f28SBenjamin Herrenschmidt 850bc5ad3f3SBenjamin Herrenschmidt int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 req) 851bc5ad3f3SBenjamin Herrenschmidt { 852e7d26f28SBenjamin Herrenschmidt struct kvmppc_xics *xics = vcpu->kvm->arch.xics; 853bc5ad3f3SBenjamin Herrenschmidt unsigned long res; 854bc5ad3f3SBenjamin Herrenschmidt int rc = H_SUCCESS; 855bc5ad3f3SBenjamin Herrenschmidt 856bc5ad3f3SBenjamin Herrenschmidt /* Check if we have an ICP */ 857e7d26f28SBenjamin Herrenschmidt if (!xics || !vcpu->arch.icp) 858bc5ad3f3SBenjamin Herrenschmidt return H_HARDWARE; 859bc5ad3f3SBenjamin Herrenschmidt 8608e44ddc3SPaul Mackerras /* These requests don't have real-mode implementations at present */ 8618e44ddc3SPaul Mackerras switch (req) { 8628e44ddc3SPaul Mackerras case H_XIRR_X: 8638e44ddc3SPaul Mackerras res = kvmppc_h_xirr(vcpu); 8648e44ddc3SPaul Mackerras kvmppc_set_gpr(vcpu, 4, res); 8658e44ddc3SPaul Mackerras kvmppc_set_gpr(vcpu, 5, get_tb()); 8668e44ddc3SPaul Mackerras return rc; 8678e44ddc3SPaul Mackerras case H_IPOLL: 8688e44ddc3SPaul Mackerras rc = kvmppc_h_ipoll(vcpu, kvmppc_get_gpr(vcpu, 4)); 8698e44ddc3SPaul Mackerras return rc; 8708e44ddc3SPaul Mackerras } 8718e44ddc3SPaul Mackerras 872e7d26f28SBenjamin Herrenschmidt /* Check for real mode returning too hard */ 873a78b55d1SAneesh Kumar K.V if (xics->real_mode && is_kvmppc_hv_enabled(vcpu->kvm)) 874e7d26f28SBenjamin Herrenschmidt return kvmppc_xics_rm_complete(vcpu, req); 875e7d26f28SBenjamin Herrenschmidt 876bc5ad3f3SBenjamin Herrenschmidt switch (req) { 877bc5ad3f3SBenjamin Herrenschmidt case H_XIRR: 878e7d26f28SBenjamin Herrenschmidt res = kvmppc_h_xirr(vcpu); 879bc5ad3f3SBenjamin Herrenschmidt kvmppc_set_gpr(vcpu, 4, res); 880bc5ad3f3SBenjamin Herrenschmidt break; 881bc5ad3f3SBenjamin Herrenschmidt case H_CPPR: 882e7d26f28SBenjamin Herrenschmidt kvmppc_h_cppr(vcpu, kvmppc_get_gpr(vcpu, 4)); 883bc5ad3f3SBenjamin Herrenschmidt break; 884bc5ad3f3SBenjamin Herrenschmidt case H_EOI: 885e7d26f28SBenjamin Herrenschmidt rc = kvmppc_h_eoi(vcpu, kvmppc_get_gpr(vcpu, 4)); 886bc5ad3f3SBenjamin Herrenschmidt break; 887bc5ad3f3SBenjamin Herrenschmidt case H_IPI: 888e7d26f28SBenjamin Herrenschmidt rc = kvmppc_h_ipi(vcpu, kvmppc_get_gpr(vcpu, 4), 889bc5ad3f3SBenjamin Herrenschmidt kvmppc_get_gpr(vcpu, 5)); 890bc5ad3f3SBenjamin Herrenschmidt break; 891bc5ad3f3SBenjamin Herrenschmidt } 892bc5ad3f3SBenjamin Herrenschmidt 893bc5ad3f3SBenjamin Herrenschmidt return rc; 894bc5ad3f3SBenjamin Herrenschmidt } 8952ba9f0d8SAneesh Kumar K.V EXPORT_SYMBOL_GPL(kvmppc_xics_hcall); 896bc5ad3f3SBenjamin Herrenschmidt 897bc5ad3f3SBenjamin Herrenschmidt 898bc5ad3f3SBenjamin Herrenschmidt /* -- Initialisation code etc. -- */ 899bc5ad3f3SBenjamin Herrenschmidt 900af893c7dSSuresh Warrier static void xics_debugfs_irqmap(struct seq_file *m, 901af893c7dSSuresh Warrier struct kvmppc_passthru_irqmap *pimap) 902af893c7dSSuresh Warrier { 903af893c7dSSuresh Warrier int i; 904af893c7dSSuresh Warrier 905af893c7dSSuresh Warrier if (!pimap) 906af893c7dSSuresh Warrier return; 907af893c7dSSuresh Warrier seq_printf(m, "========\nPIRQ mappings: %d maps\n===========\n", 908af893c7dSSuresh Warrier pimap->n_mapped); 909af893c7dSSuresh Warrier for (i = 0; i < pimap->n_mapped; i++) { 910af893c7dSSuresh Warrier seq_printf(m, "r_hwirq=%x, v_hwirq=%x\n", 911af893c7dSSuresh Warrier pimap->mapped[i].r_hwirq, pimap->mapped[i].v_hwirq); 912af893c7dSSuresh Warrier } 913af893c7dSSuresh Warrier } 914af893c7dSSuresh Warrier 915bc5ad3f3SBenjamin Herrenschmidt static int xics_debug_show(struct seq_file *m, void *private) 916bc5ad3f3SBenjamin Herrenschmidt { 917bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_xics *xics = m->private; 918bc5ad3f3SBenjamin Herrenschmidt struct kvm *kvm = xics->kvm; 919bc5ad3f3SBenjamin Herrenschmidt struct kvm_vcpu *vcpu; 920bc5ad3f3SBenjamin Herrenschmidt int icsid, i; 92134cb7954SSuresh Warrier unsigned long flags; 922878610feSSuresh E. Warrier unsigned long t_rm_kick_vcpu, t_rm_check_resend; 9235efa6605SLi Zhong unsigned long t_rm_notify_eoi; 9246e0365b7SSuresh Warrier unsigned long t_reject, t_check_resend; 925bc5ad3f3SBenjamin Herrenschmidt 926bc5ad3f3SBenjamin Herrenschmidt if (!kvm) 927bc5ad3f3SBenjamin Herrenschmidt return 0; 928bc5ad3f3SBenjamin Herrenschmidt 929878610feSSuresh E. Warrier t_rm_kick_vcpu = 0; 930878610feSSuresh E. Warrier t_rm_notify_eoi = 0; 931878610feSSuresh E. Warrier t_rm_check_resend = 0; 9326e0365b7SSuresh Warrier t_check_resend = 0; 9336e0365b7SSuresh Warrier t_reject = 0; 934878610feSSuresh E. Warrier 935af893c7dSSuresh Warrier xics_debugfs_irqmap(m, kvm->arch.pimap); 936af893c7dSSuresh Warrier 937bc5ad3f3SBenjamin Herrenschmidt seq_printf(m, "=========\nICP state\n=========\n"); 938bc5ad3f3SBenjamin Herrenschmidt 939bc5ad3f3SBenjamin Herrenschmidt kvm_for_each_vcpu(i, vcpu, kvm) { 940bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_icp *icp = vcpu->arch.icp; 941bc5ad3f3SBenjamin Herrenschmidt union kvmppc_icp_state state; 942bc5ad3f3SBenjamin Herrenschmidt 943bc5ad3f3SBenjamin Herrenschmidt if (!icp) 944bc5ad3f3SBenjamin Herrenschmidt continue; 945bc5ad3f3SBenjamin Herrenschmidt 9465ee07612SChristian Borntraeger state.raw = READ_ONCE(icp->state.raw); 947bc5ad3f3SBenjamin Herrenschmidt seq_printf(m, "cpu server %#lx XIRR:%#x PPRI:%#x CPPR:%#x MFRR:%#x OUT:%d NR:%d\n", 948bc5ad3f3SBenjamin Herrenschmidt icp->server_num, state.xisr, 949bc5ad3f3SBenjamin Herrenschmidt state.pending_pri, state.cppr, state.mfrr, 950bc5ad3f3SBenjamin Herrenschmidt state.out_ee, state.need_resend); 951878610feSSuresh E. Warrier t_rm_kick_vcpu += icp->n_rm_kick_vcpu; 952878610feSSuresh E. Warrier t_rm_notify_eoi += icp->n_rm_notify_eoi; 953878610feSSuresh E. Warrier t_rm_check_resend += icp->n_rm_check_resend; 9546e0365b7SSuresh Warrier t_check_resend += icp->n_check_resend; 9556e0365b7SSuresh Warrier t_reject += icp->n_reject; 956bc5ad3f3SBenjamin Herrenschmidt } 957bc5ad3f3SBenjamin Herrenschmidt 9585efa6605SLi Zhong seq_printf(m, "ICP Guest->Host totals: kick_vcpu=%lu check_resend=%lu notify_eoi=%lu\n", 959878610feSSuresh E. Warrier t_rm_kick_vcpu, t_rm_check_resend, 9605efa6605SLi Zhong t_rm_notify_eoi); 9616e0365b7SSuresh Warrier seq_printf(m, "ICP Real Mode totals: check_resend=%lu resend=%lu\n", 9626e0365b7SSuresh Warrier t_check_resend, t_reject); 963bc5ad3f3SBenjamin Herrenschmidt for (icsid = 0; icsid <= KVMPPC_XICS_MAX_ICS_ID; icsid++) { 964bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_ics *ics = xics->ics[icsid]; 965bc5ad3f3SBenjamin Herrenschmidt 966bc5ad3f3SBenjamin Herrenschmidt if (!ics) 967bc5ad3f3SBenjamin Herrenschmidt continue; 968bc5ad3f3SBenjamin Herrenschmidt 969bc5ad3f3SBenjamin Herrenschmidt seq_printf(m, "=========\nICS state for ICS 0x%x\n=========\n", 970bc5ad3f3SBenjamin Herrenschmidt icsid); 971bc5ad3f3SBenjamin Herrenschmidt 97234cb7954SSuresh Warrier local_irq_save(flags); 97334cb7954SSuresh Warrier arch_spin_lock(&ics->lock); 974bc5ad3f3SBenjamin Herrenschmidt 975bc5ad3f3SBenjamin Herrenschmidt for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) { 976bc5ad3f3SBenjamin Herrenschmidt struct ics_irq_state *irq = &ics->irq_state[i]; 977bc5ad3f3SBenjamin Herrenschmidt 978bc5ad3f3SBenjamin Herrenschmidt seq_printf(m, "irq 0x%06x: server %#x prio %#x save prio %#x asserted %d resend %d masked pending %d\n", 979bc5ad3f3SBenjamin Herrenschmidt irq->number, irq->server, irq->priority, 980bc5ad3f3SBenjamin Herrenschmidt irq->saved_priority, irq->asserted, 981bc5ad3f3SBenjamin Herrenschmidt irq->resend, irq->masked_pending); 982bc5ad3f3SBenjamin Herrenschmidt 983bc5ad3f3SBenjamin Herrenschmidt } 98434cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 98534cb7954SSuresh Warrier local_irq_restore(flags); 986bc5ad3f3SBenjamin Herrenschmidt } 987bc5ad3f3SBenjamin Herrenschmidt return 0; 988bc5ad3f3SBenjamin Herrenschmidt } 989bc5ad3f3SBenjamin Herrenschmidt 990bc5ad3f3SBenjamin Herrenschmidt static int xics_debug_open(struct inode *inode, struct file *file) 991bc5ad3f3SBenjamin Herrenschmidt { 992bc5ad3f3SBenjamin Herrenschmidt return single_open(file, xics_debug_show, inode->i_private); 993bc5ad3f3SBenjamin Herrenschmidt } 994bc5ad3f3SBenjamin Herrenschmidt 995bc5ad3f3SBenjamin Herrenschmidt static const struct file_operations xics_debug_fops = { 996bc5ad3f3SBenjamin Herrenschmidt .open = xics_debug_open, 997bc5ad3f3SBenjamin Herrenschmidt .read = seq_read, 998bc5ad3f3SBenjamin Herrenschmidt .llseek = seq_lseek, 999bc5ad3f3SBenjamin Herrenschmidt .release = single_release, 1000bc5ad3f3SBenjamin Herrenschmidt }; 1001bc5ad3f3SBenjamin Herrenschmidt 1002bc5ad3f3SBenjamin Herrenschmidt static void xics_debugfs_init(struct kvmppc_xics *xics) 1003bc5ad3f3SBenjamin Herrenschmidt { 1004bc5ad3f3SBenjamin Herrenschmidt char *name; 1005bc5ad3f3SBenjamin Herrenschmidt 1006bc5ad3f3SBenjamin Herrenschmidt name = kasprintf(GFP_KERNEL, "kvm-xics-%p", xics); 1007bc5ad3f3SBenjamin Herrenschmidt if (!name) { 1008bc5ad3f3SBenjamin Herrenschmidt pr_err("%s: no memory for name\n", __func__); 1009bc5ad3f3SBenjamin Herrenschmidt return; 1010bc5ad3f3SBenjamin Herrenschmidt } 1011bc5ad3f3SBenjamin Herrenschmidt 1012bc5ad3f3SBenjamin Herrenschmidt xics->dentry = debugfs_create_file(name, S_IRUGO, powerpc_debugfs_root, 1013bc5ad3f3SBenjamin Herrenschmidt xics, &xics_debug_fops); 1014bc5ad3f3SBenjamin Herrenschmidt 1015bc5ad3f3SBenjamin Herrenschmidt pr_debug("%s: created %s\n", __func__, name); 1016bc5ad3f3SBenjamin Herrenschmidt kfree(name); 1017bc5ad3f3SBenjamin Herrenschmidt } 1018bc5ad3f3SBenjamin Herrenschmidt 10195975a2e0SPaul Mackerras static struct kvmppc_ics *kvmppc_xics_create_ics(struct kvm *kvm, 1020bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_xics *xics, int irq) 1021bc5ad3f3SBenjamin Herrenschmidt { 1022bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_ics *ics; 1023bc5ad3f3SBenjamin Herrenschmidt int i, icsid; 1024bc5ad3f3SBenjamin Herrenschmidt 1025bc5ad3f3SBenjamin Herrenschmidt icsid = irq >> KVMPPC_XICS_ICS_SHIFT; 1026bc5ad3f3SBenjamin Herrenschmidt 1027bc5ad3f3SBenjamin Herrenschmidt mutex_lock(&kvm->lock); 1028bc5ad3f3SBenjamin Herrenschmidt 1029bc5ad3f3SBenjamin Herrenschmidt /* ICS already exists - somebody else got here first */ 1030bc5ad3f3SBenjamin Herrenschmidt if (xics->ics[icsid]) 1031bc5ad3f3SBenjamin Herrenschmidt goto out; 1032bc5ad3f3SBenjamin Herrenschmidt 1033bc5ad3f3SBenjamin Herrenschmidt /* Create the ICS */ 1034bc5ad3f3SBenjamin Herrenschmidt ics = kzalloc(sizeof(struct kvmppc_ics), GFP_KERNEL); 1035bc5ad3f3SBenjamin Herrenschmidt if (!ics) 1036bc5ad3f3SBenjamin Herrenschmidt goto out; 1037bc5ad3f3SBenjamin Herrenschmidt 1038bc5ad3f3SBenjamin Herrenschmidt ics->icsid = icsid; 1039bc5ad3f3SBenjamin Herrenschmidt 1040bc5ad3f3SBenjamin Herrenschmidt for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) { 1041bc5ad3f3SBenjamin Herrenschmidt ics->irq_state[i].number = (icsid << KVMPPC_XICS_ICS_SHIFT) | i; 1042bc5ad3f3SBenjamin Herrenschmidt ics->irq_state[i].priority = MASKED; 1043bc5ad3f3SBenjamin Herrenschmidt ics->irq_state[i].saved_priority = MASKED; 1044bc5ad3f3SBenjamin Herrenschmidt } 1045bc5ad3f3SBenjamin Herrenschmidt smp_wmb(); 1046bc5ad3f3SBenjamin Herrenschmidt xics->ics[icsid] = ics; 1047bc5ad3f3SBenjamin Herrenschmidt 1048bc5ad3f3SBenjamin Herrenschmidt if (icsid > xics->max_icsid) 1049bc5ad3f3SBenjamin Herrenschmidt xics->max_icsid = icsid; 1050bc5ad3f3SBenjamin Herrenschmidt 1051bc5ad3f3SBenjamin Herrenschmidt out: 1052bc5ad3f3SBenjamin Herrenschmidt mutex_unlock(&kvm->lock); 1053bc5ad3f3SBenjamin Herrenschmidt return xics->ics[icsid]; 1054bc5ad3f3SBenjamin Herrenschmidt } 1055bc5ad3f3SBenjamin Herrenschmidt 1056bc5ad3f3SBenjamin Herrenschmidt int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server_num) 1057bc5ad3f3SBenjamin Herrenschmidt { 1058bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_icp *icp; 1059bc5ad3f3SBenjamin Herrenschmidt 1060bc5ad3f3SBenjamin Herrenschmidt if (!vcpu->kvm->arch.xics) 1061bc5ad3f3SBenjamin Herrenschmidt return -ENODEV; 1062bc5ad3f3SBenjamin Herrenschmidt 1063bc5ad3f3SBenjamin Herrenschmidt if (kvmppc_xics_find_server(vcpu->kvm, server_num)) 1064bc5ad3f3SBenjamin Herrenschmidt return -EEXIST; 1065bc5ad3f3SBenjamin Herrenschmidt 1066bc5ad3f3SBenjamin Herrenschmidt icp = kzalloc(sizeof(struct kvmppc_icp), GFP_KERNEL); 1067bc5ad3f3SBenjamin Herrenschmidt if (!icp) 1068bc5ad3f3SBenjamin Herrenschmidt return -ENOMEM; 1069bc5ad3f3SBenjamin Herrenschmidt 1070bc5ad3f3SBenjamin Herrenschmidt icp->vcpu = vcpu; 1071bc5ad3f3SBenjamin Herrenschmidt icp->server_num = server_num; 1072bc5ad3f3SBenjamin Herrenschmidt icp->state.mfrr = MASKED; 1073bc5ad3f3SBenjamin Herrenschmidt icp->state.pending_pri = MASKED; 1074bc5ad3f3SBenjamin Herrenschmidt vcpu->arch.icp = icp; 1075bc5ad3f3SBenjamin Herrenschmidt 1076bc5ad3f3SBenjamin Herrenschmidt XICS_DBG("created server for vcpu %d\n", vcpu->vcpu_id); 1077bc5ad3f3SBenjamin Herrenschmidt 1078bc5ad3f3SBenjamin Herrenschmidt return 0; 1079bc5ad3f3SBenjamin Herrenschmidt } 1080bc5ad3f3SBenjamin Herrenschmidt 10818b78645cSPaul Mackerras u64 kvmppc_xics_get_icp(struct kvm_vcpu *vcpu) 10828b78645cSPaul Mackerras { 10838b78645cSPaul Mackerras struct kvmppc_icp *icp = vcpu->arch.icp; 10848b78645cSPaul Mackerras union kvmppc_icp_state state; 10858b78645cSPaul Mackerras 10868b78645cSPaul Mackerras if (!icp) 10878b78645cSPaul Mackerras return 0; 10888b78645cSPaul Mackerras state = icp->state; 10898b78645cSPaul Mackerras return ((u64)state.cppr << KVM_REG_PPC_ICP_CPPR_SHIFT) | 10908b78645cSPaul Mackerras ((u64)state.xisr << KVM_REG_PPC_ICP_XISR_SHIFT) | 10918b78645cSPaul Mackerras ((u64)state.mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) | 10928b78645cSPaul Mackerras ((u64)state.pending_pri << KVM_REG_PPC_ICP_PPRI_SHIFT); 10938b78645cSPaul Mackerras } 10948b78645cSPaul Mackerras 10958b78645cSPaul Mackerras int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval) 10968b78645cSPaul Mackerras { 10978b78645cSPaul Mackerras struct kvmppc_icp *icp = vcpu->arch.icp; 10988b78645cSPaul Mackerras struct kvmppc_xics *xics = vcpu->kvm->arch.xics; 10998b78645cSPaul Mackerras union kvmppc_icp_state old_state, new_state; 11008b78645cSPaul Mackerras struct kvmppc_ics *ics; 11018b78645cSPaul Mackerras u8 cppr, mfrr, pending_pri; 11028b78645cSPaul Mackerras u32 xisr; 11038b78645cSPaul Mackerras u16 src; 11048b78645cSPaul Mackerras bool resend; 11058b78645cSPaul Mackerras 11068b78645cSPaul Mackerras if (!icp || !xics) 11078b78645cSPaul Mackerras return -ENOENT; 11088b78645cSPaul Mackerras 11098b78645cSPaul Mackerras cppr = icpval >> KVM_REG_PPC_ICP_CPPR_SHIFT; 11108b78645cSPaul Mackerras xisr = (icpval >> KVM_REG_PPC_ICP_XISR_SHIFT) & 11118b78645cSPaul Mackerras KVM_REG_PPC_ICP_XISR_MASK; 11128b78645cSPaul Mackerras mfrr = icpval >> KVM_REG_PPC_ICP_MFRR_SHIFT; 11138b78645cSPaul Mackerras pending_pri = icpval >> KVM_REG_PPC_ICP_PPRI_SHIFT; 11148b78645cSPaul Mackerras 11158b78645cSPaul Mackerras /* Require the new state to be internally consistent */ 11168b78645cSPaul Mackerras if (xisr == 0) { 11178b78645cSPaul Mackerras if (pending_pri != 0xff) 11188b78645cSPaul Mackerras return -EINVAL; 11198b78645cSPaul Mackerras } else if (xisr == XICS_IPI) { 11208b78645cSPaul Mackerras if (pending_pri != mfrr || pending_pri >= cppr) 11218b78645cSPaul Mackerras return -EINVAL; 11228b78645cSPaul Mackerras } else { 11238b78645cSPaul Mackerras if (pending_pri >= mfrr || pending_pri >= cppr) 11248b78645cSPaul Mackerras return -EINVAL; 11258b78645cSPaul Mackerras ics = kvmppc_xics_find_ics(xics, xisr, &src); 11268b78645cSPaul Mackerras if (!ics) 11278b78645cSPaul Mackerras return -EINVAL; 11288b78645cSPaul Mackerras } 11298b78645cSPaul Mackerras 11308b78645cSPaul Mackerras new_state.raw = 0; 11318b78645cSPaul Mackerras new_state.cppr = cppr; 11328b78645cSPaul Mackerras new_state.xisr = xisr; 11338b78645cSPaul Mackerras new_state.mfrr = mfrr; 11348b78645cSPaul Mackerras new_state.pending_pri = pending_pri; 11358b78645cSPaul Mackerras 11368b78645cSPaul Mackerras /* 11378b78645cSPaul Mackerras * Deassert the CPU interrupt request. 11388b78645cSPaul Mackerras * icp_try_update will reassert it if necessary. 11398b78645cSPaul Mackerras */ 11408b78645cSPaul Mackerras kvmppc_book3s_dequeue_irqprio(icp->vcpu, 11418b78645cSPaul Mackerras BOOK3S_INTERRUPT_EXTERNAL_LEVEL); 11428b78645cSPaul Mackerras 11438b78645cSPaul Mackerras /* 11448b78645cSPaul Mackerras * Note that if we displace an interrupt from old_state.xisr, 11458b78645cSPaul Mackerras * we don't mark it as rejected. We expect userspace to set 11468b78645cSPaul Mackerras * the state of the interrupt sources to be consistent with 11478b78645cSPaul Mackerras * the ICP states (either before or afterwards, which doesn't 11488b78645cSPaul Mackerras * matter). We do handle resends due to CPPR becoming less 11498b78645cSPaul Mackerras * favoured because that is necessary to end up with a 11508b78645cSPaul Mackerras * consistent state in the situation where userspace restores 11518b78645cSPaul Mackerras * the ICS states before the ICP states. 11528b78645cSPaul Mackerras */ 11538b78645cSPaul Mackerras do { 11545ee07612SChristian Borntraeger old_state = READ_ONCE(icp->state); 11558b78645cSPaul Mackerras 11568b78645cSPaul Mackerras if (new_state.mfrr <= old_state.mfrr) { 11578b78645cSPaul Mackerras resend = false; 11588b78645cSPaul Mackerras new_state.need_resend = old_state.need_resend; 11598b78645cSPaul Mackerras } else { 11608b78645cSPaul Mackerras resend = old_state.need_resend; 11618b78645cSPaul Mackerras new_state.need_resend = 0; 11628b78645cSPaul Mackerras } 11638b78645cSPaul Mackerras } while (!icp_try_update(icp, old_state, new_state, false)); 11648b78645cSPaul Mackerras 11658b78645cSPaul Mackerras if (resend) 11668b78645cSPaul Mackerras icp_check_resend(xics, icp); 11678b78645cSPaul Mackerras 11688b78645cSPaul Mackerras return 0; 11698b78645cSPaul Mackerras } 11708b78645cSPaul Mackerras 11715975a2e0SPaul Mackerras static int xics_get_source(struct kvmppc_xics *xics, long irq, u64 addr) 1172bc5ad3f3SBenjamin Herrenschmidt { 11735975a2e0SPaul Mackerras int ret; 11745975a2e0SPaul Mackerras struct kvmppc_ics *ics; 11755975a2e0SPaul Mackerras struct ics_irq_state *irqp; 11765975a2e0SPaul Mackerras u64 __user *ubufp = (u64 __user *) addr; 11775975a2e0SPaul Mackerras u16 idx; 11785975a2e0SPaul Mackerras u64 val, prio; 117934cb7954SSuresh Warrier unsigned long flags; 1180bc5ad3f3SBenjamin Herrenschmidt 11815975a2e0SPaul Mackerras ics = kvmppc_xics_find_ics(xics, irq, &idx); 11825975a2e0SPaul Mackerras if (!ics) 11835975a2e0SPaul Mackerras return -ENOENT; 1184bc5ad3f3SBenjamin Herrenschmidt 11855975a2e0SPaul Mackerras irqp = &ics->irq_state[idx]; 118634cb7954SSuresh Warrier local_irq_save(flags); 118734cb7954SSuresh Warrier arch_spin_lock(&ics->lock); 11885975a2e0SPaul Mackerras ret = -ENOENT; 11895975a2e0SPaul Mackerras if (irqp->exists) { 11905975a2e0SPaul Mackerras val = irqp->server; 11915975a2e0SPaul Mackerras prio = irqp->priority; 11925975a2e0SPaul Mackerras if (prio == MASKED) { 11935975a2e0SPaul Mackerras val |= KVM_XICS_MASKED; 11945975a2e0SPaul Mackerras prio = irqp->saved_priority; 11955975a2e0SPaul Mackerras } 11965975a2e0SPaul Mackerras val |= prio << KVM_XICS_PRIORITY_SHIFT; 1197b1a4286bSPaul Mackerras if (irqp->lsi) { 1198b1a4286bSPaul Mackerras val |= KVM_XICS_LEVEL_SENSITIVE; 11995975a2e0SPaul Mackerras if (irqp->asserted) 1200b1a4286bSPaul Mackerras val |= KVM_XICS_PENDING; 1201b1a4286bSPaul Mackerras } else if (irqp->masked_pending || irqp->resend) 12025975a2e0SPaul Mackerras val |= KVM_XICS_PENDING; 12035975a2e0SPaul Mackerras ret = 0; 12045975a2e0SPaul Mackerras } 120534cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 120634cb7954SSuresh Warrier local_irq_restore(flags); 1207bc5ad3f3SBenjamin Herrenschmidt 12085975a2e0SPaul Mackerras if (!ret && put_user(val, ubufp)) 12095975a2e0SPaul Mackerras ret = -EFAULT; 12105975a2e0SPaul Mackerras 12115975a2e0SPaul Mackerras return ret; 12125975a2e0SPaul Mackerras } 12135975a2e0SPaul Mackerras 12145975a2e0SPaul Mackerras static int xics_set_source(struct kvmppc_xics *xics, long irq, u64 addr) 12155975a2e0SPaul Mackerras { 12165975a2e0SPaul Mackerras struct kvmppc_ics *ics; 12175975a2e0SPaul Mackerras struct ics_irq_state *irqp; 12185975a2e0SPaul Mackerras u64 __user *ubufp = (u64 __user *) addr; 12195975a2e0SPaul Mackerras u16 idx; 12205975a2e0SPaul Mackerras u64 val; 12215975a2e0SPaul Mackerras u8 prio; 12225975a2e0SPaul Mackerras u32 server; 122334cb7954SSuresh Warrier unsigned long flags; 12245975a2e0SPaul Mackerras 12255975a2e0SPaul Mackerras if (irq < KVMPPC_XICS_FIRST_IRQ || irq >= KVMPPC_XICS_NR_IRQS) 12265975a2e0SPaul Mackerras return -ENOENT; 12275975a2e0SPaul Mackerras 12285975a2e0SPaul Mackerras ics = kvmppc_xics_find_ics(xics, irq, &idx); 12295975a2e0SPaul Mackerras if (!ics) { 12305975a2e0SPaul Mackerras ics = kvmppc_xics_create_ics(xics->kvm, xics, irq); 12315975a2e0SPaul Mackerras if (!ics) 12325975a2e0SPaul Mackerras return -ENOMEM; 12335975a2e0SPaul Mackerras } 12345975a2e0SPaul Mackerras irqp = &ics->irq_state[idx]; 12355975a2e0SPaul Mackerras if (get_user(val, ubufp)) 12365975a2e0SPaul Mackerras return -EFAULT; 12375975a2e0SPaul Mackerras 12385975a2e0SPaul Mackerras server = val & KVM_XICS_DESTINATION_MASK; 12395975a2e0SPaul Mackerras prio = val >> KVM_XICS_PRIORITY_SHIFT; 12405975a2e0SPaul Mackerras if (prio != MASKED && 12415975a2e0SPaul Mackerras kvmppc_xics_find_server(xics->kvm, server) == NULL) 12425975a2e0SPaul Mackerras return -EINVAL; 12435975a2e0SPaul Mackerras 124434cb7954SSuresh Warrier local_irq_save(flags); 124534cb7954SSuresh Warrier arch_spin_lock(&ics->lock); 12465975a2e0SPaul Mackerras irqp->server = server; 12475975a2e0SPaul Mackerras irqp->saved_priority = prio; 12485975a2e0SPaul Mackerras if (val & KVM_XICS_MASKED) 12495975a2e0SPaul Mackerras prio = MASKED; 12505975a2e0SPaul Mackerras irqp->priority = prio; 12515975a2e0SPaul Mackerras irqp->resend = 0; 12525975a2e0SPaul Mackerras irqp->masked_pending = 0; 1253b1a4286bSPaul Mackerras irqp->lsi = 0; 12545975a2e0SPaul Mackerras irqp->asserted = 0; 1255b1a4286bSPaul Mackerras if (val & KVM_XICS_LEVEL_SENSITIVE) { 1256b1a4286bSPaul Mackerras irqp->lsi = 1; 1257b1a4286bSPaul Mackerras if (val & KVM_XICS_PENDING) 12585975a2e0SPaul Mackerras irqp->asserted = 1; 1259b1a4286bSPaul Mackerras } 12605975a2e0SPaul Mackerras irqp->exists = 1; 126134cb7954SSuresh Warrier arch_spin_unlock(&ics->lock); 126234cb7954SSuresh Warrier local_irq_restore(flags); 12635975a2e0SPaul Mackerras 12645975a2e0SPaul Mackerras if (val & KVM_XICS_PENDING) 12655975a2e0SPaul Mackerras icp_deliver_irq(xics, NULL, irqp->number); 12665975a2e0SPaul Mackerras 12675975a2e0SPaul Mackerras return 0; 12685975a2e0SPaul Mackerras } 12695975a2e0SPaul Mackerras 12705975a2e0SPaul Mackerras int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, 12715975a2e0SPaul Mackerras bool line_status) 12725975a2e0SPaul Mackerras { 12735975a2e0SPaul Mackerras struct kvmppc_xics *xics = kvm->arch.xics; 12745975a2e0SPaul Mackerras 1275e48ba1cbSPaul Mackerras if (!xics) 1276e48ba1cbSPaul Mackerras return -ENODEV; 127725a2150bSPaul Mackerras return ics_deliver_irq(xics, irq, level); 127825a2150bSPaul Mackerras } 127925a2150bSPaul Mackerras 1280b1a4286bSPaul Mackerras int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *irq_entry, 1281b1a4286bSPaul Mackerras struct kvm *kvm, int irq_source_id, 1282b1a4286bSPaul Mackerras int level, bool line_status) 128325a2150bSPaul Mackerras { 128425a2150bSPaul Mackerras return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi, 128525a2150bSPaul Mackerras level, line_status); 12865975a2e0SPaul Mackerras } 12875975a2e0SPaul Mackerras 12885975a2e0SPaul Mackerras static int xics_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 12895975a2e0SPaul Mackerras { 12905975a2e0SPaul Mackerras struct kvmppc_xics *xics = dev->private; 12915975a2e0SPaul Mackerras 12925975a2e0SPaul Mackerras switch (attr->group) { 12935975a2e0SPaul Mackerras case KVM_DEV_XICS_GRP_SOURCES: 12945975a2e0SPaul Mackerras return xics_set_source(xics, attr->attr, attr->addr); 12955975a2e0SPaul Mackerras } 12965975a2e0SPaul Mackerras return -ENXIO; 12975975a2e0SPaul Mackerras } 12985975a2e0SPaul Mackerras 12995975a2e0SPaul Mackerras static int xics_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 13005975a2e0SPaul Mackerras { 13015975a2e0SPaul Mackerras struct kvmppc_xics *xics = dev->private; 13025975a2e0SPaul Mackerras 13035975a2e0SPaul Mackerras switch (attr->group) { 13045975a2e0SPaul Mackerras case KVM_DEV_XICS_GRP_SOURCES: 13055975a2e0SPaul Mackerras return xics_get_source(xics, attr->attr, attr->addr); 13065975a2e0SPaul Mackerras } 13075975a2e0SPaul Mackerras return -ENXIO; 13085975a2e0SPaul Mackerras } 13095975a2e0SPaul Mackerras 13105975a2e0SPaul Mackerras static int xics_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 13115975a2e0SPaul Mackerras { 13125975a2e0SPaul Mackerras switch (attr->group) { 13135975a2e0SPaul Mackerras case KVM_DEV_XICS_GRP_SOURCES: 13145975a2e0SPaul Mackerras if (attr->attr >= KVMPPC_XICS_FIRST_IRQ && 13155975a2e0SPaul Mackerras attr->attr < KVMPPC_XICS_NR_IRQS) 13165975a2e0SPaul Mackerras return 0; 1317bc5ad3f3SBenjamin Herrenschmidt break; 13185975a2e0SPaul Mackerras } 13195975a2e0SPaul Mackerras return -ENXIO; 1320bc5ad3f3SBenjamin Herrenschmidt } 1321bc5ad3f3SBenjamin Herrenschmidt 13225975a2e0SPaul Mackerras static void kvmppc_xics_free(struct kvm_device *dev) 1323bc5ad3f3SBenjamin Herrenschmidt { 13245975a2e0SPaul Mackerras struct kvmppc_xics *xics = dev->private; 1325bc5ad3f3SBenjamin Herrenschmidt int i; 1326bc5ad3f3SBenjamin Herrenschmidt struct kvm *kvm = xics->kvm; 1327bc5ad3f3SBenjamin Herrenschmidt 1328bc5ad3f3SBenjamin Herrenschmidt debugfs_remove(xics->dentry); 1329bc5ad3f3SBenjamin Herrenschmidt 1330bc5ad3f3SBenjamin Herrenschmidt if (kvm) 1331bc5ad3f3SBenjamin Herrenschmidt kvm->arch.xics = NULL; 1332bc5ad3f3SBenjamin Herrenschmidt 1333bc5ad3f3SBenjamin Herrenschmidt for (i = 0; i <= xics->max_icsid; i++) 1334bc5ad3f3SBenjamin Herrenschmidt kfree(xics->ics[i]); 1335bc5ad3f3SBenjamin Herrenschmidt kfree(xics); 13365975a2e0SPaul Mackerras kfree(dev); 1337bc5ad3f3SBenjamin Herrenschmidt } 1338bc5ad3f3SBenjamin Herrenschmidt 13395975a2e0SPaul Mackerras static int kvmppc_xics_create(struct kvm_device *dev, u32 type) 1340bc5ad3f3SBenjamin Herrenschmidt { 1341bc5ad3f3SBenjamin Herrenschmidt struct kvmppc_xics *xics; 13425975a2e0SPaul Mackerras struct kvm *kvm = dev->kvm; 1343bc5ad3f3SBenjamin Herrenschmidt int ret = 0; 1344bc5ad3f3SBenjamin Herrenschmidt 1345bc5ad3f3SBenjamin Herrenschmidt xics = kzalloc(sizeof(*xics), GFP_KERNEL); 1346bc5ad3f3SBenjamin Herrenschmidt if (!xics) 1347bc5ad3f3SBenjamin Herrenschmidt return -ENOMEM; 1348bc5ad3f3SBenjamin Herrenschmidt 13495975a2e0SPaul Mackerras dev->private = xics; 13505975a2e0SPaul Mackerras xics->dev = dev; 1351bc5ad3f3SBenjamin Herrenschmidt xics->kvm = kvm; 1352bc5ad3f3SBenjamin Herrenschmidt 1353bc5ad3f3SBenjamin Herrenschmidt /* Already there ? */ 1354bc5ad3f3SBenjamin Herrenschmidt if (kvm->arch.xics) 1355bc5ad3f3SBenjamin Herrenschmidt ret = -EEXIST; 1356bc5ad3f3SBenjamin Herrenschmidt else 1357bc5ad3f3SBenjamin Herrenschmidt kvm->arch.xics = xics; 1358bc5ad3f3SBenjamin Herrenschmidt 1359458ff3c0SGleb Natapov if (ret) { 1360458ff3c0SGleb Natapov kfree(xics); 1361bc5ad3f3SBenjamin Herrenschmidt return ret; 1362458ff3c0SGleb Natapov } 1363bc5ad3f3SBenjamin Herrenschmidt 13643a167beaSAneesh Kumar K.V #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 1365e7d26f28SBenjamin Herrenschmidt if (cpu_has_feature(CPU_FTR_ARCH_206)) { 1366e7d26f28SBenjamin Herrenschmidt /* Enable real mode support */ 1367e7d26f28SBenjamin Herrenschmidt xics->real_mode = ENABLE_REALMODE; 1368e7d26f28SBenjamin Herrenschmidt xics->real_mode_dbg = DEBUG_REALMODE; 1369e7d26f28SBenjamin Herrenschmidt } 13703a167beaSAneesh Kumar K.V #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ 1371e7d26f28SBenjamin Herrenschmidt 1372bc5ad3f3SBenjamin Herrenschmidt return 0; 1373bc5ad3f3SBenjamin Herrenschmidt } 1374bc5ad3f3SBenjamin Herrenschmidt 1375023e9fddSChristoffer Dall static void kvmppc_xics_init(struct kvm_device *dev) 1376023e9fddSChristoffer Dall { 1377023e9fddSChristoffer Dall struct kvmppc_xics *xics = (struct kvmppc_xics *)dev->private; 1378023e9fddSChristoffer Dall 1379023e9fddSChristoffer Dall xics_debugfs_init(xics); 1380023e9fddSChristoffer Dall } 1381023e9fddSChristoffer Dall 13825975a2e0SPaul Mackerras struct kvm_device_ops kvm_xics_ops = { 13835975a2e0SPaul Mackerras .name = "kvm-xics", 13845975a2e0SPaul Mackerras .create = kvmppc_xics_create, 1385023e9fddSChristoffer Dall .init = kvmppc_xics_init, 13865975a2e0SPaul Mackerras .destroy = kvmppc_xics_free, 13875975a2e0SPaul Mackerras .set_attr = xics_set_attr, 13885975a2e0SPaul Mackerras .get_attr = xics_get_attr, 13895975a2e0SPaul Mackerras .has_attr = xics_has_attr, 13905975a2e0SPaul Mackerras }; 13915975a2e0SPaul Mackerras 13925975a2e0SPaul Mackerras int kvmppc_xics_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu, 13935975a2e0SPaul Mackerras u32 xcpu) 13945975a2e0SPaul Mackerras { 13955975a2e0SPaul Mackerras struct kvmppc_xics *xics = dev->private; 13965975a2e0SPaul Mackerras int r = -EBUSY; 13975975a2e0SPaul Mackerras 13985975a2e0SPaul Mackerras if (dev->ops != &kvm_xics_ops) 13995975a2e0SPaul Mackerras return -EPERM; 14005975a2e0SPaul Mackerras if (xics->kvm != vcpu->kvm) 14015975a2e0SPaul Mackerras return -EPERM; 14025975a2e0SPaul Mackerras if (vcpu->arch.irq_type) 14035975a2e0SPaul Mackerras return -EBUSY; 14045975a2e0SPaul Mackerras 14055975a2e0SPaul Mackerras r = kvmppc_xics_create_icp(vcpu, xcpu); 14065975a2e0SPaul Mackerras if (!r) 14075975a2e0SPaul Mackerras vcpu->arch.irq_type = KVMPPC_IRQ_XICS; 14085975a2e0SPaul Mackerras 14095975a2e0SPaul Mackerras return r; 14105975a2e0SPaul Mackerras } 14115975a2e0SPaul Mackerras 1412bc5ad3f3SBenjamin Herrenschmidt void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) 1413bc5ad3f3SBenjamin Herrenschmidt { 1414bc5ad3f3SBenjamin Herrenschmidt if (!vcpu->arch.icp) 1415bc5ad3f3SBenjamin Herrenschmidt return; 1416bc5ad3f3SBenjamin Herrenschmidt kfree(vcpu->arch.icp); 1417bc5ad3f3SBenjamin Herrenschmidt vcpu->arch.icp = NULL; 1418bc5ad3f3SBenjamin Herrenschmidt vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT; 1419bc5ad3f3SBenjamin Herrenschmidt } 142025a2150bSPaul Mackerras 142125a2150bSPaul Mackerras static int xics_set_irq(struct kvm_kernel_irq_routing_entry *e, 142225a2150bSPaul Mackerras struct kvm *kvm, int irq_source_id, int level, 142325a2150bSPaul Mackerras bool line_status) 142425a2150bSPaul Mackerras { 142525a2150bSPaul Mackerras return kvm_set_irq(kvm, irq_source_id, e->gsi, level, line_status); 142625a2150bSPaul Mackerras } 142725a2150bSPaul Mackerras 142825a2150bSPaul Mackerras int kvm_irq_map_gsi(struct kvm *kvm, 142925a2150bSPaul Mackerras struct kvm_kernel_irq_routing_entry *entries, int gsi) 143025a2150bSPaul Mackerras { 143125a2150bSPaul Mackerras entries->gsi = gsi; 143225a2150bSPaul Mackerras entries->type = KVM_IRQ_ROUTING_IRQCHIP; 143325a2150bSPaul Mackerras entries->set = xics_set_irq; 143425a2150bSPaul Mackerras entries->irqchip.irqchip = 0; 143525a2150bSPaul Mackerras entries->irqchip.pin = gsi; 143625a2150bSPaul Mackerras return 1; 143725a2150bSPaul Mackerras } 143825a2150bSPaul Mackerras 143925a2150bSPaul Mackerras int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin) 144025a2150bSPaul Mackerras { 144125a2150bSPaul Mackerras return pin; 144225a2150bSPaul Mackerras } 14435d375199SPaul Mackerras 14445d375199SPaul Mackerras void kvmppc_xics_set_mapped(struct kvm *kvm, unsigned long irq, 14455d375199SPaul Mackerras unsigned long host_irq) 14465d375199SPaul Mackerras { 14475d375199SPaul Mackerras struct kvmppc_xics *xics = kvm->arch.xics; 14485d375199SPaul Mackerras struct kvmppc_ics *ics; 14495d375199SPaul Mackerras u16 idx; 14505d375199SPaul Mackerras 14515d375199SPaul Mackerras ics = kvmppc_xics_find_ics(xics, irq, &idx); 14525d375199SPaul Mackerras if (!ics) 14535d375199SPaul Mackerras return; 14545d375199SPaul Mackerras 14555d375199SPaul Mackerras ics->irq_state[idx].host_irq = host_irq; 14565d375199SPaul Mackerras ics->irq_state[idx].intr_cpu = -1; 14575d375199SPaul Mackerras } 14585d375199SPaul Mackerras EXPORT_SYMBOL_GPL(kvmppc_xics_set_mapped); 14595d375199SPaul Mackerras 14605d375199SPaul Mackerras void kvmppc_xics_clr_mapped(struct kvm *kvm, unsigned long irq, 14615d375199SPaul Mackerras unsigned long host_irq) 14625d375199SPaul Mackerras { 14635d375199SPaul Mackerras struct kvmppc_xics *xics = kvm->arch.xics; 14645d375199SPaul Mackerras struct kvmppc_ics *ics; 14655d375199SPaul Mackerras u16 idx; 14665d375199SPaul Mackerras 14675d375199SPaul Mackerras ics = kvmppc_xics_find_ics(xics, irq, &idx); 14685d375199SPaul Mackerras if (!ics) 14695d375199SPaul Mackerras return; 14705d375199SPaul Mackerras 14715d375199SPaul Mackerras ics->irq_state[idx].host_irq = 0; 14725d375199SPaul Mackerras } 14735d375199SPaul Mackerras EXPORT_SYMBOL_GPL(kvmppc_xics_clr_mapped); 1474