···88 */991010#include <linux/kernel.h>1111+#include <linux/bitops.h>1212+#include <linux/irq.h>1313+#include <linux/irqdomain.h>1114#include <linux/kvm_host.h>1515+#include <linux/percpu.h>1616+#include <linux/spinlock.h>1217#include <asm/hwcap.h>1818+#include <asm/kvm_aia_imsic.h>13192020+struct aia_hgei_control {2121+ raw_spinlock_t lock;2222+ unsigned long free_bitmap;2323+ struct kvm_vcpu *owners[BITS_PER_LONG];2424+};2525+static DEFINE_PER_CPU(struct aia_hgei_control, aia_hgei);2626+static int hgei_parent_irq;2727+2828+unsigned int kvm_riscv_aia_nr_hgei;2929+unsigned int kvm_riscv_aia_max_ids;1430DEFINE_STATIC_KEY_FALSE(kvm_riscv_aia_available);3131+3232+static int aia_find_hgei(struct kvm_vcpu *owner)3333+{3434+ int i, hgei;3535+ unsigned long flags;3636+ struct aia_hgei_control *hgctrl = get_cpu_ptr(&aia_hgei);3737+3838+ raw_spin_lock_irqsave(&hgctrl->lock, flags);3939+4040+ hgei = -1;4141+ for (i = 1; i <= kvm_riscv_aia_nr_hgei; i++) {4242+ if (hgctrl->owners[i] == owner) {4343+ hgei = i;4444+ break;4545+ }4646+ }4747+4848+ raw_spin_unlock_irqrestore(&hgctrl->lock, flags);4949+5050+ put_cpu_ptr(&aia_hgei);5151+ return hgei;5252+}15531654static void aia_set_hvictl(bool ext_irq_pending)1755{···94569557bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)9658{5959+ int hgei;9760 unsigned long seip;98619962 if (!kvm_riscv_aia_available())···1127311374 if (!kvm_riscv_aia_initialized(vcpu->kvm) || !seip)11475 return false;7676+7777+ hgei = aia_find_hgei(vcpu);7878+ if (hgei > 0)7979+ return !!(csr_read(CSR_HGEIP) & BIT(hgei));1158011681 return false;11782}···366323 return KVM_INSN_CONTINUE_NEXT_SEPC;367324}368325369369-#define IMSIC_FIRST 0x70370370-#define IMSIC_LAST 0xff371326int kvm_riscv_vcpu_aia_rmw_ireg(struct kvm_vcpu *vcpu, unsigned int csr_num,372327 unsigned long *val, unsigned long new_val,373328 unsigned long wr_mask)···389348 return KVM_INSN_EXIT_TO_USER_SPACE;390349}391350351351+int kvm_riscv_aia_alloc_hgei(int cpu, struct kvm_vcpu *owner,352352+ void __iomem **hgei_va, phys_addr_t *hgei_pa)353353+{354354+ int ret = -ENOENT;355355+ unsigned long flags;356356+ struct aia_hgei_control *hgctrl = per_cpu_ptr(&aia_hgei, cpu);357357+358358+ if (!kvm_riscv_aia_available() || !hgctrl)359359+ return -ENODEV;360360+361361+ raw_spin_lock_irqsave(&hgctrl->lock, flags);362362+363363+ if (hgctrl->free_bitmap) {364364+ ret = __ffs(hgctrl->free_bitmap);365365+ hgctrl->free_bitmap &= ~BIT(ret);366366+ hgctrl->owners[ret] = owner;367367+ }368368+369369+ raw_spin_unlock_irqrestore(&hgctrl->lock, flags);370370+371371+ /* TODO: To be updated later by AIA IMSIC HW guest file support */372372+ if (hgei_va)373373+ *hgei_va = NULL;374374+ if (hgei_pa)375375+ *hgei_pa = 0;376376+377377+ return ret;378378+}379379+380380+void kvm_riscv_aia_free_hgei(int cpu, int hgei)381381+{382382+ unsigned long flags;383383+ struct aia_hgei_control *hgctrl = per_cpu_ptr(&aia_hgei, cpu);384384+385385+ if (!kvm_riscv_aia_available() || !hgctrl)386386+ return;387387+388388+ raw_spin_lock_irqsave(&hgctrl->lock, flags);389389+390390+ if (hgei > 0 && hgei <= kvm_riscv_aia_nr_hgei) {391391+ if (!(hgctrl->free_bitmap & BIT(hgei))) {392392+ hgctrl->free_bitmap |= BIT(hgei);393393+ hgctrl->owners[hgei] = NULL;394394+ }395395+ }396396+397397+ raw_spin_unlock_irqrestore(&hgctrl->lock, flags);398398+}399399+400400+void kvm_riscv_aia_wakeon_hgei(struct kvm_vcpu *owner, bool enable)401401+{402402+ int hgei;403403+404404+ if (!kvm_riscv_aia_available())405405+ return;406406+407407+ hgei = aia_find_hgei(owner);408408+ if (hgei > 0) {409409+ if (enable)410410+ csr_set(CSR_HGEIE, BIT(hgei));411411+ else412412+ csr_clear(CSR_HGEIE, BIT(hgei));413413+ }414414+}415415+416416+static irqreturn_t hgei_interrupt(int irq, void *dev_id)417417+{418418+ int i;419419+ unsigned long hgei_mask, flags;420420+ struct aia_hgei_control *hgctrl = get_cpu_ptr(&aia_hgei);421421+422422+ hgei_mask = csr_read(CSR_HGEIP) & csr_read(CSR_HGEIE);423423+ csr_clear(CSR_HGEIE, hgei_mask);424424+425425+ raw_spin_lock_irqsave(&hgctrl->lock, flags);426426+427427+ for_each_set_bit(i, &hgei_mask, BITS_PER_LONG) {428428+ if (hgctrl->owners[i])429429+ kvm_vcpu_kick(hgctrl->owners[i]);430430+ }431431+432432+ raw_spin_unlock_irqrestore(&hgctrl->lock, flags);433433+434434+ put_cpu_ptr(&aia_hgei);435435+ return IRQ_HANDLED;436436+}437437+438438+static int aia_hgei_init(void)439439+{440440+ int cpu, rc;441441+ struct irq_domain *domain;442442+ struct aia_hgei_control *hgctrl;443443+444444+ /* Initialize per-CPU guest external interrupt line management */445445+ for_each_possible_cpu(cpu) {446446+ hgctrl = per_cpu_ptr(&aia_hgei, cpu);447447+ raw_spin_lock_init(&hgctrl->lock);448448+ if (kvm_riscv_aia_nr_hgei) {449449+ hgctrl->free_bitmap =450450+ BIT(kvm_riscv_aia_nr_hgei + 1) - 1;451451+ hgctrl->free_bitmap &= ~BIT(0);452452+ } else453453+ hgctrl->free_bitmap = 0;454454+ }455455+456456+ /* Find INTC irq domain */457457+ domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(),458458+ DOMAIN_BUS_ANY);459459+ if (!domain) {460460+ kvm_err("unable to find INTC domain\n");461461+ return -ENOENT;462462+ }463463+464464+ /* Map per-CPU SGEI interrupt from INTC domain */465465+ hgei_parent_irq = irq_create_mapping(domain, IRQ_S_GEXT);466466+ if (!hgei_parent_irq) {467467+ kvm_err("unable to map SGEI IRQ\n");468468+ return -ENOMEM;469469+ }470470+471471+ /* Request per-CPU SGEI interrupt */472472+ rc = request_percpu_irq(hgei_parent_irq, hgei_interrupt,473473+ "riscv-kvm", &aia_hgei);474474+ if (rc) {475475+ kvm_err("failed to request SGEI IRQ\n");476476+ return rc;477477+ }478478+479479+ return 0;480480+}481481+482482+static void aia_hgei_exit(void)483483+{484484+ /* Free per-CPU SGEI interrupt */485485+ free_percpu_irq(hgei_parent_irq, &aia_hgei);486486+}487487+392488void kvm_riscv_aia_enable(void)393489{394490 if (!kvm_riscv_aia_available())···540362 csr_write(CSR_HVIPRIO1H, 0x0);541363 csr_write(CSR_HVIPRIO2H, 0x0);542364#endif365365+366366+ /* Enable per-CPU SGEI interrupt */367367+ enable_percpu_irq(hgei_parent_irq,368368+ irq_get_trigger_type(hgei_parent_irq));369369+ csr_set(CSR_HIE, BIT(IRQ_S_GEXT));543370}544371545372void kvm_riscv_aia_disable(void)546373{374374+ int i;375375+ unsigned long flags;376376+ struct kvm_vcpu *vcpu;377377+ struct aia_hgei_control *hgctrl;378378+547379 if (!kvm_riscv_aia_available())548380 return;381381+ hgctrl = get_cpu_ptr(&aia_hgei);382382+383383+ /* Disable per-CPU SGEI interrupt */384384+ csr_clear(CSR_HIE, BIT(IRQ_S_GEXT));385385+ disable_percpu_irq(hgei_parent_irq);549386550387 aia_set_hvictl(false);388388+389389+ raw_spin_lock_irqsave(&hgctrl->lock, flags);390390+391391+ for (i = 0; i <= kvm_riscv_aia_nr_hgei; i++) {392392+ vcpu = hgctrl->owners[i];393393+ if (!vcpu)394394+ continue;395395+396396+ /*397397+ * We release hgctrl->lock before notifying IMSIC398398+ * so that we don't have lock ordering issues.399399+ */400400+ raw_spin_unlock_irqrestore(&hgctrl->lock, flags);401401+402402+ /* Notify IMSIC */403403+ kvm_riscv_vcpu_aia_imsic_release(vcpu);404404+405405+ /*406406+ * Wakeup VCPU if it was blocked so that it can407407+ * run on other HARTs408408+ */409409+ if (csr_read(CSR_HGEIE) & BIT(i)) {410410+ csr_clear(CSR_HGEIE, BIT(i));411411+ kvm_vcpu_kick(vcpu);412412+ }413413+414414+ raw_spin_lock_irqsave(&hgctrl->lock, flags);415415+ }416416+417417+ raw_spin_unlock_irqrestore(&hgctrl->lock, flags);418418+419419+ put_cpu_ptr(&aia_hgei);551420}552421553422int kvm_riscv_aia_init(void)554423{424424+ int rc;425425+555426 if (!riscv_isa_extension_available(NULL, SxAIA))556427 return -ENODEV;428428+429429+ /* Figure-out number of bits in HGEIE */430430+ csr_write(CSR_HGEIE, -1UL);431431+ kvm_riscv_aia_nr_hgei = fls_long(csr_read(CSR_HGEIE));432432+ csr_write(CSR_HGEIE, 0);433433+ if (kvm_riscv_aia_nr_hgei)434434+ kvm_riscv_aia_nr_hgei--;435435+436436+ /*437437+ * Number of usable HGEI lines should be minimum of per-HART438438+ * IMSIC guest files and number of bits in HGEIE439439+ *440440+ * TODO: To be updated later by AIA IMSIC HW guest file support441441+ */442442+ kvm_riscv_aia_nr_hgei = 0;443443+444444+ /*445445+ * Find number of guest MSI IDs446446+ *447447+ * TODO: To be updated later by AIA IMSIC HW guest file support448448+ */449449+ kvm_riscv_aia_max_ids = IMSIC_MAX_ID;450450+451451+ /* Initialize guest external interrupt line management */452452+ rc = aia_hgei_init();453453+ if (rc)454454+ return rc;455455+456456+ /* Register device operations */457457+ rc = kvm_register_device_ops(&kvm_riscv_aia_device_ops,458458+ KVM_DEV_TYPE_RISCV_AIA);459459+ if (rc) {460460+ aia_hgei_exit();461461+ return rc;462462+ }557463558464 /* Enable KVM AIA support */559465 static_branch_enable(&kvm_riscv_aia_available);···647385648386void kvm_riscv_aia_exit(void)649387{388388+ if (!kvm_riscv_aia_available())389389+ return;390390+391391+ /* Unregister device operations */392392+ kvm_unregister_device_ops(KVM_DEV_TYPE_RISCV_AIA);393393+394394+ /* Cleanup the HGEI state */395395+ aia_hgei_exit();650396}
+619
arch/riscv/kvm/aia_aplic.c
···11+// SPDX-License-Identifier: GPL-2.022+/*33+ * Copyright (C) 2021 Western Digital Corporation or its affiliates.44+ * Copyright (C) 2022 Ventana Micro Systems Inc.55+ *66+ * Authors:77+ * Anup Patel <apatel@ventanamicro.com>88+ */99+1010+#include <linux/kvm_host.h>1111+#include <linux/math.h>1212+#include <linux/spinlock.h>1313+#include <linux/swab.h>1414+#include <kvm/iodev.h>1515+#include <asm/kvm_aia_aplic.h>1616+1717+struct aplic_irq {1818+ raw_spinlock_t lock;1919+ u32 sourcecfg;2020+ u32 state;2121+#define APLIC_IRQ_STATE_PENDING BIT(0)2222+#define APLIC_IRQ_STATE_ENABLED BIT(1)2323+#define APLIC_IRQ_STATE_ENPEND (APLIC_IRQ_STATE_PENDING | \2424+ APLIC_IRQ_STATE_ENABLED)2525+#define APLIC_IRQ_STATE_INPUT BIT(8)2626+ u32 target;2727+};2828+2929+struct aplic {3030+ struct kvm_io_device iodev;3131+3232+ u32 domaincfg;3333+ u32 genmsi;3434+3535+ u32 nr_irqs;3636+ u32 nr_words;3737+ struct aplic_irq *irqs;3838+};3939+4040+static u32 aplic_read_sourcecfg(struct aplic *aplic, u32 irq)4141+{4242+ u32 ret;4343+ unsigned long flags;4444+ struct aplic_irq *irqd;4545+4646+ if (!irq || aplic->nr_irqs <= irq)4747+ return 0;4848+ irqd = &aplic->irqs[irq];4949+5050+ raw_spin_lock_irqsave(&irqd->lock, flags);5151+ ret = irqd->sourcecfg;5252+ raw_spin_unlock_irqrestore(&irqd->lock, flags);5353+5454+ return ret;5555+}5656+5757+static void aplic_write_sourcecfg(struct aplic *aplic, u32 irq, u32 val)5858+{5959+ unsigned long flags;6060+ struct aplic_irq *irqd;6161+6262+ if (!irq || aplic->nr_irqs <= irq)6363+ return;6464+ irqd = &aplic->irqs[irq];6565+6666+ if (val & APLIC_SOURCECFG_D)6767+ val = 0;6868+ else6969+ val &= APLIC_SOURCECFG_SM_MASK;7070+7171+ raw_spin_lock_irqsave(&irqd->lock, flags);7272+ irqd->sourcecfg = val;7373+ raw_spin_unlock_irqrestore(&irqd->lock, flags);7474+}7575+7676+static u32 aplic_read_target(struct aplic *aplic, u32 irq)7777+{7878+ u32 ret;7979+ unsigned long flags;8080+ struct aplic_irq *irqd;8181+8282+ if (!irq || aplic->nr_irqs <= irq)8383+ return 0;8484+ irqd = &aplic->irqs[irq];8585+8686+ raw_spin_lock_irqsave(&irqd->lock, flags);8787+ ret = irqd->target;8888+ raw_spin_unlock_irqrestore(&irqd->lock, flags);8989+9090+ return ret;9191+}9292+9393+static void aplic_write_target(struct aplic *aplic, u32 irq, u32 val)9494+{9595+ unsigned long flags;9696+ struct aplic_irq *irqd;9797+9898+ if (!irq || aplic->nr_irqs <= irq)9999+ return;100100+ irqd = &aplic->irqs[irq];101101+102102+ val &= APLIC_TARGET_EIID_MASK |103103+ (APLIC_TARGET_HART_IDX_MASK << APLIC_TARGET_HART_IDX_SHIFT) |104104+ (APLIC_TARGET_GUEST_IDX_MASK << APLIC_TARGET_GUEST_IDX_SHIFT);105105+106106+ raw_spin_lock_irqsave(&irqd->lock, flags);107107+ irqd->target = val;108108+ raw_spin_unlock_irqrestore(&irqd->lock, flags);109109+}110110+111111+static bool aplic_read_pending(struct aplic *aplic, u32 irq)112112+{113113+ bool ret;114114+ unsigned long flags;115115+ struct aplic_irq *irqd;116116+117117+ if (!irq || aplic->nr_irqs <= irq)118118+ return false;119119+ irqd = &aplic->irqs[irq];120120+121121+ raw_spin_lock_irqsave(&irqd->lock, flags);122122+ ret = (irqd->state & APLIC_IRQ_STATE_PENDING) ? true : false;123123+ raw_spin_unlock_irqrestore(&irqd->lock, flags);124124+125125+ return ret;126126+}127127+128128+static void aplic_write_pending(struct aplic *aplic, u32 irq, bool pending)129129+{130130+ unsigned long flags, sm;131131+ struct aplic_irq *irqd;132132+133133+ if (!irq || aplic->nr_irqs <= irq)134134+ return;135135+ irqd = &aplic->irqs[irq];136136+137137+ raw_spin_lock_irqsave(&irqd->lock, flags);138138+139139+ sm = irqd->sourcecfg & APLIC_SOURCECFG_SM_MASK;140140+ if (!pending &&141141+ ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) ||142142+ (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)))143143+ goto skip_write_pending;144144+145145+ if (pending)146146+ irqd->state |= APLIC_IRQ_STATE_PENDING;147147+ else148148+ irqd->state &= ~APLIC_IRQ_STATE_PENDING;149149+150150+skip_write_pending:151151+ raw_spin_unlock_irqrestore(&irqd->lock, flags);152152+}153153+154154+static bool aplic_read_enabled(struct aplic *aplic, u32 irq)155155+{156156+ bool ret;157157+ unsigned long flags;158158+ struct aplic_irq *irqd;159159+160160+ if (!irq || aplic->nr_irqs <= irq)161161+ return false;162162+ irqd = &aplic->irqs[irq];163163+164164+ raw_spin_lock_irqsave(&irqd->lock, flags);165165+ ret = (irqd->state & APLIC_IRQ_STATE_ENABLED) ? true : false;166166+ raw_spin_unlock_irqrestore(&irqd->lock, flags);167167+168168+ return ret;169169+}170170+171171+static void aplic_write_enabled(struct aplic *aplic, u32 irq, bool enabled)172172+{173173+ unsigned long flags;174174+ struct aplic_irq *irqd;175175+176176+ if (!irq || aplic->nr_irqs <= irq)177177+ return;178178+ irqd = &aplic->irqs[irq];179179+180180+ raw_spin_lock_irqsave(&irqd->lock, flags);181181+ if (enabled)182182+ irqd->state |= APLIC_IRQ_STATE_ENABLED;183183+ else184184+ irqd->state &= ~APLIC_IRQ_STATE_ENABLED;185185+ raw_spin_unlock_irqrestore(&irqd->lock, flags);186186+}187187+188188+static bool aplic_read_input(struct aplic *aplic, u32 irq)189189+{190190+ bool ret;191191+ unsigned long flags;192192+ struct aplic_irq *irqd;193193+194194+ if (!irq || aplic->nr_irqs <= irq)195195+ return false;196196+ irqd = &aplic->irqs[irq];197197+198198+ raw_spin_lock_irqsave(&irqd->lock, flags);199199+ ret = (irqd->state & APLIC_IRQ_STATE_INPUT) ? true : false;200200+ raw_spin_unlock_irqrestore(&irqd->lock, flags);201201+202202+ return ret;203203+}204204+205205+static void aplic_inject_msi(struct kvm *kvm, u32 irq, u32 target)206206+{207207+ u32 hart_idx, guest_idx, eiid;208208+209209+ hart_idx = target >> APLIC_TARGET_HART_IDX_SHIFT;210210+ hart_idx &= APLIC_TARGET_HART_IDX_MASK;211211+ guest_idx = target >> APLIC_TARGET_GUEST_IDX_SHIFT;212212+ guest_idx &= APLIC_TARGET_GUEST_IDX_MASK;213213+ eiid = target & APLIC_TARGET_EIID_MASK;214214+ kvm_riscv_aia_inject_msi_by_id(kvm, hart_idx, guest_idx, eiid);215215+}216216+217217+static void aplic_update_irq_range(struct kvm *kvm, u32 first, u32 last)218218+{219219+ bool inject;220220+ u32 irq, target;221221+ unsigned long flags;222222+ struct aplic_irq *irqd;223223+ struct aplic *aplic = kvm->arch.aia.aplic_state;224224+225225+ if (!(aplic->domaincfg & APLIC_DOMAINCFG_IE))226226+ return;227227+228228+ for (irq = first; irq <= last; irq++) {229229+ if (!irq || aplic->nr_irqs <= irq)230230+ continue;231231+ irqd = &aplic->irqs[irq];232232+233233+ raw_spin_lock_irqsave(&irqd->lock, flags);234234+235235+ inject = false;236236+ target = irqd->target;237237+ if ((irqd->state & APLIC_IRQ_STATE_ENPEND) ==238238+ APLIC_IRQ_STATE_ENPEND) {239239+ irqd->state &= ~APLIC_IRQ_STATE_PENDING;240240+ inject = true;241241+ }242242+243243+ raw_spin_unlock_irqrestore(&irqd->lock, flags);244244+245245+ if (inject)246246+ aplic_inject_msi(kvm, irq, target);247247+ }248248+}249249+250250+int kvm_riscv_aia_aplic_inject(struct kvm *kvm, u32 source, bool level)251251+{252252+ u32 target;253253+ bool inject = false, ie;254254+ unsigned long flags;255255+ struct aplic_irq *irqd;256256+ struct aplic *aplic = kvm->arch.aia.aplic_state;257257+258258+ if (!aplic || !source || (aplic->nr_irqs <= source))259259+ return -ENODEV;260260+ irqd = &aplic->irqs[source];261261+ ie = (aplic->domaincfg & APLIC_DOMAINCFG_IE) ? true : false;262262+263263+ raw_spin_lock_irqsave(&irqd->lock, flags);264264+265265+ if (irqd->sourcecfg & APLIC_SOURCECFG_D)266266+ goto skip_unlock;267267+268268+ switch (irqd->sourcecfg & APLIC_SOURCECFG_SM_MASK) {269269+ case APLIC_SOURCECFG_SM_EDGE_RISE:270270+ if (level && !(irqd->state & APLIC_IRQ_STATE_INPUT) &&271271+ !(irqd->state & APLIC_IRQ_STATE_PENDING))272272+ irqd->state |= APLIC_IRQ_STATE_PENDING;273273+ break;274274+ case APLIC_SOURCECFG_SM_EDGE_FALL:275275+ if (!level && (irqd->state & APLIC_IRQ_STATE_INPUT) &&276276+ !(irqd->state & APLIC_IRQ_STATE_PENDING))277277+ irqd->state |= APLIC_IRQ_STATE_PENDING;278278+ break;279279+ case APLIC_SOURCECFG_SM_LEVEL_HIGH:280280+ if (level && !(irqd->state & APLIC_IRQ_STATE_PENDING))281281+ irqd->state |= APLIC_IRQ_STATE_PENDING;282282+ break;283283+ case APLIC_SOURCECFG_SM_LEVEL_LOW:284284+ if (!level && !(irqd->state & APLIC_IRQ_STATE_PENDING))285285+ irqd->state |= APLIC_IRQ_STATE_PENDING;286286+ break;287287+ }288288+289289+ if (level)290290+ irqd->state |= APLIC_IRQ_STATE_INPUT;291291+ else292292+ irqd->state &= ~APLIC_IRQ_STATE_INPUT;293293+294294+ target = irqd->target;295295+ if (ie && ((irqd->state & APLIC_IRQ_STATE_ENPEND) ==296296+ APLIC_IRQ_STATE_ENPEND)) {297297+ irqd->state &= ~APLIC_IRQ_STATE_PENDING;298298+ inject = true;299299+ }300300+301301+skip_unlock:302302+ raw_spin_unlock_irqrestore(&irqd->lock, flags);303303+304304+ if (inject)305305+ aplic_inject_msi(kvm, source, target);306306+307307+ return 0;308308+}309309+310310+static u32 aplic_read_input_word(struct aplic *aplic, u32 word)311311+{312312+ u32 i, ret = 0;313313+314314+ for (i = 0; i < 32; i++)315315+ ret |= aplic_read_input(aplic, word * 32 + i) ? BIT(i) : 0;316316+317317+ return ret;318318+}319319+320320+static u32 aplic_read_pending_word(struct aplic *aplic, u32 word)321321+{322322+ u32 i, ret = 0;323323+324324+ for (i = 0; i < 32; i++)325325+ ret |= aplic_read_pending(aplic, word * 32 + i) ? BIT(i) : 0;326326+327327+ return ret;328328+}329329+330330+static void aplic_write_pending_word(struct aplic *aplic, u32 word,331331+ u32 val, bool pending)332332+{333333+ u32 i;334334+335335+ for (i = 0; i < 32; i++) {336336+ if (val & BIT(i))337337+ aplic_write_pending(aplic, word * 32 + i, pending);338338+ }339339+}340340+341341+static u32 aplic_read_enabled_word(struct aplic *aplic, u32 word)342342+{343343+ u32 i, ret = 0;344344+345345+ for (i = 0; i < 32; i++)346346+ ret |= aplic_read_enabled(aplic, word * 32 + i) ? BIT(i) : 0;347347+348348+ return ret;349349+}350350+351351+static void aplic_write_enabled_word(struct aplic *aplic, u32 word,352352+ u32 val, bool enabled)353353+{354354+ u32 i;355355+356356+ for (i = 0; i < 32; i++) {357357+ if (val & BIT(i))358358+ aplic_write_enabled(aplic, word * 32 + i, enabled);359359+ }360360+}361361+362362+static int aplic_mmio_read_offset(struct kvm *kvm, gpa_t off, u32 *val32)363363+{364364+ u32 i;365365+ struct aplic *aplic = kvm->arch.aia.aplic_state;366366+367367+ if ((off & 0x3) != 0)368368+ return -EOPNOTSUPP;369369+370370+ if (off == APLIC_DOMAINCFG) {371371+ *val32 = APLIC_DOMAINCFG_RDONLY |372372+ aplic->domaincfg | APLIC_DOMAINCFG_DM;373373+ } else if ((off >= APLIC_SOURCECFG_BASE) &&374374+ (off < (APLIC_SOURCECFG_BASE + (aplic->nr_irqs - 1) * 4))) {375375+ i = ((off - APLIC_SOURCECFG_BASE) >> 2) + 1;376376+ *val32 = aplic_read_sourcecfg(aplic, i);377377+ } else if ((off >= APLIC_SETIP_BASE) &&378378+ (off < (APLIC_SETIP_BASE + aplic->nr_words * 4))) {379379+ i = (off - APLIC_SETIP_BASE) >> 2;380380+ *val32 = aplic_read_pending_word(aplic, i);381381+ } else if (off == APLIC_SETIPNUM) {382382+ *val32 = 0;383383+ } else if ((off >= APLIC_CLRIP_BASE) &&384384+ (off < (APLIC_CLRIP_BASE + aplic->nr_words * 4))) {385385+ i = (off - APLIC_CLRIP_BASE) >> 2;386386+ *val32 = aplic_read_input_word(aplic, i);387387+ } else if (off == APLIC_CLRIPNUM) {388388+ *val32 = 0;389389+ } else if ((off >= APLIC_SETIE_BASE) &&390390+ (off < (APLIC_SETIE_BASE + aplic->nr_words * 4))) {391391+ i = (off - APLIC_SETIE_BASE) >> 2;392392+ *val32 = aplic_read_enabled_word(aplic, i);393393+ } else if (off == APLIC_SETIENUM) {394394+ *val32 = 0;395395+ } else if ((off >= APLIC_CLRIE_BASE) &&396396+ (off < (APLIC_CLRIE_BASE + aplic->nr_words * 4))) {397397+ *val32 = 0;398398+ } else if (off == APLIC_CLRIENUM) {399399+ *val32 = 0;400400+ } else if (off == APLIC_SETIPNUM_LE) {401401+ *val32 = 0;402402+ } else if (off == APLIC_SETIPNUM_BE) {403403+ *val32 = 0;404404+ } else if (off == APLIC_GENMSI) {405405+ *val32 = aplic->genmsi;406406+ } else if ((off >= APLIC_TARGET_BASE) &&407407+ (off < (APLIC_TARGET_BASE + (aplic->nr_irqs - 1) * 4))) {408408+ i = ((off - APLIC_TARGET_BASE) >> 2) + 1;409409+ *val32 = aplic_read_target(aplic, i);410410+ } else411411+ return -ENODEV;412412+413413+ return 0;414414+}415415+416416+static int aplic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,417417+ gpa_t addr, int len, void *val)418418+{419419+ if (len != 4)420420+ return -EOPNOTSUPP;421421+422422+ return aplic_mmio_read_offset(vcpu->kvm,423423+ addr - vcpu->kvm->arch.aia.aplic_addr,424424+ val);425425+}426426+427427+static int aplic_mmio_write_offset(struct kvm *kvm, gpa_t off, u32 val32)428428+{429429+ u32 i;430430+ struct aplic *aplic = kvm->arch.aia.aplic_state;431431+432432+ if ((off & 0x3) != 0)433433+ return -EOPNOTSUPP;434434+435435+ if (off == APLIC_DOMAINCFG) {436436+ /* Only IE bit writeable */437437+ aplic->domaincfg = val32 & APLIC_DOMAINCFG_IE;438438+ } else if ((off >= APLIC_SOURCECFG_BASE) &&439439+ (off < (APLIC_SOURCECFG_BASE + (aplic->nr_irqs - 1) * 4))) {440440+ i = ((off - APLIC_SOURCECFG_BASE) >> 2) + 1;441441+ aplic_write_sourcecfg(aplic, i, val32);442442+ } else if ((off >= APLIC_SETIP_BASE) &&443443+ (off < (APLIC_SETIP_BASE + aplic->nr_words * 4))) {444444+ i = (off - APLIC_SETIP_BASE) >> 2;445445+ aplic_write_pending_word(aplic, i, val32, true);446446+ } else if (off == APLIC_SETIPNUM) {447447+ aplic_write_pending(aplic, val32, true);448448+ } else if ((off >= APLIC_CLRIP_BASE) &&449449+ (off < (APLIC_CLRIP_BASE + aplic->nr_words * 4))) {450450+ i = (off - APLIC_CLRIP_BASE) >> 2;451451+ aplic_write_pending_word(aplic, i, val32, false);452452+ } else if (off == APLIC_CLRIPNUM) {453453+ aplic_write_pending(aplic, val32, false);454454+ } else if ((off >= APLIC_SETIE_BASE) &&455455+ (off < (APLIC_SETIE_BASE + aplic->nr_words * 4))) {456456+ i = (off - APLIC_SETIE_BASE) >> 2;457457+ aplic_write_enabled_word(aplic, i, val32, true);458458+ } else if (off == APLIC_SETIENUM) {459459+ aplic_write_enabled(aplic, val32, true);460460+ } else if ((off >= APLIC_CLRIE_BASE) &&461461+ (off < (APLIC_CLRIE_BASE + aplic->nr_words * 4))) {462462+ i = (off - APLIC_CLRIE_BASE) >> 2;463463+ aplic_write_enabled_word(aplic, i, val32, false);464464+ } else if (off == APLIC_CLRIENUM) {465465+ aplic_write_enabled(aplic, val32, false);466466+ } else if (off == APLIC_SETIPNUM_LE) {467467+ aplic_write_pending(aplic, val32, true);468468+ } else if (off == APLIC_SETIPNUM_BE) {469469+ aplic_write_pending(aplic, __swab32(val32), true);470470+ } else if (off == APLIC_GENMSI) {471471+ aplic->genmsi = val32 & ~(APLIC_TARGET_GUEST_IDX_MASK <<472472+ APLIC_TARGET_GUEST_IDX_SHIFT);473473+ kvm_riscv_aia_inject_msi_by_id(kvm,474474+ val32 >> APLIC_TARGET_HART_IDX_SHIFT, 0,475475+ val32 & APLIC_TARGET_EIID_MASK);476476+ } else if ((off >= APLIC_TARGET_BASE) &&477477+ (off < (APLIC_TARGET_BASE + (aplic->nr_irqs - 1) * 4))) {478478+ i = ((off - APLIC_TARGET_BASE) >> 2) + 1;479479+ aplic_write_target(aplic, i, val32);480480+ } else481481+ return -ENODEV;482482+483483+ aplic_update_irq_range(kvm, 1, aplic->nr_irqs - 1);484484+485485+ return 0;486486+}487487+488488+static int aplic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,489489+ gpa_t addr, int len, const void *val)490490+{491491+ if (len != 4)492492+ return -EOPNOTSUPP;493493+494494+ return aplic_mmio_write_offset(vcpu->kvm,495495+ addr - vcpu->kvm->arch.aia.aplic_addr,496496+ *((const u32 *)val));497497+}498498+499499+static struct kvm_io_device_ops aplic_iodoev_ops = {500500+ .read = aplic_mmio_read,501501+ .write = aplic_mmio_write,502502+};503503+504504+int kvm_riscv_aia_aplic_set_attr(struct kvm *kvm, unsigned long type, u32 v)505505+{506506+ int rc;507507+508508+ if (!kvm->arch.aia.aplic_state)509509+ return -ENODEV;510510+511511+ rc = aplic_mmio_write_offset(kvm, type, v);512512+ if (rc)513513+ return rc;514514+515515+ return 0;516516+}517517+518518+int kvm_riscv_aia_aplic_get_attr(struct kvm *kvm, unsigned long type, u32 *v)519519+{520520+ int rc;521521+522522+ if (!kvm->arch.aia.aplic_state)523523+ return -ENODEV;524524+525525+ rc = aplic_mmio_read_offset(kvm, type, v);526526+ if (rc)527527+ return rc;528528+529529+ return 0;530530+}531531+532532+int kvm_riscv_aia_aplic_has_attr(struct kvm *kvm, unsigned long type)533533+{534534+ int rc;535535+ u32 val;536536+537537+ if (!kvm->arch.aia.aplic_state)538538+ return -ENODEV;539539+540540+ rc = aplic_mmio_read_offset(kvm, type, &val);541541+ if (rc)542542+ return rc;543543+544544+ return 0;545545+}546546+547547+int kvm_riscv_aia_aplic_init(struct kvm *kvm)548548+{549549+ int i, ret = 0;550550+ struct aplic *aplic;551551+552552+ /* Do nothing if we have zero sources */553553+ if (!kvm->arch.aia.nr_sources)554554+ return 0;555555+556556+ /* Allocate APLIC global state */557557+ aplic = kzalloc(sizeof(*aplic), GFP_KERNEL);558558+ if (!aplic)559559+ return -ENOMEM;560560+ kvm->arch.aia.aplic_state = aplic;561561+562562+ /* Setup APLIC IRQs */563563+ aplic->nr_irqs = kvm->arch.aia.nr_sources + 1;564564+ aplic->nr_words = DIV_ROUND_UP(aplic->nr_irqs, 32);565565+ aplic->irqs = kcalloc(aplic->nr_irqs,566566+ sizeof(*aplic->irqs), GFP_KERNEL);567567+ if (!aplic->irqs) {568568+ ret = -ENOMEM;569569+ goto fail_free_aplic;570570+ }571571+ for (i = 0; i < aplic->nr_irqs; i++)572572+ raw_spin_lock_init(&aplic->irqs[i].lock);573573+574574+ /* Setup IO device */575575+ kvm_iodevice_init(&aplic->iodev, &aplic_iodoev_ops);576576+ mutex_lock(&kvm->slots_lock);577577+ ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,578578+ kvm->arch.aia.aplic_addr,579579+ KVM_DEV_RISCV_APLIC_SIZE,580580+ &aplic->iodev);581581+ mutex_unlock(&kvm->slots_lock);582582+ if (ret)583583+ goto fail_free_aplic_irqs;584584+585585+ /* Setup default IRQ routing */586586+ ret = kvm_riscv_setup_default_irq_routing(kvm, aplic->nr_irqs);587587+ if (ret)588588+ goto fail_unreg_iodev;589589+590590+ return 0;591591+592592+fail_unreg_iodev:593593+ mutex_lock(&kvm->slots_lock);594594+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &aplic->iodev);595595+ mutex_unlock(&kvm->slots_lock);596596+fail_free_aplic_irqs:597597+ kfree(aplic->irqs);598598+fail_free_aplic:599599+ kvm->arch.aia.aplic_state = NULL;600600+ kfree(aplic);601601+ return ret;602602+}603603+604604+void kvm_riscv_aia_aplic_cleanup(struct kvm *kvm)605605+{606606+ struct aplic *aplic = kvm->arch.aia.aplic_state;607607+608608+ if (!aplic)609609+ return;610610+611611+ mutex_lock(&kvm->slots_lock);612612+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &aplic->iodev);613613+ mutex_unlock(&kvm->slots_lock);614614+615615+ kfree(aplic->irqs);616616+617617+ kvm->arch.aia.aplic_state = NULL;618618+ kfree(aplic);619619+}
+673
arch/riscv/kvm/aia_device.c
···11+// SPDX-License-Identifier: GPL-2.022+/*33+ * Copyright (C) 2021 Western Digital Corporation or its affiliates.44+ * Copyright (C) 2022 Ventana Micro Systems Inc.55+ *66+ * Authors:77+ * Anup Patel <apatel@ventanamicro.com>88+ */99+1010+#include <linux/bits.h>1111+#include <linux/kvm_host.h>1212+#include <linux/uaccess.h>1313+#include <asm/kvm_aia_imsic.h>1414+1515+static void unlock_vcpus(struct kvm *kvm, int vcpu_lock_idx)1616+{1717+ struct kvm_vcpu *tmp_vcpu;1818+1919+ for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {2020+ tmp_vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);2121+ mutex_unlock(&tmp_vcpu->mutex);2222+ }2323+}2424+2525+static void unlock_all_vcpus(struct kvm *kvm)2626+{2727+ unlock_vcpus(kvm, atomic_read(&kvm->online_vcpus) - 1);2828+}2929+3030+static bool lock_all_vcpus(struct kvm *kvm)3131+{3232+ struct kvm_vcpu *tmp_vcpu;3333+ unsigned long c;3434+3535+ kvm_for_each_vcpu(c, tmp_vcpu, kvm) {3636+ if (!mutex_trylock(&tmp_vcpu->mutex)) {3737+ unlock_vcpus(kvm, c - 1);3838+ return false;3939+ }4040+ }4141+4242+ return true;4343+}4444+4545+static int aia_create(struct kvm_device *dev, u32 type)4646+{4747+ int ret;4848+ unsigned long i;4949+ struct kvm *kvm = dev->kvm;5050+ struct kvm_vcpu *vcpu;5151+5252+ if (irqchip_in_kernel(kvm))5353+ return -EEXIST;5454+5555+ ret = -EBUSY;5656+ if (!lock_all_vcpus(kvm))5757+ return ret;5858+5959+ kvm_for_each_vcpu(i, vcpu, kvm) {6060+ if (vcpu->arch.ran_atleast_once)6161+ goto out_unlock;6262+ }6363+ ret = 0;6464+6565+ kvm->arch.aia.in_kernel = true;6666+6767+out_unlock:6868+ unlock_all_vcpus(kvm);6969+ return ret;7070+}7171+7272+static void aia_destroy(struct kvm_device *dev)7373+{7474+ kfree(dev);7575+}7676+7777+static int aia_config(struct kvm *kvm, unsigned long type,7878+ u32 *nr, bool write)7979+{8080+ struct kvm_aia *aia = &kvm->arch.aia;8181+8282+ /* Writes can only be done before irqchip is initialized */8383+ if (write && kvm_riscv_aia_initialized(kvm))8484+ return -EBUSY;8585+8686+ switch (type) {8787+ case KVM_DEV_RISCV_AIA_CONFIG_MODE:8888+ if (write) {8989+ switch (*nr) {9090+ case KVM_DEV_RISCV_AIA_MODE_EMUL:9191+ break;9292+ case KVM_DEV_RISCV_AIA_MODE_HWACCEL:9393+ case KVM_DEV_RISCV_AIA_MODE_AUTO:9494+ /*9595+ * HW Acceleration and Auto modes only9696+ * supported on host with non-zero guest9797+ * external interrupts (i.e. non-zero9898+ * VS-level IMSIC pages).9999+ */100100+ if (!kvm_riscv_aia_nr_hgei)101101+ return -EINVAL;102102+ break;103103+ default:104104+ return -EINVAL;105105+ }106106+ aia->mode = *nr;107107+ } else108108+ *nr = aia->mode;109109+ break;110110+ case KVM_DEV_RISCV_AIA_CONFIG_IDS:111111+ if (write) {112112+ if ((*nr < KVM_DEV_RISCV_AIA_IDS_MIN) ||113113+ (*nr >= KVM_DEV_RISCV_AIA_IDS_MAX) ||114114+ ((*nr & KVM_DEV_RISCV_AIA_IDS_MIN) !=115115+ KVM_DEV_RISCV_AIA_IDS_MIN) ||116116+ (kvm_riscv_aia_max_ids <= *nr))117117+ return -EINVAL;118118+ aia->nr_ids = *nr;119119+ } else120120+ *nr = aia->nr_ids;121121+ break;122122+ case KVM_DEV_RISCV_AIA_CONFIG_SRCS:123123+ if (write) {124124+ if ((*nr >= KVM_DEV_RISCV_AIA_SRCS_MAX) ||125125+ (*nr >= kvm_riscv_aia_max_ids))126126+ return -EINVAL;127127+ aia->nr_sources = *nr;128128+ } else129129+ *nr = aia->nr_sources;130130+ break;131131+ case KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS:132132+ if (write) {133133+ if (*nr >= KVM_DEV_RISCV_AIA_GROUP_BITS_MAX)134134+ return -EINVAL;135135+ aia->nr_group_bits = *nr;136136+ } else137137+ *nr = aia->nr_group_bits;138138+ break;139139+ case KVM_DEV_RISCV_AIA_CONFIG_GROUP_SHIFT:140140+ if (write) {141141+ if ((*nr < KVM_DEV_RISCV_AIA_GROUP_SHIFT_MIN) ||142142+ (*nr >= KVM_DEV_RISCV_AIA_GROUP_SHIFT_MAX))143143+ return -EINVAL;144144+ aia->nr_group_shift = *nr;145145+ } else146146+ *nr = aia->nr_group_shift;147147+ break;148148+ case KVM_DEV_RISCV_AIA_CONFIG_HART_BITS:149149+ if (write) {150150+ if (*nr >= KVM_DEV_RISCV_AIA_HART_BITS_MAX)151151+ return -EINVAL;152152+ aia->nr_hart_bits = *nr;153153+ } else154154+ *nr = aia->nr_hart_bits;155155+ break;156156+ case KVM_DEV_RISCV_AIA_CONFIG_GUEST_BITS:157157+ if (write) {158158+ if (*nr >= KVM_DEV_RISCV_AIA_GUEST_BITS_MAX)159159+ return -EINVAL;160160+ aia->nr_guest_bits = *nr;161161+ } else162162+ *nr = aia->nr_guest_bits;163163+ break;164164+ default:165165+ return -ENXIO;166166+ }167167+168168+ return 0;169169+}170170+171171+static int aia_aplic_addr(struct kvm *kvm, u64 *addr, bool write)172172+{173173+ struct kvm_aia *aia = &kvm->arch.aia;174174+175175+ if (write) {176176+ /* Writes can only be done before irqchip is initialized */177177+ if (kvm_riscv_aia_initialized(kvm))178178+ return -EBUSY;179179+180180+ if (*addr & (KVM_DEV_RISCV_APLIC_ALIGN - 1))181181+ return -EINVAL;182182+183183+ aia->aplic_addr = *addr;184184+ } else185185+ *addr = aia->aplic_addr;186186+187187+ return 0;188188+}189189+190190+static int aia_imsic_addr(struct kvm *kvm, u64 *addr,191191+ unsigned long vcpu_idx, bool write)192192+{193193+ struct kvm_vcpu *vcpu;194194+ struct kvm_vcpu_aia *vcpu_aia;195195+196196+ vcpu = kvm_get_vcpu(kvm, vcpu_idx);197197+ if (!vcpu)198198+ return -EINVAL;199199+ vcpu_aia = &vcpu->arch.aia_context;200200+201201+ if (write) {202202+ /* Writes can only be done before irqchip is initialized */203203+ if (kvm_riscv_aia_initialized(kvm))204204+ return -EBUSY;205205+206206+ if (*addr & (KVM_DEV_RISCV_IMSIC_ALIGN - 1))207207+ return -EINVAL;208208+ }209209+210210+ mutex_lock(&vcpu->mutex);211211+ if (write)212212+ vcpu_aia->imsic_addr = *addr;213213+ else214214+ *addr = vcpu_aia->imsic_addr;215215+ mutex_unlock(&vcpu->mutex);216216+217217+ return 0;218218+}219219+220220+static gpa_t aia_imsic_ppn(struct kvm_aia *aia, gpa_t addr)221221+{222222+ u32 h, l;223223+ gpa_t mask = 0;224224+225225+ h = aia->nr_hart_bits + aia->nr_guest_bits +226226+ IMSIC_MMIO_PAGE_SHIFT - 1;227227+ mask = GENMASK_ULL(h, 0);228228+229229+ if (aia->nr_group_bits) {230230+ h = aia->nr_group_bits + aia->nr_group_shift - 1;231231+ l = aia->nr_group_shift;232232+ mask |= GENMASK_ULL(h, l);233233+ }234234+235235+ return (addr & ~mask) >> IMSIC_MMIO_PAGE_SHIFT;236236+}237237+238238+static u32 aia_imsic_hart_index(struct kvm_aia *aia, gpa_t addr)239239+{240240+ u32 hart, group = 0;241241+242242+ hart = (addr >> (aia->nr_guest_bits + IMSIC_MMIO_PAGE_SHIFT)) &243243+ GENMASK_ULL(aia->nr_hart_bits - 1, 0);244244+ if (aia->nr_group_bits)245245+ group = (addr >> aia->nr_group_shift) &246246+ GENMASK_ULL(aia->nr_group_bits - 1, 0);247247+248248+ return (group << aia->nr_hart_bits) | hart;249249+}250250+251251+static int aia_init(struct kvm *kvm)252252+{253253+ int ret, i;254254+ unsigned long idx;255255+ struct kvm_vcpu *vcpu;256256+ struct kvm_vcpu_aia *vaia;257257+ struct kvm_aia *aia = &kvm->arch.aia;258258+ gpa_t base_ppn = KVM_RISCV_AIA_UNDEF_ADDR;259259+260260+ /* Irqchip can be initialized only once */261261+ if (kvm_riscv_aia_initialized(kvm))262262+ return -EBUSY;263263+264264+ /* We might be in the middle of creating a VCPU? */265265+ if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))266266+ return -EBUSY;267267+268268+ /* Number of sources should be less than or equals number of IDs */269269+ if (aia->nr_ids < aia->nr_sources)270270+ return -EINVAL;271271+272272+ /* APLIC base is required for non-zero number of sources */273273+ if (aia->nr_sources && aia->aplic_addr == KVM_RISCV_AIA_UNDEF_ADDR)274274+ return -EINVAL;275275+276276+ /* Initialize APLIC */277277+ ret = kvm_riscv_aia_aplic_init(kvm);278278+ if (ret)279279+ return ret;280280+281281+ /* Iterate over each VCPU */282282+ kvm_for_each_vcpu(idx, vcpu, kvm) {283283+ vaia = &vcpu->arch.aia_context;284284+285285+ /* IMSIC base is required */286286+ if (vaia->imsic_addr == KVM_RISCV_AIA_UNDEF_ADDR) {287287+ ret = -EINVAL;288288+ goto fail_cleanup_imsics;289289+ }290290+291291+ /* All IMSICs should have matching base PPN */292292+ if (base_ppn == KVM_RISCV_AIA_UNDEF_ADDR)293293+ base_ppn = aia_imsic_ppn(aia, vaia->imsic_addr);294294+ if (base_ppn != aia_imsic_ppn(aia, vaia->imsic_addr)) {295295+ ret = -EINVAL;296296+ goto fail_cleanup_imsics;297297+ }298298+299299+ /* Update HART index of the IMSIC based on IMSIC base */300300+ vaia->hart_index = aia_imsic_hart_index(aia,301301+ vaia->imsic_addr);302302+303303+ /* Initialize IMSIC for this VCPU */304304+ ret = kvm_riscv_vcpu_aia_imsic_init(vcpu);305305+ if (ret)306306+ goto fail_cleanup_imsics;307307+ }308308+309309+ /* Set the initialized flag */310310+ kvm->arch.aia.initialized = true;311311+312312+ return 0;313313+314314+fail_cleanup_imsics:315315+ for (i = idx - 1; i >= 0; i--) {316316+ vcpu = kvm_get_vcpu(kvm, i);317317+ if (!vcpu)318318+ continue;319319+ kvm_riscv_vcpu_aia_imsic_cleanup(vcpu);320320+ }321321+ kvm_riscv_aia_aplic_cleanup(kvm);322322+ return ret;323323+}324324+325325+static int aia_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)326326+{327327+ u32 nr;328328+ u64 addr;329329+ int nr_vcpus, r = -ENXIO;330330+ unsigned long v, type = (unsigned long)attr->attr;331331+ void __user *uaddr = (void __user *)(long)attr->addr;332332+333333+ switch (attr->group) {334334+ case KVM_DEV_RISCV_AIA_GRP_CONFIG:335335+ if (copy_from_user(&nr, uaddr, sizeof(nr)))336336+ return -EFAULT;337337+338338+ mutex_lock(&dev->kvm->lock);339339+ r = aia_config(dev->kvm, type, &nr, true);340340+ mutex_unlock(&dev->kvm->lock);341341+342342+ break;343343+344344+ case KVM_DEV_RISCV_AIA_GRP_ADDR:345345+ if (copy_from_user(&addr, uaddr, sizeof(addr)))346346+ return -EFAULT;347347+348348+ nr_vcpus = atomic_read(&dev->kvm->online_vcpus);349349+ mutex_lock(&dev->kvm->lock);350350+ if (type == KVM_DEV_RISCV_AIA_ADDR_APLIC)351351+ r = aia_aplic_addr(dev->kvm, &addr, true);352352+ else if (type < KVM_DEV_RISCV_AIA_ADDR_IMSIC(nr_vcpus))353353+ r = aia_imsic_addr(dev->kvm, &addr,354354+ type - KVM_DEV_RISCV_AIA_ADDR_IMSIC(0), true);355355+ mutex_unlock(&dev->kvm->lock);356356+357357+ break;358358+359359+ case KVM_DEV_RISCV_AIA_GRP_CTRL:360360+ switch (type) {361361+ case KVM_DEV_RISCV_AIA_CTRL_INIT:362362+ mutex_lock(&dev->kvm->lock);363363+ r = aia_init(dev->kvm);364364+ mutex_unlock(&dev->kvm->lock);365365+ break;366366+ }367367+368368+ break;369369+ case KVM_DEV_RISCV_AIA_GRP_APLIC:370370+ if (copy_from_user(&nr, uaddr, sizeof(nr)))371371+ return -EFAULT;372372+373373+ mutex_lock(&dev->kvm->lock);374374+ r = kvm_riscv_aia_aplic_set_attr(dev->kvm, type, nr);375375+ mutex_unlock(&dev->kvm->lock);376376+377377+ break;378378+ case KVM_DEV_RISCV_AIA_GRP_IMSIC:379379+ if (copy_from_user(&v, uaddr, sizeof(v)))380380+ return -EFAULT;381381+382382+ mutex_lock(&dev->kvm->lock);383383+ r = kvm_riscv_aia_imsic_rw_attr(dev->kvm, type, true, &v);384384+ mutex_unlock(&dev->kvm->lock);385385+386386+ break;387387+ }388388+389389+ return r;390390+}391391+392392+static int aia_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)393393+{394394+ u32 nr;395395+ u64 addr;396396+ int nr_vcpus, r = -ENXIO;397397+ void __user *uaddr = (void __user *)(long)attr->addr;398398+ unsigned long v, type = (unsigned long)attr->attr;399399+400400+ switch (attr->group) {401401+ case KVM_DEV_RISCV_AIA_GRP_CONFIG:402402+ if (copy_from_user(&nr, uaddr, sizeof(nr)))403403+ return -EFAULT;404404+405405+ mutex_lock(&dev->kvm->lock);406406+ r = aia_config(dev->kvm, type, &nr, false);407407+ mutex_unlock(&dev->kvm->lock);408408+ if (r)409409+ return r;410410+411411+ if (copy_to_user(uaddr, &nr, sizeof(nr)))412412+ return -EFAULT;413413+414414+ break;415415+ case KVM_DEV_RISCV_AIA_GRP_ADDR:416416+ if (copy_from_user(&addr, uaddr, sizeof(addr)))417417+ return -EFAULT;418418+419419+ nr_vcpus = atomic_read(&dev->kvm->online_vcpus);420420+ mutex_lock(&dev->kvm->lock);421421+ if (type == KVM_DEV_RISCV_AIA_ADDR_APLIC)422422+ r = aia_aplic_addr(dev->kvm, &addr, false);423423+ else if (type < KVM_DEV_RISCV_AIA_ADDR_IMSIC(nr_vcpus))424424+ r = aia_imsic_addr(dev->kvm, &addr,425425+ type - KVM_DEV_RISCV_AIA_ADDR_IMSIC(0), false);426426+ mutex_unlock(&dev->kvm->lock);427427+ if (r)428428+ return r;429429+430430+ if (copy_to_user(uaddr, &addr, sizeof(addr)))431431+ return -EFAULT;432432+433433+ break;434434+ case KVM_DEV_RISCV_AIA_GRP_APLIC:435435+ if (copy_from_user(&nr, uaddr, sizeof(nr)))436436+ return -EFAULT;437437+438438+ mutex_lock(&dev->kvm->lock);439439+ r = kvm_riscv_aia_aplic_get_attr(dev->kvm, type, &nr);440440+ mutex_unlock(&dev->kvm->lock);441441+ if (r)442442+ return r;443443+444444+ if (copy_to_user(uaddr, &nr, sizeof(nr)))445445+ return -EFAULT;446446+447447+ break;448448+ case KVM_DEV_RISCV_AIA_GRP_IMSIC:449449+ if (copy_from_user(&v, uaddr, sizeof(v)))450450+ return -EFAULT;451451+452452+ mutex_lock(&dev->kvm->lock);453453+ r = kvm_riscv_aia_imsic_rw_attr(dev->kvm, type, false, &v);454454+ mutex_unlock(&dev->kvm->lock);455455+ if (r)456456+ return r;457457+458458+ if (copy_to_user(uaddr, &v, sizeof(v)))459459+ return -EFAULT;460460+461461+ break;462462+ }463463+464464+ return r;465465+}466466+467467+static int aia_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr)468468+{469469+ int nr_vcpus;470470+471471+ switch (attr->group) {472472+ case KVM_DEV_RISCV_AIA_GRP_CONFIG:473473+ switch (attr->attr) {474474+ case KVM_DEV_RISCV_AIA_CONFIG_MODE:475475+ case KVM_DEV_RISCV_AIA_CONFIG_IDS:476476+ case KVM_DEV_RISCV_AIA_CONFIG_SRCS:477477+ case KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS:478478+ case KVM_DEV_RISCV_AIA_CONFIG_GROUP_SHIFT:479479+ case KVM_DEV_RISCV_AIA_CONFIG_HART_BITS:480480+ case KVM_DEV_RISCV_AIA_CONFIG_GUEST_BITS:481481+ return 0;482482+ }483483+ break;484484+ case KVM_DEV_RISCV_AIA_GRP_ADDR:485485+ nr_vcpus = atomic_read(&dev->kvm->online_vcpus);486486+ if (attr->attr == KVM_DEV_RISCV_AIA_ADDR_APLIC)487487+ return 0;488488+ else if (attr->attr < KVM_DEV_RISCV_AIA_ADDR_IMSIC(nr_vcpus))489489+ return 0;490490+ break;491491+ case KVM_DEV_RISCV_AIA_GRP_CTRL:492492+ switch (attr->attr) {493493+ case KVM_DEV_RISCV_AIA_CTRL_INIT:494494+ return 0;495495+ }496496+ break;497497+ case KVM_DEV_RISCV_AIA_GRP_APLIC:498498+ return kvm_riscv_aia_aplic_has_attr(dev->kvm, attr->attr);499499+ case KVM_DEV_RISCV_AIA_GRP_IMSIC:500500+ return kvm_riscv_aia_imsic_has_attr(dev->kvm, attr->attr);501501+ }502502+503503+ return -ENXIO;504504+}505505+506506+struct kvm_device_ops kvm_riscv_aia_device_ops = {507507+ .name = "kvm-riscv-aia",508508+ .create = aia_create,509509+ .destroy = aia_destroy,510510+ .set_attr = aia_set_attr,511511+ .get_attr = aia_get_attr,512512+ .has_attr = aia_has_attr,513513+};514514+515515+int kvm_riscv_vcpu_aia_update(struct kvm_vcpu *vcpu)516516+{517517+ /* Proceed only if AIA was initialized successfully */518518+ if (!kvm_riscv_aia_initialized(vcpu->kvm))519519+ return 1;520520+521521+ /* Update the IMSIC HW state before entering guest mode */522522+ return kvm_riscv_vcpu_aia_imsic_update(vcpu);523523+}524524+525525+void kvm_riscv_vcpu_aia_reset(struct kvm_vcpu *vcpu)526526+{527527+ struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;528528+ struct kvm_vcpu_aia_csr *reset_csr =529529+ &vcpu->arch.aia_context.guest_reset_csr;530530+531531+ if (!kvm_riscv_aia_available())532532+ return;533533+ memcpy(csr, reset_csr, sizeof(*csr));534534+535535+ /* Proceed only if AIA was initialized successfully */536536+ if (!kvm_riscv_aia_initialized(vcpu->kvm))537537+ return;538538+539539+ /* Reset the IMSIC context */540540+ kvm_riscv_vcpu_aia_imsic_reset(vcpu);541541+}542542+543543+int kvm_riscv_vcpu_aia_init(struct kvm_vcpu *vcpu)544544+{545545+ struct kvm_vcpu_aia *vaia = &vcpu->arch.aia_context;546546+547547+ if (!kvm_riscv_aia_available())548548+ return 0;549549+550550+ /*551551+ * We don't do any memory allocations over here because these552552+ * will be done after AIA device is initialized by the user-space.553553+ *554554+ * Refer, aia_init() implementation for more details.555555+ */556556+557557+ /* Initialize default values in AIA vcpu context */558558+ vaia->imsic_addr = KVM_RISCV_AIA_UNDEF_ADDR;559559+ vaia->hart_index = vcpu->vcpu_idx;560560+561561+ return 0;562562+}563563+564564+void kvm_riscv_vcpu_aia_deinit(struct kvm_vcpu *vcpu)565565+{566566+ /* Proceed only if AIA was initialized successfully */567567+ if (!kvm_riscv_aia_initialized(vcpu->kvm))568568+ return;569569+570570+ /* Cleanup IMSIC context */571571+ kvm_riscv_vcpu_aia_imsic_cleanup(vcpu);572572+}573573+574574+int kvm_riscv_aia_inject_msi_by_id(struct kvm *kvm, u32 hart_index,575575+ u32 guest_index, u32 iid)576576+{577577+ unsigned long idx;578578+ struct kvm_vcpu *vcpu;579579+580580+ /* Proceed only if AIA was initialized successfully */581581+ if (!kvm_riscv_aia_initialized(kvm))582582+ return -EBUSY;583583+584584+ /* Inject MSI to matching VCPU */585585+ kvm_for_each_vcpu(idx, vcpu, kvm) {586586+ if (vcpu->arch.aia_context.hart_index == hart_index)587587+ return kvm_riscv_vcpu_aia_imsic_inject(vcpu,588588+ guest_index,589589+ 0, iid);590590+ }591591+592592+ return 0;593593+}594594+595595+int kvm_riscv_aia_inject_msi(struct kvm *kvm, struct kvm_msi *msi)596596+{597597+ gpa_t tppn, ippn;598598+ unsigned long idx;599599+ struct kvm_vcpu *vcpu;600600+ u32 g, toff, iid = msi->data;601601+ struct kvm_aia *aia = &kvm->arch.aia;602602+ gpa_t target = (((gpa_t)msi->address_hi) << 32) | msi->address_lo;603603+604604+ /* Proceed only if AIA was initialized successfully */605605+ if (!kvm_riscv_aia_initialized(kvm))606606+ return -EBUSY;607607+608608+ /* Convert target address to target PPN */609609+ tppn = target >> IMSIC_MMIO_PAGE_SHIFT;610610+611611+ /* Extract and clear Guest ID from target PPN */612612+ g = tppn & (BIT(aia->nr_guest_bits) - 1);613613+ tppn &= ~((gpa_t)(BIT(aia->nr_guest_bits) - 1));614614+615615+ /* Inject MSI to matching VCPU */616616+ kvm_for_each_vcpu(idx, vcpu, kvm) {617617+ ippn = vcpu->arch.aia_context.imsic_addr >>618618+ IMSIC_MMIO_PAGE_SHIFT;619619+ if (ippn == tppn) {620620+ toff = target & (IMSIC_MMIO_PAGE_SZ - 1);621621+ return kvm_riscv_vcpu_aia_imsic_inject(vcpu, g,622622+ toff, iid);623623+ }624624+ }625625+626626+ return 0;627627+}628628+629629+int kvm_riscv_aia_inject_irq(struct kvm *kvm, unsigned int irq, bool level)630630+{631631+ /* Proceed only if AIA was initialized successfully */632632+ if (!kvm_riscv_aia_initialized(kvm))633633+ return -EBUSY;634634+635635+ /* Inject interrupt level change in APLIC */636636+ return kvm_riscv_aia_aplic_inject(kvm, irq, level);637637+}638638+639639+void kvm_riscv_aia_init_vm(struct kvm *kvm)640640+{641641+ struct kvm_aia *aia = &kvm->arch.aia;642642+643643+ if (!kvm_riscv_aia_available())644644+ return;645645+646646+ /*647647+ * We don't do any memory allocations over here because these648648+ * will be done after AIA device is initialized by the user-space.649649+ *650650+ * Refer, aia_init() implementation for more details.651651+ */652652+653653+ /* Initialize default values in AIA global context */654654+ aia->mode = (kvm_riscv_aia_nr_hgei) ?655655+ KVM_DEV_RISCV_AIA_MODE_AUTO : KVM_DEV_RISCV_AIA_MODE_EMUL;656656+ aia->nr_ids = kvm_riscv_aia_max_ids - 1;657657+ aia->nr_sources = 0;658658+ aia->nr_group_bits = 0;659659+ aia->nr_group_shift = KVM_DEV_RISCV_AIA_GROUP_SHIFT_MIN;660660+ aia->nr_hart_bits = 0;661661+ aia->nr_guest_bits = 0;662662+ aia->aplic_addr = KVM_RISCV_AIA_UNDEF_ADDR;663663+}664664+665665+void kvm_riscv_aia_destroy_vm(struct kvm *kvm)666666+{667667+ /* Proceed only if AIA was initialized successfully */668668+ if (!kvm_riscv_aia_initialized(kvm))669669+ return;670670+671671+ /* Cleanup APLIC context */672672+ kvm_riscv_aia_aplic_cleanup(kvm);673673+}
+1084
arch/riscv/kvm/aia_imsic.c
···11+// SPDX-License-Identifier: GPL-2.022+/*33+ * Copyright (C) 2021 Western Digital Corporation or its affiliates.44+ * Copyright (C) 2022 Ventana Micro Systems Inc.55+ *66+ * Authors:77+ * Anup Patel <apatel@ventanamicro.com>88+ */99+1010+#include <linux/atomic.h>1111+#include <linux/bitmap.h>1212+#include <linux/kvm_host.h>1313+#include <linux/math.h>1414+#include <linux/spinlock.h>1515+#include <linux/swab.h>1616+#include <kvm/iodev.h>1717+#include <asm/csr.h>1818+#include <asm/kvm_aia_imsic.h>1919+2020+#define IMSIC_MAX_EIX (IMSIC_MAX_ID / BITS_PER_TYPE(u64))2121+2222+struct imsic_mrif_eix {2323+ unsigned long eip[BITS_PER_TYPE(u64) / BITS_PER_LONG];2424+ unsigned long eie[BITS_PER_TYPE(u64) / BITS_PER_LONG];2525+};2626+2727+struct imsic_mrif {2828+ struct imsic_mrif_eix eix[IMSIC_MAX_EIX];2929+ unsigned long eithreshold;3030+ unsigned long eidelivery;3131+};3232+3333+struct imsic {3434+ struct kvm_io_device iodev;3535+3636+ u32 nr_msis;3737+ u32 nr_eix;3838+ u32 nr_hw_eix;3939+4040+ /*4141+ * At any point in time, the register state is in4242+ * one of the following places:4343+ *4444+ * 1) Hardware: IMSIC VS-file (vsfile_cpu >= 0)4545+ * 2) Software: IMSIC SW-file (vsfile_cpu < 0)4646+ */4747+4848+ /* IMSIC VS-file */4949+ rwlock_t vsfile_lock;5050+ int vsfile_cpu;5151+ int vsfile_hgei;5252+ void __iomem *vsfile_va;5353+ phys_addr_t vsfile_pa;5454+5555+ /* IMSIC SW-file */5656+ struct imsic_mrif *swfile;5757+ phys_addr_t swfile_pa;5858+};5959+6060+#define imsic_vs_csr_read(__c) \6161+({ \6262+ unsigned long __r; \6363+ csr_write(CSR_VSISELECT, __c); \6464+ __r = csr_read(CSR_VSIREG); \6565+ __r; \6666+})6767+6868+#define imsic_read_switchcase(__ireg) \6969+ case __ireg: \7070+ return imsic_vs_csr_read(__ireg);7171+#define imsic_read_switchcase_2(__ireg) \7272+ imsic_read_switchcase(__ireg + 0) \7373+ imsic_read_switchcase(__ireg + 1)7474+#define imsic_read_switchcase_4(__ireg) \7575+ imsic_read_switchcase_2(__ireg + 0) \7676+ imsic_read_switchcase_2(__ireg + 2)7777+#define imsic_read_switchcase_8(__ireg) \7878+ imsic_read_switchcase_4(__ireg + 0) \7979+ imsic_read_switchcase_4(__ireg + 4)8080+#define imsic_read_switchcase_16(__ireg) \8181+ imsic_read_switchcase_8(__ireg + 0) \8282+ imsic_read_switchcase_8(__ireg + 8)8383+#define imsic_read_switchcase_32(__ireg) \8484+ imsic_read_switchcase_16(__ireg + 0) \8585+ imsic_read_switchcase_16(__ireg + 16)8686+#define imsic_read_switchcase_64(__ireg) \8787+ imsic_read_switchcase_32(__ireg + 0) \8888+ imsic_read_switchcase_32(__ireg + 32)8989+9090+static unsigned long imsic_eix_read(int ireg)9191+{9292+ switch (ireg) {9393+ imsic_read_switchcase_64(IMSIC_EIP0)9494+ imsic_read_switchcase_64(IMSIC_EIE0)9595+ }9696+9797+ return 0;9898+}9999+100100+#define imsic_vs_csr_swap(__c, __v) \101101+({ \102102+ unsigned long __r; \103103+ csr_write(CSR_VSISELECT, __c); \104104+ __r = csr_swap(CSR_VSIREG, __v); \105105+ __r; \106106+})107107+108108+#define imsic_swap_switchcase(__ireg, __v) \109109+ case __ireg: \110110+ return imsic_vs_csr_swap(__ireg, __v);111111+#define imsic_swap_switchcase_2(__ireg, __v) \112112+ imsic_swap_switchcase(__ireg + 0, __v) \113113+ imsic_swap_switchcase(__ireg + 1, __v)114114+#define imsic_swap_switchcase_4(__ireg, __v) \115115+ imsic_swap_switchcase_2(__ireg + 0, __v) \116116+ imsic_swap_switchcase_2(__ireg + 2, __v)117117+#define imsic_swap_switchcase_8(__ireg, __v) \118118+ imsic_swap_switchcase_4(__ireg + 0, __v) \119119+ imsic_swap_switchcase_4(__ireg + 4, __v)120120+#define imsic_swap_switchcase_16(__ireg, __v) \121121+ imsic_swap_switchcase_8(__ireg + 0, __v) \122122+ imsic_swap_switchcase_8(__ireg + 8, __v)123123+#define imsic_swap_switchcase_32(__ireg, __v) \124124+ imsic_swap_switchcase_16(__ireg + 0, __v) \125125+ imsic_swap_switchcase_16(__ireg + 16, __v)126126+#define imsic_swap_switchcase_64(__ireg, __v) \127127+ imsic_swap_switchcase_32(__ireg + 0, __v) \128128+ imsic_swap_switchcase_32(__ireg + 32, __v)129129+130130+static unsigned long imsic_eix_swap(int ireg, unsigned long val)131131+{132132+ switch (ireg) {133133+ imsic_swap_switchcase_64(IMSIC_EIP0, val)134134+ imsic_swap_switchcase_64(IMSIC_EIE0, val)135135+ }136136+137137+ return 0;138138+}139139+140140+#define imsic_vs_csr_write(__c, __v) \141141+do { \142142+ csr_write(CSR_VSISELECT, __c); \143143+ csr_write(CSR_VSIREG, __v); \144144+} while (0)145145+146146+#define imsic_write_switchcase(__ireg, __v) \147147+ case __ireg: \148148+ imsic_vs_csr_write(__ireg, __v); \149149+ break;150150+#define imsic_write_switchcase_2(__ireg, __v) \151151+ imsic_write_switchcase(__ireg + 0, __v) \152152+ imsic_write_switchcase(__ireg + 1, __v)153153+#define imsic_write_switchcase_4(__ireg, __v) \154154+ imsic_write_switchcase_2(__ireg + 0, __v) \155155+ imsic_write_switchcase_2(__ireg + 2, __v)156156+#define imsic_write_switchcase_8(__ireg, __v) \157157+ imsic_write_switchcase_4(__ireg + 0, __v) \158158+ imsic_write_switchcase_4(__ireg + 4, __v)159159+#define imsic_write_switchcase_16(__ireg, __v) \160160+ imsic_write_switchcase_8(__ireg + 0, __v) \161161+ imsic_write_switchcase_8(__ireg + 8, __v)162162+#define imsic_write_switchcase_32(__ireg, __v) \163163+ imsic_write_switchcase_16(__ireg + 0, __v) \164164+ imsic_write_switchcase_16(__ireg + 16, __v)165165+#define imsic_write_switchcase_64(__ireg, __v) \166166+ imsic_write_switchcase_32(__ireg + 0, __v) \167167+ imsic_write_switchcase_32(__ireg + 32, __v)168168+169169+static void imsic_eix_write(int ireg, unsigned long val)170170+{171171+ switch (ireg) {172172+ imsic_write_switchcase_64(IMSIC_EIP0, val)173173+ imsic_write_switchcase_64(IMSIC_EIE0, val)174174+ }175175+}176176+177177+#define imsic_vs_csr_set(__c, __v) \178178+do { \179179+ csr_write(CSR_VSISELECT, __c); \180180+ csr_set(CSR_VSIREG, __v); \181181+} while (0)182182+183183+#define imsic_set_switchcase(__ireg, __v) \184184+ case __ireg: \185185+ imsic_vs_csr_set(__ireg, __v); \186186+ break;187187+#define imsic_set_switchcase_2(__ireg, __v) \188188+ imsic_set_switchcase(__ireg + 0, __v) \189189+ imsic_set_switchcase(__ireg + 1, __v)190190+#define imsic_set_switchcase_4(__ireg, __v) \191191+ imsic_set_switchcase_2(__ireg + 0, __v) \192192+ imsic_set_switchcase_2(__ireg + 2, __v)193193+#define imsic_set_switchcase_8(__ireg, __v) \194194+ imsic_set_switchcase_4(__ireg + 0, __v) \195195+ imsic_set_switchcase_4(__ireg + 4, __v)196196+#define imsic_set_switchcase_16(__ireg, __v) \197197+ imsic_set_switchcase_8(__ireg + 0, __v) \198198+ imsic_set_switchcase_8(__ireg + 8, __v)199199+#define imsic_set_switchcase_32(__ireg, __v) \200200+ imsic_set_switchcase_16(__ireg + 0, __v) \201201+ imsic_set_switchcase_16(__ireg + 16, __v)202202+#define imsic_set_switchcase_64(__ireg, __v) \203203+ imsic_set_switchcase_32(__ireg + 0, __v) \204204+ imsic_set_switchcase_32(__ireg + 32, __v)205205+206206+static void imsic_eix_set(int ireg, unsigned long val)207207+{208208+ switch (ireg) {209209+ imsic_set_switchcase_64(IMSIC_EIP0, val)210210+ imsic_set_switchcase_64(IMSIC_EIE0, val)211211+ }212212+}213213+214214+static unsigned long imsic_mrif_atomic_rmw(struct imsic_mrif *mrif,215215+ unsigned long *ptr,216216+ unsigned long new_val,217217+ unsigned long wr_mask)218218+{219219+ unsigned long old_val = 0, tmp = 0;220220+221221+ __asm__ __volatile__ (222222+ "0: lr.w.aq %1, %0\n"223223+ " and %2, %1, %3\n"224224+ " or %2, %2, %4\n"225225+ " sc.w.rl %2, %2, %0\n"226226+ " bnez %2, 0b"227227+ : "+A" (*ptr), "+r" (old_val), "+r" (tmp)228228+ : "r" (~wr_mask), "r" (new_val & wr_mask)229229+ : "memory");230230+231231+ return old_val;232232+}233233+234234+static unsigned long imsic_mrif_atomic_or(struct imsic_mrif *mrif,235235+ unsigned long *ptr,236236+ unsigned long val)237237+{238238+ return atomic_long_fetch_or(val, (atomic_long_t *)ptr);239239+}240240+241241+#define imsic_mrif_atomic_write(__mrif, __ptr, __new_val) \242242+ imsic_mrif_atomic_rmw(__mrif, __ptr, __new_val, -1UL)243243+#define imsic_mrif_atomic_read(__mrif, __ptr) \244244+ imsic_mrif_atomic_or(__mrif, __ptr, 0)245245+246246+static u32 imsic_mrif_topei(struct imsic_mrif *mrif, u32 nr_eix, u32 nr_msis)247247+{248248+ struct imsic_mrif_eix *eix;249249+ u32 i, imin, imax, ei, max_msi;250250+ unsigned long eipend[BITS_PER_TYPE(u64) / BITS_PER_LONG];251251+ unsigned long eithreshold = imsic_mrif_atomic_read(mrif,252252+ &mrif->eithreshold);253253+254254+ max_msi = (eithreshold && (eithreshold <= nr_msis)) ?255255+ eithreshold : nr_msis;256256+ for (ei = 0; ei < nr_eix; ei++) {257257+ eix = &mrif->eix[ei];258258+ eipend[0] = imsic_mrif_atomic_read(mrif, &eix->eie[0]) &259259+ imsic_mrif_atomic_read(mrif, &eix->eip[0]);260260+#ifdef CONFIG_32BIT261261+ eipend[1] = imsic_mrif_atomic_read(mrif, &eix->eie[1]) &262262+ imsic_mrif_atomic_read(mrif, &eix->eip[1]);263263+ if (!eipend[0] && !eipend[1])264264+#else265265+ if (!eipend[0])266266+#endif267267+ continue;268268+269269+ imin = ei * BITS_PER_TYPE(u64);270270+ imax = ((imin + BITS_PER_TYPE(u64)) < max_msi) ?271271+ imin + BITS_PER_TYPE(u64) : max_msi;272272+ for (i = (!imin) ? 1 : imin; i < imax; i++) {273273+ if (test_bit(i - imin, eipend))274274+ return (i << TOPEI_ID_SHIFT) | i;275275+ }276276+ }277277+278278+ return 0;279279+}280280+281281+static int imsic_mrif_isel_check(u32 nr_eix, unsigned long isel)282282+{283283+ u32 num = 0;284284+285285+ switch (isel) {286286+ case IMSIC_EIDELIVERY:287287+ case IMSIC_EITHRESHOLD:288288+ break;289289+ case IMSIC_EIP0 ... IMSIC_EIP63:290290+ num = isel - IMSIC_EIP0;291291+ break;292292+ case IMSIC_EIE0 ... IMSIC_EIE63:293293+ num = isel - IMSIC_EIE0;294294+ break;295295+ default:296296+ return -ENOENT;297297+ }298298+#ifndef CONFIG_32BIT299299+ if (num & 0x1)300300+ return -EINVAL;301301+#endif302302+ if ((num / 2) >= nr_eix)303303+ return -EINVAL;304304+305305+ return 0;306306+}307307+308308+static int imsic_mrif_rmw(struct imsic_mrif *mrif, u32 nr_eix,309309+ unsigned long isel, unsigned long *val,310310+ unsigned long new_val, unsigned long wr_mask)311311+{312312+ bool pend;313313+ struct imsic_mrif_eix *eix;314314+ unsigned long *ei, num, old_val = 0;315315+316316+ switch (isel) {317317+ case IMSIC_EIDELIVERY:318318+ old_val = imsic_mrif_atomic_rmw(mrif, &mrif->eidelivery,319319+ new_val, wr_mask & 0x1);320320+ break;321321+ case IMSIC_EITHRESHOLD:322322+ old_val = imsic_mrif_atomic_rmw(mrif, &mrif->eithreshold,323323+ new_val, wr_mask & (IMSIC_MAX_ID - 1));324324+ break;325325+ case IMSIC_EIP0 ... IMSIC_EIP63:326326+ case IMSIC_EIE0 ... IMSIC_EIE63:327327+ if (isel >= IMSIC_EIP0 && isel <= IMSIC_EIP63) {328328+ pend = true;329329+ num = isel - IMSIC_EIP0;330330+ } else {331331+ pend = false;332332+ num = isel - IMSIC_EIE0;333333+ }334334+335335+ if ((num / 2) >= nr_eix)336336+ return -EINVAL;337337+ eix = &mrif->eix[num / 2];338338+339339+#ifndef CONFIG_32BIT340340+ if (num & 0x1)341341+ return -EINVAL;342342+ ei = (pend) ? &eix->eip[0] : &eix->eie[0];343343+#else344344+ ei = (pend) ? &eix->eip[num & 0x1] : &eix->eie[num & 0x1];345345+#endif346346+347347+ /* Bit0 of EIP0 or EIE0 is read-only */348348+ if (!num)349349+ wr_mask &= ~BIT(0);350350+351351+ old_val = imsic_mrif_atomic_rmw(mrif, ei, new_val, wr_mask);352352+ break;353353+ default:354354+ return -ENOENT;355355+ }356356+357357+ if (val)358358+ *val = old_val;359359+360360+ return 0;361361+}362362+363363+struct imsic_vsfile_read_data {364364+ int hgei;365365+ u32 nr_eix;366366+ bool clear;367367+ struct imsic_mrif *mrif;368368+};369369+370370+static void imsic_vsfile_local_read(void *data)371371+{372372+ u32 i;373373+ struct imsic_mrif_eix *eix;374374+ struct imsic_vsfile_read_data *idata = data;375375+ struct imsic_mrif *mrif = idata->mrif;376376+ unsigned long new_hstatus, old_hstatus, old_vsiselect;377377+378378+ old_vsiselect = csr_read(CSR_VSISELECT);379379+ old_hstatus = csr_read(CSR_HSTATUS);380380+ new_hstatus = old_hstatus & ~HSTATUS_VGEIN;381381+ new_hstatus |= ((unsigned long)idata->hgei) << HSTATUS_VGEIN_SHIFT;382382+ csr_write(CSR_HSTATUS, new_hstatus);383383+384384+ /*385385+ * We don't use imsic_mrif_atomic_xyz() functions to store386386+ * values in MRIF because imsic_vsfile_read() is always called387387+ * with pointer to temporary MRIF on stack.388388+ */389389+390390+ if (idata->clear) {391391+ mrif->eidelivery = imsic_vs_csr_swap(IMSIC_EIDELIVERY, 0);392392+ mrif->eithreshold = imsic_vs_csr_swap(IMSIC_EITHRESHOLD, 0);393393+ for (i = 0; i < idata->nr_eix; i++) {394394+ eix = &mrif->eix[i];395395+ eix->eip[0] = imsic_eix_swap(IMSIC_EIP0 + i * 2, 0);396396+ eix->eie[0] = imsic_eix_swap(IMSIC_EIE0 + i * 2, 0);397397+#ifdef CONFIG_32BIT398398+ eix->eip[1] = imsic_eix_swap(IMSIC_EIP0 + i * 2 + 1, 0);399399+ eix->eie[1] = imsic_eix_swap(IMSIC_EIE0 + i * 2 + 1, 0);400400+#endif401401+ }402402+ } else {403403+ mrif->eidelivery = imsic_vs_csr_read(IMSIC_EIDELIVERY);404404+ mrif->eithreshold = imsic_vs_csr_read(IMSIC_EITHRESHOLD);405405+ for (i = 0; i < idata->nr_eix; i++) {406406+ eix = &mrif->eix[i];407407+ eix->eip[0] = imsic_eix_read(IMSIC_EIP0 + i * 2);408408+ eix->eie[0] = imsic_eix_read(IMSIC_EIE0 + i * 2);409409+#ifdef CONFIG_32BIT410410+ eix->eip[1] = imsic_eix_read(IMSIC_EIP0 + i * 2 + 1);411411+ eix->eie[1] = imsic_eix_read(IMSIC_EIE0 + i * 2 + 1);412412+#endif413413+ }414414+ }415415+416416+ csr_write(CSR_HSTATUS, old_hstatus);417417+ csr_write(CSR_VSISELECT, old_vsiselect);418418+}419419+420420+static void imsic_vsfile_read(int vsfile_hgei, int vsfile_cpu, u32 nr_eix,421421+ bool clear, struct imsic_mrif *mrif)422422+{423423+ struct imsic_vsfile_read_data idata;424424+425425+ /* We can only read clear if we have a IMSIC VS-file */426426+ if (vsfile_cpu < 0 || vsfile_hgei <= 0)427427+ return;428428+429429+ /* We can only read clear on local CPU */430430+ idata.hgei = vsfile_hgei;431431+ idata.nr_eix = nr_eix;432432+ idata.clear = clear;433433+ idata.mrif = mrif;434434+ on_each_cpu_mask(cpumask_of(vsfile_cpu),435435+ imsic_vsfile_local_read, &idata, 1);436436+}437437+438438+struct imsic_vsfile_rw_data {439439+ int hgei;440440+ int isel;441441+ bool write;442442+ unsigned long val;443443+};444444+445445+static void imsic_vsfile_local_rw(void *data)446446+{447447+ struct imsic_vsfile_rw_data *idata = data;448448+ unsigned long new_hstatus, old_hstatus, old_vsiselect;449449+450450+ old_vsiselect = csr_read(CSR_VSISELECT);451451+ old_hstatus = csr_read(CSR_HSTATUS);452452+ new_hstatus = old_hstatus & ~HSTATUS_VGEIN;453453+ new_hstatus |= ((unsigned long)idata->hgei) << HSTATUS_VGEIN_SHIFT;454454+ csr_write(CSR_HSTATUS, new_hstatus);455455+456456+ switch (idata->isel) {457457+ case IMSIC_EIDELIVERY:458458+ if (idata->write)459459+ imsic_vs_csr_write(IMSIC_EIDELIVERY, idata->val);460460+ else461461+ idata->val = imsic_vs_csr_read(IMSIC_EIDELIVERY);462462+ break;463463+ case IMSIC_EITHRESHOLD:464464+ if (idata->write)465465+ imsic_vs_csr_write(IMSIC_EITHRESHOLD, idata->val);466466+ else467467+ idata->val = imsic_vs_csr_read(IMSIC_EITHRESHOLD);468468+ break;469469+ case IMSIC_EIP0 ... IMSIC_EIP63:470470+ case IMSIC_EIE0 ... IMSIC_EIE63:471471+#ifndef CONFIG_32BIT472472+ if (idata->isel & 0x1)473473+ break;474474+#endif475475+ if (idata->write)476476+ imsic_eix_write(idata->isel, idata->val);477477+ else478478+ idata->val = imsic_eix_read(idata->isel);479479+ break;480480+ default:481481+ break;482482+ }483483+484484+ csr_write(CSR_HSTATUS, old_hstatus);485485+ csr_write(CSR_VSISELECT, old_vsiselect);486486+}487487+488488+static int imsic_vsfile_rw(int vsfile_hgei, int vsfile_cpu, u32 nr_eix,489489+ unsigned long isel, bool write,490490+ unsigned long *val)491491+{492492+ int rc;493493+ struct imsic_vsfile_rw_data rdata;494494+495495+ /* We can only access register if we have a IMSIC VS-file */496496+ if (vsfile_cpu < 0 || vsfile_hgei <= 0)497497+ return -EINVAL;498498+499499+ /* Check IMSIC register iselect */500500+ rc = imsic_mrif_isel_check(nr_eix, isel);501501+ if (rc)502502+ return rc;503503+504504+ /* We can only access register on local CPU */505505+ rdata.hgei = vsfile_hgei;506506+ rdata.isel = isel;507507+ rdata.write = write;508508+ rdata.val = (write) ? *val : 0;509509+ on_each_cpu_mask(cpumask_of(vsfile_cpu),510510+ imsic_vsfile_local_rw, &rdata, 1);511511+512512+ if (!write)513513+ *val = rdata.val;514514+515515+ return 0;516516+}517517+518518+static void imsic_vsfile_local_clear(int vsfile_hgei, u32 nr_eix)519519+{520520+ u32 i;521521+ unsigned long new_hstatus, old_hstatus, old_vsiselect;522522+523523+ /* We can only zero-out if we have a IMSIC VS-file */524524+ if (vsfile_hgei <= 0)525525+ return;526526+527527+ old_vsiselect = csr_read(CSR_VSISELECT);528528+ old_hstatus = csr_read(CSR_HSTATUS);529529+ new_hstatus = old_hstatus & ~HSTATUS_VGEIN;530530+ new_hstatus |= ((unsigned long)vsfile_hgei) << HSTATUS_VGEIN_SHIFT;531531+ csr_write(CSR_HSTATUS, new_hstatus);532532+533533+ imsic_vs_csr_write(IMSIC_EIDELIVERY, 0);534534+ imsic_vs_csr_write(IMSIC_EITHRESHOLD, 0);535535+ for (i = 0; i < nr_eix; i++) {536536+ imsic_eix_write(IMSIC_EIP0 + i * 2, 0);537537+ imsic_eix_write(IMSIC_EIE0 + i * 2, 0);538538+#ifdef CONFIG_32BIT539539+ imsic_eix_write(IMSIC_EIP0 + i * 2 + 1, 0);540540+ imsic_eix_write(IMSIC_EIE0 + i * 2 + 1, 0);541541+#endif542542+ }543543+544544+ csr_write(CSR_HSTATUS, old_hstatus);545545+ csr_write(CSR_VSISELECT, old_vsiselect);546546+}547547+548548+static void imsic_vsfile_local_update(int vsfile_hgei, u32 nr_eix,549549+ struct imsic_mrif *mrif)550550+{551551+ u32 i;552552+ struct imsic_mrif_eix *eix;553553+ unsigned long new_hstatus, old_hstatus, old_vsiselect;554554+555555+ /* We can only update if we have a HW IMSIC context */556556+ if (vsfile_hgei <= 0)557557+ return;558558+559559+ /*560560+ * We don't use imsic_mrif_atomic_xyz() functions to read values561561+ * from MRIF in this function because it is always called with562562+ * pointer to temporary MRIF on stack.563563+ */564564+565565+ old_vsiselect = csr_read(CSR_VSISELECT);566566+ old_hstatus = csr_read(CSR_HSTATUS);567567+ new_hstatus = old_hstatus & ~HSTATUS_VGEIN;568568+ new_hstatus |= ((unsigned long)vsfile_hgei) << HSTATUS_VGEIN_SHIFT;569569+ csr_write(CSR_HSTATUS, new_hstatus);570570+571571+ for (i = 0; i < nr_eix; i++) {572572+ eix = &mrif->eix[i];573573+ imsic_eix_set(IMSIC_EIP0 + i * 2, eix->eip[0]);574574+ imsic_eix_set(IMSIC_EIE0 + i * 2, eix->eie[0]);575575+#ifdef CONFIG_32BIT576576+ imsic_eix_set(IMSIC_EIP0 + i * 2 + 1, eix->eip[1]);577577+ imsic_eix_set(IMSIC_EIE0 + i * 2 + 1, eix->eie[1]);578578+#endif579579+ }580580+ imsic_vs_csr_write(IMSIC_EITHRESHOLD, mrif->eithreshold);581581+ imsic_vs_csr_write(IMSIC_EIDELIVERY, mrif->eidelivery);582582+583583+ csr_write(CSR_HSTATUS, old_hstatus);584584+ csr_write(CSR_VSISELECT, old_vsiselect);585585+}586586+587587+static void imsic_vsfile_cleanup(struct imsic *imsic)588588+{589589+ int old_vsfile_hgei, old_vsfile_cpu;590590+ unsigned long flags;591591+592592+ /*593593+ * We don't use imsic_mrif_atomic_xyz() functions to clear the594594+ * SW-file in this function because it is always called when the595595+ * VCPU is being destroyed.596596+ */597597+598598+ write_lock_irqsave(&imsic->vsfile_lock, flags);599599+ old_vsfile_hgei = imsic->vsfile_hgei;600600+ old_vsfile_cpu = imsic->vsfile_cpu;601601+ imsic->vsfile_cpu = imsic->vsfile_hgei = -1;602602+ imsic->vsfile_va = NULL;603603+ imsic->vsfile_pa = 0;604604+ write_unlock_irqrestore(&imsic->vsfile_lock, flags);605605+606606+ memset(imsic->swfile, 0, sizeof(*imsic->swfile));607607+608608+ if (old_vsfile_cpu >= 0)609609+ kvm_riscv_aia_free_hgei(old_vsfile_cpu, old_vsfile_hgei);610610+}611611+612612+static void imsic_swfile_extirq_update(struct kvm_vcpu *vcpu)613613+{614614+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;615615+ struct imsic_mrif *mrif = imsic->swfile;616616+617617+ if (imsic_mrif_atomic_read(mrif, &mrif->eidelivery) &&618618+ imsic_mrif_topei(mrif, imsic->nr_eix, imsic->nr_msis))619619+ kvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_EXT);620620+ else621621+ kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT);622622+}623623+624624+static void imsic_swfile_read(struct kvm_vcpu *vcpu, bool clear,625625+ struct imsic_mrif *mrif)626626+{627627+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;628628+629629+ /*630630+ * We don't use imsic_mrif_atomic_xyz() functions to read and631631+ * write SW-file and MRIF in this function because it is always632632+ * called when VCPU is not using SW-file and the MRIF points to633633+ * a temporary MRIF on stack.634634+ */635635+636636+ memcpy(mrif, imsic->swfile, sizeof(*mrif));637637+ if (clear) {638638+ memset(imsic->swfile, 0, sizeof(*imsic->swfile));639639+ kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT);640640+ }641641+}642642+643643+static void imsic_swfile_update(struct kvm_vcpu *vcpu,644644+ struct imsic_mrif *mrif)645645+{646646+ u32 i;647647+ struct imsic_mrif_eix *seix, *eix;648648+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;649649+ struct imsic_mrif *smrif = imsic->swfile;650650+651651+ imsic_mrif_atomic_write(smrif, &smrif->eidelivery, mrif->eidelivery);652652+ imsic_mrif_atomic_write(smrif, &smrif->eithreshold, mrif->eithreshold);653653+ for (i = 0; i < imsic->nr_eix; i++) {654654+ seix = &smrif->eix[i];655655+ eix = &mrif->eix[i];656656+ imsic_mrif_atomic_or(smrif, &seix->eip[0], eix->eip[0]);657657+ imsic_mrif_atomic_or(smrif, &seix->eie[0], eix->eie[0]);658658+#ifdef CONFIG_32BIT659659+ imsic_mrif_atomic_or(smrif, &seix->eip[1], eix->eip[1]);660660+ imsic_mrif_atomic_or(smrif, &seix->eie[1], eix->eie[1]);661661+#endif662662+ }663663+664664+ imsic_swfile_extirq_update(vcpu);665665+}666666+667667+void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu)668668+{669669+ unsigned long flags;670670+ struct imsic_mrif tmrif;671671+ int old_vsfile_hgei, old_vsfile_cpu;672672+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;673673+674674+ /* Read and clear IMSIC VS-file details */675675+ write_lock_irqsave(&imsic->vsfile_lock, flags);676676+ old_vsfile_hgei = imsic->vsfile_hgei;677677+ old_vsfile_cpu = imsic->vsfile_cpu;678678+ imsic->vsfile_cpu = imsic->vsfile_hgei = -1;679679+ imsic->vsfile_va = NULL;680680+ imsic->vsfile_pa = 0;681681+ write_unlock_irqrestore(&imsic->vsfile_lock, flags);682682+683683+ /* Do nothing, if no IMSIC VS-file to release */684684+ if (old_vsfile_cpu < 0)685685+ return;686686+687687+ /*688688+ * At this point, all interrupt producers are still using689689+ * the old IMSIC VS-file so we first re-direct all interrupt690690+ * producers.691691+ */692692+693693+ /* Purge the G-stage mapping */694694+ kvm_riscv_gstage_iounmap(vcpu->kvm,695695+ vcpu->arch.aia_context.imsic_addr,696696+ IMSIC_MMIO_PAGE_SZ);697697+698698+ /* TODO: Purge the IOMMU mapping ??? */699699+700700+ /*701701+ * At this point, all interrupt producers have been re-directed702702+ * to somewhere else so we move register state from the old IMSIC703703+ * VS-file to the IMSIC SW-file.704704+ */705705+706706+ /* Read and clear register state from old IMSIC VS-file */707707+ memset(&tmrif, 0, sizeof(tmrif));708708+ imsic_vsfile_read(old_vsfile_hgei, old_vsfile_cpu, imsic->nr_hw_eix,709709+ true, &tmrif);710710+711711+ /* Update register state in IMSIC SW-file */712712+ imsic_swfile_update(vcpu, &tmrif);713713+714714+ /* Free-up old IMSIC VS-file */715715+ kvm_riscv_aia_free_hgei(old_vsfile_cpu, old_vsfile_hgei);716716+}717717+718718+int kvm_riscv_vcpu_aia_imsic_update(struct kvm_vcpu *vcpu)719719+{720720+ unsigned long flags;721721+ phys_addr_t new_vsfile_pa;722722+ struct imsic_mrif tmrif;723723+ void __iomem *new_vsfile_va;724724+ struct kvm *kvm = vcpu->kvm;725725+ struct kvm_run *run = vcpu->run;726726+ struct kvm_vcpu_aia *vaia = &vcpu->arch.aia_context;727727+ struct imsic *imsic = vaia->imsic_state;728728+ int ret = 0, new_vsfile_hgei = -1, old_vsfile_hgei, old_vsfile_cpu;729729+730730+ /* Do nothing for emulation mode */731731+ if (kvm->arch.aia.mode == KVM_DEV_RISCV_AIA_MODE_EMUL)732732+ return 1;733733+734734+ /* Read old IMSIC VS-file details */735735+ read_lock_irqsave(&imsic->vsfile_lock, flags);736736+ old_vsfile_hgei = imsic->vsfile_hgei;737737+ old_vsfile_cpu = imsic->vsfile_cpu;738738+ read_unlock_irqrestore(&imsic->vsfile_lock, flags);739739+740740+ /* Do nothing if we are continuing on same CPU */741741+ if (old_vsfile_cpu == vcpu->cpu)742742+ return 1;743743+744744+ /* Allocate new IMSIC VS-file */745745+ ret = kvm_riscv_aia_alloc_hgei(vcpu->cpu, vcpu,746746+ &new_vsfile_va, &new_vsfile_pa);747747+ if (ret <= 0) {748748+ /* For HW acceleration mode, we can't continue */749749+ if (kvm->arch.aia.mode == KVM_DEV_RISCV_AIA_MODE_HWACCEL) {750750+ run->fail_entry.hardware_entry_failure_reason =751751+ CSR_HSTATUS;752752+ run->fail_entry.cpu = vcpu->cpu;753753+ run->exit_reason = KVM_EXIT_FAIL_ENTRY;754754+ return 0;755755+ }756756+757757+ /* Release old IMSIC VS-file */758758+ if (old_vsfile_cpu >= 0)759759+ kvm_riscv_vcpu_aia_imsic_release(vcpu);760760+761761+ /* For automatic mode, we continue */762762+ goto done;763763+ }764764+ new_vsfile_hgei = ret;765765+766766+ /*767767+ * At this point, all interrupt producers are still using768768+ * to the old IMSIC VS-file so we first move all interrupt769769+ * producers to the new IMSIC VS-file.770770+ */771771+772772+ /* Zero-out new IMSIC VS-file */773773+ imsic_vsfile_local_clear(new_vsfile_hgei, imsic->nr_hw_eix);774774+775775+ /* Update G-stage mapping for the new IMSIC VS-file */776776+ ret = kvm_riscv_gstage_ioremap(kvm, vcpu->arch.aia_context.imsic_addr,777777+ new_vsfile_pa, IMSIC_MMIO_PAGE_SZ,778778+ true, true);779779+ if (ret)780780+ goto fail_free_vsfile_hgei;781781+782782+ /* TODO: Update the IOMMU mapping ??? */783783+784784+ /* Update new IMSIC VS-file details in IMSIC context */785785+ write_lock_irqsave(&imsic->vsfile_lock, flags);786786+ imsic->vsfile_hgei = new_vsfile_hgei;787787+ imsic->vsfile_cpu = vcpu->cpu;788788+ imsic->vsfile_va = new_vsfile_va;789789+ imsic->vsfile_pa = new_vsfile_pa;790790+ write_unlock_irqrestore(&imsic->vsfile_lock, flags);791791+792792+ /*793793+ * At this point, all interrupt producers have been moved794794+ * to the new IMSIC VS-file so we move register state from795795+ * the old IMSIC VS/SW-file to the new IMSIC VS-file.796796+ */797797+798798+ memset(&tmrif, 0, sizeof(tmrif));799799+ if (old_vsfile_cpu >= 0) {800800+ /* Read and clear register state from old IMSIC VS-file */801801+ imsic_vsfile_read(old_vsfile_hgei, old_vsfile_cpu,802802+ imsic->nr_hw_eix, true, &tmrif);803803+804804+ /* Free-up old IMSIC VS-file */805805+ kvm_riscv_aia_free_hgei(old_vsfile_cpu, old_vsfile_hgei);806806+ } else {807807+ /* Read and clear register state from IMSIC SW-file */808808+ imsic_swfile_read(vcpu, true, &tmrif);809809+ }810810+811811+ /* Restore register state in the new IMSIC VS-file */812812+ imsic_vsfile_local_update(new_vsfile_hgei, imsic->nr_hw_eix, &tmrif);813813+814814+done:815815+ /* Set VCPU HSTATUS.VGEIN to new IMSIC VS-file */816816+ vcpu->arch.guest_context.hstatus &= ~HSTATUS_VGEIN;817817+ if (new_vsfile_hgei > 0)818818+ vcpu->arch.guest_context.hstatus |=819819+ ((unsigned long)new_vsfile_hgei) << HSTATUS_VGEIN_SHIFT;820820+821821+ /* Continue run-loop */822822+ return 1;823823+824824+fail_free_vsfile_hgei:825825+ kvm_riscv_aia_free_hgei(vcpu->cpu, new_vsfile_hgei);826826+ return ret;827827+}828828+829829+int kvm_riscv_vcpu_aia_imsic_rmw(struct kvm_vcpu *vcpu, unsigned long isel,830830+ unsigned long *val, unsigned long new_val,831831+ unsigned long wr_mask)832832+{833833+ u32 topei;834834+ struct imsic_mrif_eix *eix;835835+ int r, rc = KVM_INSN_CONTINUE_NEXT_SEPC;836836+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;837837+838838+ if (isel == KVM_RISCV_AIA_IMSIC_TOPEI) {839839+ /* Read pending and enabled interrupt with highest priority */840840+ topei = imsic_mrif_topei(imsic->swfile, imsic->nr_eix,841841+ imsic->nr_msis);842842+ if (val)843843+ *val = topei;844844+845845+ /* Writes ignore value and clear top pending interrupt */846846+ if (topei && wr_mask) {847847+ topei >>= TOPEI_ID_SHIFT;848848+ if (topei) {849849+ eix = &imsic->swfile->eix[topei /850850+ BITS_PER_TYPE(u64)];851851+ clear_bit(topei & (BITS_PER_TYPE(u64) - 1),852852+ eix->eip);853853+ }854854+ }855855+ } else {856856+ r = imsic_mrif_rmw(imsic->swfile, imsic->nr_eix, isel,857857+ val, new_val, wr_mask);858858+ /* Forward unknown IMSIC register to user-space */859859+ if (r)860860+ rc = (r == -ENOENT) ? 0 : KVM_INSN_ILLEGAL_TRAP;861861+ }862862+863863+ if (wr_mask)864864+ imsic_swfile_extirq_update(vcpu);865865+866866+ return rc;867867+}868868+869869+int kvm_riscv_aia_imsic_rw_attr(struct kvm *kvm, unsigned long type,870870+ bool write, unsigned long *val)871871+{872872+ u32 isel, vcpu_id;873873+ unsigned long flags;874874+ struct imsic *imsic;875875+ struct kvm_vcpu *vcpu;876876+ int rc, vsfile_hgei, vsfile_cpu;877877+878878+ if (!kvm_riscv_aia_initialized(kvm))879879+ return -ENODEV;880880+881881+ vcpu_id = KVM_DEV_RISCV_AIA_IMSIC_GET_VCPU(type);882882+ vcpu = kvm_get_vcpu_by_id(kvm, vcpu_id);883883+ if (!vcpu)884884+ return -ENODEV;885885+886886+ isel = KVM_DEV_RISCV_AIA_IMSIC_GET_ISEL(type);887887+ imsic = vcpu->arch.aia_context.imsic_state;888888+889889+ read_lock_irqsave(&imsic->vsfile_lock, flags);890890+891891+ rc = 0;892892+ vsfile_hgei = imsic->vsfile_hgei;893893+ vsfile_cpu = imsic->vsfile_cpu;894894+ if (vsfile_cpu < 0) {895895+ if (write) {896896+ rc = imsic_mrif_rmw(imsic->swfile, imsic->nr_eix,897897+ isel, NULL, *val, -1UL);898898+ imsic_swfile_extirq_update(vcpu);899899+ } else900900+ rc = imsic_mrif_rmw(imsic->swfile, imsic->nr_eix,901901+ isel, val, 0, 0);902902+ }903903+904904+ read_unlock_irqrestore(&imsic->vsfile_lock, flags);905905+906906+ if (!rc && vsfile_cpu >= 0)907907+ rc = imsic_vsfile_rw(vsfile_hgei, vsfile_cpu, imsic->nr_eix,908908+ isel, write, val);909909+910910+ return rc;911911+}912912+913913+int kvm_riscv_aia_imsic_has_attr(struct kvm *kvm, unsigned long type)914914+{915915+ u32 isel, vcpu_id;916916+ struct imsic *imsic;917917+ struct kvm_vcpu *vcpu;918918+919919+ if (!kvm_riscv_aia_initialized(kvm))920920+ return -ENODEV;921921+922922+ vcpu_id = KVM_DEV_RISCV_AIA_IMSIC_GET_VCPU(type);923923+ vcpu = kvm_get_vcpu_by_id(kvm, vcpu_id);924924+ if (!vcpu)925925+ return -ENODEV;926926+927927+ isel = KVM_DEV_RISCV_AIA_IMSIC_GET_ISEL(type);928928+ imsic = vcpu->arch.aia_context.imsic_state;929929+ return imsic_mrif_isel_check(imsic->nr_eix, isel);930930+}931931+932932+void kvm_riscv_vcpu_aia_imsic_reset(struct kvm_vcpu *vcpu)933933+{934934+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;935935+936936+ if (!imsic)937937+ return;938938+939939+ kvm_riscv_vcpu_aia_imsic_release(vcpu);940940+941941+ memset(imsic->swfile, 0, sizeof(*imsic->swfile));942942+}943943+944944+int kvm_riscv_vcpu_aia_imsic_inject(struct kvm_vcpu *vcpu,945945+ u32 guest_index, u32 offset, u32 iid)946946+{947947+ unsigned long flags;948948+ struct imsic_mrif_eix *eix;949949+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;950950+951951+ /* We only emulate one IMSIC MMIO page for each Guest VCPU */952952+ if (!imsic || !iid || guest_index ||953953+ (offset != IMSIC_MMIO_SETIPNUM_LE &&954954+ offset != IMSIC_MMIO_SETIPNUM_BE))955955+ return -ENODEV;956956+957957+ iid = (offset == IMSIC_MMIO_SETIPNUM_BE) ? __swab32(iid) : iid;958958+ if (imsic->nr_msis <= iid)959959+ return -EINVAL;960960+961961+ read_lock_irqsave(&imsic->vsfile_lock, flags);962962+963963+ if (imsic->vsfile_cpu >= 0) {964964+ writel(iid, imsic->vsfile_va + IMSIC_MMIO_SETIPNUM_LE);965965+ kvm_vcpu_kick(vcpu);966966+ } else {967967+ eix = &imsic->swfile->eix[iid / BITS_PER_TYPE(u64)];968968+ set_bit(iid & (BITS_PER_TYPE(u64) - 1), eix->eip);969969+ imsic_swfile_extirq_update(vcpu);970970+ }971971+972972+ read_unlock_irqrestore(&imsic->vsfile_lock, flags);973973+974974+ return 0;975975+}976976+977977+static int imsic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,978978+ gpa_t addr, int len, void *val)979979+{980980+ if (len != 4 || (addr & 0x3) != 0)981981+ return -EOPNOTSUPP;982982+983983+ *((u32 *)val) = 0;984984+985985+ return 0;986986+}987987+988988+static int imsic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,989989+ gpa_t addr, int len, const void *val)990990+{991991+ struct kvm_msi msi = { 0 };992992+993993+ if (len != 4 || (addr & 0x3) != 0)994994+ return -EOPNOTSUPP;995995+996996+ msi.address_hi = addr >> 32;997997+ msi.address_lo = (u32)addr;998998+ msi.data = *((const u32 *)val);999999+ kvm_riscv_aia_inject_msi(vcpu->kvm, &msi);10001000+10011001+ return 0;10021002+};10031003+10041004+static struct kvm_io_device_ops imsic_iodoev_ops = {10051005+ .read = imsic_mmio_read,10061006+ .write = imsic_mmio_write,10071007+};10081008+10091009+int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu)10101010+{10111011+ int ret = 0;10121012+ struct imsic *imsic;10131013+ struct page *swfile_page;10141014+ struct kvm *kvm = vcpu->kvm;10151015+10161016+ /* Fail if we have zero IDs */10171017+ if (!kvm->arch.aia.nr_ids)10181018+ return -EINVAL;10191019+10201020+ /* Allocate IMSIC context */10211021+ imsic = kzalloc(sizeof(*imsic), GFP_KERNEL);10221022+ if (!imsic)10231023+ return -ENOMEM;10241024+ vcpu->arch.aia_context.imsic_state = imsic;10251025+10261026+ /* Setup IMSIC context */10271027+ imsic->nr_msis = kvm->arch.aia.nr_ids + 1;10281028+ rwlock_init(&imsic->vsfile_lock);10291029+ imsic->nr_eix = BITS_TO_U64(imsic->nr_msis);10301030+ imsic->nr_hw_eix = BITS_TO_U64(kvm_riscv_aia_max_ids);10311031+ imsic->vsfile_hgei = imsic->vsfile_cpu = -1;10321032+10331033+ /* Setup IMSIC SW-file */10341034+ swfile_page = alloc_pages(GFP_KERNEL | __GFP_ZERO,10351035+ get_order(sizeof(*imsic->swfile)));10361036+ if (!swfile_page) {10371037+ ret = -ENOMEM;10381038+ goto fail_free_imsic;10391039+ }10401040+ imsic->swfile = page_to_virt(swfile_page);10411041+ imsic->swfile_pa = page_to_phys(swfile_page);10421042+10431043+ /* Setup IO device */10441044+ kvm_iodevice_init(&imsic->iodev, &imsic_iodoev_ops);10451045+ mutex_lock(&kvm->slots_lock);10461046+ ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,10471047+ vcpu->arch.aia_context.imsic_addr,10481048+ KVM_DEV_RISCV_IMSIC_SIZE,10491049+ &imsic->iodev);10501050+ mutex_unlock(&kvm->slots_lock);10511051+ if (ret)10521052+ goto fail_free_swfile;10531053+10541054+ return 0;10551055+10561056+fail_free_swfile:10571057+ free_pages((unsigned long)imsic->swfile,10581058+ get_order(sizeof(*imsic->swfile)));10591059+fail_free_imsic:10601060+ vcpu->arch.aia_context.imsic_state = NULL;10611061+ kfree(imsic);10621062+ return ret;10631063+}10641064+10651065+void kvm_riscv_vcpu_aia_imsic_cleanup(struct kvm_vcpu *vcpu)10661066+{10671067+ struct kvm *kvm = vcpu->kvm;10681068+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;10691069+10701070+ if (!imsic)10711071+ return;10721072+10731073+ imsic_vsfile_cleanup(imsic);10741074+10751075+ mutex_lock(&kvm->slots_lock);10761076+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &imsic->iodev);10771077+ mutex_unlock(&kvm->slots_lock);10781078+10791079+ free_pages((unsigned long)imsic->swfile,10801080+ get_order(sizeof(*imsic->swfile)));10811081+10821082+ vcpu->arch.aia_context.imsic_state = NULL;10831083+ kfree(imsic);10841084+}
+2-1
arch/riscv/kvm/main.c
···116116 kvm_info("VMID %ld bits available\n", kvm_riscv_gstage_vmid_bits());117117118118 if (kvm_riscv_aia_available())119119- kvm_info("AIA available\n");119119+ kvm_info("AIA available with %d guest external interrupts\n",120120+ kvm_riscv_aia_nr_hgei);120121121122 rc = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);122123 if (rc) {
+1-1
arch/riscv/kvm/tlb.c
···296296 unsigned int actual_req = req;297297 DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS);298298299299- bitmap_clear(vcpu_mask, 0, KVM_MAX_VCPUS);299299+ bitmap_zero(vcpu_mask, KVM_MAX_VCPUS);300300 kvm_for_each_vcpu(i, vcpu, kvm) {301301 if (hbase != -1UL) {302302 if (vcpu->vcpu_id < hbase)
+4
arch/riscv/kvm/vcpu.c
···6161 KVM_ISA_EXT_ARR(SSAIA),6262 KVM_ISA_EXT_ARR(SSTC),6363 KVM_ISA_EXT_ARR(SVINVAL),6464+ KVM_ISA_EXT_ARR(SVNAPOT),6465 KVM_ISA_EXT_ARR(SVPBMT),6566 KVM_ISA_EXT_ARR(ZBB),6667 KVM_ISA_EXT_ARR(ZIHINTPAUSE),···103102 case KVM_RISCV_ISA_EXT_SSAIA:104103 case KVM_RISCV_ISA_EXT_SSTC:105104 case KVM_RISCV_ISA_EXT_SVINVAL:105105+ case KVM_RISCV_ISA_EXT_SVNAPOT:106106 case KVM_RISCV_ISA_EXT_ZIHINTPAUSE:107107 case KVM_RISCV_ISA_EXT_ZBB:108108 return false;···252250253251void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)254252{253253+ kvm_riscv_aia_wakeon_hgei(vcpu, true);255254}256255257256void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)258257{258258+ kvm_riscv_aia_wakeon_hgei(vcpu, false);259259}260260261261int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
+2
arch/riscv/kvm/vcpu_exit.c
···183183 run->exit_reason = KVM_EXIT_UNKNOWN;184184 switch (trap->scause) {185185 case EXC_INST_ILLEGAL:186186+ case EXC_LOAD_MISALIGNED:187187+ case EXC_STORE_MISALIGNED:186188 if (vcpu->arch.guest_context.hstatus & HSTATUS_SPV) {187189 kvm_riscv_vcpu_trap_redirect(vcpu, trap);188190 ret = 1;
+54-26
arch/riscv/kvm/vcpu_sbi.c
···2020};2121#endif22222323-#ifdef CONFIG_RISCV_PMU_SBI2424-extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu;2525-#else2323+#ifndef CONFIG_RISCV_PMU_SBI2624static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = {2725 .extid_start = -1UL,2826 .extid_end = -1UL,···2931#endif30323133struct kvm_riscv_sbi_extension_entry {3232- enum KVM_RISCV_SBI_EXT_ID dis_idx;3434+ enum KVM_RISCV_SBI_EXT_ID ext_idx;3335 const struct kvm_vcpu_sbi_extension *ext_ptr;3436};35373638static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {3739 {3838- .dis_idx = KVM_RISCV_SBI_EXT_V01,4040+ .ext_idx = KVM_RISCV_SBI_EXT_V01,3941 .ext_ptr = &vcpu_sbi_ext_v01,4042 },4143 {4242- .dis_idx = KVM_RISCV_SBI_EXT_MAX, /* Can't be disabled */4444+ .ext_idx = KVM_RISCV_SBI_EXT_MAX, /* Can't be disabled */4345 .ext_ptr = &vcpu_sbi_ext_base,4446 },4547 {4646- .dis_idx = KVM_RISCV_SBI_EXT_TIME,4848+ .ext_idx = KVM_RISCV_SBI_EXT_TIME,4749 .ext_ptr = &vcpu_sbi_ext_time,4850 },4951 {5050- .dis_idx = KVM_RISCV_SBI_EXT_IPI,5252+ .ext_idx = KVM_RISCV_SBI_EXT_IPI,5153 .ext_ptr = &vcpu_sbi_ext_ipi,5254 },5355 {5454- .dis_idx = KVM_RISCV_SBI_EXT_RFENCE,5656+ .ext_idx = KVM_RISCV_SBI_EXT_RFENCE,5557 .ext_ptr = &vcpu_sbi_ext_rfence,5658 },5759 {5858- .dis_idx = KVM_RISCV_SBI_EXT_SRST,6060+ .ext_idx = KVM_RISCV_SBI_EXT_SRST,5961 .ext_ptr = &vcpu_sbi_ext_srst,6062 },6163 {6262- .dis_idx = KVM_RISCV_SBI_EXT_HSM,6464+ .ext_idx = KVM_RISCV_SBI_EXT_HSM,6365 .ext_ptr = &vcpu_sbi_ext_hsm,6466 },6567 {6666- .dis_idx = KVM_RISCV_SBI_EXT_PMU,6868+ .ext_idx = KVM_RISCV_SBI_EXT_PMU,6769 .ext_ptr = &vcpu_sbi_ext_pmu,6870 },6971 {7070- .dis_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL,7272+ .ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL,7173 .ext_ptr = &vcpu_sbi_ext_experimental,7274 },7375 {7474- .dis_idx = KVM_RISCV_SBI_EXT_VENDOR,7676+ .ext_idx = KVM_RISCV_SBI_EXT_VENDOR,7577 .ext_ptr = &vcpu_sbi_ext_vendor,7678 },7779};···145147 return -EINVAL;146148147149 for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {148148- if (sbi_ext[i].dis_idx == reg_num) {150150+ if (sbi_ext[i].ext_idx == reg_num) {149151 sext = &sbi_ext[i];150152 break;151153 }···153155 if (!sext)154156 return -ENOENT;155157156156- scontext->extension_disabled[sext->dis_idx] = !reg_val;158158+ /*159159+ * We can't set the extension status to available here, since it may160160+ * have a probe() function which needs to confirm availability first,161161+ * but it may be too early to call that here. We can set the status to162162+ * unavailable, though.163163+ */164164+ if (!reg_val)165165+ scontext->ext_status[sext->ext_idx] =166166+ KVM_RISCV_SBI_EXT_UNAVAILABLE;157167158168 return 0;159169}···178172 return -EINVAL;179173180174 for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {181181- if (sbi_ext[i].dis_idx == reg_num) {175175+ if (sbi_ext[i].ext_idx == reg_num) {182176 sext = &sbi_ext[i];183177 break;184178 }···186180 if (!sext)187181 return -ENOENT;188182189189- *reg_val = !scontext->extension_disabled[sext->dis_idx];183183+ /*184184+ * If the extension status is still uninitialized, then we should probe185185+ * to determine if it's available, but it may be too early to do that186186+ * here. The best we can do is report that the extension has not been187187+ * disabled, i.e. we return 1 when the extension is available and also188188+ * when it only may be available.189189+ */190190+ *reg_val = scontext->ext_status[sext->ext_idx] !=191191+ KVM_RISCV_SBI_EXT_UNAVAILABLE;190192191193 return 0;192194}···321307const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(322308 struct kvm_vcpu *vcpu, unsigned long extid)323309{324324- int i;325325- const struct kvm_riscv_sbi_extension_entry *sext;326310 struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;311311+ const struct kvm_riscv_sbi_extension_entry *entry;312312+ const struct kvm_vcpu_sbi_extension *ext;313313+ int i;327314328315 for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {329329- sext = &sbi_ext[i];330330- if (sext->ext_ptr->extid_start <= extid &&331331- sext->ext_ptr->extid_end >= extid) {332332- if (sext->dis_idx < KVM_RISCV_SBI_EXT_MAX &&333333- scontext->extension_disabled[sext->dis_idx])316316+ entry = &sbi_ext[i];317317+ ext = entry->ext_ptr;318318+319319+ if (ext->extid_start <= extid && ext->extid_end >= extid) {320320+ if (entry->ext_idx >= KVM_RISCV_SBI_EXT_MAX ||321321+ scontext->ext_status[entry->ext_idx] ==322322+ KVM_RISCV_SBI_EXT_AVAILABLE)323323+ return ext;324324+ if (scontext->ext_status[entry->ext_idx] ==325325+ KVM_RISCV_SBI_EXT_UNAVAILABLE)334326 return NULL;335335- return sbi_ext[i].ext_ptr;327327+ if (ext->probe && !ext->probe(vcpu)) {328328+ scontext->ext_status[entry->ext_idx] =329329+ KVM_RISCV_SBI_EXT_UNAVAILABLE;330330+ return NULL;331331+ }332332+333333+ scontext->ext_status[entry->ext_idx] =334334+ KVM_RISCV_SBI_EXT_AVAILABLE;335335+ return ext;336336 }337337 }338338
+118
arch/riscv/kvm/vm.c
···5555 kvm_riscv_aia_destroy_vm(kvm);5656}57575858+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irql,5959+ bool line_status)6060+{6161+ if (!irqchip_in_kernel(kvm))6262+ return -ENXIO;6363+6464+ return kvm_riscv_aia_inject_irq(kvm, irql->irq, irql->level);6565+}6666+6767+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,6868+ struct kvm *kvm, int irq_source_id,6969+ int level, bool line_status)7070+{7171+ struct kvm_msi msi;7272+7373+ if (!level)7474+ return -1;7575+7676+ msi.address_lo = e->msi.address_lo;7777+ msi.address_hi = e->msi.address_hi;7878+ msi.data = e->msi.data;7979+ msi.flags = e->msi.flags;8080+ msi.devid = e->msi.devid;8181+8282+ return kvm_riscv_aia_inject_msi(kvm, &msi);8383+}8484+8585+static int kvm_riscv_set_irq(struct kvm_kernel_irq_routing_entry *e,8686+ struct kvm *kvm, int irq_source_id,8787+ int level, bool line_status)8888+{8989+ return kvm_riscv_aia_inject_irq(kvm, e->irqchip.pin, level);9090+}9191+9292+int kvm_riscv_setup_default_irq_routing(struct kvm *kvm, u32 lines)9393+{9494+ struct kvm_irq_routing_entry *ents;9595+ int i, rc;9696+9797+ ents = kcalloc(lines, sizeof(*ents), GFP_KERNEL);9898+ if (!ents)9999+ return -ENOMEM;100100+101101+ for (i = 0; i < lines; i++) {102102+ ents[i].gsi = i;103103+ ents[i].type = KVM_IRQ_ROUTING_IRQCHIP;104104+ ents[i].u.irqchip.irqchip = 0;105105+ ents[i].u.irqchip.pin = i;106106+ }107107+ rc = kvm_set_irq_routing(kvm, ents, lines, 0);108108+ kfree(ents);109109+110110+ return rc;111111+}112112+113113+bool kvm_arch_can_set_irq_routing(struct kvm *kvm)114114+{115115+ return irqchip_in_kernel(kvm);116116+}117117+118118+int kvm_set_routing_entry(struct kvm *kvm,119119+ struct kvm_kernel_irq_routing_entry *e,120120+ const struct kvm_irq_routing_entry *ue)121121+{122122+ int r = -EINVAL;123123+124124+ switch (ue->type) {125125+ case KVM_IRQ_ROUTING_IRQCHIP:126126+ e->set = kvm_riscv_set_irq;127127+ e->irqchip.irqchip = ue->u.irqchip.irqchip;128128+ e->irqchip.pin = ue->u.irqchip.pin;129129+ if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||130130+ (e->irqchip.irqchip >= KVM_NR_IRQCHIPS))131131+ goto out;132132+ break;133133+ case KVM_IRQ_ROUTING_MSI:134134+ e->set = kvm_set_msi;135135+ e->msi.address_lo = ue->u.msi.address_lo;136136+ e->msi.address_hi = ue->u.msi.address_hi;137137+ e->msi.data = ue->u.msi.data;138138+ e->msi.flags = ue->flags;139139+ e->msi.devid = ue->u.msi.devid;140140+ break;141141+ default:142142+ goto out;143143+ }144144+ r = 0;145145+out:146146+ return r;147147+}148148+149149+int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,150150+ struct kvm *kvm, int irq_source_id, int level,151151+ bool line_status)152152+{153153+ if (!level)154154+ return -EWOULDBLOCK;155155+156156+ switch (e->type) {157157+ case KVM_IRQ_ROUTING_MSI:158158+ return kvm_set_msi(e, kvm, irq_source_id, level, line_status);159159+160160+ case KVM_IRQ_ROUTING_IRQCHIP:161161+ return kvm_riscv_set_irq(e, kvm, irq_source_id,162162+ level, line_status);163163+ }164164+165165+ return -EWOULDBLOCK;166166+}167167+168168+bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)169169+{170170+ return irqchip_in_kernel(kvm);171171+}172172+58173int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)59174{60175 int r;6117662177 switch (ext) {178178+ case KVM_CAP_IRQCHIP:179179+ r = kvm_riscv_aia_available();180180+ break;63181 case KVM_CAP_IOEVENTFD:64182 case KVM_CAP_DEVICE_CTRL:65183 case KVM_CAP_USER_MEMORY: