From patchwork Thu Aug 5 22:29:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shashi Mallela X-Patchwork-Id: 12422261 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 65263C4320A for ; Thu, 5 Aug 2021 22:35:51 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BA8B361151 for ; Thu, 5 Aug 2021 22:35:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org BA8B361151 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=nongnu.org Received: from localhost ([::1]:48166 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mBlxt-0006G7-JQ for qemu-devel@archiver.kernel.org; Thu, 05 Aug 2021 18:35:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59054) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mBlsU-0007xN-2k for qemu-devel@nongnu.org; Thu, 05 Aug 2021 18:30:14 -0400 Received: from mail-qv1-xf2d.google.com ([2607:f8b0:4864:20::f2d]:40774) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mBlsO-0005tx-KZ for qemu-devel@nongnu.org; Thu, 05 Aug 2021 18:30:13 -0400 Received: by mail-qv1-xf2d.google.com with SMTP id s11so3848915qvz.7 for ; Thu, 05 Aug 2021 15:30:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=oKUkb885UI7ejm28BLFd3Pm42YiCMY24h8VmMxAOF+M=; b=u//CZ07/B9WyKGaYr+JgkemP+uadr3HJN4iwXNZ2I6WLC8yxIFaiXx2FMSv2b/alAk 2mP5a23nk8zttQ0mkAWhidM0onbbfa+tlrUPUGuGXeanXQLatjHXyROjI+9HVkqmLMB+ MLcFDPzm5KM9CFrFZSK3WaG6YRW/zhiPk+SwSEF84dIEp3Arz6Y9AzVp41+a+rR82eZR fRXKq+pqvIBbIufFsrEBCIP8jy0FlGIAnyWi3aidWRVuQ33xxkSt8soEhw/o1Jl3OVkL Ddo7tRXFtXLf8gpoab93nd7fB2+zaHUQEAbz1q3hqDIAFqdVeIIgq6jj1pPE++43iiDL UtOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=oKUkb885UI7ejm28BLFd3Pm42YiCMY24h8VmMxAOF+M=; b=IPcTbQIxC6Gpu4sEApFtXdV7BE4dwe269ONoyRkM1+7oGza9JIsNKbyeCXEbwn4GdH IKaZLFQOs9gbTj2/TsvmT1JonqaR2NGCESI7hp31KOBCIarSKRrdezW0FnYrlvFZFKZf goxlswnCR6x1DZ6J6xQaA7G27sZbCeaOodgeoH2KPWKHcVlUEnQx4gl4UWJl3kPpa+TX n1mQSO3lrcGAs1Z5r/yYJiDjVckDpv/Rjn/uEn/R5PaR4csIoCbYPvJDl/H1OKE7O5Q8 Xt/YNzYH/owsBQKCL5nd91nOQVDb8jUryA3T+s9dKIRJuUHum6d448QQI1SxMT0qJQpP B0Ig== X-Gm-Message-State: AOAM5301OFzi5mrigtDtKU3zhaT0zgU3jUlGt0adOqOKY20C5R8HhVfm /dlzz7vw4ljJiNgIC7QeU+0+sA== X-Google-Smtp-Source: ABdhPJyKQ7VzVKWL4kd0aA2Ohsu99ypxqH+/o0K7XS/8ReZ1lLHmFsYXFQ8cRm48Wr5NUuEkbmJ2zQ== X-Received: by 2002:ad4:5ce3:: with SMTP id iv3mr7777991qvb.54.1628202607715; Thu, 05 Aug 2021 15:30:07 -0700 (PDT) Received: from localhost.localdomain (bras-base-stsvon1503w-grc-22-142-114-143-47.dsl.bell.ca. [142.114.143.47]) by smtp.googlemail.com with ESMTPSA id d28sm3655195qkj.25.2021.08.05.15.30.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Aug 2021 15:30:07 -0700 (PDT) From: Shashi Mallela To: peter.maydell@linaro.org, leif@nuviainc.com, rad@semihalf.com, mst@redhat.com, imammedo@redhat.com Subject: [PATCH v7 06/10] hw/intc: GICv3 redistributor ITS processing Date: Thu, 5 Aug 2021 18:29:58 -0400 Message-Id: <20210805223002.144855-7-shashi.mallela@linaro.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210805223002.144855-1-shashi.mallela@linaro.org> References: <20210805223002.144855-1-shashi.mallela@linaro.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::f2d; envelope-from=shashi.mallela@linaro.org; helo=mail-qv1-xf2d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: eric.auger@redhat.com, qemu-arm@nongnu.org, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Implemented lpi processing at redistributor to get lpi config info from lpi configuration table,determine priority,set pending state in lpi pending table and forward the lpi to cpuif.Added logic to invoke redistributor lpi processing with translated LPI which set/clear LPI from ITS device as part of ITS INT,CLEAR,DISCARD command and GITS_TRANSLATER processing. Signed-off-by: Shashi Mallela Tested-by: Neil Armstrong --- hw/intc/arm_gicv3.c | 14 +++ hw/intc/arm_gicv3_common.c | 1 + hw/intc/arm_gicv3_cpuif.c | 7 +- hw/intc/arm_gicv3_its.c | 23 +++++ hw/intc/arm_gicv3_redist.c | 141 +++++++++++++++++++++++++++++ hw/intc/gicv3_internal.h | 9 ++ include/hw/intc/arm_gicv3_common.h | 7 ++ 7 files changed, 200 insertions(+), 2 deletions(-) diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index d63f8af604..3f24707838 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -165,6 +165,16 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs) cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq); } + if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable && + (cs->hpplpi.prio != 0xff)) { + if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) { + cs->hppi.irq = cs->hpplpi.irq; + cs->hppi.prio = cs->hpplpi.prio; + cs->hppi.grp = cs->hpplpi.grp; + seenbetter = true; + } + } + /* If the best interrupt we just found would preempt whatever * was the previous best interrupt before this update, then * we know it's definitely the best one now. @@ -339,9 +349,13 @@ static void gicv3_set_irq(void *opaque, int irq, int level) static void arm_gicv3_post_load(GICv3State *s) { + int i; /* Recalculate our cached idea of the current highest priority * pending interrupt, but don't set IRQ or FIQ lines. */ + for (i = 0; i < s->num_cpu; i++) { + gicv3_redist_update_lpi(&s->cpu[i]); + } gicv3_full_update_noirqset(s); /* Repopulate the cache of GICv3CPUState pointers for target CPUs */ gicv3_cache_all_target_cpustates(s); diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 53dea2a775..223db16fec 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -435,6 +435,7 @@ static void arm_gicv3_common_reset(DeviceState *dev) memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr)); cs->hppi.prio = 0xff; + cs->hpplpi.prio = 0xff; /* State in the CPU interface must *not* be reset here, because it * is part of the CPU's reset domain, not the GIC device's. diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index a032d505f5..462a35f66e 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -899,10 +899,12 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq) cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1); cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0); gicv3_redist_update(cs); - } else { + } else if (irq < GICV3_LPI_INTID_START) { gicv3_gicd_active_set(cs->gic, irq); gicv3_gicd_pending_clear(cs->gic, irq); gicv3_update(cs->gic, irq, 1); + } else { + gicv3_redist_lpi_pending(cs, irq, 0); } } @@ -1318,7 +1320,8 @@ static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_icc_eoir_write(is_eoir0 ? 0 : 1, gicv3_redist_affid(cs), value); - if (irq >= cs->gic->num_irq) { + if ((irq >= cs->gic->num_irq) && + !(cs->gic->lpi_enable && (irq >= GICV3_LPI_INTID_START))) { /* This handles two cases: * 1. If software writes the ID of a spurious interrupt [ie 1020-1023] * to the GICC_EOIR, the GIC ignores that write. diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index 35308f1c32..efa43b0333 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -225,6 +225,7 @@ static MemTxResult process_its_cmd(GICv3ITSState *s, uint64_t value, bool ite_valid = false; uint64_t cte = 0; bool cte_valid = false; + uint64_t rdbase; if (cmd == NONE) { devid = offset; @@ -285,6 +286,18 @@ static MemTxResult process_its_cmd(GICv3ITSState *s, uint64_t value, * Current implementation only supports rdbase == procnum * Hence rdbase physical address is ignored */ + rdbase = (cte & GITS_CTE_RDBASE_PROCNUM_MASK) >> 1U; + + if (rdbase > s->gicv3->num_cpu) { + return res; + } + + if ((cmd == CLEAR) || (cmd == DISCARD)) { + gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 0); + } else { + gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 1); + } + if (cmd == DISCARD) { IteEntry ite = {}; /* remove mapping from interrupt translation table */ @@ -602,6 +615,7 @@ static void process_cmdq(GICv3ITSState *s) AddressSpace *as = &s->gicv3->dma_as; MemTxResult res = MEMTX_OK; uint8_t cmd; + int i; if (!(s->ctlr & ITS_CTLR_ENABLED)) { return; @@ -663,6 +677,15 @@ static void process_cmdq(GICv3ITSState *s) break; case GITS_CMD_INV: case GITS_CMD_INVALL: + /* + * Current implementation doesn't cache any ITS tables, + * but the calculated lpi priority information. We only + * need to trigger lpi priority re-calculation to be in + * sync with LPI config table or pending table changes. + */ + for (i = 0; i < s->gicv3->num_cpu; i++) { + gicv3_redist_update_lpi(&s->gicv3->cpu[i]); + } break; default: break; diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index 2108abfe9c..7072bfcbb1 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -254,6 +254,9 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, if (cs->gicr_typer & GICR_TYPER_PLPIS) { if (value & GICR_CTLR_ENABLE_LPIS) { cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS; + /* Check for any pending interr in pending table */ + gicv3_redist_update_lpi(cs); + gicv3_redist_update(cs); } else { cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS; } @@ -532,6 +535,144 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, return r; } +static void gicv3_redist_check_lpi_priority(GICv3CPUState *cs, int irq) +{ + AddressSpace *as = &cs->gic->dma_as; + uint64_t lpict_baddr; + uint8_t lpite; + uint8_t prio; + + lpict_baddr = cs->gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK; + + address_space_read(as, lpict_baddr + ((irq - GICV3_LPI_INTID_START) * + sizeof(lpite)), MEMTXATTRS_UNSPECIFIED, &lpite, + sizeof(lpite)); + + if (!(lpite & LPI_CTE_ENABLED)) { + return; + } + + if (cs->gic->gicd_ctlr & GICD_CTLR_DS) { + prio = lpite & LPI_PRIORITY_MASK; + } else { + prio = ((lpite & LPI_PRIORITY_MASK) >> 1) | 0x80; + } + + if ((prio < cs->hpplpi.prio) || + ((prio == cs->hpplpi.prio) && (irq <= cs->hpplpi.irq))) { + cs->hpplpi.irq = irq; + cs->hpplpi.prio = prio; + /* LPIs are always non-secure Grp1 interrupts */ + cs->hpplpi.grp = GICV3_G1NS; + } +} + +void gicv3_redist_update_lpi(GICv3CPUState *cs) +{ + /* + * This function scans the LPI pending table and for each pending + * LPI, reads the corresponding entry from LPI configuration table + * to extract the priority info and determine if the current LPI + * priority is lower than the last computed high priority lpi interrupt. + * If yes, replace current LPI as the new high priority lpi interrupt. + */ + AddressSpace *as = &cs->gic->dma_as; + uint64_t lpipt_baddr; + uint32_t pendt_size = 0; + uint8_t pend; + int i, bit; + uint64_t idbits; + + idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS), + GICD_TYPER_IDBITS); + + if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser || + !cs->gicr_pendbaser) { + return; + } + + cs->hpplpi.prio = 0xff; + + lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK; + + /* Determine the highest priority pending interrupt among LPIs */ + pendt_size = (1ULL << (idbits + 1)); + + for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) { + address_space_read(as, lpipt_baddr + i, MEMTXATTRS_UNSPECIFIED, &pend, + sizeof(pend)); + + while (pend) { + bit = ctz32(pend); + gicv3_redist_check_lpi_priority(cs, i * 8 + bit); + pend &= ~(1 << bit); + } + } +} + +void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level) +{ + /* + * This function updates the pending bit in lpi pending table for + * the irq being activated or deactivated. + */ + AddressSpace *as = &cs->gic->dma_as; + uint64_t lpipt_baddr; + bool ispend = false; + uint8_t pend; + + /* + * get the bit value corresponding to this irq in the + * lpi pending table + */ + lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK; + + address_space_read(as, lpipt_baddr + ((irq / 8) * sizeof(pend)), + MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend)); + + ispend = extract32(pend, irq % 8, 1); + + /* no change in the value of pending bit, return */ + if (ispend == level) { + return; + } + pend = deposit32(pend, irq % 8, 1, level ? 1 : 0); + + address_space_write(as, lpipt_baddr + ((irq / 8) * sizeof(pend)), + MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend)); + + /* + * check if this LPI is better than the current hpplpi, if yes + * just set hpplpi.prio and .irq without doing a full rescan + */ + if (level) { + gicv3_redist_check_lpi_priority(cs, irq); + } else { + if (irq == cs->hpplpi.irq) { + gicv3_redist_update_lpi(cs); + } + } +} + +void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level) +{ + uint64_t idbits; + + idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS), + GICD_TYPER_IDBITS); + + if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser || + !cs->gicr_pendbaser || (irq > (1ULL << (idbits + 1)) - 1) || + irq < GICV3_LPI_INTID_START) { + return; + } + + /* set/clear the pending bit for this irq */ + gicv3_redist_lpi_pending(cs, irq, level); + + gicv3_redist_update(cs); +} + void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level) { /* Update redistributor state for a change in an external PPI input line */ diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h index 530d1c1789..a0369dace7 100644 --- a/hw/intc/gicv3_internal.h +++ b/hw/intc/gicv3_internal.h @@ -140,6 +140,8 @@ FIELD(GICR_PENDBASER, PHYADDR, 16, 36) FIELD(GICR_PENDBASER, OUTERCACHE, 56, 3) FIELD(GICR_PENDBASER, PTZ, 62, 1) +#define GICR_PROPBASER_IDBITS_THRESHOLD 0xd + #define ICC_CTLR_EL1_CBPR (1U << 0) #define ICC_CTLR_EL1_EOIMODE (1U << 1) #define ICC_CTLR_EL1_PMHE (1U << 6) @@ -305,6 +307,9 @@ FIELD(GITS_TYPER, CIL, 36, 1) #define L1TABLE_ENTRY_SIZE 8 +#define LPI_CTE_ENABLED TABLE_ENTRY_VALID_MASK +#define LPI_PRIORITY_MASK 0xfc + #define GITS_CMDQ_ENTRY_SIZE 32 #define NUM_BYTES_IN_DW 8 @@ -397,6 +402,7 @@ FIELD(MAPC, RDBASE, 16, 32) * Valid = 1 bit,RDBase = 36 bits(considering max RDBASE) */ #define GITS_CTE_SIZE (0x8ULL) +#define GITS_CTE_RDBASE_PROCNUM_MASK MAKE_64BIT_MASK(1, RDBASE_PROCNUM_LENGTH) /* Special interrupt IDs */ #define INTID_SECURE 1020 @@ -455,6 +461,9 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, unsigned size, MemTxAttrs attrs); void gicv3_dist_set_irq(GICv3State *s, int irq, int level); void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); +void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level); +void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level); +void gicv3_redist_update_lpi(GICv3CPUState *cs); void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); void gicv3_init_cpuif(GICv3State *s); diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h index c1348cc60a..aa4f0d6770 100644 --- a/include/hw/intc/arm_gicv3_common.h +++ b/include/hw/intc/arm_gicv3_common.h @@ -204,6 +204,13 @@ struct GICv3CPUState { * real state above; it doesn't need to be migrated. */ PendingIrq hppi; + + /* + * Cached information recalculated from LPI tables + * in guest memory + */ + PendingIrq hpplpi; + /* This is temporary working state, to avoid a malloc in gicv3_update() */ bool seenbetter; };