From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123111748507.000195915135; Wed, 15 Jul 2026 06:45:11 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzuz-0005W0-Po; Wed, 15 Jul 2026 09:44:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzux-0005VF-Vf for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:44:56 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzuv-0007tj-D7 for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:44:55 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id fcf91f7f (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:50 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id f5583df9; Wed, 15 Jul 2026 15:44:48 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=oLa3hXp VybPaEEG+nSSWTh72dsSJUNMzDnoCcO6qWa/539z2z76xH1kJU5byUXh2bK8MoBI8WoB3E 2wJfwMhwaLmnyRwxMspw0c+7XdfwtfARp+QrTuuDXWnc5UNLlG28H1ZuNwsWZC/z2luzBG BHH3ZrHgt/omwMXfO4VRcam9FqHZhr5wEqBNU4JnVBTRCTO1K71gjrpNWloDa09WCPxmnb IaRyQV0FG8rRMcgsJSGcuBvpc6Cxa/qtcvsT5mE3H30+EiZ2ZZZ64hgJfN+8kc9imo49t7 d7UMjaNWJshpc45ooaG8Y572bLvMe1wRdWalzrfOPX0pogz921VPOCg== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=E MUHPNfas3t/n8i/gxlXqlWs5T+o6W3ezbRVV0wl284=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=a0oyOe4q0txVjoOyETyIaFuuV3Y89Qzr2HJ9ScHIu1hHXvP+QIcgRuGyA/vtYI/jxDdO /0uK3xhg8cq6O2k4v+VXhQCKEY7xHvi1GPiBo7jnV7WvoAmKcmH6OdXcy+P7g6tEXTx4hw h/rfaX3gMGtLgH1kYqqGXI5St1BrNXpg8fosb6DV+N1cpfvzVEG2Q/oBCRMo3qs6/+eVTJ KCaJkst6iuVY7ISEBlqzMOvwNDv0dfVUsBptp2owWRlUelcb8KnrpbGW1xug7jj1zGKVbU VxIPdValnaYT0sOwxwXMb8CUigI3LbJ1eY1DEAOZoDgUS9kl1aXHO51VFsgsbDhw== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=MaOJc516; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=JvZnIhQ6; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=EMUHPNfa s3t/n8i/gxlXqlWs5T+o6W3ezbRVV0wl284=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=MaOJc516PgEhiWvwv8yRsXhd6PAhir/Yb/C srAmkeykb9jz8t8nLdLUMoJgfIOMfgDNp3td3mYzmmdGFrwzcON/LjucJKVeJiTvIrVJ8g 0o5J1A+oiEeh9Bj5JlV2AfeViUnaFtid4W6llbUXZ0PHe2LXK4fKI2KYqtllvR1AL6rmTK HSFEF1Up+Whac2nKTq3GY524JxBHdt8NfxmY4zJbcdDwdbTpu0kgoV7pNgqYqMkq+uvKT0 X/a7q9QeE/M6AD+b8hQRO/2t5nh3wfUV/rU6rhrribzZn2gAFDyczKOUc5PkCUqyvhh2Vl mbozbKJTVVzji73/46C/cuXhfoA== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=EMUHPNfas3t/n8i/gxlXqlWs5T+o6W3ezbRVV0wl284=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=JvZnIhQ66Tp4H0RBG2 dee0ZP9oKgwZ5AWIUvwJWLdolE+rZPAQbB2N+WV6eGl0Ch2qJ1Y90mzEqekkSG5ejdDw== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 01/25] target/mips: make CP0 interrupt state atomic Date: Wed, 15 Jul 2026 15:43:47 +0200 Message-ID: <20260715134447.56007-2-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123113257158500 Content-Type: text/plain; charset="utf-8" MTTCG lets interrupt inputs and timer callbacks update CP0_Cause, CP0_Status, and CP0_Count while a vCPU checks interrupt state. Use qatomic accessors for CP0 fields that participate in interrupt and timer decisions, and kick remote CPUs explicitly after raising a hard interrupt; MIPS interrupt line updates no longer depend on taking the BQL. --- hw/mips/mips_int.c | 17 +++++++------ target/mips/internal.h | 13 ++++++---- target/mips/system/cp0.c | 27 +++++++++++++-------- target/mips/system/cp0_timer.c | 32 ++++++++++++++----------- target/mips/tcg/system/special_helper.c | 17 +++++++------ target/mips/tcg/system/tlb_helper.c | 21 +++++++++------- 6 files changed, 75 insertions(+), 52 deletions(-) diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index 26e7dd6d5f..537394c8fd 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -21,30 +21,33 @@ */ =20 #include "qemu/osdep.h" -#include "qemu/main-loop.h" #include "hw/core/irq.h" #include "target/mips/cpu.h" +#include "target/mips/internal.h" =20 static void cpu_mips_irq_request(void *opaque, int irq, int level) { MIPSCPU *cpu =3D opaque; CPUMIPSState *env =3D &cpu->env; CPUState *cs =3D CPU(cpu); + int32_t irq_bit; =20 if (irq < 0 || irq > 7) { return; } =20 - BQL_LOCK_GUARD(); - + irq_bit =3D 1 << (irq + CP0Ca_IP); if (level) { - env->CP0_Cause |=3D 1 << (irq + CP0Ca_IP); + qatomic_or(&env->CP0_Cause, irq_bit); } else { - env->CP0_Cause &=3D ~(1 << (irq + CP0Ca_IP)); + qatomic_and(&env->CP0_Cause, ~irq_bit); } =20 - if (env->CP0_Cause & CP0Ca_IP_mask) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); + if (qatomic_read(&env->CP0_Cause) & CP0Ca_IP_mask) { + cpu_set_interrupt(cs, CPU_INTERRUPT_HARD); + if (!qemu_cpu_is_self(cs)) { + qemu_cpu_kick(cs); + } } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } diff --git a/target/mips/internal.h b/target/mips/internal.h index c5c286872e..cd06d84140 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -8,6 +8,7 @@ #ifndef MIPS_INTERNAL_H #define MIPS_INTERNAL_H =20 +#include "qemu/atomic.h" #include "exec/memattrs.h" #ifdef CONFIG_TCG #include "tcg/tcg-internal.h" @@ -167,9 +168,11 @@ extern const VMStateDescription vmstate_mips_cpu; =20 static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env) { - return (env->CP0_Status & (1 << CP0St_IE)) && - !(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && + int32_t status =3D qatomic_read(&env->CP0_Status); + + return (status & (1 << CP0St_IE)) && + !(status & (1 << CP0St_EXL)) && + !(status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM) && /* * Note that the TCStatus IXMT field is initialized to zero, @@ -186,8 +189,8 @@ static inline bool cpu_mips_hw_interrupts_pending(CPUMI= PSState *env) int32_t status; bool r; =20 - pending =3D env->CP0_Cause & CP0Ca_IP_mask; - status =3D env->CP0_Status & CP0Ca_IP_mask; + pending =3D qatomic_read(&env->CP0_Cause) & CP0Ca_IP_mask; + status =3D qatomic_read(&env->CP0_Status) & CP0Ca_IP_mask; =20 if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { /* diff --git a/target/mips/system/cp0.c b/target/mips/system/cp0.c index ff7d3db00c..6f222ad586 100644 --- a/target/mips/system/cp0.c +++ b/target/mips/system/cp0.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "internal.h" #include "exec/cputlb.h" +#include "qemu/atomic.h" =20 /* Called for updates to CP0_Status. */ void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) @@ -61,7 +62,8 @@ void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu,= int tc) void cpu_mips_store_status(CPUMIPSState *env, target_ulong val) { uint32_t mask =3D env->CP0_Status_rw_bitmask; - target_ulong old =3D env->CP0_Status; + target_ulong old; + target_ulong status; =20 if (env->insn_flags & ISA_MIPS_R6) { bool has_supervisor =3D extract32(mask, CP0St_KSU, 2) =3D=3D 0x3; @@ -77,9 +79,11 @@ void cpu_mips_store_status(CPUMIPSState *env, target_ulo= ng val) mask &=3D ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val); } =20 - env->CP0_Status =3D (old & ~mask) | (val & mask); + old =3D qatomic_read(&env->CP0_Status); + status =3D (old & ~mask) | (val & mask); + qatomic_set(&env->CP0_Status, status); #if defined(TARGET_MIPS64) - if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) { + if ((status ^ old) & (old & (7 << CP0St_UX))) { /* Access to at least one of the 64-bit segments has been disabled= */ tlb_flush(env_cpu(env)); } @@ -93,8 +97,9 @@ void cpu_mips_store_status(CPUMIPSState *env, target_ulon= g val) =20 void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) { - uint32_t mask =3D 0x00C00300; - uint32_t old =3D env->CP0_Cause; + int32_t mask =3D 0x00C00300; + int32_t old; + int32_t cause; int i; =20 if (env->insn_flags & ISA_MIPS_R2) { @@ -104,10 +109,12 @@ void cpu_mips_store_cause(CPUMIPSState *env, target_u= long val) mask &=3D ~((1 << CP0Ca_WP) & val); } =20 - env->CP0_Cause =3D (env->CP0_Cause & ~mask) | (val & mask); + old =3D qatomic_fetch_and(&env->CP0_Cause, ~mask); + qatomic_or(&env->CP0_Cause, (int32_t)(val & mask)); + cause =3D qatomic_read(&env->CP0_Cause); =20 - if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { - if (env->CP0_Cause & (1 << CP0Ca_DC)) { + if ((old ^ cause) & (1 << CP0Ca_DC)) { + if (cause & (1 << CP0Ca_DC)) { cpu_mips_stop_count(env); } else { cpu_mips_start_count(env); @@ -116,8 +123,8 @@ void cpu_mips_store_cause(CPUMIPSState *env, target_ulo= ng val) =20 /* Set/reset software interrupts */ for (i =3D 0 ; i < 2 ; i++) { - if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { - cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i= ))); + if ((old ^ cause) & (1 << (CP0Ca_IP + i))) { + cpu_mips_soft_irq(env, i, cause & (1 << (CP0Ca_IP + i))); } } } diff --git a/target/mips/system/cp0_timer.c b/target/mips/system/cp0_timer.c index 6aed5d3af2..622fee357d 100644 --- a/target/mips/system/cp0_timer.c +++ b/target/mips/system/cp0_timer.c @@ -23,6 +23,7 @@ #include "qemu/osdep.h" #include "hw/core/irq.h" #include "qemu/timer.h" +#include "qemu/atomic.h" #include "internal.h" =20 /* MIPS R4K timer */ @@ -31,7 +32,7 @@ static uint32_t cpu_mips_get_count_val(CPUMIPSState *env) MIPSCPU *cpu =3D env_archcpu(env); int64_t now_ns; now_ns =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - return env->CP0_Count + + return qatomic_read(&env->CP0_Count) + (uint32_t)clock_ns_to_ticks(cpu->count_clock, now_ns); } =20 @@ -56,15 +57,15 @@ static void cpu_mips_timer_expire(CPUMIPSState *env) { cpu_mips_timer_update(env); if (env->insn_flags & ISA_MIPS_R2) { - env->CP0_Cause |=3D 1 << CP0Ca_TI; + qatomic_or(&env->CP0_Cause, 1 << CP0Ca_TI); } qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); } =20 uint32_t cpu_mips_get_count(CPUMIPSState *env) { - if (env->CP0_Cause & (1 << CP0Ca_DC)) { - return env->CP0_Count; + if (qatomic_read(&env->CP0_Cause) & (1 << CP0Ca_DC)) { + return qatomic_read(&env->CP0_Count); } else { uint64_t now_ns; =20 @@ -86,12 +87,13 @@ void cpu_mips_store_count(CPUMIPSState *env, uint32_t c= ount) * So env->timer may be NULL, so treat timer as disabled in that case. */ MIPSCPU *cpu =3D env_archcpu(env); - if (env->CP0_Cause & (1 << CP0Ca_DC) || !env->timer) { - env->CP0_Count =3D count; + if ((qatomic_read(&env->CP0_Cause) & (1 << CP0Ca_DC)) || !env->timer) { + qatomic_set(&env->CP0_Count, count); } else { /* Store new count register */ - env->CP0_Count =3D count - (uint32_t)clock_ns_to_ticks(cpu->count_= clock, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + qatomic_set(&env->CP0_Count, + count - (uint32_t)clock_ns_to_ticks(cpu->count_clock, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL))); /* Update timer timer */ cpu_mips_timer_update(env); } @@ -100,26 +102,28 @@ void cpu_mips_store_count(CPUMIPSState *env, uint32_t= count) void cpu_mips_store_compare(CPUMIPSState *env, uint32_t value) { env->CP0_Compare =3D value; - if (!(env->CP0_Cause & (1 << CP0Ca_DC))) { + if (!(qatomic_read(&env->CP0_Cause) & (1 << CP0Ca_DC))) { cpu_mips_timer_update(env); } if (env->insn_flags & ISA_MIPS_R2) { - env->CP0_Cause &=3D ~(1 << CP0Ca_TI); + qatomic_and(&env->CP0_Cause, ~(1 << CP0Ca_TI)); } qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); } =20 void cpu_mips_start_count(CPUMIPSState *env) { - cpu_mips_store_count(env, env->CP0_Count); + cpu_mips_store_count(env, qatomic_read(&env->CP0_Count)); } =20 void cpu_mips_stop_count(CPUMIPSState *env) { /* Store the current value */ MIPSCPU *cpu =3D env_archcpu(env); - env->CP0_Count +=3D (uint32_t)clock_ns_to_ticks(cpu->count_clock, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + + qatomic_add(&env->CP0_Count, + (uint32_t)clock_ns_to_ticks(cpu->count_clock, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL))); } =20 static void mips_timer_cb(void *opaque) @@ -128,7 +132,7 @@ static void mips_timer_cb(void *opaque) =20 env =3D opaque; =20 - if (env->CP0_Cause & (1 << CP0Ca_DC)) { + if (qatomic_read(&env->CP0_Cause) & (1 << CP0Ca_DC)) { return; } =20 diff --git a/target/mips/tcg/system/special_helper.c b/target/mips/tcg/syst= em/special_helper.c index b54cbe88a3..04ae0bc6c3 100644 --- a/target/mips/tcg/system/special_helper.c +++ b/target/mips/tcg/system/special_helper.c @@ -24,21 +24,22 @@ #include "exec/helper-proto.h" #include "exec/translation-block.h" #include "internal.h" +#include "qemu/atomic.h" =20 /* Specials */ target_ulong helper_di(CPUMIPSState *env) { - target_ulong t0 =3D env->CP0_Status; + target_ulong t0 =3D qatomic_read(&env->CP0_Status); =20 - env->CP0_Status =3D t0 & ~(1 << CP0St_IE); + qatomic_set(&env->CP0_Status, t0 & ~(1 << CP0St_IE)); return t0; } =20 target_ulong helper_ei(CPUMIPSState *env) { - target_ulong t0 =3D env->CP0_Status; + target_ulong t0 =3D qatomic_read(&env->CP0_Status); =20 - env->CP0_Status =3D t0 | (1 << CP0St_IE); + qatomic_set(&env->CP0_Status, t0 | (1 << CP0St_IE)); return t0; } =20 @@ -103,13 +104,15 @@ bool mips_io_recompile_replay_branch(CPUState *cs, co= nst TranslationBlock *tb) =20 static inline void exception_return(CPUMIPSState *env) { + target_ulong status =3D qatomic_read(&env->CP0_Status); + debug_pre_eret(env); - if (env->CP0_Status & (1 << CP0St_ERL)) { + if (status & (1 << CP0St_ERL)) { mips_env_set_pc(env, env->CP0_ErrorEPC); - env->CP0_Status &=3D ~(1 << CP0St_ERL); + qatomic_set(&env->CP0_Status, status & ~(1 << CP0St_ERL)); } else { mips_env_set_pc(env, env->CP0_EPC); - env->CP0_Status &=3D ~(1 << CP0St_EXL); + qatomic_set(&env->CP0_Status, status & ~(1 << CP0St_EXL)); } compute_hflags(env); debug_post_eret(env); diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/t= lb_helper.c index 4398c6f80b..9772df5d6c 100644 --- a/target/mips/tcg/system/tlb_helper.c +++ b/target/mips/tcg/system/tlb_helper.c @@ -1106,7 +1106,7 @@ void mips_cpu_do_interrupt(CPUState *cs) env->hflags &=3D ~(MIPS_HFLAG_KSU); /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) { - env->CP0_Cause &=3D ~(1U << CP0Ca_BD); + qatomic_and(&env->CP0_Cause, (int32_t)~(1U << CP0Ca_BD)); } env->active_tc.PC =3D env->exception_base + 0x480; set_hflags_for_handler(env); @@ -1134,7 +1134,7 @@ void mips_cpu_do_interrupt(CPUState *cs) env->hflags |=3D MIPS_HFLAG_CP0; env->hflags &=3D ~(MIPS_HFLAG_KSU); if (!(env->CP0_Status & (1 << CP0St_EXL))) { - env->CP0_Cause &=3D ~(1U << CP0Ca_BD); + qatomic_and(&env->CP0_Cause, (int32_t)~(1U << CP0Ca_BD)); } env->active_tc.PC =3D env->exception_base; set_hflags_for_handler(env); @@ -1148,7 +1148,9 @@ void mips_cpu_do_interrupt(CPUState *cs) offset =3D 0x200; } else { uint32_t vector =3D 0; - uint32_t pending =3D (env->CP0_Cause & CP0Ca_IP_mask) >> C= P0Ca_IP; + uint32_t pending =3D + (qatomic_read(&env->CP0_Cause) & CP0Ca_IP_mask) >> + CP0Ca_IP; =20 if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { /* @@ -1246,8 +1248,9 @@ void mips_cpu_do_interrupt(CPUState *cs) case EXCP_CpU: cause =3D 11; update_badinstr =3D 1; - env->CP0_Cause =3D (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) | - (env->error_code << CP0Ca_CE); + qatomic_and(&env->CP0_Cause, (int32_t)~(0x3U << CP0Ca_CE)); + qatomic_or(&env->CP0_Cause, + (int32_t)(env->error_code << CP0Ca_CE)); goto set_EPC; case EXCP_OVERFLOW: cause =3D 12; @@ -1305,9 +1308,9 @@ void mips_cpu_do_interrupt(CPUState *cs) set_badinstr_registers(env); } if (env->hflags & MIPS_HFLAG_BMASK) { - env->CP0_Cause |=3D (1U << CP0Ca_BD); + qatomic_or(&env->CP0_Cause, (int32_t)(1U << CP0Ca_BD)); } else { - env->CP0_Cause &=3D ~(1U << CP0Ca_BD); + qatomic_and(&env->CP0_Cause, (int32_t)~(1U << CP0Ca_BD)); } env->CP0_Status |=3D (1 << CP0St_EXL); if (env->insn_flags & ISA_MIPS3) { @@ -1333,8 +1336,8 @@ void mips_cpu_do_interrupt(CPUState *cs) =20 env->active_tc.PC +=3D offset; set_hflags_for_handler(env); - env->CP0_Cause =3D (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | - (cause << CP0Ca_EC); + qatomic_and(&env->CP0_Cause, (int32_t)~(0x1f << CP0Ca_EC)); + qatomic_or(&env->CP0_Cause, cause << CP0Ca_EC); break; default: abort(); --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123177589975.0536572300292; Wed, 15 Jul 2026 06:46:17 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv3-0005Xt-EY; Wed, 15 Jul 2026 09:45:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv0-0005WD-0j for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:44:58 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzuy-0007tj-Dx for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:44:57 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id a9292252 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:50 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id ab459214; Wed, 15 Jul 2026 15:44:48 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=Ti53ne6 d2jvcPHcXNQ0kzqezW2C38SNRcjJZLFXLYaa06qH6V2Zo2/BtWphk5TsuZjCsz3xfgKCci sCe6XjaJOg3kXYV0wwfv6YDzhNFx+2B+LS0x8Hx7eeFqHi3/BFL0jMOR7dD/YpXPXk0YE6 igBXdc77NGJF6w+rXR6+yQJv79D5tIzvX7Vlv8AoHFL+ziEP5uoY7NRLKpPsNy18e/E59T ZEgh3ODcUS2ZPPhwSS9K7vg6tZW+9e2ffm/DEYQZAc5WTkYDQD0mbXr+TCHfeZLVnxsujh 8pW4UKzt7jdN6jo09u/GLV938Bh+ta7PDb3dRz/Sb31J+WJfnV3UVFA== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=p QgaFwBfH2WRlTWcwX1VVdSzuQK3HKOK1hbZcrUPRaU=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=m3CqlcIlp3BYu6lyYLvrnlTrNilY9i0rArgU5w0S0YpERhnTYUbNn9lQTjXgOb+tq+cC tgXnJ/K63Q/UqhTqddbn+SlhzxtJtSmYKWpRWdmIWqTntdbKOWsN1ZJLnchb88K2933MWD XsnmtBvALuO3uJatgRMMRJDDZw3DRGM5JFesjgSS2iTjsNgrFCUykMwuNcUVnM0wcWFhvq bEBbowvkdF5tMYOgvJtsQzKDq1dT1E7j1ILRH+xAvsOLaEPznAtg8SXenV+rLngeavyc3U HH7uopdBRL8qFhoCgF0x2WV1xMwm85BcrsnNhvDtiSB27DG6sPVVAekHnfhg5vFA== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=SHnMwXJG; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=DHWCnELH; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=pQgaFwBf H2WRlTWcwX1VVdSzuQK3HKOK1hbZcrUPRaU=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=SHnMwXJGCj6j6U2psJPrlRgtSH14CdjDOeZ eYc4IhkQR3BCJAi7J8NS9Gx0SSw92MT/6nWy/gxOS91rjFsFfNvbFDL64gQo+52XWd9YDP 1KeO8fzP6uWd7yZD3FaAlwa1aBhQcq5VI7mX+U44Rr3CoiJDzM+L7enmAJOgbkcTWZ/W16 A5miJhYsWVIRqnICyA6VKTlCgqGpoc9v4e46DXzyDz4uHFLfHmhgvfxek7CZpB0pJTyots MRFiBPXT7E0bbHTSudsmns1jS1zIzyKSz0ai9UL3pMSYMNR3jCb0WXMgtsK6k8cqLHppyI sx8Ee7jWJMa0hy/bmldvDvectgQ== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=pQgaFwBfH2WRlTWcwX1VVdSzuQK3HKOK1hbZcrUPRaU=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=DHWCnELHhPfGg380SK tnZl9oGw6Q7MtGA1lykDp2R28MEyJor+k774oPUssWCjsxfYBroO7HhC6SjxDX0ABiCw== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 02/25] target/mips: fix MIPS64 segment access checks Date: Wed, 15 Jul 2026 15:43:48 +0200 Message-ID: <20260715134447.56007-3-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123179740158500 Content-Type: text/plain; charset="utf-8" The xuseg and xsseg checks only tested UX and SX respectively; kernel and supervisor accesses must instead use the mode bit that applies to the current execution mode. Allow supervisor and kernel mode to use xuseg when SX or KX is set, and allow kernel mode to use xsseg when KX is set. --- target/mips/system/physaddr.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/target/mips/system/physaddr.c b/target/mips/system/physaddr.c index 746dbf8aa4..626d7ccc4c 100644 --- a/target/mips/system/physaddr.c +++ b/target/mips/system/physaddr.c @@ -143,7 +143,9 @@ int get_physical_address(CPUMIPSState *env, hwaddr *phy= sical, #if defined(TARGET_MIPS64) } else if (address < 0x4000000000000000ULL) { /* xuseg */ - if (UX && address <=3D (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { + if (((user_mode && UX) || (supervisor_mode && SX) || + (kernel_mode && KX)) && + address <=3D (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret =3D env->tlb->map_address(env, physical, prot, real_address, access_type); } else { @@ -151,8 +153,8 @@ int get_physical_address(CPUMIPSState *env, hwaddr *phy= sical, } } else if (address < 0x8000000000000000ULL) { /* xsseg */ - if ((supervisor_mode || kernel_mode) && - SX && address <=3D (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { + if (((supervisor_mode && SX) || (kernel_mode && KX)) && + address <=3D (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret =3D env->tlb->map_address(env, physical, prot, real_address, access_type); } else { --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123229056389.34877322961916; Wed, 15 Jul 2026 06:47:09 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv4-0005YN-1S; Wed, 15 Jul 2026 09:45:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv1-0005We-Dm for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:44:59 -0400 Received: from mx1.catap.net ([2a01:4f8:271:125e::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzuy-0007u3-Rp for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:44:58 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 5f4afba7 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:50 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 60a4bac6; Wed, 15 Jul 2026 15:44:48 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=Hi1eRls rq5IF20+n++CRehrROOA1/74g4q4GLsA73qaBHwz5c5ElWbyAPYbHoKua1roXKRvM+8IFG HhPt0bSJudUaZwSPPZSME+O8ILHgv0xMgEj9pil3wOvVVrTmtMzEfvHdX7Ioh7q8UxjyuV g+3/z30+haPw3HiFaEsbM78p+7LAA9UlcfpYHDMQGhh2GwvRKGS7wWZ8Y4bSy+mpg/WvyX bHPZfPHS2wicy9x8ddzgFYDYVOUW5gdEhgbF6LMNWJxX1/3jId2ZY9pSVthAef3o2d0J/h /Se7WQTTdnM5NG0CAG5x1bNQ1nqhmD9Z3ISPB3L6tqhMPFXS0PshSmA== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=6 mS6E9/j2Z3UyVv8/YQsOxEUThpdW2ccwS2/LnYdZag=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=KDDzjVmnncssdIYLCWV0Eez63FyqSWwblNb3GGDgZqqk9XgUacxBTGqLndd2bKYgIhkc rl9k/zD9iKIdNMPUjjT4FSTEKQOQU1MQ1TlchoJTa1yJU8gmEaTY3dvMw+sh3D3L+s98kq Y0MHSKIcnybKnUX0x9aeK5tZwpmhbhBlM8o8M0qy28alionMVZ9Hm4XeetdaKoESvndFZe mNHtyDfQLzYVxmzF4W81VDzSJnsqy3HpavvH9rO85O5L7iXAbW6gwmAbG/Kh0SR28Xwn55 cYjm2UMe8glOiiwKOxQkn5TaJDg7jQs4bk8rHUvHvLh+gxSUZHqMIfP8Zd5Tg7cA== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=Ue22u+iB; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=0WzbjoKy; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=6mS6E9/j 2Z3UyVv8/YQsOxEUThpdW2ccwS2/LnYdZag=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=Ue22u+iBhM/1dtrEml1t3nWp9zFPl7Ga3TQ Z8TXP9u6KGn+jyy4IPeoLEFUwU7QkBGmm2/26HbSnQkb2DFqw7ZitPxNZclsftEwBC2Zdq 0bTRhVBOiukSezub+pu0+a3S2V7FydUUX4s+2WD71JpBUjWI/8TtZ9J3CUxuEu7Wdgg6a6 jTH3gMZudCsBM3tZFOdFl294c052KmhimUYbzoGj5bVXny4SYjRZx6SCmVL03uqGGu5fNZ H5d13mt7wx7vxR7Q5JQyhPJmmsH+4CjVXsEgpb3u3jf+6hYqcjV34kF6sVEnuZeMr//yEB 5m529Bd7ES4LUuSnPzVp+kRNQAg== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=6mS6E9/j2Z3UyVv8/YQsOxEUThpdW2ccwS2/LnYdZag=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=0WzbjoKysEz25EL+Mc P1z9lU6HMPSe8ZQIvxQL0j2JaTxlPfnDG3TUVAUPYGcZRLe9ByRCq5M+kb6Q2kDMgWBA== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 03/25] target/mips: drop hidden TLB shadowing for tlbwr Date: Wed, 15 Jul 2026 15:43:49 +0200 Message-ID: <20260715134447.56007-4-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f8:271:125e::2; envelope-from=kirill@korins.ky; helo=mx1.catap.net 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_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123230834158500 Content-Type: text/plain; charset="utf-8" tlbwr replaces a random architectural TLB entry. Once that happens, the evicted entry must stop translating guest virtual addresses. The current helper keeps the evicted entry in QEMU-only extra TLB state. That makes the old mapping survive until some later operation discards the extra entries. A guest can observe this directly by writing through a TLB mapping, replacing that entry with tlbwr, and writing through the old virtual address again. Invalidate the replaced entry instead of shadowing it. This keeps the translated TLB state aligned with the architectural TLB contents. --- target/mips/tcg/system/tlb_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/t= lb_helper.c index 9772df5d6c..4c0a25e622 100644 --- a/target/mips/tcg/system/tlb_helper.c +++ b/target/mips/tcg/system/tlb_helper.c @@ -165,7 +165,7 @@ static void r4k_helper_tlbwr(CPUMIPSState *env) { int r =3D cpu_mips_get_random(env); =20 - r4k_invalidate_tlb(env, r, 1); + r4k_invalidate_tlb(env, r, 0); r4k_fill_tlb(env, r); } =20 --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123193722914.0198127339522; Wed, 15 Jul 2026 06:46:33 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv5-0005Yr-4j; Wed, 15 Jul 2026 09:45:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv2-0005XC-4B for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:00 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzuz-0007uM-RT for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:44:59 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 4337c747 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:50 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 71268d47; Wed, 15 Jul 2026 15:44:48 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=TZTajLj rGR3e6R7acXpAdo9xyMv1zgcxQGVdgqMtQz2KgM1XTxPsbLJ0dXsHDoxI4zwHVo0HS70WU GKB42dcOqu9h3rJjJTcmesmRg1dtjnptp1CAV8cBkv3K+RsMKOPtHMyXRetONgkxoLtSiV cdcmjDDEYAt1dlUfn9aVFz+fzxGaUJ+cil9SbMQYMM28u5nfzlkacapDx4iAHYkpMzKfeD BVakBch6M2PcDdqOUObTqlGhAzHivQvSSheHIS8E08MtncbUt3kWl4NijvF06UZo6XBEiS 7gajyFX/2+wcQWVrilTyA1cFdUAuC/R8iNn42d5Ao9a59cSZobi4Mgw== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=C 4NmE7Kk+MtzQaZNwDS9VtzXQS6aXULBpUidEkcaWyU=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=IDIlpEbzEN+zKWBQmuxEOkwr/lSibpmDJMLJpAgoW4ENaCeULIesADUxJbdI8w1otcbt rxH4z3QhR6U6+ig9EXduieHLxjNbPMf7GEZUusP1Cug14hNYWKwifqI+aQhPaIiweBjtI2 A6VMdG3/uhuPHr63ZAOYKzy8R9Owr5BH4JrHH/cI3xAZTmEPukzthsZg6awya1cbALkTxp tx5M6v2B1HrLVk/LS9mk9WWrPrzz81jD3Q+6GYk4R4E1xi6rHMWi6PmolbkmHZhnlN+Bn8 FhGMVxTmLNVzwHxfdQgzdG9ISvFhxKq/KKdWRYB7K14nAvvFwbc/8LCRcW5Fqvuw== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=C2tfaxC/; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=bQOEHQm0; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=C4NmE7Kk +MtzQaZNwDS9VtzXQS6aXULBpUidEkcaWyU=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=C2tfaxC/6TdhwKRLDioqQEFefS7SV60AduY a+jme/L6pnsNyyQ02KP9o4g3WH5Vt13WbJR0h5TyOc0HbA4uYjqb64aM9Jz6e0zVHMhrtV 115pD8FpJThPWS/MBucaid+RqnQSi0ZEUK02PPzQIR7laxEDd4Z/iRtqBaOCn6+XEMjR/3 3wOw5FyEzCSX09N5kFo5rz6lMBys9wMcL5L+KvgP8htmwoGg/DgXkp6/kxPPh80rUwj6vk IbD8O6BbVwMGUe7iq27tLpC82io0rp9cCEW5NYz2JxYpt4tklSkhFiF0kMxcKZcg6gbcWT wzYcMPSVPAKhWGjRQXeMBgZdGuQ== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=C4NmE7Kk+MtzQaZNwDS9VtzXQS6aXULBpUidEkcaWyU=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=bQOEHQm0UZs7CaFV4x psYk6I6fVvGW5nhwBjYkUyp7oHbx5lDcR/Z1uKbEwUDfOPtdhu9BHdp9ARlFPXqqKSDg== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 04/25] target/mips: add Octeon CP0 register state Date: Wed, 15 Jul 2026 15:43:50 +0200 Message-ID: <20260715134447.56007-5-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123195806158500 Content-Type: text/plain; charset="utf-8" Octeon firmware and kernels use implementation specific CP0 registers for the cycle counter and local memory control. Add CvmCount, CvmCtl, and CvmMemCtl accessors for Octeon CPUs; migrate the new CP0 state, and translate the enabled CVMSEG virtual window to per vCPU backing memory. --- target/mips/cpu.h | 5 +++ target/mips/system/machine.c | 13 +++++++ target/mips/system/physaddr.c | 22 +++++++++++ target/mips/tcg/op_helper.c | 2 +- target/mips/tcg/system/cp0_helper.c | 10 +++++ target/mips/tcg/system_helper.h.inc | 1 + target/mips/tcg/translate.c | 60 +++++++++++++++++++++++++++++ 7 files changed, 112 insertions(+), 1 deletion(-) diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 319147a948..c6da52e17f 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -341,6 +341,8 @@ typedef struct mips_def_t mips_def_t; #define CP0_REG09__COUNT 0 #define CP0_REG09__SAARI 6 #define CP0_REG09__SAAR 7 +#define CP0_REG09__CVMCOUNT 6 +#define CP0_REG09__CVMCTL 7 /* CP0 Register 10 */ #define CP0_REG10__ENTRYHI 0 #define CP0_REG10__GUESTCTL1 4 @@ -349,6 +351,7 @@ typedef struct mips_def_t mips_def_t; /* CP0 Register 11 */ #define CP0_REG11__COMPARE 0 #define CP0_REG11__GUESTCTL0EXT 4 +#define CP0_REG11__CVMMEMCTL 7 /* CP0 Register 12 */ #define CP0_REG12__STATUS 0 #define CP0_REG12__INTCTL 1 @@ -787,6 +790,7 @@ typedef struct CPUArchState { * CP0 Register 9 */ int32_t CP0_Count; + target_ulong CP0_CvmCtl; #define CP0SAARI_TARGET 0 /* 5..0 */ #define CP0SAAR_BASE 12 /* 43..12 */ #define CP0SAAR_SIZE 1 /* 5..1 */ @@ -801,6 +805,7 @@ typedef struct CPUArchState { * CP0 Register 11 */ int32_t CP0_Compare; + target_ulong CP0_CvmMemCtl; /* * CP0 Register 12 */ diff --git a/target/mips/system/machine.c b/target/mips/system/machine.c index bd1e4002cf..3661da0566 100644 --- a/target/mips/system/machine.c +++ b/target/mips/system/machine.c @@ -372,6 +372,18 @@ static const VMStateDescription mips_vmstate_octeon_cr= ypto =3D { } }; =20 +static const VMStateDescription mips_vmstate_octeon_cp0 =3D { + .name =3D "cpu/octeon_cp0", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D mips_octeon_needed, + .fields =3D (const VMStateField[]) { + VMSTATE_UINTTL(env.CP0_CvmCtl, MIPSCPU), + VMSTATE_UINTTL(env.CP0_CvmMemCtl, MIPSCPU), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_mips_cpu =3D { .name =3D "cpu", .version_id =3D 21, @@ -490,6 +502,7 @@ const VMStateDescription vmstate_mips_cpu =3D { &mips_vmstate_timer, &mips_vmstate_octeon_multiplier, &mips_vmstate_octeon_crypto, + &mips_vmstate_octeon_cp0, NULL } }; diff --git a/target/mips/system/physaddr.c b/target/mips/system/physaddr.c index 626d7ccc4c..a0538d8b6b 100644 --- a/target/mips/system/physaddr.c +++ b/target/mips/system/physaddr.c @@ -21,6 +21,14 @@ #include "exec/page-protection.h" #include "../internal.h" =20 +/* + * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; + * the guest sees the virtual CVMSEG window, not this physical address. + */ +#define OCTEON_CVMSEG_BASE 0x10000000000ULL +#define OCTEON_CVMSEG_SIZE 0x4000ULL +#define OCTEON_CVMSEG_MASK 0x3fffULL + static int is_seg_am_mapped(unsigned int am, bool eu, int mmu_idx) { /* @@ -128,6 +136,20 @@ int get_physical_address(CPUMIPSState *env, hwaddr *ph= ysical, int ret =3D TLBRET_MATCH; target_ulong address =3D real_address; =20 +#if defined(TARGET_MIPS64) + if ((env->insn_flags & INSN_OCTEON) && (env->CP0_CvmMemCtl & 0x100) && + address >=3D 0xffffffffffff8000ULL && + address <=3D 0xffffffffffffbfffULL) { + MIPSCPU *cpu =3D env_archcpu(env); + + *physical =3D OCTEON_CVMSEG_BASE + + CPU(cpu)->cpu_index * OCTEON_CVMSEG_SIZE + + (address & OCTEON_CVMSEG_MASK); + *prot =3D PAGE_READ | PAGE_WRITE; + return TLBRET_MATCH; + } +#endif + if (address <=3D USEG_LIMIT) { /* useg */ uint16_t segctl; diff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c index df1b5c3734..2bfe661ef2 100644 --- a/target/mips/tcg/op_helper.c +++ b/target/mips/tcg/op_helper.c @@ -268,7 +268,7 @@ target_ulong helper_rdhwr_cvmcount(CPUMIPSState *env) #ifdef CONFIG_USER_ONLY return cpu_get_host_ticks(); #else - return (uint32_t)cpu_mips_get_count(env); + return helper_mfc0_cvmcount(env); #endif } =20 diff --git a/target/mips/tcg/system/cp0_helper.c b/target/mips/tcg/system/c= p0_helper.c index ba6b487b75..1c23d2a525 100644 --- a/target/mips/tcg/system/cp0_helper.c +++ b/target/mips/tcg/system/cp0_helper.c @@ -23,6 +23,8 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/main-loop.h" +#include "qemu/timer.h" +#include "hw/core/clock.h" #include "cpu.h" #include "internal.h" #include "qemu/host-utils.h" @@ -374,6 +376,14 @@ target_ulong helper_mfc0_count(CPUMIPSState *env) return (int32_t)cpu_mips_get_count(env); } =20 +target_ulong helper_mfc0_cvmcount(CPUMIPSState *env) +{ + MIPSCPU *cpu =3D env_archcpu(env); + + return clock_ns_to_ticks(cpu->clock, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); +} + target_ulong helper_mftc0_entryhi(CPUMIPSState *env) { int other_tc =3D env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); diff --git a/target/mips/tcg/system_helper.h.inc b/target/mips/tcg/system_h= elper.h.inc index eaac5e2c6f..c8b6d8b92c 100644 --- a/target/mips/tcg/system_helper.h.inc +++ b/target/mips/tcg/system_helper.h.inc @@ -31,6 +31,7 @@ DEF_HELPER_1(mftc0_tcschedule, tl, env) DEF_HELPER_1(mfc0_tcschefback, tl, env) DEF_HELPER_1(mftc0_tcschefback, tl, env) DEF_HELPER_1(mfc0_count, tl, env) +DEF_HELPER_1(mfc0_cvmcount, tl, env) DEF_HELPER_1(mftc0_entryhi, tl, env) DEF_HELPER_1(mftc0_status, tl, env) DEF_HELPER_1(mftc0_cause, tl, env) diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index e3467d1525..123ba6aecd 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -5460,6 +5460,19 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, in= t reg, int sel) ctx->base.is_jmp =3D DISAS_EXIT; register_name =3D "Count"; break; + case CP0_REG09__CVMCOUNT: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + translator_io_start(&ctx->base); + gen_helper_mfc0_cvmcount(arg, tcg_env); + tcg_gen_ext32s_tl(arg, arg); + register_name =3D "CvmCount"; + break; + case CP0_REG09__CVMCTL: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_CvmCtl)= ); + tcg_gen_ext32s_tl(arg, arg); + register_name =3D "CvmCtl"; + break; default: goto cp0_unimplemented; } @@ -5481,6 +5494,13 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, in= t reg, int sel) gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare)); register_name =3D "Compare"; break; + case CP0_REG11__CVMMEMCTL: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + tcg_gen_ld_tl(arg, tcg_env, + offsetof(CPUMIPSState, CP0_CvmMemCtl)); + tcg_gen_ext32s_tl(arg, arg); + register_name =3D "CvmMemCtl"; + break; /* 6,7 are implementation dependent */ default: goto cp0_unimplemented; @@ -6176,6 +6196,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, in= t reg, int sel) gen_helper_mtc0_count(tcg_env, arg); register_name =3D "Count"; break; + case CP0_REG09__CVMCTL: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_CvmCtl)= ); + register_name =3D "CvmCtl"; + break; default: goto cp0_unimplemented; } @@ -6196,6 +6221,13 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, in= t reg, int sel) gen_helper_mtc0_compare(tcg_env, arg); register_name =3D "Compare"; break; + case CP0_REG11__CVMMEMCTL: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + tcg_gen_st_tl(arg, tcg_env, + offsetof(CPUMIPSState, CP0_CvmMemCtl)); + ctx->base.is_jmp =3D DISAS_STOP; + register_name =3D "CvmMemCtl"; + break; /* 6,7 are implementation dependent */ default: goto cp0_unimplemented; @@ -6940,6 +6972,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, i= nt reg, int sel) ctx->base.is_jmp =3D DISAS_EXIT; register_name =3D "Count"; break; + case CP0_REG09__CVMCOUNT: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + translator_io_start(&ctx->base); + gen_helper_mfc0_cvmcount(arg, tcg_env); + register_name =3D "CvmCount"; + break; + case CP0_REG09__CVMCTL: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + tcg_gen_ld_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_CvmCtl)= ); + register_name =3D "CvmCtl"; + break; default: goto cp0_unimplemented; } @@ -6960,6 +7003,12 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, i= nt reg, int sel) gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare)); register_name =3D "Compare"; break; + case CP0_REG11__CVMMEMCTL: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + tcg_gen_ld_tl(arg, tcg_env, + offsetof(CPUMIPSState, CP0_CvmMemCtl)); + register_name =3D "CvmMemCtl"; + break; /* 6,7 are implementation dependent */ default: goto cp0_unimplemented; @@ -7642,6 +7691,11 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, i= nt reg, int sel) gen_helper_mtc0_count(tcg_env, arg); register_name =3D "Count"; break; + case CP0_REG09__CVMCTL: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + tcg_gen_st_tl(arg, tcg_env, offsetof(CPUMIPSState, CP0_CvmCtl)= ); + register_name =3D "CvmCtl"; + break; default: goto cp0_unimplemented; } @@ -7664,6 +7718,12 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, i= nt reg, int sel) gen_helper_mtc0_compare(tcg_env, arg); register_name =3D "Compare"; break; + case CP0_REG11__CVMMEMCTL: + CP0_CHECK(ctx->insn_flags & INSN_OCTEON); + tcg_gen_st_tl(arg, tcg_env, + offsetof(CPUMIPSState, CP0_CvmMemCtl)); + register_name =3D "CvmMemCtl"; + break; /* 6,7 are implementation dependent */ default: goto cp0_unimplemented; --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123188414821.6731008457588; Wed, 15 Jul 2026 06:46:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv6-0005a6-9c; Wed, 15 Jul 2026 09:45:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv2-0005XM-Gh for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:00 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv0-0007tj-CC for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:00 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id fe0d8c33 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:51 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 694c9095; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=l7DDRAg VAgLl7fMyxNP68NFRW45Vg/87JXuhs43rF+M6YrXv34Q7k19PNGdIsliIFN1yARsIMTXWO REOM0gYsa6DvbbjEOHfe4jUZu7v2Br4u+8kylUe+SgiTRnM2h+GcjayJlh8fQGj5s7JN7z 2bTXMAqTXW8cD+2gyMY7/3/TI6ym0Sd6Ng0d1dyiz0CoQ+Uu4qM1V1Rm2oI9I9OnwLNG86 waLha8n4K41WMNnqHO8WU7iYq32u4VBpRTT1D8bQcVoP9mIvA0RYhju7ouzy5D33l+H8J5 atcuxE3ll9XJnTchN9gNQei6iNzkL98IBnkF7n7U6JV1KgVjK+72HMg== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=5 unVjui2VqYQAOoR8Cz3h7Wz8eYsYZYctNPB/KH5TKQ=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=v7UbFguvfz6y8cBVVj1neOEYYcKt7eExNAHiALyWfFK1XurOfmbSh50doHnumzK+Zks/ 2yLVaomPjU0zyX77XfTXYn8mQ5K/z02XeVQI6xTn4u4Y3kpcSj9REmXnGCs++Di4TMNy62 69h9POqs+W0JgzpTgaKMKzrb3AuXrI3nfDnBu45L3sfN8+HcRzui6VX8Ns4+7B3/aFBWXR B39DNiQ/v8licnUH2D/BfpUqTNzvGICT5kYF60NiJYEbn9g4tfvdsQ5SD3uruOiH5w2jY/ miHQgCERuRChWqARSluzVC8soFbzuyoKU5zSpg3lqmgL5uSf+eHMbDrY+uJ+ugDA== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=zkJ5SZo1; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=3vR+7kuv; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=5unVjui2 VqYQAOoR8Cz3h7Wz8eYsYZYctNPB/KH5TKQ=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=zkJ5SZo1l7pSrJx8BcQZocfcSkh2cV8Izz5 v8nN86AJbzKtVeb3UnCg0AdkT6LKZUtL95EFPzV+UmIgmU/UzSffJABRrV+3R/CKQZ64AK a15maoe1ZdCQXaN1IUNkL3cy16V2BHvBJ1mzdSY7BpqC/nHhjPGL3Qn3KY+iIndm5omo9z EJbu/XyIiBod4d4ql07WF8grVl5tCE61xe4zY19c6ZEXT0PnrKX7vtzZbkUlvapqE9WV36 svoUtgikbUXC30mltuQsveV7psUSDbZWxgJJpFnqYkXC5fGrR4Mt0HmSevfSwBW151KGkj ZQYcRyOY790s+wUb4uk+3sNRDaA== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=5unVjui2VqYQAOoR8Cz3h7Wz8eYsYZYctNPB/KH5TKQ=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=3vR+7kuvgCDwM3Fv9m DkQYBX+d7W600GqhwRzK7KKPUUHs5dHH8EIs1SOib+eHOUKBO3pnIMmcmSyUwpvUB0Cg== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 05/25] target/mips: add Octeon CN73xx CPU model Date: Wed, 15 Jul 2026 15:43:51 +0200 Message-ID: <20260715134447.56007-6-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123189740158500 Content-Type: text/plain; charset="utf-8" Add a CN73xx CPU definition for the Octeon III machine. The PRId, FPU FIR, and L2 cache geometry come from EdgeRouter Infinity ER-8-XG data; the remaining CP0 fields come from a Juniper SRX300 CN70xx/CN71xx dump. --- target/mips/cpu-defs.c.inc | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/target/mips/cpu-defs.c.inc b/target/mips/cpu-defs.c.inc index cc1916232f..ee638568db 100644 --- a/target/mips/cpu-defs.c.inc +++ b/target/mips/cpu-defs.c.inc @@ -1023,6 +1023,48 @@ const mips_def_t mips_defs[] =3D .insn_flags =3D CPU_MIPS64R2 | INSN_OCTEON, .mmu_type =3D MMU_TYPE_R4000, }, + { + /* + * Minimal Octeon CN73xx model for EBB7304 firmware. PRId, FPU FIR, + * and L2 cache geometry match a Ubiquiti EdgeRouter Infinity + * ER-8-XG; the remaining CP0 values are a placeholder Octeon III + * model derived from a Juniper SRX300 CN70xx/CN71xx dump. + */ + .name =3D "OcteonCN73XX", + .CP0_PRid =3D 0x000D9702, + .CP0_Config0 =3D MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_= AT) | + (MMU_TYPE_R4000 << CP0C0_MT) | (1 << CP0C0_VI), + .CP0_Config1 =3D MIPS_CONFIG1 | (1 << CP0C1_FP) | + (0x3F << CP0C1_MMU) | + (0 << CP0C1_IS) | (6 << CP0C1_IL) | (7 << CP0C1_IA)= | + (0 << CP0C1_DS) | (0 << CP0C1_DL) | (7 << CP0C1_DA)= | + (1 << CP0C1_C2) | (1 << CP0C1_PC) | + (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 =3D MIPS_CONFIG2 | (5 << CP0C2_SS) | (6 << CP0C2_SL) | + (15 << CP0C2_SA), + .CP0_Config3 =3D MIPS_CONFIG3 | (1U << CP0C3_M) | + (1 << CP0C3_BP) | (1 << CP0C3_BI) | + (1 << CP0C3_VZ) | (1 << CP0C3_ULRI) | + (1 << CP0C3_RXI) | (1 << CP0C3_LPA), + .CP0_Config4 =3D MIPS_CONFIG4 | (1U << CP0C4_M) | + (0x3c << CP0C4_KScrExist), + .CP0_Config7 =3D 1 << CP0C7_WII, + .CP0_LLAddr_rw_bitmask =3D 0, + .CP0_LLAddr_shift =3D 4, + .CP0_PageGrain =3D (1 << CP0PG_ELPA), + .SYNCI_Step =3D 32, + .CCRes =3D 1, + .CP0_Status_rw_bitmask =3D 0x36F8FFFF, + .CP1_fcr0 =3D (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | + (1 << FCR0_D) | (1 << FCR0_S) | + (0x97 << FCR0_PRID) | (0x0 << FCR0_REV), + .CP1_fcr31 =3D 0, + .CP1_fcr31_rw_bitmask =3D 0xFF83FFFF, + .SEGBITS =3D 42, + .PABITS =3D 49, + .insn_flags =3D CPU_MIPS64R2 | INSN_OCTEON, + .mmu_type =3D MMU_TYPE_R4000, + }, =20 #endif }; --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123180890917.958875934534; Wed, 15 Jul 2026 06:46:20 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv9-0005cI-7f; Wed, 15 Jul 2026 09:45:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv3-0005Xu-DJ for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:01 -0400 Received: from mx1.catap.net ([2a01:4f8:271:125e::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv1-0007uq-Ew for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:01 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id b64b0226 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:51 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id b42f9560; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=WPGSZzh UIP5yf8j+lp9rVikzwrpbBBx9p+9GPdRnCf7VRaDeVnfD6fo13wMidy12Sqw9u2maU7FBE aSNbo5nIPdvnICcZjv0QT2PPK+iTqzAA3XtKDnjn0xG7Al/srv32CvgnlpbqjulXa+aAs3 I38ZRd71YHmzYVBYFmQsXB9pI3MxT0EeAeCgdnji02EwYkyRqAp5Tg5VYr9L1lQJ3Q68YY Hs/mzQzPjFtJ4j/g6SBXCXXynYsRjXODIE142Qzul8V0vJGkgHFgR+f1ZMLBSCo8D/IyS2 COAPv8hwtngoI6Q7QVJ2NhC6GESVt1VgdR6VlBwm8iPq4ASXqMAvGTA== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=P Oyhf9Iunjp2h42Ks9RVFy2rrI6RIYh+DpHMxI4OICM=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=zhTXOglavO82RdyUSUrxaHBmq48hv+v69RVfpyMGOVjd8rJdi2sYK/hZIHsx8YXIR84B aNxH8pT8OBpMcForwZGclZdyh42URy2xQS/cIYG8zfreVSS7rrLBbkDzhMctyX4H6Ytjn6 QdISuce6R65jkuaNbOAcHuV21bOSlUgB7688ZoKbR4xCQuJw39OdcymKlpWt76HPK/kPj4 g0rw801WX0jBQwyEFfcYu0vEA98f8rMFdCbkyKpEX0PTE1kyqy76tJLzaYfa4DfRB3KLRC 3xn6b0LaD2OWqHxKbe1aLeZ/IctdwPdDuX1eJcbFMMuynBqvUNSMlOdtI0hs9c7A== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=DxcymHrR; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=dX2I6ata; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=POyhf9Iu njp2h42Ks9RVFy2rrI6RIYh+DpHMxI4OICM=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=DxcymHrRyn04We/RBykTsKoJ7qtKljAs+9n Qv7/ejSkJmNwjoWU4inQaCETrAyia2ZuM35Oe6GaYjE+ZhG6LqYbjoEw9KgRLrLRmlFyp0 ZXsoCSa87Uz2zOHafuFcug1LTmrMP8z9ruAXZo8Rz3EEw86dct7Qt1KBQ3U+2lIzEnYWh1 RxOJMRm9aFMdYIvZN+sSUy+sEkjJ34dtWJLOumC/9HkzhFoU8O3KHEejGAVJs8mmJDTUC0 sxN2meSMrbub2ZtmU5PcVwtJA8Kbiw2bPaSCkttggiEjJ4xc6/jH7Higt3vyWUehc8fe4G tSsF8ro41sdLOke3GiyNoQjAg/w== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=POyhf9Iunjp2h42Ks9RVFy2rrI6RIYh+DpHMxI4OICM=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=dX2I6atazOFqDucYUO jGhbr2PuhJT0FXmDGEY3PptVUakdMn5zmpcvMINWZJamSfwCDSIto6SPMcGJf4BNW/CQ== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 06/25] target/mips: accept Octeon PageMask encodings Date: Wed, 15 Jul 2026 15:43:52 +0200 Message-ID: <20260715134447.56007-7-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f8:271:125e::2; envelope-from=kirill@korins.ky; helo=mx1.catap.net 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_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123181784158500 Content-Type: text/plain; charset="utf-8" Octeon firmware programs contiguous PageMask values that do not follow the generic R4K even maskbits rule. Keep the generic validation rule for other MIPS CPUs, while allowing Octeon CPUs to use the contiguous masks accepted by hardware. --- target/mips/tcg/system/cp0_helper.c | 15 ++++++++++----- target/mips/tcg/system/tlb_helper.c | 2 +- target/mips/tcg/tcg-internal.h | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/target/mips/tcg/system/cp0_helper.c b/target/mips/tcg/system/c= p0_helper.c index 1c23d2a525..40a41805fa 100644 --- a/target/mips/tcg/system/cp0_helper.c +++ b/target/mips/tcg/system/cp0_helper.c @@ -882,14 +882,19 @@ void helper_mtc0_memorymapid(CPUMIPSState *env, targe= t_ulong arg1) } } =20 -uint32_t compute_pagemask(uint32_t val) +uint32_t compute_pagemask(CPUMIPSState *env, uint32_t val) { /* Don't care MASKX as we don't support 1KB page */ - uint32_t mask =3D extract32(val, CP0PM_MASK, 16); + uint32_t mask =3D val >> CP0PM_MASK; int maskbits =3D cto32(mask); =20 - /* Ensure no more set bit after first zero, and maskbits even. */ - if ((mask >> maskbits) =3D=3D 0 && maskbits % 2 =3D=3D 0) { + /* + * Generic R4K PageMask values use two mask bits per size step. + * Octeon accepts contiguous byte masks such as 0x003fffff for + * two 2 MiB pages. + */ + if ((mask & (mask + 1)) =3D=3D 0 && + ((env->insn_flags & INSN_OCTEON) || maskbits % 2 =3D=3D 0)) { return mask << CP0PM_MASK; } else { /* When invalid, set to default target page size. */ @@ -899,7 +904,7 @@ uint32_t compute_pagemask(uint32_t val) =20 void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) { - env->CP0_PageMask =3D compute_pagemask(arg1); + env->CP0_PageMask =3D compute_pagemask(env, arg1); } =20 void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/t= lb_helper.c index 4c0a25e622..ae805bff28 100644 --- a/target/mips/tcg/system/tlb_helper.c +++ b/target/mips/tcg/system/tlb_helper.c @@ -877,7 +877,7 @@ refill: } } pw_pagemask =3D m >> TARGET_PAGE_BITS; - pw_pagemask =3D compute_pagemask(pw_pagemask << CP0PM_MASK); + pw_pagemask =3D compute_pagemask(env, pw_pagemask << CP0PM_MASK); pw_entryhi =3D (address & ~0x1fff) | (env->CP0_EntryHi & 0xFF); { target_ulong tmp_entryhi =3D env->CP0_EntryHi; diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index 950e6afc3f..66ae39551e 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -47,7 +47,7 @@ bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); =20 void mmu_init(CPUMIPSState *env, const mips_def_t *def); =20 -uint32_t compute_pagemask(uint32_t val); +uint32_t compute_pagemask(CPUMIPSState *env, uint32_t val); =20 void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra); uint32_t cpu_mips_get_random(CPUMIPSState *env); --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123171817860.3613304742628; Wed, 15 Jul 2026 06:46:11 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv7-0005ai-9V; Wed, 15 Jul 2026 09:45:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv3-0005YI-O1 for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:01 -0400 Received: from mx1.catap.net ([2a01:4f8:271:125e::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv1-0007u3-Nc for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:01 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 8722d684 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:51 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 49fd2b21; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=ts6aM0m WcFLIi/+Jxj9p5mWm/B1sUdsH1lOiEf17h0lakknpm5EDogN93+kdMw2oQGWAK+Bl7w8VD 40PgvCtbWGznGVt1/MbtXev8fvJvWjJe+2o9Li/7OMvVZw9uO5GfsGhYfVumuSvR/e858w +9mxh/5XPRGLo6NIEdlwPxe9ojDKPVexNQkYHS0voAxpq0botncbb5JfFZQatz2mdx3r22 FnyaZSGW4dYWGDRuJlloi+Au9gubmKa036sXZJxGmIwaEsMtIR9XWZqh6SA1Nt2GVb45dX kTPfaeMGh0ahn3NU4VaRHqRWbQbw+KovnTRvm6XX4Jas/jznjB3Q/pw== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=3 MLQZQuX57ziRIMf9bNLKRlOE2JdgNKjvbZaASZXHtQ=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=q76iLWIdO9IOgSMhtVEmzPBoapWpDzlG67L+XeCHWZjMT1imZQ26ob84k4ap1ZRLKMTX JW2xQBYwOYL+dHp6GSpz7+p0bEY+MOIhvLmvLiDBcpnQKUn1+EqVZ5l1Z735qOx7+m+14y sZsMxX7WCfESNFuOT66QTWVZ09UZZKEM0iwoj9v+4bEAql04xBlWltAg+e/TmPvCRFWEva 1Y+Z3xyxP1CbZCawm7f6JtbOC+efFp2YRY6HOhgUUsPqVnSVdBGTFFP5nNUE9HRDZ1rGxa 2aWKLAuG74rQ8UmIyUG97W40FrNiyD7MV/aJ3KDIHGmLd+L/9UFABL7q9Wbkw3Sw== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=m/ycMag2; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=d7/Zx56Q; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=3MLQZQuX 57ziRIMf9bNLKRlOE2JdgNKjvbZaASZXHtQ=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=m/ycMag23WG3gAu9TUqNvts2XOxpx6CChgG m82oNjw9aV87hYOA7txnAW/Oy+LME70gxe/vdiN/uGPbSdS0/GNSWs5fkSs6jI3b9j6L5l ESmzbJa5edwpJouNzoWp72EEAEWICwgyKpa1qHiZmLLSOCObPzXR+onUvy5xMq7ryvXOwS p7KM4NVhwgbZUb4mq1Pi0lBenl5kN4pE4JEKxInJpvCudsWbOK/i/rSasciN39oqjBqJ0Q AiZuJrNuIq7aA+6SMY2uUvSAqxV1yPFlu/xS7HvE6ANr26LCRfCQVJNmmLtAqrcU0dXp8x d9GC/oZZ5iaKY4RHuQikINRK9xQ== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=3MLQZQuX57ziRIMf9bNLKRlOE2JdgNKjvbZaASZXHtQ=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=d7/Zx56QqUiFjcYz/f 934aB2Z+dJi/JWfSrPa9wBmQjmyy2TRVJf8mzpumY4Zf+Jz9UHaycB3pBxFwRe+zlVAg== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 07/25] target/mips: allow Octeon unaligned accesses Date: Wed, 15 Jul 2026 15:43:53 +0200 Message-ID: <20260715134447.56007-8-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f8:271:125e::2; envelope-from=kirill@korins.ky; helo=mx1.catap.net 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_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123173791158500 Content-Type: text/plain; charset="utf-8" Octeon firmware performs unaligned memory accesses during early DDR setup. Use QEMU's unaligned memory operation mode for Octeon translations, matching the existing treatment for MIPS R6 and Loongson3A. --- target/mips/tcg/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 123ba6aecd..d83f76e514 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -15193,6 +15193,7 @@ static void mips_tr_init_disas_context(DisasContext= Base *dcbase, CPUState *cs) #endif ctx->default_tcg_memop_mask =3D (!(ctx->insn_flags & ISA_NANOMIPS32) && (ctx->insn_flags & (ISA_MIPS_R6 | + INSN_OCTEON | INSN_LOONGSON3A))) ? MO_UNALN : MO_ALIGN; if (tb_flags & TB_FLAG_MIPS_FIXADE) { ctx->default_tcg_memop_mask =3D MO_UNALN; --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123313279368.71261268140563; Wed, 15 Jul 2026 06:48:33 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvA-0005dx-0D; Wed, 15 Jul 2026 09:45:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv4-0005Yp-Jv for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:02 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv2-0007uM-Fm for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:02 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 8fb73eee (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:52 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 7ba03e47; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=oZPUNjb n7BKVINuYzJ2lWf/cowJIL9BsK9B2dHWq0jHf5VUOgx9V7s4BOogFpdOHlw/rfX2pBd9ct ecfKv5pHr90jdUN7aN5ompINPpQnWnzKIHAGPi1NybNVPCab0IAPcH0XpRsPPDyNcF908q pO/TSUDbnEvSrNvcttGf7Qzi9oqEIv88svqucxpV7Jo19xDHLBZJTP4kRGnpixxQ4a1icM JLrkW5146axjvmjH6mOapVktAjD/g2GOZWgesGoNPdcEnMWAX6zVB5sWt09pUdRH+llAqg YHsXEJjK76ChevHXzSBRGftyJyOj6UHUZeQ47RRWqDtmZoNLYzlbSAQ== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=1 CN3i4bgmNiJi3qNNhW8S3FBGVql07O2JBNhqQFUEiA=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=yAMzDwFvsGG/UWICIPn/A43KwfDSm3FLejAtGIl4QLubQxpToTrHDCsUSRXgnZ8lukh3 93e0NuDIj+7SDv290Nn3oRQvNd/dt+S7BceR8hTxfQ7sxeuV43BHYR+c2tlvQQP4fQsDLl kBGKPcOGWQreRv2zxh3VeO/ldPIybz6eefjvslX8MgSW6zrE+pV8sKrAHd+yu8nZ8YHQHJ cP/0s2qQcWlXFWhFnKV15hr/YN4rErOsHZh3ktRh3XhsCLbrc4WqIfP9HIMOaIUDOB5etl KLqrUKlMq0rHrvwan3UrSdVjjlg71WpQAi9Y1sqyNAfAIukw1Rgd5oYBK+bTS7Mw== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=oe9lA1a/; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=hA9al6nO; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=1CN3i4bg mNiJi3qNNhW8S3FBGVql07O2JBNhqQFUEiA=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=oe9lA1a/twCkEX/MnMfMM8mc7UySPkAtoWm bLI4g8XYjpMQG1YWUhz5AnZ7LNeroJFGwMTU+6gikvKS6teQhVYT5jOh4alW1f+egVpNGJ rkHAsk/njokyUZtOEHiCF4ExI1sq3buOc0F4juA17fjhhMw3fuOqelAIESbTPrGm/A6lCy rxIAQcTSEMdTs8T7aZWQHByYbWu+kjklAC7jA4Dhw1CTT8vpXaY4vYkpCYgv0rK+DimHdP INFstpe0/0xjP2svyj704dtPlA6Jzac9oVLVF8ILvVhP6vTTguUbCOWIulP/dyH6e1G1nT I7s9UPugEaCK47Dvy7wF/PgcZJg== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=1CN3i4bgmNiJi3qNNhW8S3FBGVql07O2JBNhqQFUEiA=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=hA9al6nOVZ8Dt8U5CG nLk8NZHG/G14KSK3FgrxKyY9qMNyfQTFy1OptN3ZnBYtDGIRUoTm+JhOoigLUx6upnDA== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 08/25] hw/mips: add empty Octeon III machine Date: Wed, 15 Jul 2026 15:43:54 +0200 Message-ID: <20260715134447.56007-9-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123314833158500 Content-Type: text/plain; charset="utf-8" Register an empty octeon3 machine for the Cavium/Marvell Octeon III EBB7304 evaluation board. Define its CPU, RAM and clock defaults; later commits add the board devices. Early Octeon investigation used Amir Mehmood's original Octeon host.patch as a behavioral reference; that work informed the basic machine approach and several hardware model ideas. No code from that patch remains in this implementation. --- hw/mips/Kconfig | 5 +++ hw/mips/meson.build | 1 + hw/mips/octeon.c | 89 +++++++++++++++++++++++++++++++++++++++ hw/mips/octeon_internal.h | 16 +++++++ 4 files changed, 111 insertions(+) create mode 100644 hw/mips/octeon.c create mode 100644 hw/mips/octeon_internal.h diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index b59cb2f111..2e71e6dee6 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -67,6 +67,11 @@ config LOONGSON3V select FW_CFG_MIPS select UNIMP =20 +config MIPS_OCTEON + bool + default y + depends on MIPS64 && TARGET_BIG_ENDIAN + config MIPS_CPS bool select MIPS_ITU if TCG diff --git a/hw/mips/meson.build b/hw/mips/meson.build index 390f0fd7f9..f11dcdf794 100644 --- a/hw/mips/meson.build +++ b/hw/mips/meson.build @@ -10,6 +10,7 @@ if 'CONFIG_TCG' in config_all_accel mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c')) mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c')) mips_ss.add(when: 'CONFIG_MIPS_BOSTON', if_true: files('boston.c')) +mips_ss.add(when: 'CONFIG_MIPS_OCTEON', if_true: files('octeon.c')) endif =20 hw_arch +=3D {'mips': mips_ss} diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c new file mode 100644 index 0000000000..2ecc464579 --- /dev/null +++ b/hw/mips/octeon.c @@ -0,0 +1,89 @@ +/* + * QEMU Cavium Octeon board model. + * + * Copyright (c) 2026 Kirill A. Korinsky + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "hw/core/boards.h" +#include "hw/core/qdev-properties.h" +#include "hw/mips/octeon_internal.h" +#include "target/mips/cpu.h" + +#define TYPE_OCTEON_MACHINE MACHINE_TYPE_NAME("octeon3") +OBJECT_DECLARE_SIMPLE_TYPE(OcteonMachineState, OCTEON_MACHINE) + +#define OCTEON_DEFAULT_CPU_HZ 1800000000 +#define OCTEON_DEFAULT_REF_HZ 50000000 +#define OCTEON_DEFAULT_IO_HZ 1000000000 +#define OCTEON_DEFAULT_DDR_HZ 800000000 +#define OCTEON_DEFAULT_RAM_SIZE (1 * GiB) + +struct OcteonMachineState { + MachineState parent_obj; + uint64_t cpu_hz; + uint64_t ref_hz; + uint64_t io_hz; + uint64_t ddr_hz; +}; + +static void mips_octeon_init(MachineState *machine) +{ +} + +static void octeon_machine_instance_init(Object *obj) +{ + OcteonMachineState *oms =3D OCTEON_MACHINE(obj); + + oms->cpu_hz =3D OCTEON_DEFAULT_CPU_HZ; + oms->ref_hz =3D OCTEON_DEFAULT_REF_HZ; + oms->io_hz =3D OCTEON_DEFAULT_IO_HZ; + oms->ddr_hz =3D OCTEON_DEFAULT_DDR_HZ; + + object_property_add_uint64_ptr(obj, "cpu-clock-hz", &oms->cpu_hz, + OBJ_PROP_FLAG_READWRITE); + object_property_set_description(obj, "cpu-clock-hz", + "CPU clock frequency in Hz"); + + object_property_add_uint64_ptr(obj, "ref-clock-hz", &oms->ref_hz, + OBJ_PROP_FLAG_READWRITE); + object_property_set_description(obj, "ref-clock-hz", + "Reference clock frequency in Hz"); + + object_property_add_uint64_ptr(obj, "io-clock-hz", &oms->io_hz, + OBJ_PROP_FLAG_READWRITE); + object_property_set_description(obj, "io-clock-hz", + "IO clock frequency in Hz"); + + object_property_add_uint64_ptr(obj, "ddr-clock-hz", &oms->ddr_hz, + OBJ_PROP_FLAG_READWRITE); + object_property_set_description(obj, "ddr-clock-hz", + "DDR clock frequency in Hz"); +} + +static void octeon_machine_class_init(ObjectClass *oc, const void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + + mc->desc =3D "Cavium Octeon III / EBB7304 EVK"; + mc->init =3D mips_octeon_init; + mc->default_cpu_type =3D MIPS_CPU_TYPE_NAME("OcteonCN73XX"); + mc->default_ram_size =3D OCTEON_DEFAULT_RAM_SIZE; + mc->default_ram_id =3D "octeon.ram"; + mc->max_cpus =3D OCTEON_MAX_CPUS; +} + +static const TypeInfo octeon_machine_types[] =3D { + { + .name =3D TYPE_OCTEON_MACHINE, + .parent =3D TYPE_MACHINE, + .instance_size =3D sizeof(OcteonMachineState), + .instance_init =3D octeon_machine_instance_init, + .class_init =3D octeon_machine_class_init, + } +}; + +DEFINE_TYPES(octeon_machine_types) diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h new file mode 100644 index 0000000000..7cab7790bd --- /dev/null +++ b/hw/mips/octeon_internal.h @@ -0,0 +1,16 @@ +/* + * QEMU Cavium Octeon board model internal declarations. + * + * Copyright (c) 2026 Kirill A. Korinsky + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MIPS_OCTEON_INTERNAL_H +#define HW_MIPS_OCTEON_INTERNAL_H + +#include "qemu/typedefs.h" + +#define OCTEON_MAX_CPUS 16 + +#endif --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123263541957.6986841281871; Wed, 15 Jul 2026 06:47:43 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv8-0005bo-Ja; Wed, 15 Jul 2026 09:45:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv5-0005Za-LO for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:03 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv2-0007tj-R0 for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:03 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id c8b15487 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:52 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 3dada449; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=pn7LMKL RvzQ+uHwaBnvia9Tb9QVdPdgA64G5aZVJFJ5DpvcFZB/Rl8+J0poI5Xmomiv8KaARdKVSy qqsJIzjNhmZqQ71f153XTDi2BzdDPHY3+HCUWBa1RKefBgabaB+bkdRgOrccskknDbTYt9 zW8wO9jsYXMLAp8Bl0uj3KdouYZTklYhCvoyXSwYpPnQyuqeI1s//vS8v9wH2KD9kHUKhW vb3qyYfPLSNv3Mq9R8yF8fEtteAyZGw2hm26rkRPjbGBtdMX2pZ6qccydLI++AWjD59Rf3 Fku7Qp1o0swBOQmZ64H6WCPBOx/EefvWQIhQSGVBKkgUyZ+E4XNUyyg== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=L vU3uZ5hTIR4e9PtiNPD+TtAzQZqjoWYFcGKtiHcZz8=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=UMOZn3WmXTbFoZuPupwFcXcF105qq4OvtVid5yFNz/8+aAW7KjMVXoZTGL2sLDXr+JZB JvzGrHS/pxTkGVJZvHQ4uhM55/Rrl1WKgzyriZ9elM7uUeGfY7DYbMwQzeB6g9aP5IlMtf mBhF9gJCXt6AYLYXLhfhtm78lXxy5baCEj/By97xo/wMxEgKY1AAyGuzl+wwCLXNiriQKv QWRshUpECBKrIS+9Zl5FCE4qxBHPVzZkPisvqkw1VkMK22EpZLt/OI9dOIIZ++rrbdBHU8 XvWl22M1PZF0K4L9E0YAKYMV5DjQR08auf0epzWCo4zWfA669I5YyabT+Gk5oPaA== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=a2IHo5DC; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=adV4tdDr; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=LvU3uZ5h TIR4e9PtiNPD+TtAzQZqjoWYFcGKtiHcZz8=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=a2IHo5DC6VJRPJM/C/T7W6B7GXqB/z8Z1aD nJCQrq/8IMI0PV4xSQCAhhy4kcQT8eDbhoZe4Ofhw4V5HVm6SldRxyGVKtPYLNHzX7hzr9 8XJWls1U2ZfTKMllLF4vesx/D9qDpeqI7tI46nEqTrVLfAduGqBx1t2BmIrg+uRnQJVffO fKklyF11jHG7UhUaFdyThU3L/aWEOQfM5dfYLkQUoiyiht8RHZkBtodQmr2WRy6ZqGIWFT x1TB5OsnyjeDtMfuhKcBhgRY+pXLrcOULAJIC2ZSy3KZ9EmWulbd/JY3jhGZu1VQ+sH480 qqasFw11e6STw2JR3xYVW6tzBJQ== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=LvU3uZ5hTIR4e9PtiNPD+TtAzQZqjoWYFcGKtiHcZz8=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=adV4tdDrOS1ff910IZ l8Ivwucz/thIDX2nAFUuqktLZwIid45hFnWWWIrfAD/UdZzdT1ekZPosFWTLWESYg1CA== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 09/25] hw/mips: add Octeon CPUs and boot memory Date: Wed, 15 Jul 2026 15:43:55 +0200 Message-ID: <20260715134447.56007-10-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123264493158500 Content-Type: text/plain; charset="utf-8" Create the Octeon CPUs and clock, map the split DRAM layout and per-core CVMSEG storage, and provide the EBB7304 boot flash windows. Load firmware into the flash reset alias and restore the boot PC during machine reset. --- hw/mips/Kconfig | 1 + hw/mips/octeon.c | 308 ++++++++++++++++++++++++++++++++++++++ hw/mips/octeon_internal.h | 28 ++++ 3 files changed, 337 insertions(+) diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 2e71e6dee6..cb6057fe38 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -71,6 +71,7 @@ config MIPS_OCTEON bool default y depends on MIPS64 && TARGET_BIG_ENDIAN + select PFLASH_CFI02 =20 config MIPS_CPS bool diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 2ecc464579..0e02d3693d 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -8,30 +8,337 @@ =20 #include "qemu/osdep.h" #include "qemu/units.h" +#include "qemu/datadir.h" +#include "qapi/error.h" +#include "hw/core/clock.h" #include "hw/core/boards.h" +#include "hw/core/qdev-clock.h" #include "hw/core/qdev-properties.h" +#include "hw/core/qdev-properties-system.h" +#include "hw/core/sysbus.h" +#include "hw/block/flash.h" +#include "hw/mips/mips.h" +#include "system/blockdev.h" +#include "system/address-spaces.h" +#include "system/memory.h" +#include "system/reset.h" +#include "qemu/error-report.h" #include "hw/mips/octeon_internal.h" #include "target/mips/cpu.h" =20 #define TYPE_OCTEON_MACHINE MACHINE_TYPE_NAME("octeon3") OBJECT_DECLARE_SIMPLE_TYPE(OcteonMachineState, OCTEON_MACHINE) =20 +/* + * Clock defaults follow a Ubiquiti E1000 EBB7304 U-Boot banner. + * DDR follows the upstream EBB7304 U-Boot board default. + */ #define OCTEON_DEFAULT_CPU_HZ 1800000000 #define OCTEON_DEFAULT_REF_HZ 50000000 #define OCTEON_DEFAULT_IO_HZ 1000000000 #define OCTEON_DEFAULT_DDR_HZ 800000000 + +/* + * The physical layout follows U-Boot's generic Octeon III + * OCTEON_MAX_PHY_MEM_SIZE value. Keep 1 GiB as the tested default. + */ #define OCTEON_DEFAULT_RAM_SIZE (1 * GiB) +#define OCTEON_MAX_PHY_MEM_SIZE (512 * GiB) + +/* + * The EBB7304 FDT exposes DRAM below and above the + * 0x10000000..0x1fffffff boot-bus/EJTAG hole. + */ +#define OCTEON_DR0_BASE 0x000000000ULL +#define OCTEON_DR0_SIZE (256 * MiB) +#define OCTEON_DR1_BASE 0x020000000ULL +#define OCTEON_DR1_SIZE (OCTEON_MAX_PHY_MEM_SIZE - OCTEON_DR0_= SIZE) + +/* + * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; + * the guest sees the virtual CVMSEG window, not this physical address. + */ +#define OCTEON_CVMSEG_BASE 0x10000000000ULL +#define OCTEON_CVMSEG_SIZE 0x4000 +#define OCTEON_CVMSEG_TOTAL_SIZE (OCTEON_MAX_CPUS * OCTEON_CVMSEG_SIZE) + +#define OCTEON_FLASH_BASE 0x1f400000ULL +#define OCTEON_FLASH_RESET_BASE 0x1fc00000ULL +#define OCTEON_FLASH_RESET_SIZE (4 * MiB) +#define OCTEON_FLASH_MAIN_SECTORS 127 +#define OCTEON_FLASH_MAIN_SECTOR_SIZE (64 * KiB) +#define OCTEON_FLASH_ENV_SECTORS 8 +#define OCTEON_FLASH_ENV_SECTOR_SIZE 0x2000 +#define OCTEON_FLASH_SIZE \ + (OCTEON_FLASH_MAIN_SECTORS * OCTEON_FLASH_MAIN_SECTOR_SIZE + \ + OCTEON_FLASH_ENV_SECTORS * OCTEON_FLASH_ENV_SECTOR_SIZE) +#define OCTEON_FLASH_ENV_OFFSET \ + (OCTEON_FLASH_SIZE - OCTEON_FLASH_ENV_SECTOR_SIZE) +#define OCTEON_FLASH_WIDTH 2 =20 struct OcteonMachineState { MachineState parent_obj; + OcteonState *board; uint64_t cpu_hz; uint64_t ref_hz; uint64_t io_hz; uint64_t ddr_hz; }; =20 +static void octeon_validate_clocks(OcteonMachineState *oms) +{ + if (!oms->cpu_hz || !oms->ref_hz || !oms->io_hz || !oms->ddr_hz) { + error_report("octeon3 clock frequencies must be non-zero"); + exit(1); + } + + if (oms->cpu_hz % oms->ref_hz || oms->io_hz % oms->ref_hz) { + error_report("octeon3 CPU and IO clocks must be multiples of " + "ref-clock-hz"); + exit(1); + } +} + +static void octeon_cpu_after_reset(OcteonCPUState *cs) +{ + CPUMIPSState *env =3D &cs->cpu->env; + + env->CP0_CvmMemCtl =3D 0x100; + env->CP0_CvmCtl =3D 0; + + if (cs->boot_cpu && cs->board->firmware_entry) { + env->active_tc.PC =3D cs->board->firmware_entry; + } +} + +static void octeon_create_cpus(OcteonState *s) +{ + unsigned int i; + + s->cpuclk =3D clock_new(OBJECT(s->machine), "cpu-refclk"); + clock_set_hz(s->cpuclk, s->cpu_hz); + s->cpu_count =3D s->machine->smp.cpus; + for (i =3D 0; i < s->cpu_count; i++) { + DeviceState *dev =3D qdev_new(s->machine->cpu_type); + + s->cpu[i].board =3D s; + s->cpu[i].boot_cpu =3D i =3D=3D 0; + object_property_set_bool(OBJECT(dev), "big-endian", TARGET_BIG_END= IAN, + &error_abort); + object_property_set_bool(OBJECT(dev), "start-powered-off", i !=3D = 0, + &error_abort); + qdev_connect_clock_in(dev, "clk-in", s->cpuclk); + qdev_realize(dev, NULL, &error_abort); + s->cpu[i].cpu =3D MIPS_CPU(dev); + + cpu_mips_irq_init_cpu(s->cpu[i].cpu); + cpu_mips_clock_init(s->cpu[i].cpu); + qemu_register_resettable(OBJECT(dev)); + } +} + +static uint64_t octeon_map_ram_alias(OcteonState *s, MemoryRegion *alias, + const char *name, hwaddr base, + uint64_t offset, uint64_t size) +{ + MemoryRegion *sysmem =3D get_system_memory(); + + if (!size) { + return offset; + } + + memory_region_init_alias(alias, NULL, name, s->machine->ram, offset, s= ize); + memory_region_add_subregion(sysmem, base, alias); + return offset + size; +} + +static void octeon_map_ram(OcteonState *s) +{ + MemoryRegion *sysmem =3D get_system_memory(); + uint64_t offset =3D 0; + uint64_t remaining =3D s->machine->ram_size; + uint64_t size; + + size =3D MIN(remaining, (uint64_t)OCTEON_DR0_SIZE); + offset =3D octeon_map_ram_alias(s, &s->dr0, "octeon.dr0", + OCTEON_DR0_BASE, offset, size); + remaining -=3D size; + + size =3D MIN(remaining, (uint64_t)OCTEON_DR1_SIZE); + octeon_map_ram_alias(s, &s->dr1, "octeon.dr1", + OCTEON_DR1_BASE, offset, size); + + memory_region_init_ram(&s->cvmseg, NULL, "octeon.cvmseg", + OCTEON_CVMSEG_TOTAL_SIZE, &error_fatal); + memory_region_add_subregion(sysmem, OCTEON_CVMSEG_BASE, &s->cvmseg); +} + +static void octeon_load_firmware(OcteonState *s) +{ + g_autofree char *filename =3D NULL; + g_autofree gchar *contents =3D NULL; + g_autoptr(GError) err =3D NULL; + gsize len; + uint8_t *flash; + + if (!s->machine->firmware) { + return; + } + if (!s->flash) { + error_report("Octeon boot flash is not initialized"); + exit(1); + } + + filename =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, s->machine->firmware); + if (!filename) { + error_report("Could not find Octeon firmware '%s'", + s->machine->firmware); + exit(1); + } + + if (!g_file_get_contents(filename, &contents, &len, &err)) { + error_report("Could not load Octeon firmware '%s': %s", + filename, err->message); + exit(1); + } + + if (len =3D=3D 0 || len > OCTEON_FLASH_ENV_OFFSET) { + error_report("Octeon firmware '%s' has invalid size %" G_GSIZE_FOR= MAT, + filename, len); + exit(1); + } + + flash =3D memory_region_get_ram_ptr(s->flash); + memcpy(flash, contents, len); + s->firmware_entry =3D cpu_mips_phys_to_kseg1(NULL, OCTEON_FLASH_RESET_= BASE); +} + +static MemTxResult octeon_boot_flash_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + OcteonState *s =3D opaque; + uint8_t buf[8]; + MemTxResult result =3D MEMTX_OK; + unsigned int i; + + for (i =3D 0; i < size; i++) { + uint64_t value; + + result |=3D memory_region_dispatch_read(s->flash, addr + i, &value, + MO_8, attrs); + buf[i] =3D value; + } + *data =3D ldn_be_p(buf, size); + return result; +} + +static MemTxResult octeon_boot_flash_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + OcteonState *s =3D opaque; + unsigned access_size =3D MIN(size, 4); + + if (size > access_size) { + access_size =3D OCTEON_FLASH_WIDTH; + } + return memory_region_dispatch_write(s->flash, addr, value, + size_memop(access_size) | MO_BE, + attrs); +} + +static const MemoryRegionOps octeon_boot_flash_ops =3D { + .read_with_attrs =3D octeon_boot_flash_read, + .write_with_attrs =3D octeon_boot_flash_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 8, + }, +}; + +static void octeon_init_flash(OcteonState *s) +{ + DriveInfo *dinfo =3D drive_get(IF_PFLASH, 0, 0); + DeviceState *dev; + uint8_t *flash; + + dev =3D qdev_new(TYPE_PFLASH_CFI02); + if (dinfo) { + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo)); + } + qdev_prop_set_uint32(dev, "num-blocks0", OCTEON_FLASH_MAIN_SECTORS); + qdev_prop_set_uint32(dev, "sector-length0", + OCTEON_FLASH_MAIN_SECTOR_SIZE); + qdev_prop_set_uint32(dev, "num-blocks1", OCTEON_FLASH_ENV_SECTORS); + qdev_prop_set_uint32(dev, "sector-length1", + OCTEON_FLASH_ENV_SECTOR_SIZE); + qdev_prop_set_uint8(dev, "width", OCTEON_FLASH_WIDTH); + qdev_prop_set_uint8(dev, "mappings", 1); + qdev_prop_set_uint8(dev, "big-endian", TARGET_BIG_ENDIAN); + qdev_prop_set_uint16(dev, "id0", 0x01); + qdev_prop_set_uint16(dev, "id1", 0x7e); + qdev_prop_set_uint16(dev, "id2", 0x00); + qdev_prop_set_uint16(dev, "id3", 0x00); + qdev_prop_set_uint16(dev, "unlock-addr0", 0x555); + qdev_prop_set_uint16(dev, "unlock-addr1", 0x2aa); + qdev_prop_set_string(dev, "name", "octeon.bootbus-flash"); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + s->flash =3D sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + if (!dinfo) { + flash =3D memory_region_get_ram_ptr(s->flash); + memset(flash, 0xff, OCTEON_FLASH_SIZE); + } + memory_region_init_io(&s->boot_flash, NULL, &octeon_boot_flash_ops, s, + "octeon.bootbus-flash-window", OCTEON_FLASH_SIZE= ); + memory_region_add_subregion(get_system_memory(), OCTEON_FLASH_BASE, + &s->boot_flash); + + memory_region_init_alias(&s->boot_flash_alias, NULL, + "octeon.bootbus-flash-reset-alias", + &s->boot_flash, 0, OCTEON_FLASH_RESET_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_FLASH_RESET_BA= SE, + &s->boot_flash_alias); +} + static void mips_octeon_init(MachineState *machine) { + OcteonMachineState *oms =3D OCTEON_MACHINE(machine); + OcteonState *s =3D g_new0(OcteonState, 1); + + octeon_validate_clocks(oms); + + oms->board =3D s; + s->machine =3D machine; + s->cpu_hz =3D oms->cpu_hz; + s->ref_hz =3D oms->ref_hz; + s->io_hz =3D oms->io_hz; + s->ddr_hz =3D oms->ddr_hz; + + if (machine->kernel_filename) { + error_report("-kernel is not implemented for octeon3; " + "boot via -bios and U-Boot"); + exit(1); + } + + octeon_map_ram(s); + octeon_init_flash(s); + octeon_load_firmware(s); + octeon_create_cpus(s); + +} + +static void octeon_machine_reset(MachineState *machine, ResetType type) +{ + OcteonState *s =3D OCTEON_MACHINE(machine)->board; + unsigned int i; + + qemu_devices_reset(type); + for (i =3D 0; i < s->cpu_count; i++) { + octeon_cpu_after_reset(&s->cpu[i]); + } } =20 static void octeon_machine_instance_init(Object *obj) @@ -70,6 +377,7 @@ static void octeon_machine_class_init(ObjectClass *oc, c= onst void *data) =20 mc->desc =3D "Cavium Octeon III / EBB7304 EVK"; mc->init =3D mips_octeon_init; + mc->reset =3D octeon_machine_reset; mc->default_cpu_type =3D MIPS_CPU_TYPE_NAME("OcteonCN73XX"); mc->default_ram_size =3D OCTEON_DEFAULT_RAM_SIZE; mc->default_ram_id =3D "octeon.ram"; diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index 7cab7790bd..2e568c29ea 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -10,7 +10,35 @@ #define HW_MIPS_OCTEON_INTERNAL_H =20 #include "qemu/typedefs.h" +#include "system/memory.h" +#include "target/mips/cpu.h" =20 #define OCTEON_MAX_CPUS 16 +typedef struct OcteonState OcteonState; + +typedef struct OcteonCPUState { + OcteonState *board; + MIPSCPU *cpu; + bool boot_cpu; +} OcteonCPUState; + +struct OcteonState { + MachineState *machine; + Clock *cpuclk; + uint64_t cpu_hz; + uint64_t ref_hz; + uint64_t io_hz; + uint64_t ddr_hz; + OcteonCPUState cpu[OCTEON_MAX_CPUS]; + unsigned int cpu_count; + uint64_t firmware_entry; + + MemoryRegion dr0; + MemoryRegion dr1; + MemoryRegion *flash; + MemoryRegion boot_flash; + MemoryRegion boot_flash_alias; + MemoryRegion cvmseg; +}; =20 #endif --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123179527140.29335162166183; Wed, 15 Jul 2026 06:46:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvE-0005kr-SV; Wed, 15 Jul 2026 09:45:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv6-0005aX-U2 for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:04 -0400 Received: from mx1.catap.net ([2a01:4f8:271:125e::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv3-0007uq-Qk for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:04 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 110431e6 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:52 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id f52a85c7; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=qBysbkb 6KbdbnMg2RHIYN2AXBceoQGCmiJlbGjbash6MN93DrG495DcJXnypq4eJlqQAtl25B7b4c BIkMLPhSlGAHtod9SNoHqTC0fmQMxsQj+o9A1MNLhP9rb7pJPSO6DSh+cnLgC531NXTytL 5qKOQ6zWbnKDh70N0WJwn4rvTFictm2myQwPSNmcN1/hqo8lCn4gHiH2ecSRzG26Q2UcnO F1nW6zW+PfAQKBMkKnAd1gaVhms8h0AJt1F2wris/aglJ60ra/ttmPhENYAiAG8Aj2THLy xOQrgIF0Ixb6XxhcsGDsX8yVsRFqpbb8/iw+hWY5tjR2ZZoMkBsE7iw== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=c 8FXoUIvEWfGh5UlrrmZX/RCD5/r1RQd+Ff4HqRqQSM=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=XB/xo4kVEGUwx/QT4FvRAYDdr5EKqZcrNtgAw5IhBZ47fD+ReM431NVyVYnzYaz1JnTb OcndCieMYC9gTajDRLVR2SFIY4sY0SQvWzLcZGOqyV9qY/kmnbNSyOeqNbHAjxFz1RhfLF JY+jCS9MWkqltYcy3iyWiSdvD6GC7WPt5BI8tQzf7r7UWKMNwp2x7WwxTEQD/6R0oMS+G4 iajwhdwCFN1V1yAnlgWTGtvKoKOF9YRIpsdDZpiyUDJeFiNEW5hoOzHqZNZP0vzzbsc0Bz waWkkNGl3V46TldOd2rOGrn7XI9bhy+eBf3iA/wiYoKdv7ibCRieK8xooAGjGkPA== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=kbUcdUC9; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=k4UkbLsC; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=c8FXoUIv EWfGh5UlrrmZX/RCD5/r1RQd+Ff4HqRqQSM=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=kbUcdUC9tptVhccYbo8q5QtBq/6KiyvcOPC gsJJ0k/HD2xXm7bs4H3nYITFWFjMZ2VFfBqtddSrOmxLOiSmYU5mcgjusA/hxCeMCldatn wvdjxz7wcWP6GHZobD1eRwJ49GhfMzOpHHW6t8qJOe5fRAAgApXzI0XKJFJMPlfLEc5il3 ibpQc5L+VBMOUAhfPI23zaOd63abc3jewfz8Bd2SgSDH+pxQm8gbKzQ12ueNTDwbYaid0N 7XQELgi3MRNgNSCdmYAM7fun1AMdoawMSwA1XKyDOSTA2pkaKWlBdqPXjMAO07qB+DBUz8 ezBb/V3JLMfh4bPNQnOcDQeJlgQ== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=c8FXoUIvEWfGh5UlrrmZX/RCD5/r1RQd+Ff4HqRqQSM=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=k4UkbLsCfpts2OaOCN e+yyHAPdqCDv+XxksZdV1gN4Klf8lGVIBz4Dk3JJmOZfLK3EuIKzuSL0qMs0ijgZL6AQ== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 10/25] hw/mips: add Octeon reset controller Date: Wed, 15 Jul 2026 15:43:56 +0200 Message-ID: <20260715134447.56007-11-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f8:271:125e::2; envelope-from=kirill@korins.ky; helo=mx1.catap.net 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_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123179731158500 Content-Type: text/plain; charset="utf-8" Add the common resettable peripheral base and model the Octeon RST state used to hold secondary cores in reset. Create and realize the controller as part of the machine without exposing its CSR interface yet. --- hw/mips/octeon.c | 105 ++++++++++++++++++++++++++++++++++++++ hw/mips/octeon_internal.h | 2 + 2 files changed, 107 insertions(+) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 0e02d3693d..4fc5a71a90 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -29,6 +29,13 @@ #define TYPE_OCTEON_MACHINE MACHINE_TYPE_NAME("octeon3") OBJECT_DECLARE_SIMPLE_TYPE(OcteonMachineState, OCTEON_MACHINE) =20 +#define TYPE_OCTEON_PERIPHERAL "octeon-peripheral" +OBJECT_DECLARE_TYPE(OcteonPeripheralState, OcteonPeripheralClass, + OCTEON_PERIPHERAL) + +#define TYPE_OCTEON_RST "octeon-rst" +OBJECT_DECLARE_SIMPLE_TYPE(OcteonRstState, OCTEON_RST) + /* * Clock defaults follow a Ubiquiti E1000 EBB7304 U-Boot banner. * DDR follows the upstream EBB7304 U-Boot board default. @@ -85,6 +92,22 @@ struct OcteonMachineState { uint64_t ddr_hz; }; =20 +struct OcteonPeripheralState { + SysBusDevice parent_obj; + OcteonState *board; + unsigned int index; +}; + +struct OcteonPeripheralClass { + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; +}; + +struct OcteonRstState { + OcteonPeripheralState parent_obj; + uint64_t rst_pp_power; +}; + static void octeon_validate_clocks(OcteonMachineState *oms) { if (!oms->cpu_hz || !oms->ref_hz || !oms->io_hz || !oms->ddr_hz) { @@ -99,6 +122,16 @@ static void octeon_validate_clocks(OcteonMachineState *= oms) } } =20 +static uint64_t octeon_present_cpu_mask(OcteonState *s) +{ + return (1ULL << s->cpu_count) - 1; +} + +static uint64_t octeon_secondary_cpu_mask(OcteonState *s) +{ + return octeon_present_cpu_mask(s) & ~1ULL; +} + static void octeon_cpu_after_reset(OcteonCPUState *cs) { CPUMIPSState *env =3D &cs->cpu->env; @@ -303,6 +336,62 @@ static void octeon_init_flash(OcteonState *s) &s->boot_flash_alias); } =20 +static void octeon_rst_reset_hold(Object *obj, ResetType type) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); + OcteonRstState *rst =3D OCTEON_RST(obj); + + if (opc->parent_phases.hold) { + opc->parent_phases.hold(obj, type); + } + + rst->rst_pp_power =3D octeon_secondary_cpu_mask(rst->parent_obj.board); +} + +static void octeon_peripheral_class_init(ObjectClass *klass, + const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->user_creatable =3D false; +} + +static void octeon_rst_class_init(ObjectClass *klass, const void *data) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + resettable_class_set_parent_phases(rc, NULL, octeon_rst_reset_hold, + NULL, &opc->parent_phases); +} + +static OcteonPeripheralState *octeon_new_peripheral(OcteonState *s, + const char *type, + unsigned int index) +{ + DeviceState *qdev =3D qdev_new(type); + OcteonPeripheralState *dev =3D OCTEON_PERIPHERAL(qdev); + + dev->board =3D s; + dev->index =3D index; + return dev; +} + +static void octeon_create_peripherals(OcteonState *s) +{ + s->rst =3D OCTEON_RST(octeon_new_peripheral(s, TYPE_OCTEON_RST, 0)); +} + +static void octeon_realize_peripheral(OcteonPeripheralState *dev) +{ + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); +} + +static void octeon_realize_peripherals(OcteonState *s) +{ + octeon_realize_peripheral(&s->rst->parent_obj); +} + static void mips_octeon_init(MachineState *machine) { OcteonMachineState *oms =3D OCTEON_MACHINE(machine); @@ -316,6 +405,7 @@ static void mips_octeon_init(MachineState *machine) s->ref_hz =3D oms->ref_hz; s->io_hz =3D oms->io_hz; s->ddr_hz =3D oms->ddr_hz; + octeon_create_peripherals(s); =20 if (machine->kernel_filename) { error_report("-kernel is not implemented for octeon3; " @@ -328,6 +418,7 @@ static void mips_octeon_init(MachineState *machine) octeon_load_firmware(s); octeon_create_cpus(s); =20 + octeon_realize_peripherals(s); } =20 static void octeon_machine_reset(MachineState *machine, ResetType type) @@ -385,6 +476,20 @@ static void octeon_machine_class_init(ObjectClass *oc,= const void *data) } =20 static const TypeInfo octeon_machine_types[] =3D { + { + .name =3D TYPE_OCTEON_PERIPHERAL, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(OcteonPeripheralState), + .class_size =3D sizeof(OcteonPeripheralClass), + .class_init =3D octeon_peripheral_class_init, + .abstract =3D true, + }, + { + .name =3D TYPE_OCTEON_RST, + .parent =3D TYPE_OCTEON_PERIPHERAL, + .instance_size =3D sizeof(OcteonRstState), + .class_init =3D octeon_rst_class_init, + }, { .name =3D TYPE_OCTEON_MACHINE, .parent =3D TYPE_MACHINE, diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index 2e568c29ea..9c1baee292 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -15,6 +15,7 @@ =20 #define OCTEON_MAX_CPUS 16 typedef struct OcteonState OcteonState; +typedef struct OcteonRstState OcteonRstState; =20 typedef struct OcteonCPUState { OcteonState *board; @@ -39,6 +40,7 @@ struct OcteonState { MemoryRegion boot_flash; MemoryRegion boot_flash_alias; MemoryRegion cvmseg; + OcteonRstState *rst; }; =20 #endif --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123108937564.2798742294761; Wed, 15 Jul 2026 06:45:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv1-0005Wx-Sr; Wed, 15 Jul 2026 09:44:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzuz-0005W9-S8 for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:44:57 -0400 Received: from mx2.catap.net ([65.21.79.163]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzux-0007u1-DG for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:44:57 -0400 Received: by mx2.catap.net (OpenSMTPD) with ESMTPSA id f3081d79 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:52 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 745c94ab; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=jEn9RLY vuQfEAO2OByfsnpQzrSXFM5i1zDqBOqblSLU5yYlgoMuIR2Sn/aRypfsbSVoskfzhmhxZ5 lvv4N1JymXXiIMZVUp+Z3tWur9ocYhbMSw3GLlSWFETT8oApBhAyhplXg0x/JRnuqZA9dL KOOoM+TZKt8WvrGiwc2EKIGsSZj+vk4F8IR5GbsfYlBvjd/cDa5O99WoNR+5CiXXNAicF/ WGGuOCwgp/mh6HZZQ9Fr1zfLf+80fbKhS9T0tPgs3Ta88KxY3zVS2udQsLWYPoRMy9wAkJ FLCb9mGK1p+AuDSmWu7f37gKOqjCmlspEhItIiwkHEKl5jMgkgdVNqw== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=X F34/pBUEjG3G9aNLoQgzVKziu3LxBlE+nXDCywaBeQ=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=ZFZN7cLC//+7cp9xS19syPT52677DeWcku9MMdwSNKVGEx8fXndJIbcBpYyaexe5DMwX ElNKCvbHrVlonQ075nKjQ5YlNbr9hgPRMZ6GkmkpaelbnF5vXPCU5sxhX9OE/MUnaYYII0 C1v5EnXhY8RaNo+lVRt5v+2RmMROzLuJg2oC3jweUbGdvCHJDl7us7CGf0N22w7+icVD1c lIwr6lT5rPDYP9ecCWXZftvenXjI6OWn1RFRfnnfI6pwdc18CyVmg9jcLmVBqU68GOwiMN 90VPG7+M79jCp9cnhl0hIYYRrOyNplncd9gYRqvZ7KC2kVx15xCCefI+Ryi+5p1Q== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=t/9Qs9hZ; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=GQL+I2QL; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=XF34/pBU EjG3G9aNLoQgzVKziu3LxBlE+nXDCywaBeQ=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=t/9Qs9hZ6PpTjHeKAI/0fEP7Nu9q7pzRBVe JxD8Utpxnyiu3HP3twLfg77ixUF/VhOhxvwNFLOBjI4Iuj59c5AGd1N5ZG0+05PbPUt1UJ k9QOs+OAy8PAiRQuJa4OGA54sA7el3EOlwQ3ArosgLq6NpnoVY/wvi0NNzzx9YBwUoPcNd Iu4AYFgvOOZ5mZ5QXKalvhMof2y3VUzFiLyRLQPVqBgmdxgW5DfsX2x9SN69Lge0XBuO47 LfmELOrtyUO3PQZDer/TCmsuP7HaesSh6URAIYAHRcuB/sfELgoOsEekUr/DiTxR40NxQk /s97fTSrq5LgVhKEjpfzoxK9uaA== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=XF34/pBUEjG3G9aNLoQgzVKziu3LxBlE+nXDCywaBeQ=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=GQL+I2QL+obXAwaA0y zauQH6XGLtAgLxF6/zI9m3hFThWulOZ+a/xKwDsUfyWkq12QgUjrX7xXQzzRT1M5ZEDA== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 11/25] hw/mips: add Octeon CIU3 CPU control Date: Wed, 15 Jul 2026 15:43:57 +0200 Message-ID: <20260715134447.56007-12-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=65.21.79.163; envelope-from=kirill@korins.ky; helo=mx2.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123111338158500 Content-Type: text/plain; charset="utf-8" Model the CIU3 CPU reset, NMI and fuse registers. Park secondary cores after reset and release them through the CIU3 reset register or NMI path, while leaving interrupt source routing for a separate change. --- hw/mips/octeon.c | 247 +++++++++++++++++++++++++++++++++++++- hw/mips/octeon_internal.h | 6 + 2 files changed, 252 insertions(+), 1 deletion(-) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 4fc5a71a90..eeca7ca67e 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -20,9 +20,12 @@ #include "hw/mips/mips.h" #include "system/blockdev.h" #include "system/address-spaces.h" +#include "system/cpus.h" #include "system/memory.h" #include "system/reset.h" +#include "exec/cpu-interrupt.h" #include "qemu/error-report.h" +#include "qemu/atomic.h" #include "hw/mips/octeon_internal.h" #include "target/mips/cpu.h" =20 @@ -35,6 +38,10 @@ OBJECT_DECLARE_TYPE(OcteonPeripheralState, OcteonPeriphe= ralClass, =20 #define TYPE_OCTEON_RST "octeon-rst" OBJECT_DECLARE_SIMPLE_TYPE(OcteonRstState, OCTEON_RST) +#define TYPE_OCTEON_INTC "octeon-intc" +OBJECT_DECLARE_SIMPLE_TYPE(OcteonIntcState, OCTEON_INTC) + +#define OCTEON_CSR_64BIT_SIZE 8 =20 /* * Clock defaults follow a Ubiquiti E1000 EBB7304 U-Boot banner. @@ -61,6 +68,13 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonRstState, OCTEON_RST) #define OCTEON_DR1_BASE 0x020000000ULL #define OCTEON_DR1_SIZE (OCTEON_MAX_PHY_MEM_SIZE - OCTEON_DR0_= SIZE) =20 +#define OCTEON_CIU3_BASE 0x1010000000000ULL +#define OCTEON_CIU3_SIZE 0xb0000000ULL +#define OCTEON_CIU3_PP_RST 0x100 +#define OCTEON_CIU3_PP_RST_PENDING 0x110 +#define OCTEON_CIU3_NMI 0x160 +#define OCTEON_CIU3_FUSE 0x1a0 + /* * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; * the guest sees the virtual CVMSEG window, not this physical address. @@ -108,6 +122,59 @@ struct OcteonRstState { uint64_t rst_pp_power; }; =20 +struct OcteonIntcState { + OcteonPeripheralState parent_obj; + MemoryRegion ciu3; + uint64_t ciu3_pp_rst; +}; + +uint64_t octeon_read64(uint64_t value, hwaddr addr, unsigned size) +{ + if (size =3D=3D 4) { + if (addr & 4) { + return value & 0xffffffffU; + } + return value >> 32; + } + + return value; +} + +uint64_t octeon_write64(uint64_t old, hwaddr addr, + uint64_t value, unsigned size) +{ + if (size =3D=3D 4) { + if (addr & 4) { + return (old & 0xffffffff00000000ULL) | (value & 0xffffffffU); + } + return (old & 0xffffffffULL) | ((value & 0xffffffffU) << 32); + } + + return value; +} + +static uint64_t octeon_atomic_write64(uint64_t *ptr, hwaddr addr, + uint64_t value, unsigned size, + uint64_t and_mask, uint64_t or_mask, + uint64_t *oldp) +{ + uint64_t old; + uint64_t new; + uint64_t cmp =3D qatomic_read(ptr); + + do { + old =3D cmp; + new =3D (octeon_write64(old, addr, value, size) & and_mask) | or_m= ask; + cmp =3D qatomic_cmpxchg(ptr, old, new); + } while (old !=3D cmp); + + if (oldp) { + *oldp =3D old; + } + + return new; +} + static void octeon_validate_clocks(OcteonMachineState *oms) { if (!oms->cpu_hz || !oms->ref_hz || !oms->io_hz || !oms->ddr_hz) { @@ -132,6 +199,140 @@ static uint64_t octeon_secondary_cpu_mask(OcteonState= *s) return octeon_present_cpu_mask(s) & ~1ULL; } =20 +static void octeon_cpu_park_now(MIPSCPU *cpu) +{ + CPUMIPSState *env =3D &cpu->env; + CPUState *cs =3D CPU(cpu); + + env->active_tc.CP0_TCHalt =3D 1; + env->tcs[0].CP0_TCHalt =3D 1; + cs->halted =3D 1; + cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); +} + +static void octeon_cpu_park_work(CPUState *cs, run_on_cpu_data data) +{ + octeon_cpu_park_now(MIPS_CPU(cs)); +} + +static void octeon_cpu_start_work(CPUState *cs, run_on_cpu_data data) +{ + MIPSCPU *cpu =3D MIPS_CPU(cs); + CPUMIPSState *env =3D &cpu->env; + + cpu->mvp->CP0_MVPControl |=3D (1 << CP0MVPCo_EVP); + env->CP0_VPEConf0 |=3D (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); + env->active_tc.CP0_TCHalt =3D 0; + env->tcs[0].CP0_TCHalt =3D 0; + env->active_tc.CP0_TCStatus =3D (1 << CP0TCSt_A); + env->tcs[0].CP0_TCStatus =3D (1 << CP0TCSt_A); + env->active_tc.PC =3D cpu_mips_phys_to_kseg1(NULL, OCTEON_FLASH_RESET_= BASE); + cs->halted =3D 0; + cpu_interrupt(cs, CPU_INTERRUPT_WAKE | CPU_INTERRUPT_EXITTB); +} + +static void octeon_start_cpu(OcteonState *s, unsigned int cpu_index) +{ + MIPSCPU *cpu; + + if (cpu_index >=3D s->cpu_count || !s->cpu[cpu_index].cpu) { + return; + } + + cpu =3D s->cpu[cpu_index].cpu; + async_run_on_cpu(CPU(cpu), octeon_cpu_start_work, RUN_ON_CPU_NULL); +} + +static void octeon_ciu3_start_cpu(OcteonState *s, unsigned int cpu_index) +{ + if (qatomic_read(&s->intc->ciu3_pp_rst) & (1ULL << cpu_index)) { + return; + } + + octeon_start_cpu(s, cpu_index); +} + +static void octeon_ciu3_nmi(OcteonState *s, uint64_t mask) +{ + unsigned int cpu; + + for (cpu =3D 1; cpu < s->cpu_count; cpu++) { + if (mask & (1ULL << cpu)) { + octeon_ciu3_start_cpu(s, cpu); + } + } +} + +static uint64_t octeon_ciu3_read(void *opaque, hwaddr addr, unsigned size) +{ + OcteonState *s =3D opaque; + hwaddr reg =3D addr & ~7ULL; + uint64_t value; + + if (reg =3D=3D OCTEON_CIU3_PP_RST) { + return octeon_read64(qatomic_read(&s->intc->ciu3_pp_rst), addr, si= ze); + } + + if (reg =3D=3D OCTEON_CIU3_PP_RST_PENDING) { + return 0; + } + + if (reg =3D=3D OCTEON_CIU3_NMI) { + return 0; + } + + if (reg =3D=3D OCTEON_CIU3_FUSE) { + value =3D octeon_present_cpu_mask(s); + return octeon_read64(value, addr, size); + } + + return 0; +} + +static void octeon_ciu3_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonState *s =3D opaque; + hwaddr reg =3D addr & ~7ULL; + uint64_t old; + unsigned int cpu; + + if (reg =3D=3D OCTEON_CIU3_PP_RST) { + value =3D octeon_atomic_write64(&s->intc->ciu3_pp_rst, addr, value= , size, + octeon_present_cpu_mask(s), 0, &old); + + for (cpu =3D 1; cpu < s->cpu_count; cpu++) { + uint64_t mask =3D 1ULL << cpu; + + if (!((old ^ value) & mask)) { + continue; + } + if (value & mask) { + async_run_on_cpu(CPU(s->cpu[cpu].cpu), octeon_cpu_park_wor= k, + RUN_ON_CPU_NULL); + } else { + octeon_ciu3_start_cpu(s, cpu); + } + } + return; + } + + if (reg =3D=3D OCTEON_CIU3_NMI) { + octeon_ciu3_nmi(s, octeon_write64(0, addr, value, size)); + return; + } +} + +static const MemoryRegionOps octeon_ciu3_ops =3D { + .read =3D octeon_ciu3_read, + .write =3D octeon_ciu3_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + static void octeon_cpu_after_reset(OcteonCPUState *cs) { CPUMIPSState *env =3D &cs->cpu->env; @@ -139,7 +340,13 @@ static void octeon_cpu_after_reset(OcteonCPUState *cs) env->CP0_CvmMemCtl =3D 0x100; env->CP0_CvmCtl =3D 0; =20 - if (cs->boot_cpu && cs->board->firmware_entry) { + if (!cs->boot_cpu) { + /* Secondary cores are released by the Octeon reset controller. */ + octeon_cpu_park_now(cs->cpu); + return; + } + + if (cs->board->firmware_entry) { env->active_tc.PC =3D cs->board->firmware_entry; } } @@ -151,6 +358,8 @@ static void octeon_create_cpus(OcteonState *s) s->cpuclk =3D clock_new(OBJECT(s->machine), "cpu-refclk"); clock_set_hz(s->cpuclk, s->cpu_hz); s->cpu_count =3D s->machine->smp.cpus; + qatomic_set(&s->intc->ciu3_pp_rst, octeon_secondary_cpu_mask(s)); + for (i =3D 0; i < s->cpu_count; i++) { DeviceState *dev =3D qdev_new(s->machine->cpu_type); =20 @@ -348,6 +557,19 @@ static void octeon_rst_reset_hold(Object *obj, ResetTy= pe type) rst->rst_pp_power =3D octeon_secondary_cpu_mask(rst->parent_obj.board); } =20 +static void octeon_intc_reset_hold(Object *obj, ResetType type) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); + OcteonIntcState *intc =3D OCTEON_INTC(obj); + OcteonState *s =3D intc->parent_obj.board; + + if (opc->parent_phases.hold) { + opc->parent_phases.hold(obj, type); + } + + qatomic_set(&intc->ciu3_pp_rst, octeon_secondary_cpu_mask(s)); +} + static void octeon_peripheral_class_init(ObjectClass *klass, const void *data) { @@ -365,6 +587,15 @@ static void octeon_rst_class_init(ObjectClass *klass, = const void *data) NULL, &opc->parent_phases); } =20 +static void octeon_intc_class_init(ObjectClass *klass, const void *data) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + resettable_class_set_parent_phases(rc, NULL, octeon_intc_reset_hold, + NULL, &opc->parent_phases); +} + static OcteonPeripheralState *octeon_new_peripheral(OcteonState *s, const char *type, unsigned int index) @@ -380,6 +611,7 @@ static OcteonPeripheralState *octeon_new_peripheral(Oct= eonState *s, static void octeon_create_peripherals(OcteonState *s) { s->rst =3D OCTEON_RST(octeon_new_peripheral(s, TYPE_OCTEON_RST, 0)); + s->intc =3D OCTEON_INTC(octeon_new_peripheral(s, TYPE_OCTEON_INTC, 0)); } =20 static void octeon_realize_peripheral(OcteonPeripheralState *dev) @@ -389,6 +621,7 @@ static void octeon_realize_peripheral(OcteonPeripheralS= tate *dev) =20 static void octeon_realize_peripherals(OcteonState *s) { + octeon_realize_peripheral(&s->intc->parent_obj); octeon_realize_peripheral(&s->rst->parent_obj); } =20 @@ -418,6 +651,12 @@ static void mips_octeon_init(MachineState *machine) octeon_load_firmware(s); octeon_create_cpus(s); =20 + memory_region_init_io(&s->intc->ciu3, OBJECT(s->intc), + &octeon_ciu3_ops, s, + "octeon.ciu3", OCTEON_CIU3_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_CIU3_BASE, + &s->intc->ciu3); + octeon_realize_peripherals(s); } =20 @@ -490,6 +729,12 @@ static const TypeInfo octeon_machine_types[] =3D { .instance_size =3D sizeof(OcteonRstState), .class_init =3D octeon_rst_class_init, }, + { + .name =3D TYPE_OCTEON_INTC, + .parent =3D TYPE_OCTEON_PERIPHERAL, + .instance_size =3D sizeof(OcteonIntcState), + .class_init =3D octeon_intc_class_init, + }, { .name =3D TYPE_OCTEON_MACHINE, .parent =3D TYPE_MACHINE, diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index 9c1baee292..884eed8994 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -16,6 +16,7 @@ #define OCTEON_MAX_CPUS 16 typedef struct OcteonState OcteonState; typedef struct OcteonRstState OcteonRstState; +typedef struct OcteonIntcState OcteonIntcState; =20 typedef struct OcteonCPUState { OcteonState *board; @@ -41,6 +42,11 @@ struct OcteonState { MemoryRegion boot_flash_alias; MemoryRegion cvmseg; OcteonRstState *rst; + OcteonIntcState *intc; }; =20 +uint64_t octeon_read64(uint64_t value, hwaddr addr, unsigned size); +uint64_t octeon_write64(uint64_t old, hwaddr addr, + uint64_t value, unsigned size); + #endif --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178412317186431.051962117343464; Wed, 15 Jul 2026 06:46:11 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv9-0005cO-C3; Wed, 15 Jul 2026 09:45:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv2-0005XS-NN for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:00 -0400 Received: from mx2.catap.net ([2a01:4f9:3b:5410::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzuz-0007uL-Sw for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:00 -0400 Received: by mx2.catap.net (OpenSMTPD) with ESMTPSA id 57ce568f (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:53 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id a95b5257; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=vP5+dSX 8DfLpZ3MszfBsPgnwxmkDE7XWEfsCjY4bIlvdC/2L++SKGIhGiwUX5t0fFMnjlJ6bhaXrJ +XzVQ8tQ5iMiCvMWhxQ7epNIOn1s0HmRssDF2+y71ojvR9o/6b/u3eJwzpmhDvE7HsQ9uY JXHBYWm8Rh5fzk133Sfs2yrvZVCSR+eaEFc5QE43O/sPMBFC7II78vJ4iBnc4d7XElhEqm 5JDN8o5KZ3eC0zEIp6NJptqF8cI4PGPQQj8Hyy5kNlFuzUR2QKvoXiu5AsBeFBirVwLPiy sANW0aSMU0X95fCoUkD/s0LH/hfzsiL68i08YHz+5jFjzgqTAisI05w== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=Z E1iANrwE19UyO5KuxTGON1ip8EfBfPXWbIE+cgJkhU=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=UzNhwEOpUQ8jY3I1YafGPOl93lR2aOBMQVTk0BN+ao6bBufrYRPa7k8HMKa7fQ42+JXF rfFZi6qy6UPYYsGHhLYlMmndQ9svHqAk9anKCNxljjX6vg8SD7CsJ6cbzVtmyWhKk2xIB0 g/KYHKFS9R9VM7ZgGT0L6O85Rt3DQHQkT9s5Bc7MAMG90oQ/hQFRByZOjwRXPwBM71zQY+ 7G0bfyTsaCcRkhaZU0M8vyfcdOtsDBpAGVfJrOlmmLTbukS+qHiqa4oK5qKKiDJD9YN+gx dBJK6h8SdlzFJMILpJxgW5C8mh3im2BIxxfWXuyjvFutmCrqpxCvwX9xY4ykwpmA== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=YnVwuzRF; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=udZUS15p; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=ZE1iANrw E19UyO5KuxTGON1ip8EfBfPXWbIE+cgJkhU=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=YnVwuzRFhYoydLIg/3s35gISo18R+2iw3II pBSgdrAi5yz9NcsBmi1PKRGUOe0CzTRVNpYDMSHa1eBpc+x+HYL//j01PwBKL5jL7rjhM8 RmY5InblNC5R67OS0rTvudfpU4WZXT5et5v1y80V6uV7vXvMSIR43IkiVBvSSBkqK1RNw6 n5U7L4mTs5U9+6W9Im3KksmuGpIXmAYajJH59eFfM6Vc2ZFGevx//VLryQAzY6wyIUNwWA W4rGsH/pGNxf6d3uuWmwpN4ZSZ9mZ2Ip7ybCo+AcaHByGmzXUWevK/xMabq8Dmfid0Li++ sbAHk0kFm1DFk99OHPEIBMJPWOA== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=ZE1iANrwE19UyO5KuxTGON1ip8EfBfPXWbIE+cgJkhU=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=udZUS15ptMSuvv9huD LIrFCfhUnYRck7cSpDW5k+OdOFU8EIB9Ndc9gI/V052a7Em5mgPof0y8MiREmDY2KSDA== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 12/25] hw/mips: add Octeon CIU3 interrupt routing Date: Wed, 15 Jul 2026 15:43:58 +0200 Message-ID: <20260715134447.56007-13-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f9:3b:5410::2; envelope-from=kirill@korins.ky; helo=mx2.catap.net 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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123173791158501 Content-Type: text/plain; charset="utf-8" Model CIU3 interrupt sources, ISC and IDT registers, destination selection and CP0 interrupt delivery. Route UART and mailbox sources through CIU3 while keeping the legacy CIU register block separate. --- hw/mips/octeon.c | 483 ++++++++++++++++++++++++++++++++++++++ hw/mips/octeon_internal.h | 15 ++ 2 files changed, 498 insertions(+) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index eeca7ca67e..567be0905a 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -11,6 +11,7 @@ #include "qemu/datadir.h" #include "qapi/error.h" #include "hw/core/clock.h" +#include "hw/core/irq.h" #include "hw/core/boards.h" #include "hw/core/qdev-clock.h" #include "hw/core/qdev-properties.h" @@ -74,6 +75,28 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonIntcState, OCTEON_INTC) #define OCTEON_CIU3_PP_RST_PENDING 0x110 #define OCTEON_CIU3_NMI 0x160 #define OCTEON_CIU3_FUSE 0x1a0 +#define OCTEON_CIU3_IDT_CTL(idt) ((idt) * 8 + 0x110000U) +#define OCTEON_CIU3_IDT_PP(idt) ((idt) * 32 + 0x120000U) +#define OCTEON_CIU3_IDT_IO(idt) ((idt) * 8 + 0x130000U) +#define OCTEON_CIU3_DEST_PP_INT(cpu) ((cpu) * 8 + 0x200000U) +#define OCTEON_CIU3_DEST_PP_INT_INTSN_SHIFT 32 +#define OCTEON_CIU3_DEST_PP_INT_INTR 0x0000000000000001ULL +#define OCTEON_CIU3_IDT_CTL_IP_NUM 0x7 +#define OCTEON_CIU3_CP0_IRQ_BASE 2 +#define OCTEON_CIU3_ISC_CTL_BASE 0x80000000U +#define OCTEON_CIU3_ISC_W1C_BASE 0x90000000U +#define OCTEON_CIU3_ISC_W1S_BASE 0xa0000000U +#define OCTEON_CIU3_ISC_CTL_IDT 0x0000000000ff0000ULL +#define OCTEON_CIU3_ISC_CTL_IDT_SHIFT 16 +#define OCTEON_CIU3_ISC_CTL_IMP 0x0000000000008000ULL +#define OCTEON_CIU3_ISC_CTL_EN 0x0000000000000002ULL +#define OCTEON_CIU3_ISC_CTL_RAW 0x0000000000000001ULL +#define OCTEON_CIU3_SRC_LEVEL 0x00000001U +#define OCTEON_CIU3_SRC_RAW 0x00000002U +#define OCTEON_CIU3_NINTSN (1U << 20) +#define OCTEON_CIU3_ISC_SIZE (OCTEON_CIU3_NINTSN * 8) +#define OCTEON_CIU3_MBOX_INTSN(cpu) ((cpu) + 0x4000U) +#define OCTEON_CIU3_UART0_INTSN 0x8000 =20 /* * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; @@ -126,6 +149,13 @@ struct OcteonIntcState { OcteonPeripheralState parent_obj; MemoryRegion ciu3; uint64_t ciu3_pp_rst; + uint32_t ciu3_src_state[OCTEON_CIU3_SRC_COUNT]; + uint64_t ciu3_src_ctl[OCTEON_CIU3_SRC_COUNT]; + uint64_t ciu3_idt_ctl[OCTEON_CIU3_IDT_COUNT]; + uint64_t ciu3_idt_pp[OCTEON_CIU3_IDT_COUNT]; + uint64_t ciu3_idt_io[OCTEON_CIU3_IDT_COUNT]; + uint16_t ciu3_src_cursor[OCTEON_MAX_CPUS][OCTEON_CIU3_CP0_IRQ_COUNT]; + uint8_t ciu3_irq_line[OCTEON_MAX_CPUS][OCTEON_CIU3_CP0_IRQ_COUNT]; }; =20 uint64_t octeon_read64(uint64_t value, hwaddr addr, unsigned size) @@ -189,6 +219,286 @@ static void octeon_validate_clocks(OcteonMachineState= *oms) } } =20 +static bool octeon_ciu3_source_from_intsn(uint32_t intsn, + unsigned int *source) +{ + if (intsn =3D=3D OCTEON_CIU3_UART0_INTSN) { + *source =3D OCTEON_CIU3_SRC_UART0; + return true; + } + if (intsn >=3D OCTEON_CIU3_MBOX_INTSN(0) && + intsn < OCTEON_CIU3_MBOX_INTSN(OCTEON_MAX_CPUS)) { + *source =3D OCTEON_CIU3_SRC_MBOX0 + + intsn - OCTEON_CIU3_MBOX_INTSN(0); + return true; + } + + return false; +} + +static uint32_t octeon_ciu3_source_intsn(unsigned int source) +{ + switch (source) { + case OCTEON_CIU3_SRC_UART0: + return OCTEON_CIU3_UART0_INTSN; + } + + if (source >=3D OCTEON_CIU3_SRC_MBOX0 && + source < OCTEON_CIU3_SRC_COUNT) { + return OCTEON_CIU3_MBOX_INTSN(source - OCTEON_CIU3_SRC_MBOX0); + } + + g_assert_not_reached(); +} + +static bool octeon_ciu3_source_is_level(unsigned int source) +{ + switch (source) { + case OCTEON_CIU3_SRC_UART0: + return true; + } + + return false; +} + +static bool octeon_ciu3_set_level(OcteonState *s, unsigned int source, + int level) +{ + uint32_t old; + uint32_t new; + uint32_t cmp =3D qatomic_read(&s->intc->ciu3_src_state[source]); + + do { + old =3D cmp; + if (level) { + new =3D old | OCTEON_CIU3_SRC_LEVEL | OCTEON_CIU3_SRC_RAW; + } else { + new =3D old & ~(OCTEON_CIU3_SRC_LEVEL | OCTEON_CIU3_SRC_RAW); + } + if (new =3D=3D old) { + return false; + } + cmp =3D qatomic_cmpxchg(&s->intc->ciu3_src_state[source], old, new= ); + } while (old !=3D cmp); + + return true; +} + +static void octeon_ciu3_clear_raw(OcteonState *s, unsigned int source) +{ + uint32_t old; + uint32_t new; + uint32_t cmp =3D qatomic_read(&s->intc->ciu3_src_state[source]); + + do { + old =3D cmp; + if (octeon_ciu3_source_is_level(source) && + (old & OCTEON_CIU3_SRC_LEVEL)) { + new =3D old | OCTEON_CIU3_SRC_RAW; + } else { + new =3D old & ~OCTEON_CIU3_SRC_RAW; + } + if (new =3D=3D old) { + return; + } + cmp =3D qatomic_cmpxchg(&s->intc->ciu3_src_state[source], old, new= ); + } while (old !=3D cmp); +} + +static bool octeon_ciu3_isc_decode(hwaddr reg, uint32_t base, + uint32_t *intsn) +{ + if (reg < base || reg >=3D base + OCTEON_CIU3_ISC_SIZE) { + return false; + } + + *intsn =3D (reg - base) >> 3; + return true; +} + +static uint64_t octeon_ciu3_isc_read(OcteonState *s, uint32_t intsn) +{ + unsigned int src; + uint64_t value; + + if (!octeon_ciu3_source_from_intsn(intsn, &src)) { + return 0; + } + + value =3D qatomic_read(&s->intc->ciu3_src_ctl[src]) | OCTEON_CIU3_ISC_= CTL_IMP; + if (qatomic_read(&s->intc->ciu3_src_state[src]) & OCTEON_CIU3_SRC_RAW)= { + value |=3D OCTEON_CIU3_ISC_CTL_RAW; + } + return value; +} + +static bool octeon_ciu3_source_pending(OcteonState *s, unsigned int cpu_in= dex, + unsigned int irq, unsigned int src) +{ + uint64_t ctl =3D qatomic_read(&s->intc->ciu3_src_ctl[src]); + unsigned int idt; + unsigned int output; + + if (!(qatomic_read(&s->intc->ciu3_src_state[src]) & OCTEON_CIU3_SRC_RA= W) || + !(ctl & OCTEON_CIU3_ISC_CTL_EN)) { + return false; + } + + idt =3D (ctl & OCTEON_CIU3_ISC_CTL_IDT) >> + OCTEON_CIU3_ISC_CTL_IDT_SHIFT; + if (idt >=3D OCTEON_CIU3_IDT_COUNT) { + return false; + } + + output =3D qatomic_read(&s->intc->ciu3_idt_ctl[idt]) & + OCTEON_CIU3_IDT_CTL_IP_NUM; + if (output >=3D OCTEON_CIU3_CP0_IRQ_COUNT || + irq !=3D OCTEON_CIU3_CP0_IRQ_BASE + output) { + return false; + } + + return qatomic_read(&s->intc->ciu3_idt_pp[idt]) & (1ULL << cpu_index); +} + +static bool octeon_ciu3_pending_intsn(OcteonState *s, unsigned int cpu_ind= ex, + unsigned int irq, uint32_t *intsn) +{ + unsigned int src; + + for (src =3D 0; src < OCTEON_CIU3_SRC_COUNT; src++) { + if (octeon_ciu3_source_pending(s, cpu_index, irq, src)) { + *intsn =3D octeon_ciu3_source_intsn(src); + return true; + } + } + + return false; +} + +static bool octeon_ciu3_pending_intsn_from(OcteonState *s, + unsigned int cpu_index, + unsigned int irq, + unsigned int first_src, + uint32_t *intsn, + unsigned int *source) +{ + unsigned int i; + unsigned int src; + + for (i =3D 0; i < OCTEON_CIU3_SRC_COUNT; i++) { + src =3D (first_src + i) % OCTEON_CIU3_SRC_COUNT; + if (octeon_ciu3_source_pending(s, cpu_index, irq, src)) { + *intsn =3D octeon_ciu3_source_intsn(src); + *source =3D src; + return true; + } + } + + return false; +} + +static bool octeon_ciu3_pending_dest_intsn(OcteonState *s, + unsigned int cpu_index, + uint32_t *intsn) +{ + unsigned int irq; + unsigned int irq_index; + unsigned int src; + + for (irq =3D OCTEON_CIU3_CP0_IRQ_BASE; + irq < OCTEON_CIU3_CP0_IRQ_BASE + OCTEON_CIU3_CP0_IRQ_COUNT; + irq++) { + irq_index =3D irq - OCTEON_CIU3_CP0_IRQ_BASE; + if (octeon_ciu3_pending_intsn_from(s, cpu_index, irq, + qatomic_read(&s->intc->ciu3_src_cursor[cpu_index][irq_inde= x]), + intsn, &src)) { + qatomic_set(&s->intc->ciu3_src_cursor[cpu_index][irq_index], + (src + 1) % OCTEON_CIU3_SRC_COUNT); + return true; + } + } + + return false; +} + +static void octeon_ciu3_set_cpu_irq(OcteonState *s, unsigned int cpu_index, + unsigned int irq, bool level) +{ + CPUMIPSState *env =3D &s->cpu[cpu_index].cpu->env; + unsigned int irq_index =3D irq - OCTEON_CIU3_CP0_IRQ_BASE; + uint8_t new_level =3D level; + uint8_t old_level; + + old_level =3D qatomic_xchg(&s->intc->ciu3_irq_line[cpu_index][irq_inde= x], + new_level); + if (old_level =3D=3D new_level) { + return; + } + + qemu_set_irq(env->irq[irq], level); +} + +static void octeon_intc_update_cpu(OcteonState *s, unsigned int cpu_index) +{ + uint32_t intsn; + unsigned int irq; + bool level; + + if (cpu_index >=3D s->cpu_count || !s->cpu[cpu_index].cpu) { + return; + } + + if (qatomic_read(&s->intc->ciu3_pp_rst) & (1ULL << cpu_index)) { + for (irq =3D OCTEON_CIU3_CP0_IRQ_BASE; + irq < OCTEON_CIU3_CP0_IRQ_BASE + OCTEON_CIU3_CP0_IRQ_COUNT; + irq++) { + octeon_ciu3_set_cpu_irq(s, cpu_index, irq, false); + } + return; + } + + for (irq =3D OCTEON_CIU3_CP0_IRQ_BASE; + irq < OCTEON_CIU3_CP0_IRQ_BASE + OCTEON_CIU3_CP0_IRQ_COUNT; + irq++) { + level =3D false; + if (octeon_ciu3_pending_intsn(s, cpu_index, irq, &intsn)) { + level =3D true; + } + + octeon_ciu3_set_cpu_irq(s, cpu_index, irq, level); + } +} + +static void octeon_intc_request_cpu_update(OcteonState *s, + unsigned int cpu_index) +{ + if (cpu_index >=3D s->cpu_count || !s->cpu[cpu_index].cpu) { + return; + } + + octeon_intc_update_cpu(s, cpu_index); +} + +static void octeon_intc_update_cpu_mask(OcteonState *s, uint64_t cpu_mask) +{ + unsigned int cpu; + + for (cpu =3D 0; cpu < s->cpu_count; cpu++) { + if (cpu_mask & (1ULL << cpu)) { + octeon_intc_request_cpu_update(s, cpu); + } + } +} + +static void octeon_intc_update_all_cpus(OcteonState *s) +{ + unsigned int cpu; + + for (cpu =3D 0; cpu < s->cpu_count; cpu++) { + octeon_intc_request_cpu_update(s, cpu); + } +} + static uint64_t octeon_present_cpu_mask(OcteonState *s) { return (1ULL << s->cpu_count) - 1; @@ -199,6 +509,24 @@ static uint64_t octeon_secondary_cpu_mask(OcteonState = *s) return octeon_present_cpu_mask(s) & ~1ULL; } =20 +static uint64_t octeon_ciu3_ctl_cpu_mask(OcteonState *s, uint64_t ctl) +{ + unsigned int idt =3D (ctl & OCTEON_CIU3_ISC_CTL_IDT) >> + OCTEON_CIU3_ISC_CTL_IDT_SHIFT; + + if (idt >=3D OCTEON_CIU3_IDT_COUNT) { + return 0; + } + + return qatomic_read(&s->intc->ciu3_idt_pp[idt]); +} + +static uint64_t octeon_ciu3_source_cpu_mask(OcteonState *s, unsigned int s= rc) +{ + return octeon_ciu3_ctl_cpu_mask( + s, qatomic_read(&s->intc->ciu3_src_ctl[src])); +} + static void octeon_cpu_park_now(MIPSCPU *cpu) { CPUMIPSState *env =3D &cpu->env; @@ -268,6 +596,9 @@ static uint64_t octeon_ciu3_read(void *opaque, hwaddr a= ddr, unsigned size) OcteonState *s =3D opaque; hwaddr reg =3D addr & ~7ULL; uint64_t value; + uint32_t intsn; + unsigned int cpu; + unsigned int idt; =20 if (reg =3D=3D OCTEON_CIU3_PP_RST) { return octeon_read64(qatomic_read(&s->intc->ciu3_pp_rst), addr, si= ze); @@ -286,6 +617,51 @@ static uint64_t octeon_ciu3_read(void *opaque, hwaddr = addr, unsigned size) return octeon_read64(value, addr, size); } =20 + if (reg >=3D OCTEON_CIU3_IDT_CTL(0) && + reg < OCTEON_CIU3_IDT_CTL(OCTEON_CIU3_IDT_COUNT)) { + idt =3D (reg - OCTEON_CIU3_IDT_CTL(0)) >> 3; + return octeon_read64(qatomic_read(&s->intc->ciu3_idt_ctl[idt]), + addr, size); + } + + if (reg >=3D OCTEON_CIU3_IDT_PP(0) && + reg < OCTEON_CIU3_IDT_PP(OCTEON_CIU3_IDT_COUNT)) { + idt =3D (reg - OCTEON_CIU3_IDT_PP(0)) >> 5; + return octeon_read64(qatomic_read(&s->intc->ciu3_idt_pp[idt]), + addr, size); + } + + if (reg >=3D OCTEON_CIU3_IDT_IO(0) && + reg < OCTEON_CIU3_IDT_IO(OCTEON_CIU3_IDT_COUNT)) { + idt =3D (reg - OCTEON_CIU3_IDT_IO(0)) >> 3; + return octeon_read64(qatomic_read(&s->intc->ciu3_idt_io[idt]), + addr, size); + } + + if (reg >=3D OCTEON_CIU3_DEST_PP_INT(0) && + reg < OCTEON_CIU3_DEST_PP_INT(OCTEON_MAX_CPUS)) { + cpu =3D (reg - OCTEON_CIU3_DEST_PP_INT(0)) >> 3; + value =3D 0; + if (cpu < s->cpu_count) { + if (!(qatomic_read(&s->intc->ciu3_pp_rst) & (1ULL << cpu)) && + octeon_ciu3_pending_dest_intsn(s, cpu, &intsn)) { + value =3D OCTEON_CIU3_DEST_PP_INT_INTR | + ((uint64_t)intsn << + OCTEON_CIU3_DEST_PP_INT_INTSN_SHIFT); + } + } + return octeon_read64(value, addr, size); + } + + if (octeon_ciu3_isc_decode(reg, OCTEON_CIU3_ISC_CTL_BASE, &intsn)) { + return octeon_read64(octeon_ciu3_isc_read(s, intsn), addr, size); + } + + if (octeon_ciu3_isc_decode(reg, OCTEON_CIU3_ISC_W1C_BASE, &intsn) || + octeon_ciu3_isc_decode(reg, OCTEON_CIU3_ISC_W1S_BASE, &intsn)) { + return octeon_read64(octeon_ciu3_isc_read(s, intsn), addr, size); + } + return 0; } =20 @@ -295,7 +671,10 @@ static void octeon_ciu3_write(void *opaque, hwaddr add= r, OcteonState *s =3D opaque; hwaddr reg =3D addr & ~7ULL; uint64_t old; + uint32_t intsn; unsigned int cpu; + unsigned int idt; + unsigned int src; =20 if (reg =3D=3D OCTEON_CIU3_PP_RST) { value =3D octeon_atomic_write64(&s->intc->ciu3_pp_rst, addr, value= , size, @@ -314,13 +693,89 @@ static void octeon_ciu3_write(void *opaque, hwaddr ad= dr, octeon_ciu3_start_cpu(s, cpu); } } + octeon_intc_update_all_cpus(s); return; } =20 if (reg =3D=3D OCTEON_CIU3_NMI) { octeon_ciu3_nmi(s, octeon_write64(0, addr, value, size)); + octeon_intc_update_all_cpus(s); + return; + } + + if (reg >=3D OCTEON_CIU3_IDT_CTL(0) && + reg < OCTEON_CIU3_IDT_CTL(OCTEON_CIU3_IDT_COUNT)) { + idt =3D (reg - OCTEON_CIU3_IDT_CTL(0)) >> 3; + octeon_atomic_write64(&s->intc->ciu3_idt_ctl[idt], addr, value, si= ze, + UINT64_MAX, 0, NULL); + octeon_intc_update_cpu_mask( + s, qatomic_read(&s->intc->ciu3_idt_pp[idt])); + return; + } + + if (reg >=3D OCTEON_CIU3_IDT_PP(0) && + reg < OCTEON_CIU3_IDT_PP(OCTEON_CIU3_IDT_COUNT)) { + idt =3D (reg - OCTEON_CIU3_IDT_PP(0)) >> 5; + value =3D octeon_atomic_write64(&s->intc->ciu3_idt_pp[idt], addr, = value, + size, UINT64_MAX, 0, &old); + octeon_intc_update_cpu_mask(s, old | value); + return; + } + + if (reg >=3D OCTEON_CIU3_IDT_IO(0) && + reg < OCTEON_CIU3_IDT_IO(OCTEON_CIU3_IDT_COUNT)) { + idt =3D (reg - OCTEON_CIU3_IDT_IO(0)) >> 3; + octeon_atomic_write64(&s->intc->ciu3_idt_io[idt], addr, value, siz= e, + UINT64_MAX, 0, NULL); + octeon_intc_update_cpu_mask( + s, qatomic_read(&s->intc->ciu3_idt_pp[idt])); + return; + } + + if (octeon_ciu3_isc_decode(reg, OCTEON_CIU3_ISC_CTL_BASE, &intsn)) { + if (octeon_ciu3_source_from_intsn(intsn, &src)) { + value =3D octeon_atomic_write64(&s->intc->ciu3_src_ctl[src], a= ddr, + value, size, + ~OCTEON_CIU3_ISC_CTL_RAW, + 0, &old); + octeon_intc_update_cpu_mask(s, + octeon_ciu3_ctl_cpu_mask(s, old) | + octeon_ciu3_ctl_cpu_mask(s, value)= ); + } + return; + } + + if (octeon_ciu3_isc_decode(reg, OCTEON_CIU3_ISC_W1C_BASE, &intsn)) { + if (octeon_ciu3_source_from_intsn(intsn, &src)) { + old =3D qatomic_read(&s->intc->ciu3_src_ctl[src]); + if (value & OCTEON_CIU3_ISC_CTL_EN) { + qatomic_and(&s->intc->ciu3_src_ctl[src], + ~OCTEON_CIU3_ISC_CTL_EN); + } + if (value & OCTEON_CIU3_ISC_CTL_RAW) { + octeon_ciu3_clear_raw(s, src); + } + octeon_intc_update_cpu_mask(s, + octeon_ciu3_ctl_cpu_mask(s, old) | + octeon_ciu3_source_cpu_mask(s, src= )); + } return; } + + if (octeon_ciu3_isc_decode(reg, OCTEON_CIU3_ISC_W1S_BASE, &intsn)) { + if (octeon_ciu3_source_from_intsn(intsn, &src)) { + old =3D qatomic_read(&s->intc->ciu3_src_ctl[src]); + if (value & OCTEON_CIU3_ISC_CTL_EN) { + qatomic_or(&s->intc->ciu3_src_ctl[src], OCTEON_CIU3_ISC_CT= L_EN); + } + if (value & OCTEON_CIU3_ISC_CTL_RAW) { + qatomic_or(&s->intc->ciu3_src_state[src], OCTEON_CIU3_SRC_= RAW); + } + octeon_intc_update_cpu_mask(s, + octeon_ciu3_ctl_cpu_mask(s, old) | + octeon_ciu3_source_cpu_mask(s, src= )); + } + } } =20 static const MemoryRegionOps octeon_ciu3_ops =3D { @@ -333,6 +788,26 @@ static const MemoryRegionOps octeon_ciu3_ops =3D { }, }; =20 +void octeon_irq_set(void *opaque, int irq, int level) +{ + OcteonState *s =3D opaque; + unsigned int src; + + switch (irq) { + case OCTEON_IRQ_UART: + src =3D OCTEON_CIU3_SRC_UART0; + if (!octeon_ciu3_set_level(s, src, level)) { + return; + } + break; + default: + return; + } + + octeon_intc_update_cpu_mask(s, octeon_ciu3_source_cpu_mask(s, src)); +} + + static void octeon_cpu_after_reset(OcteonCPUState *cs) { CPUMIPSState *env =3D &cs->cpu->env; @@ -568,6 +1043,14 @@ static void octeon_intc_reset_hold(Object *obj, Reset= Type type) } =20 qatomic_set(&intc->ciu3_pp_rst, octeon_secondary_cpu_mask(s)); + memset(intc->ciu3_src_state, 0, sizeof(intc->ciu3_src_state)); + memset(intc->ciu3_src_ctl, 0, sizeof(intc->ciu3_src_ctl)); + memset(intc->ciu3_idt_ctl, 0, sizeof(intc->ciu3_idt_ctl)); + memset(intc->ciu3_idt_pp, 0, sizeof(intc->ciu3_idt_pp)); + memset(intc->ciu3_idt_io, 0, sizeof(intc->ciu3_idt_io)); + memset(intc->ciu3_src_cursor, 0, sizeof(intc->ciu3_src_cursor)); + memset(intc->ciu3_irq_line, 0, sizeof(intc->ciu3_irq_line)); + octeon_intc_update_all_cpus(s); } =20 static void octeon_peripheral_class_init(ObjectClass *klass, diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index 884eed8994..fef88419b5 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -14,6 +14,20 @@ #include "target/mips/cpu.h" =20 #define OCTEON_MAX_CPUS 16 +#define OCTEON_CIU3_CP0_IRQ_COUNT 4 +#define OCTEON_CIU3_IDT_COUNT (OCTEON_MAX_CPUS * 4) + +typedef enum OcteonIRQ { + OCTEON_IRQ_UART, + OCTEON_IRQ_COUNT, +} OcteonIRQ; + +typedef enum OcteonCiu3Source { + OCTEON_CIU3_SRC_UART0, + OCTEON_CIU3_SRC_MBOX0, + OCTEON_CIU3_SRC_COUNT =3D OCTEON_CIU3_SRC_MBOX0 + OCTEON_MAX_CPUS, +} OcteonCiu3Source; + typedef struct OcteonState OcteonState; typedef struct OcteonRstState OcteonRstState; typedef struct OcteonIntcState OcteonIntcState; @@ -48,5 +62,6 @@ struct OcteonState { uint64_t octeon_read64(uint64_t value, hwaddr addr, unsigned size); uint64_t octeon_write64(uint64_t old, hwaddr addr, uint64_t value, unsigned size); +void octeon_irq_set(void *opaque, int irq, int level); =20 #endif --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123306033723.3568102099147; Wed, 15 Jul 2026 06:48:26 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvE-0005kT-D8; Wed, 15 Jul 2026 09:45:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv7-0005b3-Uu for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:05 -0400 Received: from mx1.catap.net ([2a01:4f8:271:125e::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv4-0007u3-7g for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:05 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 7452db17 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:53 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id ffb67bf2; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=j8b1AJ9 OABWZnYaRWjK3/hkvOqv0iSOuXMpQs9dNpfcBY9y+xXcGP+sjLSuu5cLeYPm/4b5SOhuWC Gihzh8wnVZjaoxWfTf0CFhBFxiQl0PL+jP6gaZQNMHYfguiqOzi3FpdOSJHeZ1Vt29j5Zx zGusPJ0BDQeolVcVya5l95RReVJSAmBB48RRVBsZpOjf1S5pQS+jVeczrmbOXrrxsByvRn QjgsznjzD5oBxj4xO2s/KZeA0PwKjuzS6innv2OpNRUHj6jNfe6CshAvqZNxiN75js/Fsh 7YCVcfxY23+Bq8VEG2FROrgVEaR7mUGnUhABHXRUWRxwfAVXrqCmZvg== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=N lQCfTUIrGK7wU89VmqWVsJFJIz1WtVMwoSI2sKlRx0=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=eWnbGkYfiMQwXtrn+HlcftVnXF3hLRvsR6wc7s07GON7QdBEvGFnh+HL52X2sgv3C6mr NfUmAbLycmGjQ0m1vVHJOGbWlNguxnfKE/4OgEJNGlfA1bNjOF9xAeEaxxxhd0aS2eV/5y ZTnXN/HXeIshfFq0ZzCuTFEQkb4Gjsv7P01OCOEFhr2cpmwvxJbHVDYy/O7pwIc3qj+FqE vtR7Ek6oQ9e+Fm/iggwhbq2Hih+vvFkt0g9J1k/BTDQT2RbAOg2IMDsK1J1EKnVVH4kU45 Ci3HBSR7DfIFPY0aku91TPoVzSI0kdGVLiA1EXaQ0IU0DH7p74TTXG3U0may8WZw== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=VeVsZL0c; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=MwtYVLiI; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=NlQCfTUI rGK7wU89VmqWVsJFJIz1WtVMwoSI2sKlRx0=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=VeVsZL0cj/KWdQgqNONUZtO90db9i3QF8xD 1ALiBLT81sJWAhNj7B9dz4rmh2VTrTXx/BnSRPN5o0wyFvrRU2cOTkU3s2aFGB34Hc84fc nooW58eiGQem2mJWl32MJIULvVyTVDSxTo02+A8j8uO321jSsOTmYID+/gtNWOgn5lM7V/ df/XBfhCbSZ1v8Ac1zvJNu5oIJLHVytrSrj/61k4dSpHg9StfzsGl6dexbgkJkPOWyphaR TXsiDPSeBNbOaq2CcMFpoSyyeErWQOsNXFRCjofI6+mUl7vOhCjwdfznBMhk1vfyue84pV DpoptSoNzb4sJQT6gjfxyRhHxkw== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=NlQCfTUIrGK7wU89VmqWVsJFJIz1WtVMwoSI2sKlRx0=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=MwtYVLiIGqdc91kvMr cQaC0v1tdgWXEa8pWwo4Qk4kKXTMD8Vniek5Fu0P5ozfh7IPMSuS3VlO/6VoajRZvkDQ== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 13/25] hw/mips: add Octeon legacy CIU Date: Wed, 15 Jul 2026 15:43:59 +0200 Message-ID: <20260715134447.56007-14-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f8:271:125e::2; envelope-from=kirill@korins.ky; helo=mx1.catap.net 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_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123308876158500 Content-Type: text/plain; charset="utf-8" Model the legacy CIU mailbox, IPI, GPIO and UART summary registers. Mirror mailbox state into CIU3 interrupt sources so firmware using either controller observes consistent interrupt delivery. --- hw/mips/octeon.c | 248 +++++++++++++++++++++++++++++++++++++- hw/mips/octeon_internal.h | 1 + 2 files changed, 248 insertions(+), 1 deletion(-) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 567be0905a..638d96559f 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -69,6 +69,29 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonIntcState, OCTEON_INTC) #define OCTEON_DR1_BASE 0x020000000ULL #define OCTEON_DR1_SIZE (OCTEON_MAX_PHY_MEM_SIZE - OCTEON_DR0_= SIZE) =20 +#define OCTEON_CIU_BASE 0x1070000000000ULL +#define OCTEON_CIU_LEGACY_PAGE_SIZE (4 * KiB) +#define OCTEON_CIU_SIZE (1 * MiB + OCTEON_CIU_LEGACY_PAGE_SIZE) +#define OCTEON_CIU_FUSE 0x728 +#define OCTEON_CIU_SUM_IPI 0x0000000100000000ULL +#define OCTEON_CIU_SUM_UART 0x0000000800000000ULL +#define OCTEON_CIU_ENABLE0 0x88006f1800000000ULL +#define OCTEON_CIU_IPI_SUM_BASE 0x008 +#define OCTEON_CIU_IPI_SUM_STRIDE 0x10 +#define OCTEON_CIU_IPI_EN_BASE 0x210 +#define OCTEON_CIU_IPI_EN_STRIDE 0x20 +#define OCTEON_CIU_MBOX_SET_BASE 0x600 +#define OCTEON_CIU_MBOX_CLR_BASE 0x680 +#define OCTEON_CIU_MBOX_SET_STRIDE 8 +#define OCTEON_CIU_GPIO_RX_DAT 0x880 +#define OCTEON_CIU_GPIO_TX_SET 0x888 +#define OCTEON_CIU_GPIO_TX_CLR 0x890 +#define OCTEON_CIU_GPIO_BIT_CFG_STRIDE OCTEON_CSR_64BIT_SIZE +#define OCTEON_CIU_GPIO_BIT_CFGX(x) \ + (0x900 + (x) * OCTEON_CIU_GPIO_BIT_CFG_STRIDE) +#define OCTEON_CIU_GPIO_INPUTS ((1ULL << OCTEON_CIU_GPIO_COUNT) - 1) +#define OCTEON_CIU_GPIO_BIT_CFG_TX_OE (1ULL << 0) + #define OCTEON_CIU3_BASE 0x1010000000000ULL #define OCTEON_CIU3_SIZE 0xb0000000ULL #define OCTEON_CIU3_PP_RST 0x100 @@ -97,7 +120,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonIntcState, OCTEON_INTC) #define OCTEON_CIU3_ISC_SIZE (OCTEON_CIU3_NINTSN * 8) #define OCTEON_CIU3_MBOX_INTSN(cpu) ((cpu) + 0x4000U) #define OCTEON_CIU3_UART0_INTSN 0x8000 - /* * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; * the guest sees the virtual CVMSEG window, not this physical address. @@ -147,7 +169,14 @@ struct OcteonRstState { =20 struct OcteonIntcState { OcteonPeripheralState parent_obj; + MemoryRegion ciu; MemoryRegion ciu3; + uint32_t ciu_mbox[OCTEON_MAX_CPUS]; + uint64_t ciu_ipi_en[OCTEON_MAX_CPUS]; + uint64_t ciu_gpio_rx; + uint64_t ciu_gpio_tx; + uint64_t ciu_gpio_bit_cfg[OCTEON_CIU_GPIO_COUNT]; + bool uart_pending; uint64_t ciu3_pp_rst; uint32_t ciu3_src_state[OCTEON_CIU3_SRC_COUNT]; uint64_t ciu3_src_ctl[OCTEON_CIU3_SRC_COUNT]; @@ -305,6 +334,12 @@ static void octeon_ciu3_clear_raw(OcteonState *s, unsi= gned int source) } while (old !=3D cmp); } =20 +static bool octeon_ciu3_set_mbox(OcteonState *s, unsigned int cpu) +{ + return octeon_ciu3_set_level(s, OCTEON_CIU3_SRC_MBOX0 + cpu, + qatomic_read(&s->intc->ciu_mbox[cpu]) != =3D 0); +} + static bool octeon_ciu3_isc_decode(hwaddr reg, uint32_t base, uint32_t *intsn) { @@ -461,6 +496,12 @@ static void octeon_intc_update_cpu(OcteonState *s, uns= igned int cpu_index) irq < OCTEON_CIU3_CP0_IRQ_BASE + OCTEON_CIU3_CP0_IRQ_COUNT; irq++) { level =3D false; + if (irq =3D=3D 3) { + level =3D qatomic_read(&s->intc->ciu_mbox[cpu_index]) && + (qatomic_read(&s->intc->ciu_ipi_en[cpu_index]) & + OCTEON_CIU_SUM_IPI); + } + if (octeon_ciu3_pending_intsn(s, cpu_index, irq, &intsn)) { level =3D true; } @@ -527,6 +568,189 @@ static uint64_t octeon_ciu3_source_cpu_mask(OcteonSta= te *s, unsigned int src) s, qatomic_read(&s->intc->ciu3_src_ctl[src])); } =20 +static uint64_t octeon_ciu_gpio_rx_value(OcteonState *s) +{ + uint64_t value =3D 0; + unsigned int i; + + for (i =3D 0; i < OCTEON_CIU_GPIO_COUNT; i++) { + uint64_t mask =3D 1ULL << i; + + if (qatomic_read(&s->intc->ciu_gpio_bit_cfg[i]) & + OCTEON_CIU_GPIO_BIT_CFG_TX_OE) { + if (qatomic_read(&s->intc->ciu_gpio_tx) & mask) { + value |=3D mask; + } + } else if (qatomic_read(&s->intc->ciu_gpio_rx) & mask) { + value |=3D mask; + } + } + + return value; +} + +static uint64_t octeon_ciu_read(void *opaque, hwaddr addr, unsigned size) +{ + OcteonState *s =3D opaque; + uint64_t value =3D 0; + hwaddr reg =3D addr & ~7ULL; + unsigned int cpu; + + if (reg =3D=3D 0) { + if (qatomic_read(&s->intc->uart_pending)) { + value |=3D OCTEON_CIU_SUM_UART; + } + octeon_intc_request_cpu_update(s, 0); + return octeon_read64(value, addr, size); + } + + if (reg =3D=3D OCTEON_CIU_IPI_EN_BASE) { + return octeon_read64(OCTEON_CIU_ENABLE0, addr, size); + } + + if (reg =3D=3D OCTEON_CIU_FUSE) { + value =3D octeon_present_cpu_mask(s); + return octeon_read64(value, addr, size); + } + + if (reg =3D=3D OCTEON_CIU_GPIO_RX_DAT) { + return octeon_read64(octeon_ciu_gpio_rx_value(s), addr, size); + } + + if (reg =3D=3D OCTEON_CIU_GPIO_TX_SET || + reg =3D=3D OCTEON_CIU_GPIO_TX_CLR) { + return octeon_read64(qatomic_read(&s->intc->ciu_gpio_tx), addr, si= ze); + } + + if (reg >=3D OCTEON_CIU_GPIO_BIT_CFGX(0) && + reg < OCTEON_CIU_GPIO_BIT_CFGX(OCTEON_CIU_GPIO_COUNT)) { + unsigned int index =3D (reg - OCTEON_CIU_GPIO_BIT_CFGX(0)) / + OCTEON_CIU_GPIO_BIT_CFG_STRIDE; + + return octeon_read64(qatomic_read(&s->intc->ciu_gpio_bit_cfg[index= ]), + addr, size); + } + + if (reg >=3D OCTEON_CIU_IPI_SUM_BASE && + reg < OCTEON_CIU_IPI_SUM_BASE + + OCTEON_MAX_CPUS * OCTEON_CIU_IPI_SUM_STRIDE && + ((reg - OCTEON_CIU_IPI_SUM_BASE) & + (OCTEON_CIU_IPI_SUM_STRIDE - 1)) =3D=3D 0) { + cpu =3D (reg - OCTEON_CIU_IPI_SUM_BASE) / OCTEON_CIU_IPI_SUM_STRID= E; + if (cpu < s->cpu_count && qatomic_read(&s->intc->ciu_mbox[cpu])) { + return octeon_read64(OCTEON_CIU_SUM_IPI, addr, size); + } + } + + if (reg >=3D OCTEON_CIU_IPI_EN_BASE && + reg < OCTEON_CIU_IPI_EN_BASE + + OCTEON_MAX_CPUS * OCTEON_CIU_IPI_EN_STRIDE && + ((reg - OCTEON_CIU_IPI_EN_BASE) & + (OCTEON_CIU_IPI_EN_STRIDE - 1)) =3D=3D 0) { + cpu =3D (reg - OCTEON_CIU_IPI_EN_BASE) / OCTEON_CIU_IPI_EN_STRIDE; + if (cpu < s->cpu_count) { + return octeon_read64(qatomic_read(&s->intc->ciu_ipi_en[cpu]), + addr, size); + } + } + + if (reg >=3D OCTEON_CIU_MBOX_CLR_BASE && + reg < OCTEON_CIU_MBOX_CLR_BASE + + OCTEON_MAX_CPUS * OCTEON_CIU_MBOX_SET_STRIDE && + ((reg - OCTEON_CIU_MBOX_CLR_BASE) & + (OCTEON_CIU_MBOX_SET_STRIDE - 1)) =3D=3D 0) { + cpu =3D (reg - OCTEON_CIU_MBOX_CLR_BASE) / OCTEON_CIU_MBOX_SET_STR= IDE; + if (cpu < s->cpu_count) { + return octeon_read64(qatomic_read(&s->intc->ciu_mbox[cpu]), + addr, size); + } + } + + return 0; +} + +static void octeon_ciu_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonState *s =3D opaque; + hwaddr reg =3D addr & ~7ULL; + uint64_t old; + unsigned int cpu; + + if (reg >=3D OCTEON_CIU_IPI_EN_BASE && + reg < OCTEON_CIU_IPI_EN_BASE + + OCTEON_MAX_CPUS * OCTEON_CIU_IPI_EN_STRIDE && + ((reg - OCTEON_CIU_IPI_EN_BASE) & + (OCTEON_CIU_IPI_EN_STRIDE - 1)) =3D=3D 0) { + cpu =3D (reg - OCTEON_CIU_IPI_EN_BASE) / OCTEON_CIU_IPI_EN_STRIDE; + if (cpu < s->cpu_count) { + value =3D octeon_atomic_write64(&s->intc->ciu_ipi_en[cpu], add= r, + value, size, UINT64_MAX, 0, &old= ); + if (old !=3D value) { + octeon_intc_request_cpu_update(s, cpu); + } + } + return; + } + + if (reg >=3D OCTEON_CIU_MBOX_SET_BASE && + reg < OCTEON_CIU_MBOX_SET_BASE + + OCTEON_MAX_CPUS * OCTEON_CIU_MBOX_SET_STRIDE && + ((reg - OCTEON_CIU_MBOX_SET_BASE) & + (OCTEON_CIU_MBOX_SET_STRIDE - 1)) =3D=3D 0) { + cpu =3D (reg - OCTEON_CIU_MBOX_SET_BASE) / OCTEON_CIU_MBOX_SET_STR= IDE; + if (cpu < s->cpu_count) { + old =3D qatomic_fetch_or(&s->intc->ciu_mbox[cpu], value & UINT= 32_MAX); + if ((old | (value & UINT32_MAX)) !=3D old && + octeon_ciu3_set_mbox(s, cpu)) { + octeon_intc_request_cpu_update(s, cpu); + } + } + return; + } + + if (reg >=3D OCTEON_CIU_MBOX_CLR_BASE && + reg < OCTEON_CIU_MBOX_CLR_BASE + + OCTEON_MAX_CPUS * OCTEON_CIU_MBOX_SET_STRIDE && + ((reg - OCTEON_CIU_MBOX_CLR_BASE) & + (OCTEON_CIU_MBOX_SET_STRIDE - 1)) =3D=3D 0) { + cpu =3D (reg - OCTEON_CIU_MBOX_CLR_BASE) / OCTEON_CIU_MBOX_SET_STR= IDE; + if (cpu < s->cpu_count) { + old =3D qatomic_fetch_and(&s->intc->ciu_mbox[cpu], + ~(value & UINT32_MAX)); + if ((old & (value & UINT32_MAX)) && + octeon_ciu3_set_mbox(s, cpu)) { + octeon_intc_request_cpu_update(s, cpu); + } + } + return; + } + + if (reg =3D=3D OCTEON_CIU_GPIO_TX_SET) { + value =3D octeon_write64(0, addr, value, size) & + OCTEON_CIU_GPIO_INPUTS; + qatomic_or(&s->intc->ciu_gpio_tx, value); + return; + } + + if (reg =3D=3D OCTEON_CIU_GPIO_TX_CLR) { + value =3D octeon_write64(0, addr, value, size) & + OCTEON_CIU_GPIO_INPUTS; + qatomic_and(&s->intc->ciu_gpio_tx, ~value); + return; + } + + if (reg >=3D OCTEON_CIU_GPIO_BIT_CFGX(0) && + reg < OCTEON_CIU_GPIO_BIT_CFGX(OCTEON_CIU_GPIO_COUNT)) { + unsigned int index =3D (reg - OCTEON_CIU_GPIO_BIT_CFGX(0)) / + OCTEON_CIU_GPIO_BIT_CFG_STRIDE; + + octeon_atomic_write64(&s->intc->ciu_gpio_bit_cfg[index], addr, val= ue, + size, UINT64_MAX, 0, NULL); + return; + } +} + static void octeon_cpu_park_now(MIPSCPU *cpu) { CPUMIPSState *env =3D &cpu->env; @@ -591,6 +815,16 @@ static void octeon_ciu3_nmi(OcteonState *s, uint64_t m= ask) } } =20 +static const MemoryRegionOps octeon_ciu_ops =3D { + .read =3D octeon_ciu_read, + .write =3D octeon_ciu_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + static uint64_t octeon_ciu3_read(void *opaque, hwaddr addr, unsigned size) { OcteonState *s =3D opaque; @@ -799,6 +1033,7 @@ void octeon_irq_set(void *opaque, int irq, int level) if (!octeon_ciu3_set_level(s, src, level)) { return; } + qatomic_set(&s->intc->uart_pending, level); break; default: return; @@ -1042,6 +1277,12 @@ static void octeon_intc_reset_hold(Object *obj, Rese= tType type) opc->parent_phases.hold(obj, type); } =20 + memset(intc->ciu_mbox, 0, sizeof(intc->ciu_mbox)); + memset(intc->ciu_ipi_en, 0, sizeof(intc->ciu_ipi_en)); + qatomic_set(&intc->ciu_gpio_rx, OCTEON_CIU_GPIO_INPUTS); + qatomic_set(&intc->ciu_gpio_tx, 0); + memset(intc->ciu_gpio_bit_cfg, 0, sizeof(intc->ciu_gpio_bit_cfg)); + qatomic_set(&intc->uart_pending, false); qatomic_set(&intc->ciu3_pp_rst, octeon_secondary_cpu_mask(s)); memset(intc->ciu3_src_state, 0, sizeof(intc->ciu3_src_state)); memset(intc->ciu3_src_ctl, 0, sizeof(intc->ciu3_src_ctl)); @@ -1134,6 +1375,11 @@ static void mips_octeon_init(MachineState *machine) octeon_load_firmware(s); octeon_create_cpus(s); =20 + memory_region_init_io(&s->intc->ciu, OBJECT(s->intc), &octeon_ciu_ops,= s, + "octeon.ciu", OCTEON_CIU_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_CIU_BASE, + &s->intc->ciu); + memory_region_init_io(&s->intc->ciu3, OBJECT(s->intc), &octeon_ciu3_ops, s, "octeon.ciu3", OCTEON_CIU3_SIZE); diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index fef88419b5..cd810f3dd5 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -14,6 +14,7 @@ #include "target/mips/cpu.h" =20 #define OCTEON_MAX_CPUS 16 +#define OCTEON_CIU_GPIO_COUNT 32 #define OCTEON_CIU3_CP0_IRQ_COUNT 4 #define OCTEON_CIU3_IDT_COUNT (OCTEON_MAX_CPUS * 4) =20 --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123280095908.5259762188207; Wed, 15 Jul 2026 06:48:00 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvA-0005eM-MP; Wed, 15 Jul 2026 09:45:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv8-0005bF-B2 for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:06 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv5-0007uM-Ky for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:05 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 50a8a76a (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:53 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id d7f6cd2b; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=N4ZbCbT nnjMgOaud8cewOgOFRS61/9dRmelnbNmFjA0TccERaILAe9vtXNzwXS4xuatZNv+6Bn2Ck NI+pK0+nzhGpWnQgjJI2KFSPy1bPwxQggaCy8hRJ4Txtn6rtol2Ya9up0UIl+HlFarbDRj C6i21MiAnH12+d6o7TrJgQIQP45nnQ/DnbEEuH4SfTz1hUMJuWlhwogEdi0algIQLBnE20 2W4zHJ1Rezq8iLSEgjU7acQzgXA37t/mURh7UmI5yLgmxkgeWOdecvHhguB2zhBP+RA5xY EVk5KBssV8jSYpyr5oxpIGRyk4mVRDa8w/aaLi4zrfdX1r31xh83oOQ== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=L DYsvlZpBY7OPcJlDbaVU2CpyR6pAY3yYm5q2JmOMbo=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=Fvb9MBiDhZWezHTCkaFTuhxsioASnsx1B2fvoY32dlIpTyrkHneQyOaAin0hTemqCzju /FrmS/Ly/KN91+owEHo0AfOTJQ3tmjOe3qtqTXB43HEPabN9IPKzobl1u6lvUPGOiTsHun WXWGU4q5ePAfj+6FMtq+xeZQRzUNul4OoPqiDcL245MVhyBsTU5+qFonWOsKgaUmy6vt+H IYKMb3ILmuEUwRfeer8cUJgsFVabr7o4pl6Ofe9T+2yfQ9YGsalvzU1qhlV2gTxoV8fpqw 8KWpEfewERUl+VCIwz/r8nEhFb9RQHENp0KialpLLOqm8V7jKXwuC9nKDPCAQvmg== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=yYyMreAL; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=NDeSUyU9; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=LDYsvlZp BY7OPcJlDbaVU2CpyR6pAY3yYm5q2JmOMbo=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=yYyMreALTFB2XMNC2HkuZ+WlinG2Gn0Ogls 6WKHwLyrzEwvL8uHBYeUCo5r29RCkFa9g0UuPS5Ri1xpi6rgZW0gE7nDp9PAKW1Yay8MKR rPn9xIwisoX2aUy7/4C3un8pwN8+IKbdXzjxYu8YHgnQTjaezlIh8auGiFrRHx/3cm7gEv USG31ichxhwGCyBmVJZOIlO+6pkxalKKnOBrtKke6TG7eBmdLlVFkwZBbZeN3qZYLjCvXO TDNCQL1gWigdOrmTssXk6Xxa+w3LWrwFJnyGf3ba8bBi3NJUKBL1xS7NzQG8kzFjDXPeh0 YXirPlYRs3WSQnTBhYeZqeW/jeg== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=LDYsvlZpBY7OPcJlDbaVU2CpyR6pAY3yYm5q2JmOMbo=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=NDeSUyU9PLzwD3B4da sYqFA6s+ELF72fpb4jRw2mqPenYP9uBh2sbMTQG2q30QBCGuAnJi0WCSJqYiFS8+WLBA== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 14/25] hw/mips: add Octeon CSR window Date: Wed, 15 Jul 2026 15:44:00 +0200 Message-ID: <20260715134447.56007-15-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123280576158500 Content-Type: text/plain; charset="utf-8" Add the shared CSR window and backing register storage. Keep mutable state in a resettable CSR bank device so later controllers can route their registers through it. --- hw/mips/octeon.c | 146 ++++++++++++++++++++++++++++++++++++++ hw/mips/octeon_internal.h | 7 ++ 2 files changed, 153 insertions(+) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 638d96559f..0caf088adf 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -41,6 +41,8 @@ OBJECT_DECLARE_TYPE(OcteonPeripheralState, OcteonPeripher= alClass, OBJECT_DECLARE_SIMPLE_TYPE(OcteonRstState, OCTEON_RST) #define TYPE_OCTEON_INTC "octeon-intc" OBJECT_DECLARE_SIMPLE_TYPE(OcteonIntcState, OCTEON_INTC) +#define TYPE_OCTEON_CSR_BANK "octeon-csr-bank" +OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_CSR_BANK) =20 #define OCTEON_CSR_64BIT_SIZE 8 =20 @@ -120,6 +122,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonIntcState, OCTEON_INTC) #define OCTEON_CIU3_ISC_SIZE (OCTEON_CIU3_NINTSN * 8) #define OCTEON_CIU3_MBOX_INTSN(cpu) ((cpu) + 0x4000U) #define OCTEON_CIU3_UART0_INTSN 0x8000 +#define OCTEON_CSR_BASE 0x1180000000000ULL +#define OCTEON_CSR_SIZE 0x100000000ULL /* * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; * the guest sees the virtual CVMSEG window, not this physical address. @@ -187,6 +191,24 @@ struct OcteonIntcState { uint8_t ciu3_irq_line[OCTEON_MAX_CPUS][OCTEON_CIU3_CP0_IRQ_COUNT]; }; =20 +struct OcteonCsrBankState { + OcteonPeripheralState parent_obj; + MemoryRegion csr; + GHashTable *values; +}; + +guint octeon_uint64_hash(gconstpointer v) +{ + uint64_t value =3D *(const uint64_t *)v; + + return value ^ (value >> 32); +} + +gboolean octeon_uint64_equal(gconstpointer a, gconstpointer b) +{ + return *(const uint64_t *)a =3D=3D *(const uint64_t *)b; +} + uint64_t octeon_read64(uint64_t value, hwaddr addr, unsigned size) { if (size =3D=3D 4) { @@ -248,6 +270,38 @@ static void octeon_validate_clocks(OcteonMachineState = *oms) } } =20 +bool octeon_reg_lookup(GHashTable *regs, uint64_t reg, uint64_t *value) +{ + uint64_t *stored =3D g_hash_table_lookup(regs, ®); + + if (!stored) { + return false; + } + + *value =3D *stored; + return true; +} + +void octeon_reg_store(GHashTable *regs, uint64_t reg, uint64_t value) +{ + uint64_t *key =3D g_new(uint64_t, 1); + uint64_t *stored =3D g_new(uint64_t, 1); + + *key =3D reg; + *stored =3D value; + g_hash_table_replace(regs, key, stored); +} + +bool octeon_csr_lookup(OcteonState *s, uint64_t reg, uint64_t *value) +{ + return octeon_reg_lookup(s->csr_bank->values, reg, value); +} + +static void octeon_csr_store(OcteonState *s, uint64_t reg, uint64_t value) +{ + octeon_reg_store(s->csr_bank->values, reg, value); +} + static bool octeon_ciu3_source_from_intsn(uint32_t intsn, unsigned int *source) { @@ -1022,6 +1076,42 @@ static const MemoryRegionOps octeon_ciu3_ops =3D { }, }; =20 +static uint64_t octeon_csr_read(void *opaque, hwaddr addr, unsigned size) +{ + OcteonState *s =3D opaque; + hwaddr reg =3D addr & ~7ULL; + uint64_t value; + + if (!octeon_csr_lookup(s, reg, &value)) { + value =3D 0; + } + return octeon_read64(value, addr, size); +} + +static void octeon_csr_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonState *s =3D opaque; + hwaddr reg =3D addr & ~7ULL; + uint64_t old; + + if (!octeon_csr_lookup(s, reg, &old)) { + old =3D 0; + } + value =3D octeon_write64(old, addr, value, size); + octeon_csr_store(s, reg, value); +} + +static const MemoryRegionOps octeon_csr_ops =3D { + .read =3D octeon_csr_read, + .write =3D octeon_csr_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + void octeon_irq_set(void *opaque, int irq, int level) { OcteonState *s =3D opaque; @@ -1294,6 +1384,18 @@ static void octeon_intc_reset_hold(Object *obj, Rese= tType type) octeon_intc_update_all_cpus(s); } =20 +static void octeon_csr_bank_reset_hold(Object *obj, ResetType type) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); + OcteonCsrBankState *bank =3D OCTEON_CSR_BANK(obj); + + if (opc->parent_phases.hold) { + opc->parent_phases.hold(obj, type); + } + + g_hash_table_remove_all(bank->values); +} + static void octeon_peripheral_class_init(ObjectClass *klass, const void *data) { @@ -1302,6 +1404,23 @@ static void octeon_peripheral_class_init(ObjectClass= *klass, dc->user_creatable =3D false; } =20 +static GHashTable *octeon_reg_table_new(void) +{ + return g_hash_table_new_full(octeon_uint64_hash, + octeon_uint64_equal, + g_free, g_free); +} + +static void octeon_csr_bank_init(Object *obj) +{ + OCTEON_CSR_BANK(obj)->values =3D octeon_reg_table_new(); +} + +static void octeon_csr_bank_finalize(Object *obj) +{ + g_hash_table_destroy(OCTEON_CSR_BANK(obj)->values); +} + static void octeon_rst_class_init(ObjectClass *klass, const void *data) { OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); @@ -1320,6 +1439,16 @@ static void octeon_intc_class_init(ObjectClass *klas= s, const void *data) NULL, &opc->parent_phases); } =20 +static void octeon_csr_bank_class_init(ObjectClass *klass, const void *dat= a) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + resettable_class_set_parent_phases(rc, NULL, + octeon_csr_bank_reset_hold, NULL, + &opc->parent_phases); +} + static OcteonPeripheralState *octeon_new_peripheral(OcteonState *s, const char *type, unsigned int index) @@ -1336,6 +1465,8 @@ static void octeon_create_peripherals(OcteonState *s) { s->rst =3D OCTEON_RST(octeon_new_peripheral(s, TYPE_OCTEON_RST, 0)); s->intc =3D OCTEON_INTC(octeon_new_peripheral(s, TYPE_OCTEON_INTC, 0)); + s->csr_bank =3D OCTEON_CSR_BANK(octeon_new_peripheral( + s, TYPE_OCTEON_CSR_BANK, 0)); } =20 static void octeon_realize_peripheral(OcteonPeripheralState *dev) @@ -1347,6 +1478,7 @@ static void octeon_realize_peripherals(OcteonState *s) { octeon_realize_peripheral(&s->intc->parent_obj); octeon_realize_peripheral(&s->rst->parent_obj); + octeon_realize_peripheral(&s->csr_bank->parent_obj); } =20 static void mips_octeon_init(MachineState *machine) @@ -1386,6 +1518,12 @@ static void mips_octeon_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), OCTEON_CIU3_BASE, &s->intc->ciu3); =20 + memory_region_init_io(&s->csr_bank->csr, OBJECT(s->csr_bank), + &octeon_csr_ops, s, + "octeon.csr", OCTEON_CSR_SIZE); + memory_region_add_subregion_overlap(get_system_memory(), OCTEON_CSR_BA= SE, + &s->csr_bank->csr, -1); + octeon_realize_peripherals(s); } =20 @@ -1464,6 +1602,14 @@ static const TypeInfo octeon_machine_types[] =3D { .instance_size =3D sizeof(OcteonIntcState), .class_init =3D octeon_intc_class_init, }, + { + .name =3D TYPE_OCTEON_CSR_BANK, + .parent =3D TYPE_OCTEON_PERIPHERAL, + .instance_size =3D sizeof(OcteonCsrBankState), + .instance_init =3D octeon_csr_bank_init, + .instance_finalize =3D octeon_csr_bank_finalize, + .class_init =3D octeon_csr_bank_class_init, + }, { .name =3D TYPE_OCTEON_MACHINE, .parent =3D TYPE_MACHINE, diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index cd810f3dd5..6327103f52 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -32,6 +32,7 @@ typedef enum OcteonCiu3Source { typedef struct OcteonState OcteonState; typedef struct OcteonRstState OcteonRstState; typedef struct OcteonIntcState OcteonIntcState; +typedef struct OcteonCsrBankState OcteonCsrBankState; =20 typedef struct OcteonCPUState { OcteonState *board; @@ -58,11 +59,17 @@ struct OcteonState { MemoryRegion cvmseg; OcteonRstState *rst; OcteonIntcState *intc; + OcteonCsrBankState *csr_bank; }; =20 +guint octeon_uint64_hash(gconstpointer v); +gboolean octeon_uint64_equal(gconstpointer a, gconstpointer b); uint64_t octeon_read64(uint64_t value, hwaddr addr, unsigned size); uint64_t octeon_write64(uint64_t old, hwaddr addr, uint64_t value, unsigned size); +bool octeon_reg_lookup(GHashTable *regs, uint64_t reg, uint64_t *value); +void octeon_reg_store(GHashTable *regs, uint64_t reg, uint64_t value); +bool octeon_csr_lookup(OcteonState *s, uint64_t reg, uint64_t *value); void octeon_irq_set(void *opaque, int irq, int level); =20 #endif --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123149379134.03758089894654; Wed, 15 Jul 2026 06:45:49 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv4-0005Ym-Ec; Wed, 15 Jul 2026 09:45:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv2-0005XN-IB for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:00 -0400 Received: from mx2.catap.net ([65.21.79.163]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv0-0007u1-9C for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:00 -0400 Received: by mx2.catap.net (OpenSMTPD) with ESMTPSA id 1ad36fbc (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:53 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 0eef788f; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=IWnNruG 7b18Sc/fI0yfVWBcXhnw9xZ3bmnU2PdxFCdVz9McEZt6isKwchP/e20xhW2hPnFpXQjdbO Dxf/JnPaGY7gu6Sq1BSGHmo+/JL1xhJ2zbFfoQq/2zAnCl0pqJHgOUOEJcN3YzQtnxBpKa NwLi4JY40Oq2l7JY94cZcBnHFmNvBkJh2V+o30o76NAz6rRc1+jPkrpiYQC8vJ4kHgsxUD 3H0Agn8f8mjTB21ZAct7fORzLPSXsn0A4cNFhV1ybFjktNuqzCqEzfGxmupfs6Ue1tt39N dvl25z/Hj+lGpk34OJhh8p54TOluNr8yyZvBkWqjy5mbEycee1jj90g== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=o vBHesXI0MiKFPQdP7nUTsJW4n+0iEF97sGoPyPeFZo=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=ri7AfcxUPV4yfUR84R07aNNumff9m2zPPj0u+mrLmLvsBcEGpZTmZphEqKXkkeOHtnoS m4NCYAkdNAyI6t0RO970qmkmAlLtq+QIOlV6pl69XNkm1e7PF8TBW9QnHSEe7otmF5oLxi Dy+LSxGXdimfy1XhtHXkfGoUq5LgG9VW8tiEQwxRWhRi1H0mZUjA/293ZfXihx/9adrQ3T P4qQbkiUZ/8B1xs4W3x2to0Lbjyor/qmWdUXsMp/AjSOLGVXZEdxKAHI8X4UDWnHo3L4HZ wHon9zeF0q2Nfp3s+O+QnLSTG7eI+YgA13+VKevK6XeURlkXDl2TKsOR2GGQ9Vcg== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=lwlGSnYN; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=sAiFX7Hc; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=ovBHesXI 0MiKFPQdP7nUTsJW4n+0iEF97sGoPyPeFZo=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=lwlGSnYNrnX/QNQKklYO3vcK7l9WyjVn1t6 hSpn2mdB3wJ3TFc9+RKQAou6uma5rRtpT8ofCuVD5mr3kxap33ham81ARN2kiD7VsdELib n86Y3y7sKY4PzB6irzEjG/RLWgd8zqKvX/CnaFqxuMdw0QeEtJM//3YQeaMBffQ3M07jCA YDeCP9J/W9R4ozLqbevJz2BDe5HNTvEtXM/RgEOox6XAl/awLKaysDOxh6XhYR70EjCYhn puba8phqhJ4M87NXSxIfDnvJOhByDQs+wLuM+pYcpPGsGBhqLa0exZfzOOQlzIQgfwa65H +LgOmSiWAfwu4b45dph9Wsvu0Uw== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=ovBHesXI0MiKFPQdP7nUTsJW4n+0iEF97sGoPyPeFZo=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=sAiFX7HcIV1sYpu6K7 I8c0vdpcPD+bE8ZPI3YXl+A5A1aCgsWtG7BVriyuCB18q/zvBhfUZZosQGan++oxd2CA== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 15/25] hw/mips: expose Octeon reset CSRs Date: Wed, 15 Jul 2026 15:44:01 +0200 Message-ID: <20260715134447.56007-16-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=65.21.79.163; envelope-from=kirill@korins.ky; helo=mx2.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123151509158500 Content-Type: text/plain; charset="utf-8" Expose reset clock, soft reset and processor power registers through the shared CSR window. Keep mutable register state and reset handling in the reset controller. --- hw/mips/octeon.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 0caf088adf..007fc4b537 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -24,6 +24,8 @@ #include "system/cpus.h" #include "system/memory.h" #include "system/reset.h" +#include "system/runstate.h" +#include "system/system.h" #include "exec/cpu-interrupt.h" #include "qemu/error-report.h" #include "qemu/atomic.h" @@ -124,6 +126,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_= CSR_BANK) #define OCTEON_CIU3_UART0_INTSN 0x8000 #define OCTEON_CSR_BASE 0x1180000000000ULL #define OCTEON_CSR_SIZE 0x100000000ULL +#define OCTEON_RST_BOOT 0x6001600 +#define OCTEON_RST_SOFT_RST 0x6001680 +/* U-Boot uses the reset controller to park and release secondary cores. */ +#define OCTEON_RST_PP_POWER 0x6001700 +#define OCTEON_RST_BOOT_C_MUL_SHIFT 30 +#define OCTEON_RST_BOOT_PNR_MUL_SHIFT 24 /* * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; * the guest sees the virtual CVMSEG window, not this physical address. @@ -168,6 +176,7 @@ struct OcteonPeripheralClass { =20 struct OcteonRstState { OcteonPeripheralState parent_obj; + GHashTable *regs; uint64_t rst_pp_power; }; =20 @@ -294,11 +303,18 @@ void octeon_reg_store(GHashTable *regs, uint64_t reg,= uint64_t value) =20 bool octeon_csr_lookup(OcteonState *s, uint64_t reg, uint64_t *value) { + if (reg =3D=3D OCTEON_RST_SOFT_RST) { + return octeon_reg_lookup(s->rst->regs, reg, value); + } return octeon_reg_lookup(s->csr_bank->values, reg, value); } =20 static void octeon_csr_store(OcteonState *s, uint64_t reg, uint64_t value) { + if (reg =3D=3D OCTEON_RST_SOFT_RST) { + octeon_reg_store(s->rst->regs, reg, value); + return; + } octeon_reg_store(s->csr_bank->values, reg, value); } =20 @@ -869,6 +885,33 @@ static void octeon_ciu3_nmi(OcteonState *s, uint64_t m= ask) } } =20 +static void octeon_rst_pp_power_write(OcteonState *s, hwaddr addr, + uint64_t value, unsigned size) +{ + uint64_t old =3D s->rst->rst_pp_power; + uint64_t changed; + unsigned int cpu; + + value =3D octeon_write64(old, addr, value, size) & + octeon_present_cpu_mask(s); + s->rst->rst_pp_power =3D value; + changed =3D old ^ value; + + for (cpu =3D 1; cpu < s->cpu_count; cpu++) { + uint64_t mask =3D 1ULL << cpu; + + if (!(changed & mask)) { + continue; + } + if (value & mask) { + async_run_on_cpu(CPU(s->cpu[cpu].cpu), octeon_cpu_park_work, + RUN_ON_CPU_NULL); + } else { + octeon_start_cpu(s, cpu); + } + } +} + static const MemoryRegionOps octeon_ciu_ops =3D { .read =3D octeon_ciu_read, .write =3D octeon_ciu_write, @@ -1082,6 +1125,19 @@ static uint64_t octeon_csr_read(void *opaque, hwaddr= addr, unsigned size) hwaddr reg =3D addr & ~7ULL; uint64_t value; =20 + switch (reg) { + case OCTEON_RST_BOOT: + value =3D ((uint64_t)(s->cpu_hz / s->ref_hz) << + OCTEON_RST_BOOT_C_MUL_SHIFT) | + ((uint64_t)(s->io_hz / s->ref_hz) << + OCTEON_RST_BOOT_PNR_MUL_SHIFT); + return octeon_read64(value, addr, size); + case OCTEON_RST_PP_POWER: + return octeon_read64(s->rst->rst_pp_power, addr, size); + default: + break; + } + if (!octeon_csr_lookup(s, reg, &value)) { value =3D 0; } @@ -1095,6 +1151,16 @@ static void octeon_csr_write(void *opaque, hwaddr ad= dr, hwaddr reg =3D addr & ~7ULL; uint64_t old; =20 + if (reg =3D=3D OCTEON_RST_SOFT_RST && value) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; + } + + if (reg =3D=3D OCTEON_RST_PP_POWER) { + octeon_rst_pp_power_write(s, addr, value, size); + return; + } + if (!octeon_csr_lookup(s, reg, &old)) { old =3D 0; } @@ -1354,6 +1420,7 @@ static void octeon_rst_reset_hold(Object *obj, ResetT= ype type) opc->parent_phases.hold(obj, type); } =20 + g_hash_table_remove_all(rst->regs); rst->rst_pp_power =3D octeon_secondary_cpu_mask(rst->parent_obj.board); } =20 @@ -1411,6 +1478,16 @@ static GHashTable *octeon_reg_table_new(void) g_free, g_free); } =20 +static void octeon_rst_init(Object *obj) +{ + OCTEON_RST(obj)->regs =3D octeon_reg_table_new(); +} + +static void octeon_rst_finalize(Object *obj) +{ + g_hash_table_destroy(OCTEON_RST(obj)->regs); +} + static void octeon_csr_bank_init(Object *obj) { OCTEON_CSR_BANK(obj)->values =3D octeon_reg_table_new(); @@ -1594,6 +1671,8 @@ static const TypeInfo octeon_machine_types[] =3D { .name =3D TYPE_OCTEON_RST, .parent =3D TYPE_OCTEON_PERIPHERAL, .instance_size =3D sizeof(OcteonRstState), + .instance_init =3D octeon_rst_init, + .instance_finalize =3D octeon_rst_finalize, .class_init =3D octeon_rst_class_init, }, { --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123177932552.0870013353982; Wed, 15 Jul 2026 06:46:17 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvF-0005lM-AR; Wed, 15 Jul 2026 09:45:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv9-0005cH-48 for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:07 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv6-0007tj-2v for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:06 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 66d59427 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:53 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 65c117d1; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=mrj/3gf eULLlIZph2Dsva6OCcFp3HrQB1Nvlx0LUusqFESUKzgfL3OLrgeB+yIz4FYenJzTWLH0d7 i/s8H+PnLvD82sjFa5HplQhp6N6qlY1sDvgcnave+JXcHpWZ+/4TYl/nKWXMRIemSKveT6 EkOK9TAo4P9mVdar+DSGLTgbkXM2gW7bd2LGrIVemf4qz/4ZmaJDPLG15Me78nZBCsNGaa B8NeM6EhdNEVIMmu7J44Q1UaUKoQcmizueIqmHK7/j3aaDNutpQFPXvHr3dhjsECYFGyWt 4ZtBOpZ3otMVXHmQlbr/Metdf3ZxYWJPe0YpI8/Ql8GsGSpLj2qIhPQ== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=u 5IwPcsaEcCkMsLZUacKiW9nBpMcItWT+/kThlPfpqI=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=hK1tbIVrGakZS1cL+EhMXw+V9MUSvmkxweVipQWStFN7oJIf4bluiVnp4ZPGpQgMYGl0 d4mhetNX8meQPIYqYaaBR1yEA/UVraS2oxkmhBZqEPFZt2CllSOvAYHv6QiruF/P3ydknD VMyaY4i+JAon0jrnRW8TEFj3uJ8r7yjAlMA+5FCENOBwxwPOYRcqnOUFYCO56SmtNgbNs2 W/w4jKWyNqoU6KtgL4lFOs+z5Y8DUwEmOVpht3uDj7JLxV9sbWEPpGmz5stH3CxWJ0CPWU rwhhIUSJRAEpPWRjml8b5L+AjcEv6Z5cI4PN7KoF0kg8bZC/TkP+O7MQd0F9jbjg== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=XGJmB4me; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=b7j3pPVG; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=u5IwPcsa EcCkMsLZUacKiW9nBpMcItWT+/kThlPfpqI=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=XGJmB4meivOCNoVfx9BrW0R9C56hS/exFpF SrywaIEZ4kAeVYJbAJBA0Ab15yz/osxDUWVCR/SaQNkgAYBYx5zPk9ni1Ly99zE6PlN2qu Yzvwo0aZAMR9bzlW3zf8jIwkD4MdSX42Rr5P1btfv974IdBDDpVkPRaPgsDq46+UYJtnmq ePfXmNrL2YUUwolZICm2DC29yfg8jYKbFucDpyHZvQ22OXcQkxtf7lLQq85B1hPKuMwfQb y2G0EHmHTN5w7C7P6xi2i/2viQSRepGz4ccjzLLWqhs5zCI3FxNWBYHZLjtV1jCfMjDVN7 apvOOdUwHc/2cbkAw5AEQYWJKVA== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=u5IwPcsaEcCkMsLZUacKiW9nBpMcItWT+/kThlPfpqI=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=b7j3pPVGlw/rq5icNN q/HuhdtB2MXPohQ+m86EAUohoJ/1jeA+1xpvzRNYMC+s2r5BFqCYjgGuOb1I6lp9s2Aw== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 16/25] hw/mips: add Octeon MIO boot support Date: Wed, 15 Jul 2026 15:44:02 +0200 Message-ID: <20260715134447.56007-17-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123179835158500 Content-Type: text/plain; charset="utf-8" Add MIO boot bus configuration, boot location storage and fuse responses. Keep mutable state and memory mappings in a resettable MIO device. --- hw/mips/octeon.c | 248 +++++++++++++++++++++++++++++++++++++- hw/mips/octeon_internal.h | 4 + 2 files changed, 250 insertions(+), 2 deletions(-) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 007fc4b537..59754cb741 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -39,6 +39,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonMachineState, OCTEON_MAC= HINE) OBJECT_DECLARE_TYPE(OcteonPeripheralState, OcteonPeripheralClass, OCTEON_PERIPHERAL) =20 +#define TYPE_OCTEON_MIO "octeon-mio" +OBJECT_DECLARE_SIMPLE_TYPE(OcteonMioState, OCTEON_MIO) #define TYPE_OCTEON_RST "octeon-rst" OBJECT_DECLARE_SIMPLE_TYPE(OcteonRstState, OCTEON_RST) #define TYPE_OCTEON_INTC "octeon-intc" @@ -126,12 +128,33 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON= _CSR_BANK) #define OCTEON_CIU3_UART0_INTSN 0x8000 #define OCTEON_CSR_BASE 0x1180000000000ULL #define OCTEON_CSR_SIZE 0x100000000ULL +#define OCTEON_MIO_BOOT_REG_CFGX(x) \ + (0x0000000 + (x) * OCTEON_CSR_64BIT_SIZE) +#define OCTEON_MIO_BOOT_REG_CFG_INDEX(reg) \ + ((reg) / OCTEON_CSR_64BIT_SIZE) +#define OCTEON_MIO_BOOT_REG_CFG_BASE 0x000000000000ffffULL +#define OCTEON_MIO_BOOT_LOC_CFGX(x) \ + (0x0000080 + ((x) & 1) * OCTEON_CSR_64BIT_SIZE) +#define OCTEON_MIO_BOOT_LOC_CFG_INDEX(reg) \ + (((reg) - OCTEON_MIO_BOOT_LOC_CFGX(0)) / OCTEON_CSR_64BIT_SIZE) +#define OCTEON_MIO_BOOT_LOC_ADR 0x0000090 +#define OCTEON_MIO_BOOT_LOC_DAT 0x0000098 +#define OCTEON_MIO_BOOT_LOC_CFG_BASE 0x000000000ffffff8ULL +#define OCTEON_MIO_BOOT_LOC_CFG_BASE_SHIFT 3 +#define OCTEON_MIO_BOOT_LOC_CFG_EN 0x0000000080000000ULL +#define OCTEON_MIO_BOOT_LOC_ADR_MASK 0xf8 +/* Fuses are left unprogrammed; firmware only needs reads to complete. */ +#define OCTEON_MIO_FUS_DAT2 0x0001410 +#define OCTEON_MIO_FUS_RCMD 0x0001500 +#define OCTEON_MIO_FUS_RCMD_PEND 0x0000000000001000ULL +#define OCTEON_MIO_FUS_RCMD_DAT 0x0000000000ff0000ULL #define OCTEON_RST_BOOT 0x6001600 #define OCTEON_RST_SOFT_RST 0x6001680 /* U-Boot uses the reset controller to park and release secondary cores. */ #define OCTEON_RST_PP_POWER 0x6001700 #define OCTEON_RST_BOOT_C_MUL_SHIFT 30 #define OCTEON_RST_BOOT_PNR_MUL_SHIFT 24 + /* * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; * the guest sees the virtual CVMSEG window, not this physical address. @@ -153,6 +176,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_C= SR_BANK) #define OCTEON_FLASH_ENV_OFFSET \ (OCTEON_FLASH_SIZE - OCTEON_FLASH_ENV_SECTOR_SIZE) #define OCTEON_FLASH_WIDTH 2 +#define OCTEON_MIO_BOOT_REG_CFG_RESET_BASE (OCTEON_FLASH_RESET_BASE >> 16) +#define OCTEON_BOOTBUS_LED_CS 4 +#define OCTEON_BOOTBUS_LED_SIZE (64 * KiB) =20 struct OcteonMachineState { MachineState parent_obj; @@ -174,6 +200,21 @@ struct OcteonPeripheralClass { ResettablePhases parent_phases; }; =20 +struct OcteonMioState { + OcteonPeripheralState parent_obj; + MemoryRegion bootbus_led; + MemoryRegion mio_boot_loc; + uint64_t mio_boot_reg_cfg[OCTEON_MIO_BOOT_REG_CFG_COUNT]; + uint64_t mio_boot_loc_cfg[2]; + uint64_t mio_boot_loc_adr; + uint64_t mio_fus_rcmd; + hwaddr mio_boot_loc_base; + uint8_t mio_boot_loc_data[OCTEON_MIO_BOOT_LOC_SIZE]; + bool mio_boot_loc_mapped; + hwaddr bootbus_led_base; + bool bootbus_led_mapped; +}; + struct OcteonRstState { OcteonPeripheralState parent_obj; GHashTable *regs; @@ -318,6 +359,89 @@ static void octeon_csr_store(OcteonState *s, uint64_t = reg, uint64_t value) octeon_reg_store(s->csr_bank->values, reg, value); } =20 +static hwaddr octeon_mio_boot_loc_base(uint64_t cfg) +{ + uint64_t base =3D (cfg & OCTEON_MIO_BOOT_LOC_CFG_BASE) >> + OCTEON_MIO_BOOT_LOC_CFG_BASE_SHIFT; + + return base << 7; +} + +static void octeon_mio_boot_loc_update(OcteonState *s) +{ + MemoryRegion *sysmem =3D get_system_memory(); + bool enabled =3D s->mio->mio_boot_loc_cfg[0] & OCTEON_MIO_BOOT_LOC_CFG= _EN; + hwaddr base =3D octeon_mio_boot_loc_base(s->mio->mio_boot_loc_cfg[0]); + + if (s->mio->mio_boot_loc_mapped) { + if (enabled && base =3D=3D s->mio->mio_boot_loc_base) { + return; + } + memory_region_del_subregion(sysmem, &s->mio->mio_boot_loc); + s->mio->mio_boot_loc_mapped =3D false; + } + + if (enabled) { + memory_region_add_subregion_overlap(sysmem, base, + &s->mio->mio_boot_loc, 1); + s->mio->mio_boot_loc_base =3D base; + s->mio->mio_boot_loc_mapped =3D true; + } +} + +static hwaddr octeon_mio_boot_reg_cfg_base(uint64_t cfg) +{ + return (cfg & OCTEON_MIO_BOOT_REG_CFG_BASE) << 16; +} + +static void octeon_bootbus_led_update(OcteonState *s) +{ + MemoryRegion *sysmem =3D get_system_memory(); + hwaddr base =3D octeon_mio_boot_reg_cfg_base( + s->mio->mio_boot_reg_cfg[OCTEON_BOOTBUS_LED_CS]); + + if (s->mio->bootbus_led_mapped) { + if (base =3D=3D s->mio->bootbus_led_base) { + return; + } + memory_region_del_subregion(sysmem, &s->mio->bootbus_led); + s->mio->bootbus_led_mapped =3D false; + } + + if (base) { + memory_region_add_subregion(sysmem, base, &s->mio->bootbus_led); + s->mio->bootbus_led_base =3D base; + s->mio->bootbus_led_mapped =3D true; + } +} + +static uint64_t octeon_mio_boot_loc_dat_read(OcteonState *s) +{ + unsigned int offset =3D s->mio->mio_boot_loc_adr & + OCTEON_MIO_BOOT_LOC_ADR_MASK; + uint64_t value =3D ldq_be_p(s->mio->mio_boot_loc_data + offset); + + s->mio->mio_boot_loc_adr =3D + (s->mio->mio_boot_loc_adr + OCTEON_CSR_64BIT_SIZE) & + OCTEON_MIO_BOOT_LOC_ADR_MASK; + return value; +} + +static void octeon_mio_boot_loc_dat_write(OcteonState *s, hwaddr addr, + uint64_t value, unsigned size) +{ + unsigned int offset =3D s->mio->mio_boot_loc_adr & + OCTEON_MIO_BOOT_LOC_ADR_MASK; + uint64_t old =3D ldq_be_p(s->mio->mio_boot_loc_data + offset); + + value =3D octeon_write64(old, addr, value, size); + stq_be_p(s->mio->mio_boot_loc_data + offset, value); + memory_region_set_dirty(&s->mio->mio_boot_loc, offset, sizeof(value)); + s->mio->mio_boot_loc_adr =3D + (s->mio->mio_boot_loc_adr + OCTEON_CSR_64BIT_SIZE) & + OCTEON_MIO_BOOT_LOC_ADR_MASK; +} + static bool octeon_ciu3_source_from_intsn(uint32_t intsn, unsigned int *source) { @@ -1125,7 +1249,28 @@ static uint64_t octeon_csr_read(void *opaque, hwaddr= addr, unsigned size) hwaddr reg =3D addr & ~7ULL; uint64_t value; =20 + if (reg >=3D OCTEON_MIO_BOOT_REG_CFGX(0) && + reg < OCTEON_MIO_BOOT_REG_CFGX(OCTEON_MIO_BOOT_REG_CFG_COUNT)) { + unsigned int index =3D OCTEON_MIO_BOOT_REG_CFG_INDEX(reg); + + return octeon_read64(s->mio->mio_boot_reg_cfg[index], addr, size); + } + switch (reg) { + case OCTEON_MIO_BOOT_LOC_CFGX(0): + case OCTEON_MIO_BOOT_LOC_CFGX(1): { + unsigned int index =3D OCTEON_MIO_BOOT_LOC_CFG_INDEX(reg); + + return octeon_read64(s->mio->mio_boot_loc_cfg[index], addr, size); + } + case OCTEON_MIO_BOOT_LOC_ADR: + return octeon_read64(s->mio->mio_boot_loc_adr, addr, size); + case OCTEON_MIO_BOOT_LOC_DAT: + return octeon_read64(octeon_mio_boot_loc_dat_read(s), addr, size); + case OCTEON_MIO_FUS_DAT2: + return 0; + case OCTEON_MIO_FUS_RCMD: + return octeon_read64(s->mio->mio_fus_rcmd, addr, size); case OCTEON_RST_BOOT: value =3D ((uint64_t)(s->cpu_hz / s->ref_hz) << OCTEON_RST_BOOT_C_MUL_SHIFT) | @@ -1156,11 +1301,56 @@ static void octeon_csr_write(void *opaque, hwaddr a= ddr, return; } =20 + if (reg =3D=3D OCTEON_MIO_BOOT_LOC_CFGX(0) || + reg =3D=3D OCTEON_MIO_BOOT_LOC_CFGX(1)) { + unsigned int index =3D OCTEON_MIO_BOOT_LOC_CFG_INDEX(reg); + + old =3D s->mio->mio_boot_loc_cfg[index]; + s->mio->mio_boot_loc_cfg[index] =3D + octeon_write64(old, addr, value, size); + if (index =3D=3D 0) { + octeon_mio_boot_loc_update(s); + } + return; + } + + if (reg =3D=3D OCTEON_MIO_BOOT_LOC_ADR) { + old =3D s->mio->mio_boot_loc_adr; + value =3D octeon_write64(old, addr, value, size); + s->mio->mio_boot_loc_adr =3D value & OCTEON_MIO_BOOT_LOC_ADR_MASK; + return; + } + + if (reg =3D=3D OCTEON_MIO_BOOT_LOC_DAT) { + octeon_mio_boot_loc_dat_write(s, addr, value, size); + return; + } + + if (reg =3D=3D OCTEON_MIO_FUS_RCMD) { + value =3D octeon_write64(s->mio->mio_fus_rcmd, addr, value, size); + s->mio->mio_fus_rcmd =3D value & ~(OCTEON_MIO_FUS_RCMD_PEND | + OCTEON_MIO_FUS_RCMD_DAT); + return; + } + if (reg =3D=3D OCTEON_RST_PP_POWER) { octeon_rst_pp_power_write(s, addr, value, size); return; } =20 + if (reg >=3D OCTEON_MIO_BOOT_REG_CFGX(0) && + reg < OCTEON_MIO_BOOT_REG_CFGX(OCTEON_MIO_BOOT_REG_CFG_COUNT)) { + unsigned int index =3D OCTEON_MIO_BOOT_REG_CFG_INDEX(reg); + + old =3D s->mio->mio_boot_reg_cfg[index]; + s->mio->mio_boot_reg_cfg[index] =3D + octeon_write64(old, addr, value, size); + if (index =3D=3D OCTEON_BOOTBUS_LED_CS) { + octeon_bootbus_led_update(s); + } + return; + } + if (!octeon_csr_lookup(s, reg, &old)) { old =3D 0; } @@ -1411,6 +1601,42 @@ static void octeon_init_flash(OcteonState *s) &s->boot_flash_alias); } =20 +static void octeon_init_mio_boot_loc(OcteonState *s) +{ + memory_region_init_ram(&s->mio->bootbus_led, OBJECT(s->mio), + "octeon.bootbus-led", + OCTEON_BOOTBUS_LED_SIZE, &error_fatal); + memory_region_init_ram_ptr(&s->mio->mio_boot_loc, OBJECT(s->mio), + "octeon.mio-boot-loc", + OCTEON_MIO_BOOT_LOC_SIZE, + s->mio->mio_boot_loc_data); +} + + +static void octeon_mio_reset_hold(Object *obj, ResetType type) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); + OcteonMioState *mio =3D OCTEON_MIO(obj); + OcteonState *s =3D mio->parent_obj.board; + + if (opc->parent_phases.hold) { + opc->parent_phases.hold(obj, type); + } + + if (mio->bootbus_led_mapped) { + memory_region_del_subregion(get_system_memory(), &mio->bootbus_led= ); + mio->bootbus_led_mapped =3D false; + } + memset(mio->mio_boot_reg_cfg, 0, sizeof(mio->mio_boot_reg_cfg)); + mio->mio_boot_reg_cfg[0] =3D OCTEON_MIO_BOOT_REG_CFG_RESET_BASE; + mio->mio_boot_loc_cfg[0] =3D 0; + mio->mio_boot_loc_cfg[1] =3D 0; + mio->mio_boot_loc_adr =3D 0; + mio->mio_fus_rcmd =3D 0; + memset(mio->mio_boot_loc_data, 0, sizeof(mio->mio_boot_loc_data)); + octeon_mio_boot_loc_update(s); +} + static void octeon_rst_reset_hold(Object *obj, ResetType type) { OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); @@ -1498,6 +1724,15 @@ static void octeon_csr_bank_finalize(Object *obj) g_hash_table_destroy(OCTEON_CSR_BANK(obj)->values); } =20 +static void octeon_mio_class_init(ObjectClass *klass, const void *data) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + resettable_class_set_parent_phases(rc, NULL, octeon_mio_reset_hold, + NULL, &opc->parent_phases); +} + static void octeon_rst_class_init(ObjectClass *klass, const void *data) { OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); @@ -1540,10 +1775,11 @@ static OcteonPeripheralState *octeon_new_peripheral= (OcteonState *s, =20 static void octeon_create_peripherals(OcteonState *s) { + s->mio =3D OCTEON_MIO(octeon_new_peripheral(s, TYPE_OCTEON_MIO, 0)); s->rst =3D OCTEON_RST(octeon_new_peripheral(s, TYPE_OCTEON_RST, 0)); s->intc =3D OCTEON_INTC(octeon_new_peripheral(s, TYPE_OCTEON_INTC, 0)); s->csr_bank =3D OCTEON_CSR_BANK(octeon_new_peripheral( - s, TYPE_OCTEON_CSR_BANK, 0)); + s, TYPE_OCTEON_CSR_BANK, 0)); } =20 static void octeon_realize_peripheral(OcteonPeripheralState *dev) @@ -1553,9 +1789,10 @@ static void octeon_realize_peripheral(OcteonPeripher= alState *dev) =20 static void octeon_realize_peripherals(OcteonState *s) { + octeon_realize_peripheral(&s->csr_bank->parent_obj); octeon_realize_peripheral(&s->intc->parent_obj); octeon_realize_peripheral(&s->rst->parent_obj); - octeon_realize_peripheral(&s->csr_bank->parent_obj); + octeon_realize_peripheral(&s->mio->parent_obj); } =20 static void mips_octeon_init(MachineState *machine) @@ -1581,6 +1818,7 @@ static void mips_octeon_init(MachineState *machine) =20 octeon_map_ram(s); octeon_init_flash(s); + octeon_init_mio_boot_loc(s); octeon_load_firmware(s); octeon_create_cpus(s); =20 @@ -1667,6 +1905,12 @@ static const TypeInfo octeon_machine_types[] =3D { .class_init =3D octeon_peripheral_class_init, .abstract =3D true, }, + { + .name =3D TYPE_OCTEON_MIO, + .parent =3D TYPE_OCTEON_PERIPHERAL, + .instance_size =3D sizeof(OcteonMioState), + .class_init =3D octeon_mio_class_init, + }, { .name =3D TYPE_OCTEON_RST, .parent =3D TYPE_OCTEON_PERIPHERAL, diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index 6327103f52..7b45daba10 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -17,6 +17,8 @@ #define OCTEON_CIU_GPIO_COUNT 32 #define OCTEON_CIU3_CP0_IRQ_COUNT 4 #define OCTEON_CIU3_IDT_COUNT (OCTEON_MAX_CPUS * 4) +#define OCTEON_MIO_BOOT_REG_CFG_COUNT 8 +#define OCTEON_MIO_BOOT_LOC_SIZE 0x100 =20 typedef enum OcteonIRQ { OCTEON_IRQ_UART, @@ -30,6 +32,7 @@ typedef enum OcteonCiu3Source { } OcteonCiu3Source; =20 typedef struct OcteonState OcteonState; +typedef struct OcteonMioState OcteonMioState; typedef struct OcteonRstState OcteonRstState; typedef struct OcteonIntcState OcteonIntcState; typedef struct OcteonCsrBankState OcteonCsrBankState; @@ -57,6 +60,7 @@ struct OcteonState { MemoryRegion boot_flash; MemoryRegion boot_flash_alias; MemoryRegion cvmseg; + OcteonMioState *mio; OcteonRstState *rst; OcteonIntcState *intc; OcteonCsrBankState *csr_bank; --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123179538907.1650529756968; Wed, 15 Jul 2026 06:46:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvB-0005fN-AL; Wed, 15 Jul 2026 09:45:09 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv9-0005cT-Mk for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:07 -0400 Received: from mx1.catap.net ([2a01:4f8:271:125e::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv7-0007uq-Al for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:07 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 32aa2197 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:53 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id a91425ee; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=hfRmq9G u6/ptu0qU4beWYEPJZwpPMLFMyuXDC3LY5q82YXCrwogKw4heW7LrnpI4E/RlDT4u1bW85 KSgeEktZ4YxX2ry0MF6lgwxl0MzVZfArj8i2uNCom6CdXvflIbReguyXIix6nZLtfFLYf1 bWzf3Xxgoif1FDRdfNbKNdPl7ArNoB+G5WJqhqLRVVyz4GdFXLgX1zlD2PCflSM210SQMu SLTkbQSeLjcHuQKsbkBkJosAwHyt5btkOOt80e2Sut4xqGmEuLFVvnrWUIm1yBOZ2PuJZv rDQD+HTq8ivCOrn6VFKW6Ch4ejIEkdzjSgHSteI5jCOirzFZSdFJtMg== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=u IbKli1QgdyezVxeAX0vcwMYcv2NNPb0R3DxNFoBUhM=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=Y9d+QdLPkF076QOBSQwngM2jJVNvJ/wj0J+hLReeA1a9IEhYPHWt9Vb6uSTDpVruZI6I OR7JB8jWtQCg8qauiBte8fcMxy6C1sc7/c+LNrOBw8ElxPffjzVjeF+xyemuYubt5nulVT hnq+3CZuyiVAQuDx3gMaVOHKSCnQhdQE+rFBxppuVQ3vvYVPn9s0qRoRVjkCxWKyqG4h1L vUeIp0YwQaFjr8ebJyhVXbOOAUIZRuNBV/xuu/bCVhIC9fHa1po5uZ/I4xYbUjEKBz30j5 ST+LzsUQWgtRdLu3mcljg2sjWa+/5LVQgwPkNTkO+WE4vsqQmRXhkC9PZGuQO8ww== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=TDB1Rx9t; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=pGakznMY; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=uIbKli1Q gdyezVxeAX0vcwMYcv2NNPb0R3DxNFoBUhM=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=TDB1Rx9tMd3EVxnMiqaGV4sXFBHbnbSNyDd kQ7HoSJS3S+m9orNNTGE2QnY80CkO/OWAfI9O7WXDQN+PE7krdjT3H7HnMu4QTTwJEUHjE DNHUNIvHI39zILeLy83irWZaaJjAYIJEve/kwel+ieV4T6lOmXdU5T0FSB/1QEz3ob4Z5z CDkZuN+4uui184s/dmi68PAu2ysSSt60VpqPL6zhhDeQ9/XWdMaRV92uo6jLQwQHaIISo2 SK+13NuAjcdt4dCFOI5zXnKwP9YRzR+MpQJ+cxw2B8jmulZudGRoN8fmy5nCZbM23ze9Hg uZaACrXIYhmDJ+iUr6X9DZ7K9aA== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=uIbKli1QgdyezVxeAX0vcwMYcv2NNPb0R3DxNFoBUhM=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=pGakznMYFJlIASbLln VUneuqT0EVpzuArHAHpTgqgA7mhlvwZbqMvwWSihpHe5jblyXdBhQ6SQzlTuJJmg29CA== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 17/25] hw/mips: wire the Octeon UART Date: Wed, 15 Jul 2026 15:44:03 +0200 Message-ID: <20260715134447.56007-18-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f8:271:125e::2; envelope-from=kirill@korins.ky; helo=mx1.catap.net 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_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123179794158500 Content-Type: text/plain; charset="utf-8" Wire the Octeon UART and its alias to the existing serial-mm device. Provide the special transmit register window and connect the UART interrupt to CIU and CIU3. --- hw/mips/Kconfig | 1 + hw/mips/octeon.c | 69 +++++++++++++++++++++++++++++++++++++++ hw/mips/octeon_internal.h | 5 +++ 3 files changed, 75 insertions(+) diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index cb6057fe38..5fe5f885e3 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -72,6 +72,7 @@ config MIPS_OCTEON default y depends on MIPS64 && TARGET_BIG_ENDIAN select PFLASH_CFI02 + select SERIAL_MM =20 config MIPS_CPS bool diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 59754cb741..133b3636a0 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -10,6 +10,7 @@ #include "qemu/units.h" #include "qemu/datadir.h" #include "qapi/error.h" +#include "hw/char/serial-mm.h" #include "hw/core/clock.h" #include "hw/core/irq.h" #include "hw/core/boards.h" @@ -48,7 +49,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonIntcState, OCTEON_INTC) #define TYPE_OCTEON_CSR_BANK "octeon-csr-bank" OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_CSR_BANK) =20 +#define OCTEON_CSR_32BIT_SIZE 4 #define OCTEON_CSR_64BIT_SIZE 8 +#define OCTEON_CSR_HI32_OFFSET 0 =20 /* * Clock defaults follow a Ubiquiti E1000 EBB7304 U-Boot banner. @@ -155,6 +158,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_= CSR_BANK) #define OCTEON_RST_BOOT_C_MUL_SHIFT 30 #define OCTEON_RST_BOOT_PNR_MUL_SHIFT 24 =20 +#define OCTEON_UART0_BASE 0x1180000000800ULL +#define OCTEON_UART0_ALIAS_BASE 0x1180000000c00ULL +#define OCTEON_UART_TX_REG 0x40 +#define OCTEON_UART_TX_HI32_OFFSET OCTEON_CSR_HI32_OFFSET +#define OCTEON_UART_TX_SIZE OCTEON_CSR_64BIT_SIZE + /* * QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM; * the guest sees the virtual CVMSEG window, not this physical address. @@ -1613,6 +1622,65 @@ static void octeon_init_mio_boot_loc(OcteonState *s) } =20 =20 +static uint64_t octeon_uart_tx_read(void *opaque, hwaddr addr, unsigned si= ze) +{ + return 0; +} + +static void octeon_uart_tx_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonState *s =3D opaque; + + if (size =3D=3D OCTEON_CSR_32BIT_SIZE && + addr =3D=3D OCTEON_UART_TX_HI32_OFFSET) { + return; + } + + serial_io_ops.write(&s->uart->serial, 0, value & 0xff, 1); +} + +static const MemoryRegionOps octeon_uart_tx_ops =3D { + .read =3D octeon_uart_tx_read, + .write =3D octeon_uart_tx_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 8, + }, +}; + +static void octeon_init_uart(OcteonState *s) +{ + SerialMM *uart; + qemu_irq uart_irq; + MemoryRegion *uart_mmio; + int baudbase =3D s->io_hz / 16; + + uart_irq =3D qemu_allocate_irq(octeon_irq_set, s, OCTEON_IRQ_UART); + uart =3D serial_mm_init(get_system_memory(), OCTEON_UART0_BASE, 3, uar= t_irq, + baudbase, serial_hd(0), DEVICE_BIG_ENDIAN); + s->uart =3D uart; + + uart_mmio =3D sysbus_mmio_get_region(SYS_BUS_DEVICE(uart), 0); + memory_region_init_alias(&s->uart_alias, NULL, "octeon.uart0-alias", + uart_mmio, 0, memory_region_size(uart_mmio)); + memory_region_add_subregion(get_system_memory(), OCTEON_UART0_ALIAS_BA= SE, + &s->uart_alias); + + memory_region_init_io(&s->uart_tx, NULL, &octeon_uart_tx_ops, s, + "octeon.uart0-tx", OCTEON_UART_TX_SIZE); + memory_region_add_subregion(get_system_memory(), + OCTEON_UART0_BASE + OCTEON_UART_TX_REG, + &s->uart_tx); + memory_region_init_io(&s->uart_alias_tx, NULL, &octeon_uart_tx_ops, s, + "octeon.uart0-alias-tx", OCTEON_UART_TX_SIZE); + memory_region_add_subregion(get_system_memory(), + OCTEON_UART0_ALIAS_BASE + OCTEON_UART_TX_R= EG, + &s->uart_alias_tx); +} + + static void octeon_mio_reset_hold(Object *obj, ResetType type) { OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); @@ -1833,6 +1901,7 @@ static void mips_octeon_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), OCTEON_CIU3_BASE, &s->intc->ciu3); =20 + octeon_init_uart(s); memory_region_init_io(&s->csr_bank->csr, OBJECT(s->csr_bank), &octeon_csr_ops, s, "octeon.csr", OCTEON_CSR_SIZE); diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index 7b45daba10..fbe4875d66 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -10,6 +10,7 @@ #define HW_MIPS_OCTEON_INTERNAL_H =20 #include "qemu/typedefs.h" +#include "hw/char/serial-mm.h" #include "system/memory.h" #include "target/mips/cpu.h" =20 @@ -64,6 +65,10 @@ struct OcteonState { OcteonRstState *rst; OcteonIntcState *intc; OcteonCsrBankState *csr_bank; + SerialMM *uart; + MemoryRegion uart_alias; + MemoryRegion uart_tx; + MemoryRegion uart_alias_tx; }; =20 guint octeon_uint64_hash(gconstpointer v); --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123313235182.114634346485; Wed, 15 Jul 2026 06:48:33 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv7-0005al-Cu; Wed, 15 Jul 2026 09:45:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv5-0005ZV-Cb for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:03 -0400 Received: from mx2.catap.net ([65.21.79.163]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv2-0007uu-1q for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:03 -0400 Received: by mx2.catap.net (OpenSMTPD) with ESMTPSA id 0213ceac (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:54 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 8f4d265b; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=MYND/AO CdmhShqYb/T8htkPKKlRyUPRLXCfugBowCkqfIHBmy8hMuA171wyvL3ccIvA+BghahiNv5 0SPccyW1/aTxngYyNYxCrz0RsO3/TrOUzzCNiI7jWwLZhTg5/UH9BcXK3ZwPXeZP51sbw3 3JcG7NDe+srkV4LfTfEKDV+gV0LuRwKF8TqcuOFz207coNitLha2X6hHvBAobERpphIJf9 EKOjJyd/b3mb5q5ZOUEPN5D2MSSgW5onhXzhjZFLOJCNyk1bHI6cnxjENFGwfq2Npk2cnf e/c8XJgf9PI9Erpx8RCQPGwoWj9bdqsSBWs+frcjkDZWSlZbFldQJQQ== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=l 1ApWtYFrp90HENbzM+QkVvhKHLflprqYk7q0d8ZjnU=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=Xt/7xmg1W5pDfWb3/orlPdmW0Q2n10sHIJpEnStQmpA8Rn5pUX/JQ04sZUjgy/944ltv r4s8j0MO76KLkimDSGnS8LQkYFXsgfVFAUjKvo5213+arMFyksWaZXzQEAvJgDDeEGyFzR kODsxP1SXrpnPE9jyJGmE/s2cq9yNOup4mvwROJ2ZYNLjdYncKsg6W/2k8unJAIVbl5Upv yj1ags1fuB1CwK6Vh94NlmgjuYCv+PwXdWOcLtyt2TBGr0gygqclqL5HkLVQZ1yroAJS0N 7BXdR4H425Qw+8HA9E8DSKYkNN7ASr6k6Zf1gQR9CT4zkMM0e/lcciTg2gKNZHhw== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=cffvUjCD; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=Wbp/PO4D; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=l1ApWtYF rp90HENbzM+QkVvhKHLflprqYk7q0d8ZjnU=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=cffvUjCDjecIFtgnTK0ppsaIFOEAYNXnSpH 5dw1LmZ8rsgDyZikgIhjL5lApvTBBM+oVY3yGdDiVH18yxVswPncz8chw1PbVqQlaEpEjs aqG4kJ0KwxzYlMj79yF+SjB+EnByYzEJa8jASHa/qvVpuy6qqxs/Sgv5iNKEdbfUeHAOpq ejm46aLbvWvmQXuI+/J+Xow3gsywKPZJX3LdWt6WlnZm/WNYy4W2aWRi31awUSGuowXvWD DERlDuVzeYMy8632MbajwaCxlbgyG/PcEhdEi+jU9XgpFhxl15ON1hT6yohAPQumbcV8uD Ooey8N4EIguXePs1z7t/LvinGfQ== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=l1ApWtYFrp90HENbzM+QkVvhKHLflprqYk7q0d8ZjnU=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=Wbp/PO4DxWZNd9i7fM 4M0IM0JL4vQseZprzbnJxyI+4QaHxFc5N/EWyh9X91HsKYlWI8z/Q3BxgYGsGdn2GkCQ== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 18/25] hw/i2c: add Octeon TWSI controller Date: Wed, 15 Jul 2026 15:44:04 +0200 Message-ID: <20260715134447.56007-19-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=65.21.79.163; envelope-from=kirill@korins.ky; helo=mx2.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123314870158500 Content-Type: text/plain; charset="utf-8" Add the two Octeon TWSI controllers and a synthesized DDR4 SPD EEPROM. Derive the SPD geometry and timing from the configured RAM size and DDR clock, then wire both controller windows into the machine. --- hw/i2c/meson.build | 5 + hw/i2c/octeon_twsi.c | 553 ++++++++++++++++++++++++++++++++++++++ hw/mips/octeon.c | 8 +- hw/mips/octeon_internal.h | 11 + 4 files changed, 576 insertions(+), 1 deletion(-) create mode 100644 hw/i2c/octeon_twsi.c diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index 88aea35662..1c744768e4 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -20,3 +20,8 @@ i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mu= x_pca954x.c')) i2c_ss.add(when: 'CONFIG_PMBUS', if_true: files('pmbus_device.c')) i2c_ss.add(when: 'CONFIG_BCM2835_I2C', if_true: files('bcm2835_i2c.c')) system_ss.add_all(when: 'CONFIG_I2C', if_true: i2c_ss) + +if 'CONFIG_TCG' in config_all_accel + mips_ss.add(when: 'CONFIG_MIPS_OCTEON', + if_true: files('octeon_twsi.c')) +endif diff --git a/hw/i2c/octeon_twsi.c b/hw/i2c/octeon_twsi.c new file mode 100644 index 0000000000..3bc8bf7bcd --- /dev/null +++ b/hw/i2c/octeon_twsi.c @@ -0,0 +1,553 @@ +/* + * QEMU Cavium Octeon TWSI controller model. + * + * Copyright (c) 2026 Kirill A. Korinsky + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/host-utils.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/core/boards.h" +#include "hw/core/resettable.h" +#include "hw/core/sysbus.h" +#include "hw/mips/octeon_internal.h" +#include "qemu/module.h" + +#define OCTEON_TWSI_SIZE 0x200 +#define OCTEON_TWSI0_BASE 0x1180000001000ULL +#define OCTEON_TWSI1_BASE 0x1180000001200ULL +#define OCTEON_TWSI_SW_TWSI 0x00 +#define OCTEON_TWSI_INT 0x10 +#define OCTEON_TWSI_SW_DATA_MASK 0xffffffffULL +#define OCTEON_TWSI_SW_EOP_IA_SHIFT 32 +#define OCTEON_TWSI_SW_R (1ULL << 56) +#define OCTEON_TWSI_SW_OP_SHIFT 57 +#define OCTEON_TWSI_SW_V (1ULL << 63) +#define OCTEON_TWSI_OP_EOP_IA 6 +#define OCTEON_TWSI_EOP_DATA 1 +#define OCTEON_TWSI_EOP_CTL 2 +#define OCTEON_TWSI_EOP_STAT 3 +#define OCTEON_TWSI_CTL_AAK 0x04 +#define OCTEON_TWSI_CTL_IFLG 0x08 +#define OCTEON_TWSI_CTL_STP 0x10 +#define OCTEON_TWSI_CTL_STA 0x20 +#define OCTEON_TWSI_STAT_START 0x08 +#define OCTEON_TWSI_STAT_TXADDR_ACK 0x18 +#define OCTEON_TWSI_STAT_TXADDR_NAK 0x20 +#define OCTEON_TWSI_STAT_TXDATA_ACK 0x28 +#define OCTEON_TWSI_STAT_TXDATA_NAK 0x30 +#define OCTEON_TWSI_STAT_RXADDR_ACK 0x40 +#define OCTEON_TWSI_STAT_RXADDR_NAK 0x48 +#define OCTEON_TWSI_STAT_RXDATA_ACK 0x50 +#define OCTEON_TWSI_STAT_RXDATA_NAK 0x58 +#define OCTEON_SPD_BUS 1 +#define OCTEON_SPD_ADDR 0x50 +#define OCTEON_SPD_MIN_ROW_BITS 12 +#define OCTEON_SPD_MAX_ROW_BITS 18 +#define OCTEON_SPD_MIN_COL_BITS 9 +#define OCTEON_SPD_MAX_COL_BITS 10 +#define OCTEON_SPD_BANK_BITS 4 +#define OCTEON_SPD_MIN_RAM_SIZE \ + (1ULL << (OCTEON_SPD_MIN_ROW_BITS + OCTEON_SPD_MIN_COL_BITS + \ + OCTEON_SPD_BANK_BITS + 3)) +#define OCTEON_SPD_MAX_RAM_SIZE \ + (1ULL << (OCTEON_SPD_MAX_ROW_BITS + OCTEON_SPD_MAX_COL_BITS + \ + OCTEON_SPD_BANK_BITS + 3)) +#define OCTEON_SPD_DDR4_TCKMIN 18 +#define OCTEON_SPD_DDR4_FINE_TCKMIN 125 +#define OCTEON_SPD_DDR4_MTB_PS 125 +#define OCTEON_SPD_DDR4_FTB_PS 1 + +#define TYPE_OCTEON_TWSI "octeon-twsi" +OBJECT_DECLARE_TYPE(OcteonTWSIState, OcteonTWSIClass, OCTEON_TWSI) + +#define TYPE_OCTEON_SPD_EEPROM "octeon-spd-eeprom" +OBJECT_DECLARE_TYPE(OcteonSpdEepromState, OcteonSpdEepromClass, + OCTEON_SPD_EEPROM) + +struct OcteonTWSIState { + SysBusDevice parent_obj; + OcteonState *board; + MemoryRegion mmio; + unsigned int bus; + uint64_t sw_twsi; + uint64_t int_reg; + uint8_t ctl; + uint8_t stat; + uint8_t data; + uint8_t slave_addr; + uint8_t write_buf[2]; + unsigned int write_len; + bool have_slave; + bool read_transfer; + bool addr_phase; +}; + +struct OcteonTWSIClass { + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; +}; + +struct OcteonSpdEepromState { + SysBusDevice parent_obj; + unsigned int bus; + uint8_t addr; + uint16_t offset; + uint8_t data[OCTEON_SPD_EEPROM_SIZE]; +}; + +struct OcteonSpdEepromClass { + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; +}; + +static const uint8_t octeon_spd_eeprom_template[OCTEON_SPD_EEPROM_SIZE] = =3D { + [0] =3D 0x23, [1] =3D 0x11, [2] =3D 0x0c, [3] =3D 0x02, + [4] =3D 0x82, [5] =3D 0x19, [11] =3D 0x03, [12] =3D 0x01, + [13] =3D 0x03, [18] =3D 0x0a, [19] =3D 0x20, [20] =3D 0x78, + [24] =3D 0x6e, [25] =3D 0x6e, [26] =3D 0x6e, [27] =3D 0x11, + [29] =3D 0x6e, [31] =3D 0x05, [32] =3D 0x70, [33] =3D 0x03, + [34] =3D 0xd0, [35] =3D 0x02, [37] =3D 0xa8, [38] =3D 0x20, + [39] =3D 0x27, [40] =3D 0x28, [126] =3D 0x16, [127] =3D 0x2f, +}; + +static uint16_t octeon_spd_crc16(const uint8_t *ptr, int count) +{ + int crc =3D 0; + int i; + + while (--count >=3D 0) { + crc ^=3D *ptr++ << 8; + for (i =3D 0; i < 8; i++) { + if (crc & 0x8000) { + crc =3D (crc << 1) ^ 0x1021; + } else { + crc <<=3D 1; + } + } + } + + return crc & 0xffff; +} + +static bool octeon_spd_geometry(uint64_t ram_size, int *row_bits, + int *col_bits, int *density_code) +{ + uint64_t ram_mb; + int pbank_lsb; + int row_col_bits; + int col; + int row; + int density; + + if (ram_size < OCTEON_SPD_MIN_RAM_SIZE || + ram_size > OCTEON_SPD_MAX_RAM_SIZE || + !is_power_of_2(ram_size)) { + return false; + } + + ram_mb =3D ram_size / MiB; + pbank_lsb =3D ctz64(ram_size); + row_col_bits =3D pbank_lsb - 3 - OCTEON_SPD_BANK_BITS; + + col =3D MIN(OCTEON_SPD_MAX_COL_BITS, + row_col_bits - OCTEON_SPD_MIN_ROW_BITS); + col =3D MAX(OCTEON_SPD_MIN_COL_BITS, col); + row =3D row_col_bits - col; + density =3D ctz64(ram_mb) - 8; + + if (row < OCTEON_SPD_MIN_ROW_BITS || + row > OCTEON_SPD_MAX_ROW_BITS || + density < 0 || density > 7) { + return false; + } + + if (row_bits) { + *row_bits =3D row; + } + if (col_bits) { + *col_bits =3D col; + } + if (density_code) { + *density_code =3D density; + } + return true; +} + +void octeon_validate_ram_size(uint64_t ram_size) +{ + if (!octeon_spd_geometry(ram_size, NULL, NULL, NULL)) { + error_report("octeon3 RAM size must be a power of two from " + "%" PRIu64 " MB to %" PRIu64 " GB", + (uint64_t)OCTEON_SPD_MIN_RAM_SIZE / MiB, + (uint64_t)OCTEON_SPD_MAX_RAM_SIZE / GiB); + exit(1); + } +} + +static void octeon_spd_set_tckmin(OcteonState *s, uint8_t *spd) +{ + uint64_t tck_ps =3D (1000000000000ULL + s->ddr_hz - 1) / s->ddr_hz; + uint64_t mtb =3D tck_ps / OCTEON_SPD_DDR4_MTB_PS; + uint64_t fine =3D tck_ps % OCTEON_SPD_DDR4_MTB_PS; + + if (mtb =3D=3D 0 || mtb > UINT8_MAX || fine > INT8_MAX) { + error_report("octeon3 DDR clock cannot be represented in DDR4 SPD"= ); + exit(1); + } + + spd[OCTEON_SPD_DDR4_TCKMIN] =3D mtb; + spd[OCTEON_SPD_DDR4_FINE_TCKMIN] =3D fine / OCTEON_SPD_DDR4_FTB_PS; +} + +void octeon_init_spd(OcteonState *s) +{ + DeviceState *dev =3D qdev_new(TYPE_OCTEON_SPD_EEPROM); + OcteonSpdEepromState *eeprom =3D OCTEON_SPD_EEPROM(dev); + uint64_t ram_size =3D s->machine->ram_size; + int col_bits; + int row_bits; + int density_code; + uint16_t crc; + + s->spd[0] =3D eeprom; + eeprom->bus =3D OCTEON_SPD_BUS; + eeprom->addr =3D OCTEON_SPD_ADDR; + memcpy(eeprom->data, octeon_spd_eeprom_template, + sizeof(eeprom->data)); + + g_assert(octeon_spd_geometry(ram_size, &row_bits, &col_bits, + &density_code)); + + eeprom->data[4] =3D 0x80 | density_code; + eeprom->data[5] =3D ((row_bits - OCTEON_SPD_MIN_ROW_BITS) << 3) | + (col_bits - OCTEON_SPD_MIN_COL_BITS); + octeon_spd_set_tckmin(s, eeprom->data); + + crc =3D octeon_spd_crc16(eeprom->data, + (eeprom->data[0] & 0x80) ? 117 : 126); + eeprom->data[126] =3D crc & 0xff; + eeprom->data[127] =3D crc >> 8; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); +} + +static OcteonSpdEepromState *octeon_twsi_find_spd(OcteonTWSIState *t) +{ + OcteonState *s =3D t->board; + unsigned int i; + + for (i =3D 0; i < OCTEON_SPD_EEPROM_COUNT; i++) { + if (s->spd[i]->bus =3D=3D t->bus && + s->spd[i]->addr =3D=3D t->slave_addr) { + return s->spd[i]; + } + } + + return NULL; +} + +static uint8_t octeon_spd_eeprom_read(OcteonSpdEepromState *eeprom) +{ + uint8_t value =3D 0xff; + + if (eeprom->offset < sizeof(eeprom->data)) { + value =3D eeprom->data[eeprom->offset]; + } + eeprom->offset++; + return value; +} + +static void octeon_twsi_write_ctl(OcteonTWSIState *t, uint8_t value) +{ + OcteonSpdEepromState *eeprom; + + t->ctl =3D value | OCTEON_TWSI_CTL_IFLG; + + if (value & OCTEON_TWSI_CTL_STA) { + t->have_slave =3D false; + t->addr_phase =3D false; + t->write_len =3D 0; + t->stat =3D OCTEON_TWSI_STAT_START; + } else if (value & OCTEON_TWSI_CTL_STP) { + t->have_slave =3D false; + t->addr_phase =3D false; + t->stat =3D OCTEON_TWSI_STAT_IDLE; + } else if (t->addr_phase) { + eeprom =3D octeon_twsi_find_spd(t); + t->addr_phase =3D false; + if (eeprom) { + t->stat =3D t->read_transfer ? OCTEON_TWSI_STAT_RXADDR_ACK : + OCTEON_TWSI_STAT_TXADDR_ACK; + } else { + t->stat =3D t->read_transfer ? OCTEON_TWSI_STAT_RXADDR_NAK : + OCTEON_TWSI_STAT_TXADDR_NAK; + } + } else if (t->read_transfer) { + t->stat =3D (value & OCTEON_TWSI_CTL_AAK) ? + OCTEON_TWSI_STAT_RXDATA_ACK : OCTEON_TWSI_STAT_RXDATA_NA= K; + } else { + t->stat =3D octeon_twsi_find_spd(t) ? OCTEON_TWSI_STAT_TXDATA_ACK : + OCTEON_TWSI_STAT_TXDATA_NAK; + } +} + +static void octeon_twsi_write_data(OcteonTWSIState *t, uint8_t value) +{ + OcteonSpdEepromState *eeprom; + + t->data =3D value; + + if (!t->have_slave) { + t->slave_addr =3D value >> 1; + t->read_transfer =3D value & 1; + t->have_slave =3D true; + t->addr_phase =3D true; + t->write_len =3D 0; + return; + } + + if (!t->read_transfer && t->write_len < ARRAY_SIZE(t->write_buf)) { + t->write_buf[t->write_len++] =3D value; + eeprom =3D octeon_twsi_find_spd(t); + if (eeprom) { + if (t->write_len =3D=3D 1) { + eeprom->offset =3D value; + } else if (t->write_len =3D=3D ARRAY_SIZE(t->write_buf)) { + eeprom->offset =3D (t->write_buf[0] << 8) | t->write_buf[1= ]; + } + } + } +} + +static uint8_t octeon_twsi_read_reg(OcteonTWSIState *t, unsigned int reg) +{ + switch (reg) { + case OCTEON_TWSI_EOP_DATA: + if (t->read_transfer) { + OcteonSpdEepromState *eeprom =3D octeon_twsi_find_spd(t); + + t->data =3D eeprom ? octeon_spd_eeprom_read(eeprom) : 0xff; + } + return t->data; + case OCTEON_TWSI_EOP_CTL: + return t->ctl; + case OCTEON_TWSI_EOP_STAT: + return t->stat; + default: + return 0; + } +} + +static void octeon_twsi_write_reg(OcteonTWSIState *t, unsigned int reg, + uint8_t value) +{ + switch (reg) { + case OCTEON_TWSI_EOP_DATA: + octeon_twsi_write_data(t, value); + break; + case OCTEON_TWSI_EOP_CTL: + octeon_twsi_write_ctl(t, value); + break; + default: + break; + } +} + +static uint64_t octeon_twsi_exec(OcteonTWSIState *t, uint64_t value) +{ + unsigned int op =3D (value >> OCTEON_TWSI_SW_OP_SHIFT) & 0xf; + unsigned int reg =3D (value >> OCTEON_TWSI_SW_EOP_IA_SHIFT) & 0x7; + + if (!(value & OCTEON_TWSI_SW_V)) { + return value; + } + + if (op =3D=3D OCTEON_TWSI_OP_EOP_IA) { + if (value & OCTEON_TWSI_SW_R) { + value &=3D ~OCTEON_TWSI_SW_DATA_MASK; + value |=3D octeon_twsi_read_reg(t, reg); + } else { + octeon_twsi_write_reg(t, reg, value & 0xff); + } + } + + return value & ~OCTEON_TWSI_SW_V; +} + +static uint64_t octeon_twsi_read(void *opaque, hwaddr addr, unsigned size) +{ + OcteonTWSIState *t =3D opaque; + hwaddr reg =3D addr & ~7ULL; + + switch (reg) { + case OCTEON_TWSI_SW_TWSI: + return octeon_read64(t->sw_twsi, addr, size); + case OCTEON_TWSI_INT: + return octeon_read64(t->int_reg, addr, size); + default: + return 0; + } +} + +static void octeon_twsi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonTWSIState *t =3D opaque; + hwaddr reg =3D addr & ~7ULL; + uint64_t old =3D 0; + + switch (reg) { + case OCTEON_TWSI_SW_TWSI: + old =3D t->sw_twsi; + value =3D octeon_write64(old, addr, value, size); + if (size =3D=3D 4 && !(addr & 4)) { + t->sw_twsi =3D value; + } else { + t->sw_twsi =3D octeon_twsi_exec(t, value); + } + break; + case OCTEON_TWSI_INT: + old =3D t->int_reg; + t->int_reg =3D octeon_write64(old, addr, value, size); + break; + default: + break; + } +} + +static const MemoryRegionOps octeon_twsi_ops =3D { + .read =3D octeon_twsi_read, + .write =3D octeon_twsi_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + +static void octeon_twsi_reset_hold(Object *obj, ResetType type) +{ + OcteonTWSIState *t =3D OCTEON_TWSI(obj); + OcteonTWSIClass *otc =3D OCTEON_TWSI_GET_CLASS(obj); + + if (otc->parent_phases.hold) { + otc->parent_phases.hold(obj, type); + } + + t->sw_twsi =3D 0; + t->int_reg =3D 0; + t->ctl =3D 0; + t->stat =3D OCTEON_TWSI_STAT_IDLE; + t->data =3D 0; + t->slave_addr =3D 0; + t->write_len =3D 0; + t->have_slave =3D false; + t->read_transfer =3D false; + t->addr_phase =3D false; + memset(t->write_buf, 0, sizeof(t->write_buf)); +} + +static void octeon_spd_eeprom_reset_hold(Object *obj, ResetType type) +{ + OcteonSpdEepromState *eeprom =3D OCTEON_SPD_EEPROM(obj); + OcteonSpdEepromClass *osec =3D OCTEON_SPD_EEPROM_GET_CLASS(obj); + + if (osec->parent_phases.hold) { + osec->parent_phases.hold(obj, type); + } + + eeprom->offset =3D 0; +} + +static void octeon_twsi_realize(DeviceState *dev, Error **errp) +{ + static const char *const name[OCTEON_TWSI_COUNT] =3D { + "octeon.twsi0", + "octeon.twsi1", + }; + OcteonTWSIState *t =3D OCTEON_TWSI(dev); + + memory_region_init_io(&t->mmio, OBJECT(dev), &octeon_twsi_ops, t, + name[t->bus], OCTEON_TWSI_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &t->mmio); +} + +static void octeon_twsi_init(Object *obj) +{ + OcteonTWSIState *t =3D OCTEON_TWSI(obj); + + t->stat =3D OCTEON_TWSI_STAT_IDLE; +} + +static void octeon_twsi_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + OcteonTWSIClass *otc =3D OCTEON_TWSI_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + dc->realize =3D octeon_twsi_realize; + dc->user_creatable =3D false; + resettable_class_set_parent_phases(rc, NULL, octeon_twsi_reset_hold, N= ULL, + &otc->parent_phases); +} + +static void octeon_spd_eeprom_class_init(ObjectClass *klass, + const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + OcteonSpdEepromClass *osec =3D OCTEON_SPD_EEPROM_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + dc->user_creatable =3D false; + resettable_class_set_parent_phases(rc, NULL, + octeon_spd_eeprom_reset_hold, NULL, + &osec->parent_phases); +} + +static const TypeInfo octeon_twsi_type_info =3D { + .name =3D TYPE_OCTEON_TWSI, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(OcteonTWSIState), + .instance_init =3D octeon_twsi_init, + .class_size =3D sizeof(OcteonTWSIClass), + .class_init =3D octeon_twsi_class_init, +}; + +static const TypeInfo octeon_spd_eeprom_type_info =3D { + .name =3D TYPE_OCTEON_SPD_EEPROM, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(OcteonSpdEepromState), + .class_size =3D sizeof(OcteonSpdEepromClass), + .class_init =3D octeon_spd_eeprom_class_init, +}; + +static void octeon_twsi_register_types(void) +{ + type_register_static(&octeon_twsi_type_info); + type_register_static(&octeon_spd_eeprom_type_info); +} + +type_init(octeon_twsi_register_types) + +void octeon_init_twsi(OcteonState *s) +{ + static const uint64_t base[OCTEON_TWSI_COUNT] =3D { + OCTEON_TWSI0_BASE, + OCTEON_TWSI1_BASE, + }; + unsigned int i; + + for (i =3D 0; i < OCTEON_TWSI_COUNT; i++) { + DeviceState *dev =3D qdev_new(TYPE_OCTEON_TWSI); + OcteonTWSIState *t =3D OCTEON_TWSI(dev); + + t->board =3D s; + t->bus =3D i; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base[i]); + } +} diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 133b3636a0..9388bc005b 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -64,7 +64,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_CSR= _BANK) =20 /* * The physical layout follows U-Boot's generic Octeon III - * OCTEON_MAX_PHY_MEM_SIZE value. Keep 1 GiB as the tested default. + * OCTEON_MAX_PHY_MEM_SIZE value. The synthesized DDR4 SPD below accepts + * power-of-two RAM sizes from 256 MiB through 32 GiB. Keep 1 GiB as the + * tested default. */ #define OCTEON_DEFAULT_RAM_SIZE (1 * GiB) #define OCTEON_MAX_PHY_MEM_SIZE (512 * GiB) @@ -1884,6 +1886,8 @@ static void mips_octeon_init(MachineState *machine) exit(1); } =20 + octeon_validate_ram_size(machine->ram_size); + octeon_init_spd(s); octeon_map_ram(s); octeon_init_flash(s); octeon_init_mio_boot_loc(s); @@ -1902,6 +1906,8 @@ static void mips_octeon_init(MachineState *machine) &s->intc->ciu3); =20 octeon_init_uart(s); + octeon_init_twsi(s); + memory_region_init_io(&s->csr_bank->csr, OBJECT(s->csr_bank), &octeon_csr_ops, s, "octeon.csr", OCTEON_CSR_SIZE); diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index fbe4875d66..e9826f1713 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -20,6 +20,10 @@ #define OCTEON_CIU3_IDT_COUNT (OCTEON_MAX_CPUS * 4) #define OCTEON_MIO_BOOT_REG_CFG_COUNT 8 #define OCTEON_MIO_BOOT_LOC_SIZE 0x100 +#define OCTEON_TWSI_COUNT 2 +#define OCTEON_TWSI_STAT_IDLE 0xf8 +#define OCTEON_SPD_EEPROM_SIZE 139 +#define OCTEON_SPD_EEPROM_COUNT 1 =20 typedef enum OcteonIRQ { OCTEON_IRQ_UART, @@ -44,6 +48,8 @@ typedef struct OcteonCPUState { bool boot_cpu; } OcteonCPUState; =20 +typedef struct OcteonSpdEepromState OcteonSpdEepromState; + struct OcteonState { MachineState *machine; Clock *cpuclk; @@ -65,6 +71,7 @@ struct OcteonState { OcteonRstState *rst; OcteonIntcState *intc; OcteonCsrBankState *csr_bank; + OcteonSpdEepromState *spd[OCTEON_SPD_EEPROM_COUNT]; SerialMM *uart; MemoryRegion uart_alias; MemoryRegion uart_tx; @@ -81,4 +88,8 @@ void octeon_reg_store(GHashTable *regs, uint64_t reg, uin= t64_t value); bool octeon_csr_lookup(OcteonState *s, uint64_t reg, uint64_t *value); void octeon_irq_set(void *opaque, int irq, int level); =20 +void octeon_validate_ram_size(uint64_t ram_size); +void octeon_init_spd(OcteonState *s); +void octeon_init_twsi(OcteonState *s); + #endif --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123313626810.6596027081753; Wed, 15 Jul 2026 06:48:33 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvH-0005mv-BU; Wed, 15 Jul 2026 09:45:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzvB-0005fv-Jd for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:09 -0400 Received: from mx1.catap.net ([2a01:4f8:271:125e::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv8-0007u3-AO for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:09 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 344c2373 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:54 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 648e2674; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=hj8o81J Az+lFeDg9Hw0AVQkdXhayeL416g2ZvNb9EVmgQSnQzirewfULW58sB2dnbz2YpELv7n3KN zIpFlK8WfsrJHzwsCAODIgHcjUsEQajGzKwWK3ynd2SfFOwj6CuuYee6B+PSDheO1b/Umz IygkE14KpshIC6vmtJ+PfRFdOkkGNgXEJvQvOILsbQ/XRDZEnAFtlkxXd/Rcmb8v928V+I EiHVW+4EGVZgDmeZYKQGBBMzKniMzLEk9s5RsSSfgRIURy9HMtBczZPp/axpWMaMyUM30A rWKho43LegiMLoBArbHox2PzXYsSBjiwq9RgZjluNigFZ7KgrKK1mlw== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=T 83KjRMPwEB60hcJxPyJCUZ5ORywQwL0Np4xoSTiMHc=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=TyPN6IkXgC4Hb9m8CBG3cZEY0zX8hmzQUMHK8bU2VtS754vcZL/iUudFmRzOBh03rmK5 7GRowYc/HcYVAYKJ1ptZkmt7Rw4JgahqEhaxSuUgkd2cXgf7/3IBVyRbtA2aNn+DYVWJiJ PIMcIHGL18lnKS/V2zZDv7Z7+iqcHfgT+Tl/AmjchSuNtCIqbXXcKsYvBIRH8AdfM/AGMb dBjRK9mbawisGDj8l/K1x2cG9SdWPtIMx50uKLxo+IeRmIxTS5rUTgoFWHd9yQ8S58CcAG tXOQXgm6N61b0srEOzAhvzZa6T9+IMVLS5dSTGhbqXQkQ33o7/TD/HITYmE43+DA== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=uCEvvSeN; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=rNgfnbTP; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=T83KjRMP wEB60hcJxPyJCUZ5ORywQwL0Np4xoSTiMHc=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=uCEvvSeNJQluBchv76AF546R7PL19pjeQCH ikA3xsdLEVnbO3jpx17l+cKU/YkiNKYBbv3MDfvASotdq9BrqcBTJ3nWTkiop7ZSyBl5pz g4C1OUDHUZVOkjDVRMGIIg9fg1psnI3JeSv+SeARmQQHNWQPK8yPxYto3n2z8S250J2Abk JGKCsKPEDkOG2vYtVXvUvaDSDOZWIIU8PSLMujyy/oAhf1HZKSn+4DgCeywhdhecaw747T 4Aqb7oR4rbiEvQj7yq8300oy7kEX1UHPlx4f7Xqmnp3986YkhnVlS7nxN7wgw6s7X5olJz w08rAczeT92VXdJ9j6EpzstVCFw== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=T83KjRMPwEB60hcJxPyJCUZ5ORywQwL0Np4xoSTiMHc=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=rNgfnbTPb8j65/yiJe lXEXEFIbI6HvA2BfQAKF9m7V/xB+0LztGQzgGfHUdP8UVHRKDBAVrewtG7jgpyODPgCw== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 19/25] hw/mips: add Octeon EMM controller Date: Wed, 15 Jul 2026 15:44:05 +0200 Message-ID: <20260715134447.56007-20-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f8:271:125e::2; envelope-from=kirill@korins.ky; helo=mx1.catap.net 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_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123314794158500 Content-Type: text/plain; charset="utf-8" Model the Octeon EMM command, DMA, switch and buffer registers needed by firmware MMC initialization. Give the controller its own reset state and route its registers through the shared CSR window. --- hw/mips/octeon.c | 491 ++++++++++++++++++++++++++++++++++++++ hw/mips/octeon_internal.h | 3 + 2 files changed, 494 insertions(+) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 9388bc005b..f3f8a74cbe 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/datadir.h" +#include "qemu/host-utils.h" #include "qapi/error.h" #include "hw/char/serial-mm.h" #include "hw/core/clock.h" @@ -42,6 +43,8 @@ OBJECT_DECLARE_TYPE(OcteonPeripheralState, OcteonPeripher= alClass, =20 #define TYPE_OCTEON_MIO "octeon-mio" OBJECT_DECLARE_SIMPLE_TYPE(OcteonMioState, OCTEON_MIO) +#define TYPE_OCTEON_EMM "octeon-emm" +OBJECT_DECLARE_SIMPLE_TYPE(OcteonEmmState, OCTEON_EMM) #define TYPE_OCTEON_RST "octeon-rst" OBJECT_DECLARE_SIMPLE_TYPE(OcteonRstState, OCTEON_RST) #define TYPE_OCTEON_INTC "octeon-intc" @@ -52,6 +55,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_CSR= _BANK) #define OCTEON_CSR_32BIT_SIZE 4 #define OCTEON_CSR_64BIT_SIZE 8 #define OCTEON_CSR_HI32_OFFSET 0 +#define OCTEON_CSR_LO32_OFFSET 4 =20 /* * Clock defaults follow a Ubiquiti E1000 EBB7304 U-Boot banner. @@ -153,6 +157,88 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_= CSR_BANK) #define OCTEON_MIO_FUS_RCMD 0x0001500 #define OCTEON_MIO_FUS_RCMD_PEND 0x0000000000001000ULL #define OCTEON_MIO_FUS_RCMD_DAT 0x0000000000ff0000ULL +#define OCTEON_MIO_EMM_DMA_FIFO_CFG 0x0000160 +#define OCTEON_MIO_EMM_DMA_FIFO_ADR 0x0000170 +#define OCTEON_MIO_EMM_DMA_FIFO_CMD 0x0000178 +#define OCTEON_MIO_EMM_DMA_CFG 0x0000180 +#define OCTEON_MIO_EMM_DMA_ADR 0x0000188 +#define OCTEON_MIO_EMM_DMA_INT 0x0000190 +#define OCTEON_MIO_EMM_CFG 0x0002000 +#define OCTEON_MIO_EMM_MODEX(x) \ + (0x0002008 + (x) * OCTEON_CSR_64BIT_SIZE) +#define OCTEON_MIO_EMM_MODE_COUNT 4 +#define OCTEON_MIO_EMM_INT_EN_OLD 0x0002040 +#define OCTEON_MIO_EMM_SWITCH 0x0002048 +#define OCTEON_MIO_EMM_DMA 0x0002050 +#define OCTEON_MIO_EMM_CMD 0x0002058 +#define OCTEON_MIO_EMM_RSP_STS 0x0002060 +#define OCTEON_MIO_EMM_RSP_LO 0x0002068 +#define OCTEON_MIO_EMM_RSP_HI 0x0002070 +#define OCTEON_MIO_EMM_INT 0x0002078 +#define OCTEON_MIO_EMM_WDOG 0x0002088 +#define OCTEON_MIO_EMM_SAMPLE 0x0002090 +#define OCTEON_MIO_EMM_STS_MASK 0x0002098 +#define OCTEON_MIO_EMM_RCA 0x00020a0 +#define OCTEON_MIO_EMM_BUF_IDX 0x00020e0 +#define OCTEON_MIO_EMM_BUF_DAT 0x00020e8 +#define OCTEON_MIO_EMM_DEBUG 0x00020f8 +#define OCTEON_MIO_EMM_NODE_OFFSET 0x0002000 +#define OCTEON_MIO_EMM_CMD_VAL (1ULL << 59) +#define OCTEON_MIO_EMM_DMA_VAL (1ULL << 59) +#define OCTEON_MIO_EMM_DMA_BLOCK_CNT_SHIFT 32 +#define OCTEON_MIO_EMM_DMA_BLOCK_CNT_MASK \ + (0xffffULL << OCTEON_MIO_EMM_DMA_BLOCK_CNT_SHIFT) +#define OCTEON_MIO_EMM_SWITCH_EXE (1ULL << 59) +#define OCTEON_MIO_EMM_CMD_IDX_SHIFT 32 +#define OCTEON_MIO_EMM_CMD_IDX_BITS 6 +#define OCTEON_MIO_EMM_CMD_IDX_MASK \ + ((1U << OCTEON_MIO_EMM_CMD_IDX_BITS) - 1) +#define OCTEON_MIO_EMM_CMD_BUS_ID_SHIFT 60 +#define OCTEON_MIO_EMM_BUS_ID_MASK (OCTEON_MIO_EMM_MODE_COUNT - 1) +#define OCTEON_MIO_EMM_RSP_STS_CMD_DONE (1ULL << 0) +#define OCTEON_MIO_EMM_RSP_STS_CMD_IDX_SHIFT 1 +#define OCTEON_MIO_EMM_RSP_STS_RSP_TIMEOUT (1ULL << 13) +#define OCTEON_MIO_EMM_RSP_STS_DMA_VAL (1ULL << 57) +#define OCTEON_MIO_EMM_RSP_STS_DMA_PEND (1ULL << 56) +#define OCTEON_MIO_EMM_RSP_STS_BUS_ID_SHIFT 60 +#define OCTEON_MIO_EMM_DMA_INT_DONE (1ULL << 0) +#define OCTEON_MIO_EMM_INT_CMD_DONE (1ULL << 1) +#define OCTEON_MIO_EMM_INT_CMD_ERR (1ULL << 3) +#define OCTEON_MIO_EMM_INT_DMA_DONE (1ULL << 2) +#define OCTEON_MIO_EMM_INT_DMA_ERR (1ULL << 4) +#define OCTEON_MIO_EMM_INT_SWITCH_DONE (1ULL << 5) +#define OCTEON_MIO_EMM_INT_SWITCH_ERR (1ULL << 6) +#define OCTEON_MIO_EMM_SWITCH_MODE_MASK ((1ULL << 49) - 1) +#define OCTEON_MIO_EMM_CFG_BUS_EN_MASK \ + ((1ULL << OCTEON_MIO_EMM_MODE_COUNT) - 1) +#define OCTEON_MIO_EMM_LOW_SPEED_HZ 400000 +#define OCTEON_MIO_EMM_MODE_CLK_LO_MASK 0x000000000000ffffULL +#define OCTEON_MIO_EMM_MODE_CLK_HI_MASK 0x00000000ffff0000ULL +#define OCTEON_MIO_EMM_MODE_CLK_HI_SHIFT 16 +#define OCTEON_MIO_EMM_BUF_IDX_INC (1ULL << 16) +#define OCTEON_MIO_EMM_BUF_WORD_SIZE OCTEON_CSR_64BIT_SIZE +#define OCTEON_MIO_EMM_BUF_ENTRY_COUNT \ + (OCTEON_MIO_EMM_BUF_SIZE / OCTEON_MIO_EMM_BUF_WORD_SIZE) +#define OCTEON_MIO_EMM_BUF_IDX_OFF_MASK \ + (OCTEON_MIO_EMM_BUF_ENTRY_COUNT - 1) +#define OCTEON_MMC_CMD_GO_IDLE_STATE 0 +#define OCTEON_MMC_CMD_BUSTEST_R 14 +#define OCTEON_MMC_CMD_BUSTEST_W 19 +/* SD/MMC CMD19 request patterns and CMD14 response patterns. */ +#define OCTEON_MMC_BUSTEST_8_REQ0 0x55 +#define OCTEON_MMC_BUSTEST_8_REQ1 0xaa +#define OCTEON_MMC_BUSTEST_8_RESP0 0xaa +#define OCTEON_MMC_BUSTEST_8_RESP1 0x55 +#define OCTEON_MMC_BUSTEST_4_REQ0 0x5a +#define OCTEON_MMC_BUSTEST_4_REQ4 0x99 +#define OCTEON_MMC_BUSTEST_4_REQ5 0x50 +#define OCTEON_MMC_BUSTEST_4_REQ6 0x0f +#define OCTEON_MMC_BUSTEST_4_RESP0 0xa5 +#define OCTEON_MMC_BUSTEST_1_REQ0 0x80 +#define OCTEON_MMC_BUSTEST_1_REQ1 0x70 +#define OCTEON_MMC_BUSTEST_1_REQ2 0x78 +#define OCTEON_MMC_BUSTEST_1_REQ3 0x01 +#define OCTEON_MMC_BUSTEST_1_RESP0 0x40 #define OCTEON_RST_BOOT 0x6001600 #define OCTEON_RST_SOFT_RST 0x6001680 /* U-Boot uses the reset controller to park and release secondary cores. */ @@ -226,6 +312,19 @@ struct OcteonMioState { bool bootbus_led_mapped; }; =20 +struct OcteonEmmState { + OcteonPeripheralState parent_obj; + GHashTable *regs; + uint64_t mio_emm_rsp_sts; + uint64_t mio_emm_rsp_lo; + uint64_t mio_emm_rsp_hi; + uint64_t mio_emm_int; + uint64_t mio_emm_dma_int; + uint16_t mio_emm_buf_idx; + bool mio_emm_buf_inc; + uint8_t mio_emm_buf[OCTEON_MIO_EMM_BUF_SIZE]; +}; + struct OcteonRstState { OcteonPeripheralState parent_obj; GHashTable *regs; @@ -353,8 +452,15 @@ void octeon_reg_store(GHashTable *regs, uint64_t reg, = uint64_t value) g_hash_table_replace(regs, key, stored); } =20 +static bool octeon_mio_emm_decode(hwaddr reg, hwaddr *ereg); + bool octeon_csr_lookup(OcteonState *s, uint64_t reg, uint64_t *value) { + hwaddr ereg; + + if (octeon_mio_emm_decode(reg, &ereg)) { + return octeon_reg_lookup(s->emm->regs, ereg, value); + } if (reg =3D=3D OCTEON_RST_SOFT_RST) { return octeon_reg_lookup(s->rst->regs, reg, value); } @@ -363,6 +469,12 @@ bool octeon_csr_lookup(OcteonState *s, uint64_t reg, u= int64_t *value) =20 static void octeon_csr_store(OcteonState *s, uint64_t reg, uint64_t value) { + hwaddr ereg; + + if (octeon_mio_emm_decode(reg, &ereg)) { + octeon_reg_store(s->emm->regs, ereg, value); + return; + } if (reg =3D=3D OCTEON_RST_SOFT_RST) { octeon_reg_store(s->rst->regs, reg, value); return; @@ -453,6 +565,325 @@ static void octeon_mio_boot_loc_dat_write(OcteonState= *s, hwaddr addr, OCTEON_MIO_BOOT_LOC_ADR_MASK; } =20 +static bool octeon_mio_emm_valid_reg(hwaddr reg) +{ + if (reg >=3D OCTEON_MIO_EMM_MODEX(0) && + reg < OCTEON_MIO_EMM_MODEX(OCTEON_MIO_EMM_MODE_COUNT) && + (reg & (OCTEON_CSR_64BIT_SIZE - 1)) =3D=3D 0) { + return true; + } + + switch (reg) { + case OCTEON_MIO_EMM_DMA_INT: + case OCTEON_MIO_EMM_CFG: + case OCTEON_MIO_EMM_SWITCH: + case OCTEON_MIO_EMM_DMA: + case OCTEON_MIO_EMM_CMD: + case OCTEON_MIO_EMM_RSP_STS: + case OCTEON_MIO_EMM_INT: + case OCTEON_MIO_EMM_DMA_FIFO_CFG: + case OCTEON_MIO_EMM_DMA_FIFO_ADR: + case OCTEON_MIO_EMM_DMA_FIFO_CMD: + case OCTEON_MIO_EMM_DMA_CFG: + case OCTEON_MIO_EMM_DMA_ADR: + case OCTEON_MIO_EMM_INT_EN_OLD: + case OCTEON_MIO_EMM_RSP_LO: + case OCTEON_MIO_EMM_RSP_HI: + case OCTEON_MIO_EMM_WDOG: + case OCTEON_MIO_EMM_SAMPLE: + case OCTEON_MIO_EMM_STS_MASK: + case OCTEON_MIO_EMM_RCA: + case OCTEON_MIO_EMM_BUF_IDX: + case OCTEON_MIO_EMM_BUF_DAT: + case OCTEON_MIO_EMM_DEBUG: + return true; + default: + return false; + } +} + +static bool octeon_mio_emm_decode(hwaddr reg, hwaddr *ereg) +{ + if (octeon_mio_emm_valid_reg(reg)) { + *ereg =3D reg; + return true; + } + + reg -=3D OCTEON_MIO_EMM_NODE_OFFSET; + if (octeon_mio_emm_valid_reg(reg)) { + *ereg =3D reg; + return true; + } + + return false; +} + +static bool octeon_mio_emm_execute_write(hwaddr addr, unsigned size) +{ + return size =3D=3D OCTEON_CSR_64BIT_SIZE || + (size =3D=3D OCTEON_CSR_32BIT_SIZE && + (addr & OCTEON_CSR_LO32_OFFSET)); +} + +static void octeon_mio_emm_set_low_speed_mode(OcteonState *s, + unsigned int bus_id) +{ + uint64_t period =3D DIV_ROUND_UP(s->io_hz, OCTEON_MIO_EMM_LOW_SPEED_HZ= ); + uint64_t value; + + period =3D MIN(period, UINT16_MAX); + if (!octeon_csr_lookup(s, OCTEON_MIO_EMM_MODEX(bus_id), &value)) { + value =3D 0; + } + + value &=3D ~(OCTEON_MIO_EMM_MODE_CLK_LO_MASK | + OCTEON_MIO_EMM_MODE_CLK_HI_MASK); + value |=3D period | (period << OCTEON_MIO_EMM_MODE_CLK_HI_SHIFT); + octeon_csr_store(s, OCTEON_MIO_EMM_MODEX(bus_id), value); +} + +static void octeon_mio_emm_set_bustest(OcteonState *s) +{ + const uint8_t *buf =3D s->emm->mio_emm_buf; + bool bus8 =3D buf[0] =3D=3D OCTEON_MMC_BUSTEST_8_REQ0 && + buf[1] =3D=3D OCTEON_MMC_BUSTEST_8_REQ1; + bool bus4 =3D buf[0] =3D=3D OCTEON_MMC_BUSTEST_4_REQ0 && + buf[4] =3D=3D OCTEON_MMC_BUSTEST_4_REQ4 && + buf[5] =3D=3D OCTEON_MMC_BUSTEST_4_REQ5 && + buf[6] =3D=3D OCTEON_MMC_BUSTEST_4_REQ6; + bool bus1 =3D buf[0] =3D=3D OCTEON_MMC_BUSTEST_1_REQ0 && + buf[1] =3D=3D OCTEON_MMC_BUSTEST_1_REQ1 && + buf[2] =3D=3D OCTEON_MMC_BUSTEST_1_REQ2 && + buf[3] =3D=3D OCTEON_MMC_BUSTEST_1_REQ3; + + memset(s->emm->mio_emm_buf, 0, sizeof(s->emm->mio_emm_buf)); + if (bus8) { + s->emm->mio_emm_buf[0] =3D OCTEON_MMC_BUSTEST_8_RESP0; + s->emm->mio_emm_buf[1] =3D OCTEON_MMC_BUSTEST_8_RESP1; + } else if (bus4) { + s->emm->mio_emm_buf[0] =3D OCTEON_MMC_BUSTEST_4_RESP0; + } else if (bus1) { + s->emm->mio_emm_buf[0] =3D OCTEON_MMC_BUSTEST_1_RESP0; + } +} + +static void octeon_mio_emm_complete_dma(OcteonState *s, uint64_t dma) +{ + dma &=3D ~(OCTEON_MIO_EMM_DMA_VAL | OCTEON_MIO_EMM_DMA_BLOCK_CNT_MASK); + octeon_csr_store(s, OCTEON_MIO_EMM_DMA, dma); + s->emm->mio_emm_rsp_sts &=3D ~(OCTEON_MIO_EMM_RSP_STS_DMA_VAL | + OCTEON_MIO_EMM_RSP_STS_DMA_PEND); + s->emm->mio_emm_dma_int |=3D OCTEON_MIO_EMM_DMA_INT_DONE; + s->emm->mio_emm_int |=3D OCTEON_MIO_EMM_INT_DMA_DONE; +} + +static void octeon_mio_emm_command(OcteonState *s, uint64_t cmd) +{ + unsigned int cmd_idx =3D (cmd >> OCTEON_MIO_EMM_CMD_IDX_SHIFT) & + OCTEON_MIO_EMM_CMD_IDX_MASK; + unsigned int bus_id =3D (cmd >> OCTEON_MIO_EMM_CMD_BUS_ID_SHIFT) & + OCTEON_MIO_EMM_BUS_ID_MASK; + + s->emm->mio_emm_rsp_lo =3D 0; + s->emm->mio_emm_rsp_hi =3D 0; + s->emm->mio_emm_rsp_sts =3D + OCTEON_MIO_EMM_RSP_STS_CMD_DONE | + ((uint64_t)cmd_idx << OCTEON_MIO_EMM_RSP_STS_CMD_IDX_SHIFT) | + ((uint64_t)bus_id << OCTEON_MIO_EMM_RSP_STS_BUS_ID_SHIFT); + + switch (cmd_idx) { + case OCTEON_MMC_CMD_GO_IDLE_STATE: + case OCTEON_MMC_CMD_BUSTEST_W: + break; + case OCTEON_MMC_CMD_BUSTEST_R: + octeon_mio_emm_set_bustest(s); + break; + default: + s->emm->mio_emm_rsp_sts |=3D OCTEON_MIO_EMM_RSP_STS_RSP_TIMEOUT; + break; + } + + s->emm->mio_emm_int |=3D OCTEON_MIO_EMM_INT_CMD_DONE; + if (s->emm->mio_emm_rsp_sts & OCTEON_MIO_EMM_RSP_STS_RSP_TIMEOUT) { + s->emm->mio_emm_int |=3D OCTEON_MIO_EMM_INT_CMD_ERR; + } +} + +static uint64_t octeon_mio_emm_read(OcteonState *s, hwaddr reg, + hwaddr addr, unsigned size) +{ + uint64_t value; + + switch (reg) { + case OCTEON_MIO_EMM_RSP_STS: + value =3D s->emm->mio_emm_rsp_sts; + break; + case OCTEON_MIO_EMM_RSP_LO: + value =3D s->emm->mio_emm_rsp_lo; + break; + case OCTEON_MIO_EMM_RSP_HI: + value =3D s->emm->mio_emm_rsp_hi; + break; + case OCTEON_MIO_EMM_BUF_DAT: + value =3D ldq_be_p(s->emm->mio_emm_buf + s->emm->mio_emm_buf_idx); + if (s->emm->mio_emm_buf_inc) { + s->emm->mio_emm_buf_idx =3D + (s->emm->mio_emm_buf_idx + OCTEON_MIO_EMM_BUF_WORD_SIZE) % + OCTEON_MIO_EMM_BUF_SIZE; + } + break; + case OCTEON_MIO_EMM_INT: + value =3D s->emm->mio_emm_int; + break; + case OCTEON_MIO_EMM_DMA_INT: + value =3D s->emm->mio_emm_dma_int; + break; + case OCTEON_MIO_EMM_CMD: + case OCTEON_MIO_EMM_SWITCH: + case OCTEON_MIO_EMM_DMA: + if (!octeon_csr_lookup(s, reg, &value)) { + value =3D 0; + } + break; + case OCTEON_MIO_EMM_MODEX(0): + case OCTEON_MIO_EMM_MODEX(1): + case OCTEON_MIO_EMM_MODEX(2): + case OCTEON_MIO_EMM_MODEX(3): + if (!octeon_csr_lookup(s, reg, &value)) { + value =3D 0; + } + break; + default: + if (!octeon_csr_lookup(s, reg, &value)) { + value =3D 0; + } + break; + } + + return octeon_read64(value, addr, size); +} + +static void octeon_mio_emm_write(OcteonState *s, hwaddr reg, + hwaddr addr, uint64_t value, unsigned siz= e) +{ + uint64_t old; + uint64_t clear; + + switch (reg) { + case OCTEON_MIO_EMM_CMD: + if (!octeon_csr_lookup(s, reg, &old)) { + old =3D 0; + } + value =3D octeon_write64(old, addr, value, size); + octeon_csr_store(s, reg, value); + if (!(value & OCTEON_MIO_EMM_CMD_VAL)) { + return; + } + if (!octeon_mio_emm_execute_write(addr, size)) { + return; + } + + octeon_csr_store(s, reg, value & ~OCTEON_MIO_EMM_CMD_VAL); + octeon_mio_emm_command(s, value); + return; + case OCTEON_MIO_EMM_SWITCH: + if (!octeon_csr_lookup(s, reg, &old)) { + old =3D 0; + } + value =3D octeon_write64(old, addr, value, size); + octeon_csr_store(s, reg, value); + if (!(value & OCTEON_MIO_EMM_SWITCH_EXE)) { + return; + } + if (!octeon_mio_emm_execute_write(addr, size)) { + return; + } + octeon_csr_store(s, reg, value & ~OCTEON_MIO_EMM_SWITCH_EXE); + octeon_csr_store(s, OCTEON_MIO_EMM_MODEX( + (value >> OCTEON_MIO_EMM_CMD_BUS_ID_SHIFT) & + OCTEON_MIO_EMM_BUS_ID_MASK), + value & OCTEON_MIO_EMM_SWITCH_MODE_MASK); + s->emm->mio_emm_int |=3D OCTEON_MIO_EMM_INT_SWITCH_DONE; + return; + case OCTEON_MIO_EMM_DMA: + if (!octeon_csr_lookup(s, reg, &old)) { + old =3D 0; + } + value =3D octeon_write64(old, addr, value, size); + octeon_csr_store(s, reg, value); + if (!(value & OCTEON_MIO_EMM_DMA_VAL)) { + return; + } + if (!octeon_mio_emm_execute_write(addr, size)) { + return; + } + octeon_mio_emm_complete_dma(s, value); + return; + case OCTEON_MIO_EMM_INT: + clear =3D octeon_write64(0, addr, value, size); + s->emm->mio_emm_int &=3D ~clear; + return; + case OCTEON_MIO_EMM_DMA_INT: + clear =3D octeon_write64(0, addr, value, size); + s->emm->mio_emm_dma_int &=3D ~clear; + return; + case OCTEON_MIO_EMM_MODEX(0): + case OCTEON_MIO_EMM_MODEX(1): + case OCTEON_MIO_EMM_MODEX(2): + case OCTEON_MIO_EMM_MODEX(3): + if (!octeon_csr_lookup(s, reg, &old)) { + old =3D 0; + } + value =3D octeon_write64(old, addr, value, size); + octeon_csr_store(s, reg, value); + return; + case OCTEON_MIO_EMM_CFG: + if (!octeon_csr_lookup(s, reg, &old)) { + old =3D 0; + } + value =3D octeon_write64(old, addr, value, size); + octeon_csr_store(s, reg, value); + if (octeon_mio_emm_execute_write(addr, size)) { + uint64_t enabled =3D (value & ~old) & OCTEON_MIO_EMM_CFG_BUS_E= N_MASK; + unsigned int i; + + for (i =3D 0; i < OCTEON_MIO_EMM_MODE_COUNT; i++) { + if (enabled & (1U << i)) { + octeon_mio_emm_set_low_speed_mode(s, i); + } + } + } + return; + case OCTEON_MIO_EMM_BUF_IDX: + if (!octeon_csr_lookup(s, reg, &old)) { + old =3D 0; + } + value =3D octeon_write64(old, addr, value, size); + octeon_csr_store(s, reg, value); + s->emm->mio_emm_buf_idx =3D (value & OCTEON_MIO_EMM_BUF_IDX_OFF_MA= SK) * + OCTEON_MIO_EMM_BUF_WORD_SIZE; + s->emm->mio_emm_buf_inc =3D value & OCTEON_MIO_EMM_BUF_IDX_INC; + return; + case OCTEON_MIO_EMM_BUF_DAT: + old =3D ldq_be_p(s->emm->mio_emm_buf + s->emm->mio_emm_buf_idx); + value =3D octeon_write64(old, addr, value, size); + stq_be_p(s->emm->mio_emm_buf + s->emm->mio_emm_buf_idx, value); + if (s->emm->mio_emm_buf_inc) { + s->emm->mio_emm_buf_idx =3D + (s->emm->mio_emm_buf_idx + OCTEON_MIO_EMM_BUF_WORD_SIZE) % + OCTEON_MIO_EMM_BUF_SIZE; + } + return; + default: + if (!octeon_csr_lookup(s, reg, &old)) { + old =3D 0; + } + value =3D octeon_write64(old, addr, value, size); + octeon_csr_store(s, reg, value); + return; + } +} + static bool octeon_ciu3_source_from_intsn(uint32_t intsn, unsigned int *source) { @@ -1258,6 +1689,7 @@ static uint64_t octeon_csr_read(void *opaque, hwaddr = addr, unsigned size) { OcteonState *s =3D opaque; hwaddr reg =3D addr & ~7ULL; + hwaddr ereg; uint64_t value; =20 if (reg >=3D OCTEON_MIO_BOOT_REG_CFGX(0) && @@ -1294,6 +1726,10 @@ static uint64_t octeon_csr_read(void *opaque, hwaddr= addr, unsigned size) break; } =20 + if (octeon_mio_emm_decode(reg, &ereg)) { + return octeon_mio_emm_read(s, ereg, addr, size); + } + if (!octeon_csr_lookup(s, reg, &value)) { value =3D 0; } @@ -1305,8 +1741,14 @@ static void octeon_csr_write(void *opaque, hwaddr ad= dr, { OcteonState *s =3D opaque; hwaddr reg =3D addr & ~7ULL; + hwaddr ereg; uint64_t old; =20 + if (octeon_mio_emm_decode(reg, &ereg)) { + octeon_mio_emm_write(s, ereg, addr, value, size); + return; + } + if (reg =3D=3D OCTEON_RST_SOFT_RST && value) { qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); return; @@ -1707,6 +2149,26 @@ static void octeon_mio_reset_hold(Object *obj, Reset= Type type) octeon_mio_boot_loc_update(s); } =20 +static void octeon_emm_reset_hold(Object *obj, ResetType type) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); + OcteonEmmState *emm =3D OCTEON_EMM(obj); + + if (opc->parent_phases.hold) { + opc->parent_phases.hold(obj, type); + } + + g_hash_table_remove_all(emm->regs); + emm->mio_emm_rsp_sts =3D 0; + emm->mio_emm_rsp_lo =3D 0; + emm->mio_emm_rsp_hi =3D 0; + emm->mio_emm_int =3D 0; + emm->mio_emm_dma_int =3D 0; + emm->mio_emm_buf_idx =3D 0; + emm->mio_emm_buf_inc =3D false; + memset(emm->mio_emm_buf, 0, sizeof(emm->mio_emm_buf)); +} + static void octeon_rst_reset_hold(Object *obj, ResetType type) { OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); @@ -1774,6 +2236,16 @@ static GHashTable *octeon_reg_table_new(void) g_free, g_free); } =20 +static void octeon_emm_init(Object *obj) +{ + OCTEON_EMM(obj)->regs =3D octeon_reg_table_new(); +} + +static void octeon_emm_finalize(Object *obj) +{ + g_hash_table_destroy(OCTEON_EMM(obj)->regs); +} + static void octeon_rst_init(Object *obj) { OCTEON_RST(obj)->regs =3D octeon_reg_table_new(); @@ -1803,6 +2275,15 @@ static void octeon_mio_class_init(ObjectClass *klass= , const void *data) NULL, &opc->parent_phases); } =20 +static void octeon_emm_class_init(ObjectClass *klass, const void *data) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + resettable_class_set_parent_phases(rc, NULL, octeon_emm_reset_hold, + NULL, &opc->parent_phases); +} + static void octeon_rst_class_init(ObjectClass *klass, const void *data) { OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); @@ -1846,6 +2327,7 @@ static OcteonPeripheralState *octeon_new_peripheral(O= cteonState *s, static void octeon_create_peripherals(OcteonState *s) { s->mio =3D OCTEON_MIO(octeon_new_peripheral(s, TYPE_OCTEON_MIO, 0)); + s->emm =3D OCTEON_EMM(octeon_new_peripheral(s, TYPE_OCTEON_EMM, 0)); s->rst =3D OCTEON_RST(octeon_new_peripheral(s, TYPE_OCTEON_RST, 0)); s->intc =3D OCTEON_INTC(octeon_new_peripheral(s, TYPE_OCTEON_INTC, 0)); s->csr_bank =3D OCTEON_CSR_BANK(octeon_new_peripheral( @@ -1862,6 +2344,7 @@ static void octeon_realize_peripherals(OcteonState *s) octeon_realize_peripheral(&s->csr_bank->parent_obj); octeon_realize_peripheral(&s->intc->parent_obj); octeon_realize_peripheral(&s->rst->parent_obj); + octeon_realize_peripheral(&s->emm->parent_obj); octeon_realize_peripheral(&s->mio->parent_obj); } =20 @@ -1986,6 +2469,14 @@ static const TypeInfo octeon_machine_types[] =3D { .instance_size =3D sizeof(OcteonMioState), .class_init =3D octeon_mio_class_init, }, + { + .name =3D TYPE_OCTEON_EMM, + .parent =3D TYPE_OCTEON_PERIPHERAL, + .instance_size =3D sizeof(OcteonEmmState), + .instance_init =3D octeon_emm_init, + .instance_finalize =3D octeon_emm_finalize, + .class_init =3D octeon_emm_class_init, + }, { .name =3D TYPE_OCTEON_RST, .parent =3D TYPE_OCTEON_PERIPHERAL, diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index e9826f1713..a262107b54 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -20,6 +20,7 @@ #define OCTEON_CIU3_IDT_COUNT (OCTEON_MAX_CPUS * 4) #define OCTEON_MIO_BOOT_REG_CFG_COUNT 8 #define OCTEON_MIO_BOOT_LOC_SIZE 0x100 +#define OCTEON_MIO_EMM_BUF_SIZE 512 #define OCTEON_TWSI_COUNT 2 #define OCTEON_TWSI_STAT_IDLE 0xf8 #define OCTEON_SPD_EEPROM_SIZE 139 @@ -38,6 +39,7 @@ typedef enum OcteonCiu3Source { =20 typedef struct OcteonState OcteonState; typedef struct OcteonMioState OcteonMioState; +typedef struct OcteonEmmState OcteonEmmState; typedef struct OcteonRstState OcteonRstState; typedef struct OcteonIntcState OcteonIntcState; typedef struct OcteonCsrBankState OcteonCsrBankState; @@ -68,6 +70,7 @@ struct OcteonState { MemoryRegion boot_flash_alias; MemoryRegion cvmseg; OcteonMioState *mio; + OcteonEmmState *emm; OcteonRstState *rst; OcteonIntcState *intc; OcteonCsrBankState *csr_bank; --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123118543515.7476895808584; Wed, 15 Jul 2026 06:45:18 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv9-0005cU-RM; Wed, 15 Jul 2026 09:45:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv5-0005Zq-Nc for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:03 -0400 Received: from mx2.catap.net ([65.21.79.163]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv2-0007u1-Ty for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:03 -0400 Received: by mx2.catap.net (OpenSMTPD) with ESMTPSA id 571c79af (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:54 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 28bfe959; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=WxGznS+ J67HYZYgJZkpkY6RR73hEtk/9i1nBIu/NKT8qAN28WXfHoOmzxkhONonXxHbF6htz9DnDM to2FIvDtlTSw8+cUj+eQQMifa6E2qrTU010IQF6oe1mqz8hQOBouKrWAufa9c7uCW+y32d VnpEbIWqd2d2rjd83Rbh50SEmEMquUziTuIjcnykxcq8LxApt8gGnwZiKAIV2B70HC2G5X /1nXKMYOo74Y0kVNOcpcydUdQD6Ggqibv9oHi3lSy6htT1ExocFNwkK9TDuK6txkM3rNNL RGhJAfgcxPnDj2Pb1e/uVwQLczfjuPVOcxyziigohGcuk4l7rwD+amQ== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=U geDLBflB5zIOmlcl0N8hG70bCLFVmfl2IDtVqd/6H4=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=uIyVmbed/AI0vtZ0EMc1N1NwoYlVB7s+UKewg3/21o9YWnfDwA7HdKK2rDbzoEDo7UYo 7csBRHx6ycSrczT3l0yJd/7D+wRCvT+tBQs1zdUidJGTQnrsj95FtZDvux6hQwP8yYRglH aBTqflSLLbaB9xMAEMnyn88zXpCntaQaGZoYB9TbYCBpZe1jttxJNhHOHHWSyoMXTc+9C6 82OIcOdqOUqrGbMH0m7srTWOSc0e8oZdCBlF4lichjtqCI6XyXPvwWdb2+e5Ki/BmmpCiz Dxi5j9IpYByC32IaokpG/z5FiuFWsJjd0Nr0tY9aiDJI5AC816WlrJBR/w5SjOwQ== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=faG8B0fU; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=vLPDtqph; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=UgeDLBfl B5zIOmlcl0N8hG70bCLFVmfl2IDtVqd/6H4=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=faG8B0fUBd5NAE3URTK72A4N0gg2XBUwfk0 IHqs7sGp8NDptrs0jnyq/QXiMXy5wTKHEBCSGRJVCl2DztiohzzueHsYVjc8yoRjSqmIOd XDz47YWTU7d+4gaTrf6QJTMPlNH37G8jULTync7aPVZ6j22VdMfqlOPledkICSBEcs+Ddi T2cIU+9EB2ZiLhnwwXZJG7BOsRTKbnVZk8jvhpQY6vS6QmSNw8zAoU6hkuxn7UmBD6wcaH H2vTrawZmFF+SOAMXHMuOIXAPwm/yyOCrHQjVJwKJaIra/89vPlSmTz1D5XcxnVjJExpdk 5i/a50n78CPdqrkyRUUfwn6aUtw== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=UgeDLBflB5zIOmlcl0N8hG70bCLFVmfl2IDtVqd/6H4=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=vLPDtqphzOXfdQNcC6 R8bBpyzEPptOVvcWuLTCKiS/3e0j2u8+qt9UnTxMV7HDQdoXJedilz31jWq/TWREuqCw== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 20/25] hw/mips: add Octeon LMC controllers Date: Wed, 15 Jul 2026 15:44:06 +0200 Message-ID: <20260715134447.56007-21-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=65.21.79.163; envelope-from=kirill@korins.ky; helo=mx2.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123119248158500 Content-Type: text/plain; charset="utf-8" Add four Octeon LMC register banks with the DDR training completion, leveling, MPR and clock responses used by firmware. Each LMC owns and resets its mutable register state. --- hw/mips/octeon.c | 184 ++++++++++++++++++++++++++++++++++++++ hw/mips/octeon_internal.h | 3 + 2 files changed, 187 insertions(+) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index f3f8a74cbe..0553f8ea05 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -10,6 +10,7 @@ #include "qemu/units.h" #include "qemu/datadir.h" #include "qemu/host-utils.h" +#include "qemu/timer.h" #include "qapi/error.h" #include "hw/char/serial-mm.h" #include "hw/core/clock.h" @@ -49,6 +50,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonEmmState, OCTEON_EMM) OBJECT_DECLARE_SIMPLE_TYPE(OcteonRstState, OCTEON_RST) #define TYPE_OCTEON_INTC "octeon-intc" OBJECT_DECLARE_SIMPLE_TYPE(OcteonIntcState, OCTEON_INTC) +#define TYPE_OCTEON_LMC "octeon-lmc" +OBJECT_DECLARE_SIMPLE_TYPE(OcteonLmcState, OCTEON_LMC) #define TYPE_OCTEON_CSR_BANK "octeon-csr-bank" OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_CSR_BANK) =20 @@ -243,6 +246,24 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_= CSR_BANK) #define OCTEON_RST_SOFT_RST 0x6001680 /* U-Boot uses the reset controller to park and release secondary cores. */ #define OCTEON_RST_PP_POWER 0x6001700 +#define OCTEON_LMC_BASE 0x88000000 +#define OCTEON_LMC_SEQ_CTL 0x48 +#define OCTEON_LMC_SEQ_COMPLETE (1ULL << 5) +#define OCTEON_LMC_MPR_DATA0 0x70 +#define OCTEON_LMC_MPR_DATA1 0x78 +#define OCTEON_LMC_DCLK_CNT 0x1e0 +#define OCTEON_LMC_PHY_CTL 0x210 +#define OCTEON_LMC_PHY_DSK_COMPLETE (1ULL << 49) +#define OCTEON_LMC_RLEVEL_RANK 0x280 +#define OCTEON_LMC_RLEVEL_STATUS (3ULL << 54) +#define OCTEON_LMC_RLEVEL_DBG 0x2a8 +#define OCTEON_LMC_RLEVEL_MASK 0x3f0 +#define OCTEON_LMC_WLEVEL_RANK 0x2c0 +#define OCTEON_LMC_RANK_COUNT 4 +#define OCTEON_LMC_WLEVEL_STATUS (3ULL << 45) +#define OCTEON_LMC_WLEVEL_DBG 0x308 +#define OCTEON_LMC_WLEVEL_MASK (0x0fULL << 4) +#define OCTEON_LMC_STRIDE 0x1000000 #define OCTEON_RST_BOOT_C_MUL_SHIFT 30 #define OCTEON_RST_BOOT_PNR_MUL_SHIFT 24 =20 @@ -351,6 +372,11 @@ struct OcteonIntcState { uint8_t ciu3_irq_line[OCTEON_MAX_CPUS][OCTEON_CIU3_CP0_IRQ_COUNT]; }; =20 +struct OcteonLmcState { + OcteonPeripheralState parent_obj; + GHashTable *regs; +}; + struct OcteonCsrBankState { OcteonPeripheralState parent_obj; MemoryRegion csr; @@ -416,6 +442,13 @@ static uint64_t octeon_atomic_write64(uint64_t *ptr, h= waddr addr, return new; } =20 +static uint64_t octeon_clock_count(uint64_t hz) +{ + uint64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + return muldiv64(now, hz, NANOSECONDS_PER_SECOND); +} + static void octeon_validate_clocks(OcteonMachineState *oms) { if (!oms->cpu_hz || !oms->ref_hz || !oms->io_hz || !oms->ddr_hz) { @@ -884,6 +917,94 @@ static void octeon_mio_emm_write(OcteonState *s, hwadd= r reg, } } =20 +static bool octeon_lmc_decode(hwaddr reg, OcteonLmcState **lmc, hwaddr *lr= eg, + OcteonState *s) +{ + hwaddr offset; + unsigned int index; + + if (reg < OCTEON_LMC_BASE) { + return false; + } + + offset =3D reg - OCTEON_LMC_BASE; + index =3D offset / OCTEON_LMC_STRIDE; + if (index >=3D OCTEON_LMC_COUNT) { + return false; + } + + *lmc =3D s->lmc[index]; + *lreg =3D offset % OCTEON_LMC_STRIDE; + return true; +} + +static uint64_t octeon_lmc_get(OcteonLmcState *lmc, hwaddr reg) +{ + uint64_t value; + + if (!octeon_reg_lookup(lmc->regs, reg, &value)) { + return 0; + } + return value; +} + +static bool octeon_lmc_rank_reg(hwaddr reg, hwaddr base) +{ + return reg >=3D base && + reg < base + OCTEON_LMC_RANK_COUNT * 8 && + ((reg - base) & 7) =3D=3D 0; +} + +static uint64_t octeon_lmc_read(OcteonState *s, OcteonLmcState *lmc, + hwaddr reg, hwaddr addr, unsigned size) +{ + uint64_t value; + + switch (reg) { + case OCTEON_LMC_SEQ_CTL: + value =3D octeon_lmc_get(lmc, reg) | OCTEON_LMC_SEQ_COMPLETE; + break; + case OCTEON_LMC_MPR_DATA0: + value =3D ~0ULL; + break; + case OCTEON_LMC_MPR_DATA1: + value =3D 0xff; + break; + case OCTEON_LMC_DCLK_CNT: + value =3D octeon_clock_count(s->ddr_hz); + break; + case OCTEON_LMC_PHY_CTL: + value =3D octeon_lmc_get(lmc, reg) | OCTEON_LMC_PHY_DSK_COMPLETE; + break; + case OCTEON_LMC_RLEVEL_DBG: + value =3D OCTEON_LMC_RLEVEL_MASK; + break; + case OCTEON_LMC_WLEVEL_DBG: + value =3D OCTEON_LMC_WLEVEL_MASK; + break; + default: + if (octeon_lmc_rank_reg(reg, OCTEON_LMC_RLEVEL_RANK)) { + value =3D octeon_lmc_get(lmc, reg) | OCTEON_LMC_RLEVEL_STATUS; + } else if (octeon_lmc_rank_reg(reg, OCTEON_LMC_WLEVEL_RANK)) { + value =3D octeon_lmc_get(lmc, reg) | OCTEON_LMC_WLEVEL_STATUS; + } else { + value =3D octeon_lmc_get(lmc, reg); + } + break; + } + + return octeon_read64(value, addr, size); +} + +static void octeon_lmc_write(OcteonLmcState *lmc, hwaddr reg, + hwaddr addr, uint64_t value, unsigned size) +{ + uint64_t old =3D octeon_lmc_get(lmc, reg); + + value =3D octeon_write64(old, addr, value, size); + octeon_reg_store(lmc->regs, reg, value); +} + static bool octeon_ciu3_source_from_intsn(uint32_t intsn, unsigned int *source) { @@ -1688,7 +1809,9 @@ static const MemoryRegionOps octeon_ciu3_ops =3D { static uint64_t octeon_csr_read(void *opaque, hwaddr addr, unsigned size) { OcteonState *s =3D opaque; + OcteonLmcState *lmc; hwaddr reg =3D addr & ~7ULL; + hwaddr lreg; hwaddr ereg; uint64_t value; =20 @@ -1726,6 +1849,10 @@ static uint64_t octeon_csr_read(void *opaque, hwaddr= addr, unsigned size) break; } =20 + if (octeon_lmc_decode(reg, &lmc, &lreg, s)) { + return octeon_lmc_read(s, lmc, lreg, addr, size); + } + if (octeon_mio_emm_decode(reg, &ereg)) { return octeon_mio_emm_read(s, ereg, addr, size); } @@ -1740,10 +1867,17 @@ static void octeon_csr_write(void *opaque, hwaddr a= ddr, uint64_t value, unsigned size) { OcteonState *s =3D opaque; + OcteonLmcState *lmc; hwaddr reg =3D addr & ~7ULL; + hwaddr lreg; hwaddr ereg; uint64_t old; =20 + if (octeon_lmc_decode(reg, &lmc, &lreg, s)) { + octeon_lmc_write(lmc, lreg, addr, value, size); + return; + } + if (octeon_mio_emm_decode(reg, &ereg)) { octeon_mio_emm_write(s, ereg, addr, value, size); return; @@ -2209,6 +2343,18 @@ static void octeon_intc_reset_hold(Object *obj, Rese= tType type) octeon_intc_update_all_cpus(s); } =20 +static void octeon_lmc_reset_hold(Object *obj, ResetType type) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); + OcteonLmcState *lmc =3D OCTEON_LMC(obj); + + if (opc->parent_phases.hold) { + opc->parent_phases.hold(obj, type); + } + + g_hash_table_remove_all(lmc->regs); +} + static void octeon_csr_bank_reset_hold(Object *obj, ResetType type) { OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_GET_CLASS(obj); @@ -2256,6 +2402,16 @@ static void octeon_rst_finalize(Object *obj) g_hash_table_destroy(OCTEON_RST(obj)->regs); } =20 +static void octeon_lmc_init(Object *obj) +{ + OCTEON_LMC(obj)->regs =3D octeon_reg_table_new(); +} + +static void octeon_lmc_finalize(Object *obj) +{ + g_hash_table_destroy(OCTEON_LMC(obj)->regs); +} + static void octeon_csr_bank_init(Object *obj) { OCTEON_CSR_BANK(obj)->values =3D octeon_reg_table_new(); @@ -2302,6 +2458,15 @@ static void octeon_intc_class_init(ObjectClass *klas= s, const void *data) NULL, &opc->parent_phases); } =20 +static void octeon_lmc_class_init(ObjectClass *klass, const void *data) +{ + OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + resettable_class_set_parent_phases(rc, NULL, octeon_lmc_reset_hold, + NULL, &opc->parent_phases); +} + static void octeon_csr_bank_class_init(ObjectClass *klass, const void *dat= a) { OcteonPeripheralClass *opc =3D OCTEON_PERIPHERAL_CLASS(klass); @@ -2326,10 +2491,16 @@ static OcteonPeripheralState *octeon_new_peripheral= (OcteonState *s, =20 static void octeon_create_peripherals(OcteonState *s) { + unsigned int i; + s->mio =3D OCTEON_MIO(octeon_new_peripheral(s, TYPE_OCTEON_MIO, 0)); s->emm =3D OCTEON_EMM(octeon_new_peripheral(s, TYPE_OCTEON_EMM, 0)); s->rst =3D OCTEON_RST(octeon_new_peripheral(s, TYPE_OCTEON_RST, 0)); s->intc =3D OCTEON_INTC(octeon_new_peripheral(s, TYPE_OCTEON_INTC, 0)); + for (i =3D 0; i < OCTEON_LMC_COUNT; i++) { + s->lmc[i] =3D OCTEON_LMC(octeon_new_peripheral(s, TYPE_OCTEON_LMC, + i)); + } s->csr_bank =3D OCTEON_CSR_BANK(octeon_new_peripheral( s, TYPE_OCTEON_CSR_BANK, 0)); } @@ -2341,7 +2512,12 @@ static void octeon_realize_peripheral(OcteonPeripher= alState *dev) =20 static void octeon_realize_peripherals(OcteonState *s) { + int i; + octeon_realize_peripheral(&s->csr_bank->parent_obj); + for (i =3D OCTEON_LMC_COUNT - 1; i >=3D 0; i--) { + octeon_realize_peripheral(&s->lmc[i]->parent_obj); + } octeon_realize_peripheral(&s->intc->parent_obj); octeon_realize_peripheral(&s->rst->parent_obj); octeon_realize_peripheral(&s->emm->parent_obj); @@ -2491,6 +2667,14 @@ static const TypeInfo octeon_machine_types[] =3D { .instance_size =3D sizeof(OcteonIntcState), .class_init =3D octeon_intc_class_init, }, + { + .name =3D TYPE_OCTEON_LMC, + .parent =3D TYPE_OCTEON_PERIPHERAL, + .instance_size =3D sizeof(OcteonLmcState), + .instance_init =3D octeon_lmc_init, + .instance_finalize =3D octeon_lmc_finalize, + .class_init =3D octeon_lmc_class_init, + }, { .name =3D TYPE_OCTEON_CSR_BANK, .parent =3D TYPE_OCTEON_PERIPHERAL, diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index a262107b54..96443a9d64 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -21,6 +21,7 @@ #define OCTEON_MIO_BOOT_REG_CFG_COUNT 8 #define OCTEON_MIO_BOOT_LOC_SIZE 0x100 #define OCTEON_MIO_EMM_BUF_SIZE 512 +#define OCTEON_LMC_COUNT 4 #define OCTEON_TWSI_COUNT 2 #define OCTEON_TWSI_STAT_IDLE 0xf8 #define OCTEON_SPD_EEPROM_SIZE 139 @@ -42,6 +43,7 @@ typedef struct OcteonMioState OcteonMioState; typedef struct OcteonEmmState OcteonEmmState; typedef struct OcteonRstState OcteonRstState; typedef struct OcteonIntcState OcteonIntcState; +typedef struct OcteonLmcState OcteonLmcState; typedef struct OcteonCsrBankState OcteonCsrBankState; =20 typedef struct OcteonCPUState { @@ -73,6 +75,7 @@ struct OcteonState { OcteonEmmState *emm; OcteonRstState *rst; OcteonIntcState *intc; + OcteonLmcState *lmc[OCTEON_LMC_COUNT]; OcteonCsrBankState *csr_bank; OcteonSpdEepromState *spd[OCTEON_SPD_EEPROM_COUNT]; SerialMM *uart; --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123278630788.9555850621808; Wed, 15 Jul 2026 06:47:58 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzv8-0005bJ-4o; Wed, 15 Jul 2026 09:45:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv5-0005Zn-Ms for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:03 -0400 Received: from mx2.catap.net ([2a01:4f9:3b:5410::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv3-0007uL-2G for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:03 -0400 Received: by mx2.catap.net (OpenSMTPD) with ESMTPSA id bbbfcce8 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:54 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id e0eaefb3; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=bYmgAhL f8z7MO70tzvheXhziixVl7V48Ya4nXWsztf4EjFTpvlsPqCVSKEiAUsmb27KeDOUrrwrAk EmEKYJLQfB0fl3ip9oVNKPQ7VTjr2BRn0+nW9ZZOV09FOrxmDQ1U1iY5HYzDZBWkPnPigl m7CAmgbkRBtzOANc5scRUkxJnh7FOULSGYY6jwqxu6PLNms4sBPIAGS07RRQjsknmgK1yC AZjnKm3fbOGnux3p3D+fzCrK2QFi727+GVfVOk38FNYyaE8Z5k1A+T3cWMZyWOmmDkXu5D A0WoUzGmS18I0WStzEeU3SGfbqH+Znrw2WxLqUGUhfdErpVIF/dfEaw== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=r 34daS198u1YguWqCjhlTgbIWS7fFI5WlpNz00fKHr0=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=WCqJqzYT2od3I6dKLCCSNLogCP3k/7eLGPvqo+w3zXbOPlopOolNklKKkMcoOB6aXTat wrrWf+c9PiRY6lFwIPFLKgJI0oG2WHyB/j7BXHPWZ25FGUGTHJMfxqRhoPQjcgS0eFrc+a byxRvAnghAOODOil/trOnI2j4H3PAAKAc4K5VcIIwgRq1U1Z5OKKkdlmRNxcKWjyEO0T4R cqfHWQ2FKbncgrnMalBypanorfT7+Owu2YhqHZ4c7JAPOQY3fG1xWUWPuUPnaGURTo338V K5uR514Aa98cJzqFRWU5cCEwBBedCjg2f+Fr8ITYH2eeesxzjO8k9IrwzQ1KlH9A== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=qRkS26TS; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=JawvQ0rn; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=r34daS19 8u1YguWqCjhlTgbIWS7fFI5WlpNz00fKHr0=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=qRkS26TSmtOkSlPjAHlsI6W2DDeAurcRhAE cbzOJWSwq08zHXnFGnkZtb7YqukGXUUjZDGvQa/rkyr8nuHMqaW3o3OpU0NcQOlejXyY76 jnMl3dSJe16yeuRanlpdfiDly41mF+hg8D54h48pPmZ/hWCXGQLQEQyRE6ohZlglofi/7s IJIeek268BuhRn3zsIO7WE7QQNNI544Hjrd8LvrSA5nTaTcgRZuclXhDbvb5CWwxJd5FBC s3/hGH6B3idM1Zic44OsWgsWEZni+pS8Q7N/2s8P2C5HWYcE/spM9RAAUbzZMp2Tb/cTEV 6K2cL/Yqv5MCTRh/uqsZ9t6bR/w== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=r34daS198u1YguWqCjhlTgbIWS7fFI5WlpNz00fKHr0=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=JawvQ0rn0LKbn9DKeg mMNsqaS/n+ZvWeUX01/5kf7nYZ7tpticwkc4hRdQ/ErgApEjO7DlSfzHvNjzw9YiB/BQ== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 21/25] hw/mips: add Octeon boot support registers Date: Wed, 15 Jul 2026 15:44:07 +0200 Message-ID: <20260715134447.56007-22-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f9:3b:5410::2; envelope-from=kirill@korins.ky; helo=mx2.catap.net 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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123280604158500 Content-Type: text/plain; charset="utf-8" Add the small DPI, FPA, IPD, PKO, RNG and POW register windows needed while firmware initializes the platform. Reuse the CSR bank for stored values and compute clock and random values on demand. --- hw/mips/octeon.c | 218 ++++++++++++++++++++++++++++++++++++++ hw/mips/octeon_internal.h | 6 ++ 2 files changed, 224 insertions(+) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 0553f8ea05..7e78511b8f 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -30,6 +30,7 @@ #include "system/runstate.h" #include "system/system.h" #include "exec/cpu-interrupt.h" +#include "qemu/guest-random.h" #include "qemu/error-report.h" #include "qemu/atomic.h" #include "hw/mips/octeon_internal.h" @@ -140,6 +141,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_C= SR_BANK) #define OCTEON_CIU3_UART0_INTSN 0x8000 #define OCTEON_CSR_BASE 0x1180000000000ULL #define OCTEON_CSR_SIZE 0x100000000ULL +#define OCTEON_DPI_BASE 0x1df0000000000ULL +#define OCTEON_DPI_SIZE 0x10000 #define OCTEON_MIO_BOOT_REG_CFGX(x) \ (0x0000000 + (x) * OCTEON_CSR_64BIT_SIZE) #define OCTEON_MIO_BOOT_REG_CFG_INDEX(reg) \ @@ -267,6 +270,23 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_= CSR_BANK) #define OCTEON_RST_BOOT_C_MUL_SHIFT 30 #define OCTEON_RST_BOOT_PNR_MUL_SHIFT 24 =20 +#define OCTEON_FPA_BASE 0x1280000000000ULL +#define OCTEON_FPA_SIZE 0x1000 +#define OCTEON_FPA_CLK_COUNT 0xf0 + +#define OCTEON_IPD_BASE 0x14f0000000000ULL +#define OCTEON_IPD_SIZE 0x1000 +#define OCTEON_IPD_CLK_COUNT 0x338 + +#define OCTEON_PKO_BASE 0x1540000000000ULL +#define OCTEON_PKO_SIZE 0x1000000 + +#define OCTEON_RNG_BASE 0x1400000000000ULL +#define OCTEON_RNG_SIZE 0x8 + +#define OCTEON_POW_BASE 0x1670000000000ULL +#define OCTEON_POW_SIZE 0x2000 + #define OCTEON_UART0_BASE 0x1180000000800ULL #define OCTEON_UART0_ALIAS_BASE 0x1180000000c00ULL #define OCTEON_UART_TX_REG 0x40 @@ -1955,6 +1975,174 @@ static const MemoryRegionOps octeon_csr_ops =3D { }, }; =20 +static uint64_t octeon_stateful_io_read(OcteonState *s, uint64_t base, + hwaddr addr, unsigned size) +{ + uint64_t value; + uint64_t reg =3D base + (addr & ~7ULL); + + if (!octeon_csr_lookup(s, reg, &value)) { + value =3D 0; + } + + return octeon_read64(value, addr, size); +} + +static void octeon_stateful_io_write(OcteonState *s, uint64_t base, + hwaddr addr, uint64_t value, + unsigned size) +{ + uint64_t reg =3D base + (addr & ~7ULL); + uint64_t old; + + if (!octeon_csr_lookup(s, reg, &old)) { + old =3D 0; + } + + octeon_csr_store(s, reg, octeon_write64(old, addr, value, size)); +} + +static uint64_t octeon_dpi_read(void *opaque, hwaddr addr, unsigned size) +{ + return octeon_stateful_io_read(opaque, OCTEON_DPI_BASE, addr, size); +} + +static void octeon_dpi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + octeon_stateful_io_write(opaque, OCTEON_DPI_BASE, addr, value, size); +} + +static const MemoryRegionOps octeon_dpi_ops =3D { + .read =3D octeon_dpi_read, + .write =3D octeon_dpi_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + +static uint64_t octeon_fpa_read(void *opaque, hwaddr addr, unsigned size) +{ + OcteonState *s =3D opaque; + hwaddr reg =3D addr & ~7ULL; + + if (reg =3D=3D OCTEON_FPA_CLK_COUNT) { + return octeon_read64(octeon_clock_count(s->io_hz), addr, size); + } + + return 0; +} + +static void octeon_fpa_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ +} + +static const MemoryRegionOps octeon_fpa_ops =3D { + .read =3D octeon_fpa_read, + .write =3D octeon_fpa_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + +static uint64_t octeon_ipd_read(void *opaque, hwaddr addr, unsigned size) +{ + OcteonState *s =3D opaque; + hwaddr reg =3D addr & ~7ULL; + + if (reg =3D=3D OCTEON_IPD_CLK_COUNT) { + return octeon_read64(octeon_clock_count(s->io_hz), addr, size); + } + + return 0; +} + +static void octeon_ipd_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ +} + +static const MemoryRegionOps octeon_ipd_ops =3D { + .read =3D octeon_ipd_read, + .write =3D octeon_ipd_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + +static uint64_t octeon_pko_read(void *opaque, hwaddr addr, unsigned size) +{ + return octeon_stateful_io_read(opaque, OCTEON_PKO_BASE, addr, size); +} + +static void octeon_pko_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + octeon_stateful_io_write(opaque, OCTEON_PKO_BASE, addr, value, size); +} + +static const MemoryRegionOps octeon_pko_ops =3D { + .read =3D octeon_pko_read, + .write =3D octeon_pko_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + +static uint64_t octeon_rng_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t value; + + qemu_guest_getrandom_nofail(&value, sizeof(value)); + return octeon_read64(value, addr, size); +} + +static void octeon_rng_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ +} + +static const MemoryRegionOps octeon_rng_ops =3D { + .read =3D octeon_rng_read, + .write =3D octeon_rng_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + +static uint64_t octeon_pow_read(void *opaque, hwaddr addr, unsigned size) +{ + return octeon_stateful_io_read(opaque, OCTEON_POW_BASE, addr, size); +} + +static void octeon_pow_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + octeon_stateful_io_write(opaque, OCTEON_POW_BASE, addr, value, size); +} + +static const MemoryRegionOps octeon_pow_ops =3D { + .read =3D octeon_pow_read, + .write =3D octeon_pow_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + + void octeon_irq_set(void *opaque, int irq, int level) { OcteonState *s =3D opaque; @@ -2573,6 +2761,36 @@ static void mips_octeon_init(MachineState *machine) memory_region_add_subregion_overlap(get_system_memory(), OCTEON_CSR_BA= SE, &s->csr_bank->csr, -1); =20 + memory_region_init_io(&s->dpi, NULL, &octeon_dpi_ops, s, + "octeon.dpi", OCTEON_DPI_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_DPI_BASE, + &s->dpi); + + memory_region_init_io(&s->fpa, NULL, &octeon_fpa_ops, s, + "octeon.fpa", OCTEON_FPA_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_FPA_BASE, + &s->fpa); + + memory_region_init_io(&s->ipd, NULL, &octeon_ipd_ops, s, + "octeon.ipd", OCTEON_IPD_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_IPD_BASE, + &s->ipd); + + memory_region_init_io(&s->pko, NULL, &octeon_pko_ops, s, + "octeon.pko", OCTEON_PKO_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_PKO_BASE, + &s->pko); + + memory_region_init_io(&s->rng, NULL, &octeon_rng_ops, s, + "octeon.rng", OCTEON_RNG_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_RNG_BASE, + &s->rng); + + memory_region_init_io(&s->pow, NULL, &octeon_pow_ops, s, + "octeon.pow", OCTEON_POW_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_POW_BASE, + &s->pow); + octeon_realize_peripherals(s); } =20 diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index 96443a9d64..f2daa35cdb 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -71,6 +71,12 @@ struct OcteonState { MemoryRegion boot_flash; MemoryRegion boot_flash_alias; MemoryRegion cvmseg; + MemoryRegion dpi; + MemoryRegion fpa; + MemoryRegion ipd; + MemoryRegion pko; + MemoryRegion rng; + MemoryRegion pow; OcteonMioState *mio; OcteonEmmState *emm; OcteonRstState *rst; --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123213019141.32983003425898; Wed, 15 Jul 2026 06:46:53 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvG-0005mI-QW; Wed, 15 Jul 2026 09:45:14 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzvB-0005f0-2o for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:09 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv8-0007uM-Ee for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:08 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id c180caa2 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:54 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id f4ddd4c3; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=lnBsE9W WmH2bMIQ/aQVdrn/W9JJFhoehPu0idL5BHDJvPTmxnSE6czs26H6sGLPoiqjdiwDst/e5O UD+gD5Fj3wmzBumGlgazZpK8in0Tgk5/0u+8cbn1v2QJx9zgf6t4+79M198sw515vKHYxB c5pi4lEx7ImtLWdrixQycmjhhEeWl0kYWiqq5X2BNLU8sAWQlvIdIYyvwfNSGOvlMhjQCe lfNoj1mNyni9DVmRkF+vdbXMPF0KeCApxALXRpGywcOqZcfhU6bj4GutSD9qk20+Hnm092 GGEZE2Brv+oWIm0J34693VAFo3Zwbzea6JRuEvH5mHcdY1GuIibIyRg== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=e 7gOc4APHRmLk5zCxcyM3gv8KCfIoZktATs+fFMvpHk=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=cIOSpISBM0HlAmcGFXmqwXAoEU8y7KOQw4nZaMFswOd/ghtF6fv0auA0HOLlQfcguVZ2 SPSBVmwXDlUrqzRh5jb0+LuA4zDNg9VAxyPBxjscNujz1SaxVUSS/xLbHyz7zGkzz5Ajzl mJHA9mo6Ah5+MCMMyshChCn7s2jOcDIiy77Cs1TAFf7tz7V439JOeW0DiPqTeJFxCIlptn ESwveOpcFE7JljLbldG2c9QTHL8+k5kldYqs7Z0tXqrwOrAnc9gnoH53i6H5KxZDELC/Gp YJWPRX6dsLoP/aGNdV4BS7Ex6JHPhRR6r3y+RGbAgJgg7uQ3KDcFbTc1l5LMLgtQ== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=S4REebw1; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=G4gs9+Xl; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=e7gOc4AP HRmLk5zCxcyM3gv8KCfIoZktATs+fFMvpHk=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=S4REebw1rvWRKARIP6zi9bYU5IkA/yIZ/DL /K7Qp9ySe304XsyLVdkPZAQfoe6tUkXlMhWTKIDeGL8T/dxMEwhf2FaIFVE1gDXQdMdmMg 1xlJxPzbFHA+ja1ZZpxXR2OCTzk+kq/Pp3+qwJJsFS8gxIRHAjuVQwHNcYcm20TkF0T+uC WD13qtSF47QlA/Y5mxTO2JAj9VfqGWqhYaGjmmW4LCTVAHOHFKwq6io6gz0214JPC5ZVoZ Iloi2Vk6bp8W5XlPMVsgDC7EKHa/P8nrLkL48r61rhKvxuY7UhVXlV/GSeO94t4pTqolN3 /4b0AT/ycjs8MOJhzGAr2wRrMmQ== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=e7gOc4APHRmLk5zCxcyM3gv8KCfIoZktATs+fFMvpHk=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=G4gs9+XlusqkUhWm1L oxRef/8Sac/UlgCagslRZK/lR4Y5YO8DthvERgVRyWIm4dCWLdZUFdebONv+u2Nc12Aw== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 22/25] hw/usb: add Octeon USB controller Date: Wed, 15 Jul 2026 15:44:08 +0200 Message-ID: <20260715134447.56007-23-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123213971158500 Content-Type: text/plain; charset="utf-8" Add the Octeon UCTL wrapper around the DWC3 controller, including the big endian register window, byte swapping, DMA mapping and interrupt routing. Instantiate both EBB7304 USB controllers. --- hw/mips/Kconfig | 1 + hw/mips/octeon.c | 31 ++++ hw/mips/octeon_internal.h | 6 + hw/usb/meson.build | 5 + hw/usb/octeon_usb.c | 319 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 362 insertions(+) create mode 100644 hw/usb/octeon_usb.c diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 5fe5f885e3..2566df6da6 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -73,6 +73,7 @@ config MIPS_OCTEON depends on MIPS64 && TARGET_BIG_ENDIAN select PFLASH_CFI02 select SERIAL_MM + select USB_DWC3 =20 config MIPS_CPS bool diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 7e78511b8f..94717b6c89 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -287,6 +287,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_C= SR_BANK) #define OCTEON_POW_BASE 0x1670000000000ULL #define OCTEON_POW_SIZE 0x2000 =20 +#define OCTEON_CIU3_USB0_INTSN 0x68080 +#define OCTEON_CIU3_USB1_INTSN 0x69080 + #define OCTEON_UART0_BASE 0x1180000000800ULL #define OCTEON_UART0_ALIAS_BASE 0x1180000000c00ULL #define OCTEON_UART_TX_REG 0x40 @@ -1032,6 +1035,15 @@ static bool octeon_ciu3_source_from_intsn(uint32_t i= ntsn, *source =3D OCTEON_CIU3_SRC_UART0; return true; } + if (intsn =3D=3D OCTEON_CIU3_USB0_INTSN) { + *source =3D OCTEON_CIU3_SRC_USB0; + return true; + } + if (intsn =3D=3D OCTEON_CIU3_USB1_INTSN) { + *source =3D OCTEON_CIU3_SRC_USB1; + return true; + } + if (intsn >=3D OCTEON_CIU3_MBOX_INTSN(0) && intsn < OCTEON_CIU3_MBOX_INTSN(OCTEON_MAX_CPUS)) { *source =3D OCTEON_CIU3_SRC_MBOX0 + @@ -1047,6 +1059,10 @@ static uint32_t octeon_ciu3_source_intsn(unsigned in= t source) switch (source) { case OCTEON_CIU3_SRC_UART0: return OCTEON_CIU3_UART0_INTSN; + case OCTEON_CIU3_SRC_USB0: + return OCTEON_CIU3_USB0_INTSN; + case OCTEON_CIU3_SRC_USB1: + return OCTEON_CIU3_USB1_INTSN; } =20 if (source >=3D OCTEON_CIU3_SRC_MBOX0 && @@ -1061,6 +1077,8 @@ static bool octeon_ciu3_source_is_level(unsigned int = source) { switch (source) { case OCTEON_CIU3_SRC_UART0: + case OCTEON_CIU3_SRC_USB0: + case OCTEON_CIU3_SRC_USB1: return true; } =20 @@ -2156,6 +2174,18 @@ void octeon_irq_set(void *opaque, int irq, int level) } qatomic_set(&s->intc->uart_pending, level); break; + case OCTEON_IRQ_USB0: + src =3D OCTEON_CIU3_SRC_USB0; + if (!octeon_ciu3_set_level(s, src, level)) { + return; + } + break; + case OCTEON_IRQ_USB1: + src =3D OCTEON_CIU3_SRC_USB1; + if (!octeon_ciu3_set_level(s, src, level)) { + return; + } + break; default: return; } @@ -2791,6 +2821,7 @@ static void mips_octeon_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), OCTEON_POW_BASE, &s->pow); =20 + octeon_init_usb(s); octeon_realize_peripherals(s); } =20 diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index f2daa35cdb..6c93c957de 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -22,6 +22,7 @@ #define OCTEON_MIO_BOOT_LOC_SIZE 0x100 #define OCTEON_MIO_EMM_BUF_SIZE 512 #define OCTEON_LMC_COUNT 4 +#define OCTEON_USB_COUNT 2 #define OCTEON_TWSI_COUNT 2 #define OCTEON_TWSI_STAT_IDLE 0xf8 #define OCTEON_SPD_EEPROM_SIZE 139 @@ -29,11 +30,15 @@ =20 typedef enum OcteonIRQ { OCTEON_IRQ_UART, + OCTEON_IRQ_USB0, + OCTEON_IRQ_USB1, OCTEON_IRQ_COUNT, } OcteonIRQ; =20 typedef enum OcteonCiu3Source { OCTEON_CIU3_SRC_UART0, + OCTEON_CIU3_SRC_USB0, + OCTEON_CIU3_SRC_USB1, OCTEON_CIU3_SRC_MBOX0, OCTEON_CIU3_SRC_COUNT =3D OCTEON_CIU3_SRC_MBOX0 + OCTEON_MAX_CPUS, } OcteonCiu3Source; @@ -103,5 +108,6 @@ void octeon_irq_set(void *opaque, int irq, int level); void octeon_validate_ram_size(uint64_t ram_size); void octeon_init_spd(OcteonState *s); void octeon_init_twsi(OcteonState *s); +void octeon_init_usb(OcteonState *s); =20 #endif diff --git a/hw/usb/meson.build b/hw/usb/meson.build index ba55c28ef6..051140fa57 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -28,6 +28,11 @@ system_ss.add(when: 'CONFIG_USB_DWC2', if_true: files('h= cd-dwc2.c')) system_ss.add(when: 'CONFIG_USB_DWC3', if_true: files('hcd-dwc3.c')) system_ss.add(when: 'CONFIG_USB_CHIPIDEA', if_true: files('chipidea.c')) =20 +if 'CONFIG_TCG' in config_all_accel + mips_ss.add(when: 'CONFIG_MIPS_OCTEON', + if_true: files('octeon_usb.c')) +endif + system_ss.add(when: 'CONFIG_IMX_USBPHY', if_true: files('imx-usb-phy.c')) system_ss.add(when: 'CONFIG_VT82C686', if_true: files('vt82c686-uhci-pci.c= ')) system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-usb2= -ctrl-regs.c')) diff --git a/hw/usb/octeon_usb.c b/hw/usb/octeon_usb.c new file mode 100644 index 0000000000..48e9ec234f --- /dev/null +++ b/hw/usb/octeon_usb.c @@ -0,0 +1,319 @@ +/* + * QEMU Cavium Octeon USB controller model. + * + * Copyright (c) 2026 Kirill A. Korinsky + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/bswap.h" +#include "qapi/error.h" +#include "hw/core/irq.h" +#include "hw/core/qdev-properties.h" +#include "hw/core/resettable.h" +#include "hw/core/sysbus.h" +#include "hw/mips/octeon_internal.h" +#include "hw/usb/hcd-dwc3.h" +#include "system/address-spaces.h" +#include "system/memory.h" + +#define OCTEON_UCTL_SIZE 0x100 +#define OCTEON_USB0_UCTL_BASE 0x1180068000000ULL +#define OCTEON_USB1_UCTL_BASE 0x1180069000000ULL +#define OCTEON_USB0_DWC3_BASE 0x1680000000000ULL +#define OCTEON_USB1_DWC3_BASE 0x1690000000000ULL +#define OCTEON_UCTL_SHIM_CFG 0xe8 +#define OCTEON_UCTL_SHIM_CFG_CSR_BYTE_SWAP 0x3 +#define OCTEON_UCTL_SHIM_CFG_CSR_NATIVE 0x3 + +#define TYPE_OCTEON_USB "octeon-usb" +OBJECT_DECLARE_TYPE(OcteonUsbState, OcteonUsbClass, OCTEON_USB) + +struct OcteonUsbState { + SysBusDevice parent_obj; + USBDWC3 dwc3; + unsigned int index; + MemoryRegion uctl; + MemoryRegion dwc3_window; + AddressSpace dwc3_as; + GHashTable *regs; + bool dwc3_as_initialized; +}; + +struct OcteonUsbClass { + SysBusDeviceClass parent_class; + ResettablePhases parent_phases; +}; + +static uint64_t octeon_uctl_read(void *opaque, hwaddr addr, unsigned size) +{ + OcteonUsbState *usb =3D opaque; + hwaddr reg =3D addr & ~7ULL; + uint64_t value; + + if (!octeon_reg_lookup(usb->regs, reg, &value)) { + value =3D 0; + } + + return octeon_read64(value, addr, size); +} + +static void octeon_uctl_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonUsbState *usb =3D opaque; + hwaddr reg =3D addr & ~7ULL; + uint64_t old; + + if (!octeon_reg_lookup(usb->regs, reg, &old)) { + old =3D 0; + } + + octeon_reg_store(usb->regs, reg, octeon_write64(old, addr, value, size= )); +} + +static const MemoryRegionOps octeon_uctl_ops =3D { + .read =3D octeon_uctl_read, + .write =3D octeon_uctl_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + +static bool octeon_usb_csr_needs_swap(OcteonUsbState *usb) +{ +#if TARGET_BIG_ENDIAN + uint64_t value; + + if (!octeon_reg_lookup(usb->regs, OCTEON_UCTL_SHIM_CFG, &value)) { + return true; + } + + return (value & OCTEON_UCTL_SHIM_CFG_CSR_BYTE_SWAP) !=3D + OCTEON_UCTL_SHIM_CFG_CSR_NATIVE; +#else + return false; +#endif +} + +static uint64_t octeon_usb_swap(uint64_t value, unsigned size) +{ + switch (size) { + case 2: + return bswap16(value); + case 4: + return bswap32(value); + case 8: + return bswap64(value); + default: + return value; + } +} + +static uint64_t octeon_dwc3_window_read(void *opaque, hwaddr addr, + unsigned size) +{ + OcteonUsbState *usb =3D opaque; + uint64_t value; + + switch (size) { + case 1: + value =3D address_space_ldub(&usb->dwc3_as, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 2: + value =3D address_space_lduw_le(&usb->dwc3_as, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 4: + value =3D address_space_ldl_le(&usb->dwc3_as, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 8: + value =3D address_space_ldq_le(&usb->dwc3_as, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + default: + g_assert_not_reached(); + } + + if (octeon_usb_csr_needs_swap(usb)) { + value =3D octeon_usb_swap(value, size); + } + + return value; +} + +static void octeon_dwc3_window_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonUsbState *usb =3D opaque; + + if (octeon_usb_csr_needs_swap(usb)) { + value =3D octeon_usb_swap(value, size); + } + + switch (size) { + case 1: + address_space_stb(&usb->dwc3_as, addr, value, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 2: + address_space_stw_le(&usb->dwc3_as, addr, value, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 4: + address_space_stl_le(&usb->dwc3_as, addr, value, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 8: + address_space_stq_le(&usb->dwc3_as, addr, value, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + default: + g_assert_not_reached(); + } +} + +static const MemoryRegionOps octeon_dwc3_window_ops =3D { + .read =3D octeon_dwc3_window_read, + .write =3D octeon_dwc3_window_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 8, + }, +}; + +static void octeon_usb_reset_hold(Object *obj, ResetType type) +{ + OcteonUsbClass *ouc =3D OCTEON_USB_GET_CLASS(obj); + OcteonUsbState *usb =3D OCTEON_USB(obj); + + if (ouc->parent_phases.hold) { + ouc->parent_phases.hold(obj, type); + } + + g_hash_table_remove_all(usb->regs); +} + +static void octeon_usb_realize(DeviceState *dev, Error **errp) +{ + OcteonUsbState *usb =3D OCTEON_USB(dev); + static const char * const uctl_name[OCTEON_USB_COUNT] =3D { + "octeon.usb0-uctl", + "octeon.usb1-uctl", + }; + static const char * const dwc3_window_name[OCTEON_USB_COUNT] =3D { + "octeon.usb0-dwc3-window", + "octeon.usb1-dwc3-window", + }; + static const char * const dwc3_as_name[OCTEON_USB_COUNT] =3D { + "octeon.usb0-dwc3-as", + "octeon.usb1-dwc3-as", + }; + USBDWC3 *dwc3 =3D &usb->dwc3; + SysBusDevice *sbd =3D SYS_BUS_DEVICE(dev); + MemoryRegion *dwc3_mr; + + object_property_set_link(OBJECT(&dwc3->sysbus_xhci), "dma", + OBJECT(get_system_memory()), &error_abort); + qdev_prop_set_uint32(DEVICE(&dwc3->sysbus_xhci), "intrs", 1); + if (!sysbus_realize(SYS_BUS_DEVICE(dwc3), errp)) { + return; + } + + dwc3_mr =3D sysbus_mmio_get_region(SYS_BUS_DEVICE(dwc3), 0); + address_space_init(&usb->dwc3_as, dwc3_mr, + dwc3_as_name[usb->index]); + usb->dwc3_as_initialized =3D true; + memory_region_init_io(&usb->uctl, OBJECT(dev), &octeon_uctl_ops, usb, + uctl_name[usb->index], OCTEON_UCTL_SIZE); + sysbus_init_mmio(sbd, &usb->uctl); + memory_region_init_io(&usb->dwc3_window, OBJECT(dev), + &octeon_dwc3_window_ops, usb, + dwc3_window_name[usb->index], DWC3_SIZE); + sysbus_init_mmio(sbd, &usb->dwc3_window); + sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&dwc3->sysbus_xhci)); +} + +static void octeon_usb_init(Object *obj) +{ + OcteonUsbState *usb =3D OCTEON_USB(obj); + + usb->regs =3D g_hash_table_new_full(octeon_uint64_hash, + octeon_uint64_equal, + g_free, g_free); + object_initialize_child(obj, "dwc3", &usb->dwc3, TYPE_USB_DWC3); +} + +static void octeon_usb_finalize(Object *obj) +{ + OcteonUsbState *usb =3D OCTEON_USB(obj); + + if (usb->dwc3_as_initialized) { + address_space_destroy(&usb->dwc3_as); + } + g_hash_table_destroy(usb->regs); +} + +static void octeon_usb_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + OcteonUsbClass *ouc =3D OCTEON_USB_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + dc->realize =3D octeon_usb_realize; + dc->user_creatable =3D false; + resettable_class_set_parent_phases(rc, NULL, octeon_usb_reset_hold, NU= LL, + &ouc->parent_phases); +} + +static const TypeInfo octeon_usb_type_info =3D { + .name =3D TYPE_OCTEON_USB, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(OcteonUsbState), + .instance_init =3D octeon_usb_init, + .instance_finalize =3D octeon_usb_finalize, + .class_size =3D sizeof(OcteonUsbClass), + .class_init =3D octeon_usb_class_init, +}; + +static void octeon_usb_register_types(void) +{ + type_register_static(&octeon_usb_type_info); +} + +type_init(octeon_usb_register_types) + +void octeon_init_usb(OcteonState *s) +{ + static const uint64_t uctl_base[OCTEON_USB_COUNT] =3D { + OCTEON_USB0_UCTL_BASE, + OCTEON_USB1_UCTL_BASE, + }; + static const uint64_t dwc3_base[OCTEON_USB_COUNT] =3D { + OCTEON_USB0_DWC3_BASE, + OCTEON_USB1_DWC3_BASE, + }; + static const OcteonIRQ irq[OCTEON_USB_COUNT] =3D { + OCTEON_IRQ_USB0, + OCTEON_IRQ_USB1, + }; + unsigned int i; + + for (i =3D 0; i < OCTEON_USB_COUNT; i++) { + DeviceState *dev =3D qdev_new(TYPE_OCTEON_USB); + OcteonUsbState *usb =3D OCTEON_USB(dev); + + usb->index =3D i; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, uctl_base[i]); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, dwc3_base[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + qemu_allocate_irq(octeon_irq_set, s, irq[i])); + } +} --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123226431791.7887704239229; Wed, 15 Jul 2026 06:47:06 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvE-0005kt-Td; Wed, 15 Jul 2026 09:45:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzvC-0005hD-Eq for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:10 -0400 Received: from mx1.catap.net ([162.55.82.72]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv9-0007tj-GT for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:10 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 7f2d6f62 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:54 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 55541d4c; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=LLtVMAi x1FgZtpg1Zegurx1Bh84pk+pkSo1kkwN7FjpTjdKoYXk3poxeg+p9Mchlv+E6zMIwM2K+2 wV4gje8cg/xqhmmQC4gWBsawigVAdiAYLB9ed+WG9ONoOYE1kTqJoXdTWKzX7Rin2skuzU /fZnC7JbayzFdB3LcoARxN/7a3ELe4XFpMrkcU3Axv2XE8w7wfwm7bhX3Ri4VMtUeVVqDZ hT4Wj6PKrugFDFBPoxnMvE7a9PmJN4wepu9brsRK6pqMCOV4nSgT2sRoT3EclC8nkfaCcT mny7hRURQjWo3gsL8WyEVaAdPd6lIYfbZfQ8OYWzx1ug7VfgYG+0VTg== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=W C0X9CxkFxnjeQ7jcSsk5JmdsCC0MaBArridhyyIUkg=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=KPjcY5d/JdvA6If+AwzklwzHCiOwvBvadeGywtaWvsPNXXqK2/imZ6xqdPc3VBIHvcDu DZh3Sah9Wuz03w/hJ0Ir2HsiZpM4+6N6Q9PO8XexYFe7BYI65cHdHHwV06gz0Skgvk8M5M GB3mcK+r5FzVIxYRCLsgYTN6AVhtT/TNpB14XEemRXzLYeVQ87ZY5T2QyPEJ5E34eKvQXo Odq0qULYuFe07FkN8FHfxmZ5PqszhDUnDHo3BSjEO70tjwHraXbB3vUPR0KHsgMOovq1Au 5i+cpbWXjEtnPTmUCsl5Qr6cPaJufNdnipTIYxpQ4NJRD9jbGu1LoPyT33aKfyHQ== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=L1PcFYbz; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=32Tn4Fg1; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=WC0X9Cxk FxnjeQ7jcSsk5JmdsCC0MaBArridhyyIUkg=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=L1PcFYbzjko3snxyHJ5Kzbqpy64lF6rBxLX S5J9kUATSdH3t2c817tYxioi2Hv9BWc5W0fLiGspUYO95aB94bENrYjEHzQG5uxjh7nZYP Mw6fZ0fCgst+WuN/nhdDW6s6VtqyNcr+ELZ/qMkgbGefzQhRm63Uir0J3h6Lb8FNmkaLzt 4FbkBMVXQlwuDpUKUDykw9XSXCl5f0IB5ab5a3qQaT3JU6RYxgjvWBZDl6qk+OkrGzUWqK 5gya1nvLuL0QShYMnqTTxSDH1lgyyfBksNZBP4mcqwOsHIqMhVLvJcioN/7XRfWqgptcRF 4cBSIfDU7eXyMNcblSPc6DPxCgA== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=WC0X9CxkFxnjeQ7jcSsk5JmdsCC0MaBArridhyyIUkg=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=32Tn4Fg1gA7MSFU8Rz TJ3G/g0ZhkdT5KGVjPEVbjytFCx6hcV+Dy/aGqyd69n8JcDNlGtwH/zTnYAgzi1a4VAw== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 23/25] hw/pci-bridge: add Octeon PCI host bridge Date: Wed, 15 Jul 2026 15:44:09 +0200 Message-ID: <20260715134447.56007-24-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=162.55.82.72; envelope-from=kirill@korins.ky; helo=mx1.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123228163158500 Content-Type: text/plain; charset="utf-8" Add the root bus, configuration apertures, I/O window, PEM register access and interrupt routing. Leave guest PCI memory transactions to a separate patch. --- hw/mips/Kconfig | 3 + hw/mips/octeon.c | 69 ++++++- hw/mips/octeon_internal.h | 13 ++ hw/pci-bridge/meson.build | 5 + hw/pci-bridge/octeon_pci.c | 356 +++++++++++++++++++++++++++++++++++++ 5 files changed, 444 insertions(+), 2 deletions(-) create mode 100644 hw/pci-bridge/octeon_pci.c diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 2566df6da6..54ce3cafbd 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -71,6 +71,9 @@ config MIPS_OCTEON bool default y depends on MIPS64 && TARGET_BIG_ENDIAN + imply E1000_PCI + imply PCI_DEVICES + select PCI select PFLASH_CFI02 select SERIAL_MM select USB_DWC3 diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 94717b6c89..19d1451464 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -94,6 +94,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_CSR= _BANK) #define OCTEON_CIU_FUSE 0x728 #define OCTEON_CIU_SUM_IPI 0x0000000100000000ULL #define OCTEON_CIU_SUM_UART 0x0000000800000000ULL +#define OCTEON_CIU_SUM_PCI 0x0000001000000000ULL #define OCTEON_CIU_ENABLE0 0x88006f1800000000ULL #define OCTEON_CIU_IPI_SUM_BASE 0x008 #define OCTEON_CIU_IPI_SUM_STRIDE 0x10 @@ -137,6 +138,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_C= SR_BANK) #define OCTEON_CIU3_SRC_RAW 0x00000002U #define OCTEON_CIU3_NINTSN (1U << 20) #define OCTEON_CIU3_ISC_SIZE (OCTEON_CIU3_NINTSN * 8) +#define OCTEON_CIU3_PEM_INTSN_INTA(port) (((0xc0 + (port)) << 12) + 60) #define OCTEON_CIU3_MBOX_INTSN(cpu) ((cpu) + 0x4000U) #define OCTEON_CIU3_UART0_INTSN 0x8000 #define OCTEON_CSR_BASE 0x1180000000000ULL @@ -304,6 +306,18 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_= CSR_BANK) #define OCTEON_CVMSEG_SIZE 0x4000 #define OCTEON_CVMSEG_TOTAL_SIZE (OCTEON_MAX_CPUS * OCTEON_CVMSEG_SIZE) =20 +#define OCTEON_GSERX_CFG0 0x90000080 +#define OCTEON_GSERX_QLM_STAT0 0x900000a0 +#define OCTEON_RST_CTLX0 0x6001640 +#define OCTEON_RST_SOFT_PRSTX0 0x60016c0 +#define OCTEON_PEMX_CFG_RD0 0xc0000030 +#define OCTEON_PEMX_CFG_WR0 0xc0000028 +#define OCTEON_PEMX_BIST_STATUS0 0xc0000440 +#define OCTEON_PEMX_ON0 0xc0000420 +#define OCTEON_PEMX_STRAP0 0xc0000408 + +#define OCTEON_RST_CTL_HOST_MODE (1ULL << 6) +#define OCTEON_RST_CTL_RST_DONE (1ULL << 8) #define OCTEON_FLASH_BASE 0x1f400000ULL #define OCTEON_FLASH_RESET_BASE 0x1fc00000ULL #define OCTEON_FLASH_RESET_SIZE (4 * MiB) @@ -385,6 +399,7 @@ struct OcteonIntcState { uint64_t ciu_gpio_tx; uint64_t ciu_gpio_bit_cfg[OCTEON_CIU_GPIO_COUNT]; bool uart_pending; + bool pci_pending; uint64_t ciu3_pp_rst; uint32_t ciu3_src_state[OCTEON_CIU3_SRC_COUNT]; uint64_t ciu3_src_ctl[OCTEON_CIU3_SRC_COUNT]; @@ -517,7 +532,8 @@ bool octeon_csr_lookup(OcteonState *s, uint64_t reg, ui= nt64_t *value) if (octeon_mio_emm_decode(reg, &ereg)) { return octeon_reg_lookup(s->emm->regs, ereg, value); } - if (reg =3D=3D OCTEON_RST_SOFT_RST) { + if (reg =3D=3D OCTEON_RST_CTLX0 || reg =3D=3D OCTEON_RST_SOFT_PRSTX0 || + reg =3D=3D OCTEON_RST_SOFT_RST) { return octeon_reg_lookup(s->rst->regs, reg, value); } return octeon_reg_lookup(s->csr_bank->values, reg, value); @@ -531,7 +547,8 @@ static void octeon_csr_store(OcteonState *s, uint64_t r= eg, uint64_t value) octeon_reg_store(s->emm->regs, ereg, value); return; } - if (reg =3D=3D OCTEON_RST_SOFT_RST) { + if (reg =3D=3D OCTEON_RST_CTLX0 || reg =3D=3D OCTEON_RST_SOFT_PRSTX0 || + reg =3D=3D OCTEON_RST_SOFT_RST) { octeon_reg_store(s->rst->regs, reg, value); return; } @@ -1031,6 +1048,10 @@ static void octeon_lmc_write(OcteonLmcState *lmc, hw= addr reg, static bool octeon_ciu3_source_from_intsn(uint32_t intsn, unsigned int *source) { + if (intsn =3D=3D OCTEON_CIU3_PEM_INTSN_INTA(0)) { + *source =3D OCTEON_CIU3_SRC_PCI_INTA; + return true; + } if (intsn =3D=3D OCTEON_CIU3_UART0_INTSN) { *source =3D OCTEON_CIU3_SRC_UART0; return true; @@ -1057,6 +1078,8 @@ static bool octeon_ciu3_source_from_intsn(uint32_t in= tsn, static uint32_t octeon_ciu3_source_intsn(unsigned int source) { switch (source) { + case OCTEON_CIU3_SRC_PCI_INTA: + return OCTEON_CIU3_PEM_INTSN_INTA(0); case OCTEON_CIU3_SRC_UART0: return OCTEON_CIU3_UART0_INTSN; case OCTEON_CIU3_SRC_USB0: @@ -1076,6 +1099,7 @@ static uint32_t octeon_ciu3_source_intsn(unsigned int= source) static bool octeon_ciu3_source_is_level(unsigned int source) { switch (source) { + case OCTEON_CIU3_SRC_PCI_INTA: case OCTEON_CIU3_SRC_UART0: case OCTEON_CIU3_SRC_USB0: case OCTEON_CIU3_SRC_USB1: @@ -1395,6 +1419,9 @@ static uint64_t octeon_ciu_read(void *opaque, hwaddr = addr, unsigned size) if (qatomic_read(&s->intc->uart_pending)) { value |=3D OCTEON_CIU_SUM_UART; } + if (qatomic_read(&s->intc->pci_pending)) { + value |=3D OCTEON_CIU_SUM_PCI; + } octeon_intc_request_cpu_update(s, 0); return octeon_read64(value, addr, size); } @@ -1883,6 +1910,29 @@ static uint64_t octeon_csr_read(void *opaque, hwaddr= addr, unsigned size) return octeon_read64(value, addr, size); case OCTEON_RST_PP_POWER: return octeon_read64(s->rst->rst_pp_power, addr, size); + case OCTEON_GSERX_CFG0: + return octeon_read64(1, addr, size); + case OCTEON_GSERX_QLM_STAT0: + return octeon_read64(3, addr, size); + case OCTEON_RST_CTLX0: + if (!octeon_csr_lookup(s, reg, &value)) { + value =3D OCTEON_RST_CTL_HOST_MODE | OCTEON_RST_CTL_RST_DONE; + } + return octeon_read64(value, addr, size); + case OCTEON_RST_SOFT_PRSTX0: + if (!octeon_csr_lookup(s, reg, &value)) { + value =3D 1; + } + return octeon_read64(value, addr, size); + case OCTEON_PEMX_CFG_RD0: + case OCTEON_PEMX_CFG_WR0: + return octeon_pci_pem_read(s, reg, addr, size); + case OCTEON_PEMX_BIST_STATUS0: + return 0; + case OCTEON_PEMX_ON0: + return octeon_read64(3, addr, size); + case OCTEON_PEMX_STRAP0: + return octeon_read64(3, addr, size); default: break; } @@ -1963,6 +2013,11 @@ static void octeon_csr_write(void *opaque, hwaddr ad= dr, return; } =20 + if (reg =3D=3D OCTEON_PEMX_CFG_RD0 || reg =3D=3D OCTEON_PEMX_CFG_WR0) { + octeon_pci_pem_write(s, reg, addr, value, size); + return; + } + if (reg >=3D OCTEON_MIO_BOOT_REG_CFGX(0) && reg < OCTEON_MIO_BOOT_REG_CFGX(OCTEON_MIO_BOOT_REG_CFG_COUNT)) { unsigned int index =3D OCTEON_MIO_BOOT_REG_CFG_INDEX(reg); @@ -2174,6 +2229,13 @@ void octeon_irq_set(void *opaque, int irq, int level) } qatomic_set(&s->intc->uart_pending, level); break; + case OCTEON_IRQ_PCI: + src =3D OCTEON_CIU3_SRC_PCI_INTA; + if (!octeon_ciu3_set_level(s, src, level)) { + return; + } + qatomic_set(&s->intc->pci_pending, level); + break; case OCTEON_IRQ_USB0: src =3D OCTEON_CIU3_SRC_USB0; if (!octeon_ciu3_set_level(s, src, level)) { @@ -2550,6 +2612,7 @@ static void octeon_intc_reset_hold(Object *obj, Reset= Type type) qatomic_set(&intc->ciu_gpio_tx, 0); memset(intc->ciu_gpio_bit_cfg, 0, sizeof(intc->ciu_gpio_bit_cfg)); qatomic_set(&intc->uart_pending, false); + qatomic_set(&intc->pci_pending, false); qatomic_set(&intc->ciu3_pp_rst, octeon_secondary_cpu_mask(s)); memset(intc->ciu3_src_state, 0, sizeof(intc->ciu3_src_state)); memset(intc->ciu3_src_ctl, 0, sizeof(intc->ciu3_src_ctl)); @@ -2822,6 +2885,7 @@ static void mips_octeon_init(MachineState *machine) &s->pow); =20 octeon_init_usb(s); + octeon_init_pci(s); octeon_realize_peripherals(s); } =20 @@ -2877,6 +2941,7 @@ static void octeon_machine_class_init(ObjectClass *oc= , const void *data) mc->default_ram_size =3D OCTEON_DEFAULT_RAM_SIZE; mc->default_ram_id =3D "octeon.ram"; mc->max_cpus =3D OCTEON_MAX_CPUS; + mc->pci_allow_0_address =3D true; } =20 static const TypeInfo octeon_machine_types[] =3D { diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index 6c93c957de..c2a88dac46 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -30,12 +30,14 @@ =20 typedef enum OcteonIRQ { OCTEON_IRQ_UART, + OCTEON_IRQ_PCI, OCTEON_IRQ_USB0, OCTEON_IRQ_USB1, OCTEON_IRQ_COUNT, } OcteonIRQ; =20 typedef enum OcteonCiu3Source { + OCTEON_CIU3_SRC_PCI_INTA, OCTEON_CIU3_SRC_UART0, OCTEON_CIU3_SRC_USB0, OCTEON_CIU3_SRC_USB1, @@ -93,6 +95,12 @@ struct OcteonState { MemoryRegion uart_alias; MemoryRegion uart_tx; MemoryRegion uart_alias_tx; + MemoryRegion pcie_cfg; + MemoryRegion pcie_sli_cfg; + MemoryRegion pcie0_io; + + DeviceState *pci_host; + PCIBus *pci_bus; }; =20 guint octeon_uint64_hash(gconstpointer v); @@ -109,5 +117,10 @@ void octeon_validate_ram_size(uint64_t ram_size); void octeon_init_spd(OcteonState *s); void octeon_init_twsi(OcteonState *s); void octeon_init_usb(OcteonState *s); +void octeon_init_pci(OcteonState *s); +uint64_t octeon_pci_pem_read(OcteonState *s, hwaddr reg, + hwaddr addr, unsigned size); +void octeon_pci_pem_write(OcteonState *s, hwaddr reg, hwaddr addr, + uint64_t value, unsigned size); =20 #endif diff --git a/hw/pci-bridge/meson.build b/hw/pci-bridge/meson.build index 2e0eb0d233..caababc555 100644 --- a/hw/pci-bridge/meson.build +++ b/hw/pci-bridge/meson.build @@ -9,6 +9,11 @@ pci_ss.add(when: 'CONFIG_PXB', if_true: files('pci_expande= r_bridge.c'), pci_ss.add(when: 'CONFIG_XIO3130', if_true: files('xio3130_upstream.c', 'x= io3130_downstream.c')) pci_ss.add(when: 'CONFIG_CXL', if_true: files('cxl_root_port.c', 'cxl_upst= ream.c', 'cxl_downstream.c')) =20 +if 'CONFIG_TCG' in config_all_accel + mips_ss.add(when: 'CONFIG_MIPS_OCTEON', + if_true: files('octeon_pci.c')) +endif + # Sun4u pci_ss.add(when: 'CONFIG_SIMBA', if_true: files('simba.c')) =20 diff --git a/hw/pci-bridge/octeon_pci.c b/hw/pci-bridge/octeon_pci.c new file mode 100644 index 0000000000..e2f856e164 --- /dev/null +++ b/hw/pci-bridge/octeon_pci.c @@ -0,0 +1,356 @@ +/* + * QEMU Cavium Octeon PCI host bridge model. + * + * Copyright (c) 2026 Kirill A. Korinsky + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/core/resettable.h" +#include "hw/core/sysbus.h" +#include "hw/mips/octeon_internal.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "qemu/module.h" +#include "system/memory.h" + +#define TYPE_OCTEON_PCI_HOST "octeon-pci-host" +OBJECT_DECLARE_TYPE(OcteonPCIHostState, OcteonPCIHostClass, + OCTEON_PCI_HOST) + +#define OCTEON_PCIE_CFG_BASE 0x1190400000000ULL +#define OCTEON_PCIE_CFG_SIZE 0x20000000ULL +#define OCTEON_PCIE_SLI_CFG_BASE 0x1190c00000000ULL +#define OCTEON_PCIE_SLI_CFG_PORTS 4 +#define OCTEON_PCIE_SLI_CFG_PORT_SIZE (1ULL << 32) +#define OCTEON_PCIE_SLI_CFG_SIZE \ + (OCTEON_PCIE_SLI_CFG_PORTS * OCTEON_PCIE_SLI_CFG_PORT_SIZE) +#define OCTEON_PCIE0_IO_BASE 0x11a0400000000ULL +#define OCTEON_PCIE0_IO_SIZE (1ULL << 32) +#define OCTEON_PCIE0_MEM_SIZE (1ULL << 32) +#define OCTEON_PCIE0_ENDPOINT_DEVFN PCI_DEVFN(0x0b, 0) +#define OCTEON_PEMX_CFG_WR0 0xc0000028 +#define OCTEON_PEMX_CFG_RD0 0xc0000030 +#define OCTEON_PCIE_CFG006 0x018 +#define OCTEON_PCIE_CFG031 0x07c +#define OCTEON_PCIE_CFG032 0x080 +#define OCTEON_PCIE_CFG068 0x110 + +struct OcteonPCIHostState { + PCIHostState parent_obj; + MemoryRegion mem; + MemoryRegion io; + uint32_t pem_cfg_rd_addr; + uint64_t pem_cfg_wr; + GHashTable *root_cfg; +}; + +struct OcteonPCIHostClass { + PCIHostBridgeClass parent_class; + ResettablePhases parent_phases; +}; + +static void octeon_pci_host_reset_hold(Object *obj, ResetType type) +{ + OcteonPCIHostState *host =3D OCTEON_PCI_HOST(obj); + OcteonPCIHostClass *opc =3D OCTEON_PCI_HOST_GET_CLASS(obj); + + if (opc->parent_phases.hold) { + opc->parent_phases.hold(obj, type); + } + + host->pem_cfg_rd_addr =3D 0; + host->pem_cfg_wr =3D 0; + g_hash_table_remove_all(host->root_cfg); +} + +static OcteonPCIHostState *octeon_pci_host(OcteonState *s) +{ + return OCTEON_PCI_HOST(s->pci_host); +} + +static uint32_t octeon_pcie_root_cfg_default(uint32_t reg) +{ + switch (reg) { + case OCTEON_PCIE_CFG006: + return 0x00010101; + case OCTEON_PCIE_CFG031: + return 0x00000011; + case OCTEON_PCIE_CFG032: + return 0x20110000; + default: + return 0; + } +} + +static uint32_t octeon_pcie_root_cfg_read(OcteonPCIHostState *host, + uint32_t reg) +{ + uint64_t value; + + reg &=3D ~3U; + switch (reg) { + case OCTEON_PCIE_CFG006: + case OCTEON_PCIE_CFG031: + case OCTEON_PCIE_CFG032: + return octeon_pcie_root_cfg_default(reg); + default: + break; + } + + if (octeon_reg_lookup(host->root_cfg, reg, &value)) { + return value; + } + + return octeon_pcie_root_cfg_default(reg); +} + +static void octeon_pcie_root_cfg_write(OcteonPCIHostState *host, + uint32_t reg, uint32_t value) +{ + reg &=3D ~3U; + if (reg =3D=3D OCTEON_PCIE_CFG068) { + value =3D 0; + } + + octeon_reg_store(host->root_cfg, reg, value); +} + +uint64_t octeon_pci_pem_read(OcteonState *s, hwaddr reg, + hwaddr addr, unsigned size) +{ + OcteonPCIHostState *host =3D octeon_pci_host(s); + uint64_t value; + + switch (reg) { + case OCTEON_PEMX_CFG_RD0: + value =3D ((uint64_t)octeon_pcie_root_cfg_read( + host, host->pem_cfg_rd_addr) << 32) | + host->pem_cfg_rd_addr; + break; + case OCTEON_PEMX_CFG_WR0: + value =3D host->pem_cfg_wr; + break; + default: + g_assert_not_reached(); + } + + return octeon_read64(value, addr, size); +} + +void octeon_pci_pem_write(OcteonState *s, hwaddr reg, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonPCIHostState *host =3D octeon_pci_host(s); + + switch (reg) { + case OCTEON_PEMX_CFG_RD0: + value =3D octeon_write64(0, addr, value, size); + host->pem_cfg_rd_addr =3D value; + break; + case OCTEON_PEMX_CFG_WR0: + value =3D octeon_write64(host->pem_cfg_wr, addr, value, size); + octeon_pcie_root_cfg_write(host, value, value >> 32); + host->pem_cfg_wr =3D value; + break; + default: + g_assert_not_reached(); + } +} + +static uint64_t octeon_pci_absent(unsigned size) +{ + return size =3D=3D 1 ? 0xff : size =3D=3D 2 ? 0xffff : 0xffffffffU; +} + +static bool octeon_pcie_config_addr(hwaddr addr, uint32_t *pci_addr, + bool sli_cfg) +{ + unsigned int bus =3D (addr >> 20) & 0xff; + unsigned int dev =3D (addr >> 15) & 0x1f; + unsigned int fn =3D (addr >> 12) & 0x7; + unsigned int reg =3D addr & 0xfff; + + if (sli_cfg) { + if (addr >=3D OCTEON_PCIE_SLI_CFG_PORT_SIZE || + bus !=3D 0 || dev !=3D 0 || fn !=3D 0 || + reg >=3D PCI_CONFIG_SPACE_SIZE) { + return false; + } + } else if (bus !=3D 1 || dev !=3D 0 || fn !=3D 0 || + reg >=3D PCI_CONFIG_SPACE_SIZE) { + return false; + } + + *pci_addr =3D 0x80000000U | (OCTEON_PCIE0_ENDPOINT_DEVFN << 8) | reg; + return true; +} + +static uint64_t octeon_pcie_cfg_read(void *opaque, hwaddr addr, + unsigned size) +{ + OcteonState *s =3D opaque; + uint32_t pci_addr; + + if (!octeon_pcie_config_addr(addr, &pci_addr, false)) { + return octeon_pci_absent(size); + } + + return pci_data_read(s->pci_bus, pci_addr, size); +} + +static void octeon_pcie_cfg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonState *s =3D opaque; + uint32_t pci_addr; + + if (octeon_pcie_config_addr(addr, &pci_addr, false)) { + pci_data_write(s->pci_bus, pci_addr, value, size); + } +} + +static const MemoryRegionOps octeon_pcie_cfg_ops =3D { + .read =3D octeon_pcie_cfg_read, + .write =3D octeon_pcie_cfg_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + }, +}; + +static uint64_t octeon_pcie_sli_cfg_read(void *opaque, hwaddr addr, + unsigned size) +{ + OcteonState *s =3D opaque; + uint32_t pci_addr; + + if (!octeon_pcie_config_addr(addr, &pci_addr, true)) { + return octeon_pci_absent(size); + } + + return pci_data_read(s->pci_bus, pci_addr, size); +} + +static void octeon_pcie_sli_cfg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonState *s =3D opaque; + uint32_t pci_addr; + + if (octeon_pcie_config_addr(addr, &pci_addr, true)) { + pci_data_write(s->pci_bus, pci_addr, value, size); + } +} + +static const MemoryRegionOps octeon_pcie_sli_cfg_ops =3D { + .read =3D octeon_pcie_sli_cfg_read, + .write =3D octeon_pcie_sli_cfg_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + }, +}; + +static int octeon_pci_map_irq(PCIDevice *pci_dev, int irq_num) +{ + return 0; +} + +static void octeon_pci_set_irq(void *opaque, int irq_num, int level) +{ + octeon_irq_set(opaque, OCTEON_IRQ_PCI, level); +} + +static void octeon_pci_host_init(Object *obj) +{ + OcteonPCIHostState *host =3D OCTEON_PCI_HOST(obj); + + host->root_cfg =3D g_hash_table_new_full(octeon_uint64_hash, + octeon_uint64_equal, + g_free, g_free); +} + +static void octeon_pci_host_finalize(Object *obj) +{ + OcteonPCIHostState *host =3D OCTEON_PCI_HOST(obj); + + g_hash_table_destroy(host->root_cfg); +} + +static void octeon_pci_host_class_init(ObjectClass *klass, const void *dat= a) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + OcteonPCIHostClass *opc =3D OCTEON_PCI_HOST_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + dc->fw_name =3D "pci"; + dc->user_creatable =3D false; + resettable_class_set_parent_phases(rc, NULL, + octeon_pci_host_reset_hold, NULL, + &opc->parent_phases); +} + +static const TypeInfo octeon_pci_host_info =3D { + .name =3D TYPE_OCTEON_PCI_HOST, + .parent =3D TYPE_PCI_HOST_BRIDGE, + .instance_size =3D sizeof(OcteonPCIHostState), + .instance_init =3D octeon_pci_host_init, + .instance_finalize =3D octeon_pci_host_finalize, + .class_size =3D sizeof(OcteonPCIHostClass), + .class_init =3D octeon_pci_host_class_init, +}; + +static void octeon_pci_host_register_types(void) +{ + type_register_static(&octeon_pci_host_info); +} + +type_init(octeon_pci_host_register_types) + +void octeon_init_pci(OcteonState *s) +{ + DeviceState *dev; + OcteonPCIHostState *host; + PCIHostState *phb; + + dev =3D qdev_new(TYPE_OCTEON_PCI_HOST); + host =3D OCTEON_PCI_HOST(dev); + s->pci_host =3D dev; + phb =3D PCI_HOST_BRIDGE(dev); + + memory_region_init(&host->mem, OBJECT(dev), "octeon.pci-mem", + OCTEON_PCIE0_MEM_SIZE); + memory_region_init(&host->io, OBJECT(dev), "octeon.pci-io", + OCTEON_PCIE0_IO_SIZE); + + phb->bus =3D pci_root_bus_new(dev, "pci", &host->mem, &host->io, + OCTEON_PCIE0_ENDPOINT_DEVFN, TYPE_PCI_BUS); + s->pci_bus =3D phb->bus; + pci_bus_irqs(s->pci_bus, octeon_pci_set_irq, s, 1); + pci_bus_map_irqs(s->pci_bus, octeon_pci_map_irq); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + memory_region_init_io(&s->pcie_cfg, NULL, &octeon_pcie_cfg_ops, s, + "octeon.pcie-config", OCTEON_PCIE_CFG_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_PCIE_CFG_BASE, + &s->pcie_cfg); + + memory_region_init_io(&s->pcie_sli_cfg, NULL, &octeon_pcie_sli_cfg_ops, + s, "octeon.pcie-sli-config", + OCTEON_PCIE_SLI_CFG_SIZE); + memory_region_add_subregion(get_system_memory(), + OCTEON_PCIE_SLI_CFG_BASE, + &s->pcie_sli_cfg); + + memory_region_init_alias(&s->pcie0_io, NULL, "octeon.pcie0-io", + &host->io, 0, + OCTEON_PCIE0_IO_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_PCIE0_IO_BASE, + &s->pcie0_io); + +} --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123348829326.41870859319806; Wed, 15 Jul 2026 06:49:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvA-0005eI-LD; Wed, 15 Jul 2026 09:45:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv8-0005bk-HI for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:06 -0400 Received: from mx2.catap.net ([65.21.79.163]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzv5-0007uu-WA for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:06 -0400 Received: by mx2.catap.net (OpenSMTPD) with ESMTPSA id 9898da1c (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:54 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 63c9d030; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=FSYss4E 6G78Mxg6nUb74Iuiv81sZwFjpvw5yo21CYHHs7vgPwVIoxguHFqWE0sp8Nnyhrro1G9f/e YM6zLOugu7Az5RlVSA8L8G1Ahewkmtr7usyespUN35RcWqKgSrjRo5nlo7LeptVoT5ZINA LzMm1y/07Aeoqlcl6r92lmTrfBVSX9U4rkK7JcN8ZQlQHDxkEN66gAceuf3Hd/xSiHnDAC 2c0h9nfDl/kSZb2EDsUJB0kYau0N5aPb7UQTEqGCRGbetLKzpN78V7TG5ajMm3JgjDfHFH R/F3O3kb/A4LCzShO1IBwOBMxmNEWgrh6qAmv+YvLrvN2hCJjTWI8DA== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=n PKJd+UnP1RxQyBUkK4Ab2d7ziYU/ci5duWF0Xg8A6M=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=Q7nfoH+7TSmgerDz6w4RMMmYIsIeQjttn3GRt9T4tBv50Kpe+Er7jyIJOZtD8oEHSZS7 YA2YASOanWDL7SMeNQbpLaY2sY7LcDNB6u7A+nFo31fkU4m/vg7w5bMZoVxe4cgSdYzn4X Ky7p2YpuYh7lfN5mJsMRWrHoxMrdScc5+2Ye6SNcGxjFlMFQgz2rF0g+CBCi7Mb7zUcwZ4 OcyMLLRDkDJpDGz9PkPXUJDYKoMWiy9k4qqMxj36oMlWZJHgr7Hk1iXatscflhkKNWcPte tMphylFNyvS4K3/sweCcqDTYCSg8yAEiUFQfKvSYxqsqZ3myK0DPOldoKiREDTYQ== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=jmCvIuRh; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=LTzh/IL4; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=nPKJd+Un P1RxQyBUkK4Ab2d7ziYU/ci5duWF0Xg8A6M=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=jmCvIuRhaq/cVC9BAvmDWrYMktJ4X4qSRlC /gTYWD8lpzzxPnwyJn+HsNDvuUZUC+3O1Cq5wfIedblUvofsYuIfUGRXjffMU24rBDbCd4 +MR7GUCYflHaND7bhzeLXRtwykYFr1/DcikWtokjHjkZ/X+rNRV/2BJ7GZvJGKblEBhFhm /XRElkshiGmril+o/eTFQ70aZqeeFg7zrwKBhwdgzjr9qV3Q2Yj2ayWb3b0Fqt+ISwnFgi NZG8KZkth7uPYVufJTsWTvnbZSxh/n9t5NSncj8zmRe/+8C8mh6U7rx2N4g3A03f1rFU8G 8IufaEc09Oujshy2xKUZuSrNlqg== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=nPKJd+UnP1RxQyBUkK4Ab2d7ziYU/ci5duWF0Xg8A6M=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=LTzh/IL4E1FlunAIvK vH1uqcCPfAjKN34JVQTntZ8GU0ak3cZrkCyq4akJRwePMoO24yPv8tdLJL/YjcNGSLAA== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 24/25] hw/pci-bridge: add Octeon PCI memory window Date: Wed, 15 Jul 2026 15:44:10 +0200 Message-ID: <20260715134447.56007-25-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=65.21.79.163; envelope-from=kirill@korins.ky; helo=mx2.catap.net X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123350479158500 Content-Type: text/plain; charset="utf-8" Map the PCI memory aperture and PEXP register bank. Apply SUBID controlled byte swapping to transactions between the big endian CPU and little endian PCI memory space. --- hw/mips/octeon.c | 26 ++++++ hw/mips/octeon_internal.h | 8 ++ hw/pci-bridge/octeon_pci.c | 174 +++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c index 19d1451464..596fd678ff 100644 --- a/hw/mips/octeon.c +++ b/hw/mips/octeon.c @@ -2075,6 +2075,27 @@ static void octeon_stateful_io_write(OcteonState *s,= uint64_t base, octeon_csr_store(s, reg, octeon_write64(old, addr, value, size)); } =20 +static uint64_t octeon_pexp_read(void *opaque, hwaddr addr, unsigned size) +{ + return octeon_pci_pexp_read(opaque, addr, size); +} + +static void octeon_pexp_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + octeon_pci_pexp_write(opaque, addr, value, size); +} + +static const MemoryRegionOps octeon_pexp_ops =3D { + .read =3D octeon_pexp_read, + .write =3D octeon_pexp_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + }, +}; + static uint64_t octeon_dpi_read(void *opaque, hwaddr addr, unsigned size) { return octeon_stateful_io_read(opaque, OCTEON_DPI_BASE, addr, size); @@ -2854,6 +2875,11 @@ static void mips_octeon_init(MachineState *machine) memory_region_add_subregion_overlap(get_system_memory(), OCTEON_CSR_BA= SE, &s->csr_bank->csr, -1); =20 + memory_region_init_io(&s->pexp, NULL, &octeon_pexp_ops, s, + "octeon.pexp", OCTEON_PEXP_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_PEXP_BASE, + &s->pexp); + memory_region_init_io(&s->dpi, NULL, &octeon_dpi_ops, s, "octeon.dpi", OCTEON_DPI_SIZE); memory_region_add_subregion(get_system_memory(), OCTEON_DPI_BASE, diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h index c2a88dac46..f4ecbbac4f 100644 --- a/hw/mips/octeon_internal.h +++ b/hw/mips/octeon_internal.h @@ -18,6 +18,8 @@ #define OCTEON_CIU_GPIO_COUNT 32 #define OCTEON_CIU3_CP0_IRQ_COUNT 4 #define OCTEON_CIU3_IDT_COUNT (OCTEON_MAX_CPUS * 4) +#define OCTEON_PEXP_BASE 0x11f0000000000ULL +#define OCTEON_PEXP_SIZE 0x40000 #define OCTEON_MIO_BOOT_REG_CFG_COUNT 8 #define OCTEON_MIO_BOOT_LOC_SIZE 0x100 #define OCTEON_MIO_EMM_BUF_SIZE 512 @@ -78,6 +80,7 @@ struct OcteonState { MemoryRegion boot_flash; MemoryRegion boot_flash_alias; MemoryRegion cvmseg; + MemoryRegion pexp; MemoryRegion dpi; MemoryRegion fpa; MemoryRegion ipd; @@ -98,6 +101,8 @@ struct OcteonState { MemoryRegion pcie_cfg; MemoryRegion pcie_sli_cfg; MemoryRegion pcie0_io; + MemoryRegion pcie0_mem; + AddressSpace pcie0_mem_as; =20 DeviceState *pci_host; PCIBus *pci_bus; @@ -122,5 +127,8 @@ uint64_t octeon_pci_pem_read(OcteonState *s, hwaddr reg, hwaddr addr, unsigned size); void octeon_pci_pem_write(OcteonState *s, hwaddr reg, hwaddr addr, uint64_t value, unsigned size); +uint64_t octeon_pci_pexp_read(OcteonState *s, hwaddr addr, unsigned size); +void octeon_pci_pexp_write(OcteonState *s, hwaddr addr, + uint64_t value, unsigned size); =20 #endif diff --git a/hw/pci-bridge/octeon_pci.c b/hw/pci-bridge/octeon_pci.c index e2f856e164..02c42c4d09 100644 --- a/hw/pci-bridge/octeon_pci.c +++ b/hw/pci-bridge/octeon_pci.c @@ -7,6 +7,7 @@ */ =20 #include "qemu/osdep.h" +#include "qemu/bswap.h" #include "qapi/error.h" #include "hw/core/resettable.h" #include "hw/core/sysbus.h" @@ -14,6 +15,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" #include "qemu/module.h" +#include "system/address-spaces.h" #include "system/memory.h" =20 #define TYPE_OCTEON_PCI_HOST "octeon-pci-host" @@ -29,7 +31,15 @@ OBJECT_DECLARE_TYPE(OcteonPCIHostState, OcteonPCIHostCla= ss, (OCTEON_PCIE_SLI_CFG_PORTS * OCTEON_PCIE_SLI_CFG_PORT_SIZE) #define OCTEON_PCIE0_IO_BASE 0x11a0400000000ULL #define OCTEON_PCIE0_IO_SIZE (1ULL << 32) +#define OCTEON_PCIE0_MEM_BASE 0x11b0000000000ULL #define OCTEON_PCIE0_MEM_SIZE (1ULL << 32) +#define OCTEON_SLI_MEM_ACCESS_SUBID_BASE 0x000000e0 +#define OCTEON_SLI_MEM_ACCESS_SUBID_STRIDE 16 +#define OCTEON_SLI_MEM_ACCESS_SUBID_ESR_M 0x0000003000000000ULL +#define OCTEON_SLI_MEM_ACCESS_SUBID_ESR_S 36 +#define OCTEON_SLI_MEM_ACCESS_SUBID_ESW_M 0x0000000c00000000ULL +#define OCTEON_SLI_MEM_ACCESS_SUBID_ESW_S 34 +#define OCTEON_SLI_MEM_ACCESS_SWAP 3 #define OCTEON_PCIE0_ENDPOINT_DEVFN PCI_DEVFN(0x0b, 0) #define OCTEON_PEMX_CFG_WR0 0xc0000028 #define OCTEON_PEMX_CFG_RD0 0xc0000030 @@ -45,6 +55,7 @@ struct OcteonPCIHostState { uint32_t pem_cfg_rd_addr; uint64_t pem_cfg_wr; GHashTable *root_cfg; + GHashTable *pexp_regs; }; =20 struct OcteonPCIHostClass { @@ -64,6 +75,7 @@ static void octeon_pci_host_reset_hold(Object *obj, Reset= Type type) host->pem_cfg_rd_addr =3D 0; host->pem_cfg_wr =3D 0; g_hash_table_remove_all(host->root_cfg); + g_hash_table_remove_all(host->pexp_regs); } =20 static OcteonPCIHostState *octeon_pci_host(OcteonState *s) @@ -160,6 +172,34 @@ void octeon_pci_pem_write(OcteonState *s, hwaddr reg, = hwaddr addr, } } =20 +uint64_t octeon_pci_pexp_read(OcteonState *s, hwaddr addr, unsigned size) +{ + OcteonPCIHostState *host =3D octeon_pci_host(s); + uint64_t reg =3D OCTEON_PEXP_BASE + (addr & ~7ULL); + uint64_t value; + + if (!octeon_reg_lookup(host->pexp_regs, reg, &value)) { + value =3D 0; + } + + return octeon_read64(value, addr, size); +} + +void octeon_pci_pexp_write(OcteonState *s, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonPCIHostState *host =3D octeon_pci_host(s); + uint64_t reg =3D OCTEON_PEXP_BASE + (addr & ~7ULL); + uint64_t old; + + if (!octeon_reg_lookup(host->pexp_regs, reg, &old)) { + old =3D 0; + } + + octeon_reg_store(host->pexp_regs, reg, + octeon_write64(old, addr, value, size)); +} + static uint64_t octeon_pci_absent(unsigned size) { return size =3D=3D 1 ? 0xff : size =3D=3D 2 ? 0xffff : 0xffffffffU; @@ -256,6 +296,130 @@ static const MemoryRegionOps octeon_pcie_sli_cfg_ops = =3D { }, }; =20 +static uint64_t octeon_pcie_bswap(uint64_t value, unsigned size) +{ + switch (size) { + case 1: + return value; + case 2: + return bswap16(value); + case 4: + return bswap32(value); + case 8: + return bswap64(value); + default: + g_assert_not_reached(); + } +} + +static uint64_t octeon_pcie_mem_subid_reg(hwaddr addr) +{ + unsigned int subid =3D (addr >> 28) & 3; + + return OCTEON_PEXP_BASE + OCTEON_SLI_MEM_ACCESS_SUBID_BASE + + subid * OCTEON_SLI_MEM_ACCESS_SUBID_STRIDE; +} + +static bool octeon_pcie_mem_swap_enabled(OcteonPCIHostState *host, + hwaddr addr, bool write) +{ + uint64_t value; + uint64_t mask =3D write ? OCTEON_SLI_MEM_ACCESS_SUBID_ESW_M : + OCTEON_SLI_MEM_ACCESS_SUBID_ESR_M; + unsigned int shift =3D write ? OCTEON_SLI_MEM_ACCESS_SUBID_ESW_S : + OCTEON_SLI_MEM_ACCESS_SUBID_ESR_S; + + if (!octeon_reg_lookup(host->pexp_regs, + octeon_pcie_mem_subid_reg(addr), &value)) { + return false; + } + + return ((value & mask) >> shift) =3D=3D OCTEON_SLI_MEM_ACCESS_SWAP; +} + +static uint64_t octeon_pcie0_mem_read(void *opaque, hwaddr addr, + unsigned size) +{ + OcteonState *s =3D opaque; + OcteonPCIHostState *host =3D octeon_pci_host(s); + uint64_t value; + + switch (size) { + case 1: + value =3D address_space_ldub(&s->pcie0_mem_as, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 2: + value =3D address_space_lduw_le(&s->pcie0_mem_as, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 4: + value =3D address_space_ldl_le(&s->pcie0_mem_as, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 8: + value =3D address_space_ldq_le(&s->pcie0_mem_as, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + default: + g_assert_not_reached(); + } + + if (TARGET_BIG_ENDIAN && + !octeon_pcie_mem_swap_enabled(host, addr, false)) { + value =3D octeon_pcie_bswap(value, size); + } + + return value; +} + +static void octeon_pcie0_mem_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + OcteonState *s =3D opaque; + OcteonPCIHostState *host =3D octeon_pci_host(s); + + if (TARGET_BIG_ENDIAN && + !octeon_pcie_mem_swap_enabled(host, addr, true)) { + value =3D octeon_pcie_bswap(value, size); + } + + switch (size) { + case 1: + address_space_stb(&s->pcie0_mem_as, addr, value, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 2: + address_space_stw_le(&s->pcie0_mem_as, addr, value, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 4: + address_space_stl_le(&s->pcie0_mem_as, addr, value, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + case 8: + address_space_stq_le(&s->pcie0_mem_as, addr, value, + MEMTXATTRS_UNSPECIFIED, NULL); + break; + default: + g_assert_not_reached(); + } +} + +static const MemoryRegionOps octeon_pcie0_mem_ops =3D { + .read =3D octeon_pcie0_mem_read, + .write =3D octeon_pcie0_mem_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 8, + }, + .impl =3D { + .min_access_size =3D 1, + .max_access_size =3D 8, + }, +}; + static int octeon_pci_map_irq(PCIDevice *pci_dev, int irq_num) { return 0; @@ -273,6 +437,9 @@ static void octeon_pci_host_init(Object *obj) host->root_cfg =3D g_hash_table_new_full(octeon_uint64_hash, octeon_uint64_equal, g_free, g_free); + host->pexp_regs =3D g_hash_table_new_full(octeon_uint64_hash, + octeon_uint64_equal, + g_free, g_free); } =20 static void octeon_pci_host_finalize(Object *obj) @@ -280,6 +447,7 @@ static void octeon_pci_host_finalize(Object *obj) OcteonPCIHostState *host =3D OCTEON_PCI_HOST(obj); =20 g_hash_table_destroy(host->root_cfg); + g_hash_table_destroy(host->pexp_regs); } =20 static void octeon_pci_host_class_init(ObjectClass *klass, const void *dat= a) @@ -353,4 +521,10 @@ void octeon_init_pci(OcteonState *s) memory_region_add_subregion(get_system_memory(), OCTEON_PCIE0_IO_BASE, &s->pcie0_io); =20 + address_space_init(&s->pcie0_mem_as, &host->mem, + "octeon.pcie0-mem-as"); + memory_region_init_io(&s->pcie0_mem, NULL, &octeon_pcie0_mem_ops, s, + "octeon.pcie0-mem", OCTEON_PCIE0_MEM_SIZE); + memory_region_add_subregion(get_system_memory(), OCTEON_PCIE0_MEM_BASE, + &s->pcie0_mem); } --=20 2.54.0 From nobody Sat Jul 25 17:36:06 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; arc=fail (Bad Signature); dmarc=fail(p=none dis=none) header.from=korins.ky Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784123229110377.8114487156099; Wed, 15 Jul 2026 06:47:09 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjzvD-0005ji-Ma; Wed, 15 Jul 2026 09:45:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzvC-0005gb-13 for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:10 -0400 Received: from mx1.catap.net ([2a01:4f8:271:125e::2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjzvA-0007uq-1k for qemu-devel@nongnu.org; Wed, 15 Jul 2026 09:45:09 -0400 Received: by mx1.catap.net (OpenSMTPD) with ESMTPSA id 468d5614 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Wed, 15 Jul 2026 15:44:54 +0200 (CEST) Received: from localhost (matebook.home.arpa [local]) by matebook.home.arpa (OpenSMTPD) with ESMTPA id 1ab98d2d; Wed, 15 Jul 2026 15:44:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=20240125rsa; cv=none; d=mx.catap.net; b=WvHWwAN 09+1Q+5CYFe7MaVuqOxEm/Mv9YjQdnc5l3Tn8tpUaFhDgT8mqzpAaBJHpLGW00P/xW7T58 ffmdLBWLTvQRIDftdV/JSRvfpJ7fV2c/E1KjoruRbWzT6Ja6eOFqVNt0sF8PmnDwLjssrf VwX1VrZ7rjoRWGuyiLRru6q5IYLqmwwc5WeFHy1pK6YnlRfAxLV3rUEZfQNQsApAjAXMdl cj3N6VwE/kVdnbDXo8Y/2Fr57X9ruKCV66zLZLSQONin1NrfOZXG9BjWwll3hykm2Z0ZGm +7Kvx1u5Ka9MuWFKYoi2Kki1roEbKv6/8EZckBEopPWhwUwsuEECyIg== ARC-Message-Signature: i=1; a=rsa-sha256; s=20240125rsa; c=simple/simple; bh=T GGxxsklXjx+ZJoAtFmAIFNHc6Ki8pOSEDu4M+u9ZV8=; h=references:in-reply-to: date:subject:cc:to:from:dkim-signature:dkim-signature; d=mx.catap.net; b=L25K0X8aH7E/tzbnxR3Z+mNgEcGz+a+ucfE/8AMHbZLztnzrNZSTfR/H/BG45GRe2TSl WHTbCCQfJmUQf7czIJvN1AbIG1pgb0FBKhmj3WDYCOGhIWbkcut0HlfcvWU0EZFW6O6zQi yT7hvtabZAJ/uLr+yIcWHuLxz3vyxQq5FcvjkdXsUQkoEEbiH2KcWFgTz731RBWl9U/pbY 0D4nXroxSUN8IgC9EnRobt4M8aD/g0m/afhACremFSNEnwRlNubDU6a749iJS5m6LHzDXG jWob9TeBcZTCNUOwyHBZytBXqV4M/LEL+w/wjXTYMlMo6+XnAa6+hkGG9ul6nJWQ== ARC-Authentication-Results: i=1; mx.catap.net; dkim=pass header.s=20240125rsa header.d=korins.ky header.a=rsa-sha256 header.b=fqsKpJbu; dkim=pass header.s=20240125ed25519 header.d=korins.ky header.a=ed25519-sha256 header.b=gCdQWRpD; arc=none; iprev=pass; spf=none smtp.helo=postmaster@matebook.home.arpa; spf=softfail smtp.mailfrom=kirill@korins.ky DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=20240125rsa; bh=TGGxxskl Xjx+ZJoAtFmAIFNHc6Ki8pOSEDu4M+u9ZV8=; h=references:in-reply-to:date: subject:cc:to:from; d=korins.ky; b=fqsKpJbuEUXHfyz2XjuHGiX9sJFzIfH7h89 NrCkHDWsUzZq6mHHtadLJo51s5zoRpkTMkFIv0jvOashrRCNkn8hORXPOlpWYpM3yLo9M2 awT2tMFCEhpMS2nlAYx+Re3GFoououY8gJkc18R2D8LeaZE2hPTQFOfSVqCJRPOIP/iVCl a6vbcEuDWPszR/3ESk3GFu0BP5dHoU9jrfL9HueU/WmLolhQb5CRyPbY665Rx4DdjZo1Mh 9E4s9GcAe5CoW08mtu20q1aI0QMxjcq9r08NEmPeMTyu6nnERwpxZjoZBP+/Idqucvvy8i eykIyg4GOMPPYM9AmCTuOhz1oXQ== DKIM-Signature: v=1; a=ed25519-sha256; c=simple/simple; s=20240125ed25519; bh=TGGxxsklXjx+ZJoAtFmAIFNHc6Ki8pOSEDu4M+u9ZV8=; h=references: in-reply-to:date:subject:cc:to:from; d=korins.ky; b=gCdQWRpDE4trh+E3pc v+v0Iz9ytXkk3THazUNCqn7BLBxByn9NrVjD019TeKvg2zt1mSVJH8EFV9fIVB127lCg== From: "Kirill A. Korinsky" To: qemu-devel@nongnu.org Cc: "Kirill A. Korinsky" Subject: [PATCH v2 25/25] tests/functional: test Octeon III boot Date: Wed, 15 Jul 2026 15:44:11 +0200 Message-ID: <20260715134447.56007-26-kirill@korins.ky> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260715134447.56007-1-kirill@korins.ky> References: <20260715134447.56007-1-kirill@korins.ky> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a01:4f8:271:125e::2; envelope-from=kirill@korins.ky; helo=mx1.catap.net 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_PASS=-0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=ham 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 development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (found 2 invalid signatures) X-ZM-MESSAGEID: 1784123230852158500 Content-Type: text/plain; charset="utf-8" Boot the OpenBSD/octeon ramdisk through U-Boot using an e1000 device and QEMU user mode TFTP. Verify PCI enumeration, DHCP, image transfer and entry into the OpenBSD installer. --- tests/functional/mips64/meson.build | 2 + tests/functional/mips64/test_octeon3.py | 54 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/functional/mips64/test_octeon3.py diff --git a/tests/functional/mips64/meson.build b/tests/functional/mips64/= meson.build index 3ff2118987..98b7c491a1 100644 --- a/tests/functional/mips64/meson.build +++ b/tests/functional/mips64/meson.build @@ -2,9 +2,11 @@ =20 test_mips64_timeouts =3D { 'malta' : 240, + 'octeon3' : 300, } =20 tests_mips64_system_thorough =3D [ 'malta', + 'octeon3', 'tuxrun', ] diff --git a/tests/functional/mips64/test_octeon3.py b/tests/functional/mip= s64/test_octeon3.py new file mode 100644 index 0000000000..9c2bc67ac4 --- /dev/null +++ b/tests/functional/mips64/test_octeon3.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# +# Functional test for the Cavium Octeon III / EBB7304 machine. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os +import shutil + +from qemu_test import QemuSystemTest, Asset +from qemu_test import wait_for_console_pattern +from qemu_test import exec_command_and_wait_for_pattern as ec_and_wait + + +class Octeon3Machine(QemuSystemTest): + + ASSET_UBOOT =3D Asset( + 'https://kirill.korins.ky/pub/qemu-mips64-openbsd/u-boot.bin', + '7e519b2e52ba44b27bfafd16738c8f485e9eda5438b4899cf6a70520a6d34396') + + ASSET_BSD_RD =3D Asset( + 'https://kirill.korins.ky/pub/qemu-mips64-openbsd/bsd.rd', + '907f26f0ff67390dd21dc85e2c854fc0e65db295b15d47ae92e1927f98ac5872') + + def test_openbsd_ramdisk_tftp(self): + self.require_netdev('user') + self.require_device('e1000') + self.set_machine('octeon3') + + tftp_dir =3D self.scratch_file('tftp') + os.mkdir(tftp_dir) + shutil.copy(self.ASSET_BSD_RD.fetch(), + os.path.join(tftp_dir, 'bsd.rd')) + + self.vm.set_console() + self.vm.add_args('-bios', self.ASSET_UBOOT.fetch(), + '-m', '1G', + '-smp', '4', + '-no-reboot', + '-netdev', + f'user,id=3Dnet0,tftp=3D{tftp_dir},bootfile=3Dbsd= .rd', + '-device', 'e1000,netdev=3Dnet0') + self.vm.launch() + + wait_for_console_pattern(self, '=3D> ') + ec_and_wait(self, 'pci enum', '=3D> ') + ec_and_wait(self, 'dhcp', 'Bytes transferred') + wait_for_console_pattern(self, '=3D> ') + ec_and_wait(self, 'bootoctlinux ${loadaddr} numcores=3D4', + 'Welcome to the OpenBSD/octeon 7.9 installation progra= m.') + + +if __name__ =3D=3D '__main__': + QemuSystemTest.main() --=20 2.54.0