{"id":1585772,"url":"http://patchwork.ozlabs.org/api/patches/1585772/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20220128153009.2467560-31-peter.maydell@linaro.org/","project":{"id":14,"url":"http://patchwork.ozlabs.org/api/projects/14/?format=json","name":"QEMU Development","link_name":"qemu-devel","list_id":"qemu-devel.nongnu.org","list_email":"qemu-devel@nongnu.org","web_url":"","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20220128153009.2467560-31-peter.maydell@linaro.org>","list_archive_url":null,"date":"2022-01-28T15:30:07","name":"[PULL,30/32] hw/intc/arm_gicv3_its: Implement MOVI","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"827f1f6679d12e28cc9ba635e696d95773ad3617","submitter":{"id":5111,"url":"http://patchwork.ozlabs.org/api/people/5111/?format=json","name":"Peter Maydell","email":"peter.maydell@linaro.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20220128153009.2467560-31-peter.maydell@linaro.org/mbox/","series":[{"id":283405,"url":"http://patchwork.ozlabs.org/api/series/283405/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/list/?series=283405","date":"2022-01-28T15:29:53","name":"[PULL,01/32] Update copyright dates to 2022","version":1,"mbox":"http://patchwork.ozlabs.org/series/283405/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/1585772/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/1585772/checks/","tags":{},"related":[],"headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["bilbo.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=utdGr22w;\n\tdkim-atps=neutral","ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=<UNKNOWN>)"],"Received":["from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby bilbo.ozlabs.org (Postfix) with ESMTPS id 4Jlj7z697Pz9sPC\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 29 Jan 2022 03:09:18 +1100 (AEDT)","from localhost ([::1]:51356 helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1nDToI-0002C1-Qp\n\tfor incoming@patchwork.ozlabs.org; Fri, 28 Jan 2022 11:09:15 -0500","from eggs.gnu.org ([209.51.188.92]:57986)\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <peter.maydell@linaro.org>)\n id 1nDTDL-0002Eo-J7\n for qemu-devel@nongnu.org; Fri, 28 Jan 2022 10:31:03 -0500","from [2a00:1450:4864:20::32f] (port=44992\n helo=mail-wm1-x32f.google.com)\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <peter.maydell@linaro.org>)\n id 1nDTDJ-0006RD-50\n for qemu-devel@nongnu.org; Fri, 28 Jan 2022 10:31:03 -0500","by mail-wm1-x32f.google.com with SMTP id\n l35-20020a05600c1d2300b0034d477271c1so4288050wms.3\n for <qemu-devel@nongnu.org>; Fri, 28 Jan 2022 07:30:42 -0800 (PST)","from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2])\n by smtp.gmail.com with ESMTPSA id j3sm4749485wrb.57.2022.01.28.07.30.40\n for <qemu-devel@nongnu.org>\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 28 Jan 2022 07:30:41 -0800 (PST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google;\n h=from:to:subject:date:message-id:in-reply-to:references:mime-version\n :content-transfer-encoding;\n bh=o98uoL9Xfap+v4Tl1MPsf7fANnXlxiPhbqLzhPhwRCg=;\n b=utdGr22wTbp2fgcfiT5n8sY/Lr9AquSZb0A1KAfyHrQbIA3X6rLcQmRZ/w66F5+rHr\n i4dwHc2R9nDlTB3cjUaGJVREzEol7gBOVh6IZAOKpZoZTyuJmE2oX2KrnuYlQozHFu4i\n txpJs8XlE1mXniRxiqgeO3n2jUvp5PnvDnrUHQ7qX696iQmW7L0euBOcTiciZjH2kIJG\n Udw8tjSQ5gVxzNVr15EE6FGCedGmdiGC7Ll9du9r5+ZRwSHhu6m9VgH2MxRK2rqS7eKf\n x1atrpPsqeTEsenu5X4Fjsr5m9K7T7qTTk+NgbyNT+AkIpnEikff8zX7IV4qgXhse17T\n ZRPQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20210112;\n h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to\n :references:mime-version:content-transfer-encoding;\n bh=o98uoL9Xfap+v4Tl1MPsf7fANnXlxiPhbqLzhPhwRCg=;\n b=FiaUhIKGB/LSHRcRCxSBy9l9ykuuI/YHH9Upj+LR9AvcHN0ELpZj+rrz3uWVG/mBzw\n VKoovumbZl9b5uPIp6KrKV1Dp3XoZB1XxGnnCXX52AoIcRDbK1KAnz97+Qb6Pi98lSjd\n qETFODvmF8h+iwB5mhZyD8gM13hmrYG/kiLwl4QfA6/QxS0ERhjw75ZGAYFocPr2hjID\n MTm4Y3FJBB/PvOU/Czq7ywwKKdjnSymEMOk2RfeteY/ntX9kh5FCNNHc4DtGiODM1Ddj\n IK9XzBZfkErjE94Lhjd7BYVXtnF9a7FBUUxgiIGDu0NFdczpeHYpK9mbNTpa6zxXoZi3\n ARQA==","X-Gm-Message-State":"AOAM531oEMw17HhSkpKwlkDEr1hAyLznT2AHWuJV2k2ftH+RKrKQBaTh\n hwg6g196/1lyvW/YMIkganO3VykCb+x/UQ==","X-Google-Smtp-Source":"\n ABdhPJygCiacyNTTcZ2MsLjIJk7qY650eSZyZFHezsHdByiupi19RL799n9iG3ihNd29248QSO/CKQ==","X-Received":"by 2002:a05:600c:17d5:: with SMTP id\n y21mr8126882wmo.102.1643383841793;\n Fri, 28 Jan 2022 07:30:41 -0800 (PST)","From":"Peter Maydell <peter.maydell@linaro.org>","To":"qemu-devel@nongnu.org","Subject":"[PULL 30/32] hw/intc/arm_gicv3_its: Implement MOVI","Date":"Fri, 28 Jan 2022 15:30:07 +0000","Message-Id":"<20220128153009.2467560-31-peter.maydell@linaro.org>","X-Mailer":"git-send-email 2.25.1","In-Reply-To":"<20220128153009.2467560-1-peter.maydell@linaro.org>","References":"<20220128153009.2467560-1-peter.maydell@linaro.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-Host-Lookup-Failed":"Reverse DNS lookup failed for 2a00:1450:4864:20::32f\n (failed)","Received-SPF":"pass client-ip=2a00:1450:4864:20::32f;\n envelope-from=peter.maydell@linaro.org; helo=mail-wm1-x32f.google.com","X-Spam_score_int":"-12","X-Spam_score":"-1.3","X-Spam_bar":"-","X-Spam_report":"(-1.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n PDS_HP_HELO_NORDNS=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793,\n SPF_HELO_NONE=0.001, SPF_PASS=-0.001,\n T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n <qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"},"content":"Implement the ITS MOVI command. This command specifies a (physical) LPI\nby DeviceID and EventID and provides a new ICID for it. The ITS must\nfind the interrupt translation table entry for the LPI, which will\ntell it the old ICID. It then moves the pending state of the LPI from\nthe old redistributor to the new one and updates the ICID field in\nthe translation table entry.\n\nThis is another GICv3 ITS command that we forgot to implement.  Linux\ndoes use this one, but only if the guest powers off one of its CPUs.\n\nSigned-off-by: Peter Maydell <peter.maydell@linaro.org>\nReviewed-by: Richard Henderson <richard.henderson@linaro.org>\nMessage-id: 20220122182444.724087-15-peter.maydell@linaro.org\n---\n hw/intc/gicv3_internal.h   |  16 ++++\n hw/intc/arm_gicv3_its.c    | 146 +++++++++++++++++++++++++++++++++++++\n hw/intc/arm_gicv3_redist.c |  53 ++++++++++++++\n 3 files changed, 215 insertions(+)","diff":"diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h\nindex da45975d92b..b1af26df9f4 100644\n--- a/hw/intc/gicv3_internal.h\n+++ b/hw/intc/gicv3_internal.h\n@@ -315,6 +315,7 @@ FIELD(GITS_TYPER, CIL, 36, 1)\n #define CMD_MASK                  0xff\n \n /* ITS Commands */\n+#define GITS_CMD_MOVI             0x01\n #define GITS_CMD_INT              0x03\n #define GITS_CMD_CLEAR            0x04\n #define GITS_CMD_SYNC             0x05\n@@ -360,6 +361,11 @@ FIELD(MAPC, RDBASE, 16, 32)\n FIELD(MOVALL_2, RDBASE1, 16, 36)\n FIELD(MOVALL_3, RDBASE2, 16, 36)\n \n+/* MOVI command fields */\n+FIELD(MOVI_0, DEVICEID, 32, 32)\n+FIELD(MOVI_1, EVENTID, 0, 32)\n+FIELD(MOVI_2, ICID, 0, 16)\n+\n /*\n  * 12 bytes Interrupt translation Table Entry size\n  * as per Table 5.3 in GICv3 spec\n@@ -502,6 +508,16 @@ void gicv3_redist_update_lpi(GICv3CPUState *cs);\n  * an incoming migration has loaded new state.\n  */\n void gicv3_redist_update_lpi_only(GICv3CPUState *cs);\n+/**\n+ * gicv3_redist_mov_lpi:\n+ * @src: source redistributor\n+ * @dest: destination redistributor\n+ * @irq: LPI to update\n+ *\n+ * Move the pending state of the specified LPI from @src to @dest,\n+ * as required by the ITS MOVI command.\n+ */\n+void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq);\n /**\n  * gicv3_redist_movall_lpis:\n  * @src: source redistributor\ndiff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c\nindex ebc0403b3c7..51d9be4ae6f 100644\n--- a/hw/intc/arm_gicv3_its.c\n+++ b/hw/intc/arm_gicv3_its.c\n@@ -634,6 +634,149 @@ static ItsCmdResult process_movall(GICv3ITSState *s, uint64_t value,\n     return CMD_CONTINUE;\n }\n \n+static ItsCmdResult process_movi(GICv3ITSState *s, uint64_t value,\n+                                 uint32_t offset)\n+{\n+    AddressSpace *as = &s->gicv3->dma_as;\n+    MemTxResult res = MEMTX_OK;\n+    uint32_t devid, eventid, intid;\n+    uint16_t old_icid, new_icid;\n+    uint64_t old_cte, new_cte;\n+    uint64_t old_rdbase, new_rdbase;\n+    uint64_t dte;\n+    bool dte_valid, ite_valid, cte_valid;\n+    uint64_t num_eventids;\n+    IteEntry ite = {};\n+\n+    devid = FIELD_EX64(value, MOVI_0, DEVICEID);\n+\n+    offset += NUM_BYTES_IN_DW;\n+    value = address_space_ldq_le(as, s->cq.base_addr + offset,\n+                                 MEMTXATTRS_UNSPECIFIED, &res);\n+    if (res != MEMTX_OK) {\n+        return CMD_STALL;\n+    }\n+    eventid = FIELD_EX64(value, MOVI_1, EVENTID);\n+\n+    offset += NUM_BYTES_IN_DW;\n+    value = address_space_ldq_le(as, s->cq.base_addr + offset,\n+                                 MEMTXATTRS_UNSPECIFIED, &res);\n+    if (res != MEMTX_OK) {\n+        return CMD_STALL;\n+    }\n+    new_icid = FIELD_EX64(value, MOVI_2, ICID);\n+\n+    if (devid >= s->dt.num_entries) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: invalid command attributes: devid %d>=%d\",\n+                      __func__, devid, s->dt.num_entries);\n+        return CMD_CONTINUE;\n+    }\n+    dte = get_dte(s, devid, &res);\n+    if (res != MEMTX_OK) {\n+        return CMD_STALL;\n+    }\n+\n+    dte_valid = FIELD_EX64(dte, DTE, VALID);\n+    if (!dte_valid) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: invalid command attributes: \"\n+                      \"invalid dte: %\"PRIx64\" for %d\\n\",\n+                      __func__, dte, devid);\n+        return CMD_CONTINUE;\n+    }\n+\n+    num_eventids = 1ULL << (FIELD_EX64(dte, DTE, SIZE) + 1);\n+    if (eventid >= num_eventids) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: invalid command attributes: eventid %d >= %\"\n+                      PRId64 \"\\n\",\n+                      __func__, eventid, num_eventids);\n+        return CMD_CONTINUE;\n+    }\n+\n+    ite_valid = get_ite(s, eventid, dte, &old_icid, &intid, &res);\n+    if (res != MEMTX_OK) {\n+        return CMD_STALL;\n+    }\n+\n+    if (!ite_valid) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: invalid command attributes: invalid ITE\\n\",\n+                      __func__);\n+        return CMD_CONTINUE;\n+    }\n+\n+    if (old_icid >= s->ct.num_entries) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: invalid ICID 0x%x in ITE (table corrupted?)\\n\",\n+                      __func__, old_icid);\n+        return CMD_CONTINUE;\n+    }\n+\n+    if (new_icid >= s->ct.num_entries) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: invalid command attributes: ICID 0x%x\\n\",\n+                      __func__, new_icid);\n+        return CMD_CONTINUE;\n+    }\n+\n+    cte_valid = get_cte(s, old_icid, &old_cte, &res);\n+    if (res != MEMTX_OK) {\n+        return CMD_STALL;\n+    }\n+    if (!cte_valid) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: invalid command attributes: \"\n+                      \"invalid cte: %\"PRIx64\"\\n\",\n+                      __func__, old_cte);\n+        return CMD_CONTINUE;\n+    }\n+\n+    cte_valid = get_cte(s, new_icid, &new_cte, &res);\n+    if (res != MEMTX_OK) {\n+        return CMD_STALL;\n+    }\n+    if (!cte_valid) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: invalid command attributes: \"\n+                      \"invalid cte: %\"PRIx64\"\\n\",\n+                      __func__, new_cte);\n+        return CMD_CONTINUE;\n+    }\n+\n+    old_rdbase = FIELD_EX64(old_cte, CTE, RDBASE);\n+    if (old_rdbase >= s->gicv3->num_cpu) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: CTE has invalid rdbase 0x%\"PRIx64\"\\n\",\n+                      __func__, old_rdbase);\n+        return CMD_CONTINUE;\n+    }\n+\n+    new_rdbase = FIELD_EX64(new_cte, CTE, RDBASE);\n+    if (new_rdbase >= s->gicv3->num_cpu) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: CTE has invalid rdbase 0x%\"PRIx64\"\\n\",\n+                      __func__, new_rdbase);\n+        return CMD_CONTINUE;\n+    }\n+\n+    if (old_rdbase != new_rdbase) {\n+        /* Move the LPI from the old redistributor to the new one */\n+        gicv3_redist_mov_lpi(&s->gicv3->cpu[old_rdbase],\n+                             &s->gicv3->cpu[new_rdbase],\n+                             intid);\n+    }\n+\n+    /* Update the ICID field in the interrupt translation table entry */\n+    ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, 1);\n+    ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);\n+    ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, intid);\n+    ite.itel = FIELD_DP64(ite.itel, ITE_L, DOORBELL, INTID_SPURIOUS);\n+    ite.iteh = FIELD_DP32(ite.iteh, ITE_H, ICID, new_icid);\n+    return update_ite(s, eventid, dte, ite) ? CMD_CONTINUE : CMD_STALL;\n+}\n+\n /*\n  * Current implementation blocks until all\n  * commands are processed\n@@ -731,6 +874,9 @@ static void process_cmdq(GICv3ITSState *s)\n                 gicv3_redist_update_lpi(&s->gicv3->cpu[i]);\n             }\n             break;\n+        case GITS_CMD_MOVI:\n+            result = process_movi(s, data, cq_offset);\n+            break;\n         case GITS_CMD_MOVALL:\n             result = process_movall(s, data, cq_offset);\n             break;\ndiff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c\nindex d1645ba22c6..412a04f59cf 100644\n--- a/hw/intc/arm_gicv3_redist.c\n+++ b/hw/intc/arm_gicv3_redist.c\n@@ -681,6 +681,59 @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)\n     gicv3_redist_lpi_pending(cs, irq, level);\n }\n \n+void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq)\n+{\n+    /*\n+     * Move the specified LPI's pending state from the source redistributor\n+     * to the destination.\n+     *\n+     * If LPIs are disabled on dest this is CONSTRAINED UNPREDICTABLE:\n+     * we choose to NOP. If LPIs are disabled on source there's nothing\n+     * to be transferred anyway.\n+     */\n+    AddressSpace *as = &src->gic->dma_as;\n+    uint64_t idbits;\n+    uint32_t pendt_size;\n+    uint64_t src_baddr;\n+    uint8_t src_pend;\n+\n+    if (!(src->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||\n+        !(dest->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {\n+        return;\n+    }\n+\n+    idbits = MIN(FIELD_EX64(src->gicr_propbaser, GICR_PROPBASER, IDBITS),\n+                 GICD_TYPER_IDBITS);\n+    idbits = MIN(FIELD_EX64(dest->gicr_propbaser, GICR_PROPBASER, IDBITS),\n+                 idbits);\n+\n+    pendt_size = 1ULL << (idbits + 1);\n+    if ((irq / 8) >= pendt_size) {\n+        return;\n+    }\n+\n+    src_baddr = src->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;\n+\n+    address_space_read(as, src_baddr + (irq / 8),\n+                       MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend));\n+    if (!extract32(src_pend, irq % 8, 1)) {\n+        /* Not pending on source, nothing to do */\n+        return;\n+    }\n+    src_pend &= ~(1 << (irq % 8));\n+    address_space_write(as, src_baddr + (irq / 8),\n+                        MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend));\n+    if (irq == src->hpplpi.irq) {\n+        /*\n+         * We just made this LPI not-pending so only need to update\n+         * if it was previously the highest priority pending LPI\n+         */\n+        gicv3_redist_update_lpi(src);\n+    }\n+    /* Mark it pending on the destination */\n+    gicv3_redist_lpi_pending(dest, irq, 1);\n+}\n+\n void gicv3_redist_movall_lpis(GICv3CPUState *src, GICv3CPUState *dest)\n {\n     /*\n","prefixes":["PULL","30/32"]}