From nobody Mon Sep 21 15:09:04 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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; dmarc=pass(p=reject dis=none) header.from=oss.qualcomm.com ARC-Seal: i=1; a=rsa-sha256; t=1784044344; cv=none; d=zohomail.com; s=zohoarc; b=oIXdrsS1YLRGCIB+lP+mTYMgVS19Ow7Fm8kgYHc9V5kAlRlVw6ADKh2FbC1UVYRN3cLgjQcpamhCz/f01vG6Mu3xJVn/97TwdH5K/cPtfzYJjiQKRxW0xk4SEVgNg6V1guBUJ4SGvilU8qes8e0J5OuYPvaci1rTTlI/mVcq9QI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784044344; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=fyJkzO5j4TgyiaTMhEsNKoqg2aFZ6z7LN49qqrz0Mm8=; b=lMjtna2gWcJ+dXmg/Z3YSP0Ut3G3+B7aqzZrn4Ckjnqje5bpWE7rLeejclMuo9CNAtQUBzcpYhqSB2RfmEsmSfHhetuaS6FN+LTOUuZVsI1JopzCR9iJgDDzNnsfG6Ptru1myYlgA0MAixGeR0gmyjDShJz+ZH0CapciChEtJNo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784044344967962.7005984897381; Tue, 14 Jul 2026 08:52:24 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wjfQ6-0000zy-Ug; Tue, 14 Jul 2026 11:51:42 -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 1wjfQ5-0000z3-5p for qemu-devel@nongnu.org; Tue, 14 Jul 2026 11:51:41 -0400 Received: from mx0b-0031df01.pphosted.com ([205.220.180.131]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wjfQ1-00014U-IE for qemu-devel@nongnu.org; Tue, 14 Jul 2026 11:51:40 -0400 Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66EEcn8g677312 for ; Tue, 14 Jul 2026 15:51:36 GMT Received: from mail-pj1-f69.google.com (mail-pj1-f69.google.com [209.85.216.69]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4fdde0at1h-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 14 Jul 2026 15:51:36 +0000 (GMT) Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-38e2237bc43so711179a91.1 for ; Tue, 14 Jul 2026 08:51:36 -0700 (PDT) Received: from hu-bcain-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-13b987fc629sm41343581c88.0.2026.07.14.08.51.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Jul 2026 08:51:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= fyJkzO5j4TgyiaTMhEsNKoqg2aFZ6z7LN49qqrz0Mm8=; b=E6b4h5EQFxbHUSyZ 8qosS1hXoWzCUmTN886+unOGsr26TRFADX6AlR9pISL3J41NMwMa+FCIRondWsZc kTDWap6wLYIU9+o6ffFIyjiRWXfvQ3rKOelGIKgvQVDf6E8xN1ZP+khibpZKGowp ZhHpORSGkKsbv3gqdpXDYcJJT8YOyS9qkJ79RdQKbI9v5fMr15o8Ir12oCL7iVmz D5OftUHNTC44ZjHJY0v4SPfsn1BblkSkna4/3lZ+m8bhuKm7eqHaeHiflQ/ogHDX A7fKgB3cvn4FtMQK5Hd8pDiGGLqpAv+eSyknnu5gp4VGgp25teUuN60I3TwbKMcy gKaV+Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1784044295; x=1784649095; darn=nongnu.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=fyJkzO5j4TgyiaTMhEsNKoqg2aFZ6z7LN49qqrz0Mm8=; b=iqQf5OMMm+ViHeAx8UYRDHM4Nbi1zwa6GYMtUIuYW6nOugTExxHFzTzg/VMyAdkv80 eCF6pSt3dHtptlqn8JvDS2YAipOeLeS9ze+JioxkNK2wW3XNHbU6d7Oj1hHAyMSxbjFT xtGDY80ZlaobOkWzuRPjHsh+nK5oIHiMreV8/YwFYofcRBCjknCzhuLViX9BN7G5ekVV UN+LU6h4sPpjv8BjR3uvXDKj+HrvyJxRZ0wWSg4prspbhs4oxZvssq+4cCXejL42xTYk 0FHturFTUXsGu9W0PuYiJJPOEW0as5GibxRkcG/rt6NAWsQmMYOP5mhKFZTh9/qLVyeJ KP/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784044295; x=1784649095; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=fyJkzO5j4TgyiaTMhEsNKoqg2aFZ6z7LN49qqrz0Mm8=; b=o+/ajEtMavAFzu+k4EGECgiQ/rH06enFO5wMHLbztk2f9/8cpomxzy8hsazMdJk0xT igENU/uKnesYioIwLp+VZUDwnx25T5tXphbTM7z2r924RT3K9n1tZCxJ2HrEn/ScipVY RStAiLxL3SGFgFdw23qy07z8ODdlJW4tiEK2/jS+teHg3GvRo5jowx252VkoVSGlSjMB csl7fbZrq9+1QM3rW++oGo+tMk/n+nfLeEFBsJYnZrxqWGXMj8b3188+/mH7n233zZ1y 22R7XYWYlMObzLUhaNSLR2g2Nu8AF+sahhQqzG9RtzTXHhTMqo8/hV7CBnIdySBODhTA izdA== X-Gm-Message-State: AOJu0YwSeYKfMG+UEa1rnAMP1UcHmsGt61NVke5kMmztMBeLILm9O0U7 HbCRIyxNIxO8NBgz85tuKlHvTPwY+SdjeoEj/u5T9dMpJ03oyxoTfUzxaAQgmCQvNrrHcx3e5uY dV8NmFkcmh1xX61c46gdtIFkm4yQbU3y1rcp1XL9+DRHrCsntEpsJUUAIQo50cZV05w== X-Gm-Gg: AfdE7clIOQ8aD4z7Jm3/7DqwCUehq8drCMgYcXAokDzy+5NHLtaJtnfwVgOPnHiMmZ+ /7JSwLtjPoGg69qKPF9pPO6O7Za4M3htjE5EGIjn4Pn5We9oqSObHHWx158BNUjQK4FhYnxmrjq er6FXJbkacXa8OuoD2NMKo3g0O8tgirm0JkInJNDn+U8zvUvAlI1uD/48YSXduXTYYns8/uYgn5 60rRxKGLfSMfHiySF1UBrvVAtr2AoEj9N/Cm1eYuEGaObWy5UGDdGjawCUbJOV7kVBCxC8O1f7B P7gI9CSPXqLMA5k+pN9ktljRBI7ItdNHthxDk/NlJjL3/2BxTqJzL7tRXqNG6pR9g9/W7G6LMbb sl4f8IVoB/dtkkXdqIXH9yQcVvhaHHmOIIVs6S/k3AX5y/57lKx7usq8fgWg= X-Received: by 2002:a05:6a20:7484:b0:3c0:9c1a:8935 with SMTP id adf61e73a8af0-3c34d893c43mr5287375637.61.1784044294957; Tue, 14 Jul 2026 08:51:34 -0700 (PDT) X-Received: by 2002:a05:6a20:7484:b0:3c0:9c1a:8935 with SMTP id adf61e73a8af0-3c34d893c43mr5287319637.61.1784044294280; Tue, 14 Jul 2026 08:51:34 -0700 (PDT) From: Brian Cain To: qemu-devel@nongnu.org Cc: ltaylorsimpson@gmail.com, Laurent Vivier , Thomas Huth , Paolo Bonzini , matheus.bernardino@oss.qualcomm.com, Fabiano Rosas , Brian Cain , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , philmd@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Sid Manning , Matheus Tavares Bernardino , Damien Hedde Subject: [PATCH 4/7] hw/intc: Add l2vic interrupt controller Date: Tue, 14 Jul 2026 08:51:23 -0700 Message-Id: <20260714155126.3509544-5-brian.cain@oss.qualcomm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260714155126.3509544-1-brian.cain@oss.qualcomm.com> References: <20260714155126.3509544-1-brian.cain@oss.qualcomm.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Info: AW1haW4tMjYwNzE0MDE2NCBTYWx0ZWRfXybPPYsMwSRI9 8UsZiwfXxcXKrKlGhFdUBLr0h+H5DFhC5Gu5JXFu4PEjtUzKLy3nB0bNEhPunWTek4G/0zz9j0T ponorAib7PoV8abVJwViKi59GqtgDQY= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzE0MDE2NCBTYWx0ZWRfXwg3O1gjOS4+Y d24gkXhyWoHzXV2iLrzXDaPwvvmZE8CRu3NagQoGENY+wHgO9xcVNzWLSf3EJMUe7FMdSaZLDxn i+i+cMKBeLhXXYTUbyqkMHz/TRwAQ5/grGQUxjyQj93tqGv7WSe4b+VqFX2X4iHL9A1TdVfA94U 1kACcTLSOHWfCvACsSrgcu4MhxlxHJQdkWElsCAWTH0ZS/UqPfzyHqdgPih1eAjAcqKisqR+7yq vOTp9sKm6BbstF/ufGnC2w9oSA+1ZnYha77YEedmk+W8HqGn1tQ3Z9WM+aNAHJwIQ739RK4i/vR e74Bv/RN6JFy8mqFykTLXz5oomypVt0I1tz9MVaAOYGIcsEMHRte2Qr7aumq0pJpGm76okJ/VQF ERWsEIdG+WI9q+u7SrNah3XDGqFveVndccUmGasr4SUQPCLM3YNc6+u+b/SC06NC2vkwCQ7Bjit 5XpFC1z7fPQUPfaOZIQ== X-Proofpoint-ORIG-GUID: 0wNfHgfDjcLabYe7yQ_uzPcv060IVMFd X-Proofpoint-GUID: 0wNfHgfDjcLabYe7yQ_uzPcv060IVMFd X-Authority-Analysis: v=2.4 cv=F/FnsKhN c=1 sm=1 tr=0 ts=6a565b08 cx=c_pps a=vVfyC5vLCtgYJKYeQD43oA==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=RAioF0-LDSMA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yx91gb_oNiZeI1HMLzn7:22 a=NEAV23lmAAAA:8 a=COk6AnOGAAAA:8 a=EUspDBNiAAAA:8 a=bj4OHAFAiDXEHoaV4fEA:9 a=QEXdDO2ut3YA:10 a=rl5im9kqc5Lf4LNbBjHf:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-14_03,2026-07-14_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 priorityscore=1501 malwarescore=0 adultscore=0 clxscore=1015 suspectscore=0 spamscore=0 phishscore=0 bulkscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607140164 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=205.220.180.131; envelope-from=brian.cain@oss.qualcomm.com; helo=mx0b-0031df01.pphosted.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 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_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.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: pass (identity @qualcomm.com) X-ZM-MESSAGEID: 1784044345432158500 From: Sid Manning The Hexagon DSP requires an L2VIC to route up to 1024 external interrupt sources through 4 VID output groups into the core's 8 interrupt inputs. This device model implements the register interface, interrupt steering, and edge/level type handling needed by the sysemu machine models. Co-authored-by: Matheus Tavares Bernardino Co-authored-by: Damien Hedde Signed-off-by: Brian Cain --- MAINTAINERS | 3 + docs/devel/hexagon-l2vic.rst | 55 ++++ docs/devel/index-internals.rst | 1 + include/hw/intc/hex-l2vic.h | 87 ++++++ target/hexagon/cpu.h | 2 + hw/intc/hex-l2vic.c | 511 +++++++++++++++++++++++++++++++++ target/hexagon/cpu.c | 2 + target/hexagon/op_helper.c | 21 +- hw/hexagon/Kconfig | 1 + hw/intc/Kconfig | 3 + hw/intc/meson.build | 2 + hw/intc/trace-events | 4 + 12 files changed, 691 insertions(+), 1 deletion(-) create mode 100644 docs/devel/hexagon-l2vic.rst create mode 100644 include/hw/intc/hex-l2vic.h create mode 100644 hw/intc/hex-l2vic.c diff --git a/MAINTAINERS b/MAINTAINERS index e25df9493c5..1240d180b85 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -250,6 +250,8 @@ M: Brian Cain R: Pierrick Bouvier S: Supported F: target/hexagon/ +F: hw/intc/hex-l2vic.c +F: include/hw/intc/hex-l2vic.h X: target/hexagon/idef-parser/ X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ @@ -262,6 +264,7 @@ F: gdbstub/gdb-xml/hexagon*.xml F: docs/system/target-hexagon.rst F: docs/system/hexagon/ F: docs/devel/hexagon-sys.rst +F: docs/devel/hexagon-l2vic.rst T: git https://github.com/qualcomm/qemu.git hex-next =20 Hexagon idef-parser diff --git a/docs/devel/hexagon-l2vic.rst b/docs/devel/hexagon-l2vic.rst new file mode 100644 index 00000000000..9cb2a86871e --- /dev/null +++ b/docs/devel/hexagon-l2vic.rst @@ -0,0 +1,55 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Hexagon L2 Vectored Interrupt Controller +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +.. code-block:: none + + +-------------+ +----------------------+ + | l2vic | | hexagon core | + | | | | + IRQ in ---->| | | | + IRQ in ---->| VID0 -|----------------->| irq2 | + ... ---->| | | | | + IRQ in ---->| | | v | + | ... | | | + | | | / | | \ | + IRQ in ---->| | | t0 t1 t2 t3 ...| + IRQ in ---->| VIDN -| | | + ... ---->| | | | + IRQ in ---->| | | Global SREG File | + | | | | + | State | | | + | [ ] <--|=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D|=3D=3D> [ VID ] | + | [ ] <--|=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D|=3D=3D> [ VID1 ] | + | | | | + +-------------+ +----------------------+ + +L2VIC/Core Integration +---------------------- + +* hexagon core supports 8 external interrupt sources +* l2vic supports 1024 input interrupts mapped among 4 output interrupts +* l2vic has four output signals: { VID0, VID1, VID2, VID3 } +* l2vic device has a bank of registers per-VID that can be used to query + the status or assert new interrupts. +* Interrupts are 'steered' to threads based on { thread priority, 'EX' sta= te, + thread interrupt mask, thread interrupt enable, global interrupt enable, + etc. }. +* Any hardware thread could conceivably handle any input interrupt, depend= ent + on state. +* The system register transfer instruction can read the VID0-VID3 values f= rom + the l2vic when reading from hexagon core system registers "VID" and "VID= 1". +* When l2vic VID0 has multiple active interrupts, it pulses the VID0 output + IRQ and stores the IRQ number for the VID0 register field. Only after t= his + interrupt is cleared can the l2vic pulse the VID0 output IRQ again and p= rovide + the next interrupt number on the VID0 register. +* The ``ciad`` instruction clears the l2vic input interrupt and un-disable= s the + core interrupt. If some/an l2vic VID0 interrupt is pending when this oc= curs, + the next interrupt should fire and any subsequent reads of the VID regis= ter + should reflect the newly raised interrupt. +* In QEMU, on an external interrupt or an unmasked-pending interrupt, + all vCPUs are triggered (has_work=3D=3Dtrue) and each will grab the IO l= ock + while considering the steering logic to determine whether they're the th= read + that must handle the interrupt. diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst index b89bab9b306..84985973490 100644 --- a/docs/devel/index-internals.rst +++ b/docs/devel/index-internals.rst @@ -15,6 +15,7 @@ Details about QEMU's various subsystems including how to = add features to them. clocks ebpf_rss hexagon-sys + hexagon-l2vic migration/index multi-process reset diff --git a/include/hw/intc/hex-l2vic.h b/include/hw/intc/hex-l2vic.h new file mode 100644 index 00000000000..f6519bcd6c2 --- /dev/null +++ b/include/hw/intc/hex-l2vic.h @@ -0,0 +1,87 @@ +/* + * QEMU L2VIC Interrupt Controller + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_INTC_HEX_L2VIC_H +#define HW_INTC_HEX_L2VIC_H + +#include "qom/object.h" + +#define L2VIC_VID_GRP_0 0x0 /* Read */ +#define L2VIC_VID_GRP_1 0x4 /* Read */ +#define L2VIC_VID_GRP_2 0x8 /* Read */ +#define L2VIC_VID_GRP_3 0xC /* Read */ +#define L2VIC_INT_ENABLEn 0x100 /* Read/Write */ +#define L2VIC_INT_ENABLE_CLEARn 0x180 /* Write */ +#define L2VIC_INT_ENABLE_SETn 0x200 /* Write */ +#define L2VIC_INT_TYPEn 0x280 /* Read/Write */ +#define L2VIC_INT_STATUSn 0x380 /* Read */ +#define L2VIC_INT_CLEARn 0x400 /* Write */ +#define L2VIC_SOFT_INTn 0x480 /* Write */ +#define L2VIC_INT_PENDINGn 0x500 /* Read */ +#define L2VIC_INT_GRPn_0 0x600 /* Read/Write */ +#define L2VIC_INT_GRPn_1 0x680 /* Read/Write */ +#define L2VIC_INT_GRPn_2 0x700 /* Read/Write */ +#define L2VIC_INT_GRPn_3 0x780 /* Read/Write */ + +#define L2VIC_INTERRUPT_MAX 1024 +/* + * Note about l2vic groups: + * Each interrupt to L2VIC can be configured to associate with one of + * four groups. + * Group 0 interrupts go to IRQ2 via VID 0 (SSR: 0xC2, the default) + * Group 1 interrupts go to IRQ3 via VID 1 (SSR: 0xC3) + * Group 2 interrupts go to IRQ4 via VID 2 (SSR: 0xC4) + * Group 3 interrupts go to IRQ5 via VID 3 (SSR: 0xC5) + */ + +#define TYPE_HEX_L2VIC "hex-l2vic" +/* + * L2VIC Interface for CPU/GlobalReg interaction + */ +#define TYPE_HEX_L2VIC_INTERFACE "hex-l2vic-if" + +typedef struct HexL2VicInterface HexL2VicInterface; + +typedef struct HexL2VicInterfaceClass { + InterfaceClass parent_class; + + /* Read VID register for given group */ + uint32_t (*read_vid)(HexL2VicInterface *l2vic, uint32_t group); + + /* Update VID register value */ + void (*update_vid)(HexL2VicInterface *l2vic, uint32_t group, + uint32_t value); + + /* Clear interrupt using CIAD instruction */ + void (*clear_interrupt)(HexL2VicInterface *l2vic); +} HexL2VicInterfaceClass; + +DECLARE_OBJ_CHECKERS(HexL2VicInterface, HexL2VicInterfaceClass, + HEX_L2VIC_INTERFACE, TYPE_HEX_L2VIC_INTERFACE); + +/* Convenience functions for interface users */ +static inline uint32_t l2vic_read_vid(HexL2VicInterface *l2vic, + uint32_t group) +{ + HexL2VicInterfaceClass *k =3D HEX_L2VIC_INTERFACE_GET_CLASS(l2vic); + return k->read_vid(l2vic, group); +} + +static inline void l2vic_update_vid(HexL2VicInterface *l2vic, uint32_t gro= up, + uint32_t value) +{ + HexL2VicInterfaceClass *k =3D HEX_L2VIC_INTERFACE_GET_CLASS(l2vic); + k->update_vid(l2vic, group, value); +} + +static inline void l2vic_clear_interrupt(HexL2VicInterface *l2vic) +{ + HexL2VicInterfaceClass *k =3D HEX_L2VIC_INTERFACE_GET_CLASS(l2vic); + k->clear_interrupt(l2vic); +} + +#endif /* HW_INTC_HEX_L2VIC_H */ diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 7694fd91fa8..f6c3c639325 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -39,6 +39,7 @@ typedef struct HexagonGlobalRegState HexagonGlobalRegStat= e; #include "qemu/bitmap.h" =20 #include "target/hexagon/reg_fields.h" +#include "hw/intc/hex-l2vic.h" =20 #define NUM_PREGS 4 #define TOTAL_PER_THREAD_REGS 64 @@ -198,6 +199,7 @@ struct ArchCPU { uint32_t boot_addr; HexagonGlobalRegState *globalregs; uint32_t htid; + HexL2VicInterface *l2vic; #endif }; =20 diff --git a/hw/intc/hex-l2vic.c b/hw/intc/hex-l2vic.c new file mode 100644 index 00000000000..a284ae8a567 --- /dev/null +++ b/hw/intc/hex-l2vic.c @@ -0,0 +1,511 @@ +/* + * QEMU L2VIC Interrupt Controller + * + * Arm PrimeCell PL190 Vector Interrupt Controller was used as a reference. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/core/irq.h" +#include "hw/core/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/lockable.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/bitmap.h" +#include "qemu/bitops.h" +#include "hw/intc/hex-l2vic.h" +#include "trace.h" + +static void bitmap32_write_word(uint32_t *bitmap, int word_offset, uint32_= t val) +{ + bitmap[word_offset] =3D val; +} + +static void bitmap32_clear_word(uint32_t *bitmap, int word_offset, + uint32_t mask) +{ + bitmap[word_offset] &=3D ~mask; +} + +static void bitmap32_set_word(uint32_t *bitmap, int word_offset, uint32_t = mask) +{ + bitmap[word_offset] |=3D mask; +} + +static uint32_t bitmap32_read_word(uint32_t *bitmap, int word_offset) +{ + return bitmap[word_offset]; +} + +OBJECT_DECLARE_SIMPLE_TYPE(HexL2VICState, HEX_L2VIC) + +#define SLICE_MAX (L2VIC_INTERRUPT_MAX / 32) + +typedef struct HexL2VICState { + SysBusDevice parent_obj; + + QemuMutex active; + MemoryRegion iomem; + MemoryRegion fast_iomem; + /* + * offset 0:vid group 0 etc, 10 bits in each group + * are used: + */ + uint32_t vid_group[4]; + uint32_t vid0; + /* Enable interrupt source */ + DECLARE_BITMAP32(int_enable, L2VIC_INTERRUPT_MAX) QEMU_ALIGNED(16); + /* Present for debugging, not used */ + DECLARE_BITMAP32(int_pending, L2VIC_INTERRUPT_MAX) QEMU_ALIGNED(16); + /* Which enabled interrupt is active */ + DECLARE_BITMAP32(int_status, L2VIC_INTERRUPT_MAX) QEMU_ALIGNED(16); + /* Edge or Level interrupt */ + DECLARE_BITMAP32(int_type, L2VIC_INTERRUPT_MAX) QEMU_ALIGNED(16); + /* L2 interrupt group 0-3 0x600-0x7FF */ + DECLARE_BITMAP32(int_group_n0, L2VIC_INTERRUPT_MAX) QEMU_ALIGNED(16); + DECLARE_BITMAP32(int_group_n1, L2VIC_INTERRUPT_MAX) QEMU_ALIGNED(16); + DECLARE_BITMAP32(int_group_n2, L2VIC_INTERRUPT_MAX) QEMU_ALIGNED(16); + DECLARE_BITMAP32(int_group_n3, L2VIC_INTERRUPT_MAX) QEMU_ALIGNED(16); + qemu_irq irq[8]; +} HexL2VICState; + +/* + * Find out if this irq is associated with a group other than + * the default group + */ +static uint32_t *get_int_group(HexL2VICState *s, int irq) +{ + int n =3D irq & 0x1f; + if (n < 8) { + return s->int_group_n0; + } + if (n < 16) { + return s->int_group_n1; + } + if (n < 24) { + return s->int_group_n2; + } + return s->int_group_n3; +} + +static int find_slice(int irq) +{ + return irq / 32; +} + +static int get_vid(HexL2VICState *s, int irq) +{ + uint32_t *group =3D get_int_group(s, irq); + uint32_t slice =3D group[find_slice(irq)]; + /* Mask with 0x7 to remove the GRP:EN bit */ + uint32_t val =3D slice >> ((irq & 0x7) * 4); + if (val & 0x8) { + return val & 0x7; + } else { + return 0; + } +} + +static inline bool vid_active(HexL2VICState *s) +{ + /* scan all 1024 bits in int_status array */ + const uint32_t size =3D L2VIC_INTERRUPT_MAX; + const uint32_t active_irq =3D find_first_bit32(s->int_status, size); + return active_irq !=3D size; +} + +static bool l2vic_update(HexL2VICState *s, int irq) +{ + bool pending; + bool enable; + + if (vid_active(s)) { + return true; + } + + pending =3D test_bit32(irq, s->int_pending); + enable =3D test_bit32(irq, s->int_enable); + if (pending && enable) { + int vid =3D get_vid(s, irq); + set_bit32(irq, s->int_status); + clear_bit32(irq, s->int_pending); + /* + * Only auto-disable for edge-triggered interrupts (type=3D1). + * Level-triggered interrupts (type=3D0, the default) keep their + * enable bit set across deliveries -- the firmware enables once + * and expects the interrupt to remain enabled. + */ + if (test_bit32(irq, s->int_type)) { + clear_bit32(irq, s->int_enable); + } + s->vid0 =3D irq; + s->vid_group[vid] =3D irq; + + qemu_irq_pulse(s->irq[vid + 2]); + trace_hex_l2vic_delivered(irq, vid); + return true; + } + return false; +} + +static void l2vic_update_all(HexL2VICState *s) +{ + for (int i =3D 0; i < L2VIC_INTERRUPT_MAX; i++) { + if (l2vic_update(s, i)) { + /* once vid is active, no-one else can set it until ciad */ + return; + } + } +} + +static void l2vic_set_irq(void *opaque, int irq, int level) +{ + HexL2VICState *s =3D (HexL2VICState *)opaque; + + QEMU_LOCK_GUARD(&s->active); + if (level) { + set_bit32(irq, s->int_pending); + } + l2vic_update(s, irq); +} + +static void l2vic_write(void *opaque, hwaddr offset, uint64_t val, + unsigned size) +{ + HexL2VICState *s =3D (HexL2VICState *)opaque; + + QEMU_LOCK_GUARD(&s->active); + trace_hex_l2vic_reg_write((unsigned)offset, (uint32_t)val); + + if (offset >=3D L2VIC_INT_ENABLEn && + offset < (L2VIC_INT_ENABLE_CLEARn)) { + bitmap32_write_word(s->int_enable, + (offset - L2VIC_INT_ENABLEn) >> 2, val); + } else if (offset >=3D L2VIC_INT_ENABLE_CLEARn && + offset < L2VIC_INT_ENABLE_SETn) { + bitmap32_clear_word(s->int_enable, + (offset - L2VIC_INT_ENABLE_CLEARn) >> 2, val); + } else if (offset >=3D L2VIC_INT_ENABLE_SETn && offset < L2VIC_INT_TYP= En) { + bitmap32_set_word(s->int_enable, + (offset - L2VIC_INT_ENABLE_SETn) >> 2, val); + } else if (offset >=3D L2VIC_INT_TYPEn && offset < L2VIC_INT_TYPEn + 0= x80) { + bitmap32_write_word(s->int_type, + (offset - L2VIC_INT_TYPEn) >> 2, val); + } else if (offset >=3D L2VIC_INT_STATUSn && offset < L2VIC_INT_CLEARn)= { + bitmap32_write_word(s->int_status, + (offset - L2VIC_INT_STATUSn) >> 2, val); + } else if (offset >=3D L2VIC_INT_CLEARn && offset < L2VIC_SOFT_INTn) { + bitmap32_clear_word(s->int_status, + (offset - L2VIC_INT_CLEARn) >> 2, val); + } else if (offset >=3D L2VIC_INT_PENDINGn && + offset < L2VIC_INT_PENDINGn + 0x80) { + bitmap32_write_word(s->int_pending, + (offset - L2VIC_INT_PENDINGn) >> 2, val); + } else if (offset >=3D L2VIC_SOFT_INTn && offset < L2VIC_INT_PENDINGn)= { + int irq; + hwaddr byteoffset =3D offset - L2VIC_SOFT_INTn; + + bitmap32_set_word(s->int_enable, (offset - L2VIC_SOFT_INTn) >> 2, = val); + if (val) { + irq =3D ctz32((uint32_t)val); + irq +=3D byteoffset * 8; + + if (test_bit32(irq, s->int_type)) { + set_bit32(irq, s->int_pending); + } + } + } else if (offset >=3D L2VIC_INT_GRPn_0 && offset < L2VIC_INT_GRPn_1) { + bitmap32_write_word(s->int_group_n0, + (offset - L2VIC_INT_GRPn_0) >> 2, val); + } else if (offset >=3D L2VIC_INT_GRPn_1 && offset < L2VIC_INT_GRPn_2) { + bitmap32_write_word(s->int_group_n1, + (offset - L2VIC_INT_GRPn_1) >> 2, val); + } else if (offset >=3D L2VIC_INT_GRPn_2 && offset < L2VIC_INT_GRPn_3) { + bitmap32_write_word(s->int_group_n2, + (offset - L2VIC_INT_GRPn_2) >> 2, val); + } else if (offset >=3D L2VIC_INT_GRPn_3 && offset < L2VIC_INT_GRPn_3 += 0x80) { + bitmap32_write_word(s->int_group_n3, + (offset - L2VIC_INT_GRPn_3) >> 2, val); + } else { + qemu_log_mask(LOG_UNIMP, + "%s: offset 0x%" HWADDR_PRIx " unimplemented\n", + __func__, offset); + } + + l2vic_update_all(s); +} + +static uint64_t l2vic_read(void *opaque, hwaddr offset, unsigned size) +{ + uint64_t value; + HexL2VICState *s =3D (HexL2VICState *)opaque; + + QEMU_LOCK_GUARD(&s->active); + + if (offset =3D=3D L2VIC_VID_GRP_0) { + value =3D s->vid_group[0]; + } else if (offset =3D=3D L2VIC_VID_GRP_1) { + value =3D s->vid_group[1]; + } else if (offset =3D=3D L2VIC_VID_GRP_2) { + value =3D s->vid_group[2]; + } else if (offset =3D=3D L2VIC_VID_GRP_3) { + value =3D s->vid_group[3]; + } else if (offset >=3D L2VIC_INT_ENABLEn && + offset < L2VIC_INT_ENABLE_CLEARn) { + value =3D bitmap32_read_word(s->int_enable, + (offset - L2VIC_INT_ENABLEn) >> 2); + } else if (offset >=3D L2VIC_INT_ENABLE_CLEARn && + offset < L2VIC_INT_ENABLE_SETn) { + value =3D 0; + } else if (offset >=3D L2VIC_INT_ENABLE_SETn && offset < L2VIC_INT_TYP= En) { + value =3D 0; + } else if (offset >=3D L2VIC_INT_TYPEn && offset < L2VIC_INT_TYPEn + 0= x80) { + value =3D bitmap32_read_word(s->int_type, + (offset - L2VIC_INT_TYPEn) >> 2); + } else if (offset >=3D L2VIC_INT_STATUSn && offset < L2VIC_INT_CLEARn)= { + value =3D bitmap32_read_word(s->int_status, + (offset - L2VIC_INT_STATUSn) >> 2); + } else if (offset >=3D L2VIC_INT_CLEARn && offset < L2VIC_SOFT_INTn) { + /* INT_CLEARn is write-only, return 0 on read */ + value =3D 0; + } else if (offset >=3D L2VIC_SOFT_INTn && offset < L2VIC_INT_PENDINGn)= { + value =3D 0; + } else if (offset >=3D L2VIC_INT_PENDINGn && + offset < L2VIC_INT_PENDINGn + 0x80) { + value =3D bitmap32_read_word(s->int_pending, + (offset - L2VIC_INT_PENDINGn) >> 2); + } else if (offset >=3D L2VIC_INT_GRPn_0 && offset < L2VIC_INT_GRPn_1) { + value =3D bitmap32_read_word(s->int_group_n0, + (offset - L2VIC_INT_GRPn_0) >> 2); + } else if (offset >=3D L2VIC_INT_GRPn_1 && offset < L2VIC_INT_GRPn_2) { + value =3D bitmap32_read_word(s->int_group_n1, + (offset - L2VIC_INT_GRPn_1) >> 2); + } else if (offset >=3D L2VIC_INT_GRPn_2 && offset < L2VIC_INT_GRPn_3) { + value =3D bitmap32_read_word(s->int_group_n2, + (offset - L2VIC_INT_GRPn_2) >> 2); + } else if (offset >=3D L2VIC_INT_GRPn_3 && offset < L2VIC_INT_GRPn_3 += 0x80) { + value =3D bitmap32_read_word(s->int_group_n3, + (offset - L2VIC_INT_GRPn_3) >> 2); + } else { + value =3D 0; + qemu_log_mask(LOG_GUEST_ERROR, + "L2VIC: %s: offset 0x%" HWADDR_PRIx "\n", __func__, + offset); + } + + trace_hex_l2vic_reg_read((unsigned)offset, (uint32_t)value); + return value; +} + +static const MemoryRegionOps l2vic_ops =3D { + .read =3D l2vic_read, + .write =3D l2vic_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid.min_access_size =3D 4, + .valid.max_access_size =3D 4, + .valid.unaligned =3D false, +}; + +#define FASTL2VIC_ENABLE 0x0 +#define FASTL2VIC_DISABLE 0x1 +#define FASTL2VIC_INT 0x2 + +static void fastl2vic_write(void *opaque, hwaddr offset, uint64_t val, + unsigned size) +{ + if (offset =3D=3D 0) { + uint32_t cmd =3D (val >> 16) & 0x3; + uint32_t irq =3D val & 0x3ff; + uint32_t slice =3D (irq / 32) * 4; + val =3D 1 << (irq % 32); + + if (cmd =3D=3D FASTL2VIC_ENABLE) { + l2vic_write(opaque, L2VIC_INT_ENABLE_SETn + slice, val, size); + } else if (cmd =3D=3D FASTL2VIC_DISABLE) { + l2vic_write(opaque, L2VIC_INT_ENABLE_CLEARn + slice, val, size= ); + } else if (cmd =3D=3D FASTL2VIC_INT) { + l2vic_write(opaque, L2VIC_SOFT_INTn + slice, val, size); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid write cmd %" PRId32 "\n", + __func__, cmd); + } + return; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid write offset 0x%08" HWADDR= _PRIx + "\n", __func__, offset); +} + +static const MemoryRegionOps fastl2vic_ops =3D { + .write =3D fastl2vic_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid.min_access_size =3D 4, + .valid.max_access_size =3D 4, + .valid.unaligned =3D false, +}; + +/* L2VIC Interface Implementation */ +static uint32_t l2vic_interface_read_vid_impl(HexL2VicInterface *iface, + uint32_t group) +{ + HexL2VICState *s =3D HEX_L2VIC(iface); + uint32_t result =3D 0; + + QEMU_LOCK_GUARD(&s->active); + if (group =3D=3D 0) { + /* VID register: VID1 (bits 16-31), VID0 (bits 0-15) */ + result =3D deposit32(result, 0, 16, s->vid_group[0]); + result =3D deposit32(result, 16, 16, s->vid_group[1]); + } else if (group =3D=3D 1) { + /* VID1 register: VID3 (bits 16-31), VID2 (bits 0-15) */ + result =3D deposit32(result, 0, 16, s->vid_group[2]); + result =3D deposit32(result, 16, 16, s->vid_group[3]); + } + return result; +} + +static void l2vic_interface_update_vid_impl(HexL2VicInterface *iface, + uint32_t group, uint32_t value) +{ + HexL2VICState *s =3D HEX_L2VIC(iface); + + QEMU_LOCK_GUARD(&s->active); + + if (group =3D=3D 0) { + /* VID register: unpack VID0 and VID1 */ + s->vid_group[0] =3D extract32(value, 0, 16); + s->vid_group[1] =3D extract32(value, 16, 16); + } else if (group =3D=3D 1) { + /* VID1 register: unpack VID2 and VID3 */ + s->vid_group[2] =3D extract32(value, 0, 16); + s->vid_group[3] =3D extract32(value, 16, 16); + } + + l2vic_update_all(s); +} + +static void l2vic_interface_clear_interrupt_impl(HexL2VicInterface *iface) +{ + HexL2VICState *s =3D HEX_L2VIC(iface); + + QEMU_LOCK_GUARD(&s->active); + if (s->vid0 < L2VIC_INTERRUPT_MAX) { + clear_bit32(s->vid0, s->int_status); + } + l2vic_update_all(s); +} + +static void l2vic_reset_hold(Object *obj, ResetType type G_GNUC_UNUSED) +{ + HexL2VICState *s =3D HEX_L2VIC(obj); + + QEMU_LOCK_GUARD(&s->active); + memset(s->int_enable, 0, sizeof(s->int_enable)); + memset(s->int_pending, 0, sizeof(s->int_pending)); + memset(s->int_status, 0, sizeof(s->int_status)); + memset(s->int_type, 0, sizeof(s->int_type)); + memset(s->int_group_n0, 0, sizeof(s->int_group_n0)); + memset(s->int_group_n1, 0, sizeof(s->int_group_n1)); + memset(s->int_group_n2, 0, sizeof(s->int_group_n2)); + memset(s->int_group_n3, 0, sizeof(s->int_group_n3)); + memset(s->vid_group, 0, sizeof(s->vid_group)); + s->vid0 =3D 0; + + l2vic_update_all(s); +} + +static void reset_irq_handler(void *opaque, int irq, int level) +{ + Object *obj =3D OBJECT(opaque); + + if (level) { + l2vic_reset_hold(obj, RESET_TYPE_COLD); + } +} + +static void l2vic_init(Object *obj) +{ + DeviceState *dev =3D DEVICE(obj); + HexL2VICState *s =3D HEX_L2VIC(obj); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + int i; + + memory_region_init_io(&s->iomem, obj, &l2vic_ops, s, "l2vic", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + memory_region_init_io(&s->fast_iomem, obj, &fastl2vic_ops, s, "fast", + 0x10000); + sysbus_init_mmio(sbd, &s->fast_iomem); + + qdev_init_gpio_in(dev, l2vic_set_irq, L2VIC_INTERRUPT_MAX); + qdev_init_gpio_in_named(dev, reset_irq_handler, "reset", 1); + for (i =3D 0; i < 8; i++) { + sysbus_init_irq(sbd, &s->irq[i]); + } + qemu_mutex_init(&s->active); +} + +static const VMStateDescription vmstate_l2vic =3D { + .name =3D "l2vic", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D + (VMStateField[]){ + VMSTATE_UINT32_ARRAY(vid_group, HexL2VICState, 4), + VMSTATE_UINT32(vid0, HexL2VICState), + VMSTATE_UINT32_ARRAY(int_enable, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_type, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_status, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_pending, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_group_n0, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_group_n1, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_group_n2, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_group_n3, HexL2VICState, SLICE_MAX), + VMSTATE_END_OF_LIST() } +}; + +static void l2vic_interface_class_init(ObjectClass *klass, const void *dat= a) +{ + HexL2VicInterfaceClass *k =3D HEX_L2VIC_INTERFACE_CLASS(klass); + + k->read_vid =3D l2vic_interface_read_vid_impl; + k->update_vid =3D l2vic_interface_update_vid_impl; + k->clear_interrupt =3D l2vic_interface_clear_interrupt_impl; +} + +static void l2vic_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + dc->vmsd =3D &vmstate_l2vic; + rc->phases.hold =3D l2vic_reset_hold; +} + +static const TypeInfo l2vic_interface_info =3D { + .name =3D TYPE_HEX_L2VIC_INTERFACE, + .parent =3D TYPE_INTERFACE, + .class_size =3D sizeof(HexL2VicInterfaceClass), + .class_init =3D l2vic_interface_class_init, +}; + +static const TypeInfo l2vic_info =3D { + .name =3D TYPE_HEX_L2VIC, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(HexL2VICState), + .instance_init =3D l2vic_init, + .class_init =3D l2vic_class_init, + .interfaces =3D (InterfaceInfo[]) { + { TYPE_HEX_L2VIC_INTERFACE }, + { } + }, +}; + +static void l2vic_register_types(void) +{ + type_register_static(&l2vic_interface_info); + type_register_static(&l2vic_info); +} + +type_init(l2vic_register_types) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 42d93e5da47..be56ac0419f 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -65,6 +65,8 @@ static const Property hexagon_cpu_properties[] =3D { DEFINE_PROP_LINK("tlb", HexagonCPU, tlb, TYPE_HEXAGON_TLB, HexagonTLBState *), DEFINE_PROP_UINT32("exec-start-addr", HexagonCPU, boot_addr, 0xfffffff= f), + DEFINE_PROP_LINK("l2vic", HexagonCPU, l2vic, + TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *), DEFINE_PROP_LINK("global-regs", HexagonCPU, globalregs, TYPE_HEXAGON_GLOBALREG, HexagonGlobalRegState *), DEFINE_PROP_UINT32("htid", HexagonCPU, htid, 0), diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 125952aee59..0d88ae65e75 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -40,6 +40,7 @@ #include "hw/hexagon/hexagon_globalreg.h" #include "hex_mmu.h" #include "hw/hexagon/hexagon_tlb.h" +#include "hw/intc/hex-l2vic.h" #include "hex_interrupts.h" #include "hexswi.h" #endif @@ -1557,7 +1558,25 @@ void HELPER(raise_stack_overflow)(CPUHexagonState *e= nv, uint32_t slot, =20 void HELPER(ciad)(CPUHexagonState *env, uint32_t mask) { - g_assert_not_reached(); + uint32_t ipendad; + uint32_t iad; + HexagonCPU *cpu; + + BQL_LOCK_GUARD(); + cpu =3D env_archcpu(env); + ipendad =3D cpu->globalregs ? + hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD, + env->threadId) : 0; + iad =3D fGET_FIELD(ipendad, IPENDAD_IAD); + fSET_FIELD(ipendad, IPENDAD_IAD, iad & ~(mask)); + if (cpu->globalregs) { + hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IPENDAD, + ipendad, env->threadId); + } + if (cpu->l2vic) { + l2vic_clear_interrupt(cpu->l2vic); + } + hex_interrupt_update(env); } =20 void HELPER(siad)(CPUHexagonState *env, uint32_t mask) diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig index 52065ab3b22..191c6c5d65c 100644 --- a/hw/hexagon/Kconfig +++ b/hw/hexagon/Kconfig @@ -2,6 +2,7 @@ config HEX_DSP bool default y depends on HEXAGON + select HEX_L2VIC =20 config HEX_VIRT bool diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 636d00b7e88..097de4efc5d 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -8,6 +8,9 @@ config I8259 config PL190 bool =20 +config HEX_L2VIC + bool + config IOAPIC bool select I8259 diff --git a/hw/intc/meson.build b/hw/intc/meson.build index fac2d228f9b..9077a3f3297 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -74,6 +74,8 @@ specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('x= ics_spapr.c', 'spapr_xi specific_ss.add(when: 'CONFIG_XIVE', if_true: files('xive.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'], if_true: files('spapr_xive_kvm.c')) + +specific_ss.add(when: 'CONFIG_HEX_L2VIC', if_true: files('hex-l2vic.c')) specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) specific_ss.add(when: 'CONFIG_LOONGSON_IPI_COMMON', if_true: files('loongs= on_ipi_common.c')) specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_ipi.= c')) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index e7d6c304487..7512c6e6004 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -337,6 +337,10 @@ sh_intc_register(const char *s, int id, unsigned short= v, int c, int m) "%s %u - sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0= x%" PRIx64 " -> 0x%lx" sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u = 0x%" PRIx64 " <- 0x%lx" sh_intc_set(int id, int enable) "setting interrupt group %d to %d" +# hex-l2vic.c +hex_l2vic_reg_write(unsigned int addr, uint32_t value) "addr: 0x%03x value= : 0x%08"PRIx32 +hex_l2vic_reg_read(unsigned int addr, uint32_t value) "addr: 0x%03x value:= 0x%08"PRIx32 +hex_l2vic_delivered(int irq, int vid) "l2vic: delivered %d (vid %d)" =20 # loongson_ipi.c loongson_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u ad= dr: 0x%"PRIx64 "val: 0x%"PRIx64 --=20 2.34.1