1*67730e6cSSean Christopherson // SPDX-License-Identifier: GPL-2.0 2*67730e6cSSean Christopherson /* 3*67730e6cSSean Christopherson * Guest ITS library, generously donated by drivers/irqchip/irq-gic-v3-its.c 4*67730e6cSSean Christopherson * over in the kernel tree. 5*67730e6cSSean Christopherson */ 6*67730e6cSSean Christopherson 7*67730e6cSSean Christopherson #include <linux/kvm.h> 8*67730e6cSSean Christopherson #include <linux/sizes.h> 9*67730e6cSSean Christopherson #include <asm/kvm_para.h> 10*67730e6cSSean Christopherson #include <asm/kvm.h> 11*67730e6cSSean Christopherson 12*67730e6cSSean Christopherson #include "kvm_util.h" 13*67730e6cSSean Christopherson #include "vgic.h" 14*67730e6cSSean Christopherson #include "gic.h" 15*67730e6cSSean Christopherson #include "gic_v3.h" 16*67730e6cSSean Christopherson #include "processor.h" 17*67730e6cSSean Christopherson 18*67730e6cSSean Christopherson static u64 its_read_u64(unsigned long offset) 19*67730e6cSSean Christopherson { 20*67730e6cSSean Christopherson return readq_relaxed(GITS_BASE_GVA + offset); 21*67730e6cSSean Christopherson } 22*67730e6cSSean Christopherson 23*67730e6cSSean Christopherson static void its_write_u64(unsigned long offset, u64 val) 24*67730e6cSSean Christopherson { 25*67730e6cSSean Christopherson writeq_relaxed(val, GITS_BASE_GVA + offset); 26*67730e6cSSean Christopherson } 27*67730e6cSSean Christopherson 28*67730e6cSSean Christopherson static u32 its_read_u32(unsigned long offset) 29*67730e6cSSean Christopherson { 30*67730e6cSSean Christopherson return readl_relaxed(GITS_BASE_GVA + offset); 31*67730e6cSSean Christopherson } 32*67730e6cSSean Christopherson 33*67730e6cSSean Christopherson static void its_write_u32(unsigned long offset, u32 val) 34*67730e6cSSean Christopherson { 35*67730e6cSSean Christopherson writel_relaxed(val, GITS_BASE_GVA + offset); 36*67730e6cSSean Christopherson } 37*67730e6cSSean Christopherson 38*67730e6cSSean Christopherson static unsigned long its_find_baser(unsigned int type) 39*67730e6cSSean Christopherson { 40*67730e6cSSean Christopherson int i; 41*67730e6cSSean Christopherson 42*67730e6cSSean Christopherson for (i = 0; i < GITS_BASER_NR_REGS; i++) { 43*67730e6cSSean Christopherson u64 baser; 44*67730e6cSSean Christopherson unsigned long offset = GITS_BASER + (i * sizeof(baser)); 45*67730e6cSSean Christopherson 46*67730e6cSSean Christopherson baser = its_read_u64(offset); 47*67730e6cSSean Christopherson if (GITS_BASER_TYPE(baser) == type) 48*67730e6cSSean Christopherson return offset; 49*67730e6cSSean Christopherson } 50*67730e6cSSean Christopherson 51*67730e6cSSean Christopherson GUEST_FAIL("Couldn't find an ITS BASER of type %u", type); 52*67730e6cSSean Christopherson return -1; 53*67730e6cSSean Christopherson } 54*67730e6cSSean Christopherson 55*67730e6cSSean Christopherson static void its_install_table(unsigned int type, vm_paddr_t base, size_t size) 56*67730e6cSSean Christopherson { 57*67730e6cSSean Christopherson unsigned long offset = its_find_baser(type); 58*67730e6cSSean Christopherson u64 baser; 59*67730e6cSSean Christopherson 60*67730e6cSSean Christopherson baser = ((size / SZ_64K) - 1) | 61*67730e6cSSean Christopherson GITS_BASER_PAGE_SIZE_64K | 62*67730e6cSSean Christopherson GITS_BASER_InnerShareable | 63*67730e6cSSean Christopherson base | 64*67730e6cSSean Christopherson GITS_BASER_RaWaWb | 65*67730e6cSSean Christopherson GITS_BASER_VALID; 66*67730e6cSSean Christopherson 67*67730e6cSSean Christopherson its_write_u64(offset, baser); 68*67730e6cSSean Christopherson } 69*67730e6cSSean Christopherson 70*67730e6cSSean Christopherson static void its_install_cmdq(vm_paddr_t base, size_t size) 71*67730e6cSSean Christopherson { 72*67730e6cSSean Christopherson u64 cbaser; 73*67730e6cSSean Christopherson 74*67730e6cSSean Christopherson cbaser = ((size / SZ_4K) - 1) | 75*67730e6cSSean Christopherson GITS_CBASER_InnerShareable | 76*67730e6cSSean Christopherson base | 77*67730e6cSSean Christopherson GITS_CBASER_RaWaWb | 78*67730e6cSSean Christopherson GITS_CBASER_VALID; 79*67730e6cSSean Christopherson 80*67730e6cSSean Christopherson its_write_u64(GITS_CBASER, cbaser); 81*67730e6cSSean Christopherson } 82*67730e6cSSean Christopherson 83*67730e6cSSean Christopherson void its_init(vm_paddr_t coll_tbl, size_t coll_tbl_sz, 84*67730e6cSSean Christopherson vm_paddr_t device_tbl, size_t device_tbl_sz, 85*67730e6cSSean Christopherson vm_paddr_t cmdq, size_t cmdq_size) 86*67730e6cSSean Christopherson { 87*67730e6cSSean Christopherson u32 ctlr; 88*67730e6cSSean Christopherson 89*67730e6cSSean Christopherson its_install_table(GITS_BASER_TYPE_COLLECTION, coll_tbl, coll_tbl_sz); 90*67730e6cSSean Christopherson its_install_table(GITS_BASER_TYPE_DEVICE, device_tbl, device_tbl_sz); 91*67730e6cSSean Christopherson its_install_cmdq(cmdq, cmdq_size); 92*67730e6cSSean Christopherson 93*67730e6cSSean Christopherson ctlr = its_read_u32(GITS_CTLR); 94*67730e6cSSean Christopherson ctlr |= GITS_CTLR_ENABLE; 95*67730e6cSSean Christopherson its_write_u32(GITS_CTLR, ctlr); 96*67730e6cSSean Christopherson } 97*67730e6cSSean Christopherson 98*67730e6cSSean Christopherson struct its_cmd_block { 99*67730e6cSSean Christopherson union { 100*67730e6cSSean Christopherson u64 raw_cmd[4]; 101*67730e6cSSean Christopherson __le64 raw_cmd_le[4]; 102*67730e6cSSean Christopherson }; 103*67730e6cSSean Christopherson }; 104*67730e6cSSean Christopherson 105*67730e6cSSean Christopherson static inline void its_fixup_cmd(struct its_cmd_block *cmd) 106*67730e6cSSean Christopherson { 107*67730e6cSSean Christopherson /* Let's fixup BE commands */ 108*67730e6cSSean Christopherson cmd->raw_cmd_le[0] = cpu_to_le64(cmd->raw_cmd[0]); 109*67730e6cSSean Christopherson cmd->raw_cmd_le[1] = cpu_to_le64(cmd->raw_cmd[1]); 110*67730e6cSSean Christopherson cmd->raw_cmd_le[2] = cpu_to_le64(cmd->raw_cmd[2]); 111*67730e6cSSean Christopherson cmd->raw_cmd_le[3] = cpu_to_le64(cmd->raw_cmd[3]); 112*67730e6cSSean Christopherson } 113*67730e6cSSean Christopherson 114*67730e6cSSean Christopherson static void its_mask_encode(u64 *raw_cmd, u64 val, int h, int l) 115*67730e6cSSean Christopherson { 116*67730e6cSSean Christopherson u64 mask = GENMASK_ULL(h, l); 117*67730e6cSSean Christopherson *raw_cmd &= ~mask; 118*67730e6cSSean Christopherson *raw_cmd |= (val << l) & mask; 119*67730e6cSSean Christopherson } 120*67730e6cSSean Christopherson 121*67730e6cSSean Christopherson static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr) 122*67730e6cSSean Christopherson { 123*67730e6cSSean Christopherson its_mask_encode(&cmd->raw_cmd[0], cmd_nr, 7, 0); 124*67730e6cSSean Christopherson } 125*67730e6cSSean Christopherson 126*67730e6cSSean Christopherson static void its_encode_devid(struct its_cmd_block *cmd, u32 devid) 127*67730e6cSSean Christopherson { 128*67730e6cSSean Christopherson its_mask_encode(&cmd->raw_cmd[0], devid, 63, 32); 129*67730e6cSSean Christopherson } 130*67730e6cSSean Christopherson 131*67730e6cSSean Christopherson static void its_encode_event_id(struct its_cmd_block *cmd, u32 id) 132*67730e6cSSean Christopherson { 133*67730e6cSSean Christopherson its_mask_encode(&cmd->raw_cmd[1], id, 31, 0); 134*67730e6cSSean Christopherson } 135*67730e6cSSean Christopherson 136*67730e6cSSean Christopherson static void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id) 137*67730e6cSSean Christopherson { 138*67730e6cSSean Christopherson its_mask_encode(&cmd->raw_cmd[1], phys_id, 63, 32); 139*67730e6cSSean Christopherson } 140*67730e6cSSean Christopherson 141*67730e6cSSean Christopherson static void its_encode_size(struct its_cmd_block *cmd, u8 size) 142*67730e6cSSean Christopherson { 143*67730e6cSSean Christopherson its_mask_encode(&cmd->raw_cmd[1], size, 4, 0); 144*67730e6cSSean Christopherson } 145*67730e6cSSean Christopherson 146*67730e6cSSean Christopherson static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr) 147*67730e6cSSean Christopherson { 148*67730e6cSSean Christopherson its_mask_encode(&cmd->raw_cmd[2], itt_addr >> 8, 51, 8); 149*67730e6cSSean Christopherson } 150*67730e6cSSean Christopherson 151*67730e6cSSean Christopherson static void its_encode_valid(struct its_cmd_block *cmd, int valid) 152*67730e6cSSean Christopherson { 153*67730e6cSSean Christopherson its_mask_encode(&cmd->raw_cmd[2], !!valid, 63, 63); 154*67730e6cSSean Christopherson } 155*67730e6cSSean Christopherson 156*67730e6cSSean Christopherson static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr) 157*67730e6cSSean Christopherson { 158*67730e6cSSean Christopherson its_mask_encode(&cmd->raw_cmd[2], target_addr >> 16, 51, 16); 159*67730e6cSSean Christopherson } 160*67730e6cSSean Christopherson 161*67730e6cSSean Christopherson static void its_encode_collection(struct its_cmd_block *cmd, u16 col) 162*67730e6cSSean Christopherson { 163*67730e6cSSean Christopherson its_mask_encode(&cmd->raw_cmd[2], col, 15, 0); 164*67730e6cSSean Christopherson } 165*67730e6cSSean Christopherson 166*67730e6cSSean Christopherson #define GITS_CMDQ_POLL_ITERATIONS 0 167*67730e6cSSean Christopherson 168*67730e6cSSean Christopherson static void its_send_cmd(void *cmdq_base, struct its_cmd_block *cmd) 169*67730e6cSSean Christopherson { 170*67730e6cSSean Christopherson u64 cwriter = its_read_u64(GITS_CWRITER); 171*67730e6cSSean Christopherson struct its_cmd_block *dst = cmdq_base + cwriter; 172*67730e6cSSean Christopherson u64 cbaser = its_read_u64(GITS_CBASER); 173*67730e6cSSean Christopherson size_t cmdq_size; 174*67730e6cSSean Christopherson u64 next; 175*67730e6cSSean Christopherson int i; 176*67730e6cSSean Christopherson 177*67730e6cSSean Christopherson cmdq_size = ((cbaser & 0xFF) + 1) * SZ_4K; 178*67730e6cSSean Christopherson 179*67730e6cSSean Christopherson its_fixup_cmd(cmd); 180*67730e6cSSean Christopherson 181*67730e6cSSean Christopherson WRITE_ONCE(*dst, *cmd); 182*67730e6cSSean Christopherson dsb(ishst); 183*67730e6cSSean Christopherson next = (cwriter + sizeof(*cmd)) % cmdq_size; 184*67730e6cSSean Christopherson its_write_u64(GITS_CWRITER, next); 185*67730e6cSSean Christopherson 186*67730e6cSSean Christopherson /* 187*67730e6cSSean Christopherson * Polling isn't necessary considering KVM's ITS emulation at the time 188*67730e6cSSean Christopherson * of writing this, as the CMDQ is processed synchronously after a write 189*67730e6cSSean Christopherson * to CWRITER. 190*67730e6cSSean Christopherson */ 191*67730e6cSSean Christopherson for (i = 0; its_read_u64(GITS_CREADR) != next; i++) { 192*67730e6cSSean Christopherson __GUEST_ASSERT(i < GITS_CMDQ_POLL_ITERATIONS, 193*67730e6cSSean Christopherson "ITS didn't process command at offset %lu after %d iterations\n", 194*67730e6cSSean Christopherson cwriter, i); 195*67730e6cSSean Christopherson 196*67730e6cSSean Christopherson cpu_relax(); 197*67730e6cSSean Christopherson } 198*67730e6cSSean Christopherson } 199*67730e6cSSean Christopherson 200*67730e6cSSean Christopherson void its_send_mapd_cmd(void *cmdq_base, u32 device_id, vm_paddr_t itt_base, 201*67730e6cSSean Christopherson size_t itt_size, bool valid) 202*67730e6cSSean Christopherson { 203*67730e6cSSean Christopherson struct its_cmd_block cmd = {}; 204*67730e6cSSean Christopherson 205*67730e6cSSean Christopherson its_encode_cmd(&cmd, GITS_CMD_MAPD); 206*67730e6cSSean Christopherson its_encode_devid(&cmd, device_id); 207*67730e6cSSean Christopherson its_encode_size(&cmd, ilog2(itt_size) - 1); 208*67730e6cSSean Christopherson its_encode_itt(&cmd, itt_base); 209*67730e6cSSean Christopherson its_encode_valid(&cmd, valid); 210*67730e6cSSean Christopherson 211*67730e6cSSean Christopherson its_send_cmd(cmdq_base, &cmd); 212*67730e6cSSean Christopherson } 213*67730e6cSSean Christopherson 214*67730e6cSSean Christopherson void its_send_mapc_cmd(void *cmdq_base, u32 vcpu_id, u32 collection_id, bool valid) 215*67730e6cSSean Christopherson { 216*67730e6cSSean Christopherson struct its_cmd_block cmd = {}; 217*67730e6cSSean Christopherson 218*67730e6cSSean Christopherson its_encode_cmd(&cmd, GITS_CMD_MAPC); 219*67730e6cSSean Christopherson its_encode_collection(&cmd, collection_id); 220*67730e6cSSean Christopherson its_encode_target(&cmd, vcpu_id); 221*67730e6cSSean Christopherson its_encode_valid(&cmd, valid); 222*67730e6cSSean Christopherson 223*67730e6cSSean Christopherson its_send_cmd(cmdq_base, &cmd); 224*67730e6cSSean Christopherson } 225*67730e6cSSean Christopherson 226*67730e6cSSean Christopherson void its_send_mapti_cmd(void *cmdq_base, u32 device_id, u32 event_id, 227*67730e6cSSean Christopherson u32 collection_id, u32 intid) 228*67730e6cSSean Christopherson { 229*67730e6cSSean Christopherson struct its_cmd_block cmd = {}; 230*67730e6cSSean Christopherson 231*67730e6cSSean Christopherson its_encode_cmd(&cmd, GITS_CMD_MAPTI); 232*67730e6cSSean Christopherson its_encode_devid(&cmd, device_id); 233*67730e6cSSean Christopherson its_encode_event_id(&cmd, event_id); 234*67730e6cSSean Christopherson its_encode_phys_id(&cmd, intid); 235*67730e6cSSean Christopherson its_encode_collection(&cmd, collection_id); 236*67730e6cSSean Christopherson 237*67730e6cSSean Christopherson its_send_cmd(cmdq_base, &cmd); 238*67730e6cSSean Christopherson } 239*67730e6cSSean Christopherson 240*67730e6cSSean Christopherson void its_send_invall_cmd(void *cmdq_base, u32 collection_id) 241*67730e6cSSean Christopherson { 242*67730e6cSSean Christopherson struct its_cmd_block cmd = {}; 243*67730e6cSSean Christopherson 244*67730e6cSSean Christopherson its_encode_cmd(&cmd, GITS_CMD_INVALL); 245*67730e6cSSean Christopherson its_encode_collection(&cmd, collection_id); 246*67730e6cSSean Christopherson 247*67730e6cSSean Christopherson its_send_cmd(cmdq_base, &cmd); 248*67730e6cSSean Christopherson } 249