All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v3 00/27] Add LoongArch softmmu support.
@ 2021-12-04 12:06 Xiaojuan Yang
  2021-12-04 12:06 ` [RFC PATCH v3 01/27] target/loongarch: Update README Xiaojuan Yang
                   ` (27 more replies)
  0 siblings, 28 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This series patch add softmmu support for LoongArch.
Base on the linux-user emulation support V13 patch.
  * https://patchew.org/QEMU/1638610165-15036-1-git-send-email-gaosong@loongson.cn/
The latest kernel:
  * https://github.com/loongson/linux/tree/loongarch-next
The manual:
  * https://github.com/loongson/LoongArch-Documentation/releases/tag/2021.10.11

Changes for v3:
1.Target code mainly follow Richard's code review comments.
2.Put the csr and iocsr read/write instruction emulate into 2 different patch.
3.Simply the tlb emulation.
4.Delete some unused csr registers defintion.
5.Machine and board code mainly follow Mark's advice, discard the obsolete interface.
6.NUMA function is removed for it is not completed.
7.Adjust some format problem and the Naming problem 

Changes for v2:
1.Combine patch 2 and 3 into one.
2.Adjust the order of the patch.
3.Put all the binaries on the github.
4.Modify some emulate errors when use the kernel from the github.
5.Adjust some format problem and the Naming problem 
6.Others mainly follow Richard's code review comments.

Please help review!

Thanks

Xiaojuan Yang (27):
  target/loongarch: Update README
  target/loongarch: Add CSR registers definition
  target/loongarch: Add basic vmstate description of CPU.
  target/loongarch: Implement qmp_query_cpu_definitions()
  target/loongarch: Add stabletimer support
  target/loongarch: Add MMU support for LoongArch CPU.
  target/loongarch: Add LoongArch CSR instruction
  target/loongarch: Add LoongArch IOCSR instruction
  target/loongarch: Add TLB instruction support
  target/loongarch: Add other core instructions support
  target/loongarch: Add LoongArch interrupt and exception handle
  target/loongarch: Add timer related instructions support.
  target/loongarch: Add gdb support.
  hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson3
    Platform
  hw/loongarch: Add support loongson3-ls7a machine type.
  hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC)
  hw/loongarch: Add LoongArch ipi interrupt support(IPI)
  hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
  hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI)
  hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
  hw/loongarch: Add irq hierarchy for the system
  hw/loongarch: Add some devices support for 3A5000.
  hw/loongarch: Add LoongArch ls7a rtc device support
  hw/loongarch: Add default bios startup support.
  hw/loongarch: Add -kernel and -initrd options support
  hw/loongarch: Add LoongArch smbios support
  hw/loongarch: Add LoongArch acpi support

 .../devices/loongarch64-softmmu/default.mak   |   3 +
 configs/targets/loongarch64-softmmu.mak       |   4 +
 gdb-xml/loongarch-base64.xml                  |  43 +
 gdb-xml/loongarch-fpu64.xml                   |  57 ++
 hw/Kconfig                                    |   1 +
 hw/acpi/Kconfig                               |   4 +
 hw/acpi/ls7a.c                                | 349 ++++++++
 hw/acpi/meson.build                           |   1 +
 hw/intc/Kconfig                               |  15 +
 hw/intc/loongarch_extioi.c                    | 499 +++++++++++
 hw/intc/loongarch_ipi.c                       | 162 ++++
 hw/intc/loongarch_pch_msi.c                   |  67 ++
 hw/intc/loongarch_pch_pic.c                   | 357 ++++++++
 hw/intc/meson.build                           |   4 +
 hw/intc/trace-events                          |  21 +
 hw/loongarch/Kconfig                          |  23 +
 hw/loongarch/acpi-build.c                     | 637 ++++++++++++++
 hw/loongarch/fw_cfg.c                         |  33 +
 hw/loongarch/fw_cfg.h                         |  15 +
 hw/loongarch/loongson3.c                      | 509 +++++++++++
 hw/loongarch/meson.build                      |   6 +
 hw/meson.build                                |   1 +
 hw/pci-host/Kconfig                           |   4 +
 hw/pci-host/ls7a.c                            | 214 +++++
 hw/pci-host/meson.build                       |   1 +
 hw/rtc/Kconfig                                |   3 +
 hw/rtc/ls7a_rtc.c                             | 323 +++++++
 hw/rtc/meson.build                            |   1 +
 include/exec/poison.h                         |   2 +
 include/hw/acpi/ls7a.h                        |  53 ++
 include/hw/intc/loongarch_extioi.h            |  69 ++
 include/hw/intc/loongarch_ipi.h               |  47 ++
 include/hw/intc/loongarch_pch_msi.h           |  21 +
 include/hw/intc/loongarch_pch_pic.h           |  61 ++
 include/hw/loongarch/loongarch.h              |  68 ++
 include/hw/pci-host/ls7a.h                    |  79 ++
 include/sysemu/arch_init.h                    |   1 +
 linux-user/loongarch64/cpu_loop.c             |   8 +-
 qapi/machine-target.json                      |   6 +-
 qapi/machine.json                             |   2 +-
 softmmu/qdev-monitor.c                        |   3 +-
 target/Kconfig                                |   1 +
 target/loongarch/Kconfig                      |   2 +
 target/loongarch/README                       |  20 +
 target/loongarch/cpu-csr.h                    | 236 ++++++
 target/loongarch/cpu-param.h                  |   2 +-
 target/loongarch/cpu.c                        | 402 ++++++++-
 target/loongarch/cpu.h                        | 216 ++++-
 target/loongarch/csr_helper.c                 | 112 +++
 target/loongarch/disas.c                      |  57 ++
 target/loongarch/fpu_helper.c                 |   2 +-
 target/loongarch/gdbstub.c                    |  97 +++
 target/loongarch/helper.h                     |  26 +
 target/loongarch/insn_trans/trans_core.c.inc  | 409 +++++++++
 target/loongarch/insn_trans/trans_extra.c.inc |  36 +-
 target/loongarch/insns.decode                 |  44 +
 target/loongarch/internals.h                  |  29 +
 target/loongarch/iocsr_helper.c               | 109 +++
 target/loongarch/machine.c                    | 104 +++
 target/loongarch/meson.build                  |  11 +
 target/loongarch/op_helper.c                  |  56 ++
 target/loongarch/stabletimer.c                |  63 ++
 target/loongarch/tlb_helper.c                 | 789 ++++++++++++++++++
 target/loongarch/translate.c                  |   9 +-
 64 files changed, 6579 insertions(+), 30 deletions(-)
 create mode 100644 configs/devices/loongarch64-softmmu/default.mak
 create mode 100644 configs/targets/loongarch64-softmmu.mak
 create mode 100644 gdb-xml/loongarch-base64.xml
 create mode 100644 gdb-xml/loongarch-fpu64.xml
 create mode 100644 hw/acpi/ls7a.c
 create mode 100644 hw/intc/loongarch_extioi.c
 create mode 100644 hw/intc/loongarch_ipi.c
 create mode 100644 hw/intc/loongarch_pch_msi.c
 create mode 100644 hw/intc/loongarch_pch_pic.c
 create mode 100644 hw/loongarch/Kconfig
 create mode 100644 hw/loongarch/acpi-build.c
 create mode 100644 hw/loongarch/fw_cfg.c
 create mode 100644 hw/loongarch/fw_cfg.h
 create mode 100644 hw/loongarch/loongson3.c
 create mode 100644 hw/loongarch/meson.build
 create mode 100644 hw/pci-host/ls7a.c
 create mode 100644 hw/rtc/ls7a_rtc.c
 create mode 100644 include/hw/acpi/ls7a.h
 create mode 100644 include/hw/intc/loongarch_extioi.h
 create mode 100644 include/hw/intc/loongarch_ipi.h
 create mode 100644 include/hw/intc/loongarch_pch_msi.h
 create mode 100644 include/hw/intc/loongarch_pch_pic.h
 create mode 100644 include/hw/loongarch/loongarch.h
 create mode 100644 include/hw/pci-host/ls7a.h
 create mode 100644 target/loongarch/Kconfig
 create mode 100644 target/loongarch/cpu-csr.h
 create mode 100644 target/loongarch/csr_helper.c
 create mode 100644 target/loongarch/gdbstub.c
 create mode 100644 target/loongarch/insn_trans/trans_core.c.inc
 create mode 100644 target/loongarch/iocsr_helper.c
 create mode 100644 target/loongarch/machine.c
 create mode 100644 target/loongarch/stabletimer.c
 create mode 100644 target/loongarch/tlb_helper.c

-- 
2.27.0



^ permalink raw reply	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 01/27] target/loongarch: Update README
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
@ 2021-12-04 12:06 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 02/27] target/loongarch: Add CSR registers definition Xiaojuan Yang
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

Mainly introduce how to run the softmmu

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/README | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/target/loongarch/README b/target/loongarch/README
index 09f809cf80..49c1f1575a 100644
--- a/target/loongarch/README
+++ b/target/loongarch/README
@@ -71,6 +71,26 @@
       ./qemu-loongarch64  /opt/clfs/usr/bin/pwd
       ...
 
+- Softmmu emulation
+
+  Add support softmmu emulation support in the following series patches.
+  Mainly emulate a virt 3A5000 board that is not exactly the same as the host.
+  Kernel code is on the github and the uefi code will be opened in the near future.
+  All required binaries can get from github for test.
+
+  1.Download kernel and the cross-tools.(vmlinux)
+
+      https://github.com/loongson/linux/tree/loongarch-next
+      https://github.com/loongson/build-tools/releases/latest/download/loongarch64-clfs-20210831-cross-tools.tar.xz
+
+  2.Download the clfs-system and make a ramdisk with busybox.(ramdisk)
+
+  3.Run with command,eg:
+
+   ./build/qemu-system-loongarch64 -m 4G -smp 4 --cpu Loongson-3A5000 --machine loongson3-ls7a -kernel ./vmlinux -initrd ./ramdisk  -append "root=/dev/ram console=ttyS0,115200 rdinit=/sbin/init loglevel=8" -monitor tcp::4000,server,nowait -nographic
+
+The vmlinux, ramdisk and uefi binary loongarch_bios.bin can get from :
+    git clone https://github.com/yangxiaojuan-loongson/qemu-binary
 
 - Note.
   We can get the latest LoongArch documents or LoongArch tools at https://github.com/loongson/
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 02/27] target/loongarch: Add CSR registers definition
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
  2021-12-04 12:06 ` [RFC PATCH v3 01/27] target/loongarch: Update README Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 03/27] target/loongarch: Add basic vmstate description of CPU Xiaojuan Yang
                   ` (25 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

1.Define All the CSR registers and its field.
2.Set some default csr values.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/cpu-csr.h | 236 +++++++++++++++++++++++++++++++++++++
 target/loongarch/cpu.c     |  35 ++++++
 target/loongarch/cpu.h     |  57 +++++++++
 3 files changed, 328 insertions(+)
 create mode 100644 target/loongarch/cpu-csr.h

diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h
new file mode 100644
index 0000000000..7a57b7ea36
--- /dev/null
+++ b/target/loongarch/cpu-csr.h
@@ -0,0 +1,236 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch CPU CSR registers
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef LOONGARCH_CPU_CSR_H
+#define LOONGARCH_CPU_CSR_H
+
+/* Base on: kernal: arch/loongarch/include/asm/loongarch.h */
+
+/* Basic CSR register */
+#define LOONGARCH_CSR_CRMD           0x0 /* Current mode info */
+FIELD(CSR_CRMD, PLV, 0, 2)
+FIELD(CSR_CRMD, IE, 2, 1)
+FIELD(CSR_CRMD, DA, 3, 1)
+FIELD(CSR_CRMD, PG, 4, 1)
+FIELD(CSR_CRMD, DATF, 5, 2)
+FIELD(CSR_CRMD, DATM, 7, 2)
+FIELD(CSR_CRMD, WE, 9, 1)
+
+#define LOONGARCH_CSR_PRMD           0x1 /* Prev-exception mode info */
+FIELD(CSR_PRMD, PPLV, 0, 2)
+FIELD(CSR_PRMD, PIE, 2, 1)
+FIELD(CSR_PRMD, PWE, 3, 1)
+
+#define LOONGARCH_CSR_EUEN           0x2 /* Extended unit enable */
+FIELD(CSR_EUEN, FPE, 0, 1)
+FIELD(CSR_EUEN, SXE, 1, 1)
+FIELD(CSR_EUEN, ASXE, 2, 1)
+FIELD(CSR_EUEN, BTE, 3, 1)
+
+#define LOONGARCH_CSR_MISC           0x3 /* Misc config */
+
+#define LOONGARCH_CSR_ECFG           0x4 /* Exception config */
+FIELD(CSR_ECFG, LIE, 0, 13)
+FIELD(CSR_ECFG, VS, 16, 3)
+
+#define LOONGARCH_CSR_ESTAT          0x5 /* Exception status */
+FIELD(CSR_ESTAT, IS, 0, 13)
+FIELD(CSR_ESTAT, ECODE, 16, 6)
+FIELD(CSR_ESTAT, ESUBCODE, 22, 9)
+
+#define  EXCCODE_EXTERNAL_INT   64   /* plus external interrupt number */
+#define  EXCCODE_INT                 0
+#define  EXCCODE_PIL                 1
+#define  EXCCODE_PIS                 2
+#define  EXCCODE_PIF                 3
+#define  EXCCODE_PME                 4
+#define  EXCCODE_PNR                 5
+#define  EXCCODE_PNX                 6
+#define  EXCCODE_PPI                 7
+#define  EXCCODE_ADEF                8 /* Have different expsubcode */
+#define  EXCCODE_ADEM                8 /* Have different expsubcode */
+#define  EXCCODE_ALE                 9
+#define  EXCCODE_BCE                 10
+#define  EXCCODE_SYS                 11
+#define  EXCCODE_BRK                 12
+#define  EXCCODE_INE                 13
+#define  EXCCODE_IPE                 14
+#define  EXCCODE_FPD                 15
+#define  EXCCODE_SXD                 16
+#define  EXCCODE_ASXD                17
+#define  EXCCODE_FPE                 18 /* Have different expsubcode */
+#define  EXCCODE_VFPE                18
+#define  EXCCODE_WPEF                19 /* Have different expsubcode */
+#define  EXCCODE_WPEM                19
+#define  EXCCODE_BTD                 20
+#define  EXCCODE_BTE                 21
+#define  EXCCODE_DBP                 26 /* Reserved decode used for debug */
+
+#define LOONGARCH_CSR_ERA            0x6 /* Exception return address */
+
+#define LOONGARCH_CSR_BADV           0x7 /* Bad virtual address */
+
+#define LOONGARCH_CSR_BADI           0x8 /* Bad instruction */
+
+#define LOONGARCH_CSR_EENTRY         0xc /* Exception enter base address */
+
+/* TLB related CSR register */
+#define LOONGARCH_CSR_TLBIDX         0x10 /* TLB Index, EHINV, PageSize, NP */
+FIELD(CSR_TLBIDX, INDEX, 0, 12)
+FIELD(CSR_TLBIDX, PS, 24, 6)
+FIELD(CSR_TLBIDX, NE, 31, 1)
+
+#define LOONGARCH_CSR_TLBEHI         0x11 /* TLB EntryHi without ASID */
+FIELD(CSR_TLBEHI, VPPN, 13, 35)
+
+#define LOONGARCH_CSR_TLBELO0        0x12 /* TLB EntryLo0 */
+#define LOONGARCH_CSR_TLBELO1        0x13 /* TLB EntryLo1 */
+FIELD(TLBENTRY, V, 0, 1)
+FIELD(TLBENTRY, D, 1, 1)
+FIELD(TLBENTRY, PLV, 2, 2)
+FIELD(TLBENTRY, MAT, 4, 2)
+FIELD(TLBENTRY, G, 6, 1)
+FIELD(TLBENTRY, PPN, 12, 36)
+FIELD(TLBENTRY, NR, 61, 1)
+FIELD(TLBENTRY, NX, 62, 1)
+FIELD(TLBENTRY, RPLV, 63, 1)
+
+#define LOONGARCH_CSR_ASID           0x18 /* Address space identifier */
+FIELD(CSR_ASID, ASID, 0, 10)
+FIELD(CSR_ASID, ASIDBITS, 16, 8)
+
+/* Page table base address when badv[47] = 0 */
+#define LOONGARCH_CSR_PGDL           0x19
+/* Page table base address when badv[47] = 1 */
+#define LOONGARCH_CSR_PGDH           0x1a
+
+#define LOONGARCH_CSR_PGD            0x1b /* Page table base */
+
+/* Page walk controller's low addr */
+#define LOONGARCH_CSR_PWCL           0x1c
+FIELD(CSR_PWCL, PTBASE, 0, 5)
+FIELD(CSR_PWCL, PTWIDTH, 5, 5)
+FIELD(CSR_PWCL, DIR1_BASE, 10, 5)
+FIELD(CSR_PWCL, DIR1_WIDTH, 15, 5)
+FIELD(CSR_PWCL, DIR2_BASE, 20, 5)
+FIELD(CSR_PWCL, DIR2_WIDTH, 25, 5)
+FIELD(CSR_PWCL, PTEWIDTH, 30, 2)
+
+/* Page walk controller's high addr */
+#define LOONGARCH_CSR_PWCH           0x1d
+FIELD(CSR_PWCH, DIR3_BASE, 0, 6)
+FIELD(CSR_PWCH, DIR3_WIDTH, 6, 6)
+FIELD(CSR_PWCH, DIR4_BASE, 12, 6)
+FIELD(CSR_PWCH, DIR4_WIDTH, 18, 6)
+
+#define LOONGARCH_CSR_STLBPS         0x1e /*Stlb page size*/
+FIELD(CSR_STLBPS, PS, 0, 5)
+
+#define LOONGARCH_CSR_RVACFG         0x1f /* Reduced virtual address config */
+FIELD(CSR_RVACFG, RBITS, 0, 4)
+
+/* Config CSR registers */
+#define LOONGARCH_CSR_CPUID          0x20 /* CPU core id */
+
+#define LOONGARCH_CSR_PRCFG1         0x21 /* Config1 */
+FIELD(CSR_PRCFG1, SAVE_NUM, 0, 4)
+FIELD(CSR_PRCFG1, TIMER_BITS, 4, 8)
+FIELD(CSR_PRCFG1, VSMAX, 12, 3)
+
+#define LOONGARCH_CSR_PRCFG2         0x22 /* Config2 */
+
+#define LOONGARCH_CSR_PRCFG3         0x23 /* Config3 */
+FIELD(CSR_PRCFG3, TLB_TYPE, 0, 4)
+FIELD(CSR_PRCFG3, MTLB_ENTRY, 4, 8)
+FIELD(CSR_PRCFG3, STLB_WAYS, 12, 8)
+FIELD(CSR_PRCFG3, STLB_SETS, 20, 8)
+
+/*
+ * Save registers count can read from PRCFG1.SAVE_NUM
+ * The Min count is 1. Max count is 15.
+ */
+#define LOONGARCH_CSR_SAVE(N)        (0x30 + N)
+
+/* Timer registers */
+#define LOONGARCH_CSR_TID            0x40 /* Timer ID */
+
+#define LOONGARCH_CSR_TCFG           0x41 /* Timer config */
+FIELD(CSR_TCFG, EN, 0, 1)
+FIELD(CSR_TCFG, PERIODIC, 1, 1)
+FIELD(CSR_TCFG, INIT_VAL, 2, 46)
+
+#define LOONGARCH_CSR_TVAL           0x42 /* Timer ticks remain */
+
+#define LOONGARCH_CSR_CNTC           0x43 /* Timer offset */
+
+#define LOONGARCH_CSR_TICLR          0x44 /* Timer interrupt clear */
+
+/* LLBCTL register */
+#define LOONGARCH_CSR_LLBCTL         0x60 /* LLBit control */
+FIELD(CSR_LLBCTL, ROLLB, 0, 1)
+FIELD(CSR_LLBCTL, WCLLB, 1, 1)
+FIELD(CSR_LLBCTL, KLO, 2, 1)
+
+/* Implement dependent */
+#define LOONGARCH_CSR_IMPCTL1        0x80 /* LoongArch config1 */
+
+#define LOONGARCH_CSR_IMPCTL2        0x81 /* LoongArch config2*/
+
+/* TLB Refill registers */
+#define LOONGARCH_CSR_TLBRENTRY      0x88 /* TLB refill exception address */
+#define LOONGARCH_CSR_TLBRBADV       0x89 /* TLB refill badvaddr */
+#define LOONGARCH_CSR_TLBRERA        0x8a /* TLB refill ERA */
+#define LOONGARCH_CSR_TLBRSAVE       0x8b /* KScratch for TLB refill */
+FIELD(CSR_TLBRERA, ISTLBR, 0, 1)
+FIELD(CSR_TLBRERA, PC, 2, 62)
+#define LOONGARCH_CSR_TLBRELO0       0x8c /* TLB refill entrylo0 */
+#define LOONGARCH_CSR_TLBRELO1       0x8d /* TLB refill entrylo1 */
+#define LOONGARCH_CSR_TLBREHI        0x8e /* TLB refill entryhi */
+FIELD(CSR_TLBREHI, PS, 0, 6)
+FIELD(CSR_TLBREHI, VPPN, 13, 35)
+#define LOONGARCH_CSR_TLBRPRMD       0x8f /* TLB refill mode info */
+FIELD(CSR_TLBRPRMD, PPLV, 0, 2)
+FIELD(CSR_TLBRPRMD, PIE, 2, 1)
+FIELD(CSR_TLBRPRMD, PWE, 4, 1)
+
+/* Machine Error registers */
+#define LOONGARCH_CSR_MERRCTL        0x90 /* ERRCTL */
+FIELD(CSR_MERRCTL, ISMERR, 0, 1)
+#define LOONGARCH_CSR_MERRINFO1      0x91
+#define LOONGARCH_CSR_MERRINFO2      0x92
+#define LOONGARCH_CSR_MERRENTRY      0x93 /* MError exception base */
+#define LOONGARCH_CSR_MERRERA        0x94 /* MError exception PC */
+#define LOONGARCH_CSR_MERRSAVE       0x95 /* KScratch for error exception */
+
+#define LOONGARCH_CSR_CTAG           0x98 /* TagLo + TagHi */
+
+/* Direct map windows */
+#define LOONGARCH_CSR_DMW(N)         (0x180 + N) /* direct map win MEM & IF */
+FIELD(CSR_DMW, PLV0, 0, 1)
+FIELD(CSR_DMW, PLV1, 1, 1)
+FIELD(CSR_DMW, PLV2, 2, 1)
+FIELD(CSR_DMW, PLV3, 3, 1)
+FIELD(CSR_DMW, MAT, 4, 2)
+FIELD(CSR_DMW, VSEG, 60, 4)
+
+#define dmw_va2pa(va) \
+    (va & MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS))
+
+/* Debug registers */
+#define LOONGARCH_CSR_DBG            0x500 /* debug config */
+FIELD(CSR_DBG, DST, 0, 1)
+FIELD(CSR_DBG, DREV, 1, 7)
+FIELD(CSR_DBG, DEI, 8, 1)
+FIELD(CSR_DBG, DCL, 9, 1)
+FIELD(CSR_DBG, DFW, 10, 1)
+FIELD(CSR_DBG, DMW, 11, 1)
+FIELD(CSR_DBG, ECODE, 16, 6)
+
+#define LOONGARCH_CSR_DERA           0x501 /* Debug era */
+#define LOONGARCH_CSR_DSAVE          0x502 /* Debug save */
+
+#endif /* LOONGARCH_CPU_CSR_H */
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index edb17226a0..69a814c8e9 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -155,6 +155,8 @@ static void loongarch_3a5000_initfn(Object *obj)
     data = FIELD_DP32(data, CPUCFG20, L3IU_WAYS, 0xf00f);
     data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 0x60);
     env->cpucfg[20] = data;
+
+    env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa);
 }
 
 static void loongarch_cpu_list_entry(gpointer data, gpointer user_data)
@@ -178,12 +180,45 @@ static void loongarch_cpu_reset(DeviceState *dev)
     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
     LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu);
     CPULoongArchState *env = &cpu->env;
+    int n;
 
     lacc->parent_reset(dev);
 
     env->fcsr0_mask = 0x1f1f031f;
     env->fcsr0 = 0x0;
 
+    /* Set csr registers value after reset */
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1);
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0);
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 1);
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 1);
+
+    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0);
+    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0);
+    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, ASXE, 0);
+    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, BTE, 0);
+
+    env->CSR_MISC = 0;
+
+    env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, VS, 0);
+    env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, LIE, 0);
+
+    env->CSR_ESTAT = env->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2));
+    env->CSR_RVACFG = FIELD_DP64(env->CSR_RVACFG, CSR_RVACFG, RBITS, 0);
+    env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
+    env->CSR_LLBCTL = FIELD_DP64(env->CSR_LLBCTL, CSR_LLBCTL, KLO, 0);
+    env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0);
+    env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0);
+
+    for (n = 0; n < 4; n++) {
+        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0);
+        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0);
+        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV2, 0);
+        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0);
+    }
+
     restore_fp_status(env);
     cs->exception_index = EXCP_NONE;
 }
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index ab60322558..a4acd3b285 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -11,6 +11,7 @@
 #include "exec/cpu-defs.h"
 #include "fpu/softfloat-types.h"
 #include "hw/registerfields.h"
+#include "cpu-csr.h"
 
 #define TCG_GUEST_DEFAULT_MO (0)
 
@@ -170,6 +171,62 @@ struct CPULoongArchState {
     uint64_t llval;
 
     uint64_t badaddr;
+
+    /* LoongArch CSR registers */
+    uint64_t CSR_CRMD;
+    uint64_t CSR_PRMD;
+    uint64_t CSR_EUEN;
+    uint64_t CSR_MISC;
+    uint64_t CSR_ECFG;
+    uint64_t CSR_ESTAT;
+    uint64_t CSR_ERA;
+    uint64_t CSR_BADV;
+    uint64_t CSR_BADI;
+    uint64_t CSR_EENTRY;
+    uint64_t CSR_TLBIDX;
+    uint64_t CSR_TLBEHI;
+    uint64_t CSR_TLBELO0;
+    uint64_t CSR_TLBELO1;
+    uint64_t CSR_ASID;
+    uint64_t CSR_PGDL;
+    uint64_t CSR_PGDH;
+    uint64_t CSR_PGD;
+    uint64_t CSR_PWCL;
+    uint64_t CSR_PWCH;
+    uint64_t CSR_STLBPS;
+    uint64_t CSR_RVACFG;
+    uint64_t CSR_CPUID;
+    uint64_t CSR_PRCFG1;
+    uint64_t CSR_PRCFG2;
+    uint64_t CSR_PRCFG3;
+    uint64_t CSR_SAVE[16];
+    uint64_t CSR_TID;
+    uint64_t CSR_TCFG;
+    uint64_t CSR_TVAL;
+    uint64_t CSR_CNTC;
+    uint64_t CSR_TICLR;
+    uint64_t CSR_LLBCTL;
+    uint64_t CSR_IMPCTL1;
+    uint64_t CSR_IMPCTL2;
+    uint64_t CSR_TLBRENTRY;
+    uint64_t CSR_TLBRBADV;
+    uint64_t CSR_TLBRERA;
+    uint64_t CSR_TLBRSAVE;
+    uint64_t CSR_TLBRELO0;
+    uint64_t CSR_TLBRELO1;
+    uint64_t CSR_TLBREHI;
+    uint64_t CSR_TLBRPRMD;
+    uint64_t CSR_MERRCTL;
+    uint64_t CSR_MERRINFO1;
+    uint64_t CSR_MERRINFO2;
+    uint64_t CSR_MERRENTRY;
+    uint64_t CSR_MERRERA;
+    uint64_t CSR_MERRSAVE;
+    uint64_t CSR_CTAG;
+    uint64_t CSR_DMW[4];
+    uint64_t CSR_DBG;
+    uint64_t CSR_DERA;
+    uint64_t CSR_DSAVE;
 };
 
 /**
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 03/27] target/loongarch: Add basic vmstate description of CPU.
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
  2021-12-04 12:06 ` [RFC PATCH v3 01/27] target/loongarch: Update README Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 02/27] target/loongarch: Add CSR registers definition Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 04/27] target/loongarch: Implement qmp_query_cpu_definitions() Xiaojuan Yang
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This patch introduce vmstate_loongarch_cpu

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/loongarch/cpu.c       |  3 ++
 target/loongarch/internals.h |  4 ++
 target/loongarch/machine.c   | 84 ++++++++++++++++++++++++++++++++++++
 target/loongarch/meson.build |  6 +++
 4 files changed, 97 insertions(+)
 create mode 100644 target/loongarch/machine.c

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 69a814c8e9..55ecd83691 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -319,6 +319,9 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
     cc->has_work = loongarch_cpu_has_work;
     cc->dump_state = loongarch_cpu_dump_state;
     cc->set_pc = loongarch_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+    dc->vmsd = &vmstate_loongarch_cpu;
+#endif
     cc->disas_set_info = loongarch_cpu_disas_set_info;
 #ifdef CONFIG_TCG
     cc->tcg_ops = &loongarch_tcg_ops;
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 774a87ec80..c8e6f7012c 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -25,4 +25,8 @@ const char *loongarch_exception_name(int32_t exception);
 
 void restore_fp_status(CPULoongArchState *env);
 
+#ifndef CONFIG_USER_ONLY
+extern const VMStateDescription vmstate_loongarch_cpu;
+#endif
+
 #endif
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
new file mode 100644
index 0000000000..b9effe6db2
--- /dev/null
+++ b/target/loongarch/machine.c
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch machine State
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "migration/cpu.h"
+
+/* LoongArch CPU state */
+
+const VMStateDescription vmstate_loongarch_cpu = {
+    .name = "cpu",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+
+        VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32),
+        VMSTATE_UINTTL(env.pc, LoongArchCPU),
+        VMSTATE_UINT64_ARRAY(env.fpr, LoongArchCPU, 32),
+        VMSTATE_UINT32(env.fcsr0, LoongArchCPU),
+
+        /* Remaining CSR registers */
+        VMSTATE_UINT64(env.CSR_CRMD, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_PRMD, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_EUEN, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_MISC, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_ECFG, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_ESTAT, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_ERA, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_BADV, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_BADI, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_EENTRY, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBIDX, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBEHI, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBELO0, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBELO1, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_ASID, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_PGDL, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_PGDH, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_PGD, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_PWCL, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_PWCH, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_STLBPS, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_RVACFG, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_CPUID, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_PRCFG1, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_PRCFG2, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_PRCFG3, LoongArchCPU),
+        VMSTATE_UINT64_ARRAY(env.CSR_SAVE, LoongArchCPU, 16),
+        VMSTATE_UINT64(env.CSR_TID, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TCFG, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TVAL, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_CNTC, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TICLR, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_LLBCTL, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_IMPCTL1, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_IMPCTL2, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBRENTRY, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBRBADV, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBRERA, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBRSAVE, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBRELO0, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBRELO1, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBREHI, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_TLBRPRMD, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_MERRCTL, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_MERRINFO1, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_MERRINFO2, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_MERRENTRY, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_MERRERA, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_MERRSAVE, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_CTAG, LoongArchCPU),
+        VMSTATE_UINT64_ARRAY(env.CSR_DMW, LoongArchCPU, 4),
+        /* debug */
+        VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU),
+        VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU),
+
+        VMSTATE_END_OF_LIST()
+    },
+};
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index bcb076e55f..103f36ee15 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -14,6 +14,12 @@ loongarch_tcg_ss.add(files(
 ))
 loongarch_tcg_ss.add(zlib)
 
+loongarch_softmmu_ss = ss.source_set()
+loongarch_softmmu_ss.add(files(
+  'machine.c',
+))
+
 loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
 
 target_arch += {'loongarch': loongarch_ss}
+target_softmmu_arch += {'loongarch': loongarch_softmmu_ss}
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 04/27] target/loongarch: Implement qmp_query_cpu_definitions()
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (2 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 03/27] target/loongarch: Add basic vmstate description of CPU Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 05/27] target/loongarch: Add stabletimer support Xiaojuan Yang
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This patch introduce qmp_query_cpu_definitions interface.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 qapi/machine-target.json |  6 ++++--
 target/loongarch/cpu.c   | 26 ++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/qapi/machine-target.json b/qapi/machine-target.json
index f5ec4bc172..682dc86b42 100644
--- a/qapi/machine-target.json
+++ b/qapi/machine-target.json
@@ -324,7 +324,8 @@
                    'TARGET_ARM',
                    'TARGET_I386',
                    'TARGET_S390X',
-                   'TARGET_MIPS' ] } }
+                   'TARGET_MIPS',
+                   'TARGET_LOONGARCH64' ] } }
 
 ##
 # @query-cpu-definitions:
@@ -340,4 +341,5 @@
                    'TARGET_ARM',
                    'TARGET_I386',
                    'TARGET_S390X',
-                   'TARGET_MIPS' ] } }
+                   'TARGET_MIPS',
+                   'TARGET_LOONGARCH64' ] } }
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 55ecd83691..343632c644 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -350,3 +350,29 @@ static const TypeInfo loongarch_cpu_type_infos[] = {
 };
 
 DEFINE_TYPES(loongarch_cpu_type_infos)
+
+static void loongarch_cpu_add_definition(gpointer data, gpointer user_data)
+{
+    ObjectClass *oc = data;
+    CpuDefinitionInfoList **cpu_list = user_data;
+    CpuDefinitionInfo *info = g_new0(CpuDefinitionInfo, 1);
+    const char *typename = object_class_get_name(oc);
+
+    info->name = g_strndup(typename,
+                           strlen(typename) - strlen("-" TYPE_LOONGARCH_CPU));
+    info->q_typename = g_strdup(typename);
+
+    QAPI_LIST_PREPEND(*cpu_list, info);
+}
+
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+{
+    CpuDefinitionInfoList *cpu_list = NULL;
+    GSList *list;
+
+    list = object_class_get_list(TYPE_LOONGARCH_CPU, false);
+    g_slist_foreach(list, loongarch_cpu_add_definition, &cpu_list);
+    g_slist_free(list);
+
+    return cpu_list;
+}
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 05/27] target/loongarch: Add stabletimer support
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (3 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 04/27] target/loongarch: Implement qmp_query_cpu_definitions() Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-06  4:38   ` chen huacai
  2021-12-04 12:07 ` [RFC PATCH v3 06/27] target/loongarch: Add MMU support for LoongArch CPU Xiaojuan Yang
                   ` (22 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/cpu.c         |  9 +++++
 target/loongarch/cpu.h         | 10 ++++++
 target/loongarch/meson.build   |  1 +
 target/loongarch/stabletimer.c | 63 ++++++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+)
 create mode 100644 target/loongarch/stabletimer.c

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 343632c644..f34e9763af 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -234,12 +234,21 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
     LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
     Error *local_err = NULL;
 
+#ifndef CONFIG_USER_ONLY
+    LoongArchCPU *cpu = LOONGARCH_CPU(dev);
+#endif
+
     cpu_exec_realizefn(cs, &local_err);
     if (local_err != NULL) {
         error_propagate(errp, local_err);
         return;
     }
 
+#ifndef CONFIG_USER_ONLY
+    timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
+                  &loongarch_stable_timer_cb, cpu);
+#endif
+
     cpu_reset(cs);
     qemu_init_vcpu(cs);
 
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index a4acd3b285..aeb8a5d397 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -12,6 +12,7 @@
 #include "fpu/softfloat-types.h"
 #include "hw/registerfields.h"
 #include "cpu-csr.h"
+#include "qemu/timer.h"
 
 #define TCG_GUEST_DEFAULT_MO (0)
 
@@ -148,6 +149,9 @@ FIELD(CPUCFG20, L3IU_SIZE, 24, 7)
 extern const char * const regnames[];
 extern const char * const fregnames[];
 
+#define N_IRQS      14
+#define IRQ_TIMER   11
+
 typedef struct CPULoongArchState CPULoongArchState;
 struct CPULoongArchState {
     uint64_t gpr[32];
@@ -242,6 +246,7 @@ struct LoongArchCPU {
 
     CPUNegativeOffsetState neg;
     CPULoongArchState env;
+    QEMUTimer timer; /* Internal timer */
 };
 
 #define TYPE_LOONGARCH_CPU "loongarch-cpu"
@@ -306,4 +311,9 @@ enum {
 #define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
 #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
 
+void loongarch_stable_timer_cb(void *opaque);
+uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu);
+uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu);
+void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
+                                             uint64_t value);
 #endif /* LOONGARCH_CPU_H */
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 103f36ee15..bda9f47ae4 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -17,6 +17,7 @@ loongarch_tcg_ss.add(zlib)
 loongarch_softmmu_ss = ss.source_set()
 loongarch_softmmu_ss.add(files(
   'machine.c',
+  'stabletimer.c',
 ))
 
 loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
diff --git a/target/loongarch/stabletimer.c b/target/loongarch/stabletimer.c
new file mode 100644
index 0000000000..151f5073f5
--- /dev/null
+++ b/target/loongarch/stabletimer.c
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch timer support
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/loongarch/loongarch.h"
+#include "qemu/timer.h"
+#include "cpu.h"
+
+#define TIMER_PERIOD                10 /* 10 ns period for 100 Mhz frequency */
+#define STABLETIMER_TICK_MASK       0xfffffffffffcUL
+#define STABLETIMER_ENABLE          0x1UL
+
+/* LoongArch timer */
+uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu)
+{
+    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD;
+}
+
+uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu)
+{
+    uint64_t now, expire;
+
+    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    expire = timer_expire_time_ns(&cpu->timer);
+
+    return (expire - now) / TIMER_PERIOD;
+}
+
+void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
+                                             uint64_t value)
+{
+    CPULoongArchState *env = &cpu->env;
+    uint64_t now, next;
+
+    env->CSR_TCFG = value;
+    if (value & STABLETIMER_ENABLE) {
+        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        next = now + (value & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
+        timer_mod(&cpu->timer, next);
+    }
+}
+
+void loongarch_stable_timer_cb(void *opaque)
+{
+    LoongArchCPU *cpu  = opaque;
+    CPULoongArchState *env = &cpu->env;
+    uint64_t now, next;
+
+    if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) {
+        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        next = now + (env->CSR_TCFG & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
+        timer_mod(&cpu->timer, next);
+    } else {
+        env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
+    }
+
+    env->CSR_ESTAT |= 1 << IRQ_TIMER;
+    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
+}
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 06/27] target/loongarch: Add MMU support for LoongArch CPU.
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (4 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 05/27] target/loongarch: Add stabletimer support Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 07/27] target/loongarch: Add LoongArch CSR instruction Xiaojuan Yang
                   ` (21 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This patch introduces basic TLB interfaces.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/cpu-param.h  |   2 +-
 target/loongarch/cpu.c        |  32 ++++
 target/loongarch/cpu.h        |  45 ++++-
 target/loongarch/internals.h  |  10 +
 target/loongarch/machine.c    |  20 ++
 target/loongarch/meson.build  |   1 +
 target/loongarch/op_helper.c  |   8 +
 target/loongarch/tlb_helper.c | 334 ++++++++++++++++++++++++++++++++++
 8 files changed, 450 insertions(+), 2 deletions(-)
 create mode 100644 target/loongarch/tlb_helper.c

diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h
index 9a769b67e0..414d8fff46 100644
--- a/target/loongarch/cpu-param.h
+++ b/target/loongarch/cpu-param.h
@@ -13,6 +13,6 @@
 #define TARGET_VIRT_ADDR_SPACE_BITS 48
 
 #define TARGET_PAGE_BITS 14
-#define NB_MMU_MODES 4
+#define NB_MMU_MODES 5
 
 #endif
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index f34e9763af..8c7ce993db 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -236,6 +236,7 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
 
 #ifndef CONFIG_USER_ONLY
     LoongArchCPU *cpu = LOONGARCH_CPU(dev);
+    CPULoongArchState *env = &cpu->env;
 #endif
 
     cpu_exec_realizefn(cs, &local_err);
@@ -247,6 +248,7 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
 #ifndef CONFIG_USER_ONLY
     timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
                   &loongarch_stable_timer_cb, cpu);
+    loongarch_mmu_init(env);
 #endif
 
     cpu_reset(cs);
@@ -294,6 +296,23 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
         }
     }
 
+#ifndef CONFIG_USER_ONLY
+    qemu_fprintf(f, "EUEN=%016" PRIx64 "\n", env->CSR_EUEN);
+    qemu_fprintf(f, "ESTAT=%016" PRIx64 "\n", env->CSR_ESTAT);
+    qemu_fprintf(f, "ERA=%016" PRIx64 "\n", env->CSR_ERA);
+    qemu_fprintf(f, "CRMD=%016" PRIx64 "\n", env->CSR_CRMD);
+    qemu_fprintf(f, "PRMD=%016" PRIx64 "\n", env->CSR_PRMD);
+    qemu_fprintf(f, "BadVAddr=%016" PRIx64 "\n", env->CSR_BADV);
+    qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY);
+    qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA);
+    qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV);
+    qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY);
+    qemu_fprintf(f, "BadInstr=%016" PRIx64 "\n", env->CSR_BADI);
+    qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 ","
+                 " PRCFG3=%016" PRIx64 "\n",
+                 env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3);
+#endif
+
     /* fpr */
     if (flags & CPU_DUMP_FPU) {
         for (i = 0; i < 32; i++) {
@@ -311,9 +330,21 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 static struct TCGCPUOps loongarch_tcg_ops = {
     .initialize = loongarch_translate_init,
     .synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
+
+#if !defined(CONFIG_USER_ONLY)
+    .tlb_fill = loongarch_cpu_tlb_fill,
+#endif /* !CONFIG_USER_ONLY */
 };
 #endif /* CONFIG_TCG */
 
+#ifndef CONFIG_USER_ONLY
+#include "hw/core/sysemu-cpu-ops.h"
+
+static const struct SysemuCPUOps loongarch_sysemu_ops = {
+    .get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
+};
+#endif
+
 static void loongarch_cpu_class_init(ObjectClass *c, void *data)
 {
     LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c);
@@ -330,6 +361,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
     cc->set_pc = loongarch_cpu_set_pc;
 #ifndef CONFIG_USER_ONLY
     dc->vmsd = &vmstate_loongarch_cpu;
+    cc->sysemu_ops = &loongarch_sysemu_ops;
 #endif
     cc->disas_set_info = loongarch_cpu_disas_set_info;
 #ifdef CONFIG_TCG
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index aeb8a5d397..6bbd1ab764 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -152,6 +152,27 @@ extern const char * const fregnames[];
 #define N_IRQS      14
 #define IRQ_TIMER   11
 
+#define LOONGARCH_TLB_MAX      (2048 + 64) /* 2048 STLB + 64 MTLB */
+
+/*
+ * define the ASID PS E VPPN field of TLB
+ *
+ * PS of stlb come from stlbps.ps
+ * PS of mtlb come from tlbidx.ps
+ */
+FIELD(TLB_MISC, E, 0, 1)
+FIELD(TLB_MISC, ASID, 1, 10)
+FIELD(TLB_MISC, VPPN, 13, 35)
+FIELD(TLB_MISC, PS, 48, 6)
+
+struct loongarch_tlb {
+    uint64_t tlb_misc;
+    /* Fields corresponding to CSR_TLBELO0/1 */
+    uint64_t tlb_entry0;
+    uint64_t tlb_entry1;
+};
+typedef struct loongarch_tlb loongarch_tlb;
+
 typedef struct CPULoongArchState CPULoongArchState;
 struct CPULoongArchState {
     uint64_t gpr[32];
@@ -231,6 +252,12 @@ struct CPULoongArchState {
     uint64_t CSR_DBG;
     uint64_t CSR_DERA;
     uint64_t CSR_DSAVE;
+
+#ifndef CONFIG_USER_ONLY
+    uint32_t      stlb_size; /* at most : 8 * 256 = 2048 */
+    uint32_t      mtlb_size; /* at most : 64 */
+    loongarch_tlb tlb[LOONGARCH_TLB_MAX];
+#endif
 };
 
 /**
@@ -270,11 +297,27 @@ struct LoongArchCPUClass {
     DeviceReset parent_reset;
 };
 
-#define MMU_USER_IDX 3
+/*
+ * LoongArch cpu has 4 priv level.
+ * 0 for kernel mode, 3 for user mode.
+ * Define a extra index for Direct mode.
+ */
+#define MMU_KERNEL_IDX 0 /* kernel mode idx */
+#define MMU_USER_IDX   3 /* user mode idx */
+#define MMU_DA_IDX     4 /* DA mode idx */
 
 static inline int cpu_mmu_index(CPULoongArchState *env, bool ifetch)
 {
+#ifdef CONFIG_USER_ONLY
     return MMU_USER_IDX;
+#else
+    uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
+
+    if (!pg) {
+        return MMU_DA_IDX;
+    }
+    return FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV);
+#endif
 }
 
 static inline void cpu_get_tb_cpu_state(CPULoongArchState *env,
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index c8e6f7012c..a5b81bdca3 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -13,6 +13,9 @@
 #define FCMP_UN   0b0100  /* unordered */
 #define FCMP_GT   0b1000  /* fp0 > fp1 */
 
+#define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS)
+#define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS)
+
 void loongarch_translate_init(void);
 
 void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
@@ -27,6 +30,13 @@ void restore_fp_status(CPULoongArchState *env);
 
 #ifndef CONFIG_USER_ONLY
 extern const VMStateDescription vmstate_loongarch_cpu;
+
+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+                            MMUAccessType access_type, int mmu_idx,
+                            bool probe, uintptr_t retaddr);
+
+void loongarch_mmu_init(CPULoongArchState *env);
+hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 #endif
 
 #endif
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index b9effe6db2..fbaa091603 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -8,6 +8,20 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "migration/cpu.h"
+#include "internals.h"
+
+/* TLB state */
+const VMStateDescription vmstate_tlb = {
+    .name = "cpu/tlb",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(tlb_misc, loongarch_tlb),
+        VMSTATE_UINT64(tlb_entry0, loongarch_tlb),
+        VMSTATE_UINT64(tlb_entry1, loongarch_tlb),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 /* LoongArch CPU state */
 
@@ -22,6 +36,10 @@ const VMStateDescription vmstate_loongarch_cpu = {
         VMSTATE_UINT64_ARRAY(env.fpr, LoongArchCPU, 32),
         VMSTATE_UINT32(env.fcsr0, LoongArchCPU),
 
+        /* TLB */
+        VMSTATE_UINT32(env.stlb_size, LoongArchCPU),
+        VMSTATE_UINT32(env.mtlb_size, LoongArchCPU),
+
         /* Remaining CSR registers */
         VMSTATE_UINT64(env.CSR_CRMD, LoongArchCPU),
         VMSTATE_UINT64(env.CSR_PRMD, LoongArchCPU),
@@ -78,6 +96,8 @@ const VMStateDescription vmstate_loongarch_cpu = {
         VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU),
         VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU),
         VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU),
+        VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX,
+                             0, vmstate_tlb, loongarch_tlb),
 
         VMSTATE_END_OF_LIST()
     },
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index bda9f47ae4..935ffe2765 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -18,6 +18,7 @@ loongarch_softmmu_ss = ss.source_set()
 loongarch_softmmu_ss.add(files(
   'machine.c',
   'stabletimer.c',
+  'tlb_helper.c',
 ))
 
 loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
index 1083e39b7f..48c25e5a9b 100644
--- a/target/loongarch/op_helper.c
+++ b/target/loongarch/op_helper.c
@@ -47,16 +47,24 @@ target_ulong helper_bitswap(target_ulong v)
 void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
 {
     if (rj > rk) {
+#ifdef CONFIG_USER_ONLY
         cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
                               MMU_DATA_LOAD, true, GETPC());
+#else
+        do_raise_exception(env, EXCCODE_ADEM, GETPC());
+#endif
     }
 }
 
 void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
 {
     if (rj <= rk) {
+#ifdef CONFIG_USER_ONLY
         cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
                               MMU_DATA_LOAD, true, GETPC());
+#else
+        do_raise_exception(env, EXCCODE_ADEM, GETPC());
+#endif
     }
 }
 
diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c
new file mode 100644
index 0000000000..e0b1390903
--- /dev/null
+++ b/target/loongarch/tlb_helper.c
@@ -0,0 +1,334 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch TLB helpers for qemu
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "cpu.h"
+#include "internals.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "exec/log.h"
+#include "cpu-csr.h"
+
+enum {
+    TLBRET_MATCH = 0,
+    TLBRET_BADADDR = 1,
+    TLBRET_NOMATCH = 2,
+    TLBRET_INVALID = 3,
+    TLBRET_DIRTY = 4,
+    TLBRET_RI = 5,
+    TLBRET_XI = 6,
+    TLBRET_PE = 7,
+};
+
+/* TLB address map */
+static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
+                                   int *prot, target_ulong address,
+                                   int access_type, int index, int mmu_idx)
+{
+    loongarch_tlb *tlb = &env->tlb[index];
+    uint64_t plv = mmu_idx;
+    uint64_t tlb_entry, tlb_ppn;
+    uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv;
+
+    if (index > env->stlb_size) {
+        tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+    } else {
+        tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+    }
+    n = (address >> tlb_ps) & 0x1;/* Odd or even */
+
+    tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0;
+    tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V);
+    tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D);
+    tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV);
+    tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY, PPN);
+    tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY, NX);
+    tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY, NR);
+    tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY, RPLV);
+
+    /* Check access rights */
+    if (!tlb_v) {
+        return TLBRET_INVALID;
+    }
+
+    if (access_type == MMU_INST_FETCH && tlb_nx) {
+        return TLBRET_XI;
+    }
+
+    if (access_type == MMU_DATA_LOAD && tlb_nr) {
+        return TLBRET_RI;
+    }
+
+    if (((tlb_rplv == 0) && (plv > tlb_plv)) ||
+        ((tlb_rplv == 1) && (plv != tlb_plv))) {
+        return TLBRET_PE;
+    }
+
+    if ((access_type == MMU_DATA_STORE) && !tlb_d) {
+        return TLBRET_DIRTY;
+    }
+
+    /*
+     * tlb_entry contains ppn[47:12] while 16KB ppn is [47:15]
+     * need adjust.
+     */
+    *physical = (tlb_ppn << R_TLBENTRY_PPN_SHIFT) |
+                (address & MAKE_64BIT_MASK(0, tlb_ps));
+    *prot = PAGE_READ;
+    if (tlb_d) {
+        *prot |= PAGE_WRITE;
+    }
+    if (!tlb_nx) {
+        *prot |= PAGE_EXEC;
+    }
+    return TLBRET_MATCH;
+}
+
+/*
+ * One tlb entry holds a adjacent odd/even pair, the vpn is the
+ * content of the virtual page number divided by 2.So the
+ * compare vpn is bit[47:15] for 16KB page. while the vppn
+ * field in tlb entry contains bit[47:13], so need adjust.
+ * virt_vpn = vaddr[47:13]
+ */
+static bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr,
+                                 int *index)
+{
+    loongarch_tlb *tlb;
+    uint16_t csr_asid, tlb_asid, stlb_idx;
+    uint8_t tlb_e, tlb_ps, tlb_g, stlb_ps;
+    int i, stlb_size, mtlb_size, compare_shift;
+    uint64_t vpn, tlb_vppn;   /* Address to map */
+
+    stlb_size = env->stlb_size;
+    mtlb_size = env->mtlb_size;
+    csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+    stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+    vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1);
+    stlb_idx = vpn & 0xff; /* VA[25:15] <==> TLBIDX.index for 16KB Page */
+    compare_shift = stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
+
+    /* Search STLB */
+    for (i = 0; i < 8; ++i) {
+        tlb = &env->tlb[i * 256 + stlb_idx];
+        tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
+        if (tlb_e) {
+            tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+            tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+            tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+
+            if ((tlb_g == 1 || tlb_asid == csr_asid) &&
+                (vpn == (tlb_vppn >> compare_shift))) {
+                *index = i * 256 + stlb_idx;
+                return true;
+            }
+        }
+    }
+
+    /* Search MTLB */
+    for (i = stlb_size; i < stlb_size + mtlb_size; ++i) {
+        tlb = &env->tlb[i];
+        tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
+        if (tlb_e) {
+            tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+            tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+            tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+            tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+            compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
+
+            if ((tlb_g == 1 || tlb_asid == csr_asid) &&
+                (vpn == (tlb_vppn >> compare_shift))) {
+                *index = i;
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
+                                 int *prot, target_ulong address,
+                                 MMUAccessType access_type, int mmu_idx)
+{
+    int index, match;
+
+    match = loongarch_tlb_search(env, address, &index);
+    if (match) {
+        return loongarch_map_tlb_entry(env, physical, prot,
+                                       address, access_type, index, mmu_idx);
+    }
+
+    return TLBRET_NOMATCH;
+}
+
+static int get_physical_address(CPULoongArchState *env, hwaddr *physical,
+                                int *prot, target_ulong address,
+                                MMUAccessType access_type, int mmu_idx)
+{
+    int user_mode = mmu_idx == MMU_USER_IDX;
+    int kernel_mode = mmu_idx == MMU_KERNEL_IDX;
+    uint32_t plv, base_c, base_v;
+    int64_t addr_high;
+    uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA);
+    uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
+
+    /* Check PG and DA*/
+    if (da & !pg) {
+        /* DA mode */
+        *physical = address & TARGET_PHYS_MASK;
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return TLBRET_MATCH;
+    }
+
+    plv = kernel_mode | (user_mode << R_CSR_DMW_PLV3_SHIFT);
+    base_v = address >> TARGET_VIRT_ADDR_SPACE_BITS;
+    /* Check direct map window */
+    for (int i = 0; i < 4; i++) {
+        base_c = env->CSR_DMW[i] >> TARGET_VIRT_ADDR_SPACE_BITS;
+        if ((plv & env->CSR_DMW[i]) && (base_c == base_v)) {
+            *physical = dmw_va2pa(address);
+            *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+            return TLBRET_MATCH;
+        }
+    }
+
+    /* Check valid extension */
+    addr_high = sextract64(address, TARGET_VIRT_ADDR_SPACE_BITS, 16);
+    if (!(addr_high == 0 || addr_high == -1)) {
+        return TLBRET_BADADDR;
+    }
+    /* Mapped address */
+    return loongarch_map_address(env, physical, prot, address,
+                                 access_type, mmu_idx);
+}
+
+hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    CPULoongArchState *env = &cpu->env;
+    hwaddr phys_addr;
+    int prot;
+
+    if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD,
+                             cpu_mmu_index(env, false)) != 0) {
+        return -1;
+    }
+    return phys_addr;
+}
+
+static void raise_mmu_exception(CPULoongArchState *env, target_ulong address,
+                                MMUAccessType access_type, int tlb_error)
+{
+    CPUState *cs = env_cpu(env);
+
+    switch (tlb_error) {
+    default:
+    case TLBRET_BADADDR:
+        cs->exception_index = EXCCODE_ADEM;
+        break;
+    case TLBRET_NOMATCH:
+        /* No TLB match for a mapped address */
+        if (access_type == MMU_DATA_LOAD) {
+            cs->exception_index = EXCCODE_PIL;
+        } else if (access_type == MMU_DATA_STORE) {
+            cs->exception_index = EXCCODE_PIS;
+        } else if (access_type == MMU_INST_FETCH) {
+            cs->exception_index = EXCCODE_PIF;
+        }
+        env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 1);
+        break;
+    case TLBRET_INVALID:
+        /* TLB match with no valid bit */
+        if (access_type == MMU_DATA_LOAD) {
+            cs->exception_index = EXCCODE_PIL;
+        } else if (access_type == MMU_DATA_STORE) {
+            cs->exception_index = EXCCODE_PIS;
+        } else if (access_type == MMU_INST_FETCH) {
+            cs->exception_index = EXCCODE_PIF;
+        }
+        break;
+    case TLBRET_DIRTY:
+        /* TLB match but 'D' bit is cleared */
+        cs->exception_index = EXCCODE_PME;
+        break;
+    case TLBRET_XI:
+        /* Execute-Inhibit Exception */
+        cs->exception_index = EXCCODE_PNX;
+        break;
+    case TLBRET_RI:
+        /* Read-Inhibit Exception */
+        cs->exception_index = EXCCODE_PNR;
+        break;
+    case TLBRET_PE:
+        /* Privileged Exception */
+        cs->exception_index = EXCCODE_PPI;
+        break;
+    }
+
+    if (tlb_error == TLBRET_NOMATCH) {
+        env->CSR_TLBRBADV = address;
+        env->CSR_TLBREHI = address & (TARGET_PAGE_MASK << 1);
+    } else {
+        if (!FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) {
+            env->CSR_BADV = address;
+        }
+        env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1);
+   }
+
+}
+
+void loongarch_mmu_init(CPULoongArchState *env)
+{
+    /* Number of MTLB */
+    env->mtlb_size = 64;
+
+    /* Number of STLB */
+    env->stlb_size = 2048;
+
+    /* For 16KB, ps = 14, compare the bit [47:15] */
+    for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+        env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, TLB_MISC, E, 0);
+    }
+}
+
+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+                            MMUAccessType access_type, int mmu_idx,
+                            bool probe, uintptr_t retaddr)
+{
+    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    CPULoongArchState *env = &cpu->env;
+    hwaddr physical;
+    int prot;
+    int ret = TLBRET_BADADDR;
+
+    /* Data access */
+    /* XXX: put correct access by using cpu_restore_state() correctly */
+    ret = get_physical_address(env, &physical, &prot, address,
+                               access_type, mmu_idx);
+
+    if (ret == TLBRET_MATCH) {
+        tlb_set_page(cs, address & TARGET_PAGE_MASK,
+                     physical & TARGET_PAGE_MASK, prot,
+                     mmu_idx, TARGET_PAGE_SIZE);
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx
+                      " prot %d\n", __func__, address, physical, prot);
+        return true;
+    } else {
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s address=%" VADDR_PRIx " ret %d\n", __func__, address,
+                      ret);
+    }
+    if (probe) {
+        return false;
+    } else {
+        raise_mmu_exception(env, address, access_type, ret);
+        do_raise_exception(env, cs->exception_index, retaddr);
+    }
+}
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 07/27] target/loongarch: Add LoongArch CSR instruction
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (5 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 06/27] target/loongarch: Add MMU support for LoongArch CPU Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 08/27] target/loongarch: Add LoongArch IOCSR instruction Xiaojuan Yang
                   ` (20 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This includes:
- CSRRD
- CSRWR
- CSRXCHG

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/cpu.h                       |  88 +++++++++++++
 target/loongarch/csr_helper.c                | 112 +++++++++++++++++
 target/loongarch/disas.c                     |  15 +++
 target/loongarch/helper.h                    |   7 ++
 target/loongarch/insn_trans/trans_core.c.inc | 123 +++++++++++++++++++
 target/loongarch/insns.decode                |  13 ++
 target/loongarch/meson.build                 |   1 +
 target/loongarch/translate.c                 |   5 +
 8 files changed, 364 insertions(+)
 create mode 100644 target/loongarch/csr_helper.c
 create mode 100644 target/loongarch/insn_trans/trans_core.c.inc

diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 6bbd1ab764..307a185a51 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -260,6 +260,94 @@ struct CPULoongArchState {
 #endif
 };
 
+#define CSR_OFF(X)  \
+           [LOONGARCH_CSR_##X] = offsetof(CPULoongArchState, CSR_##X)
+#define CSR_OFF_ARRAY(X, N)  \
+           [LOONGARCH_CSR_##X(N)] = offsetof(CPULoongArchState, CSR_##X[N])
+
+static const int csr_offsets[] = {
+     CSR_OFF(CRMD),
+     CSR_OFF(PRMD),
+     CSR_OFF(EUEN),
+     CSR_OFF(MISC),
+     CSR_OFF(ECFG),
+     CSR_OFF(ESTAT),
+     CSR_OFF(ERA),
+     CSR_OFF(BADV),
+     CSR_OFF(BADI),
+     CSR_OFF(EENTRY),
+     CSR_OFF(TLBIDX),
+     CSR_OFF(TLBEHI),
+     CSR_OFF(TLBELO0),
+     CSR_OFF(TLBELO1),
+     CSR_OFF(ASID),
+     CSR_OFF(PGDL),
+     CSR_OFF(PGDH),
+     CSR_OFF(PGD),
+     CSR_OFF(PWCL),
+     CSR_OFF(PWCH),
+     CSR_OFF(STLBPS),
+     CSR_OFF(RVACFG),
+     CSR_OFF(CPUID),
+     CSR_OFF(PRCFG1),
+     CSR_OFF(PRCFG2),
+     CSR_OFF(PRCFG3),
+     CSR_OFF_ARRAY(SAVE, 0),
+     CSR_OFF_ARRAY(SAVE, 1),
+     CSR_OFF_ARRAY(SAVE, 2),
+     CSR_OFF_ARRAY(SAVE, 3),
+     CSR_OFF_ARRAY(SAVE, 4),
+     CSR_OFF_ARRAY(SAVE, 5),
+     CSR_OFF_ARRAY(SAVE, 6),
+     CSR_OFF_ARRAY(SAVE, 7),
+     CSR_OFF_ARRAY(SAVE, 8),
+     CSR_OFF_ARRAY(SAVE, 9),
+     CSR_OFF_ARRAY(SAVE, 10),
+     CSR_OFF_ARRAY(SAVE, 11),
+     CSR_OFF_ARRAY(SAVE, 12),
+     CSR_OFF_ARRAY(SAVE, 13),
+     CSR_OFF_ARRAY(SAVE, 14),
+     CSR_OFF_ARRAY(SAVE, 15),
+     CSR_OFF(TID),
+     CSR_OFF(TCFG),
+     CSR_OFF(TVAL),
+     CSR_OFF(CNTC),
+     CSR_OFF(TICLR),
+     CSR_OFF(LLBCTL),
+     CSR_OFF(IMPCTL1),
+     CSR_OFF(IMPCTL2),
+     CSR_OFF(TLBRENTRY),
+     CSR_OFF(TLBRBADV),
+     CSR_OFF(TLBRERA),
+     CSR_OFF(TLBRSAVE),
+     CSR_OFF(TLBRELO0),
+     CSR_OFF(TLBRELO1),
+     CSR_OFF(TLBREHI),
+     CSR_OFF(TLBRPRMD),
+     CSR_OFF(MERRCTL),
+     CSR_OFF(MERRINFO1),
+     CSR_OFF(MERRINFO2),
+     CSR_OFF(MERRENTRY),
+     CSR_OFF(MERRERA),
+     CSR_OFF(MERRSAVE),
+     CSR_OFF(CTAG),
+     CSR_OFF_ARRAY(DMW, 0),
+     CSR_OFF_ARRAY(DMW, 1),
+     CSR_OFF_ARRAY(DMW, 2),
+     CSR_OFF_ARRAY(DMW, 3),
+     CSR_OFF(DBG),
+     CSR_OFF(DERA),
+     CSR_OFF(DSAVE),
+};
+
+static inline int cpu_csr_offset(unsigned csr_num)
+{
+    if (csr_num < ARRAY_SIZE(csr_offsets)) {
+        return csr_offsets[csr_num];
+    }
+    return 0;
+}
+
 /**
  * LoongArchCPU:
  * @env: #CPULoongArchState
diff --git a/target/loongarch/csr_helper.c b/target/loongarch/csr_helper.c
new file mode 100644
index 0000000000..19c03295b0
--- /dev/null
+++ b/target/loongarch/csr_helper.c
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch emulation helpers for csr registers
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "internals.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "hw/irq.h"
+#include "cpu-csr.h"
+#include "hw/loongarch/loongarch.h"
+#include "tcg/tcg-ldst.h"
+
+target_ulong helper_csr_rdq(CPULoongArchState *env, uint64_t csr)
+{
+    LoongArchCPU *cpu;
+    int64_t v;
+
+    switch (csr) {
+    case LOONGARCH_CSR_PGD:
+        if (env->CSR_TLBRERA & 0x1) {
+            v = env->CSR_TLBRBADV;
+        } else {
+            v = env->CSR_BADV;
+        }
+
+        if ((v >> 63) & 0x1) {
+            v = env->CSR_PGDH;
+        } else {
+            v = env->CSR_PGDL;
+        }
+        break;
+    case LOONGARCH_CSR_CPUID:
+        v = (env_cpu(env))->cpu_index;
+        break;
+    case LOONGARCH_CSR_TVAL:
+        cpu = LOONGARCH_CPU(env_cpu(env));
+        v = cpu_loongarch_get_stable_timer_ticks(cpu);
+        break;
+    default:
+        break;
+    }
+
+    return v;
+}
+
+target_ulong helper_csr_wrq(CPULoongArchState *env, target_ulong val,
+                            uint64_t csr)
+{
+    LoongArchCPU *cpu;
+    int64_t old_v = -1;
+
+    switch (csr) {
+    case LOONGARCH_CSR_ESTAT:
+        /* Only IS[1:0] can be write */
+        env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, IS, val & 0x3);
+        break;
+    case LOONGARCH_CSR_ASID:
+        old_v = env->CSR_ASID;
+        /* Only ASID filed of CSR_ASID can be write. */
+        env->CSR_ASID = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID,
+                                   val & R_CSR_ASID_ASID_MASK);
+        if (old_v != val) {
+            tlb_flush(env_cpu(env));
+        }
+        break;
+    case LOONGARCH_CSR_TCFG:
+        cpu = LOONGARCH_CPU(env_cpu(env));
+        old_v = env->CSR_TCFG;
+        cpu_loongarch_store_stable_timer_config(cpu, val);
+        break;
+    case LOONGARCH_CSR_TICLR:
+        old_v = 0;
+        env->CSR_ESTAT &= ~(1 << IRQ_TIMER);
+        cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_HARD);
+        break;
+    default:
+        break;
+    }
+
+    return old_v;
+}
+
+target_ulong helper_csr_xchgq(CPULoongArchState *env, target_ulong new_val,
+                              target_ulong mask, uint64_t csr_num)
+{
+    unsigned csr_offset = cpu_csr_offset(csr_num);
+    if (csr_offset == 0) {
+        /* CSR is undefined: read as 0, write ignored. */
+        return 0;
+    }
+
+    uint64_t *csr = (void *)env + csr_offset;
+    uint64_t old_val = *csr;
+
+    new_val = (new_val & mask) | (old_val & ~mask);
+
+    if (csr_num == LOONGARCH_CSR_TCFG) {
+        LoongArchCPU *cpu = LOONGARCH_CPU(env_cpu(env));
+        cpu_loongarch_store_stable_timer_config(cpu, new_val);
+    } else {
+        *csr = new_val;
+    }
+    return old_val;
+}
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 45be34de27..de683bb88b 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -204,6 +204,18 @@ static void output_rr_offs(DisasContext *ctx, arg_rr_offs *a,
     output(ctx, mnemonic, "r%d, r%d, %d", a->rj, a->rd, a->offs);
 }
 
+static void output_r_csr(DisasContext *ctx, arg_r_csr *a,
+                         const char *mnemonic)
+{
+    output(ctx, mnemonic, "r%d, %d", a->rd, a->csr);
+}
+
+static void output_rr_csr(DisasContext *ctx, arg_rr_csr *a,
+                          const char *mnemonic)
+{
+    output(ctx, mnemonic, "r%d, r%d, %d", a->rd, a->rj, a->csr);
+}
+
 #define INSN(insn, type)                                    \
 static bool trans_##insn(DisasContext *ctx, arg_##type * a) \
 {                                                           \
@@ -516,6 +528,9 @@ INSN(blt,          rr_offs)
 INSN(bge,          rr_offs)
 INSN(bltu,         rr_offs)
 INSN(bgeu,         rr_offs)
+INSN(csrrd,        r_csr)
+INSN(csrwr,        r_csr)
+INSN(csrxchg,      rr_csr)
 
 #define output_fcmp(C, PREFIX, SUFFIX)                                         \
 {                                                                              \
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index da1a2bced7..036dbf31f8 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -92,3 +92,10 @@ DEF_HELPER_2(frint_s, i64, env, i64)
 DEF_HELPER_2(frint_d, i64, env, i64)
 
 DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32)
+
+/*Core functions */
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_2(csr_rdq, i64, env, i64)
+DEF_HELPER_3(csr_wrq, i64, env, tl, i64)
+DEF_HELPER_4(csr_xchgq, i64, env, tl, tl, i64)
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/insn_trans/trans_core.c.inc b/target/loongarch/insn_trans/trans_core.c.inc
new file mode 100644
index 0000000000..7d2cfe3534
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_core.c.inc
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch translate functions for system mode
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+/* Privileged instruction translation */
+
+#include "cpu-csr.h"
+
+#ifdef CONFIG_USER_ONLY
+
+#define GEN_FALSE_TRANS(name)   \
+static bool trans_##name(DisasContext *ctx, arg_##name * a)  \
+{   \
+    return false;   \
+}
+
+GEN_FALSE_TRANS(csrrd)
+GEN_FALSE_TRANS(csrwr)
+GEN_FALSE_TRANS(csrxchg)
+
+#else
+
+static bool check_plv(DisasContext *ctx)
+{
+    if (ctx->base.tb->flags == MMU_USER_IDX) {
+        generate_exception(ctx, EXCCODE_IPE);
+        return true;
+    }
+    return false;
+}
+
+static bool ro_csr(int csr_num)
+{
+    /*
+     * For now qemu does not support any features of the MISC
+     * bits yet treat as a RO CSR.
+     */
+    if ((csr_num == LOONGARCH_CSR_BADI) || (csr_num == LOONGARCH_CSR_CPUID) ||
+        (csr_num == LOONGARCH_CSR_PRCFG1) || (csr_num == LOONGARCH_CSR_PRCFG2) ||
+        (csr_num == LOONGARCH_CSR_PRCFG3) || (csr_num == LOONGARCH_CSR_PGD) ||
+        (csr_num == LOONGARCH_CSR_TVAL) || (csr_num == LOONGARCH_CSR_MISC)) {
+        return true;
+    }
+
+    return false;
+}
+
+static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
+{
+    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+
+    unsigned csr_offset = cpu_csr_offset(a->csr);
+    if (csr_offset == 0) {
+        /* CSR is undefined: read as 0 */
+        dest = tcg_constant_tl(0);
+        return true;
+    }
+
+    if ((a->csr == LOONGARCH_CSR_PGD) || (a->csr == LOONGARCH_CSR_CPUID) ||
+        (a->csr == LOONGARCH_CSR_TVAL)) {
+        gen_helper_csr_rdq(dest, cpu_env, tcg_constant_i64(a->csr));
+    } else {
+        tcg_gen_ld_tl(dest, cpu_env, csr_offset);
+    }
+    return true;
+}
+
+static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
+{
+    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+    TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
+
+    if (check_plv(ctx) || ro_csr(a->csr)) {
+        return false;
+    }
+
+    unsigned csr_offset = cpu_csr_offset(a->csr);
+    if (csr_offset == 0) {
+        /* CSR is undefined: write ignored. */
+        return true;
+    }
+
+    if ((a->csr == LOONGARCH_CSR_ASID) || (a->csr == LOONGARCH_CSR_TCFG) ||
+        (a->csr == LOONGARCH_CSR_TICLR) || (a->csr == LOONGARCH_CSR_ESTAT)) {
+        gen_helper_csr_wrq(dest, cpu_env, src1, tcg_constant_i64(a->csr));
+    } else {
+        TCGv temp = tcg_temp_new();
+        tcg_gen_ld_tl(temp, cpu_env, csr_offset);
+        tcg_gen_st_tl(src1, cpu_env, csr_offset);
+        tcg_gen_mov_tl(dest, temp);
+        tcg_temp_free(temp);
+
+        /* Cpu state may be changed, need exit */
+        if ((a->csr == LOONGARCH_CSR_CRMD) || (a->csr == LOONGARCH_CSR_EUEN)) {
+            tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+            ctx->base.is_jmp = DISAS_EXIT;
+        }
+    }
+
+    return true;
+}
+
+static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
+{
+    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+    TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
+    TCGv src2 = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx) || ro_csr(a->csr)) {
+        return false;
+    }
+    gen_helper_csr_xchgq(dest, cpu_env, src1, src2, tcg_constant_i64(a->csr));
+    return true;
+}
+
+#endif
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 3379d22979..647fcb9def 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -45,6 +45,8 @@
 &c_offs       cj offs
 &offs         offs
 &rr_offs      rj rd offs
+&r_csr        rd csr
+&rr_csr       rd rj csr
 
 #
 # Formats
@@ -85,6 +87,8 @@
 @c_offs21      .... .. ................ .. cj:3 .....    &c_offs      offs=%offs21
 @offs26            .... .. ..........................    &offs        offs=%offs26
 @rr_offs16         .... .. ................ rj:5 rd:5    &rr_offs     offs=%offs16
+@r_csr                    .... .... csr:14 ..... rd:5    &r_csr
+@rr_csr                    .... .... csr:14 rj:5 rd:5    &rr_csr
 
 #
 # Fixed point arithmetic operation instruction
@@ -440,3 +444,12 @@ blt             0110 00 ................ ..... .....     @rr_offs16
 bge             0110 01 ................ ..... .....     @rr_offs16
 bltu            0110 10 ................ ..... .....     @rr_offs16
 bgeu            0110 11 ................ ..... .....     @rr_offs16
+
+#
+# Core instructions
+#
+{
+  csrrd             0000 0100 .............. 00000 .....     @r_csr
+  csrwr             0000 0100 .............. 00001 .....     @r_csr
+  csrxchg           0000 0100 .............. ..... .....     @rr_csr
+}
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 935ffe2765..080d6297de 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -19,6 +19,7 @@ loongarch_softmmu_ss.add(files(
   'machine.c',
   'stabletimer.c',
   'tlb_helper.c',
+  'csr_helper.c',
 ))
 
 loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 2710764653..09771ee43f 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -26,6 +26,7 @@ TCGv_i32 cpu_fcsr0;
 TCGv_i64 cpu_fpr[32];
 
 #define DISAS_STOP       DISAS_TARGET_0
+#define DISAS_EXIT       DISAS_TARGET_1
 
 static inline int plus_1(DisasContext *ctx, int x)
 {
@@ -172,6 +173,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext)
 #include "insn_trans/trans_fmov.c.inc"
 #include "insn_trans/trans_fmemory.c.inc"
 #include "insn_trans/trans_branch.c.inc"
+#include "insn_trans/trans_core.c.inc"
 
 static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
 {
@@ -209,6 +211,9 @@ static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
         break;
     case DISAS_NORETURN:
         break;
+    case DISAS_EXIT:
+        tcg_gen_exit_tb(NULL, 0);
+        break;
     default:
         g_assert_not_reached();
     }
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 08/27] target/loongarch: Add LoongArch IOCSR instruction
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (6 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 07/27] target/loongarch: Add LoongArch CSR instruction Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 09/27] target/loongarch: Add TLB instruction support Xiaojuan Yang
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This includes:
- IOCSR{RD/WR}.{B/H/W/D}

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/disas.c                     |   8 ++
 target/loongarch/helper.h                    |   2 +
 target/loongarch/insn_trans/trans_core.c.inc | 103 ++++++++++++++++++
 target/loongarch/insns.decode                |   9 ++
 target/loongarch/iocsr_helper.c              | 109 +++++++++++++++++++
 target/loongarch/meson.build                 |   1 +
 6 files changed, 232 insertions(+)
 create mode 100644 target/loongarch/iocsr_helper.c

diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index de683bb88b..cbb264a318 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -531,6 +531,14 @@ INSN(bgeu,         rr_offs)
 INSN(csrrd,        r_csr)
 INSN(csrwr,        r_csr)
 INSN(csrxchg,      rr_csr)
+INSN(iocsrrd_b,    rr)
+INSN(iocsrrd_h,    rr)
+INSN(iocsrrd_w,    rr)
+INSN(iocsrrd_d,    rr)
+INSN(iocsrwr_b,    rr)
+INSN(iocsrwr_h,    rr)
+INSN(iocsrwr_w,    rr)
+INSN(iocsrwr_d,    rr)
 
 #define output_fcmp(C, PREFIX, SUFFIX)                                         \
 {                                                                              \
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 036dbf31f8..1bcd082858 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -98,4 +98,6 @@ DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32)
 DEF_HELPER_2(csr_rdq, i64, env, i64)
 DEF_HELPER_3(csr_wrq, i64, env, tl, i64)
 DEF_HELPER_4(csr_xchgq, i64, env, tl, tl, i64)
+DEF_HELPER_3(iocsr_read, i64, env, tl, i32)
+DEF_HELPER_4(iocsr_write, void, env, tl, tl, i32)
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/insn_trans/trans_core.c.inc b/target/loongarch/insn_trans/trans_core.c.inc
index 7d2cfe3534..592d2a339e 100644
--- a/target/loongarch/insn_trans/trans_core.c.inc
+++ b/target/loongarch/insn_trans/trans_core.c.inc
@@ -20,6 +20,14 @@ static bool trans_##name(DisasContext *ctx, arg_##name * a)  \
 GEN_FALSE_TRANS(csrrd)
 GEN_FALSE_TRANS(csrwr)
 GEN_FALSE_TRANS(csrxchg)
+GEN_FALSE_TRANS(iocsrrd_b)
+GEN_FALSE_TRANS(iocsrrd_h)
+GEN_FALSE_TRANS(iocsrrd_w)
+GEN_FALSE_TRANS(iocsrrd_d)
+GEN_FALSE_TRANS(iocsrwr_b)
+GEN_FALSE_TRANS(iocsrwr_h)
+GEN_FALSE_TRANS(iocsrwr_w)
+GEN_FALSE_TRANS(iocsrwr_d)
 
 #else
 
@@ -120,4 +128,99 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
     return true;
 }
 
+static bool trans_iocsrrd_b(DisasContext *ctx, arg_iocsrrd_b *a)
+{
+    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+    TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_iocsr_read(dest, cpu_env, src1, tcg_constant_i32(1));
+    return true;
+}
+
+static bool trans_iocsrrd_h(DisasContext *ctx, arg_iocsrrd_h *a)
+{
+    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+    TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_iocsr_read(dest, cpu_env, src1, tcg_constant_i32(2));
+    return true;
+}
+
+static bool trans_iocsrrd_w(DisasContext *ctx, arg_iocsrrd_w *a)
+{
+    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+    TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_iocsr_read(dest, cpu_env, src1, tcg_constant_i32(4));
+    return true;
+}
+
+static bool trans_iocsrrd_d(DisasContext *ctx, arg_iocsrrd_d *a)
+{
+    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+    TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_iocsr_read(dest, cpu_env, src1, tcg_constant_i32(8));
+    return true;
+}
+
+static bool trans_iocsrwr_b(DisasContext *ctx, arg_iocsrwr_b *a)
+{
+    TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
+    TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(1));
+    return true;
+}
+
+static bool trans_iocsrwr_h(DisasContext *ctx, arg_iocsrwr_h *a)
+{
+    TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
+    TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(2));
+    return true;
+}
+
+static bool trans_iocsrwr_w(DisasContext *ctx, arg_iocsrwr_w *a)
+{
+    TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
+    TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(4));
+    return true;
+}
+
+static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a)
+{
+    TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
+    TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(8));
+    return true;
+}
 #endif
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 647fcb9def..9a43f288c3 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -453,3 +453,12 @@ bgeu            0110 11 ................ ..... .....     @rr_offs16
   csrwr             0000 0100 .............. 00001 .....     @r_csr
   csrxchg           0000 0100 .............. ..... .....     @rr_csr
 }
+
+iocsrrd_b        0000 01100100 10000 00000 ..... .....    @rr
+iocsrrd_h        0000 01100100 10000 00001 ..... .....    @rr
+iocsrrd_w        0000 01100100 10000 00010 ..... .....    @rr
+iocsrrd_d        0000 01100100 10000 00011 ..... .....    @rr
+iocsrwr_b        0000 01100100 10000 00100 ..... .....    @rr
+iocsrwr_h        0000 01100100 10000 00101 ..... .....    @rr
+iocsrwr_w        0000 01100100 10000 00110 ..... .....    @rr
+iocsrwr_d        0000 01100100 10000 00111 ..... .....    @rr
diff --git a/target/loongarch/iocsr_helper.c b/target/loongarch/iocsr_helper.c
new file mode 100644
index 0000000000..c7be8cfd7b
--- /dev/null
+++ b/target/loongarch/iocsr_helper.c
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch emulation helpers for iocsr read/write
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "internals.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "hw/irq.h"
+#include "cpu-csr.h"
+#include "hw/loongarch/loongarch.h"
+#include "tcg/tcg-ldst.h"
+
+/*
+ * For per core address 0x10xx(IPI) 0x18xx(EXTIOI)
+ * need extra adjust the iocsr addr.
+ */
+uint64_t helper_iocsr_read(CPULoongArchState *env, target_ulong r_addr,
+                           uint32_t size)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(qdev_get_machine());
+    int cpuid = env_cpu(env)->cpu_index;
+
+    if (((r_addr & 0xff00) == 0x1000) || ((r_addr & 0xff00) == 0x1800)) {
+        r_addr = r_addr + ((target_ulong)(cpuid & 0x3) << 8);
+    }
+
+    if (size == 1) {
+        return address_space_ldub(&lams->address_space_iocsr, r_addr,
+                                  MEMTXATTRS_UNSPECIFIED, NULL);
+    } else if (size == 2) {
+        return address_space_lduw(&lams->address_space_iocsr, r_addr,
+                                  MEMTXATTRS_UNSPECIFIED, NULL);
+    } else if (size == 4) {
+        return address_space_ldl(&lams->address_space_iocsr, r_addr,
+                                 MEMTXATTRS_UNSPECIFIED, NULL);
+    } else if (size == 8) {
+        return address_space_ldq(&lams->address_space_iocsr, r_addr,
+                                 MEMTXATTRS_UNSPECIFIED, NULL);
+    }
+    return 0;
+}
+
+void helper_iocsr_write(CPULoongArchState *env, target_ulong w_addr,
+                        target_ulong val, uint32_t size)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(qdev_get_machine());
+    int cpuid = env_cpu(env)->cpu_index;
+    int mask, i;
+
+    /*
+     * For IPI send, Mail send, ANY send adjust addr and val
+     * according to their real meaning. The iocsr write
+     * will finally lead to the corresponding mmio write
+     * all operations handled there.
+     */
+    if (w_addr == 0x1040) { /* IPI send */
+        cpuid = (val >> 16) & 0x3ff;
+        val = 1UL << (val & 0x1f);
+        w_addr = 0x1008;
+    } else if (w_addr == 0x1048) { /* Mail Send */
+        cpuid = (val >> 16) & 0x3ff;
+        w_addr = 0x1020 + (val & 0x1c);
+        val = val >> 32;
+        mask = (val >> 27) & 0xf;
+        size = 4;
+    } else if (w_addr == 0x1158) { /* ANY send */
+        cpuid = (val >> 16) & 0x3ff;
+        w_addr = val & 0xffff;
+        val = val >> 32;
+        mask = (val >> 27) & 0xf;
+        size = 1;
+
+        for (i = 0; i < 4; i++) {
+            if (!((mask >> i) & 1)) {
+                address_space_stb(&lams->address_space_iocsr, w_addr,
+                                  val, MEMTXATTRS_UNSPECIFIED, NULL);
+            }
+            w_addr = w_addr + 1;
+            val = val >> 8;
+        }
+        return;
+    }
+
+    if (((w_addr & 0xff00) == 0x1000) || ((w_addr & 0xff00) == 0x1800)) {
+        w_addr = w_addr + ((target_ulong)(cpuid & 0x3) << 8);
+    }
+
+    if (size == 1) {
+        address_space_stb(&lams->address_space_iocsr, w_addr,
+                          val, MEMTXATTRS_UNSPECIFIED, NULL);
+    } else if (size == 2) {
+        address_space_stw(&lams->address_space_iocsr, w_addr,
+                          val, MEMTXATTRS_UNSPECIFIED, NULL);
+    } else if (size == 4) {
+        address_space_stl(&lams->address_space_iocsr, w_addr,
+                          val, MEMTXATTRS_UNSPECIFIED, NULL);
+    } else if (size == 8) {
+        address_space_stq(&lams->address_space_iocsr, w_addr,
+                          val, MEMTXATTRS_UNSPECIFIED, NULL);
+    }
+}
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 080d6297de..2b2feb886a 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -20,6 +20,7 @@ loongarch_softmmu_ss.add(files(
   'stabletimer.c',
   'tlb_helper.c',
   'csr_helper.c',
+  'iocsr_helper.c',
 ))
 
 loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 09/27] target/loongarch: Add TLB instruction support
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (7 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 08/27] target/loongarch: Add LoongArch IOCSR instruction Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 10/27] target/loongarch: Add other core instructions support Xiaojuan Yang
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This includes:
- TLBSRCH
- TLBRD
- TLBWR
- TLBFILL
- TLBCLR
- TLBFLUSH
- INVTLB

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/disas.c                     |  17 +
 target/loongarch/helper.h                    |  12 +
 target/loongarch/insn_trans/trans_core.c.inc | 109 ++++++
 target/loongarch/insns.decode                |  11 +
 target/loongarch/tlb_helper.c                | 368 +++++++++++++++++++
 5 files changed, 517 insertions(+)

diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index cbb264a318..483270f331 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -216,6 +216,16 @@ static void output_rr_csr(DisasContext *ctx, arg_rr_csr *a,
     output(ctx, mnemonic, "r%d, r%d, %d", a->rd, a->rj, a->csr);
 }
 
+static void output_empty(DisasContext *ctx, arg_empty *a,
+                         const char *mnemonic)
+{
+}
+
+static void output_i_rr(DisasContext *ctx, arg_i_rr *a, const char *mnemonic)
+{
+    output(ctx, mnemonic, "%d, r%d, r%d", a->imm, a->rj, a->rk);
+}
+
 #define INSN(insn, type)                                    \
 static bool trans_##insn(DisasContext *ctx, arg_##type * a) \
 {                                                           \
@@ -539,6 +549,13 @@ INSN(iocsrwr_b,    rr)
 INSN(iocsrwr_h,    rr)
 INSN(iocsrwr_w,    rr)
 INSN(iocsrwr_d,    rr)
+INSN(tlbsrch,      empty)
+INSN(tlbrd,        empty)
+INSN(tlbwr,        empty)
+INSN(tlbfill,      empty)
+INSN(tlbclr,       empty)
+INSN(tlbflush,     empty)
+INSN(invtlb,       i_rr)
 
 #define output_fcmp(C, PREFIX, SUFFIX)                                         \
 {                                                                              \
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 1bcd082858..97af7ac8aa 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -100,4 +100,16 @@ DEF_HELPER_3(csr_wrq, i64, env, tl, i64)
 DEF_HELPER_4(csr_xchgq, i64, env, tl, tl, i64)
 DEF_HELPER_3(iocsr_read, i64, env, tl, i32)
 DEF_HELPER_4(iocsr_write, void, env, tl, tl, i32)
+
+DEF_HELPER_1(tlbwr, void, env)
+DEF_HELPER_1(tlbfill, void, env)
+DEF_HELPER_1(tlbsrch, void, env)
+DEF_HELPER_1(tlbrd, void, env)
+DEF_HELPER_1(tlbclr, void, env)
+DEF_HELPER_1(tlbflush, void, env)
+DEF_HELPER_1(invtlb_all, void, env)
+DEF_HELPER_2(invtlb_all_g, void, env, i32)
+DEF_HELPER_2(invtlb_all_asid, void, env, tl)
+DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl)
+DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl)
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/insn_trans/trans_core.c.inc b/target/loongarch/insn_trans/trans_core.c.inc
index 592d2a339e..938802b526 100644
--- a/target/loongarch/insn_trans/trans_core.c.inc
+++ b/target/loongarch/insn_trans/trans_core.c.inc
@@ -28,6 +28,13 @@ GEN_FALSE_TRANS(iocsrwr_b)
 GEN_FALSE_TRANS(iocsrwr_h)
 GEN_FALSE_TRANS(iocsrwr_w)
 GEN_FALSE_TRANS(iocsrwr_d)
+GEN_FALSE_TRANS(tlbsrch)
+GEN_FALSE_TRANS(tlbrd)
+GEN_FALSE_TRANS(tlbwr)
+GEN_FALSE_TRANS(tlbfill)
+GEN_FALSE_TRANS(tlbclr)
+GEN_FALSE_TRANS(tlbflush)
+GEN_FALSE_TRANS(invtlb)
 
 #else
 
@@ -223,4 +230,106 @@ static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a)
     gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(8));
     return true;
 }
+
+static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a)
+{
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_tlbsrch(cpu_env);
+    return true;
+}
+
+static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a)
+{
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_tlbrd(cpu_env);
+    return true;
+}
+
+static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
+{
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_tlbwr(cpu_env);
+
+    if (ctx->mem_idx != MMU_DA_IDX) {
+        tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+        ctx->base.is_jmp = DISAS_EXIT;
+    }
+    return true;
+}
+
+static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a)
+{
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_tlbfill(cpu_env);
+    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+    ctx->base.is_jmp = DISAS_EXIT;
+    return true;
+}
+
+static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a)
+{
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_tlbclr(cpu_env);
+    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+    ctx->base.is_jmp = DISAS_EXIT;
+    return true;
+}
+
+static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a)
+{
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_tlbflush(cpu_env);
+    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+    ctx->base.is_jmp = DISAS_EXIT;
+    return true;
+}
+
+static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
+{
+    TCGv rj = gpr_src(ctx, a->rj, EXT_NONE);
+    TCGv rk = gpr_src(ctx, a->rk, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+
+    switch (a->imm) {
+    case 0:
+    case 1:
+        gen_helper_invtlb_all(cpu_env);
+        break;
+    case 2:
+        gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(1));
+        break;
+    case 3:
+        gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(0));
+        break;
+    case 4:
+        gen_helper_invtlb_all_asid(cpu_env, rj);
+        break;
+    case 5:
+        gen_helper_invtlb_page_asid(cpu_env, rj, rk);
+        break;
+    case 6:
+        gen_helper_invtlb_page_asid_or_g(cpu_env, rj, rk);
+        break;
+    default:
+        return false;
+    }
+    ctx->base.is_jmp = DISAS_STOP;
+    return true;
+}
+
 #endif
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 9a43f288c3..6f2a814195 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -47,6 +47,8 @@
 &rr_offs      rj rd offs
 &r_csr        rd csr
 &rr_csr       rd rj csr
+&empty
+&i_rr         imm rj rk
 
 #
 # Formats
@@ -89,6 +91,8 @@
 @rr_offs16         .... .. ................ rj:5 rd:5    &rr_offs     offs=%offs16
 @r_csr                    .... .... csr:14 ..... rd:5    &r_csr
 @rr_csr                    .... .... csr:14 rj:5 rd:5    &rr_csr
+@empty          .... ........ ..... ..... ..... .....    &empty
+@i_rr             ...... ...... ..... rk:5 rj:5 imm:5    &i_rr
 
 #
 # Fixed point arithmetic operation instruction
@@ -462,3 +466,10 @@ iocsrwr_b        0000 01100100 10000 00100 ..... .....    @rr
 iocsrwr_h        0000 01100100 10000 00101 ..... .....    @rr
 iocsrwr_w        0000 01100100 10000 00110 ..... .....    @rr
 iocsrwr_d        0000 01100100 10000 00111 ..... .....    @rr
+tlbsrch          0000 01100100 10000 01010 00000 00000    @empty
+tlbrd            0000 01100100 10000 01011 00000 00000    @empty
+tlbwr            0000 01100100 10000 01100 00000 00000    @empty
+tlbfill          0000 01100100 10000 01101 00000 00000    @empty
+tlbclr           0000 01100100 10000 01000 00000 00000    @empty
+tlbflush         0000 01100100 10000 01001 00000 00000    @empty
+invtlb           0000 01100100 10011 ..... ..... .....    @i_rr
diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c
index e0b1390903..891ea06c8f 100644
--- a/target/loongarch/tlb_helper.c
+++ b/target/loongarch/tlb_helper.c
@@ -7,9 +7,11 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/guest-random.h"
 
 #include "cpu.h"
 #include "internals.h"
+#include "exec/helper-proto.h"
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
 #include "exec/log.h"
@@ -283,6 +285,372 @@ static void raise_mmu_exception(CPULoongArchState *env, target_ulong address,
 
 }
 
+static void cpu_loongarch_tlb_flush(CPULoongArchState *env)
+{
+    /* Flush qemu's TLB and discard all shadowed entries. */
+    tlb_flush(env_cpu(env));
+}
+
+static void loongarch_invalidate_tlb_entry(CPULoongArchState *env,
+                                           int index)
+{
+    target_ulong addr, mask, pagesize;
+    uint8_t tlb_ps;
+    loongarch_tlb *tlb = &env->tlb[index];
+
+    int mmu_idx = cpu_mmu_index(env, false);
+    uint8_t tlb_v0 = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, V);
+    uint8_t tlb_v1 = FIELD_EX64(tlb->tlb_entry1, TLBENTRY, V);
+    uint64_t tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+
+    if (index > env->stlb_size) {
+        tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+    } else {
+        tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+    }
+    pagesize = 1 << tlb_ps;
+    mask = MAKE_64BIT_MASK(0, tlb_ps + 1);
+
+    if (tlb_v0) {
+        addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & ~mask;    /* even */
+        tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize,
+                                  mmu_idx, TARGET_LONG_BITS);
+    }
+
+    if (tlb_v1) {
+        addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & pagesize;    /* odd */
+        tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize,
+                                  mmu_idx, TARGET_LONG_BITS);
+    }
+}
+
+static void loongarch_invalidate_tlb(CPULoongArchState *env, int index)
+{
+    loongarch_tlb *tlb;
+    uint16_t csr_asid, tlb_asid, tlb_g;
+
+    csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+    tlb = &env->tlb[index];
+    tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+    tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+    if (tlb_g == 0 && tlb_asid != csr_asid) {
+        return;
+    }
+    loongarch_invalidate_tlb_entry(env, index);
+}
+
+static void loongarch_fill_tlb_entry(CPULoongArchState *env, int index)
+{
+    loongarch_tlb *tlb = &env->tlb[index];
+    uint64_t lo0, lo1, csr_vppn;
+    uint16_t csr_asid;
+    uint8_t csr_ps;
+
+    if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
+        csr_ps = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS);
+        csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, VPPN);
+        lo0 = env->CSR_TLBRELO0;
+        lo1 = env->CSR_TLBRELO1;
+    } else {
+        csr_ps = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS);
+        csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI, VPPN);
+        lo0 = env->CSR_TLBELO0;
+        lo1 = env->CSR_TLBELO1;
+    }
+
+    if (csr_ps == 0) {
+        qemu_log_mask(CPU_LOG_MMU, "page size is 0\n");
+    }
+
+    /* Only mtlb has the ps fields */
+    if (index > env->stlb_size) {
+        tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, PS, csr_ps);
+    }
+
+    tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, VPPN, csr_vppn);
+    tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1);
+    csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+    tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid);
+
+    tlb->tlb_entry0 = lo0;
+    tlb->tlb_entry1 = lo1;
+}
+
+/* Return random value in [low, high] */
+static uint32_t cpu_loongarch_get_random_loongarch_tlb(uint32_t low,
+                                                       uint32_t high)
+{
+    uint32_t val;
+
+    qemu_guest_getrandom_nofail(&val, sizeof(val));
+    return val % (high - low + 1) + low;
+}
+
+void helper_tlbsrch(CPULoongArchState *env)
+{
+    int index, match;
+
+    match = loongarch_tlb_search(env, env->CSR_TLBEHI, &index);
+    if (match) {
+        env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX, index);
+        env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0);
+        return;
+    }
+
+    env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1);
+}
+
+void helper_tlbrd(CPULoongArchState *env)
+{
+    loongarch_tlb *tlb;
+    int index;
+    uint8_t tlb_ps, tlb_e;
+
+    index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX);
+    tlb = &env->tlb[index];
+
+    if (index > env->stlb_size) {
+        tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+    } else {
+        tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+    }
+    tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
+
+    if (!tlb_e) {
+        /* Invalid TLB entry */
+        env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1);
+        env->CSR_ASID  = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID, 0);
+        env->CSR_TLBEHI = 0;
+        env->CSR_TLBELO0 = 0;
+        env->CSR_TLBELO1 = 0;
+        env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, PS, 0);
+    } else {
+        /* Valid TLB entry */
+        env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0);
+        env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX,
+                                     PS, (tlb_ps & 0x3f));
+        env->CSR_TLBEHI = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN) <<
+                                     R_TLB_MISC_VPPN_SHIFT;
+        env->CSR_TLBELO0 = tlb->tlb_entry0;
+        env->CSR_TLBELO1 = tlb->tlb_entry1;
+    }
+}
+
+void helper_tlbwr(CPULoongArchState *env)
+{
+    int index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX);
+
+    loongarch_invalidate_tlb(env, index);
+
+    if (FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, NE)) {
+        env->tlb[index].tlb_misc = FIELD_DP64(env->tlb[index].tlb_misc,
+                                              TLB_MISC, E, 0);
+        return;
+    }
+
+    loongarch_fill_tlb_entry(env, index);
+}
+
+void helper_tlbfill(CPULoongArchState *env)
+{
+    uint64_t address, entryhi;
+    int index, set, stlb_idx;
+    uint16_t pagesize, stlb_ps;
+
+    if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
+        entryhi = env->CSR_TLBREHI;
+        pagesize = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS);
+    } else {
+        entryhi = env->CSR_TLBEHI;
+        pagesize = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS);
+    }
+
+    uint32_t stlb_size = env->stlb_size;
+    uint32_t mtlb_size = env->mtlb_size;
+
+    stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+
+    if (pagesize == stlb_ps && env->stlb_size) {
+        /* Only write into STLB bit [47:13]*/
+        address = entryhi & ~MAKE_64BIT_MASK(0, R_CSR_TLBEHI_VPPN_SHIFT);
+
+        /* Choose one set ramdomly */
+        set = cpu_loongarch_get_random_loongarch_tlb(0, 7);
+
+        /* Index in one set */
+        stlb_idx = (address >> (stlb_ps + 1)) & 0xff; /* [0,255] */
+
+        index = set * 256 + stlb_idx;
+    } else {
+        /* Only write into MTLB */
+        index = cpu_loongarch_get_random_loongarch_tlb(
+                stlb_size, stlb_size + mtlb_size - 1);
+    }
+
+    loongarch_invalidate_tlb(env, index);
+    loongarch_fill_tlb_entry(env, index);
+}
+
+void helper_tlbclr(CPULoongArchState *env)
+{
+    loongarch_tlb *tlb;
+    int i;
+    uint16_t csr_asid, tlb_asid, tlb_g;
+    int msize, ssize, index;
+
+    csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+    msize = env->mtlb_size;
+    ssize = env->stlb_size;
+    index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX);
+
+    if (index < ssize) {
+        /* STLB. One line per operation */
+        for (i = 0; i < 8; i++) {
+            tlb = &env->tlb[i * 256 + (index % 256)];
+            tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+            tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+            if (!tlb_g && tlb_asid == csr_asid) {
+                tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+            }
+        }
+    } else if (index < (ssize + msize)) {
+        /* MTLB. All entries */
+        for (i = ssize; i < ssize + msize; i++) {
+            tlb = &env->tlb[i];
+            tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+            tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+            if (!tlb_g && tlb_asid == csr_asid) {
+                tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+            }
+        }
+    }
+
+    cpu_loongarch_tlb_flush(env);
+}
+
+void helper_tlbflush(CPULoongArchState *env)
+{
+    int i;
+    int msize, ssize, index;
+
+    msize = env->mtlb_size;
+    ssize = env->stlb_size;
+    index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX);
+
+    if (index < ssize) {
+        /* STLB. One line per operation */
+        for (i = 0; i < 8; i++) {
+            int index = i * 256 + (index % 256);
+            env->tlb[index].tlb_misc = FIELD_DP64(env->tlb[index].tlb_misc,
+                                                 TLB_MISC, E, 0);
+        }
+    } else if (index < (ssize + msize)) {
+        /* MTLB. All entries */
+        for (i = ssize; i < ssize + msize; i++) {
+            env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc,
+                                              TLB_MISC, E, 0);
+        }
+    }
+
+    cpu_loongarch_tlb_flush(env);
+}
+
+void helper_invtlb_all(CPULoongArchState *env)
+{
+    for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+        env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc,
+                                          TLB_MISC, E, 0);
+    }
+    cpu_loongarch_tlb_flush(env);
+}
+
+void helper_invtlb_all_g(CPULoongArchState *env, uint32_t g)
+{
+    for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+        loongarch_tlb *tlb = &env->tlb[i];
+        uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+
+        if (tlb_g == g) {
+            tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+        }
+    }
+    cpu_loongarch_tlb_flush(env);
+}
+
+void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info)
+{
+    uint16_t asid = info & 0x3ff;
+
+    for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+        loongarch_tlb *tlb = &env->tlb[i];
+        uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+        uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+
+        if (!tlb_g && (tlb_asid == asid)) {
+            tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+        }
+    }
+    cpu_loongarch_tlb_flush(env);
+}
+
+void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info,
+                             target_ulong addr)
+{
+    uint16_t asid = info & 0x3ff;
+
+    for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+        loongarch_tlb *tlb = &env->tlb[i];
+        uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+        uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+        uint64_t vpn, tlb_vppn;
+        uint8_t tlb_ps, compare_shift;
+
+        if (i > env->stlb_size) {
+            tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+        } else {
+            tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+        }
+        tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+        vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1);
+        compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
+
+        if (!tlb_g && (tlb_asid == asid) &&
+           (vpn == (tlb_vppn >> compare_shift))) {
+            tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+        }
+    }
+    cpu_loongarch_tlb_flush(env);
+}
+
+void helper_invtlb_page_asid_or_g(CPULoongArchState *env,
+                                  target_ulong info, target_ulong addr)
+{
+    uint16_t asid = info & 0x3ff;
+
+    for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+        loongarch_tlb *tlb = &env->tlb[i];
+        uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+        uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+        uint64_t vpn, tlb_vppn;
+        uint8_t tlb_ps, compare_shift;
+
+        if (i > env->stlb_size) {
+            tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+        } else {
+            tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+        }
+        tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+        vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1);
+        compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
+
+        if ((tlb_g || (tlb_asid == asid)) &&
+            (vpn == (tlb_vppn >> compare_shift))) {
+            tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+        }
+    }
+    cpu_loongarch_tlb_flush(env);
+}
+
 void loongarch_mmu_init(CPULoongArchState *env)
 {
     /* Number of MTLB */
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 10/27] target/loongarch: Add other core instructions support
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (8 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 09/27] target/loongarch: Add TLB instruction support Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 11/27] target/loongarch: Add LoongArch interrupt and exception handle Xiaojuan Yang
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This includes:
-CACOP
-LDDIR
-LDPTE
-ERTN
-DBCL
-IDLE

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/cpu.h                       |  2 +
 target/loongarch/disas.c                     | 17 ++++
 target/loongarch/helper.h                    |  4 +
 target/loongarch/insn_trans/trans_core.c.inc | 74 +++++++++++++++++
 target/loongarch/insns.decode                | 11 +++
 target/loongarch/internals.h                 |  5 ++
 target/loongarch/op_helper.c                 | 48 +++++++++++
 target/loongarch/tlb_helper.c                | 87 ++++++++++++++++++++
 8 files changed, 248 insertions(+)

diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 307a185a51..198d2606c5 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -438,6 +438,8 @@ enum {
     EXCP_LAST = EXCP_FPE,
 };
 
+#define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0
+
 #define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU
 #define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
 #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 483270f331..516866c2d3 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -226,6 +226,17 @@ static void output_i_rr(DisasContext *ctx, arg_i_rr *a, const char *mnemonic)
     output(ctx, mnemonic, "%d, r%d, r%d", a->imm, a->rj, a->rk);
 }
 
+static void output_cop_r_i(DisasContext *ctx, arg_cop_r_i *a,
+                           const char *mnemonic)
+{
+    output(ctx, mnemonic, "%d, r%d, %d", a->cop, a->rj, a->imm);
+}
+
+static void output_j_i(DisasContext *ctx, arg_j_i *a, const char *mnemonic)
+{
+    output(ctx, mnemonic, "r%d, %d", a->rj, a->imm);
+}
+
 #define INSN(insn, type)                                    \
 static bool trans_##insn(DisasContext *ctx, arg_##type * a) \
 {                                                           \
@@ -556,6 +567,12 @@ INSN(tlbfill,      empty)
 INSN(tlbclr,       empty)
 INSN(tlbflush,     empty)
 INSN(invtlb,       i_rr)
+INSN(cacop,        cop_r_i)
+INSN(lddir,        rr_i)
+INSN(ldpte,        j_i)
+INSN(ertn,         empty)
+INSN(idle,         i)
+INSN(dbcl,         i)
 
 #define output_fcmp(C, PREFIX, SUFFIX)                                         \
 {                                                                              \
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 97af7ac8aa..c916f2650b 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -112,4 +112,8 @@ DEF_HELPER_2(invtlb_all_g, void, env, i32)
 DEF_HELPER_2(invtlb_all_asid, void, env, tl)
 DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl)
 DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl)
+DEF_HELPER_4(lddir, tl, env, tl, tl, i32)
+DEF_HELPER_4(ldpte, void, env, tl, tl, i32)
+DEF_HELPER_1(ertn, void, env)
+DEF_HELPER_1(idle, void, env)
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/insn_trans/trans_core.c.inc b/target/loongarch/insn_trans/trans_core.c.inc
index 938802b526..3e627e9fd3 100644
--- a/target/loongarch/insn_trans/trans_core.c.inc
+++ b/target/loongarch/insn_trans/trans_core.c.inc
@@ -35,6 +35,12 @@ GEN_FALSE_TRANS(tlbfill)
 GEN_FALSE_TRANS(tlbclr)
 GEN_FALSE_TRANS(tlbflush)
 GEN_FALSE_TRANS(invtlb)
+GEN_FALSE_TRANS(cacop)
+GEN_FALSE_TRANS(ldpte)
+GEN_FALSE_TRANS(lddir)
+GEN_FALSE_TRANS(ertn)
+GEN_FALSE_TRANS(dbcl)
+GEN_FALSE_TRANS(idle)
 
 #else
 
@@ -332,4 +338,72 @@ static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
     return true;
 }
 
+static bool trans_cacop(DisasContext *ctx, arg_cacop *a)
+{
+    /* Treat the cacop as a nop */
+    if (check_plv(ctx)) {
+        return false;
+    }
+    return true;
+}
+
+static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a)
+{
+    TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
+    TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_ldpte(cpu_env, src1, tcg_constant_tl(a->imm), mem_idx);
+    return true;
+}
+
+static bool trans_lddir(DisasContext *ctx, arg_lddir *a)
+{
+    TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
+    TCGv src = gpr_src(ctx, a->rj, EXT_NONE);
+    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_lddir(dest, cpu_env, src, tcg_constant_tl(a->imm), mem_idx);
+    return true;
+}
+
+static bool trans_ertn(DisasContext *ctx, arg_ertn *a)
+{
+    if (check_plv(ctx)) {
+        return false;
+    }
+    gen_helper_ertn(cpu_env);
+    ctx->base.is_jmp = DISAS_EXIT;
+    return true;
+}
+
+static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a)
+{
+    /*
+     * XXX: not clear which exception should be raised
+     *      when in debug mode...
+     */
+    if (check_plv(ctx)) {
+        return false;
+    }
+    generate_exception(ctx, EXCCODE_DBP);
+    return true;
+}
+
+static bool trans_idle(DisasContext *ctx, arg_idle *a)
+{
+    if (check_plv(ctx)) {
+        return false;
+    }
+
+    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+    gen_helper_idle(cpu_env);
+    ctx->base.is_jmp = DISAS_NORETURN;
+    return true;
+}
 #endif
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 6f2a814195..3fdc6e148c 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -49,6 +49,8 @@
 &rr_csr       rd rj csr
 &empty
 &i_rr         imm rj rk
+&cop_r_i      cop rj imm
+&j_i          rj imm
 
 #
 # Formats
@@ -60,6 +62,7 @@
 @r_i20                          .... ... imm:s20 rd:5    &r_i
 @rr_ui5           .... ........ ..... imm:5 rj:5 rd:5    &rr_i
 @rr_ui6            .... ........ .... imm:6 rj:5 rd:5    &rr_i
+@rr_ui8              .. ........ .... imm:8 rj:5 rd:5    &rr_i
 @rr_i12                 .... ...... imm:s12 rj:5 rd:5    &rr_i
 @rr_ui12                 .... ...... imm:12 rj:5 rd:5    &rr_i
 @rr_i14s2         .... ....  .............. rj:5 rd:5    &rr_i imm=%i14s2
@@ -93,6 +96,8 @@
 @rr_csr                    .... .... csr:14 rj:5 rd:5    &rr_csr
 @empty          .... ........ ..... ..... ..... .....    &empty
 @i_rr             ...... ...... ..... rk:5 rj:5 imm:5    &i_rr
+@cop_r_i              .... ......  imm:s12 rj:5 cop:5    &cop_r_i
+@j_i               .... ........ .. imm:8 rj:5 .....    &j_i
 
 #
 # Fixed point arithmetic operation instruction
@@ -473,3 +478,9 @@ tlbfill          0000 01100100 10000 01101 00000 00000    @empty
 tlbclr           0000 01100100 10000 01000 00000 00000    @empty
 tlbflush         0000 01100100 10000 01001 00000 00000    @empty
 invtlb           0000 01100100 10011 ..... ..... .....    @i_rr
+cacop            0000 011000 ............ ..... .....     @cop_r_i
+lddir            0000 01100100 00 ........ ..... .....    @rr_ui8
+ldpte            0000 01100100 01 ........ ..... 00000    @j_i
+ertn             0000 01100100 10000 01110 00000 00000    @empty
+idle             0000 01100100 10001 ...............      @i15
+dbcl             0000 00000010 10101 ...............      @i15
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index a5b81bdca3..7035cbd7d5 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -16,6 +16,11 @@
 #define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS)
 #define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS)
 
+/* Global bit used for lddir/ldpte */
+#define LOONGARCH_PAGE_HUGE_SHIFT   6
+/* Global bit for huge page */
+#define LOONGARCH_HGLOBAL_SHIFT     12
+
 void loongarch_translate_init(void);
 
 void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
index 48c25e5a9b..ea059bb350 100644
--- a/target/loongarch/op_helper.c
+++ b/target/loongarch/op_helper.c
@@ -91,3 +91,51 @@ target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj)
 {
     return rj > 21 ? 0 : env->cpucfg[rj];
 }
+
+#ifndef CONFIG_USER_ONLY
+void helper_ertn(CPULoongArchState *env)
+{
+    uint64_t csr_pplv, csr_pie;
+    if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
+        csr_pplv = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV);
+        csr_pie = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE);
+
+        /* Clear Refill flag and set pc */
+        env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0);
+        env->pc = env->CSR_TLBRERA;
+        qemu_log_mask(CPU_LOG_INT, "%s: TLBRERA 0x%lx\n",
+                      __func__, env->CSR_TLBRERA);
+    } else {
+        csr_pplv = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PPLV);
+        csr_pie = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PIE);
+
+        /* set pc*/
+        env->pc = env->CSR_ERA;
+        qemu_log_mask(CPU_LOG_INT, "%s: ERA 0x%lx\n", __func__, env->CSR_ERA);
+    }
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, csr_pplv);
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, csr_pie);
+
+    env->lladdr = 1;
+}
+
+void helper_idle(CPULoongArchState *env)
+{
+    CPUState *cs = env_cpu(env);
+
+    cs->halted = 1;
+    cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
+    /*
+     * Last instruction in the block, PC was updated before
+     * - no need to recover PC and icount
+     */
+    do_raise_exception(env, EXCP_HLT, 0);
+}
+
+uint64_t helper_rdtime_d(CPULoongArchState *env)
+{
+     LoongArchCPU *cpu = LOONGARCH_CPU(env_cpu(env));
+     return cpu_loongarch_get_stable_counter(cpu);
+}
+
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c
index 891ea06c8f..5cd0eac962 100644
--- a/target/loongarch/tlb_helper.c
+++ b/target/loongarch/tlb_helper.c
@@ -700,3 +700,90 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
         do_raise_exception(env, cs->exception_index, retaddr);
     }
 }
+
+target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
+                          target_ulong level, uint32_t mem_idx)
+{
+    CPUState *cs = env_cpu(env);
+    target_ulong badvaddr, index, phys, ret;
+    int shift;
+    uint64_t dir1_base, dir1_width;
+    uint64_t dir3_base, dir3_width;
+    bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
+
+    badvaddr = env->CSR_TLBRBADV;
+    base = base & TARGET_PHYS_MASK;
+
+    /* 0:8B, 1:16B, 2:32B, 3:64B */
+    shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
+    shift = (shift + 1) * 3;
+
+    if (huge) {
+        return base;
+    }
+    switch (level) {
+    case 1:
+        dir1_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE);
+        dir1_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH);
+        index = (badvaddr >> dir1_base) & ((1 << dir1_width) - 1);
+        break;
+    case 3:
+        dir3_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE);
+        dir3_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH);
+        index = (badvaddr >> dir3_base) & ((1 << dir3_width) - 1);
+        break;
+    default:
+        do_raise_exception(env, EXCCODE_INE, GETPC());
+        return 0;
+    }
+
+    phys = base | index << shift;
+    ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
+    return ret;
+}
+
+void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
+                  uint32_t mem_idx)
+{
+    CPUState *cs = env_cpu(env);
+    target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv;
+    int shift;
+    bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
+    uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE);
+    uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH);
+
+    base = base & TARGET_PHYS_MASK;
+
+    if (huge) {
+        /* Huge Page. base is paddr */
+        tmp0 = base ^ LOONGARCH_PAGE_HUGE_SHIFT;
+        /* Move Global bit */
+        tmp0 = (tmp0 >> LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT |
+               (tmp0 & (~(1 << R_TLBENTRY_G_SHIFT)));
+        ps = ptbase + ptwidth - 1;
+        if (odd) {
+            tmp0 += (1 << ps);
+        }
+    } else {
+        /* 0:8B, 1:16B, 2:32B, 3:64B */
+        shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
+        shift = (shift + 1) * 3;
+        badv = env->CSR_TLBRBADV;
+
+        ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1);
+        ptindex = ptindex & ~0x1;   /* clear bit 0 */
+        ptoffset0 = ptindex << shift;
+        ptoffset1 = (ptindex + 1) << shift;
+
+        phys = base | (odd ? ptoffset1 : ptoffset0);
+        tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
+        ps = ptbase;
+    }
+
+    if (odd) {
+        env->CSR_TLBRELO1 = tmp0;
+    } else {
+        env->CSR_TLBRELO0 = tmp0;
+    }
+    env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, PS, ps);
+}
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 11/27] target/loongarch: Add LoongArch interrupt and exception handle
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (9 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 10/27] target/loongarch: Add other core instructions support Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 12/27] target/loongarch: Add timer related instructions support Xiaojuan Yang
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

1.This patch Add loongarch interrupt and exception handle.
2.Rename the user excp to the exccode from the csr defintions.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 linux-user/loongarch64/cpu_loop.c             |   8 +-
 target/loongarch/cpu.c                        | 254 +++++++++++++++++-
 target/loongarch/cpu.h                        |  11 -
 target/loongarch/fpu_helper.c                 |   2 +-
 target/loongarch/insn_trans/trans_extra.c.inc |   4 +-
 target/loongarch/translate.c                  |   2 +-
 6 files changed, 256 insertions(+), 25 deletions(-)

diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c
index 289547237f..adf9174467 100644
--- a/linux-user/loongarch64/cpu_loop.c
+++ b/linux-user/loongarch64/cpu_loop.c
@@ -28,7 +28,7 @@ void cpu_loop(CPULoongArchState *env)
         case EXCP_INTERRUPT:
             /* just indicate that signals should be handled asap */
             break;
-        case EXCP_SYSCALL:
+        case EXCCODE_SYS:
             env->pc += 4;
             ret = do_syscall(env, env->gpr[11],
                              env->gpr[4], env->gpr[5],
@@ -48,10 +48,10 @@ void cpu_loop(CPULoongArchState *env)
             }
             env->gpr[4] = ret;
             break;
-        case EXCP_INE:
+        case EXCCODE_INE:
             force_sig_fault(TARGET_SIGILL, 0, env->pc);
             break;
-        case EXCP_FPE:
+        case EXCCODE_FPE:
             si_code = TARGET_FPE_FLTUNK;
             if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) {
                 si_code = TARGET_FPE_FLTINV;
@@ -67,7 +67,7 @@ void cpu_loop(CPULoongArchState *env)
             force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
             break;
         case EXCP_DEBUG:
-        case EXCP_BREAK:
+        case EXCCODE_BRK:
             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
             break;
         case EXCP_ATOMIC:
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 8c7ce993db..e92d17dc14 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -30,11 +30,23 @@ const char * const fregnames[] = {
     "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
 };
 
-static const char * const excp_names[EXCP_LAST + 1] = {
-    [EXCP_SYSCALL] = "Syscall",
-    [EXCP_BREAK] = "Break",
-    [EXCP_INE] = "Instruction Non-existent",
-    [EXCP_FPE] = "Floating Point Exception",
+static const char * const excp_names[] = {
+    [EXCCODE_INT] = "Interrupt",
+    [EXCCODE_PIL] = "TLB load page invalid",
+    [EXCCODE_PIS] = "TLB store page invalid",
+    [EXCCODE_PIF] = "TLB Fetch page invalid",
+    [EXCCODE_PME] = "TLB Page modify",
+    [EXCCODE_PNR] = "TLB read-inhibit",
+    [EXCCODE_PNX] = "TLB execute-inhibit",
+    [EXCCODE_PPI] = "TLB priviledged error",
+    [EXCCODE_ADEF] = "Fetch instruction error",
+    [EXCCODE_ADEM] = "Memory access error",
+    [EXCCODE_SYS] = "Syscall",
+    [EXCCODE_BRK] = "Break",
+    [EXCCODE_INE] = "Instruction Non-existent",
+    [EXCCODE_IPE] = "Instruction priveiledged error",
+    [EXCCODE_FPE] = "Floating Point Exception",
+    [EXCCODE_DBP] = "Debug breakpoint",
 };
 
 const char *loongarch_exception_name(int32_t exception)
@@ -65,6 +77,216 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr value)
     env->pc = value;
 }
 
+#if !defined(CONFIG_USER_ONLY)
+static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env)
+{
+    bool ret = 0;
+
+    ret = (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE) &&
+          !(FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)));
+
+    return ret;
+}
+
+/* Check if there is pending and not masked out interrupt */
+static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env)
+{
+    uint32_t pending;
+    uint32_t status;
+    bool r;
+
+    pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
+    status  = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
+
+    r = (pending & status) != 0;
+    return r;
+}
+
+static inline unsigned int get_vint_size(CPULoongArchState *env)
+{
+    uint64_t vs = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
+    uint64_t size = 0;
+
+    if (vs == 0) {
+        return 0;
+    }
+
+    if (vs < 8) {
+        size = 1 << (vs + 2);
+    }
+
+    if (vs > 8) {
+        qemu_log("%s: unexpected value", __func__);
+        assert(0);
+    }
+
+    return size;
+}
+
+static void loongarch_cpu_do_interrupt(CPUState *cs)
+{
+    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    CPULoongArchState *env = &cpu->env;
+    bool update_badinstr = 1;
+    int cause = -1;
+    const char *name;
+    bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
+
+    if (cs->exception_index != EXCCODE_INT) {
+        if (cs->exception_index < 0 ||
+            cs->exception_index > ARRAY_SIZE(excp_names)) {
+            name = "unknown";
+        } else {
+            name = excp_names[cs->exception_index];
+        }
+
+        qemu_log_mask(CPU_LOG_INT,
+                     "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx
+                     " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__,
+                     env->pc, env->CSR_ERA, env->CSR_TLBRERA, name);
+    }
+
+    switch (cs->exception_index) {
+    case EXCCODE_DBP:
+        env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1);
+        env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC);
+        env->CSR_DERA = env->pc;
+        env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1);
+        env->pc = env->CSR_EENTRY + 0x480;
+        break;
+    case EXCCODE_INT:
+    case EXCCODE_PIF:
+        cause = cs->exception_index;
+        update_badinstr = 0;
+        break;
+    case EXCCODE_ADEM:
+    case EXCCODE_SYS:
+    case EXCCODE_BRK:
+    case EXCCODE_PIL:
+    case EXCCODE_PIS:
+    case EXCCODE_PME:
+    case EXCCODE_PNR:
+    case EXCCODE_PNX:
+    case EXCCODE_PPI:
+    case EXCCODE_INE:
+    case EXCCODE_IPE:
+    case EXCCODE_FPE:
+        cause = cs->exception_index;
+        break;
+    default:
+        qemu_log("Error: exception(%d) '%s' has not been supported\n",
+                 cs->exception_index, excp_names[cs->exception_index]);
+        abort();
+    }
+
+    if (tlbfill) {
+        env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA,
+                                      PC, (env->pc >> 2));
+    } else {
+        env->CSR_ERA = env->pc;
+    }
+
+    if (update_badinstr) {
+        env->CSR_BADI = cpu_ldl_code(env, env->pc);
+    }
+
+    /* Save PLV and IE */
+    if (tlbfill) {
+        env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV,
+                                       FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV));
+        env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE,
+                                       FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE));
+    } else {
+        env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PPLV,
+                                   FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV));
+        env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PIE,
+                                   FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE));
+    }
+
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
+    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
+
+    uint32_t vec_size = get_vint_size(env);
+    env->pc = env->CSR_EENTRY;
+    env->pc += cause * vec_size;
+    if (tlbfill) {
+        /* TLB Refill */
+        env->pc = env->CSR_TLBRENTRY;
+    }
+    if  (cs->exception_index == EXCCODE_INT) {
+        /* Interrupt */
+        uint32_t vector = 0;
+        uint32_t pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
+        pending &= FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
+
+        /* Find the highest-priority interrupt. */
+        while (pending >>= 1) {
+            vector++;
+        }
+        env->pc = env->CSR_EENTRY + (EXCCODE_EXTERNAL_INT + vector) * vec_size;
+        qemu_log_mask(CPU_LOG_INT,
+                      "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx
+                      " cause %d\n" "    A " TARGET_FMT_lx " D "
+                      TARGET_FMT_lx " vector = %d ExC %08lx ExS %08lx\n",
+                      __func__, env->pc, env->CSR_ERA,
+                      cause, env->CSR_BADV, env->CSR_DERA, vector,
+                      env->CSR_ECFG, env->CSR_ESTAT);
+    }
+
+    /* Excode */
+    env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ECODE, cause);
+
+    if (cs->exception_index != EXCCODE_INT) {
+        qemu_log_mask(CPU_LOG_INT,
+                      "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx
+                      " cause %d%s\n, ESTAT " TARGET_FMT_lx
+                      " EXCFG " TARGET_FMT_lx " BADVA " TARGET_FMT_lx
+                      "BADI " TARGET_FMT_lx " SYS_NUM " TARGET_FMT_lu
+                      " cpu %d asid 0x%lx" "\n", __func__, env->pc,
+                      tlbfill ? env->CSR_TLBRERA : env->CSR_ERA,
+                      cause, tlbfill ? "(refill)" : "", env->CSR_ESTAT,
+                      env->CSR_ECFG,
+                      tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV,
+                      env->CSR_BADI, env->gpr[11], cs->cpu_index,
+                      env->CSR_ASID);
+    }
+    cs->exception_index = -1;
+}
+
+static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+                                    vaddr addr, unsigned size,
+                                    MMUAccessType access_type,
+                                    int mmu_idx, MemTxAttrs attrs,
+                                    MemTxResult response, uintptr_t retaddr)
+{
+    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    CPULoongArchState *env = &cpu->env;
+
+    if (access_type == MMU_INST_FETCH) {
+        do_raise_exception(env, EXCCODE_ADEF, retaddr);
+    } else {
+        do_raise_exception(env, EXCCODE_ADEM, retaddr);
+    }
+}
+
+static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+    if (interrupt_request & CPU_INTERRUPT_HARD) {
+        LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+        CPULoongArchState *env = &cpu->env;
+
+        if (cpu_loongarch_hw_interrupts_enabled(env) &&
+            cpu_loongarch_hw_interrupts_pending(env)) {
+            /* Raise it */
+            cs->exception_index = EXCCODE_INT;
+            loongarch_cpu_do_interrupt(cs);
+            return true;
+        }
+    }
+    return false;
+}
+#endif
+
 #ifdef CONFIG_TCG
 static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
                                               const TranslationBlock *tb)
@@ -78,7 +300,20 @@ static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
 
 static bool loongarch_cpu_has_work(CPUState *cs)
 {
+#ifdef CONFIG_USER_ONLY
     return true;
+#else
+    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    CPULoongArchState *env = &cpu->env;
+    bool has_work = false;
+
+    if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
+        cpu_loongarch_hw_interrupts_pending(env)) {
+        has_work = true;
+    }
+
+    return has_work;
+#endif
 }
 
 static void loongarch_3a5000_initfn(Object *obj)
@@ -219,8 +454,11 @@ static void loongarch_cpu_reset(DeviceState *dev)
         env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0);
     }
 
+#ifndef CONFIG_USER_ONLY
+    env->pc = env->CSR_EENTRY;
+#endif
     restore_fp_status(env);
-    cs->exception_index = EXCP_NONE;
+    cs->exception_index = -1;
 }
 
 static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info)
@@ -249,6 +487,7 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
     timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
                   &loongarch_stable_timer_cb, cpu);
     loongarch_mmu_init(env);
+    env->CSR_EENTRY = 0x1C000000;
 #endif
 
     cpu_reset(cs);
@@ -333,6 +572,9 @@ static struct TCGCPUOps loongarch_tcg_ops = {
 
 #if !defined(CONFIG_USER_ONLY)
     .tlb_fill = loongarch_cpu_tlb_fill,
+    .cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
+    .do_interrupt = loongarch_cpu_do_interrupt,
+    .do_transaction_failed = loongarch_cpu_do_transaction_failed,
 #endif /* !CONFIG_USER_ONLY */
 };
 #endif /* CONFIG_TCG */
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 198d2606c5..37cbe8924e 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -427,17 +427,6 @@ typedef LoongArchCPU ArchCPU;
 
 #include "exec/cpu-all.h"
 
-/* Exceptions */
-enum {
-    EXCP_NONE          = -1,
-    EXCP_SYSCALL       = 0,
-    EXCP_BREAK,
-    EXCP_INE,
-    EXCP_FPE,
-
-    EXCP_LAST = EXCP_FPE,
-};
-
 #define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0
 
 #define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU
diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c
index 9f5235c4f8..1baf012ef7 100644
--- a/target/loongarch/fpu_helper.c
+++ b/target/loongarch/fpu_helper.c
@@ -74,7 +74,7 @@ static void update_fcsr0_mask(CPULoongArchState *env, uintptr_t pc, int mask)
     }
 
     if (GET_FP_ENABLES(env->fcsr0) & flags) {
-        do_raise_exception(env, EXCP_FPE, pc);
+        do_raise_exception(env, EXCCODE_FPE, pc);
     } else {
         UPDATE_FP_FLAGS(env->fcsr0, flags);
     }
diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc
index bc622ced23..2ce95d3382 100644
--- a/target/loongarch/insn_trans/trans_extra.c.inc
+++ b/target/loongarch/insn_trans/trans_extra.c.inc
@@ -5,13 +5,13 @@
 
 static bool trans_break(DisasContext *ctx, arg_break *a)
 {
-    generate_exception(ctx, EXCP_BREAK);
+    generate_exception(ctx, EXCCODE_BRK);
     return true;
 }
 
 static bool trans_syscall(DisasContext *ctx, arg_syscall *a)
 {
-    generate_exception(ctx, EXCP_SYSCALL);
+    generate_exception(ctx, EXCCODE_SYS);
     return true;
 }
 
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 09771ee43f..ddb97661fa 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -185,7 +185,7 @@ static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
     if (!decode(ctx, ctx->opcode)) {
         qemu_log_mask(LOG_UNIMP, "Error: unkown opcode. 0x%lx: 0x%x\n",
                       ctx->base.pc_next, ctx->opcode);
-        generate_exception(ctx, EXCP_INE);
+        generate_exception(ctx, EXCCODE_INE);
     }
 
     for (int i = ctx->ntemp - 1; i >= 0; --i) {
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 12/27] target/loongarch: Add timer related instructions support.
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (10 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 11/27] target/loongarch: Add LoongArch interrupt and exception handle Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 13/27] target/loongarch: Add gdb support Xiaojuan Yang
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This includes:
-RDTIME{L/H}.W
-RDTIME.D

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/helper.h                     |  1 +
 target/loongarch/insn_trans/trans_extra.c.inc | 32 +++++++++++++++++++
 target/loongarch/translate.c                  |  2 ++
 3 files changed, 35 insertions(+)

diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index c916f2650b..035bd141ed 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -116,4 +116,5 @@ DEF_HELPER_4(lddir, tl, env, tl, tl, i32)
 DEF_HELPER_4(ldpte, void, env, tl, tl, i32)
 DEF_HELPER_1(ertn, void, env)
 DEF_HELPER_1(idle, void, env)
+DEF_HELPER_1(rdtime_d, i64, env)
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc
index 2ce95d3382..8d3425ba61 100644
--- a/target/loongarch/insn_trans/trans_extra.c.inc
+++ b/target/loongarch/insn_trans/trans_extra.c.inc
@@ -33,22 +33,54 @@ static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a)
     return true;
 }
 
+#ifndef CONFIG_USER_ONLY
+static bool gen_rdtime(DisasContext *ctx, arg_rr *a,
+                       bool word, bool high)
+{
+    TCGv dst1 = gpr_dst(ctx, a->rd, EXT_NONE);
+    TCGv dst2 = gpr_dst(ctx, a->rj, EXT_NONE);
+
+    if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+        gen_io_start();
+    }
+    gen_helper_rdtime_d(dst1, cpu_env);
+    if (word) {
+        tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32);
+    }
+    tcg_gen_ld_i64(dst2, cpu_env, offsetof(CPULoongArchState, CSR_TID));
+
+    return true;
+}
+#endif
+
 static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a)
 {
+#ifdef CONFIG_USER_ONLY
     tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
     return true;
+#else
+    return gen_rdtime(ctx, a, 1, 0);
+#endif
 }
 
 static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a)
 {
+#ifdef CONFIG_USER_ONLY
     tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
     return true;
+#else
+    return gen_rdtime(ctx, a, 1, 1);
+#endif
 }
 
 static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a)
 {
+#ifdef CONFIG_USER_ONLY
     tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
     return true;
+#else
+    return gen_rdtime(ctx, a, 0, 0);
+#endif
 }
 
 static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a)
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index ddb97661fa..53a5ef3aa9 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -25,6 +25,8 @@ static TCGv cpu_lladdr, cpu_llval;
 TCGv_i32 cpu_fcsr0;
 TCGv_i64 cpu_fpr[32];
 
+#include "exec/gen-icount.h"
+
 #define DISAS_STOP       DISAS_TARGET_0
 #define DISAS_EXIT       DISAS_TARGET_1
 
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 13/27] target/loongarch: Add gdb support.
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (11 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 12/27] target/loongarch: Add timer related instructions support Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 14/27] hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson3 Platform Xiaojuan Yang
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 configs/targets/loongarch64-softmmu.mak |  1 +
 gdb-xml/loongarch-base64.xml            | 43 +++++++++++
 gdb-xml/loongarch-fpu64.xml             | 57 +++++++++++++++
 target/loongarch/cpu.c                  |  7 ++
 target/loongarch/gdbstub.c              | 97 +++++++++++++++++++++++++
 target/loongarch/internals.h            | 10 +++
 target/loongarch/meson.build            |  1 +
 7 files changed, 216 insertions(+)
 create mode 100644 configs/targets/loongarch64-softmmu.mak
 create mode 100644 gdb-xml/loongarch-base64.xml
 create mode 100644 gdb-xml/loongarch-fpu64.xml
 create mode 100644 target/loongarch/gdbstub.c

diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak
new file mode 100644
index 0000000000..f33fa1590b
--- /dev/null
+++ b/configs/targets/loongarch64-softmmu.mak
@@ -0,0 +1 @@
+TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml
diff --git a/gdb-xml/loongarch-base64.xml b/gdb-xml/loongarch-base64.xml
new file mode 100644
index 0000000000..f2af2a4b6e
--- /dev/null
+++ b/gdb-xml/loongarch-base64.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2021 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.loongarch.base">
+  <reg name="r0" bitsize="64" type="uint64" group="general"/>
+  <reg name="r1" bitsize="64" type="uint64" group="general"/>
+  <reg name="r2" bitsize="64" type="uint64" group="general"/>
+  <reg name="r3" bitsize="64" type="uint64" group="general"/>
+  <reg name="r4" bitsize="64" type="uint64" group="general"/>
+  <reg name="r5" bitsize="64" type="uint64" group="general"/>
+  <reg name="r6" bitsize="64" type="uint64" group="general"/>
+  <reg name="r7" bitsize="64" type="uint64" group="general"/>
+  <reg name="r8" bitsize="64" type="uint64" group="general"/>
+  <reg name="r9" bitsize="64" type="uint64" group="general"/>
+  <reg name="r10" bitsize="64" type="uint64" group="general"/>
+  <reg name="r11" bitsize="64" type="uint64" group="general"/>
+  <reg name="r12" bitsize="64" type="uint64" group="general"/>
+  <reg name="r13" bitsize="64" type="uint64" group="general"/>
+  <reg name="r14" bitsize="64" type="uint64" group="general"/>
+  <reg name="r15" bitsize="64" type="uint64" group="general"/>
+  <reg name="r16" bitsize="64" type="uint64" group="general"/>
+  <reg name="r17" bitsize="64" type="uint64" group="general"/>
+  <reg name="r18" bitsize="64" type="uint64" group="general"/>
+  <reg name="r19" bitsize="64" type="uint64" group="general"/>
+  <reg name="r20" bitsize="64" type="uint64" group="general"/>
+  <reg name="r21" bitsize="64" type="uint64" group="general"/>
+  <reg name="r22" bitsize="64" type="uint64" group="general"/>
+  <reg name="r23" bitsize="64" type="uint64" group="general"/>
+  <reg name="r24" bitsize="64" type="uint64" group="general"/>
+  <reg name="r25" bitsize="64" type="uint64" group="general"/>
+  <reg name="r26" bitsize="64" type="uint64" group="general"/>
+  <reg name="r27" bitsize="64" type="uint64" group="general"/>
+  <reg name="r28" bitsize="64" type="uint64" group="general"/>
+  <reg name="r29" bitsize="64" type="uint64" group="general"/>
+  <reg name="r30" bitsize="64" type="uint64" group="general"/>
+  <reg name="r31" bitsize="64" type="uint64" group="general"/>
+  <reg name="pc" bitsize="64" type="code_ptr" group="general"/>
+</feature>
diff --git a/gdb-xml/loongarch-fpu64.xml b/gdb-xml/loongarch-fpu64.xml
new file mode 100644
index 0000000000..e52cf89fbc
--- /dev/null
+++ b/gdb-xml/loongarch-fpu64.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2021 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.loongarch.fpu">
+
+  <union id="fpu64type">
+    <field name="f" type="ieee_single"/>
+    <field name="d" type="ieee_double"/>
+  </union>
+
+  <reg name="f0" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f1" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f2" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f3" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f4" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f5" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f6" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f7" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f8" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f9" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f10" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f11" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f12" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f13" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f14" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f15" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f16" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f17" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f18" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f19" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f20" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f21" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f22" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f23" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f24" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f25" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f26" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f27" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f28" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f29" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f30" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="f31" bitsize="64" type="fpu64type" group="float"/>
+  <reg name="fcc0" bitsize="8" type="uint8" group="float"/>
+  <reg name="fcc1" bitsize="8" type="uint8" group="float"/>
+  <reg name="fcc2" bitsize="8" type="uint8" group="float"/>
+  <reg name="fcc3" bitsize="8" type="uint8" group="float"/>
+  <reg name="fcc4" bitsize="8" type="uint8" group="float"/>
+  <reg name="fcc5" bitsize="8" type="uint8" group="float"/>
+  <reg name="fcc6" bitsize="8" type="uint8" group="float"/>
+  <reg name="fcc7" bitsize="8" type="uint8" group="float"/>
+  <reg name="fcsr" bitsize="32" type="uint32" group="float"/>
+</feature>
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index e92d17dc14..6d3839ea10 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -145,11 +145,18 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
                      " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__,
                      env->pc, env->CSR_ERA, env->CSR_TLBRERA, name);
     }
+    if (cs->exception_index == EXCCODE_INT &&
+       (FIELD_EX64(env->CSR_DBG, CSR_DBG, DST))) {
+        env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DEI, 1);
+        goto set_DERA;
+    }
 
     switch (cs->exception_index) {
     case EXCCODE_DBP:
         env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1);
         env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC);
+        goto set_DERA;
+    set_DERA:
         env->CSR_DERA = env->pc;
         env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1);
         env->pc = env->CSR_EENTRY + 0x480;
diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c
new file mode 100644
index 0000000000..2fec9364de
--- /dev/null
+++ b/target/loongarch/gdbstub.c
@@ -0,0 +1,97 @@
+/*
+ * LOONGARCH gdb server stub
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "internals.h"
+#include "exec/gdbstub.h"
+#include "exec/helper-proto.h"
+
+int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
+{
+    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    CPULoongArchState *env = &cpu->env;
+
+    if (0 <= n && n < 32) {
+        return gdb_get_regl(mem_buf, env->gpr[n]);
+    } else if (n == 32) {
+        return gdb_get_regl(mem_buf, env->pc);
+    }
+    return 0;
+}
+
+int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    CPULoongArchState *env = &cpu->env;
+    target_ulong tmp = ldtul_p(mem_buf);
+
+    if (0 <= n && n < 32) {
+        return env->gpr[n] = tmp, sizeof(target_ulong);
+    } else if (n == 32) {
+        return env->pc = tmp, sizeof(target_ulong);
+    }
+    return 0;
+}
+
+static int loongarch_gdb_get_fpu(CPULoongArchState *env,
+                                 GByteArray *mem_buf, int n)
+{
+    if (0 <= n && n < 32) {
+        return gdb_get_reg64(mem_buf, env->fpr[n]);
+    } else if (32 <= n && n < 40) {
+        return gdb_get_reg8(mem_buf, env->cf[n - 32]);
+    } else if (n == 40) {
+        return gdb_get_reg32(mem_buf, env->fcsr0);
+    }
+    return 0;
+}
+
+static int loongarch_gdb_set_fpu(CPULoongArchState *env,
+                                 uint8_t *mem_buf, int n)
+{
+    if (0 <= n && n < 32) {
+        return env->fpr[n] = ldq_p(mem_buf), 8;
+    } else if (32 <= n && n < 40) {
+        return env->cf[n - 32] = ldub_p(mem_buf), 1;
+    } else if (n == 40) {
+        return env->fcsr0 = ldl_p(mem_buf), 4;
+    }
+    return 0;
+}
+
+void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs)
+{
+    gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu,
+                             41, "loongarch-fpu64.xml", 0);
+}
+
+int loongarch_read_qxfer(CPUState *cs, const char *annex, uint8_t *read_buf,
+                         unsigned long offset, unsigned long len)
+{
+    if (strncmp(annex, "cpucfg", sizeof("cpucfg") - 1) == 0) {
+        if (offset % 4 != 0 || len % 4 != 0) {
+            return 0;
+        }
+
+        size_t i;
+        for (i = offset; i < offset + len; i += 4)
+            ((uint32_t *)read_buf)[(i - offset) / 4] =
+                helper_cpucfg(&(LOONGARCH_CPU(cs)->env), i / 4);
+        return 32 * 4;
+    }
+    return 0;
+}
+
+int loongarch_write_qxfer(CPUState *cs, const char *annex,
+                          const uint8_t *write_buf, unsigned long offset,
+                          unsigned long len)
+{
+    return 0;
+}
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 7035cbd7d5..dbeac6900d 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -43,5 +43,15 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
 void loongarch_mmu_init(CPULoongArchState *env);
 hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 #endif
+int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
+int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
+int loongarch_read_qxfer(CPUState *cs, const char *annex,
+                         uint8_t *read_buf,
+                         unsigned long offset, unsigned long len);
+int loongarch_write_qxfer(CPUState *cs, const char *annex,
+                          const uint8_t *write_buf,
+                          unsigned long offset, unsigned long len);
+
+void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs);
 
 #endif
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 2b2feb886a..49b7951e2e 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -11,6 +11,7 @@ loongarch_tcg_ss.add(files(
   'fpu_helper.c',
   'op_helper.c',
   'translate.c',
+  'gdbstub.c',
 ))
 loongarch_tcg_ss.add(zlib)
 
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 14/27] hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson3 Platform
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (12 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 13/27] target/loongarch: Add gdb support Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-17 23:39   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 15/27] hw/loongarch: Add support loongson3-ls7a machine type Xiaojuan Yang
                   ` (13 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This is a model of the PCIe Host Bridge found on a Loongson-5000
processor. It includes a interrupt controller, some interface for
pci and nonpci devices. Mainly emulate part of it that is not
exactly the same as the host and only use part devices for
tcg mode. It support for MSI and MSIX interrupt sources.

For more detailed info about ls7a1000 you can see the doc at
https://github.com/loongson/LoongArch-Documentation/releases/latest/
download/Loongson-7A1000-usermanual-2.00-EN.pdf

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/pci-host/Kconfig        |   4 +
 hw/pci-host/ls7a.c         | 174 +++++++++++++++++++++++++++++++++++++
 hw/pci-host/meson.build    |   1 +
 include/hw/pci-host/ls7a.h |  51 +++++++++++
 4 files changed, 230 insertions(+)
 create mode 100644 hw/pci-host/ls7a.c
 create mode 100644 include/hw/pci-host/ls7a.h

diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
index 2b5f7d58cc..b02a9d1454 100644
--- a/hw/pci-host/Kconfig
+++ b/hw/pci-host/Kconfig
@@ -77,3 +77,7 @@ config MV64361
     bool
     select PCI
     select I8259
+
+config PCI_EXPRESS_7A
+    bool
+    select PCI_EXPRESS
diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
new file mode 100644
index 0000000000..a783fb2eda
--- /dev/null
+++ b/hw/pci-host/ls7a.c
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Loongson 7A1000 North Bridge Emulation
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie_host.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
+#include "hw/irq.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_bus.h"
+#include "sysemu/reset.h"
+#include "hw/pci-host/ls7a.h"
+#include "migration/vmstate.h"
+
+static const VMStateDescription vmstate_ls7a_pcie = {
+    .name = "LS7A_PCIE",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(parent_obj, LS7APCIState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pci_ls7a_config_write(void *opaque, hwaddr addr,
+                                  uint64_t val, unsigned size)
+{
+    pci_data_write(opaque, addr, val, size);
+}
+
+static uint64_t pci_ls7a_config_read(void *opaque,
+                                     hwaddr addr, unsigned size)
+{
+    uint64_t val;
+
+    val = pci_data_read(opaque, addr, size);
+
+    return val;
+}
+
+static const MemoryRegionOps pci_ls7a_config_ops = {
+    .read = pci_ls7a_config_read,
+    .write = pci_ls7a_config_write,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
+{
+    PCIHostState *pci = PCI_HOST_BRIDGE(dev);
+    LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
+    PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
+
+    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
+                                     get_system_memory(), get_system_io(),
+                                     PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
+
+    memory_region_init_io(&s->pci_conf, OBJECT(dev),
+                          &pci_ls7a_config_ops, pci->bus,
+                          "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
+    memory_region_add_subregion(get_system_memory(), HT1LO_PCICFG_BASE,
+                                &s->pci_conf);
+
+    /* Add ls7a pci-io */
+    memory_region_init_alias(&s->pci_io, OBJECT(dev), "ls7a-pci-io",
+                             get_system_io(), 0, LS7A_PCI_IO_SIZE);
+    memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE,
+                                &s->pci_io);
+
+    pcie_host_mmcfg_update(pex, true, LS_PCIECFG_BASE, LS_PCIECFG_SIZE);
+    qdev_realize(DEVICE(&s->pci_dev), BUS(pci->bus), &error_fatal);
+}
+
+static void ls7a_pcie_realize(PCIDevice *d, Error **errp)
+{
+    /* pci status */
+    d->config[0x6] = 0x01;
+    /* base class code */
+    d->config[0xb] = 0x06;
+    /* header type */
+    d->config[0xe] = 0x80;
+    /* capabilities pointer */
+    d->config[0x34] = 0x40;
+    /* link status and control register 0 */
+    d->config[0x44] = 0x20;
+}
+
+static void ls7a_pcie_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+    dc->desc = "LS7A1000 PCIE Host bridge";
+    dc->vmsd = &vmstate_ls7a_pcie;
+    k->realize = ls7a_pcie_realize;
+    k->vendor_id = 0x0014;
+    k->device_id = 0x7a00;
+    k->revision = 0x0;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    /*
+     * PCI-facing part of the host bridge, not usable without the
+     * host-facing part, which can't be device_add'ed, yet.
+     */
+    dc->user_creatable = false;
+}
+
+static const TypeInfo ls7a_pcie_device_info = {
+    .name          = TYPE_LS7A_PCIE,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(LS7APCIState),
+    .class_init    = ls7a_pcie_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void ls7a_pciehost_initfn(Object *obj)
+{
+    LS7APCIEHost *s = LS7A_HOST_DEVICE(obj);
+    LS7APCIState *ls7a_pci = &s->pci_dev;
+
+    object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
+    qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
+    qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
+}
+
+static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
+                                          PCIBus *rootbus)
+{
+    return "0000:00";
+}
+
+static void ls7a_pciehost_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
+
+    hc->root_bus_path = ls7a_pciehost_root_bus_path;
+    dc->realize = ls7a_pciehost_realize;
+    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+    dc->fw_name = "pci";
+    dc->user_creatable = false;
+}
+
+static const TypeInfo ls7a_pciehost_info = {
+    .name          = TYPE_LS7A_HOST_DEVICE,
+    .parent        = TYPE_PCIE_HOST_BRIDGE,
+    .instance_size = sizeof(LS7APCIEHost),
+    .instance_init = ls7a_pciehost_initfn,
+    .class_init    = ls7a_pciehost_class_init,
+};
+
+static void ls7a_register_types(void)
+{
+    type_register_static(&ls7a_pciehost_info);
+    type_register_static(&ls7a_pcie_device_info);
+}
+
+type_init(ls7a_register_types)
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
index 4c4f39c15c..c4955455fd 100644
--- a/hw/pci-host/meson.build
+++ b/hw/pci-host/meson.build
@@ -11,6 +11,7 @@ pci_ss.add(when: 'CONFIG_PCI_SABRE', if_true: files('sabre.c'))
 pci_ss.add(when: 'CONFIG_XEN_IGD_PASSTHROUGH', if_true: files('xen_igd_pt.c'))
 pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c'))
 pci_ss.add(when: 'CONFIG_SH_PCI', if_true: files('sh_pci.c'))
+pci_ss.add(when: 'CONFIG_PCI_EXPRESS_7A', if_true: files('ls7a.c'))
 
 # PPC devices
 pci_ss.add(when: 'CONFIG_RAVEN_PCI', if_true: files('raven.c'))
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
new file mode 100644
index 0000000000..32d6f045dc
--- /dev/null
+++ b/include/hw/pci-host/ls7a.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch CPU
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LS7A_H
+#define HW_LS7A_H
+
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie_host.h"
+#include "hw/pci-host/pam.h"
+#include "qemu/units.h"
+#include "qemu/range.h"
+#include "qom/object.h"
+
+#define HT1LO_PCICFG_BASE        0x1a000000
+#define HT1LO_PCICFG_SIZE        0x02000000
+
+#define LS_PCIECFG_BASE          0x20000000
+#define LS_PCIECFG_SIZE          0x08000000
+
+#define LS7A_PCI_IO_BASE         0x18000000UL
+#define LS7A_PCI_IO_SIZE         0x00010000
+
+struct LS7APCIState {
+    /*< private >*/
+    PCIDevice parent_obj;
+    /*< public >*/
+};
+
+typedef struct LS7APCIState LS7APCIState;
+typedef struct LS7APCIEHost {
+    /*< private >*/
+    PCIExpressHost parent_obj;
+    /*< public >*/
+
+    LS7APCIState pci_dev;
+
+    MemoryRegion pci_conf;
+    MemoryRegion pci_io;
+} LS7APCIEHost;
+
+#define TYPE_LS7A_HOST_DEVICE "ls7a1000-pciehost"
+OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIEHost, LS7A_HOST_DEVICE)
+
+#define TYPE_LS7A_PCIE "ls7a1000_pcie"
+OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIState, LS7A_PCIE)
+
+#endif /* HW_LS7A_H */
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 15/27] hw/loongarch: Add support loongson3-ls7a machine type.
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (13 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 14/27] hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson3 Platform Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-06  4:36   ` chen huacai
  2021-12-17 23:48   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 16/27] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC) Xiaojuan Yang
                   ` (12 subsequent siblings)
  27 siblings, 2 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

Emulate a 3A5000 board use the new loongarch instruction.
3A5000 belongs to the Loongson3 series processors.
The board consists of a 3A5000 cpu model and the 7A1000
bridge. The host 3A5000 board is really complicated and
contains many functions.Now for the tcg softmmu mode
only part functions are emulated.

More detailed info you can see
https://github.com/loongson/LoongArch-Documentation

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 .../devices/loongarch64-softmmu/default.mak   |   3 +
 configs/targets/loongarch64-softmmu.mak       |   3 +
 hw/Kconfig                                    |   1 +
 hw/loongarch/Kconfig                          |   3 +
 hw/loongarch/loongson3.c                      | 160 ++++++++++++++++++
 hw/loongarch/meson.build                      |   4 +
 hw/meson.build                                |   1 +
 include/exec/poison.h                         |   2 +
 include/hw/loongarch/loongarch.h              |  48 ++++++
 include/sysemu/arch_init.h                    |   1 +
 qapi/machine.json                             |   2 +-
 target/Kconfig                                |   1 +
 target/loongarch/Kconfig                      |   2 +
 target/loongarch/cpu.c                        |   8 +
 target/loongarch/cpu.h                        |   4 +
 15 files changed, 242 insertions(+), 1 deletion(-)
 create mode 100644 configs/devices/loongarch64-softmmu/default.mak
 create mode 100644 hw/loongarch/Kconfig
 create mode 100644 hw/loongarch/loongson3.c
 create mode 100644 hw/loongarch/meson.build
 create mode 100644 include/hw/loongarch/loongarch.h
 create mode 100644 target/loongarch/Kconfig

diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak
new file mode 100644
index 0000000000..973ce4c30a
--- /dev/null
+++ b/configs/devices/loongarch64-softmmu/default.mak
@@ -0,0 +1,3 @@
+# Default configuration for loongarch64-softmmu
+
+CONFIG_LOONGSON3_LS7A=y
diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak
index f33fa1590b..7bc06c850c 100644
--- a/configs/targets/loongarch64-softmmu.mak
+++ b/configs/targets/loongarch64-softmmu.mak
@@ -1 +1,4 @@
+TARGET_ARCH=loongarch64
+TARGET_BASE_ARCH=loongarch
+TARGET_SUPPORTS_MTTCG=y
 TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml
diff --git a/hw/Kconfig b/hw/Kconfig
index ad20cce0a9..f71b2155ed 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -49,6 +49,7 @@ source avr/Kconfig
 source cris/Kconfig
 source hppa/Kconfig
 source i386/Kconfig
+source loongarch/Kconfig
 source m68k/Kconfig
 source microblaze/Kconfig
 source mips/Kconfig
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
new file mode 100644
index 0000000000..ae8498de6a
--- /dev/null
+++ b/hw/loongarch/Kconfig
@@ -0,0 +1,3 @@
+config LOONGSON3_LS7A
+    bool
+    select PCI_EXPRESS_7A
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
new file mode 100644
index 0000000000..28b623e927
--- /dev/null
+++ b/hw/loongarch/loongson3.c
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU loongson 3a5000 develop board emulation
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/units.h"
+#include "qemu/datadir.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+#include "sysemu/runstate.h"
+#include "sysemu/reset.h"
+#include "hw/loongarch/loongarch.h"
+#include "hw/pci-host/ls7a.h"
+
+
+static void loongarch_cpu_reset(void *opaque)
+{
+    LoongArchCPU *cpu = opaque;
+
+    cpu_reset(CPU(cpu));
+}
+
+#define LOONGARCH_SIMPLE_MMIO_OPS(ADDR, NAME, SIZE) \
+({\
+     MemoryRegion *iomem = g_new(MemoryRegion, 1);\
+     memory_region_init_io(iomem, NULL, &loongarch_qemu_ops,\
+                           (void *)ADDR, NAME, SIZE);\
+     memory_region_add_subregion(&lams->system_iocsr, ADDR, iomem);\
+})
+
+static void loongarch_qemu_write(void *opaque, hwaddr addr,
+                                 uint64_t val, unsigned size)
+{
+}
+
+static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
+{
+    uint64_t feature = 0UL;
+    addr = ((hwaddr)(long)opaque) + addr;
+
+    switch (addr) {
+    case FEATURE_REG:
+        feature |= 1UL << IOCSRF_MSI | 1UL << IOCSRF_EXTIOI |
+                   1UL << IOCSRF_CSRIPI;
+        return feature ;
+    case VENDOR_REG:
+        return *(uint64_t *)"Loongson-3A5000";
+    case CPUNAME_REG:
+        return *(uint64_t *)"3A5000";
+    }
+    return 0;
+}
+
+static const MemoryRegionOps loongarch_qemu_ops = {
+    .read = loongarch_qemu_read,
+    .write = loongarch_qemu_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 8,
+    },
+};
+
+static void loongson3_init(MachineState *machine)
+{
+    const char *cpu_model = machine->cpu_type;
+    LoongArchCPU *cpu;
+    ram_addr_t offset = 0;
+    ram_addr_t ram_size = machine->ram_size;
+    uint64_t highram_size = 0;
+    MemoryRegion *address_space_mem = get_system_memory();
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+    int i;
+
+    if (!cpu_model) {
+        cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
+    }
+    if (!strstr(cpu_model, "Loongson-3A5000")) {
+        error_report("LoongArch/TCG needs cpu type Loongson-3A5000");
+        exit(1);
+    }
+
+    memory_region_init_io(&lams->system_iocsr, NULL, NULL,
+                          lams, "iocsr", UINT64_MAX);
+    address_space_init(&lams->address_space_iocsr,
+                       &lams->system_iocsr, "IOCSR");
+
+    /* Init CPUs */
+    for (i = 0; i < machine->smp.cpus; i++) {
+        Object *cpuobj = NULL;
+        CPUState *cs;
+
+        cpuobj = object_new(machine->cpu_type);
+
+        cs = CPU(cpuobj);
+        cs->cpu_index = i;
+
+        qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
+        object_unref(cpuobj);
+
+        cpu = LOONGARCH_CPU(cs);
+        if (cpu == NULL) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        qemu_register_reset(loongarch_cpu_reset, cpu);
+    }
+
+    memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
+                             machine->ram, 0, 256 * MiB);
+    memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
+    offset += 256 * MiB;
+
+    highram_size = ram_size - 256 * MiB;
+    memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
+                             machine->ram, offset, highram_size);
+    memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
+    offset += highram_size;
+
+    LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
+    LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
+    LOONGARCH_SIMPLE_MMIO_OPS(CPUNAME_REG, "loongarch_cpuname", 0x8);
+}
+
+static void loongarch_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "Loongson-3A5000 LS7A1000 machine";
+    mc->init = loongson3_init;
+    mc->default_ram_size = 1 * GiB;
+    mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
+    mc->default_ram_id = "loongarch.ram";
+    mc->max_cpus = LOONGARCH_MAX_VCPUS;
+    mc->is_default = 1;
+    mc->default_kernel_irqchip_split = false;
+    mc->block_default_type = IF_VIRTIO;
+    mc->default_boot_order = "c";
+    mc->no_cdrom = 1;
+}
+
+static const TypeInfo loongarch_machine_types[] = {
+    {
+        .name           = TYPE_LOONGARCH_MACHINE,
+        .parent         = TYPE_MACHINE,
+        .instance_size  = sizeof(LoongArchMachineState),
+        .class_init     = loongarch_class_init,
+    }
+};
+
+DEFINE_TYPES(loongarch_machine_types)
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
new file mode 100644
index 0000000000..1db3529cbc
--- /dev/null
+++ b/hw/loongarch/meson.build
@@ -0,0 +1,4 @@
+loongarch_ss = ss.source_set()
+loongarch_ss.add(when: 'CONFIG_LOONGSON3_LS7A', if_true: files('loongson3.c'))
+
+hw_arch += {'loongarch': loongarch_ss}
diff --git a/hw/meson.build b/hw/meson.build
index b3366c888e..95202649b7 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -49,6 +49,7 @@ subdir('avr')
 subdir('cris')
 subdir('hppa')
 subdir('i386')
+subdir('loongarch')
 subdir('m68k')
 subdir('microblaze')
 subdir('mips')
diff --git a/include/exec/poison.h b/include/exec/poison.h
index 7ad4ad18e8..590bc305c7 100644
--- a/include/exec/poison.h
+++ b/include/exec/poison.h
@@ -14,6 +14,7 @@
 #pragma GCC poison TARGET_CRIS
 #pragma GCC poison TARGET_HEXAGON
 #pragma GCC poison TARGET_HPPA
+#pragma GCC poison TARGET_LOONGARCH64
 #pragma GCC poison TARGET_M68K
 #pragma GCC poison TARGET_MICROBLAZE
 #pragma GCC poison TARGET_MIPS
@@ -73,6 +74,7 @@
 #pragma GCC poison CONFIG_HPPA_DIS
 #pragma GCC poison CONFIG_I386_DIS
 #pragma GCC poison CONFIG_HEXAGON_DIS
+#pragma GCC poison CONFIG_LOONGARCH_DIS
 #pragma GCC poison CONFIG_M68K_DIS
 #pragma GCC poison CONFIG_MICROBLAZE_DIS
 #pragma GCC poison CONFIG_MIPS_DIS
diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
new file mode 100644
index 0000000000..150403c93d
--- /dev/null
+++ b/include/hw/loongarch/loongarch.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Definitions for loongarch board emulation.
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_H
+#define HW_LOONGARCH_H
+
+#include "target/loongarch/cpu.h"
+#include "qemu-common.h"
+#include "hw/boards.h"
+#include "qemu/queue.h"
+
+#define LOONGARCH_MAX_VCPUS     4
+#define PM_MMIO_ADDR            0x10080000UL
+#define PM_MMIO_SIZE            0x100
+#define PM_CNT_MODE             0x10
+#define FEATURE_REG             0x8
+#define IOCSRF_TEMP             0
+#define IOCSRF_NODECNT          1
+#define IOCSRF_MSI              2
+#define IOCSRF_EXTIOI           3
+#define IOCSRF_CSRIPI           4
+#define IOCSRF_FREQCSR          5
+#define IOCSRF_FREQSCALE        6
+#define IOCSRF_DVFSV1           7
+#define IOCSRF_GMOD             9
+#define IOCSRF_VM               11
+
+#define VENDOR_REG              0x10
+#define CPUNAME_REG             0x20
+
+typedef struct LoongArchMachineState {
+    /*< private >*/
+    MachineState parent_obj;
+
+    AddressSpace address_space_iocsr;
+    MemoryRegion system_iocsr;
+    MemoryRegion lowmem;
+    MemoryRegion highmem;
+} LoongArchMachineState;
+
+#define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("loongson3-ls7a")
+DECLARE_INSTANCE_CHECKER(LoongArchMachineState, LOONGARCH_MACHINE,
+                         TYPE_LOONGARCH_MACHINE)
+#endif
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 70c579560a..3ac3634bbb 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -24,6 +24,7 @@ enum {
     QEMU_ARCH_RX = (1 << 20),
     QEMU_ARCH_AVR = (1 << 21),
     QEMU_ARCH_HEXAGON = (1 << 22),
+    QEMU_ARCH_LOONGARCH = (1 << 23),
 };
 
 extern const uint32_t arch_type;
diff --git a/qapi/machine.json b/qapi/machine.json
index 067e3f5378..510ad6e566 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -30,7 +30,7 @@
 ##
 { 'enum' : 'SysEmuTarget',
   'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386',
-             'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
+             'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
              'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc',
              'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
              'sh4eb', 'sparc', 'sparc64', 'tricore',
diff --git a/target/Kconfig b/target/Kconfig
index ae7f24fc66..83da0bd293 100644
--- a/target/Kconfig
+++ b/target/Kconfig
@@ -4,6 +4,7 @@ source avr/Kconfig
 source cris/Kconfig
 source hppa/Kconfig
 source i386/Kconfig
+source loongarch/Kconfig
 source m68k/Kconfig
 source microblaze/Kconfig
 source mips/Kconfig
diff --git a/target/loongarch/Kconfig b/target/loongarch/Kconfig
new file mode 100644
index 0000000000..46b26b1a85
--- /dev/null
+++ b/target/loongarch/Kconfig
@@ -0,0 +1,2 @@
+config LOONGARCH64
+    bool
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 6d3839ea10..62c2a4d813 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -11,6 +11,7 @@
 #include "qemu/module.h"
 #include "sysemu/qtest.h"
 #include "exec/exec-all.h"
+#include "hw/qdev-properties.h"
 #include "qapi/qapi-commands-machine-target.h"
 #include "cpu.h"
 #include "internals.h"
@@ -521,6 +522,12 @@ static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
     return oc;
 }
 
+static Property loongarch_cpu_properties[] = {
+    DEFINE_PROP_INT32("core-id", LoongArchCPU, core_id, -1),
+    DEFINE_PROP_UINT32("id", LoongArchCPU, id, UNASSIGNED_CPU_ID),
+    DEFINE_PROP_END_OF_LIST()
+};
+
 void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 {
     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
@@ -603,6 +610,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
     device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
                                     &lacc->parent_realize);
     device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset);
+    device_class_set_props(dc, loongarch_cpu_properties);
 
     cc->class_by_name = loongarch_cpu_class_by_name;
     cc->has_work = loongarch_cpu_has_work;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 37cbe8924e..01bed0786c 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -16,6 +16,8 @@
 
 #define TCG_GUEST_DEFAULT_MO (0)
 
+#define UNASSIGNED_CPU_ID 0xFFFFFFFF
+
 #define FCSR0_M1    0x1f         /* FCSR1 mask, Enables */
 #define FCSR0_M2    0x1f1f0000   /* FCSR2 mask, Cause and Flags */
 #define FCSR0_M3    0x300        /* FCSR3 mask, Round Mode */
@@ -362,6 +364,8 @@ struct LoongArchCPU {
     CPUNegativeOffsetState neg;
     CPULoongArchState env;
     QEMUTimer timer; /* Internal timer */
+    uint32_t id;
+    int32_t core_id;
 };
 
 #define TYPE_LOONGARCH_CPU "loongarch-cpu"
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 16/27] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC)
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (14 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 15/27] hw/loongarch: Add support loongson3-ls7a machine type Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-17 23:54   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 17/27] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
                   ` (11 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

Loongson-3A5000 support 14 interrupts from 64 - 77(Timer->75 IPI->76)
Loongson-3A5000 and ls7a form a legacy model and extended model irq
hierarchy.Tcg mode emulate a simplified extended model which
has no Legacy I/O Interrupt Controller(LIOINTC) and LPC.
e.g:

 |    +-----+    +---------+     +-------+             |
 |    | IPI |--> | CPUINTC | <-- | Timer |             |
 |    +-----+    +---------+     +-------+             |
 |                    ^                                |
 |                    |                                |
 |               +---------+
 |               | EIOINTC |
 |               +---------+
 |                ^       ^                            |
 |                |       |                            |
 |         +---------+ +---------+                     |
 |         | PCH-PIC | | PCH-MSI |                     |
 |         +---------+ +---------+                     |
 |           ^     ^           ^                       |
 |           |     |           |                       |
 |   +---------+ +---------+ +---------+               |
 |   | UARTs | | Devices | | Devices |                 |
 |   +---------+ +---------+ +---------+               |
 |        ^                                            |

The following series patch will realize the interrupt
controller in this model.

More detailed info can be found at the kernel doc or manual
1.https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/
linux-loongson.git/tree/Documentation/loongarch?h=loongarch-next
2.https://github.com/loongson/LoongArch-Documentation

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 target/loongarch/cpu.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 62c2a4d813..afa550c950 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -504,11 +504,39 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
     lacc->parent_realize(dev, errp);
 }
 
+#ifndef CONFIG_USER_ONLY
+static void loongarch_cpu_set_irq(void *opaque, int irq, int level)
+{
+    LoongArchCPU *cpu = opaque;
+    CPULoongArchState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
+
+    if (irq < 0 || irq > N_IRQS) {
+        return;
+    }
+
+    if (level) {
+        env->CSR_ESTAT |= 1 << irq;
+    } else {
+        env->CSR_ESTAT &= ~(1 << irq);
+    }
+
+    if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+    }
+}
+#endif
+
 static void loongarch_cpu_initfn(Object *obj)
 {
     LoongArchCPU *cpu = LOONGARCH_CPU(obj);
 
     cpu_set_cpustate_pointers(cpu);
+#ifndef CONFIG_USER_ONLY
+    qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
+#endif
 }
 
 static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 17/27] hw/loongarch: Add LoongArch ipi interrupt support(IPI)
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (15 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 16/27] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC) Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-18  0:09   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 18/27] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) Xiaojuan Yang
                   ` (10 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This patch realize the IPI interrupt controller.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/intc/Kconfig                 |   3 +
 hw/intc/loongarch_ipi.c         | 162 ++++++++++++++++++++++++++++++++
 hw/intc/meson.build             |   1 +
 hw/intc/trace-events            |   4 +
 hw/loongarch/Kconfig            |   1 +
 include/hw/intc/loongarch_ipi.h |  45 +++++++++
 target/loongarch/cpu.h          |   1 +
 7 files changed, 217 insertions(+)
 create mode 100644 hw/intc/loongarch_ipi.c
 create mode 100644 include/hw/intc/loongarch_ipi.h

diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 78aed93c45..511dcac537 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -73,3 +73,6 @@ config GOLDFISH_PIC
 
 config M68K_IRQC
     bool
+
+config LOONGARCH_IPI
+    bool
diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
new file mode 100644
index 0000000000..72e434c983
--- /dev/null
+++ b/hw/intc/loongarch_ipi.c
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch ipi interrupt support
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/intc/loongarch_ipi.h"
+#include "hw/irq.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "exec/address-spaces.h"
+#include "hw/loongarch/loongarch.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
+{
+    ipi_core *s = opaque;
+    uint64_t ret = 0;
+
+    addr &= 0xff;
+    switch (addr) {
+    case CORE_STATUS_OFF:
+        ret = s->status;
+        break;
+    case CORE_EN_OFF:
+        ret = s->en;
+        break;
+    case CORE_SET_OFF:
+        ret = 0;
+        break;
+    case CORE_CLEAR_OFF:
+        ret = 0;
+        break;
+    case CORE_BUF_20 ... CORE_BUF_38:
+        if (size == 4) {
+            ret = ldl_p((void *)s->buf + (addr - CORE_BUF_20));
+        } else if (size == 8) {
+            ret = ldq_p((void *)s->buf + (addr - CORE_BUF_20));
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
+        break;
+    }
+
+    trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
+    return ret;
+}
+
+static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
+                                 unsigned size)
+{
+    ipi_core *s = opaque;
+
+    addr &= 0xff;
+    trace_loongarch_ipi_write(size, (uint64_t)addr, val);
+    switch (addr) {
+    case CORE_STATUS_OFF:
+        qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
+        break;
+    case CORE_EN_OFF:
+        s->en = val;
+        break;
+    case CORE_SET_OFF:
+        s->status |= val;
+        if (s->status != 0) {
+            qemu_irq_raise(s->irq);
+        }
+        break;
+    case CORE_CLEAR_OFF:
+        s->status ^= val;
+        if (s->status == 0) {
+            qemu_irq_lower(s->irq);
+        }
+        break;
+    case CORE_BUF_20 ... CORE_BUF_38:
+        if (size == 4) {
+            stl_p((void *)s->buf + (addr - CORE_BUF_20), val);
+        } else if (size == 8) {
+            stq_p((void *)s->buf + (addr - CORE_BUF_20), val);
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps loongarch_ipi_ops = {
+    .read = loongarch_ipi_readl,
+    .write = loongarch_ipi_writel,
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 8,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 8,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void loongarch_ipi_init(Object *obj)
+{
+    loongarch_ipi *s = LOONGARCH_IPI(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    int cpu;
+
+    for (cpu = 0; cpu < MACHINE(qdev_get_machine())->smp.cpus; cpu++) {
+        memory_region_init_io(&s->ipi_mmio[cpu], obj, &loongarch_ipi_ops,
+                              &s->core[cpu], "loongarch_ipi", 0x100);
+        sysbus_init_mmio(sbd, &s->ipi_mmio[cpu]);
+        qdev_init_gpio_out(DEVICE(obj), &s->core[cpu].irq, 1);
+   }
+}
+
+static const VMStateDescription vmstate_ipi_core = {
+    .name = "ipi-single",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(status, ipi_core),
+        VMSTATE_UINT32(en, ipi_core),
+        VMSTATE_UINT32(set, ipi_core),
+        VMSTATE_UINT32(clear, ipi_core),
+        VMSTATE_UINT64_ARRAY(buf, ipi_core, MAX_IPI_MBX_NUM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_loongarch_ipi = {
+    .name = TYPE_LOONGARCH_IPI,
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(core, loongarch_ipi, MAX_IPI_CORE_NUM, 0,
+                             vmstate_ipi_core, ipi_core),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_loongarch_ipi;
+}
+
+static const TypeInfo loongarch_ipi_info = {
+    .name          = TYPE_LOONGARCH_IPI,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(loongarch_ipi),
+    .instance_init = loongarch_ipi_init,
+    .class_init    = loongarch_ipi_class_init,
+};
+
+static void loongarch_ipi_register_types(void)
+{
+    type_register_static(&loongarch_ipi_info);
+}
+
+type_init(loongarch_ipi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index c89d2ca180..51f0c3988a 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -57,3 +57,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
 		if_true: files('spapr_xive_kvm.c'))
 specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
 specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 9aba7e3a7a..124608e51f 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -246,3 +246,7 @@ 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 0x%" 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"
+
+# loongarch_ipi.c
+loongarch_ipi_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
+loongarch_ipi_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index ae8498de6a..1591574397 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -1,3 +1,4 @@
 config LOONGSON3_LS7A
     bool
     select PCI_EXPRESS_7A
+    select LOONGARCH_IPI
diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
new file mode 100644
index 0000000000..d2397e53e7
--- /dev/null
+++ b/include/hw/intc/loongarch_ipi.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch ipi interrupt header files
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_IPI_H
+#define HW_LOONGARCH_IPI_H
+
+/* Mainy used by iocsr read and write */
+#define SMP_IPI_MAILBOX      0x1000ULL
+#define CORE_STATUS_OFF       0x0
+#define CORE_EN_OFF           0x4
+#define CORE_SET_OFF          0x8
+#define CORE_CLEAR_OFF        0xc
+#define CORE_BUF_20           0x20
+#define CORE_BUF_28           0x28
+#define CORE_BUF_30           0x30
+#define CORE_BUF_38           0x38
+
+#define MAX_IPI_CORE_NUM      16
+#define MAX_IPI_MBX_NUM       4
+
+#define TYPE_LOONGARCH_IPI "loongarch_ipi"
+DECLARE_INSTANCE_CHECKER(struct loongarch_ipi, LOONGARCH_IPI,
+                         TYPE_LOONGARCH_IPI)
+
+
+typedef struct ipi_core {
+    uint32_t status;
+    uint32_t en;
+    uint32_t set;
+    uint32_t clear;
+    uint64_t buf[MAX_IPI_MBX_NUM];
+    qemu_irq irq;
+} ipi_core;
+
+typedef struct loongarch_ipi {
+    SysBusDevice parent_obj;
+    ipi_core core[MAX_IPI_CORE_NUM];
+    MemoryRegion ipi_mmio[MAX_IPI_CORE_NUM];
+} loongarch_ipi;
+
+#endif
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 01bed0786c..b287d7fca8 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -153,6 +153,7 @@ extern const char * const fregnames[];
 
 #define N_IRQS      14
 #define IRQ_TIMER   11
+#define IRQ_IPI     12
 
 #define LOONGARCH_TLB_MAX      (2048 + 64) /* 2048 STLB + 64 MTLB */
 
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 18/27] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (16 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 17/27] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-18  0:33   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 19/27] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) Xiaojuan Yang
                   ` (9 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This patch realize the PCH-PIC interrupt controller.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/intc/Kconfig                     |   4 +
 hw/intc/loongarch_pch_pic.c         | 357 ++++++++++++++++++++++++++++
 hw/intc/meson.build                 |   1 +
 hw/intc/trace-events                |   5 +
 hw/loongarch/Kconfig                |   1 +
 include/hw/intc/loongarch_pch_pic.h |  61 +++++
 6 files changed, 429 insertions(+)
 create mode 100644 hw/intc/loongarch_pch_pic.c
 create mode 100644 include/hw/intc/loongarch_pch_pic.h

diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 511dcac537..96da13ad1d 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -76,3 +76,7 @@ config M68K_IRQC
 
 config LOONGARCH_IPI
     bool
+
+config LOONGARCH_PCH_PIC
+    bool
+    select UNIMP
diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
new file mode 100644
index 0000000000..2ede29ceb0
--- /dev/null
+++ b/hw/intc/loongarch_pch_pic.c
@@ -0,0 +1,357 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Loongson 7A1000 I/O interrupt controller.
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/loongarch/loongarch.h"
+#include "hw/irq.h"
+#include "hw/intc/loongarch_pch_pic.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+#define for_each_set_bit(bit, addr, size) \
+         for ((bit) = find_first_bit((addr), (size));            \
+              (bit) < (size);                                    \
+              (bit) = find_next_bit((addr), (size), (bit) + 1))
+
+static void pch_pic_update_irq(loongarch_pch_pic *s, uint64_t mask, int level)
+{
+    int i;
+    uint64_t val;
+    val = mask & s->intirr & (~s->int_mask);
+
+    for_each_set_bit(i, &val, 64) {
+        if (level == 1) {
+            if ((s->intisr & (0x1ULL << i)) == 0) {
+                s->intisr |= 1ULL << i;
+                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 1);
+            }
+        } else if (level == 0) {
+            if (s->intisr & (0x1ULL << i)) {
+                s->intisr &= ~(0x1ULL << i);
+                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 0);
+            }
+        }
+    }
+}
+
+static void pch_pic_irq_handler(void *opaque, int irq, int level)
+{
+    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
+
+    assert(irq < PCH_PIC_IRQ_NUM);
+    uint64_t mask = 1ULL << irq;
+
+    trace_pch_pic_irq_handler(s->intedge, irq, level);
+
+    if (s->intedge & mask) {
+        /* Edge triggered */
+        if (level) {
+            if ((s->last_intirr & mask) == 0) {
+                s->intirr |= mask;
+            }
+            s->last_intirr |= mask;
+        } else {
+            s->last_intirr &= ~mask;
+        }
+    } else {
+        /* Level triggered */
+        if (level) {
+            s->intirr |= mask;
+            s->last_intirr |= mask;
+        } else {
+            s->intirr &= ~mask;
+            s->last_intirr &= ~mask;
+        }
+
+    }
+    pch_pic_update_irq(s, mask, level);
+}
+
+static uint64_t loongarch_pch_pic_reg_read(void *opaque, hwaddr addr,
+                                           unsigned size)
+{
+    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
+    uint64_t val = 0;
+    uint32_t offset = addr & 0xfff;
+    int64_t offset_tmp;
+
+    if (size == 8) {
+        switch (offset) {
+        case PCH_PIC_INT_ID_OFFSET:
+            val = (PCH_PIC_INT_ID_NUM << 32) | PCH_PIC_INT_ID_VAL;
+            break;
+        case PCH_PIC_INT_MASK_OFFSET:
+            val =  s->int_mask;
+            break;
+        case PCH_PIC_INT_STATUS_OFFSET:
+            val = s->intisr & (~s->int_mask);
+            break;
+        case PCH_PIC_INT_EDGE_OFFSET:
+            val = s->intedge;
+            break;
+        case PCH_PIC_INT_POL_OFFSET:
+            val = s->int_polarity;
+            break;
+        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
+            val = s->htmsi_en;
+            break;
+        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
+        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
+            break;
+        default:
+            break;
+        }
+    } else if (size == 4) {
+        switch (offset) {
+        case PCH_PIC_INT_ID_OFFSET:
+            val = PCH_PIC_INT_ID_VAL;
+            break;
+        case PCH_PIC_INT_ID_OFFSET + 4:
+            val = PCH_PIC_INT_ID_NUM;
+            break;
+        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
+            val = ldl_p((void *)&s->int_mask +
+                        (offset - PCH_PIC_INT_MASK_OFFSET));
+            break;
+        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
+            val = ldl_p((void *)&s->intisr +
+                        (offset - PCH_PIC_INT_STATUS_OFFSET)) & (~s->int_mask);
+            break;
+        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
+            val = ldl_p((void *)&s->intedge +
+                        (offset - PCH_PIC_INT_EDGE_OFFSET));
+            break;
+        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
+            val = ldl_p((void *)&s->int_polarity +
+                        (offset - PCH_PIC_INT_POL_OFFSET));
+            break;
+        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
+            val = ldl_p((void *)&s->htmsi_en +
+                        (offset - PCH_PIC_HTMSI_EN_OFFSET));
+            break;
+        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
+        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
+            break;
+        default:
+            break;
+        }
+    } else if (size == 1) {
+        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
+            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
+            if (offset_tmp >= 0 && offset_tmp < 64) {
+                val = s->htmsi_vector[offset_tmp];
+            }
+        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
+            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
+            if (offset_tmp >= 0 && offset_tmp < 64) {
+                val = s->route_entry[offset_tmp];
+            }
+        }
+    }
+
+    trace_loongarch_pch_pic_read(size, (uint32_t)addr, val);
+    return val;
+}
+
+static void loongarch_pch_pic_reg_write(void *opaque, hwaddr addr,
+                                        uint64_t data, unsigned size)
+{
+    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
+    int32_t offset_tmp;
+    uint32_t offset, old;
+    offset = addr & 0xfff;
+
+    trace_loongarch_pch_pic_write(size, (uint32_t)addr, data);
+
+    if (size == 8) {
+        switch (offset) {
+        case PCH_PIC_INT_MASK_OFFSET:
+            old = s->int_mask;
+            s->int_mask = data;
+            if (old & ~data) {
+                pch_pic_update_irq(s, (old & ~data), 1);
+            } else if (~old & data) {
+                pch_pic_update_irq(s, (~old & data), 0);
+            }
+            break;
+        case PCH_PIC_INT_STATUS_OFFSET:
+            s->intisr = data;
+            break;
+        case PCH_PIC_INT_EDGE_OFFSET:
+            s->intedge = data;
+            break;
+        case PCH_PIC_INT_CLEAR_OFFSET:
+            s->intirr &= (~(data & s->intedge));
+            pch_pic_update_irq(s, data, 0);
+            s->intisr &= (~data);
+            break;
+        case PCH_PIC_INT_POL_OFFSET:
+            s->int_polarity = data;
+            break;
+        case PCH_PIC_HTMSI_EN_OFFSET:
+            s->htmsi_en = data;
+            break;
+        case PCH_PIC_AUTO_CTRL0_OFFSET:
+        case PCH_PIC_AUTO_CTRL1_OFFSET:
+            break;
+        default:
+            break;
+        }
+    } else if (size == 4) {
+        switch (offset) {
+        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
+            offset -= PCH_PIC_INT_MASK_OFFSET;
+            old = ldl_p((void *)&s->int_mask + offset);
+            stl_p((void *)&s->int_mask + offset, data);
+
+            if (old & ~data) {
+                pch_pic_update_irq(s, (old & ~data), 1);
+            } else if (~old & data) {
+                pch_pic_update_irq(s, (~old & data), 0);
+            }
+            break;
+        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
+            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_STATUS_OFFSET),
+                  data);
+            break;
+        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
+            stl_p((void *)&s->intedge + (offset - PCH_PIC_INT_EDGE_OFFSET),
+                  data);
+            break;
+        case PCH_PIC_INT_CLEAR_OFFSET...PCH_PIC_INT_CLEAR_END:
+            old = s->intirr & (~(data & s->intedge));
+            stl_p((void *)&s->intirr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
+                  old);
+            pch_pic_update_irq(s, data, 0);
+            old = s->intisr & (~data);
+            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
+                  old);
+            break;
+        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
+            stl_p((void *)&s->int_polarity + (offset - PCH_PIC_INT_POL_OFFSET),
+                  data);
+            break;
+        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
+            stl_p((void *)&s->htmsi_en + (offset - PCH_PIC_HTMSI_EN_OFFSET),
+                  data);
+            break;
+        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
+        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
+            break;
+        default:
+            break;
+        }
+    } else if (size == 1) {
+        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
+            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
+            if (offset_tmp >= 0 && offset_tmp < 64) {
+                s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
+            }
+        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
+            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
+            if (offset_tmp >= 0 && offset_tmp < 64) {
+                s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
+            }
+        }
+    }
+}
+
+static const MemoryRegionOps loongarch_pch_pic_ops = {
+    .read = loongarch_pch_pic_reg_read,
+    .write = loongarch_pch_pic_reg_write,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 8,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void loongarch_pch_pic_reset(DeviceState *d)
+{
+    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(d);
+    int i;
+
+    s->int_mask = -1ULL;
+    s->htmsi_en = 0x0;
+    s->intedge  = 0x0;
+    s->intclr   = 0x0;
+    s->auto_crtl0 = 0x0;
+    s->auto_crtl1 = 0x0;
+    for (i = 0; i < 64; i++) {
+        s->route_entry[i] = 0x1;
+        s->htmsi_vector[i] = 0x0;
+    }
+    s->intirr = 0x0;
+    s->intisr = 0x0;
+    s->last_intirr = 0x0;
+    s->int_polarity = 0x0;
+}
+
+static void loongarch_pch_pic_init(Object *obj)
+{
+    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    int i;
+
+    memory_region_init_io(&s->iomem, obj, &loongarch_pch_pic_ops,
+                          s, TYPE_LOONGARCH_PCH_PIC, 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+
+    for (i = 0; i < PCH_PIC_IRQ_NUM; i++) {
+        sysbus_init_irq(sbd, &s->parent_irq[i]);
+    }
+    qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
+}
+
+static const VMStateDescription vmstate_loongarch_pch_pic = {
+    .name = TYPE_LOONGARCH_PCH_PIC,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(int_mask, loongarch_pch_pic),
+        VMSTATE_UINT64(htmsi_en, loongarch_pch_pic),
+        VMSTATE_UINT64(intedge, loongarch_pch_pic),
+        VMSTATE_UINT64(intclr, loongarch_pch_pic),
+        VMSTATE_UINT64(auto_crtl0, loongarch_pch_pic),
+        VMSTATE_UINT64(auto_crtl1, loongarch_pch_pic),
+        VMSTATE_UINT8_ARRAY(route_entry, loongarch_pch_pic, 64),
+        VMSTATE_UINT8_ARRAY(htmsi_vector, loongarch_pch_pic, 64),
+        VMSTATE_UINT64(last_intirr, loongarch_pch_pic),
+        VMSTATE_UINT64(intirr, loongarch_pch_pic),
+        VMSTATE_UINT64(intisr, loongarch_pch_pic),
+        VMSTATE_UINT64(int_polarity, loongarch_pch_pic),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = loongarch_pch_pic_reset;
+    dc->vmsd = &vmstate_loongarch_pch_pic;
+}
+
+static const TypeInfo loongarch_pch_pic_info = {
+    .name          = TYPE_LOONGARCH_PCH_PIC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(loongarch_pch_pic),
+    .instance_init = loongarch_pch_pic_init,
+    .class_init    = loongarch_pch_pic_class_init,
+};
+
+static void loongarch_pch_pic_register_types(void)
+{
+    type_register_static(&loongarch_pch_pic_info);
+}
+
+type_init(loongarch_pch_pic_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 51f0c3988a..33ba63266e 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -58,3 +58,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
 specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
 specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
 specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 124608e51f..52fedf82be 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -250,3 +250,8 @@ sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
 # loongarch_ipi.c
 loongarch_ipi_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
 loongarch_ipi_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
+
+# loongarch_pch_pic.c
+pch_pic_irq_handler(uint32_t edge, int irq, int level) "edge 0x%02x irq %d level %d"
+loongarch_pch_pic_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
+loongarch_pch_pic_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 1591574397..c2b8046b94 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -2,3 +2,4 @@ config LOONGSON3_LS7A
     bool
     select PCI_EXPRESS_7A
     select LOONGARCH_IPI
+    select LOONGARCH_PCH_PIC
diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
new file mode 100644
index 0000000000..bc04ed28ef
--- /dev/null
+++ b/include/hw/intc/loongarch_pch_pic.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch 7A1000 I/O interrupt controller definitions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
+DECLARE_INSTANCE_CHECKER(struct loongarch_pch_pic, LOONGARCH_PCH_PIC,
+                         TYPE_LOONGARCH_PCH_PIC)
+
+#define PCH_PIC_IRQ_START               0
+#define PCH_PIC_IRQ_END                 63
+#define PCH_PIC_IRQ_NUM                 64
+#define PCH_PIC_INT_ID_VAL              0x7000000UL
+#define PCH_PIC_INT_ID_NUM              0x3f0001UL
+
+#define PCH_PIC_INT_ID_OFFSET           0x00
+#define PCH_PIC_INT_ID_END              0x07
+#define PCH_PIC_INT_MASK_OFFSET         0x20
+#define PCH_PIC_INT_MASK_END            0x27
+#define PCH_PIC_HTMSI_EN_OFFSET         0x40
+#define PCH_PIC_HTMSI_EN_END            0x47
+#define PCH_PIC_INT_EDGE_OFFSET         0x60
+#define PCH_PIC_INT_EDGE_END            0x67
+#define PCH_PIC_INT_CLEAR_OFFSET        0x80
+#define PCH_PIC_INT_CLEAR_END           0x87
+#define PCH_PIC_AUTO_CTRL0_OFFSET       0xc0
+#define PCH_PIC_AUTO_CTRL0_END          0xc7
+#define PCH_PIC_AUTO_CTRL1_OFFSET       0xe0
+#define PCH_PIC_AUTO_CTRL1_END          0xe8
+#define PCH_PIC_ROUTE_ENTRY_OFFSET      0x100
+#define PCH_PIC_ROUTE_ENTRY_END         0x13f
+#define PCH_PIC_HTMSI_VEC_OFFSET        0x200
+#define PCH_PIC_HTMSI_VEC_END           0x23f
+#define PCH_PIC_INT_STATUS_OFFSET       0x3a0
+#define PCH_PIC_INT_STATUS_END          0x3a7
+#define PCH_PIC_INT_POL_OFFSET          0x3e0
+#define PCH_PIC_INT_POL_END             0x3e7
+
+typedef struct loongarch_pch_pic {
+    SysBusDevice parent_obj;
+    qemu_irq parent_irq[64];
+    uint64_t int_mask; /*0x020 interrupt mask register*/
+    uint64_t htmsi_en;/*0x040 1=msi*/
+    uint64_t intedge; /*0x060 edge=1 level  =0*/
+    uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
+    uint64_t auto_crtl0; /*0x0c0*/
+    uint64_t auto_crtl1; /*0x0e0*/
+    uint8_t route_entry[64]; /*0x100 - 0x138*/
+    uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
+    uint64_t last_intirr;    /* edge detection */
+    uint64_t intirr; /* 0x380 interrupt request register */
+    uint64_t intisr; /* 0x3a0 interrupt service register */
+    /*
+     * 0x3e0 interrupt level polarity selection
+     * register 0 for high level trigger
+     */
+    uint64_t int_polarity;
+    MemoryRegion iomem;
+} loongarch_pch_pic;
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 19/27] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI)
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (17 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 18/27] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-18  0:36   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 20/27] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
                   ` (8 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This patch realize PCH-MSI interrupt controller.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/intc/Kconfig                     |  5 +++
 hw/intc/loongarch_pch_msi.c         | 67 +++++++++++++++++++++++++++++
 hw/intc/meson.build                 |  1 +
 hw/intc/trace-events                |  3 ++
 hw/loongarch/Kconfig                |  1 +
 include/hw/intc/loongarch_pch_msi.h | 21 +++++++++
 6 files changed, 98 insertions(+)
 create mode 100644 hw/intc/loongarch_pch_msi.c
 create mode 100644 include/hw/intc/loongarch_pch_msi.h

diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 96da13ad1d..dc5f41f5f5 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -80,3 +80,8 @@ config LOONGARCH_IPI
 config LOONGARCH_PCH_PIC
     bool
     select UNIMP
+
+config LOONGARCH_PCH_MSI
+    select MSI_NONBROKEN
+    bool
+    select UNIMP
diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c
new file mode 100644
index 0000000000..c7777f763b
--- /dev/null
+++ b/hw/intc/loongarch_pch_msi.c
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Loongson 7A1000 msi interrupt controller.
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "hw/intc/loongarch_pch_msi.h"
+#include "hw/intc/loongarch_pch_pic.h"
+#include "hw/pci/msi.h"
+#include "hw/misc/unimp.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0;
+}
+
+static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
+                                    uint64_t val, unsigned size)
+{
+    loongarch_pch_msi *s = LOONGARCH_PCH_MSI(opaque);
+    int irq_num = val & 0xff;
+
+    trace_loongarch_msi_set_irq(irq_num);
+    qemu_set_irq(s->pch_msi_irq[irq_num - PCH_PIC_IRQ_NUM], 1);
+}
+
+static const MemoryRegionOps loongarch_pch_msi_ops = {
+    .read  = loongarch_msi_mem_read,
+    .write = loongarch_msi_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void loongarch_pch_msi_init(Object *obj)
+{
+    loongarch_pch_msi *s = LOONGARCH_PCH_MSI(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    int i;
+
+    memory_region_init_io(&s->msi_mmio, obj, &loongarch_pch_msi_ops,
+                          s, TYPE_LOONGARCH_PCH_MSI, 0x8);
+    sysbus_init_mmio(sbd, &s->msi_mmio);
+    msi_nonbroken = true;
+
+    for (i = 0; i < PCH_MSI_IRQ_NUM; i++) {
+        sysbus_init_irq(sbd, &s->pch_msi_irq[i]);
+    }
+}
+
+static const TypeInfo loongarch_pch_msi_info = {
+    .name          = TYPE_LOONGARCH_PCH_MSI,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(loongarch_pch_msi),
+    .instance_init = loongarch_pch_msi_init,
+};
+
+static void loongarch_pch_msi_register_types(void)
+{
+    type_register_static(&loongarch_pch_msi_info);
+}
+
+type_init(loongarch_pch_msi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 33ba63266e..acefe0c5aa 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -59,3 +59,4 @@ specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
 specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
 specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
 specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 52fedf82be..20da343cfe 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -255,3 +255,6 @@ loongarch_ipi_write(unsigned size, uint32_t addr, unsigned long val) "size: %u a
 pch_pic_irq_handler(uint32_t edge, int irq, int level) "edge 0x%02x irq %d level %d"
 loongarch_pch_pic_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
 loongarch_pch_pic_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
+
+# loongarch_pch_msi.c
+loongarch_msi_set_irq(int irq_num) "set msi irq %d"
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index c2b8046b94..cd38d03a19 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -3,3 +3,4 @@ config LOONGSON3_LS7A
     select PCI_EXPRESS_7A
     select LOONGARCH_IPI
     select LOONGARCH_PCH_PIC
+    select LOONGARCH_PCH_MSI
diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h
new file mode 100644
index 0000000000..35297d51d8
--- /dev/null
+++ b/include/hw/intc/loongarch_pch_msi.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch 7A1000 I/O interrupt controller definitions
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi"
+DECLARE_INSTANCE_CHECKER(struct loongarch_pch_msi, LOONGARCH_PCH_MSI,
+                         TYPE_LOONGARCH_PCH_MSI)
+
+/* Msi irq start start from 64 to 255 */
+#define PCH_MSI_IRQ_START   64
+#define PCH_MSI_IRQ_END     255
+#define PCH_MSI_IRQ_NUM     192
+
+typedef struct loongarch_pch_msi {
+    SysBusDevice parent_obj;
+    qemu_irq pch_msi_irq[PCH_MSI_IRQ_NUM];
+    MemoryRegion msi_mmio;
+} loongarch_pch_msi;
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 20/27] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (18 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 19/27] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-18  0:50   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 21/27] hw/loongarch: Add irq hierarchy for the system Xiaojuan Yang
                   ` (7 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This patch realize the EIOINTC interrupt controller.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/intc/Kconfig                    |   3 +
 hw/intc/loongarch_extioi.c         | 499 +++++++++++++++++++++++++++++
 hw/intc/meson.build                |   1 +
 hw/intc/trace-events               |   9 +
 hw/loongarch/Kconfig               |   1 +
 include/hw/intc/loongarch_extioi.h |  69 ++++
 6 files changed, 582 insertions(+)
 create mode 100644 hw/intc/loongarch_extioi.c
 create mode 100644 include/hw/intc/loongarch_extioi.h

diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index dc5f41f5f5..2868b25005 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -85,3 +85,6 @@ config LOONGARCH_PCH_MSI
     select MSI_NONBROKEN
     bool
     select UNIMP
+
+config LOONGARCH_EXTIOI
+    bool
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
new file mode 100644
index 0000000000..9838f05806
--- /dev/null
+++ b/hw/intc/loongarch_extioi.c
@@ -0,0 +1,499 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Loongson 3A5000 ext interrupt controller emulation
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu/log.h"
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "hw/loongarch/loongarch.h"
+#include "hw/qdev-properties.h"
+#include "exec/address-spaces.h"
+#include "hw/intc/loongarch_extioi.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+static void extioi_update_irq(void *opaque, int irq_num, int level)
+{
+    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
+    uint8_t  ipnum, cpu;
+    unsigned long found1, found2;
+
+    ipnum = s->sw_ipmap[irq_num];
+    cpu   = s->sw_coremap[irq_num];
+    if (level == 1) {
+        if (test_bit(irq_num, (void *)s->enable) == false) {
+            return;
+        }
+        bitmap_set((void *)s->coreisr[cpu], irq_num, 1);
+        found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
+                               EXTIOI_IRQS, 0);
+        bitmap_set((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
+
+        if (found1 >= EXTIOI_IRQS) {
+            qemu_set_irq(s->parent_irq[cpu][ipnum], level);
+        }
+    } else {
+        bitmap_clear((void *)s->coreisr[cpu], irq_num, 1);
+        found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
+                               EXTIOI_IRQS, 0);
+        bitmap_clear((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
+        found2 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
+                               EXTIOI_IRQS, 0);
+
+        if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) {
+            qemu_set_irq(s->parent_irq[cpu][ipnum], level);
+        }
+    }
+}
+
+static void extioi_setirq(void *opaque, int irq, int level)
+{
+    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
+    trace_extioi_setirq(irq, level);
+    extioi_update_irq(s, irq, level);
+}
+
+static uint32_t extioi_readb(void *opaque, hwaddr addr)
+{
+    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
+    unsigned long offset, reg_count;
+    uint8_t ret;
+    int cpu;
+
+    offset = addr & 0xffff;
+
+    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
+        ret = ldub_p((void *)s->enable + (offset - EXTIOI_ENABLE_START));
+    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
+        ret = ldub_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START));
+    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
+        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
+        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
+        ret = ldub_p((void *)s->coreisr[cpu] + reg_count);
+    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
+        ret = ldub_p((void *)&s->ipmap + (offset - EXTIOI_IPMAP_START));
+    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
+        ret = ldub_p((void *)s->coremap + (offset - EXTIOI_COREMAP_START));
+    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
+        ret = ldub_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START));
+    }
+
+    trace_loongarch_extioi_readb((uint32_t)addr, ret);
+    return ret;
+}
+
+static uint32_t extioi_readw(void *opaque, hwaddr addr)
+{
+    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
+    unsigned long offset, reg_count;
+    uint32_t ret;
+    int cpu;
+
+    offset = addr & 0xffff;
+
+    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
+        ret = ldl_p((void *)s->enable + (offset - EXTIOI_ENABLE_START));
+    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
+        ret = ldl_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START));
+    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
+        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
+        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
+        ret = ldl_p((void *)s->coreisr[cpu] + reg_count);
+    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
+        ret = ldl_p((void *)&s->ipmap + (offset - EXTIOI_IPMAP_START));
+    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
+        ret = ldl_p((void *)s->coremap + (offset - EXTIOI_COREMAP_START));
+    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
+        ret = ldl_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START));
+    }
+
+    trace_loongarch_extioi_readw((uint32_t)addr, ret);
+    return ret;
+}
+
+static uint64_t extioi_readl(void *opaque, hwaddr addr)
+{
+    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
+    unsigned long offset, reg_count;
+    uint64_t ret;
+    int cpu;
+
+    offset = addr & 0xffff;
+
+    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
+        ret = ldq_p((void *)s->enable + (offset - EXTIOI_ENABLE_START));
+    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
+        ret = ldq_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START));
+    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
+        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
+        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
+        ret = ldq_p((void *)s->coreisr[cpu] + reg_count);
+    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
+        ret = ldq_p((void *)&s->ipmap + (offset - EXTIOI_IPMAP_START));
+    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
+        ret = ldq_p((void *)s->coremap + (offset - EXTIOI_COREMAP_START));
+    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
+        ret = ldq_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START));
+    }
+
+    trace_loongarch_extioi_readl((uint32_t)addr, ret);
+    return ret;
+}
+
+static void extioi_writeb(void *opaque, hwaddr addr, uint32_t val,
+                          unsigned size)
+{
+    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
+    unsigned long offset, reg_count;
+    uint8_t old_data;
+    int cpu, i, j, ipnum, level, irqnum, bits;
+
+    offset = addr & 0xffff;
+    val = val & 0xffUL;
+
+    trace_loongarch_extioi_writeb(size, (uint32_t)addr, val);
+    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
+        reg_count = (offset - EXTIOI_ENABLE_START);
+        old_data = ldub_p((void *)s->enable + reg_count);
+        if (old_data != val) {
+            stb_p((void *)s->enable + reg_count, val);
+            old_data = old_data ^ val;
+            bits = size * 8;
+            while ((i = find_first_bit((void *)&old_data, bits)) != bits) {
+                level = test_bit(i, (unsigned long *)&val);
+                extioi_update_irq(s, i + reg_count * 8, level);
+                clear_bit(i, (void *)&old_data);
+            }
+        }
+    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
+        stb_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START), val);
+    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
+        reg_count = (offset - EXTIOI_COREISR_START) & 0x1f;
+        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
+
+        old_data = ldub_p((void *)s->coreisr[cpu] + reg_count);
+        stb_p((void *)s->coreisr[cpu] + reg_count, (old_data & ~val));
+
+        if (old_data != (old_data & ~val)) {
+            bits = size * 8;
+
+            while ((i = find_first_bit((void *)&val, bits)) != bits) {
+                j = test_bit(i, (unsigned long *)&old_data);
+                if (j) {
+                    extioi_update_irq(s, i + reg_count * 8, 0);
+                }
+                clear_bit(i, (void *)&val);
+            }
+        }
+    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
+        /* Drop arch.core_ip_mask use s->ipmap */
+        reg_count = (offset - EXTIOI_IPMAP_START);
+        stb_p((void *)&s->ipmap + reg_count, val);
+
+        /* Routing in groups of 32 interrupt */
+        while (val) {
+            ipnum = find_first_bit((void *)&val, 4);
+            for (i = 0; i < 32; i++) {
+                irqnum = reg_count * 32 + i;
+                if (ipnum != 4) {
+                    s->sw_ipmap[irqnum] = ipnum;
+                } else {
+                    s->sw_ipmap[irqnum] = 0;
+                }
+            }
+            val = val >> 8;
+            reg_count += 1;
+        }
+    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
+        reg_count = (offset - EXTIOI_COREMAP_START);
+
+        /* Only map the core */
+        while (val) {
+            stb_p((void *)s->coremap + reg_count, val);
+            s->sw_coremap[reg_count] = val & 0xf;
+            val = val >> 8;
+        }
+    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
+        stb_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START), val);
+    }
+}
+
+static void extioi_writew(void *opaque, hwaddr addr, uint32_t val,
+                          unsigned size)
+{
+    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
+    int cpu, level, irqnum, ipnum;
+    uint32_t offset, old_data, reg_count, i, j, bits;
+
+    offset = addr & 0xffff;
+    trace_loongarch_extioi_writew(size, (uint32_t)addr, val);
+
+    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
+        reg_count = (offset - EXTIOI_ENABLE_START);
+        old_data = ldl_p((void *)s->enable + reg_count);
+        if (old_data != val) {
+            stl_p((void *)s->enable + reg_count, val);
+            old_data = old_data ^ val;
+
+            bits = size * 8;
+            while ((i = find_first_bit((void *)&old_data, bits)) != bits) {
+                level = test_bit(i, (unsigned long *)&val);
+                extioi_update_irq(s, i + reg_count * 8, level);
+                clear_bit(i, (void *)&old_data);
+            }
+        }
+    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
+        stl_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START), val);
+    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
+        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
+        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
+
+        /* Ext_core_ioisr */
+        old_data = ldl_p((void *)s->coreisr[cpu] + reg_count);
+        stl_p((void *)s->coreisr[cpu] + reg_count, (old_data & ~val));
+
+        if (old_data != (old_data & ~val)) {
+            bits = size * 8;
+            while ((i = find_first_bit((void *)&val, bits)) != bits) {
+                j = test_bit(i, (unsigned long *)&old_data);
+                if (j) {
+                    extioi_update_irq(s, i + reg_count * 8, 0);
+                }
+                clear_bit(i, (void *)&val);
+            }
+        }
+    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
+        /* Drop arch.core_ip_mask use s->ipmap */
+        reg_count = (offset - EXTIOI_IPMAP_START);
+        stl_p((void *)&s->ipmap + reg_count, val);
+
+        /* Routing in groups of 32 interrupt */
+        while (val) {
+            ipnum = find_first_bit((void *)&val, 4);
+            for (i = 0; i < 32; i++) {
+                irqnum = reg_count * 32 + i;
+                if (ipnum != 4) {
+                    s->sw_ipmap[irqnum] = ipnum;
+                } else {
+                    s->sw_ipmap[irqnum] = 0;
+                }
+            }
+            val = val >> 8;
+            reg_count += 1;
+        }
+    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
+        reg_count = (offset - EXTIOI_COREMAP_START);
+        /* Only map the core */
+        while (val) {
+            stl_p((void *)s->coremap + reg_count, val);
+            s->sw_coremap[reg_count] = val & 0xf;
+            val = val >> 8;
+        }
+    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
+        stl_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START), val);
+    }
+}
+
+static void extioi_writel(void *opaque, hwaddr addr, uint64_t val,
+                          unsigned size)
+{
+    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
+    int cpu, level, i, j, bits, ipnum, irqnum;
+    uint64_t offset, old_data, reg_count;
+
+    offset = addr & 0xffff;
+    trace_loongarch_extioi_writel(size, (uint32_t)addr, val);
+
+    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
+        reg_count = (offset - EXTIOI_ENABLE_START);
+        old_data = s->enable[reg_count];
+        if (old_data != val) {
+            s->enable[reg_count] = val;
+            old_data = old_data ^ val;
+
+            bits = size * 8;
+            while ((i = find_first_bit((void *)&old_data, bits)) != bits) {
+                level = test_bit(i, (unsigned long *)&val);
+                extioi_update_irq(s, i + reg_count * 8, level);
+                clear_bit(i, (void *)&old_data);
+            }
+        }
+    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
+        stq_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START), val);
+    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
+        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
+        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
+
+        /* core_ext_ioisr */
+        old_data = ldq_p((void *)s->coreisr[cpu] + reg_count);
+        stq_p((void *)s->coreisr[cpu] + reg_count, (old_data & ~val));
+
+        if (old_data != (old_data & ~val)) {
+            bits = size * 8;
+            while ((i = find_first_bit((void *)&val, bits)) != bits) {
+                j = test_bit(i, (unsigned long *)&old_data);
+                if (j) {
+                    extioi_update_irq(s, i + reg_count * 8, 0);
+                }
+                clear_bit(i, (void *)&val);
+            }
+        }
+    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
+        /* Drop arch.core_ip_mask use s->ipmap */
+        reg_count = (offset - EXTIOI_IPMAP_START);
+        stq_p((void *)&s->ipmap + reg_count, val);
+
+        /* Routing in groups of 32 interrupt */
+        while (val) {
+            ipnum = find_first_bit((void *)&val, 4);
+            for (i = 0; i < 32; i++) {
+                irqnum = reg_count * 32 + i;
+                if (ipnum != 4) {
+                    s->sw_ipmap[irqnum] = ipnum;
+                } else {
+                    s->sw_ipmap[irqnum] = 0;
+                }
+            }
+            val = val >> 8;
+            reg_count += 1;
+        }
+    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
+        reg_count = (offset - EXTIOI_COREMAP_START);
+        /* Only map the core */
+        while (val) {
+            stq_p((void *)s->coremap + reg_count, val);
+            s->sw_coremap[reg_count] = val & 0xf;
+            val = val >> 8;
+        }
+    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
+        stq_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START), val);
+    }
+}
+
+static uint64_t extioi_readfn(void *opaque, hwaddr addr, unsigned size)
+{
+    switch (size) {
+    case 1:
+        return extioi_readb(opaque, addr);
+    case 4:
+        return extioi_readw(opaque, addr);
+    case 8:
+        return extioi_readl(opaque, addr);
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void extioi_writefn(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned size)
+{
+    switch (size) {
+    case 1:
+        extioi_writeb(opaque, addr, value, size);
+        break;
+    case 4:
+        extioi_writew(opaque, addr, value, size);
+        break;
+    case 8:
+        extioi_writel(opaque, addr, value, size);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static const MemoryRegionOps extioi_ops = {
+    .read = extioi_readfn,
+    .write = extioi_writefn,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 8,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 8,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(qdev_get_machine());
+    MachineState *ms = MACHINE(lams);
+    loongarch_extioi *p = LOONGARCH_EXTIOI(dev);
+    int i, cpu, pin;
+
+    qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS);
+
+    for (i = 0; i < EXTIOI_IRQS; i++) {
+        sysbus_init_irq(SYS_BUS_DEVICE(dev), &p->irq[i]);
+    }
+
+    memory_region_init_io(&p->mmio, OBJECT(p), &extioi_ops, p,
+                          TYPE_LOONGARCH_EXTIOI, 0x900);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &p->mmio);
+
+    for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
+        for (pin = 0; pin < LS3A_INTC_IP; pin++) {
+            qdev_init_gpio_out(dev, &p->parent_irq[cpu][pin], 1);
+        }
+    }
+}
+
+static const VMStateDescription vmstate_ext_sw_ipisr = {
+    .name = "ext_sw_ipisr",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(irq, ext_sw_ipisr, EXTIOI_IRQS_BITMAP_SIZE),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_loongarch_extioi = {
+    .name = TYPE_LOONGARCH_EXTIOI,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64_ARRAY(enable, loongarch_extioi,
+                             EXTIOI_IRQS_BITMAP_SIZE / 8),
+        VMSTATE_UINT64_ARRAY(bounce, loongarch_extioi,
+                             EXTIOI_IRQS_BITMAP_SIZE / 8),
+        VMSTATE_UINT64_2DARRAY(coreisr, loongarch_extioi,
+                               MAX_CORES, EXTIOI_IRQS_BITMAP_SIZE / 8),
+        VMSTATE_UINT64(ipmap, loongarch_extioi),
+        VMSTATE_UINT64_ARRAY(coremap, loongarch_extioi,
+                             EXTIOI_IRQS_COREMAP_SIZE / 8),
+        VMSTATE_UINT64_ARRAY(nodetype, loongarch_extioi,
+                             EXTIOI_IRQS_NODETYPE_SIZE / 4),
+        VMSTATE_UINT8_ARRAY(sw_ipmap, loongarch_extioi, EXTIOI_IRQS),
+        VMSTATE_UINT8_ARRAY(sw_coremap, loongarch_extioi, EXTIOI_IRQS),
+        VMSTATE_STRUCT_2DARRAY(sw_ipisr, loongarch_extioi, MAX_CORES,
+                               LS3A_INTC_IP, 1, vmstate_ext_sw_ipisr,
+                               ext_sw_ipisr),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_loongarch_extioi;
+    dc->realize = loongarch_extioi_realize;
+}
+
+static const TypeInfo loongarch_extioi_info = {
+    .name          = TYPE_LOONGARCH_EXTIOI,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct loongarch_extioi),
+    .class_init    = loongarch_extioi_class_init,
+};
+
+static void loongarch_extioi_register_types(void)
+{
+    type_register_static(&loongarch_extioi_info);
+}
+
+type_init(loongarch_extioi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index acefe0c5aa..cee88a0d73 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -60,3 +60,4 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
 specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
 specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
 specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 20da343cfe..3f85126cf0 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -258,3 +258,12 @@ loongarch_pch_pic_write(unsigned size, uint32_t addr, unsigned long val) "size:
 
 # loongarch_pch_msi.c
 loongarch_msi_set_irq(int irq_num) "set msi irq %d"
+
+# loongarch_extioi.c
+extioi_setirq(int irq, int level) "set extirq irq %d level %d"
+loongarch_extioi_readb(uint32_t addr, uint8_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIu8
+loongarch_extioi_readw(uint32_t addr, uint32_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIx32
+loongarch_extioi_readl(uint32_t addr, uint64_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIx64
+loongarch_extioi_writeb(unsigned size, uint32_t addr, uint8_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIu8
+loongarch_extioi_writew(unsigned size, uint32_t addr, uint32_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx32
+loongarch_extioi_writel(unsigned size, uint32_t addr, uint64_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index cd38d03a19..468e3acc74 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -4,3 +4,4 @@ config LOONGSON3_LS7A
     select LOONGARCH_IPI
     select LOONGARCH_PCH_PIC
     select LOONGARCH_PCH_MSI
+    select LOONGARCH_EXTIOI
diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
new file mode 100644
index 0000000000..4e6a20dced
--- /dev/null
+++ b/include/hw/intc/loongarch_extioi.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch 3A5000 ext interrupt controller definitions
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "hw/sysbus.h"
+#include "hw/loongarch/loongarch.h"
+
+#ifndef LOONGARCH_EXTIOI_H
+#define LOONGARCH_EXTIOI_H
+
+#define LS3A_INTC_IP               8
+#define MAX_CORES                  LOONGARCH_MAX_VCPUS
+#define EXTIOI_IRQS                (256)
+#define EXTIOI_IRQS_BITMAP_SIZE    (256 / 8)
+/* map to ipnum per 32 irqs */
+#define EXTIOI_IRQS_IPMAP_SIZE     (256 / 32)
+#define EXTIOI_IRQS_COREMAP_SIZE   256
+#define EXTIOI_IRQS_NODETYPE_SIZE  16
+
+#define APIC_OFFSET                  0x400
+#define APIC_BASE                    (0x1000ULL + APIC_OFFSET)
+
+#define EXTIOI_NODETYPE_START        (0x4a0 - APIC_OFFSET)
+#define EXTIOI_NODETYPE_END          (0x4c0 - APIC_OFFSET)
+#define EXTIOI_IPMAP_START           (0x4c0 - APIC_OFFSET)
+#define EXTIOI_IPMAP_END             (0x4c8 - APIC_OFFSET)
+#define EXTIOI_ENABLE_START          (0x600 - APIC_OFFSET)
+#define EXTIOI_ENABLE_END            (0x620 - APIC_OFFSET)
+#define EXTIOI_BOUNCE_START          (0x680 - APIC_OFFSET)
+#define EXTIOI_BOUNCE_END            (0x6a0 - APIC_OFFSET)
+#define EXTIOI_ISR_START             (0x700 - APIC_OFFSET)
+#define EXTIOI_ISR_END               (0x720 - APIC_OFFSET)
+#define EXTIOI_COREISR_START         (0x800 - APIC_OFFSET)
+#define EXTIOI_COREISR_END           (0xB20 - APIC_OFFSET)
+#define EXTIOI_COREMAP_START         (0xC00 - APIC_OFFSET)
+#define EXTIOI_COREMAP_END           (0xD00 - APIC_OFFSET)
+
+#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi"
+DECLARE_INSTANCE_CHECKER(struct loongarch_extioi, LOONGARCH_EXTIOI,
+                         TYPE_LOONGARCH_EXTIOI)
+
+typedef struct ext_sw_ipisr {
+    uint8_t irq[EXTIOI_IRQS_BITMAP_SIZE];
+} ext_sw_ipisr;
+
+typedef struct loongarch_extioi {
+    SysBusDevice parent_obj;
+    /* hardware state */
+    uint64_t enable[EXTIOI_IRQS_BITMAP_SIZE / 8];
+    uint64_t bounce[EXTIOI_IRQS_BITMAP_SIZE / 8];
+    uint64_t coreisr[MAX_CORES][EXTIOI_IRQS_BITMAP_SIZE / 8];
+    uint64_t ipmap;
+    uint64_t coremap[EXTIOI_IRQS_COREMAP_SIZE / 8];
+    uint64_t nodetype[EXTIOI_IRQS_NODETYPE_SIZE / 4];
+
+    /*software state */
+    uint8_t sw_ipmap[EXTIOI_IRQS];
+    uint8_t sw_coremap[EXTIOI_IRQS];
+    ext_sw_ipisr sw_ipisr[MAX_CORES][LS3A_INTC_IP];
+
+    qemu_irq parent_irq[MAX_CORES][LS3A_INTC_IP];
+    qemu_irq irq[EXTIOI_IRQS];
+    MemoryRegion mmio;
+} loongarch_extioi;
+
+#endif /* LOONGARCH_EXTIOI_H */
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 21/27] hw/loongarch: Add irq hierarchy for the system
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (19 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 20/27] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-18  9:45   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000 Xiaojuan Yang
                   ` (6 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This patch add the irq hierarchy for the virt board.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/loongarch/loongson3.c   | 84 ++++++++++++++++++++++++++++++++++++++
 include/hw/pci-host/ls7a.h | 13 ++++++
 2 files changed, 97 insertions(+)

diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 28b623e927..c42f830208 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -15,6 +15,10 @@
 #include "sysemu/runstate.h"
 #include "sysemu/reset.h"
 #include "hw/loongarch/loongarch.h"
+#include "hw/intc/loongarch_ipi.h"
+#include "hw/intc/loongarch_extioi.h"
+#include "hw/intc/loongarch_pch_pic.h"
+#include "hw/intc/loongarch_pch_msi.h"
 #include "hw/pci-host/ls7a.h"
 
 
@@ -70,6 +74,83 @@ static const MemoryRegionOps loongarch_qemu_ops = {
     },
 };
 
+static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
+                                      hwaddr addr, MemoryRegion *iocsr)
+{
+    assert(n >= 0 && n < dev->num_mmio);
+
+    if (dev->mmio[n].addr == addr) {
+        /* ??? region already mapped here. */
+        return;
+    }
+    if (dev->mmio[n].addr != (hwaddr)-1) {
+        /* Unregister previous mapping. */
+        memory_region_del_subregion(iocsr, dev->mmio[n].memory);
+    }
+    dev->mmio[n].addr = addr;
+    memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
+}
+
+static void loongson3_irq_init(MachineState *machine)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
+    SysBusDevice *d;
+    int cpu, pin, i;
+    unsigned long ipi_addr;
+
+    ipi = qdev_new(TYPE_LOONGARCH_IPI);
+    d = SYS_BUS_DEVICE(ipi);
+    sysbus_realize_and_unref(d, &error_fatal);
+    for (cpu = 0; cpu < machine->smp.cpus; cpu++) {
+        cpudev = DEVICE(qemu_get_cpu(cpu));
+        ipi_addr = SMP_IPI_MAILBOX + cpu * 0x100;
+        sysbus_mmio_map_loongarch(d, cpu, ipi_addr, &lams->system_iocsr);
+        qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
+    }
+
+    extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
+    d = SYS_BUS_DEVICE(extioi);
+    sysbus_realize_and_unref(d, &error_fatal);
+    sysbus_mmio_map_loongarch(d, 0, APIC_BASE, &lams->system_iocsr);
+
+    for (i = 0; i < EXTIOI_IRQS; i++) {
+        sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
+    }
+
+    /*
+     * connect ext irq to the cpu irq
+     * cpu_pin[9:2] <= intc_pin[7:0]
+     */
+    for (cpu = 0; cpu < machine->smp.cpus; cpu++) {
+        cpudev = DEVICE(qemu_get_cpu(cpu));
+        for (pin = 0; pin < LS3A_INTC_IP; pin++) {
+            qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
+                                  qdev_get_gpio_in(cpudev, pin + 2));
+        }
+    }
+
+    pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
+    d = SYS_BUS_DEVICE(pch_pic);
+    sysbus_realize_and_unref(d, &error_fatal);
+    sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
+
+    /* Connect 64 pch_pic irqs to extioi */
+    for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
+        sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
+    }
+
+    pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
+    d = SYS_BUS_DEVICE(pch_msi);
+    sysbus_realize_and_unref(d, &error_fatal);
+    sysbus_mmio_map(d, 0, LS7A_PCH_MSI_ADDR_LOW);
+    for (i = 0; i < PCH_MSI_IRQ_NUM; i++) {
+        /* Connect 192 pch_msi irqs to extioi */
+        sysbus_connect_irq(d, i,
+                           qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
+    }
+}
+
 static void loongson3_init(MachineState *machine)
 {
     const char *cpu_model = machine->cpu_type;
@@ -126,6 +207,9 @@ static void loongson3_init(MachineState *machine)
     memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
     offset += highram_size;
 
+    /* Initialize the IO interrupt subsystem */
+    loongson3_irq_init(machine);
+
     LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
     LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
     LOONGARCH_SIMPLE_MMIO_OPS(CPUNAME_REG, "loongarch_cpuname", 0x8);
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index 32d6f045dc..ac938d6d5f 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -24,6 +24,19 @@
 #define LS7A_PCI_IO_BASE         0x18000000UL
 #define LS7A_PCI_IO_SIZE         0x00010000
 
+#define LS7A_PCH_REG_BASE       0x10000000UL
+#define LS7A_IOAPIC_REG_BASE    (LS7A_PCH_REG_BASE)
+#define LS7A_PCH_MSI_ADDR_LOW   0x2FF00000UL
+
+/*
+ * According to the kernel pch irq start from 64 offset
+ * 0 ~ 16 irqs used for non-pci device while 16 ~ 64 irqs
+ * used for pci device.
+ */
+#define PCH_PIC_IRQ_OFFSET      64
+#define LS7A_DEVICE_IRQS        16
+#define LS7A_PCI_IRQS           48
+
 struct LS7APCIState {
     /*< private >*/
     PCIDevice parent_obj;
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (20 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 21/27] hw/loongarch: Add irq hierarchy for the system Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 17:54   ` Philippe Mathieu-Daudé
  2021-12-18 10:02   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 23/27] hw/loongarch: Add LoongArch ls7a rtc device support Xiaojuan Yang
                   ` (5 subsequent siblings)
  27 siblings, 2 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

1.Add uart,virtio-net,vga and usb for 3A5000.
2.Add irq set and map for the pci host. Non pci device
use irq 0-16, pci device use 16-64.
3.Add some unimplented device to emulate guest unused
memory space.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/loongarch/Kconfig            |  8 +++++
 hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
 hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
 include/hw/intc/loongarch_ipi.h |  2 ++
 include/hw/pci-host/ls7a.h      |  4 +++
 softmmu/qdev-monitor.c          |  3 +-
 6 files changed, 117 insertions(+), 5 deletions(-)

diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 468e3acc74..9ea3b92708 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -1,5 +1,13 @@
 config LOONGSON3_LS7A
     bool
+    imply VGA_PCI
+    imply VIRTIO_VGA
+    imply PARALLEL
+    imply PCI_DEVICES
+    select ISA_BUS
+    select SERIAL
+    select SERIAL_ISA
+    select VIRTIO_PCI
     select PCI_EXPRESS_7A
     select LOONGARCH_IPI
     select LOONGARCH_PCH_PIC
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index c42f830208..e4a02e7c18 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -10,8 +10,11 @@
 #include "qemu/datadir.h"
 #include "qapi/error.h"
 #include "hw/boards.h"
+#include "hw/char/serial.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/qtest.h"
+#include "hw/irq.h"
+#include "net/net.h"
 #include "sysemu/runstate.h"
 #include "sysemu/reset.h"
 #include "hw/loongarch/loongarch.h"
@@ -20,6 +23,7 @@
 #include "hw/intc/loongarch_pch_pic.h"
 #include "hw/intc/loongarch_pch_msi.h"
 #include "hw/pci-host/ls7a.h"
+#include "hw/misc/unimp.h"
 
 
 static void loongarch_cpu_reset(void *opaque)
@@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
     memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
 }
 
-static void loongson3_irq_init(MachineState *machine)
+static PCIBus *loongson3_irq_init(MachineState *machine)
 {
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
-    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
+    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
     SysBusDevice *d;
+    PCIBus *pci_bus;
     int cpu, pin, i;
     unsigned long ipi_addr;
 
@@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
     sysbus_realize_and_unref(d, &error_fatal);
     sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
 
+    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
+                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
+                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
+
     /* Connect 64 pch_pic irqs to extioi */
     for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
         sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
@@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
         sysbus_connect_irq(d, i,
                            qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
     }
+
+    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
+    d = SYS_BUS_DEVICE(pciehost);
+    sysbus_realize_and_unref(d, &error_fatal);
+    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
+
+    /* Connect 48 pci irq to pch_pic */
+    for (i = 0; i < LS7A_PCI_IRQS; i++) {
+        qdev_connect_gpio_out(pciehost, i,
+                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
+    }
+
+    return pci_bus;
+}
+
+/* Network support */
+static void network_init(PCIBus *pci_bus)
+{
+    int i;
+
+    for (i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!nd->model) {
+            nd->model = g_strdup("virtio");
+        }
+
+        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
+    }
 }
 
 static void loongson3_init(MachineState *machine)
@@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
     MemoryRegion *address_space_mem = get_system_memory();
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
     int i;
+    PCIBus *pci_bus = NULL;
 
     if (!cpu_model) {
         cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
@@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
     memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
     offset += highram_size;
 
+    /*
+     * There are some invalid guest memory access.
+     * Create some unimplemented devices to emulate this.
+     */
+    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
+    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
+    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
+    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
+    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
+
     /* Initialize the IO interrupt subsystem */
-    loongson3_irq_init(machine);
+    pci_bus = loongson3_irq_init(machine);
+
+    /* Network card */
+    network_init(pci_bus);
+
+    /* VGA setup. Don't bother loading the bios. */
+    pci_vga_init(pci_bus);
+
+    pci_create_simple(pci_bus, -1, "pci-ohci");
 
     LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
     LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
index a783fb2eda..06cd641573 100644
--- a/hw/pci-host/ls7a.c
+++ b/hw/pci-host/ls7a.c
@@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
     }
 };
 
+static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
+{
+    PCIINTxRoute route;
+
+    route.irq = pin;
+    route.mode = PCI_INTX_ENABLED;
+    return route;
+}
+
+static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
+{
+    PCIBus *bus;
+    int offset, irq;
+
+    bus = pci_get_bus(d);
+    if (bus->parent_dev) {
+        irq = pci_swizzle_map_irq_fn(d, irq_num);
+        return irq;
+    }
+
+    /* pci device start from irq 80 */
+    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
+    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
+
+    return irq;
+}
+
+static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
+{
+    LS7APCIEHost *pciehost = opaque;
+    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
+
+    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
+}
+
 static void pci_ls7a_config_write(void *opaque, hwaddr addr,
                                   uint64_t val, unsigned size)
 {
@@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
     LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
     PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
 
-    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
+    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
+                                     pci_ls7a_map_irq, s,
                                      get_system_memory(), get_system_io(),
                                      PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
 
+    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
+
     memory_region_init_io(&s->pci_conf, OBJECT(dev),
                           &pci_ls7a_config_ops, pci->bus,
                           "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
@@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
     object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
     qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
     qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
+
+    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
 }
 
 static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
index d2397e53e7..1113c3b1a8 100644
--- a/include/hw/intc/loongarch_ipi.h
+++ b/include/hw/intc/loongarch_ipi.h
@@ -8,6 +8,8 @@
 #ifndef HW_LOONGARCH_IPI_H
 #define HW_LOONGARCH_IPI_H
 
+#include "hw/sysbus.h"
+
 /* Mainy used by iocsr read and write */
 #define SMP_IPI_MAILBOX      0x1000ULL
 #define CORE_STATUS_OFF       0x0
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index ac938d6d5f..3b9ad1e175 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -37,6 +37,9 @@
 #define LS7A_DEVICE_IRQS        16
 #define LS7A_PCI_IRQS           48
 
+#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
+#define LS7A_UART_BASE          0x1fe001e0
+
 struct LS7APCIState {
     /*< private >*/
     PCIDevice parent_obj;
@@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
 
     LS7APCIState pci_dev;
 
+    qemu_irq irqs[LS7A_PCI_IRQS];
     MemoryRegion pci_conf;
     MemoryRegion pci_io;
 } LS7APCIEHost;
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index 01f3834db5..49491d74a1 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ -60,7 +60,8 @@ typedef struct QDevAlias
                               QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
                               QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
                               QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
-                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
+                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
+                              QEMU_ARCH_LOONGARCH)
 #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
 #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
 
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 23/27] hw/loongarch: Add LoongArch ls7a rtc device support
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (21 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000 Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-18 10:10   ` Mark Cave-Ayland
  2021-12-04 12:07 ` [RFC PATCH v3 24/27] hw/loongarch: Add default bios startup support Xiaojuan Yang
                   ` (4 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

This patch add ls7a rtc device support.

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/loongarch/Kconfig       |   1 +
 hw/loongarch/loongson3.c   |   3 +
 hw/rtc/Kconfig             |   3 +
 hw/rtc/ls7a_rtc.c          | 323 +++++++++++++++++++++++++++++++++++++
 hw/rtc/meson.build         |   1 +
 include/hw/pci-host/ls7a.h |   4 +
 6 files changed, 335 insertions(+)
 create mode 100644 hw/rtc/ls7a_rtc.c

diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 9ea3b92708..6d3506fee9 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -13,3 +13,4 @@ config LOONGSON3_LS7A
     select LOONGARCH_PCH_PIC
     select LOONGARCH_PCH_MSI
     select LOONGARCH_EXTIOI
+    select LS7A_RTC
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index e4a02e7c18..f86f83c0b8 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -144,6 +144,9 @@ static PCIBus *loongson3_irq_init(MachineState *machine)
                    qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
                    115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
 
+    sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE,
+                         qdev_get_gpio_in(pch_pic, LS7A_RTC_IRQ - PCH_PIC_IRQ_OFFSET));
+
     /* Connect 64 pch_pic irqs to extioi */
     for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
         sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
index f06e133b8a..ba8f7bc202 100644
--- a/hw/rtc/Kconfig
+++ b/hw/rtc/Kconfig
@@ -25,3 +25,6 @@ config SUN4V_RTC
 
 config GOLDFISH_RTC
     bool
+
+config LS7A_RTC
+    bool
diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c
new file mode 100644
index 0000000000..b771db2e62
--- /dev/null
+++ b/hw/rtc/ls7a_rtc.c
@@ -0,0 +1,323 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Loongarch LS7A Real Time Clock emulation
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "include/hw/register.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "migration/vmstate.h"
+#include "hw/misc/unimp.h"
+
+#define SYS_TOYTRIM        0x20
+#define SYS_TOYWRITE0      0x24
+#define SYS_TOYWRITE1      0x28
+#define SYS_TOYREAD0       0x2C
+#define SYS_TOYREAD1       0x30
+#define SYS_TOYMATCH0      0x34
+#define SYS_TOYMATCH1      0x38
+#define SYS_TOYMATCH2      0x3C
+#define SYS_RTCCTRL        0x40
+#define SYS_RTCTRIM        0x60
+#define SYS_RTCWRTIE0      0x64
+#define SYS_RTCREAD0       0x68
+#define SYS_RTCMATCH0      0x6C
+#define SYS_RTCMATCH1      0x70
+#define SYS_RTCMATCH2      0x74
+
+/*
+ * Shift bits and filed mask
+ */
+#define TOY_MON_MASK   0x3f
+#define TOY_DAY_MASK   0x1f
+#define TOY_HOUR_MASK  0x1f
+#define TOY_MIN_MASK   0x3f
+#define TOY_SEC_MASK   0x3f
+#define TOY_MSEC_MASK  0xf
+
+#define TOY_MON_SHIFT  26
+#define TOY_DAY_SHIFT  21
+#define TOY_HOUR_SHIFT 16
+#define TOY_MIN_SHIFT  10
+#define TOY_SEC_SHIFT  4
+#define TOY_MSEC_SHIFT 0
+
+#define TOY_MATCH_YEAR_MASK  0x3f
+#define TOY_MATCH_MON_MASK   0xf
+#define TOY_MATCH_DAY_MASK   0x1f
+#define TOY_MATCH_HOUR_MASK  0x1f
+#define TOY_MATCH_MIN_MASK   0x3f
+#define TOY_MATCH_SEC_MASK   0x3f
+
+#define TOY_MATCH_YEAR_SHIFT 26
+#define TOY_MATCH_MON_SHIFT  22
+#define TOY_MATCH_DAY_SHIFT  17
+#define TOY_MATCH_HOUR_SHIFT 12
+#define TOY_MATCH_MIN_SHIFT  6
+#define TOY_MATCH_SEC_SHIFT  0
+
+#define TOY_ENABLE_BIT (1U << 11)
+
+#define TYPE_LS7A_RTC "ls7a_rtc"
+OBJECT_DECLARE_SIMPLE_TYPE(LS7A_RTCState, LS7A_RTC)
+
+typedef struct LS7A_RTCState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+    QEMUTimer *timer;
+    /*
+     * Needed to preserve the tick_count across migration, even if the
+     * absolute value of the rtc_clock is different on the source and
+     * destination.
+     */
+    int64_t offset;
+    int64_t data;
+    int64_t save_alarm_offset;
+    int tidx;
+    uint32_t toymatch[3];
+    uint32_t toytrim;
+    uint32_t cntrctl;
+    uint32_t rtctrim;
+    uint32_t rtccount;
+    uint32_t rtcmatch[3];
+    qemu_irq toy_irq;
+} LS7A_RTCState;
+
+enum {
+    TOYEN = 1UL << 11,
+    RTCEN = 1UL << 13,
+};
+
+static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size)
+{
+    LS7A_RTCState *s = LS7A_RTC(opaque);
+    struct tm tm;
+    unsigned int val;
+
+    val = 0;
+
+    switch (addr) {
+    case SYS_TOYREAD0:
+        qemu_get_timedate(&tm, s->offset);
+        val = (((tm.tm_mon + 1) & TOY_MON_MASK) << TOY_MON_SHIFT)
+        | (((tm.tm_mday) & TOY_DAY_MASK) << TOY_DAY_SHIFT)
+        | (((tm.tm_hour) & TOY_HOUR_MASK) << TOY_HOUR_SHIFT)
+        | (((tm.tm_min) & TOY_MIN_MASK) << TOY_MIN_SHIFT)
+        | (((tm.tm_sec) & TOY_SEC_MASK) << TOY_SEC_SHIFT) | 0x0;
+        break;
+    case SYS_TOYREAD1:
+        qemu_get_timedate(&tm, s->offset);
+        val = tm.tm_year;
+        break;
+    case SYS_TOYMATCH0:
+        val = s->toymatch[0];
+        break;
+    case SYS_TOYMATCH1:
+        val = s->toymatch[1];
+        break;
+    case SYS_TOYMATCH2:
+        val = s->toymatch[2];
+        break;
+    case SYS_RTCCTRL:
+        val = s->cntrctl;
+        break;
+    case SYS_RTCREAD0:
+        val = s->rtccount;
+        break;
+    case SYS_RTCMATCH0:
+        val = s->rtcmatch[0];
+        break;
+    case SYS_RTCMATCH1:
+        val = s->rtcmatch[1];
+        break;
+    case SYS_RTCMATCH2:
+        val = s->rtcmatch[2];
+        break;
+    default:
+        val = 0;
+        break;
+    }
+    return val;
+}
+
+static void ls7a_rtc_write(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
+{
+    LS7A_RTCState *s = LS7A_RTC(opaque);
+    struct tm tm;
+    int64_t alarm_offset, year_diff, expire_time;
+
+    switch (addr) {
+    case SYS_TOYWRITE0:
+        qemu_get_timedate(&tm, s->offset);
+        tm.tm_sec = (val >> TOY_SEC_SHIFT) & TOY_SEC_MASK;
+        tm.tm_min = (val >> TOY_MIN_SHIFT) & TOY_MIN_MASK;
+        tm.tm_hour = (val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK;
+        tm.tm_mday = ((val >> TOY_DAY_SHIFT) & TOY_DAY_MASK);
+        tm.tm_mon = ((val >> TOY_MON_SHIFT) & TOY_MON_MASK) - 1;
+        s->offset = qemu_timedate_diff(&tm);
+        break;
+    case SYS_TOYWRITE1:
+        qemu_get_timedate(&tm, s->offset);
+        tm.tm_year = val;
+        s->offset = qemu_timedate_diff(&tm);
+        break;
+    case SYS_TOYMATCH0:
+        s->toymatch[0] = val;
+        qemu_get_timedate(&tm, s->offset);
+        tm.tm_sec = (val >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK;
+        tm.tm_min = (val >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK;
+        tm.tm_hour = ((val >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK);
+        tm.tm_mday = ((val >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK);
+        tm.tm_mon = ((val >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1;
+        year_diff = ((val >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK);
+        year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK);
+        tm.tm_year = tm.tm_year + year_diff;
+        alarm_offset = qemu_timedate_diff(&tm) - s->offset;
+        if ((alarm_offset < 0) && (alarm_offset > -5)) {
+                alarm_offset = 0;
+        }
+        expire_time = qemu_clock_get_ms(rtc_clock);
+        expire_time += ((alarm_offset * 1000) + 100);
+        timer_mod(s->timer, expire_time);
+        break;
+    case SYS_TOYMATCH1:
+        s->toymatch[1] = val;
+        break;
+    case SYS_TOYMATCH2:
+        s->toymatch[2] = val;
+        break;
+    case SYS_RTCCTRL:
+        s->cntrctl = val;
+        break;
+    case SYS_RTCWRTIE0:
+        s->rtccount = val;
+        break;
+    case SYS_RTCMATCH0:
+        s->rtcmatch[0] = val;
+        break;
+    case SYS_RTCMATCH1:
+        val = s->rtcmatch[1];
+        break;
+    case SYS_RTCMATCH2:
+        val = s->rtcmatch[2];
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps ls7a_rtc_ops = {
+    .read = ls7a_rtc_read,
+    .write = ls7a_rtc_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+
+};
+
+static void toy_timer(void *opaque)
+{
+    LS7A_RTCState *s = LS7A_RTC(opaque);
+
+    if (s->cntrctl & TOY_ENABLE_BIT) {
+            qemu_irq_pulse(s->toy_irq);
+    }
+}
+
+static void ls7a_rtc_realize(DeviceState *dev, Error **errp)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    LS7A_RTCState *d = LS7A_RTC(sbd);
+    memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops,
+                    (void *)d, "ls7a_rtc", 0x100);
+
+    sysbus_init_irq(sbd, &d->toy_irq);
+
+    sysbus_init_mmio(sbd, &d->iomem);
+    d->timer = timer_new_ms(rtc_clock, toy_timer, d);
+    timer_mod(d->timer, qemu_clock_get_ms(rtc_clock) + 100);
+    d->offset = 0;
+
+    create_unimplemented_device("mmio fallback 1", 0x10013ffc, 0x4);
+}
+
+static int ls7a_rtc_pre_save(void *opaque)
+{
+    LS7A_RTCState *s = LS7A_RTC(opaque);
+    struct tm tm;
+    int64_t year_diff, value;
+
+    value = s->toymatch[0];
+    qemu_get_timedate(&tm, s->offset);
+    tm.tm_sec = (value >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK;
+    tm.tm_min = (value >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK;
+    tm.tm_hour = ((value >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK);
+    tm.tm_mday = ((value >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK);
+    tm.tm_mon = ((value >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1;
+    year_diff = ((value >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK);
+    year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK);
+    tm.tm_year = tm.tm_year + year_diff;
+    s->save_alarm_offset = qemu_timedate_diff(&tm) - s->offset;
+
+    return 0;
+}
+
+static int ls7a_rtc_post_load(void *opaque, int version_id)
+{
+    LS7A_RTCState *s = LS7A_RTC(opaque);
+    int64_t expire_time;
+
+    expire_time = qemu_clock_get_ms(rtc_clock) + (s->save_alarm_offset * 1000);
+    timer_mod(s->timer, expire_time);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_ls7a_rtc = {
+    .name = "ls7a_rtc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .pre_save = ls7a_rtc_pre_save,
+    .post_load = ls7a_rtc_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT64(offset, LS7A_RTCState),
+        VMSTATE_INT64(save_alarm_offset, LS7A_RTCState),
+        VMSTATE_UINT32(toymatch[0], LS7A_RTCState),
+        VMSTATE_UINT32(cntrctl, LS7A_RTCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ls7a_rtc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->vmsd = &vmstate_ls7a_rtc;
+    dc->realize = ls7a_rtc_realize;
+    dc->desc = "ls7a rtc";
+}
+
+static const TypeInfo ls7a_rtc_info = {
+    .name          = TYPE_LS7A_RTC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LS7A_RTCState),
+    .class_init    = ls7a_rtc_class_init,
+};
+
+static void ls7a_rtc_register_types(void)
+{
+    type_register_static(&ls7a_rtc_info);
+}
+
+type_init(ls7a_rtc_register_types)
diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
index 8fd8d8f9a7..1d4870d8c4 100644
--- a/hw/rtc/meson.build
+++ b/hw/rtc/meson.build
@@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_rtc.c'))
 softmmu_ss.add(when: 'CONFIG_SUN4V_RTC', if_true: files('sun4v-rtc.c'))
 softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_rtc.c'))
 softmmu_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
+softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
 softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
 
 specific_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index 3b9ad1e175..c724b93b6d 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -39,6 +39,10 @@
 
 #define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
 #define LS7A_UART_BASE          0x1fe001e0
+#define LS7A_RTC_IRQ            (PCH_PIC_IRQ_OFFSET + 3)
+#define LS7A_MISC_REG_BASE      (LS7A_PCH_REG_BASE + 0x00080000)
+#define LS7A_RTC_REG_BASE       (LS7A_MISC_REG_BASE + 0x00050100)
+#define LS7A_RTC_LEN            0x100
 
 struct LS7APCIState {
     /*< private >*/
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 24/27] hw/loongarch: Add default bios startup support.
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (22 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 23/27] hw/loongarch: Add LoongArch ls7a rtc device support Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 25/27] hw/loongarch: Add -kernel and -initrd options support Xiaojuan Yang
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/loongarch/Kconfig             |  4 ++++
 hw/loongarch/fw_cfg.c            | 33 ++++++++++++++++++++++++++++++
 hw/loongarch/fw_cfg.h            | 15 ++++++++++++++
 hw/loongarch/loongson3.c         | 35 ++++++++++++++++++++++++++++++++
 hw/loongarch/meson.build         |  1 +
 include/hw/loongarch/loongarch.h |  8 ++++++++
 6 files changed, 96 insertions(+)
 create mode 100644 hw/loongarch/fw_cfg.c
 create mode 100644 hw/loongarch/fw_cfg.h

diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 6d3506fee9..44319531bc 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -14,3 +14,7 @@ config LOONGSON3_LS7A
     select LOONGARCH_PCH_MSI
     select LOONGARCH_EXTIOI
     select LS7A_RTC
+    select FW_CFG_LOONGARCH
+
+config FW_CFG_LOONGARCH
+    bool
diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c
new file mode 100644
index 0000000000..2a7f8ed0ce
--- /dev/null
+++ b/hw/loongarch/fw_cfg.c
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU fw_cfg helpers (LoongArch specific)
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/loongarch/fw_cfg.h"
+#include "hw/loongarch/loongarch.h"
+#include "hw/nvram/fw_cfg.h"
+#include "sysemu/sysemu.h"
+
+static void fw_cfg_boot_set(void *opaque, const char *boot_device,
+                            Error **errp)
+{
+    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+}
+
+FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms)
+{
+    FWCfgState *fw_cfg;
+    int max_cpus = ms->smp.max_cpus;
+    int smp_cpus = ms->smp.cpus;
+
+    fw_cfg = fw_cfg_init_mem_wide(FW_CFG_ADDR, FW_CFG_ADDR + 8, 8, 0, NULL);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
+
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+    return fw_cfg;
+}
diff --git a/hw/loongarch/fw_cfg.h b/hw/loongarch/fw_cfg.h
new file mode 100644
index 0000000000..7c0de4db4a
--- /dev/null
+++ b/hw/loongarch/fw_cfg.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU fw_cfg helpers (LoongArch specific)
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_FW_CFG_H
+#define HW_LOONGARCH_FW_CFG_H
+
+#include "hw/boards.h"
+#include "hw/nvram/fw_cfg.h"
+
+FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms);
+#endif
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index f86f83c0b8..bc3c1920ef 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -13,6 +13,8 @@
 #include "hw/char/serial.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/qtest.h"
+#include "hw/loader.h"
+#include "elf.h"
 #include "hw/irq.h"
 #include "net/net.h"
 #include "sysemu/runstate.h"
@@ -24,6 +26,9 @@
 #include "hw/intc/loongarch_pch_msi.h"
 #include "hw/pci-host/ls7a.h"
 #include "hw/misc/unimp.h"
+#include "hw/loongarch/fw_cfg.h"
+
+#define LOONGSON3_BIOSNAME "loongarch_bios.bin"
 
 
 static void loongarch_cpu_reset(void *opaque)
@@ -203,6 +208,8 @@ static void loongson3_init(MachineState *machine)
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
     int i;
     PCIBus *pci_bus = NULL;
+    int bios_size;
+    char *filename;
 
     if (!cpu_model) {
         cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
@@ -238,6 +245,11 @@ static void loongson3_init(MachineState *machine)
         qemu_register_reset(loongarch_cpu_reset, cpu);
     }
 
+    if (ram_size < 1 * GiB) {
+        error_report("ram_size must be greater than 1G due to the bios memory layout");
+        exit(1);
+    }
+
     memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
                              machine->ram, 0, 256 * MiB);
     memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
@@ -249,6 +261,28 @@ static void loongson3_init(MachineState *machine)
     memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
     offset += highram_size;
 
+    /* load the BIOS image. */
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
+                              machine->firmware ?: LOONGSON3_BIOSNAME);
+    if (filename) {
+        bios_size = load_image_targphys(filename, LA_BIOS_BASE, LA_BIOS_SIZE);
+        lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
+        rom_set_fw(lams->fw_cfg);
+        g_free(filename);
+    } else {
+        bios_size = -1;
+    }
+
+    if ((bios_size < 0 || bios_size > LA_BIOS_SIZE) && !qtest_enabled()) {
+        error_report("Could not load LOONGARCH bios '%s'", machine->firmware);
+        exit(1);
+    }
+
+
+    memory_region_init_ram(&lams->bios, NULL, "loongarch.bios",
+                           LA_BIOS_SIZE, &error_fatal);
+    memory_region_set_readonly(&lams->bios, true);
+    memory_region_add_subregion(get_system_memory(), LA_BIOS_BASE, &lams->bios);
     /*
      * There are some invalid guest memory access.
      * Create some unimplemented devices to emulate this.
@@ -286,6 +320,7 @@ static void loongarch_class_init(ObjectClass *oc, void *data)
     mc->default_ram_id = "loongarch.ram";
     mc->max_cpus = LOONGARCH_MAX_VCPUS;
     mc->is_default = 1;
+    mc->default_machine_opts = "firmware=loongarch_bios.bin";
     mc->default_kernel_irqchip_split = false;
     mc->block_default_type = IF_VIRTIO;
     mc->default_boot_order = "c";
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index 1db3529cbc..fed69dfb62 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,4 +1,5 @@
 loongarch_ss = ss.source_set()
 loongarch_ss.add(when: 'CONFIG_LOONGSON3_LS7A', if_true: files('loongson3.c'))
+loongarch_ss.add(when: 'CONFIG_FW_CFG_LOONGARCH', if_true: files('fw_cfg.c'))
 
 hw_arch += {'loongarch': loongarch_ss}
diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
index 150403c93d..aab8097f7d 100644
--- a/include/hw/loongarch/loongarch.h
+++ b/include/hw/loongarch/loongarch.h
@@ -32,6 +32,10 @@
 #define VENDOR_REG              0x10
 #define CPUNAME_REG             0x20
 
+#define FW_CFG_ADDR             0x1e020000
+#define LA_BIOS_BASE            0x1c000000
+#define LA_BIOS_SIZE            (4 * 1024 * 1024)
+
 typedef struct LoongArchMachineState {
     /*< private >*/
     MachineState parent_obj;
@@ -40,6 +44,10 @@ typedef struct LoongArchMachineState {
     MemoryRegion system_iocsr;
     MemoryRegion lowmem;
     MemoryRegion highmem;
+    MemoryRegion bios;
+
+    /* State for other subsystems/APIs: */
+    FWCfgState  *fw_cfg;
 } LoongArchMachineState;
 
 #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("loongson3-ls7a")
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 25/27] hw/loongarch: Add -kernel and -initrd options support
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (23 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 24/27] hw/loongarch: Add default bios startup support Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 26/27] hw/loongarch: Add LoongArch smbios support Xiaojuan Yang
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/loongarch/loongson3.c         | 79 ++++++++++++++++++++++++++++++++
 include/hw/loongarch/loongarch.h |  5 ++
 2 files changed, 84 insertions(+)

diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index bc3c1920ef..677d61c262 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -30,6 +30,75 @@
 
 #define LOONGSON3_BIOSNAME "loongarch_bios.bin"
 
+static struct _loaderparams {
+    unsigned long ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
+{
+    return addr & 0x1fffffffll;
+}
+
+static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg)
+{
+    int64_t kernel_entry, kernel_low, kernel_high, initrd_size = 0;
+    long kernel_size;
+    ram_addr_t initrd_offset = 0;
+    void *cmdline_buf;
+    int ret = 0;
+
+    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
+                           cpu_loongarch_virt_to_phys, NULL,
+                           (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
+                           (uint64_t *)&kernel_high, NULL, 0,
+                           EM_LOONGARCH, 1, 0);
+
+    if (kernel_size < 0) {
+        error_report("could not load kernel '%s': %s",
+                     loaderparams.kernel_filename,
+                     load_elf_strerror(kernel_size));
+        exit(1);
+    }
+
+    fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ENTRY, kernel_entry);
+
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size(loaderparams.initrd_filename);
+
+        if (initrd_size > 0) {
+            initrd_offset = MAX(INITRD_BASE,
+                                ROUND_UP(kernel_high, INITRD_PAGE_SIZE));
+            if (initrd_offset + initrd_size > 0x10000000) {
+                error_report("ramdisk '%s' is too big",
+                             loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                                              initrd_offset,
+                                              loaderparams.ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong) -1) {
+            error_report("could not load initial ram disk '%s'",
+                         loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+
+    cmdline_buf = g_malloc0(COMMAND_LINE_SIZE);
+    if (initrd_size > 0)
+        ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE,
+                "initrd=0x%lx,%li %s", initrd_offset,
+                initrd_size, loaderparams.kernel_cmdline));
+    else
+        ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE, "%s",
+                loaderparams.kernel_cmdline));
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, ret);
+    fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, (const char *)cmdline_buf);
+}
 
 static void loongarch_cpu_reset(void *opaque)
 {
@@ -200,6 +269,9 @@ static void network_init(PCIBus *pci_bus)
 static void loongson3_init(MachineState *machine)
 {
     const char *cpu_model = machine->cpu_type;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     LoongArchCPU *cpu;
     ram_addr_t offset = 0;
     ram_addr_t ram_size = machine->ram_size;
@@ -278,6 +350,13 @@ static void loongson3_init(MachineState *machine)
         exit(1);
     }
 
+    if (kernel_filename) {
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        fw_cfg_add_kernel_info(lams->fw_cfg);
+    }
 
     memory_region_init_ram(&lams->bios, NULL, "loongarch.bios",
                            LA_BIOS_SIZE, &error_fatal);
diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
index aab8097f7d..fd09d987b2 100644
--- a/include/hw/loongarch/loongarch.h
+++ b/include/hw/loongarch/loongarch.h
@@ -36,6 +36,11 @@
 #define LA_BIOS_BASE            0x1c000000
 #define LA_BIOS_SIZE            (4 * 1024 * 1024)
 
+/* Kernels can be configured with 64KB pages */
+#define INITRD_PAGE_SIZE        (64 * KiB)
+#define INITRD_BASE             0x04000000
+#define COMMAND_LINE_SIZE       4096
+
 typedef struct LoongArchMachineState {
     /*< private >*/
     MachineState parent_obj;
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 26/27] hw/loongarch: Add LoongArch smbios support
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (24 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 25/27] hw/loongarch: Add -kernel and -initrd options support Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-04 12:07 ` [RFC PATCH v3 27/27] hw/loongarch: Add LoongArch acpi support Xiaojuan Yang
  2021-12-13  3:13 ` [RFC PATCH v3 00/27] Add LoongArch softmmu support yangxiaojuan
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/loongarch/Kconfig             |  1 +
 hw/loongarch/loongson3.c         | 41 ++++++++++++++++++++++++++++++++
 include/hw/loongarch/loongarch.h |  1 +
 3 files changed, 43 insertions(+)

diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 44319531bc..26138516e3 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -15,6 +15,7 @@ config LOONGSON3_LS7A
     select LOONGARCH_EXTIOI
     select LS7A_RTC
     select FW_CFG_LOONGARCH
+    select SMBIOS
 
 config FW_CFG_LOONGARCH
     bool
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 677d61c262..83fb6b8f0f 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -27,6 +27,7 @@
 #include "hw/pci-host/ls7a.h"
 #include "hw/misc/unimp.h"
 #include "hw/loongarch/fw_cfg.h"
+#include "hw/firmware/smbios.h"
 
 #define LOONGSON3_BIOSNAME "loongarch_bios.bin"
 
@@ -100,6 +101,42 @@ static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg)
     fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, (const char *)cmdline_buf);
 }
 
+static void loongarch_build_smbios(LoongArchMachineState *lams)
+{
+    MachineState *ms = MACHINE(lams);
+    MachineClass *mc = MACHINE_GET_CLASS(lams);
+    uint8_t *smbios_tables, *smbios_anchor;
+    size_t smbios_tables_len, smbios_anchor_len;
+    const char *product = "QEMU Virtual Machine";
+
+    if (!lams->fw_cfg) {
+        return;
+    }
+
+    product = "Loongson-3A5000-7A1000-TCG";
+
+    smbios_set_defaults("QEMU", product, mc->name, false,
+                        true, SMBIOS_ENTRY_POINT_30);
+
+    smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len,
+                      &smbios_anchor, &smbios_anchor_len, &error_fatal);
+
+    if (smbios_anchor) {
+        fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-tables",
+                        smbios_tables, smbios_tables_len);
+        fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-anchor",
+                        smbios_anchor, smbios_anchor_len);
+    }
+}
+
+static
+void loongarch_machine_done(Notifier *notifier, void *data)
+{
+    LoongArchMachineState *lams = container_of(notifier,
+                                        LoongArchMachineState, machine_done);
+    loongarch_build_smbios(lams);
+}
+
 static void loongarch_cpu_reset(void *opaque)
 {
     LoongArchCPU *cpu = opaque;
@@ -362,6 +399,10 @@ static void loongson3_init(MachineState *machine)
                            LA_BIOS_SIZE, &error_fatal);
     memory_region_set_readonly(&lams->bios, true);
     memory_region_add_subregion(get_system_memory(), LA_BIOS_BASE, &lams->bios);
+
+    lams->machine_done.notify = loongarch_machine_done;
+    qemu_add_machine_init_done_notifier(&lams->machine_done);
+
     /*
      * There are some invalid guest memory access.
      * Create some unimplemented devices to emulate this.
diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
index fd09d987b2..bda7dd645d 100644
--- a/include/hw/loongarch/loongarch.h
+++ b/include/hw/loongarch/loongarch.h
@@ -52,6 +52,7 @@ typedef struct LoongArchMachineState {
     MemoryRegion bios;
 
     /* State for other subsystems/APIs: */
+    Notifier machine_done;
     FWCfgState  *fw_cfg;
 } LoongArchMachineState;
 
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [RFC PATCH v3 27/27] hw/loongarch: Add LoongArch acpi support
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (25 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 26/27] hw/loongarch: Add LoongArch smbios support Xiaojuan Yang
@ 2021-12-04 12:07 ` Xiaojuan Yang
  2021-12-13  3:13 ` [RFC PATCH v3 00/27] Add LoongArch softmmu support yangxiaojuan
  27 siblings, 0 replies; 58+ messages in thread
From: Xiaojuan Yang @ 2021-12-04 12:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, thuth, chenhuacai, philmd, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, yangxiaojuan,
	alistair.francis, maobibo, pbonzini, richard.henderson,
	alex.bennee, gaosong

Add a simple acpi model for LoongArch cpu
More complex functions will be added later

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/acpi/Kconfig                  |   4 +
 hw/acpi/ls7a.c                   | 349 +++++++++++++++++
 hw/acpi/meson.build              |   1 +
 hw/loongarch/Kconfig             |   2 +
 hw/loongarch/acpi-build.c        | 637 +++++++++++++++++++++++++++++++
 hw/loongarch/loongson3.c         |  50 +++
 hw/loongarch/meson.build         |   1 +
 include/hw/acpi/ls7a.h           |  53 +++
 include/hw/loongarch/loongarch.h |   6 +
 include/hw/pci-host/ls7a.h       |   7 +
 10 files changed, 1110 insertions(+)
 create mode 100644 hw/acpi/ls7a.c
 create mode 100644 hw/loongarch/acpi-build.c
 create mode 100644 include/hw/acpi/ls7a.h

diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig
index 622b0b50b7..30f887d479 100644
--- a/hw/acpi/Kconfig
+++ b/hw/acpi/Kconfig
@@ -11,6 +11,10 @@ config ACPI_X86
     select ACPI_PIIX4
     select ACPI_PCIHP
 
+config ACPI_LOONGARCH
+    bool
+    select ACPI
+
 config ACPI_X86_ICH
     bool
     select ACPI_X86
diff --git a/hw/acpi/ls7a.c b/hw/acpi/ls7a.c
new file mode 100644
index 0000000000..37cec6517d
--- /dev/null
+++ b/hw/acpi/ls7a.c
@@ -0,0 +1,349 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch ACPI implementation
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/sysemu.h"
+#include "hw/hw.h"
+#include "hw/irq.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/ls7a.h"
+#include "hw/nvram/fw_cfg.h"
+#include "qemu/config-file.h"
+#include "qapi/opts-visitor.h"
+#include "qapi/qapi-events-run-state.h"
+#include "qapi/error.h"
+#include "hw/pci-host/ls7a.h"
+#include "hw/mem/pc-dimm.h"
+#include "hw/mem/nvdimm.h"
+#include "migration/vmstate.h"
+
+static void ls7a_pm_update_sci_fn(ACPIREGS *regs)
+{
+    LS7APCIPMRegs *pm = container_of(regs, LS7APCIPMRegs, acpi_regs);
+    acpi_update_sci(&pm->acpi_regs, pm->irq);
+}
+
+static uint64_t ls7a_gpe_readb(void *opaque, hwaddr addr, unsigned width)
+{
+    LS7APCIPMRegs *pm = opaque;
+    return acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
+}
+
+static void ls7a_gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
+                            unsigned width)
+{
+    LS7APCIPMRegs *pm = opaque;
+    acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
+    acpi_update_sci(&pm->acpi_regs, pm->irq);
+}
+
+static const MemoryRegionOps ls7a_gpe_ops = {
+    .read = ls7a_gpe_readb,
+    .write = ls7a_gpe_writeb,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 8,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 1,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+#define VMSTATE_GPE_ARRAY(_field, _state)                            \
+ {                                                                   \
+     .name       = (stringify(_field)),                              \
+     .version_id = 0,                                                \
+     .num        = ACPI_GPE0_LEN,                                    \
+     .info       = &vmstate_info_uint8,                              \
+     .size       = sizeof(uint8_t),                                  \
+     .flags      = VMS_ARRAY | VMS_POINTER,                          \
+     .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
+ }
+
+static uint64_t ls7a_reset_readw(void *opaque, hwaddr addr, unsigned width)
+{
+    return 0;
+}
+
+static void ls7a_reset_writew(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned width)
+{
+    if (val & 1) {
+        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+        return;
+    }
+}
+
+static const MemoryRegionOps ls7a_reset_ops = {
+    .read = ls7a_reset_readw,
+    .write = ls7a_reset_writew,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+const VMStateDescription vmstate_ls7a_pm = {
+    .name = "ls7a_pm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16(acpi_regs.pm1.evt.sts, LS7APCIPMRegs),
+        VMSTATE_UINT16(acpi_regs.pm1.evt.en, LS7APCIPMRegs),
+        VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, LS7APCIPMRegs),
+        VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, LS7APCIPMRegs),
+        VMSTATE_INT64(acpi_regs.tmr.overflow_time, LS7APCIPMRegs),
+        VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, LS7APCIPMRegs),
+        VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, LS7APCIPMRegs),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static inline int64_t acpi_pm_tmr_get_clock(void)
+{
+    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY,
+                    NANOSECONDS_PER_SECOND);
+}
+
+static uint32_t acpi_pm_tmr_get(ACPIREGS *ar)
+{
+    uint32_t d = acpi_pm_tmr_get_clock();
+    return d & 0xffffff;
+}
+
+static void acpi_pm_tmr_timer(void *opaque)
+{
+    ACPIREGS *ar = opaque;
+    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL);
+    ar->tmr.update_sci(ar);
+}
+
+static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width)
+{
+    return acpi_pm_tmr_get(opaque);
+}
+
+static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned width)
+{
+}
+
+static const MemoryRegionOps acpi_pm_tmr_ops = {
+    .read = acpi_pm_tmr_read,
+    .write = acpi_pm_tmr_write,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ls7a_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
+                             MemoryRegion *parent, uint64_t offset)
+{
+    ar->tmr.update_sci = update_sci;
+    ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar);
+    memory_region_init_io(&ar->tmr.io, memory_region_owner(parent),
+                          &acpi_pm_tmr_ops, ar, "acpi-tmr", 4);
+    memory_region_add_subregion(parent, offset, &ar->tmr.io);
+}
+
+static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val)
+{
+    uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar);
+    if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
+        /* if TMRSTS is reset, then compute the new overflow time */
+        acpi_pm_tmr_calc_overflow_time(ar);
+    }
+    ar->pm1.evt.sts &= ~val;
+}
+
+static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width)
+{
+    ACPIREGS *ar = opaque;
+    switch (addr) {
+    case 0:
+        return acpi_pm1_evt_get_sts(ar);
+    case 4:
+        return ar->pm1.evt.en;
+    default:
+        return 0;
+    }
+}
+
+static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val)
+{
+    ar->pm1.evt.en = val;
+    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC,
+                              val & ACPI_BITMASK_RT_CLOCK_ENABLE);
+    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER,
+                              val & ACPI_BITMASK_TIMER_ENABLE);
+}
+
+static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned width)
+{
+    ACPIREGS *ar = opaque;
+    switch (addr) {
+    case 0:
+        acpi_pm1_evt_write_sts(ar, val);
+        ar->pm1.evt.update_sci(ar);
+        break;
+    case 4:
+        acpi_pm1_evt_write_en(ar, val);
+        ar->pm1.evt.update_sci(ar);
+        break;
+    }
+}
+
+static const MemoryRegionOps acpi_pm_evt_ops = {
+    .read = acpi_pm_evt_read,
+    .write = acpi_pm_evt_write,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ls7a_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
+                              MemoryRegion *parent, uint64_t offset)
+{
+    ar->pm1.evt.update_sci = update_sci;
+    memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent),
+                          &acpi_pm_evt_ops, ar, "acpi-evt", 8);
+    memory_region_add_subregion(parent, offset, &ar->pm1.evt.io);
+}
+
+static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width)
+{
+    ACPIREGS *ar = opaque;
+    return ar->pm1.cnt.cnt;
+}
+
+/* ACPI PM1aCNT */
+static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
+{
+    ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
+
+    if (val & ACPI_BITMASK_SLEEP_ENABLE) {
+        /* Change suspend type */
+        uint16_t sus_typ = (val >> 10) & 7;
+        switch (sus_typ) {
+        /* Not support s3 s4 yet */
+        case 7: /* Soft power off */
+            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned width)
+{
+    acpi_pm1_cnt_write(opaque, val);
+}
+
+static const MemoryRegionOps acpi_pm_cnt_ops = {
+    .read = acpi_pm_cnt_read,
+    .write = acpi_pm_cnt_write,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void acpi_notify_wakeup(Notifier *notifier, void *data)
+{
+    ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup);
+    WakeupReason *reason = data;
+
+    switch (*reason) {
+    case QEMU_WAKEUP_REASON_RTC:
+        ar->pm1.evt.sts |=
+            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS);
+        break;
+    case QEMU_WAKEUP_REASON_PMTIMER:
+        ar->pm1.evt.sts |=
+            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS);
+        break;
+    case QEMU_WAKEUP_REASON_OTHER:
+        /*
+         * ACPI_BITMASK_WAKE_STATUS should be set on resume.
+         * Pretend that resume was caused by power button
+         */
+        ar->pm1.evt.sts |=
+            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
+        break;
+    default:
+        break;
+    }
+}
+
+static void ls7a_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent,
+                              uint64_t offset)
+{
+    ar->wakeup.notify = acpi_notify_wakeup;
+    qemu_register_wakeup_notifier(&ar->wakeup);
+    memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent),
+                          &acpi_pm_cnt_ops, ar, "acpi-cnt", 4);
+    memory_region_add_subregion(parent, offset, &ar->pm1.cnt.io);
+}
+
+static void ls7a_pm_reset(void *opaque)
+{
+    LS7APCIPMRegs *pm = opaque;
+
+    acpi_pm1_evt_reset(&pm->acpi_regs);
+    acpi_pm1_cnt_reset(&pm->acpi_regs);
+    acpi_pm_tmr_reset(&pm->acpi_regs);
+    acpi_gpe_reset(&pm->acpi_regs);
+
+    acpi_update_sci(&pm->acpi_regs, pm->irq);
+}
+
+static void pm_powerdown_req(Notifier *n, void *opaque)
+{
+    LS7APCIPMRegs *pm = container_of(n, LS7APCIPMRegs, powerdown_notifier);
+
+    acpi_pm1_evt_power_down(&pm->acpi_regs);
+}
+
+void ls7a_pm_init(PCIDevice *pci_dev, LS7APCIPMRegs *pm, DeviceState *pch_pic)
+{
+    unsigned long base, gpe_len;
+
+    /*
+     * ls7a board acpi hardware info, including
+     * acpi system io base address
+     * acpi gpe length
+     * acpi sci irq number
+     */
+    base = ACPI_IO_BASE;
+    gpe_len = ACPI_GPE0_LEN;
+
+    pm->irq = qdev_get_gpio_in(pch_pic, (ACPI_SCI_IRQ - 64));
+    memory_region_init(&pm->iomem, OBJECT(pci_dev), "ls7a_pm", ACPI_IO_SIZE);
+    memory_region_add_subregion(get_system_memory(), base, &pm->iomem);
+
+    ls7a_pm_tmr_init(&pm->acpi_regs, ls7a_pm_update_sci_fn,
+                     &pm->iomem, LS7A_PM_TMR_BLK);
+    ls7a_pm1_evt_init(&pm->acpi_regs, ls7a_pm_update_sci_fn,
+                      &pm->iomem, LS7A_PM_EVT_BLK);
+    ls7a_pm1_cnt_init(&pm->acpi_regs, &pm->iomem, LS7A_PM_CNT_BLK);
+
+    acpi_gpe_init(&pm->acpi_regs, gpe_len);
+    memory_region_init_io(&pm->iomem_gpe, OBJECT(pci_dev), &ls7a_gpe_ops, pm,
+                          "acpi-gpe0", gpe_len);
+    memory_region_add_subregion(&pm->iomem, LS7A_GPE0_STS_REG, &pm->iomem_gpe);
+
+    memory_region_init_io(&pm->iomem_reset, OBJECT(pci_dev),
+                          &ls7a_reset_ops, pm, "acpi-reset", 4);
+    memory_region_add_subregion(&pm->iomem, LS7A_GPE0_RESET_REG,
+                                &pm->iomem_reset);
+
+    qemu_register_reset(ls7a_pm_reset, pm);
+
+    pm->powerdown_notifier.notify = pm_powerdown_req;
+    qemu_register_powerdown_notifier(&pm->powerdown_notifier);
+}
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index adf6347bc4..52f851d52b 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -25,6 +25,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c'))
 acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c'))
 acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))
 acpi_ss.add(when: 'CONFIG_TPM', if_true: files('tpm.c'))
+acpi_ss.add(when: 'CONFIG_ACPI_LOONGARCH', if_true: files('ls7a.c'))
 softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c'))
 softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss)
 softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c',
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 26138516e3..c54f4ac241 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -16,6 +16,8 @@ config LOONGSON3_LS7A
     select LS7A_RTC
     select FW_CFG_LOONGARCH
     select SMBIOS
+    select ACPI_LOONGARCH
+    select ACPI_PCI
 
 config FW_CFG_LOONGARCH
     bool
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
new file mode 100644
index 0000000000..3f2fcf486f
--- /dev/null
+++ b/hw/loongarch/acpi-build.c
@@ -0,0 +1,637 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Support for generating ACPI tables and passing them to Guests
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/bitmap.h"
+#include "hw/pci/pci.h"
+#include "hw/core/cpu.h"
+#include "target/loongarch/cpu.h"
+#include "hw/acpi/acpi-defs.h"
+#include "hw/acpi/acpi.h"
+#include "hw/nvram/fw_cfg.h"
+#include "hw/acpi/bios-linker-loader.h"
+#include "migration/vmstate.h"
+#include "hw/mem/memory-device.h"
+#include "sysemu/reset.h"
+
+/* Supported chipsets: */
+#include "hw/pci-host/ls7a.h"
+#include "hw/loongarch/loongarch.h"
+#include "hw/acpi/aml-build.h"
+
+#include "hw/acpi/utils.h"
+#include "hw/acpi/pci.h"
+
+#include "qom/qom-qobject.h"
+
+#include "hw/acpi/ls7a.h"
+
+#define ACPI_BUILD_ALIGN_SIZE             0x1000
+#define ACPI_BUILD_TABLE_SIZE             0x20000
+
+#define DEBUG_ACPI_BUILD
+
+#ifdef DEBUG_ACPI_BUILD
+#define ACPI_BUILD_DPRINTF(fmt, ...)        \
+    do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define ACPI_BUILD_DPRINTF(fmt, ...)
+#endif
+
+static void init_common_fadt_data(AcpiFadtData *data)
+{
+    AmlAddressSpace as = AML_AS_SYSTEM_MEMORY;
+    uint64_t base = LS7A_ACPI_REG_BASE;
+    AcpiFadtData fadt = {
+        .rev = 3,
+        .flags =
+            (1 << ACPI_FADT_F_WBINVD) |
+            (1 << ACPI_FADT_F_PROC_C1) |
+            (1 << ACPI_FADT_F_SLP_BUTTON) |
+            (1 << ACPI_FADT_F_TMR_VAL_EXT) |
+            (1 << ACPI_FADT_F_RESET_REG_SUP) ,
+        .plvl2_lat = 0xfff /* C2 state not supported */,
+        .plvl3_lat = 0xfff /* C3 state not supported */,
+        .smi_cmd = 0x00,
+        .sci_int = ACPI_SCI_IRQ,
+        .acpi_enable_cmd = 0x00,
+        .acpi_disable_cmd = 0x00,
+        .pm1a_evt = { .space_id = as, .bit_width = 8 * 8,
+                      .address = base + LS7A_PM_EVT_BLK },
+        .pm1a_cnt = { .space_id = as, .bit_width = 4 * 8,
+                      .address = base + LS7A_PM_CNT_BLK },
+        .pm_tmr = { .space_id = as, .bit_width = 4 * 8,
+                    .address = base + LS7A_PM_TMR_BLK },
+        .gpe0_blk = { .space_id = as, .bit_width = 8 * 8,
+                      .address = base + LS7A_GPE0_STS_REG},
+        .reset_reg = { .space_id = as, .bit_width = 4 * 8,
+                       .address = base + LS7A_GPE0_RESET_REG},
+        .reset_val = 0x1,
+    };
+    *data = fadt;
+}
+
+static void acpi_align_size(GArray *blob, unsigned align)
+{
+    /*
+     * Align size to multiple of given size. This reduces the chance
+     * we need to change size in the future (breaking cross version migration).
+     */
+    g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
+}
+
+/*
+ * ACPI spec 1.0b,
+ * 5.2.6 Firmware ACPI Control Structure
+ */
+static void
+build_facs(GArray *table_data)
+{
+    const char *sig = "FACS";
+    const uint8_t reserved[40] = {};
+
+    g_array_append_vals(table_data, sig, 4); /* Signature */
+    build_append_int_noprefix(table_data, 64, 4); /* Length */
+    build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */
+    build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */
+    build_append_int_noprefix(table_data, 0, 4); /* Global Lock */
+    build_append_int_noprefix(table_data, 0, 4); /* Flags */
+    g_array_append_vals(table_data, reserved, 40); /* Reserved */
+}
+
+static void
+build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams)
+{
+    MachineState *ms = MACHINE(lams);
+    int i;
+    AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id,
+                        .oem_table_id = lams->oem_table_id };
+
+    acpi_table_begin(&table, table_data);
+
+    /* Local APIC Address */
+    build_append_int_noprefix(table_data, 0, 4);
+    build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
+
+    for (i = 0; i < ms->smp.cpus; i++) {
+        /* Rev 1.0b, Table 5-13 Processor Core Interrupt Controller Structure */
+        build_append_int_noprefix(table_data, 17, 1);       /* Type */
+        build_append_int_noprefix(table_data, 15, 1);       /* Length */
+        build_append_int_noprefix(table_data, 1, 1);       /* Version */
+        build_append_int_noprefix(table_data, i + 1, 4);     /* ACPI Processor ID */
+        build_append_int_noprefix(table_data, i, 4); /* Core ID */
+        build_append_int_noprefix(table_data, 1, 4); /* Flags */
+    }
+
+    /* Rev 1.0b, Table 5-13 Extend I/O Interrupt Controller Structure */
+    build_append_int_noprefix(table_data, 20, 1);       /* Type */
+    build_append_int_noprefix(table_data, 13, 1);        /* Length */
+    build_append_int_noprefix(table_data, 1, 1);        /* Version */
+    build_append_int_noprefix(table_data, 3, 1);        /* Cascade */
+    build_append_int_noprefix(table_data, 0, 1);        /* Node */
+    build_append_int_noprefix(table_data, 0xffff, 8);   /* Node map */
+
+    /* Rev 1.0b, Table 5-13 MSI Interrupt Controller Structure */
+    build_append_int_noprefix(table_data, 21, 1);       /* Type */
+    build_append_int_noprefix(table_data, 19, 1);       /* Length */
+    build_append_int_noprefix(table_data, 1, 1);        /* Version */
+    build_append_int_noprefix(table_data, 0x2ff00000, 8);        /* Address */
+    build_append_int_noprefix(table_data, 0x40, 4);        /* Start */
+    build_append_int_noprefix(table_data, 0xc0, 4);        /* Count */
+
+    /* Rev 1.0b, Table 5-13 Bridge I/O Interrupt Controller Structure */
+    build_append_int_noprefix(table_data, 22, 1);       /* Type */
+    build_append_int_noprefix(table_data, 17, 1);       /* Length */
+    build_append_int_noprefix(table_data, 1, 1);        /* Version */
+    build_append_int_noprefix(table_data, 0x10000000, 8);        /* Address */
+    build_append_int_noprefix(table_data, 0x1000, 2);        /* Size */
+    build_append_int_noprefix(table_data, 0, 2);        /* Id */
+    build_append_int_noprefix(table_data, 0x40, 2);   /* Base */
+
+    acpi_table_end(linker, &table);
+}
+
+/*
+ * ACPI spec, Revision 3.0
+ * 5.2.15 System Resource Affinity Table (SRAT)
+ */
+static void
+build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
+{
+    uint64_t i, mem_len, mem_base;
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+    MachineState *ms = MACHINE(lams);
+    AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
+                        .oem_table_id = lams->oem_table_id };
+
+    acpi_table_begin(&table, table_data);
+    build_append_int_noprefix(table_data, 1, 4); /* Reserved */
+    build_append_int_noprefix(table_data, 0, 8); /* Reserved */
+
+    for (i = 0; i < ms->smp.cpus; ++i) {
+        /* 5.2.15.1 Processor Local APIC/SAPIC Affinity Structure */
+        build_append_int_noprefix(table_data, 0, 1);  /* Type  */
+        build_append_int_noprefix(table_data, 16, 1); /* Length */
+        /* Proximity Domain [7:0] */
+        build_append_int_noprefix(table_data, 0, 1);
+        build_append_int_noprefix(table_data, i, 1); /* APIC ID */
+        /* Flags, Table 5-36 */
+        build_append_int_noprefix(table_data, 1, 4);
+        build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */
+        /* Proximity Domain [31:8] */
+        build_append_int_noprefix(table_data, 0, 3);
+        build_append_int_noprefix(table_data, 0, 4); /* Reserved */
+    }
+
+    mem_base = 0;
+    mem_len = 0x10000000;
+    build_srat_memory(table_data, mem_base, mem_len,
+                        0, MEM_AFFINITY_ENABLED);
+
+    mem_base = 0x90000000;
+    mem_len = machine->ram_size - 0x10000000;
+    build_srat_memory(table_data, mem_base, mem_len,
+                            0, MEM_AFFINITY_ENABLED);
+
+    acpi_table_end(linker, &table);
+}
+
+typedef
+struct AcpiBuildState {
+    /* Copy of table in RAM (for patching). */
+    MemoryRegion *table_mr;
+    /* Is table patched? */
+    uint8_t patched;
+    void *rsdp;
+    MemoryRegion *rsdp_mr;
+    MemoryRegion *linker_mr;
+} AcpiBuildState;
+
+static void build_ls7a_pci0_int(Aml *table)
+{
+    Aml *sb_scope = aml_scope("_SB");
+    Aml *pci0_scope = aml_scope("PCI0");
+    Aml *prt_pkg = aml_varpackage(128);
+    int slot, pin;
+
+    for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+        for (pin = 0; pin < PCI_NUM_PINS; pin++) {
+            Aml *pkg = aml_package(4);
+            aml_append(pkg, aml_int((slot << 16) | 0xFFFF));
+            aml_append(pkg, aml_int(pin));
+            aml_append(pkg, aml_int(0));
+            aml_append(pkg, aml_int(80 + (slot * 4 + pin) % LS7A_PCI_IRQS));
+            aml_append(prt_pkg, pkg);
+        }
+    }
+    aml_append(pci0_scope, aml_name_decl("_PRT", prt_pkg));
+    aml_append(sb_scope, pci0_scope);
+    aml_append(table, sb_scope);
+}
+
+static void build_dbg_aml(Aml *table)
+{
+    Aml *field;
+    Aml *method;
+    Aml *while_ctx;
+    Aml *scope = aml_scope("\\");
+    Aml *buf = aml_local(0);
+    Aml *len = aml_local(1);
+    Aml *idx = aml_local(2);
+
+    aml_append(scope,
+       aml_operation_region("DBG", AML_SYSTEM_IO, aml_int(0x0402), 0x01));
+    field = aml_field("DBG", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
+    aml_append(field, aml_named_field("DBGB", 8));
+    aml_append(scope, field);
+
+    method = aml_method("DBUG", 1, AML_NOTSERIALIZED);
+
+    aml_append(method, aml_to_hexstring(aml_arg(0), buf));
+    aml_append(method, aml_to_buffer(buf, buf));
+    aml_append(method, aml_subtract(aml_sizeof(buf), aml_int(1), len));
+    aml_append(method, aml_store(aml_int(0), idx));
+
+    while_ctx = aml_while(aml_lless(idx, len));
+    aml_append(while_ctx,
+        aml_store(aml_derefof(aml_index(buf, idx)), aml_name("DBGB")));
+    aml_append(while_ctx, aml_increment(idx));
+    aml_append(method, while_ctx);
+    aml_append(method, aml_store(aml_int(0x0A), aml_name("DBGB")));
+    aml_append(scope, method);
+    aml_append(table, scope);
+}
+
+static Aml *build_ls7a_osc_method(void)
+{
+    Aml *if_ctx;
+    Aml *if_ctx2;
+    Aml *else_ctx;
+    Aml *method;
+    Aml *a_cwd1 = aml_name("CDW1");
+    Aml *a_ctrl = aml_local(0);
+
+    method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
+    aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
+
+    if_ctx = aml_if(aml_equal(
+        aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")));
+    aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
+    aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
+    aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl));
+
+    /*
+     * Always allow native PME, AER (no dependencies)
+     * Allow SHPC (PCI bridges can have SHPC controller)
+     */
+    aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl));
+
+    if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
+    /* Unknown revision */
+    aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1));
+    aml_append(if_ctx, if_ctx2);
+
+    if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
+    /* Capabilities bits were masked */
+    aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1));
+    aml_append(if_ctx, if_ctx2);
+
+    /* Update DWORD3 in the buffer */
+    aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3")));
+    aml_append(method, if_ctx);
+
+    else_ctx = aml_else();
+    /* Unrecognized UUID */
+    aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1));
+    aml_append(method, else_ctx);
+
+    aml_append(method, aml_return(aml_arg(3)));
+    return method;
+}
+
+static void build_ls7a_uart_device_aml(Aml *table)
+{
+    Aml *dev;
+    Aml *crs;
+    Aml *pkg0, *pkg1, *pkg2;
+    uint32_t uart_irq = LS7A_UART_IRQ;
+
+    Aml *scope = aml_scope("_SB");
+    dev = aml_device("COMA");
+    aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
+    aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+    aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
+    crs = aml_resource_template();
+    aml_append(crs,
+        aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+                         AML_NON_CACHEABLE, AML_READ_WRITE,
+                         0, 0x1FE001E0, 0x1FE001E7, 0, 0x8));
+    aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+                                  AML_SHARED, &uart_irq, 1));
+    aml_append(dev, aml_name_decl("_CRS", crs));
+    pkg0 = aml_package(0x2);
+    aml_append(pkg0, aml_int(0x05F5E100));
+    aml_append(pkg0, aml_string("clock-frenquency"));
+    pkg1 = aml_package(0x1);
+    aml_append(pkg1, pkg0);
+    pkg2 = aml_package(0x2);
+    aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301"));
+    aml_append(pkg2, pkg1);
+    aml_append(dev, aml_name_decl("_DSD", pkg2));
+    aml_append(scope, dev);
+    aml_append(table, scope);
+}
+
+static void
+build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
+{
+    Aml *dsdt, *sb_scope, *scope, *dev, *crs, *pkg;
+    uint64_t base = LS7A_ACPI_REG_BASE;
+    int root_bus_limit = 0x7F;
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+    AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
+                        .oem_table_id = lams->oem_table_id };
+
+    acpi_table_begin(&table, table_data);
+
+    dsdt = init_aml_allocator();
+
+    build_dbg_aml(dsdt);
+
+    sb_scope = aml_scope("_SB");
+    dev = aml_device("PCI0");
+    aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
+    aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
+    aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
+    aml_append(dev, aml_name_decl("_BBN", aml_int(0)));
+    aml_append(dev, aml_name_decl("_UID", aml_int(1)));
+    aml_append(dev, build_ls7a_osc_method());
+    aml_append(sb_scope, dev);
+    aml_append(dsdt, sb_scope);
+
+    build_ls7a_pci0_int(dsdt);
+    build_ls7a_uart_device_aml(dsdt);
+
+    scope =  aml_scope("_GPE");
+    {
+        aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006")));
+    }
+    aml_append(dsdt, scope);
+
+    scope = aml_scope("\\_SB.PCI0");
+    /* Build PCI0._CRS */
+    crs = aml_resource_template();
+    aml_append(crs,
+        aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
+                            0x0000, 0x0, root_bus_limit,
+                            0x0000, root_bus_limit + 1));
+    aml_append(crs,
+        aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED,
+                    AML_POS_DECODE, AML_ENTIRE_RANGE,
+                    0x0000, 0x4000, 0xFFFF, 0x18000000, 0xC000));
+    aml_append(crs,
+        aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+                         AML_CACHEABLE, AML_READ_WRITE,
+                         0, LS7A_PCI_MEM_BASE, LS7A_PCI_MEM_BASE + LS7A_PCI_MEM_SIZE,
+                         0, LS7A_PCI_MEM_BASE));
+    aml_append(scope, aml_name_decl("_CRS", crs));
+
+    /* Reserve GPE0 block resources */
+    dev = aml_device("GPE0");
+    aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06")));
+    aml_append(dev, aml_name_decl("_UID", aml_string("GPE0 resources")));
+    /* Device present, functioning, decoding, not shown in UI */
+    aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
+    crs = aml_resource_template();
+    aml_append(crs,
+        aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+                        AML_CACHEABLE, AML_READ_WRITE,
+                        0, base + LS7A_GPE0_STS_REG,
+                        base + LS7A_GPE0_STS_REG + 0x3, 0, 0x4));
+    aml_append(dev, aml_name_decl("_CRS", crs));
+    aml_append(scope, dev);
+    aml_append(dsdt, scope);
+
+    scope = aml_scope("\\");
+    pkg = aml_package(4);
+    aml_append(pkg, aml_int(7)); /* PM1a_CNT.SLP_TYP */
+    aml_append(pkg, aml_int(7)); /* PM1b_CNT.SLP_TYP not impl. */
+    aml_append(pkg, aml_int(0)); /* Reserved */
+    aml_append(pkg, aml_int(0)); /* Reserved */
+    aml_append(scope, aml_name_decl("_S5", pkg));
+    aml_append(dsdt, scope);
+
+    /* Copy AML table into ACPI tables blob and patch header there */
+    g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
+    acpi_table_end(linker, &table);
+    free_aml_allocator();
+}
+
+static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+    GArray *table_offsets;
+    AcpiFadtData fadt_data;
+    unsigned facs, rsdt, fadt, dsdt;
+    uint8_t *u;
+    size_t aml_len = 0;
+    GArray *tables_blob = tables->table_data;
+
+    init_common_fadt_data(&fadt_data);
+
+    table_offsets = g_array_new(false, true /* Clear */,
+                                        sizeof(uint32_t));
+    ACPI_BUILD_DPRINTF("init ACPI tables\n");
+
+    bios_linker_loader_alloc(tables->linker,
+                             ACPI_BUILD_TABLE_FILE, tables_blob,
+                             64 /* Ensure FACS is aligned */,
+                             false /* High memory */);
+
+    /*
+     * FACS is pointed to by FADT.
+     * We place it first since it's the only table that has alignment
+     * requirements.
+     */
+    facs = tables_blob->len;
+    build_facs(tables_blob);
+
+    /* DSDT is pointed to by FADT */
+    dsdt = tables_blob->len;
+    build_dsdt(tables_blob, tables->linker, machine);
+
+    /*
+     * Count the size of the DSDT, we will need it for
+     * legacy sizing of ACPI tables.
+     */
+    aml_len += tables_blob->len - dsdt;
+
+    /* ACPI tables pointed to by RSDT */
+    fadt = tables_blob->len;
+    acpi_add_table(table_offsets, tables_blob);
+    fadt_data.facs_tbl_offset = &facs;
+    fadt_data.dsdt_tbl_offset = &dsdt;
+    fadt_data.xdsdt_tbl_offset = &dsdt;
+    build_fadt(tables_blob, tables->linker, &fadt_data,
+               lams->oem_id, lams->oem_table_id);
+    aml_len += tables_blob->len - fadt;
+
+    acpi_add_table(table_offsets, tables_blob);
+    build_madt(tables_blob, tables->linker, lams);
+
+    acpi_add_table(table_offsets, tables_blob);
+    build_srat(tables_blob, tables->linker, machine);
+
+    acpi_add_table(table_offsets, tables_blob);
+    {
+        AcpiMcfgInfo mcfg = {
+           .base = cpu_to_le64(LS_PCIECFG_BASE),
+           .size = cpu_to_le64(LS_PCIECFG_SIZE),
+        };
+        build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id,
+                   lams->oem_table_id);
+    }
+
+    /* Add tables supplied by user (if any) */
+    for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
+        unsigned len = acpi_table_len(u);
+
+        acpi_add_table(table_offsets, tables_blob);
+        g_array_append_vals(tables_blob, u, len);
+    }
+
+    /* RSDT is pointed to by RSDP */
+    rsdt = tables_blob->len;
+    build_rsdt(tables_blob, tables->linker, table_offsets,
+               lams->oem_id, lams->oem_table_id);
+
+    /* RSDP is in FSEG memory, so allocate it separately */
+    {
+        AcpiRsdpData rsdp_data = {
+            .revision = 0,
+            .oem_id = lams->oem_id,
+            .xsdt_tbl_offset = NULL,
+            .rsdt_tbl_offset = &rsdt,
+        };
+        build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
+    }
+
+    /*
+     * The align size is 128, warn if 64k is not enough therefore
+     * the align size could be resized.
+     */
+    if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
+        warn_report("ACPI table size %u exceeds %d bytes,"
+                    " migration may not work",
+                    tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
+        error_printf("Try removing CPUs, NUMA nodes, memory slots"
+                     " or PCI bridges.");
+    }
+
+    acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
+
+    /* Cleanup memory that's no longer used. */
+    g_array_free(table_offsets, true);
+}
+
+static void acpi_ram_update(MemoryRegion *mr, GArray *data)
+{
+    uint32_t size = acpi_data_len(data);
+
+    /*
+     * Make sure RAM size is correct - in case it got changed
+     * e.g. by migration
+     */
+    memory_region_ram_resize(mr, size, &error_abort);
+
+    memcpy(memory_region_get_ram_ptr(mr), data->data, size);
+    memory_region_set_dirty(mr, 0, size);
+}
+
+static void acpi_build_update(void *build_opaque)
+{
+    AcpiBuildState *build_state = build_opaque;
+    AcpiBuildTables tables;
+
+    /* No state to update or already patched? Nothing to do. */
+    if (!build_state || build_state->patched) {
+        return;
+    }
+    build_state->patched = 1;
+
+    acpi_build_tables_init(&tables);
+
+    acpi_build(&tables, MACHINE(qdev_get_machine()));
+
+    acpi_ram_update(build_state->table_mr, tables.table_data);
+    acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
+    acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
+
+    acpi_build_tables_cleanup(&tables, true);
+}
+
+static void acpi_build_reset(void *build_opaque)
+{
+    AcpiBuildState *build_state = build_opaque;
+    build_state->patched = 0;
+}
+
+static const VMStateDescription vmstate_acpi_build = {
+    .name = "acpi_build",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(patched, AcpiBuildState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+void loongarch_acpi_setup(LoongArchMachineState *lams)
+{
+    AcpiBuildTables tables;
+    AcpiBuildState *build_state;
+
+    if (!lams->fw_cfg) {
+        ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
+        return;
+    }
+
+    if (!loongarch_is_acpi_enabled(lams)) {
+        ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
+        return;
+    }
+
+    build_state = g_malloc0(sizeof *build_state);
+
+    acpi_build_tables_init(&tables);
+    acpi_build(&tables, MACHINE(lams));
+
+    /* Now expose it all to Guest */
+    build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
+                                              build_state, tables.table_data,
+                                              ACPI_BUILD_TABLE_FILE);
+    assert(build_state->table_mr != NULL);
+
+    build_state->linker_mr =
+        acpi_add_rom_blob(acpi_build_update, build_state,
+                          tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
+
+    build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
+                                             build_state, tables.rsdp,
+                                             ACPI_BUILD_RSDP_FILE);
+
+    qemu_register_reset(acpi_build_reset, build_state);
+    acpi_build_reset(build_state);
+    vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
+
+    /*
+     * Cleanup tables but don't free the memory: we track it
+     * in build_state.
+     */
+    acpi_build_tables_cleanup(&tables, false);
+}
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 83fb6b8f0f..bf0f63dc1b 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -28,6 +28,8 @@
 #include "hw/misc/unimp.h"
 #include "hw/loongarch/fw_cfg.h"
 #include "hw/firmware/smbios.h"
+#include "hw/acpi/aml-build.h"
+#include "qapi/qapi-visit-common.h"
 
 #define LOONGSON3_BIOSNAME "loongarch_bios.bin"
 
@@ -134,6 +136,7 @@ void loongarch_machine_done(Notifier *notifier, void *data)
 {
     LoongArchMachineState *lams = container_of(notifier,
                                         LoongArchMachineState, machine_done);
+    loongarch_acpi_setup(lams);
     loongarch_build_smbios(lams);
 }
 
@@ -211,6 +214,8 @@ static PCIBus *loongson3_irq_init(MachineState *machine)
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
     DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
     SysBusDevice *d;
+    LS7APCIState *ls7a_pci;
+    PCIDevice *pci_dev;
     PCIBus *pci_bus;
     int cpu, pin, i;
     unsigned long ipi_addr;
@@ -284,6 +289,10 @@ static PCIBus *loongson3_irq_init(MachineState *machine)
                               qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
     }
 
+    pci_dev = PCI_DEVICE(qdev_new(TYPE_LS7A_PCIE));
+    ls7a_pci = LS7A_PCIE(pci_dev);
+    ls7a_pm_init(pci_dev, &ls7a_pci->pm, pch_pic);
+
     return pci_bus;
 }
 
@@ -429,6 +438,40 @@ static void loongson3_init(MachineState *machine)
     LOONGARCH_SIMPLE_MMIO_OPS(CPUNAME_REG, "loongarch_cpuname", 0x8);
 }
 
+bool loongarch_is_acpi_enabled(LoongArchMachineState *lams)
+{
+    if (lams->acpi == ON_OFF_AUTO_OFF) {
+        return false;
+    }
+    return true;
+}
+
+static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name,
+                               void *opaque, Error **errp)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+    OnOffAuto acpi = lams->acpi;
+
+    visit_type_OnOffAuto(v, name, &acpi, errp);
+}
+
+static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name,
+                               void *opaque, Error **errp)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+
+    visit_type_OnOffAuto(v, name, &lams->acpi, errp);
+}
+
+static void loongarch_machine_initfn(Object *obj)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+
+    lams->acpi = ON_OFF_AUTO_AUTO;
+    lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
+    lams->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
+}
+
 static void loongarch_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -445,6 +488,12 @@ static void loongarch_class_init(ObjectClass *oc, void *data)
     mc->block_default_type = IF_VIRTIO;
     mc->default_boot_order = "c";
     mc->no_cdrom = 1;
+
+    object_class_property_add(oc, "acpi", "OnOffAuto",
+        loongarch_get_acpi, loongarch_set_acpi,
+        NULL, NULL);
+    object_class_property_set_description(oc, "acpi",
+        "Enable ACPI");
 }
 
 static const TypeInfo loongarch_machine_types[] = {
@@ -452,6 +501,7 @@ static const TypeInfo loongarch_machine_types[] = {
         .name           = TYPE_LOONGARCH_MACHINE,
         .parent         = TYPE_MACHINE,
         .instance_size  = sizeof(LoongArchMachineState),
+        .instance_init = loongarch_machine_initfn,
         .class_init     = loongarch_class_init,
     }
 };
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index fed69dfb62..94e0e976d7 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,5 +1,6 @@
 loongarch_ss = ss.source_set()
 loongarch_ss.add(when: 'CONFIG_LOONGSON3_LS7A', if_true: files('loongson3.c'))
 loongarch_ss.add(when: 'CONFIG_FW_CFG_LOONGARCH', if_true: files('fw_cfg.c'))
+loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c'))
 
 hw_arch += {'loongarch': loongarch_ss}
diff --git a/include/hw/acpi/ls7a.h b/include/hw/acpi/ls7a.h
new file mode 100644
index 0000000000..9c511f956b
--- /dev/null
+++ b/include/hw/acpi/ls7a.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU GMCH/LS7A PCI PM Emulation
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_ACPI_LS7A_H
+#define HW_ACPI_LS7A_H
+
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/cpu_hotplug.h"
+#include "hw/acpi/cpu.h"
+#include "hw/acpi/memory_hotplug.h"
+#include "hw/acpi/acpi_dev_interface.h"
+#include "hw/acpi/tco.h"
+
+#define LS7A_ACPI_IO_BASE         0x800
+#define LS7A_ACPI_IO_SIZE         0x100
+#define LS7A_PM_EVT_BLK           (0x0C) /* 4 bytes */
+#define LS7A_PM_CNT_BLK           (0x14) /* 2 bytes */
+#define LS7A_GPE0_STS_REG         (0x28) /* 4 bytes */
+#define LS7A_GPE0_ENA_REG         (0x2C) /* 4 bytes */
+#define LS7A_GPE0_RESET_REG       (0x30) /* 4 bytes */
+#define LS7A_PM_TMR_BLK           (0x18) /* 4 bytes */
+#define LS7A_GPE0_LEN             (8)
+#define ACPI_IO_BASE              (LS7A_ACPI_REG_BASE)
+#define ACPI_GPE0_LEN             (LS7A_GPE0_LEN)
+#define ACPI_IO_SIZE              (LS7A_ACPI_IO_SIZE)
+#define ACPI_SCI_IRQ              (LS7A_SCI_IRQ)
+
+typedef struct LS7APCIPMRegs {
+    /*
+     * In ls7a spec says that pm1_cnt register is 32bit width and
+     * that the upper 16bits are reserved and unused.
+     * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t.
+     */
+    ACPIREGS acpi_regs;
+
+    MemoryRegion iomem;
+    MemoryRegion iomem_gpe;
+    MemoryRegion iomem_reset;
+
+    qemu_irq irq;      /* SCI */
+
+    uint32_t pm_io_base;
+    Notifier powerdown_notifier;
+} LS7APCIPMRegs;
+
+void ls7a_pm_init(PCIDevice *pci_device, LS7APCIPMRegs *ls7a,
+                  DeviceState *pch_pic);
+extern const VMStateDescription vmstate_ls7a_pm;
+#endif /* HW_ACPI_LS7A_H */
diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
index bda7dd645d..6d8ec4a06b 100644
--- a/include/hw/loongarch/loongarch.h
+++ b/include/hw/loongarch/loongarch.h
@@ -54,9 +54,15 @@ typedef struct LoongArchMachineState {
     /* State for other subsystems/APIs: */
     Notifier machine_done;
     FWCfgState  *fw_cfg;
+    OnOffAuto   acpi;
+    char        *oem_id;
+    char        *oem_table_id;
 } LoongArchMachineState;
 
 #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("loongson3-ls7a")
 DECLARE_INSTANCE_CHECKER(LoongArchMachineState, LOONGARCH_MACHINE,
                          TYPE_LOONGARCH_MACHINE)
+
+bool loongarch_is_acpi_enabled(LoongArchMachineState *lams);
+void loongarch_acpi_setup(LoongArchMachineState *lams);
 #endif
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index c724b93b6d..8de752ef7d 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -11,6 +11,7 @@
 #include "hw/pci/pci.h"
 #include "hw/pci/pcie_host.h"
 #include "hw/pci-host/pam.h"
+#include "hw/acpi/ls7a.h"
 #include "qemu/units.h"
 #include "qemu/range.h"
 #include "qom/object.h"
@@ -23,6 +24,8 @@
 
 #define LS7A_PCI_IO_BASE         0x18000000UL
 #define LS7A_PCI_IO_SIZE         0x00010000
+#define LS7A_PCI_MEM_BASE        0x40000000
+#define LS7A_PCI_MEM_SIZE        0x3fffffff
 
 #define LS7A_PCH_REG_BASE       0x10000000UL
 #define LS7A_IOAPIC_REG_BASE    (LS7A_PCH_REG_BASE)
@@ -43,11 +46,15 @@
 #define LS7A_MISC_REG_BASE      (LS7A_PCH_REG_BASE + 0x00080000)
 #define LS7A_RTC_REG_BASE       (LS7A_MISC_REG_BASE + 0x00050100)
 #define LS7A_RTC_LEN            0x100
+#define LS7A_ACPI_REG_BASE      (LS7A_MISC_REG_BASE + 0x00050000)
+#define LS7A_SCI_IRQ            (PCH_PIC_IRQ_OFFSET + 4)
 
 struct LS7APCIState {
     /*< private >*/
     PCIDevice parent_obj;
     /*< public >*/
+
+    LS7APCIPMRegs pm;
 };
 
 typedef struct LS7APCIState LS7APCIState;
-- 
2.27.0



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2021-12-04 12:07 ` [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000 Xiaojuan Yang
@ 2021-12-04 17:54   ` Philippe Mathieu-Daudé
  2021-12-06  6:55     ` yangxiaojuan
  2021-12-18 10:02   ` Mark Cave-Ayland
  1 sibling, 1 reply; 58+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-12-04 17:54 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, richard.henderson, i.qemu,
	mark.cave-ayland, laurent, peterx, f4bug, alistair.francis,
	maobibo, pbonzini, chenhuacai, alex.bennee, gaosong

On 12/4/21 13:07, Xiaojuan Yang wrote:
> 1.Add uart,virtio-net,vga and usb for 3A5000.
> 2.Add irq set and map for the pci host. Non pci device
> use irq 0-16, pci device use 16-64.
> 3.Add some unimplented device to emulate guest unused
> memory space.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>  hw/loongarch/Kconfig            |  8 +++++
>  hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>  hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>  include/hw/intc/loongarch_ipi.h |  2 ++
>  include/hw/pci-host/ls7a.h      |  4 +++
>  softmmu/qdev-monitor.c          |  3 +-
>  6 files changed, 117 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index 468e3acc74..9ea3b92708 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -1,5 +1,13 @@
>  config LOONGSON3_LS7A
>      bool
> +    imply VGA_PCI
> +    imply VIRTIO_VGA
> +    imply PARALLEL

Is there really a parallel port? If so, maybe you forgot to
instantiate it.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 15/27] hw/loongarch: Add support loongson3-ls7a machine type.
  2021-12-04 12:07 ` [RFC PATCH v3 15/27] hw/loongarch: Add support loongson3-ls7a machine type Xiaojuan Yang
@ 2021-12-06  4:36   ` chen huacai
  2021-12-06  6:57     ` yangxiaojuan
  2021-12-17 23:48   ` Mark Cave-Ayland
  1 sibling, 1 reply; 58+ messages in thread
From: chen huacai @ 2021-12-06  4:36 UTC (permalink / raw)
  To: Xiaojuan Yang
  Cc: Peter Maydell, Thomas Huth, Philippe Mathieu-Daudé,
	Philippe Mathieu-Daudé,
	mark.cave-ayland, qemu-level, peterx, Laurent Vivier,
	Alex Bennée, alistair.francis, maobibo, Song Gao,
	Paolo Bonzini, Richard Henderson, i.qemu, chenhuacai

Hi, Xiaojuan,

On Sat, Dec 4, 2021 at 8:11 PM Xiaojuan Yang <yangxiaojuan@loongson.cn> wrote:
>
> Emulate a 3A5000 board use the new loongarch instruction.
> 3A5000 belongs to the Loongson3 series processors.
> The board consists of a 3A5000 cpu model and the 7A1000
> bridge. The host 3A5000 board is really complicated and
> contains many functions.Now for the tcg softmmu mode
> only part functions are emulated.
>
> More detailed info you can see
> https://github.com/loongson/LoongArch-Documentation
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>  .../devices/loongarch64-softmmu/default.mak   |   3 +
>  configs/targets/loongarch64-softmmu.mak       |   3 +
>  hw/Kconfig                                    |   1 +
>  hw/loongarch/Kconfig                          |   3 +
>  hw/loongarch/loongson3.c                      | 160 ++++++++++++++++++
>  hw/loongarch/meson.build                      |   4 +
>  hw/meson.build                                |   1 +
>  include/exec/poison.h                         |   2 +
>  include/hw/loongarch/loongarch.h              |  48 ++++++
>  include/sysemu/arch_init.h                    |   1 +
>  qapi/machine.json                             |   2 +-
>  target/Kconfig                                |   1 +
>  target/loongarch/Kconfig                      |   2 +
>  target/loongarch/cpu.c                        |   8 +
>  target/loongarch/cpu.h                        |   4 +
>  15 files changed, 242 insertions(+), 1 deletion(-)
>  create mode 100644 configs/devices/loongarch64-softmmu/default.mak
>  create mode 100644 hw/loongarch/Kconfig
>  create mode 100644 hw/loongarch/loongson3.c
>  create mode 100644 hw/loongarch/meson.build
>  create mode 100644 include/hw/loongarch/loongarch.h
>  create mode 100644 target/loongarch/Kconfig
>
> diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak
> new file mode 100644
> index 0000000000..973ce4c30a
> --- /dev/null
> +++ b/configs/devices/loongarch64-softmmu/default.mak
> @@ -0,0 +1,3 @@
> +# Default configuration for loongarch64-softmmu
> +
> +CONFIG_LOONGSON3_LS7A=y
> diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak
> index f33fa1590b..7bc06c850c 100644
> --- a/configs/targets/loongarch64-softmmu.mak
> +++ b/configs/targets/loongarch64-softmmu.mak
> @@ -1 +1,4 @@
> +TARGET_ARCH=loongarch64
> +TARGET_BASE_ARCH=loongarch
> +TARGET_SUPPORTS_MTTCG=y
>  TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml
> diff --git a/hw/Kconfig b/hw/Kconfig
> index ad20cce0a9..f71b2155ed 100644
> --- a/hw/Kconfig
> +++ b/hw/Kconfig
> @@ -49,6 +49,7 @@ source avr/Kconfig
>  source cris/Kconfig
>  source hppa/Kconfig
>  source i386/Kconfig
> +source loongarch/Kconfig
>  source m68k/Kconfig
>  source microblaze/Kconfig
>  source mips/Kconfig
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> new file mode 100644
> index 0000000000..ae8498de6a
> --- /dev/null
> +++ b/hw/loongarch/Kconfig
> @@ -0,0 +1,3 @@
> +config LOONGSON3_LS7A
> +    bool
> +    select PCI_EXPRESS_7A
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> new file mode 100644
> index 0000000000..28b623e927
> --- /dev/null
> +++ b/hw/loongarch/loongson3.c
> @@ -0,0 +1,160 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU loongson 3a5000 develop board emulation
> + *
> + * Copyright (c) 2021 Loongson Technology Corporation Limited
> + */
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/units.h"
> +#include "qemu/datadir.h"
> +#include "qapi/error.h"
> +#include "hw/boards.h"
> +#include "sysemu/sysemu.h"
> +#include "sysemu/qtest.h"
> +#include "sysemu/runstate.h"
> +#include "sysemu/reset.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "hw/pci-host/ls7a.h"
> +
> +
> +static void loongarch_cpu_reset(void *opaque)
> +{
> +    LoongArchCPU *cpu = opaque;
> +
> +    cpu_reset(CPU(cpu));
> +}
> +
> +#define LOONGARCH_SIMPLE_MMIO_OPS(ADDR, NAME, SIZE) \
> +({\
> +     MemoryRegion *iomem = g_new(MemoryRegion, 1);\
> +     memory_region_init_io(iomem, NULL, &loongarch_qemu_ops,\
> +                           (void *)ADDR, NAME, SIZE);\
> +     memory_region_add_subregion(&lams->system_iocsr, ADDR, iomem);\
> +})
> +
> +static void loongarch_qemu_write(void *opaque, hwaddr addr,
> +                                 uint64_t val, unsigned size)
> +{
> +}
> +
> +static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    uint64_t feature = 0UL;
> +    addr = ((hwaddr)(long)opaque) + addr;
> +
> +    switch (addr) {
> +    case FEATURE_REG:
> +        feature |= 1UL << IOCSRF_MSI | 1UL << IOCSRF_EXTIOI |
> +                   1UL << IOCSRF_CSRIPI;
> +        return feature ;
> +    case VENDOR_REG:
> +        return *(uint64_t *)"Loongson-3A5000";
> +    case CPUNAME_REG:
> +        return *(uint64_t *)"3A5000";
Due to the user manual, VENDOR register only include "Loongson", and
CPUNAME register include "3A5000".

Huacai
> +    }
> +    return 0;
> +}
> +
> +static const MemoryRegionOps loongarch_qemu_ops = {
> +    .read = loongarch_qemu_read,
> +    .write = loongarch_qemu_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 4,
> +        .max_access_size = 8,
> +    },
> +};
> +
> +static void loongson3_init(MachineState *machine)
> +{
> +    const char *cpu_model = machine->cpu_type;
> +    LoongArchCPU *cpu;
> +    ram_addr_t offset = 0;
> +    ram_addr_t ram_size = machine->ram_size;
> +    uint64_t highram_size = 0;
> +    MemoryRegion *address_space_mem = get_system_memory();
> +    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
> +    int i;
> +
> +    if (!cpu_model) {
> +        cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
> +    }
> +    if (!strstr(cpu_model, "Loongson-3A5000")) {
> +        error_report("LoongArch/TCG needs cpu type Loongson-3A5000");
> +        exit(1);
> +    }
> +
> +    memory_region_init_io(&lams->system_iocsr, NULL, NULL,
> +                          lams, "iocsr", UINT64_MAX);
> +    address_space_init(&lams->address_space_iocsr,
> +                       &lams->system_iocsr, "IOCSR");
> +
> +    /* Init CPUs */
> +    for (i = 0; i < machine->smp.cpus; i++) {
> +        Object *cpuobj = NULL;
> +        CPUState *cs;
> +
> +        cpuobj = object_new(machine->cpu_type);
> +
> +        cs = CPU(cpuobj);
> +        cs->cpu_index = i;
> +
> +        qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
> +        object_unref(cpuobj);
> +
> +        cpu = LOONGARCH_CPU(cs);
> +        if (cpu == NULL) {
> +            fprintf(stderr, "Unable to find CPU definition\n");
> +            exit(1);
> +        }
> +        qemu_register_reset(loongarch_cpu_reset, cpu);
> +    }
> +
> +    memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
> +                             machine->ram, 0, 256 * MiB);
> +    memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
> +    offset += 256 * MiB;
> +
> +    highram_size = ram_size - 256 * MiB;
> +    memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
> +                             machine->ram, offset, highram_size);
> +    memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
> +    offset += highram_size;
> +
> +    LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
> +    LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
> +    LOONGARCH_SIMPLE_MMIO_OPS(CPUNAME_REG, "loongarch_cpuname", 0x8);
> +}
> +
> +static void loongarch_class_init(ObjectClass *oc, void *data)
> +{
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
> +    mc->desc = "Loongson-3A5000 LS7A1000 machine";
> +    mc->init = loongson3_init;
> +    mc->default_ram_size = 1 * GiB;
> +    mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
> +    mc->default_ram_id = "loongarch.ram";
> +    mc->max_cpus = LOONGARCH_MAX_VCPUS;
> +    mc->is_default = 1;
> +    mc->default_kernel_irqchip_split = false;
> +    mc->block_default_type = IF_VIRTIO;
> +    mc->default_boot_order = "c";
> +    mc->no_cdrom = 1;
> +}
> +
> +static const TypeInfo loongarch_machine_types[] = {
> +    {
> +        .name           = TYPE_LOONGARCH_MACHINE,
> +        .parent         = TYPE_MACHINE,
> +        .instance_size  = sizeof(LoongArchMachineState),
> +        .class_init     = loongarch_class_init,
> +    }
> +};
> +
> +DEFINE_TYPES(loongarch_machine_types)
> diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
> new file mode 100644
> index 0000000000..1db3529cbc
> --- /dev/null
> +++ b/hw/loongarch/meson.build
> @@ -0,0 +1,4 @@
> +loongarch_ss = ss.source_set()
> +loongarch_ss.add(when: 'CONFIG_LOONGSON3_LS7A', if_true: files('loongson3.c'))
> +
> +hw_arch += {'loongarch': loongarch_ss}
> diff --git a/hw/meson.build b/hw/meson.build
> index b3366c888e..95202649b7 100644
> --- a/hw/meson.build
> +++ b/hw/meson.build
> @@ -49,6 +49,7 @@ subdir('avr')
>  subdir('cris')
>  subdir('hppa')
>  subdir('i386')
> +subdir('loongarch')
>  subdir('m68k')
>  subdir('microblaze')
>  subdir('mips')
> diff --git a/include/exec/poison.h b/include/exec/poison.h
> index 7ad4ad18e8..590bc305c7 100644
> --- a/include/exec/poison.h
> +++ b/include/exec/poison.h
> @@ -14,6 +14,7 @@
>  #pragma GCC poison TARGET_CRIS
>  #pragma GCC poison TARGET_HEXAGON
>  #pragma GCC poison TARGET_HPPA
> +#pragma GCC poison TARGET_LOONGARCH64
>  #pragma GCC poison TARGET_M68K
>  #pragma GCC poison TARGET_MICROBLAZE
>  #pragma GCC poison TARGET_MIPS
> @@ -73,6 +74,7 @@
>  #pragma GCC poison CONFIG_HPPA_DIS
>  #pragma GCC poison CONFIG_I386_DIS
>  #pragma GCC poison CONFIG_HEXAGON_DIS
> +#pragma GCC poison CONFIG_LOONGARCH_DIS
>  #pragma GCC poison CONFIG_M68K_DIS
>  #pragma GCC poison CONFIG_MICROBLAZE_DIS
>  #pragma GCC poison CONFIG_MIPS_DIS
> diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
> new file mode 100644
> index 0000000000..150403c93d
> --- /dev/null
> +++ b/include/hw/loongarch/loongarch.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Definitions for loongarch board emulation.
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef HW_LOONGARCH_H
> +#define HW_LOONGARCH_H
> +
> +#include "target/loongarch/cpu.h"
> +#include "qemu-common.h"
> +#include "hw/boards.h"
> +#include "qemu/queue.h"
> +
> +#define LOONGARCH_MAX_VCPUS     4
> +#define PM_MMIO_ADDR            0x10080000UL
> +#define PM_MMIO_SIZE            0x100
> +#define PM_CNT_MODE             0x10
> +#define FEATURE_REG             0x8
> +#define IOCSRF_TEMP             0
> +#define IOCSRF_NODECNT          1
> +#define IOCSRF_MSI              2
> +#define IOCSRF_EXTIOI           3
> +#define IOCSRF_CSRIPI           4
> +#define IOCSRF_FREQCSR          5
> +#define IOCSRF_FREQSCALE        6
> +#define IOCSRF_DVFSV1           7
> +#define IOCSRF_GMOD             9
> +#define IOCSRF_VM               11
> +
> +#define VENDOR_REG              0x10
> +#define CPUNAME_REG             0x20
> +
> +typedef struct LoongArchMachineState {
> +    /*< private >*/
> +    MachineState parent_obj;
> +
> +    AddressSpace address_space_iocsr;
> +    MemoryRegion system_iocsr;
> +    MemoryRegion lowmem;
> +    MemoryRegion highmem;
> +} LoongArchMachineState;
> +
> +#define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("loongson3-ls7a")
> +DECLARE_INSTANCE_CHECKER(LoongArchMachineState, LOONGARCH_MACHINE,
> +                         TYPE_LOONGARCH_MACHINE)
> +#endif
> diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
> index 70c579560a..3ac3634bbb 100644
> --- a/include/sysemu/arch_init.h
> +++ b/include/sysemu/arch_init.h
> @@ -24,6 +24,7 @@ enum {
>      QEMU_ARCH_RX = (1 << 20),
>      QEMU_ARCH_AVR = (1 << 21),
>      QEMU_ARCH_HEXAGON = (1 << 22),
> +    QEMU_ARCH_LOONGARCH = (1 << 23),
>  };
>
>  extern const uint32_t arch_type;
> diff --git a/qapi/machine.json b/qapi/machine.json
> index 067e3f5378..510ad6e566 100644
> --- a/qapi/machine.json
> +++ b/qapi/machine.json
> @@ -30,7 +30,7 @@
>  ##
>  { 'enum' : 'SysEmuTarget',
>    'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386',
> -             'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
> +             'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
>               'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc',
>               'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
>               'sh4eb', 'sparc', 'sparc64', 'tricore',
> diff --git a/target/Kconfig b/target/Kconfig
> index ae7f24fc66..83da0bd293 100644
> --- a/target/Kconfig
> +++ b/target/Kconfig
> @@ -4,6 +4,7 @@ source avr/Kconfig
>  source cris/Kconfig
>  source hppa/Kconfig
>  source i386/Kconfig
> +source loongarch/Kconfig
>  source m68k/Kconfig
>  source microblaze/Kconfig
>  source mips/Kconfig
> diff --git a/target/loongarch/Kconfig b/target/loongarch/Kconfig
> new file mode 100644
> index 0000000000..46b26b1a85
> --- /dev/null
> +++ b/target/loongarch/Kconfig
> @@ -0,0 +1,2 @@
> +config LOONGARCH64
> +    bool
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 6d3839ea10..62c2a4d813 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -11,6 +11,7 @@
>  #include "qemu/module.h"
>  #include "sysemu/qtest.h"
>  #include "exec/exec-all.h"
> +#include "hw/qdev-properties.h"
>  #include "qapi/qapi-commands-machine-target.h"
>  #include "cpu.h"
>  #include "internals.h"
> @@ -521,6 +522,12 @@ static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
>      return oc;
>  }
>
> +static Property loongarch_cpu_properties[] = {
> +    DEFINE_PROP_INT32("core-id", LoongArchCPU, core_id, -1),
> +    DEFINE_PROP_UINT32("id", LoongArchCPU, id, UNASSIGNED_CPU_ID),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
>  void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>  {
>      LoongArchCPU *cpu = LOONGARCH_CPU(cs);
> @@ -603,6 +610,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
>      device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
>                                      &lacc->parent_realize);
>      device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset);
> +    device_class_set_props(dc, loongarch_cpu_properties);
>
>      cc->class_by_name = loongarch_cpu_class_by_name;
>      cc->has_work = loongarch_cpu_has_work;
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 37cbe8924e..01bed0786c 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -16,6 +16,8 @@
>
>  #define TCG_GUEST_DEFAULT_MO (0)
>
> +#define UNASSIGNED_CPU_ID 0xFFFFFFFF
> +
>  #define FCSR0_M1    0x1f         /* FCSR1 mask, Enables */
>  #define FCSR0_M2    0x1f1f0000   /* FCSR2 mask, Cause and Flags */
>  #define FCSR0_M3    0x300        /* FCSR3 mask, Round Mode */
> @@ -362,6 +364,8 @@ struct LoongArchCPU {
>      CPUNegativeOffsetState neg;
>      CPULoongArchState env;
>      QEMUTimer timer; /* Internal timer */
> +    uint32_t id;
> +    int32_t core_id;
>  };
>
>  #define TYPE_LOONGARCH_CPU "loongarch-cpu"
> --
> 2.27.0
>
>


-- 
Huacai Chen


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 05/27] target/loongarch: Add stabletimer support
  2021-12-04 12:07 ` [RFC PATCH v3 05/27] target/loongarch: Add stabletimer support Xiaojuan Yang
@ 2021-12-06  4:38   ` chen huacai
  2021-12-07  7:04     ` maobibo
  0 siblings, 1 reply; 58+ messages in thread
From: chen huacai @ 2021-12-06  4:38 UTC (permalink / raw)
  To: Xiaojuan Yang
  Cc: Peter Maydell, Thomas Huth, Philippe Mathieu-Daudé,
	Philippe Mathieu-Daudé,
	mark.cave-ayland, qemu-level, peterx, Laurent Vivier,
	Alex Bennée, alistair.francis, maobibo, Song Gao,
	Paolo Bonzini, Richard Henderson, i.qemu, chenhuacai

Hi, Xiaojuan,

Maybe it is better to use "constant timer" instead of "stable timer",
which is more "native" in English.

Huacai

On Sat, Dec 4, 2021 at 8:11 PM Xiaojuan Yang <yangxiaojuan@loongson.cn> wrote:
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>  target/loongarch/cpu.c         |  9 +++++
>  target/loongarch/cpu.h         | 10 ++++++
>  target/loongarch/meson.build   |  1 +
>  target/loongarch/stabletimer.c | 63 ++++++++++++++++++++++++++++++++++
>  4 files changed, 83 insertions(+)
>  create mode 100644 target/loongarch/stabletimer.c
>
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 343632c644..f34e9763af 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -234,12 +234,21 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
>      LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
>      Error *local_err = NULL;
>
> +#ifndef CONFIG_USER_ONLY
> +    LoongArchCPU *cpu = LOONGARCH_CPU(dev);
> +#endif
> +
>      cpu_exec_realizefn(cs, &local_err);
>      if (local_err != NULL) {
>          error_propagate(errp, local_err);
>          return;
>      }
>
> +#ifndef CONFIG_USER_ONLY
> +    timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
> +                  &loongarch_stable_timer_cb, cpu);
> +#endif
> +
>      cpu_reset(cs);
>      qemu_init_vcpu(cs);
>
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index a4acd3b285..aeb8a5d397 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -12,6 +12,7 @@
>  #include "fpu/softfloat-types.h"
>  #include "hw/registerfields.h"
>  #include "cpu-csr.h"
> +#include "qemu/timer.h"
>
>  #define TCG_GUEST_DEFAULT_MO (0)
>
> @@ -148,6 +149,9 @@ FIELD(CPUCFG20, L3IU_SIZE, 24, 7)
>  extern const char * const regnames[];
>  extern const char * const fregnames[];
>
> +#define N_IRQS      14
> +#define IRQ_TIMER   11
> +
>  typedef struct CPULoongArchState CPULoongArchState;
>  struct CPULoongArchState {
>      uint64_t gpr[32];
> @@ -242,6 +246,7 @@ struct LoongArchCPU {
>
>      CPUNegativeOffsetState neg;
>      CPULoongArchState env;
> +    QEMUTimer timer; /* Internal timer */
>  };
>
>  #define TYPE_LOONGARCH_CPU "loongarch-cpu"
> @@ -306,4 +311,9 @@ enum {
>  #define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
>  #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
>
> +void loongarch_stable_timer_cb(void *opaque);
> +uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu);
> +uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu);
> +void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
> +                                             uint64_t value);
>  #endif /* LOONGARCH_CPU_H */
> diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
> index 103f36ee15..bda9f47ae4 100644
> --- a/target/loongarch/meson.build
> +++ b/target/loongarch/meson.build
> @@ -17,6 +17,7 @@ loongarch_tcg_ss.add(zlib)
>  loongarch_softmmu_ss = ss.source_set()
>  loongarch_softmmu_ss.add(files(
>    'machine.c',
> +  'stabletimer.c',
>  ))
>
>  loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
> diff --git a/target/loongarch/stabletimer.c b/target/loongarch/stabletimer.c
> new file mode 100644
> index 0000000000..151f5073f5
> --- /dev/null
> +++ b/target/loongarch/stabletimer.c
> @@ -0,0 +1,63 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU LoongArch timer support
> + *
> + * Copyright (c) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "qemu/timer.h"
> +#include "cpu.h"
> +
> +#define TIMER_PERIOD                10 /* 10 ns period for 100 Mhz frequency */
> +#define STABLETIMER_TICK_MASK       0xfffffffffffcUL
> +#define STABLETIMER_ENABLE          0x1UL
> +
> +/* LoongArch timer */
> +uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu)
> +{
> +    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD;
> +}
> +
> +uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu)
> +{
> +    uint64_t now, expire;
> +
> +    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    expire = timer_expire_time_ns(&cpu->timer);
> +
> +    return (expire - now) / TIMER_PERIOD;
> +}
> +
> +void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
> +                                             uint64_t value)
> +{
> +    CPULoongArchState *env = &cpu->env;
> +    uint64_t now, next;
> +
> +    env->CSR_TCFG = value;
> +    if (value & STABLETIMER_ENABLE) {
> +        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        next = now + (value & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
> +        timer_mod(&cpu->timer, next);
> +    }
> +}
> +
> +void loongarch_stable_timer_cb(void *opaque)
> +{
> +    LoongArchCPU *cpu  = opaque;
> +    CPULoongArchState *env = &cpu->env;
> +    uint64_t now, next;
> +
> +    if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) {
> +        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        next = now + (env->CSR_TCFG & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
> +        timer_mod(&cpu->timer, next);
> +    } else {
> +        env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
> +    }
> +
> +    env->CSR_ESTAT |= 1 << IRQ_TIMER;
> +    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
> +}
> --
> 2.27.0
>
>


-- 
Huacai Chen


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2021-12-04 17:54   ` Philippe Mathieu-Daudé
@ 2021-12-06  6:55     ` yangxiaojuan
  0 siblings, 0 replies; 58+ messages in thread
From: yangxiaojuan @ 2021-12-06  6:55 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: peter.maydell, thuth, richard.henderson, i.qemu,
	mark.cave-ayland, laurent, peterx, gaosong, alistair.francis,
	maobibo, pbonzini, alex.bennee, chenhuacai

Hi,

On 12/05/2021 01:54 AM, Philippe Mathieu-Daudé wrote:
> On 12/4/21 13:07, Xiaojuan Yang wrote:
>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>> 2.Add irq set and map for the pci host. Non pci device
>> use irq 0-16, pci device use 16-64.
>> 3.Add some unimplented device to emulate guest unused
>> memory space.
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>  hw/loongarch/Kconfig            |  8 +++++
>>  hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>  hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>  include/hw/intc/loongarch_ipi.h |  2 ++
>>  include/hw/pci-host/ls7a.h      |  4 +++
>>  softmmu/qdev-monitor.c          |  3 +-
>>  6 files changed, 117 insertions(+), 5 deletions(-)
>>
>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>> index 468e3acc74..9ea3b92708 100644
>> --- a/hw/loongarch/Kconfig
>> +++ b/hw/loongarch/Kconfig
>> @@ -1,5 +1,13 @@
>>  config LOONGSON3_LS7A
>>      bool
>> +    imply VGA_PCI
>> +    imply VIRTIO_VGA
>> +    imply PARALLEL
> 
> Is there really a parallel port? If so, maybe you forgot to
> instantiate it.
> 
There is no parallel port, I will fix it, thanks.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 15/27] hw/loongarch: Add support loongson3-ls7a machine type.
  2021-12-06  4:36   ` chen huacai
@ 2021-12-06  6:57     ` yangxiaojuan
  0 siblings, 0 replies; 58+ messages in thread
From: yangxiaojuan @ 2021-12-06  6:57 UTC (permalink / raw)
  To: qemu-devel

Hi, Huacai

On 12/06/2021 12:36 PM, chen huacai wrote:
> Hi, Xiaojuan,
> 
> On Sat, Dec 4, 2021 at 8:11 PM Xiaojuan Yang <yangxiaojuan@loongson.cn> wrote:
>>
>> Emulate a 3A5000 board use the new loongarch instruction.
>> 3A5000 belongs to the Loongson3 series processors.
>> The board consists of a 3A5000 cpu model and the 7A1000
>> bridge. The host 3A5000 board is really complicated and
>> contains many functions.Now for the tcg softmmu mode
>> only part functions are emulated.
>>
>> More detailed info you can see
>> https://github.com/loongson/LoongArch-Documentation
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>  .../devices/loongarch64-softmmu/default.mak   |   3 +
>>  configs/targets/loongarch64-softmmu.mak       |   3 +
>>  hw/Kconfig                                    |   1 +
>>  hw/loongarch/Kconfig                          |   3 +
>>  hw/loongarch/loongson3.c                      | 160 ++++++++++++++++++
>>  hw/loongarch/meson.build                      |   4 +
>>  hw/meson.build                                |   1 +
>>  include/exec/poison.h                         |   2 +
>>  include/hw/loongarch/loongarch.h              |  48 ++++++
>>  include/sysemu/arch_init.h                    |   1 +
>>  qapi/machine.json                             |   2 +-
>>  target/Kconfig                                |   1 +
>>  target/loongarch/Kconfig                      |   2 +
>>  target/loongarch/cpu.c                        |   8 +
>>  target/loongarch/cpu.h                        |   4 +
>>  15 files changed, 242 insertions(+), 1 deletion(-)
>>  create mode 100644 configs/devices/loongarch64-softmmu/default.mak
>>  create mode 100644 hw/loongarch/Kconfig
>>  create mode 100644 hw/loongarch/loongson3.c
>>  create mode 100644 hw/loongarch/meson.build
>>  create mode 100644 include/hw/loongarch/loongarch.h
>>  create mode 100644 target/loongarch/Kconfig
>>
>> diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak
>> new file mode 100644
>> index 0000000000..973ce4c30a
>> --- /dev/null
>> +++ b/configs/devices/loongarch64-softmmu/default.mak
>> @@ -0,0 +1,3 @@
>> +# Default configuration for loongarch64-softmmu
>> +
>> +CONFIG_LOONGSON3_LS7A=y
>> diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak
>> index f33fa1590b..7bc06c850c 100644
>> --- a/configs/targets/loongarch64-softmmu.mak
>> +++ b/configs/targets/loongarch64-softmmu.mak
>> @@ -1 +1,4 @@
>> +TARGET_ARCH=loongarch64
>> +TARGET_BASE_ARCH=loongarch
>> +TARGET_SUPPORTS_MTTCG=y
>>  TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml
>> diff --git a/hw/Kconfig b/hw/Kconfig
>> index ad20cce0a9..f71b2155ed 100644
>> --- a/hw/Kconfig
>> +++ b/hw/Kconfig
>> @@ -49,6 +49,7 @@ source avr/Kconfig
>>  source cris/Kconfig
>>  source hppa/Kconfig
>>  source i386/Kconfig
>> +source loongarch/Kconfig
>>  source m68k/Kconfig
>>  source microblaze/Kconfig
>>  source mips/Kconfig
>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>> new file mode 100644
>> index 0000000000..ae8498de6a
>> --- /dev/null
>> +++ b/hw/loongarch/Kconfig
>> @@ -0,0 +1,3 @@
>> +config LOONGSON3_LS7A
>> +    bool
>> +    select PCI_EXPRESS_7A
>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>> new file mode 100644
>> index 0000000000..28b623e927
>> --- /dev/null
>> +++ b/hw/loongarch/loongson3.c
>> @@ -0,0 +1,160 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * QEMU loongson 3a5000 develop board emulation
>> + *
>> + * Copyright (c) 2021 Loongson Technology Corporation Limited
>> + */
>> +#include "qemu/osdep.h"
>> +#include "qemu-common.h"
>> +#include "qemu/units.h"
>> +#include "qemu/datadir.h"
>> +#include "qapi/error.h"
>> +#include "hw/boards.h"
>> +#include "sysemu/sysemu.h"
>> +#include "sysemu/qtest.h"
>> +#include "sysemu/runstate.h"
>> +#include "sysemu/reset.h"
>> +#include "hw/loongarch/loongarch.h"
>> +#include "hw/pci-host/ls7a.h"
>> +
>> +
>> +static void loongarch_cpu_reset(void *opaque)
>> +{
>> +    LoongArchCPU *cpu = opaque;
>> +
>> +    cpu_reset(CPU(cpu));
>> +}
>> +
>> +#define LOONGARCH_SIMPLE_MMIO_OPS(ADDR, NAME, SIZE) \
>> +({\
>> +     MemoryRegion *iomem = g_new(MemoryRegion, 1);\
>> +     memory_region_init_io(iomem, NULL, &loongarch_qemu_ops,\
>> +                           (void *)ADDR, NAME, SIZE);\
>> +     memory_region_add_subregion(&lams->system_iocsr, ADDR, iomem);\
>> +})
>> +
>> +static void loongarch_qemu_write(void *opaque, hwaddr addr,
>> +                                 uint64_t val, unsigned size)
>> +{
>> +}
>> +
>> +static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> +    uint64_t feature = 0UL;
>> +    addr = ((hwaddr)(long)opaque) + addr;
>> +
>> +    switch (addr) {
>> +    case FEATURE_REG:
>> +        feature |= 1UL << IOCSRF_MSI | 1UL << IOCSRF_EXTIOI |
>> +                   1UL << IOCSRF_CSRIPI;
>> +        return feature ;
>> +    case VENDOR_REG:
>> +        return *(uint64_t *)"Loongson-3A5000";
>> +    case CPUNAME_REG:
>> +        return *(uint64_t *)"3A5000";
> Due to the user manual, VENDOR register only include "Loongson", and
> CPUNAME register include "3A5000".
> 

yes, I see it, I will fix it, thanks.

> Huacai
>> +    }
>> +    return 0;
>> +}
>> +
>> +static const MemoryRegionOps loongarch_qemu_ops = {
>> +    .read = loongarch_qemu_read,
>> +    .write = loongarch_qemu_write,
>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>> +    .valid = {
>> +        .min_access_size = 4,
>> +        .max_access_size = 8,
>> +    },
>> +    .impl = {
>> +        .min_access_size = 4,
>> +        .max_access_size = 8,
>> +    },
>> +};
>> +
>> +static void loongson3_init(MachineState *machine)
>> +{
>> +    const char *cpu_model = machine->cpu_type;
>> +    LoongArchCPU *cpu;
>> +    ram_addr_t offset = 0;
>> +    ram_addr_t ram_size = machine->ram_size;
>> +    uint64_t highram_size = 0;
>> +    MemoryRegion *address_space_mem = get_system_memory();
>> +    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>> +    int i;
>> +
>> +    if (!cpu_model) {
>> +        cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>> +    }
>> +    if (!strstr(cpu_model, "Loongson-3A5000")) {
>> +        error_report("LoongArch/TCG needs cpu type Loongson-3A5000");
>> +        exit(1);
>> +    }
>> +
>> +    memory_region_init_io(&lams->system_iocsr, NULL, NULL,
>> +                          lams, "iocsr", UINT64_MAX);
>> +    address_space_init(&lams->address_space_iocsr,
>> +                       &lams->system_iocsr, "IOCSR");
>> +
>> +    /* Init CPUs */
>> +    for (i = 0; i < machine->smp.cpus; i++) {
>> +        Object *cpuobj = NULL;
>> +        CPUState *cs;
>> +
>> +        cpuobj = object_new(machine->cpu_type);
>> +
>> +        cs = CPU(cpuobj);
>> +        cs->cpu_index = i;
>> +
>> +        qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
>> +        object_unref(cpuobj);
>> +
>> +        cpu = LOONGARCH_CPU(cs);
>> +        if (cpu == NULL) {
>> +            fprintf(stderr, "Unable to find CPU definition\n");
>> +            exit(1);
>> +        }
>> +        qemu_register_reset(loongarch_cpu_reset, cpu);
>> +    }
>> +
>> +    memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
>> +                             machine->ram, 0, 256 * MiB);
>> +    memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
>> +    offset += 256 * MiB;
>> +
>> +    highram_size = ram_size - 256 * MiB;
>> +    memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
>> +                             machine->ram, offset, highram_size);
>> +    memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>> +    offset += highram_size;
>> +
>> +    LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>> +    LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>> +    LOONGARCH_SIMPLE_MMIO_OPS(CPUNAME_REG, "loongarch_cpuname", 0x8);
>> +}
>> +
>> +static void loongarch_class_init(ObjectClass *oc, void *data)
>> +{
>> +    MachineClass *mc = MACHINE_CLASS(oc);
>> +
>> +    mc->desc = "Loongson-3A5000 LS7A1000 machine";
>> +    mc->init = loongson3_init;
>> +    mc->default_ram_size = 1 * GiB;
>> +    mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>> +    mc->default_ram_id = "loongarch.ram";
>> +    mc->max_cpus = LOONGARCH_MAX_VCPUS;
>> +    mc->is_default = 1;
>> +    mc->default_kernel_irqchip_split = false;
>> +    mc->block_default_type = IF_VIRTIO;
>> +    mc->default_boot_order = "c";
>> +    mc->no_cdrom = 1;
>> +}
>> +
>> +static const TypeInfo loongarch_machine_types[] = {
>> +    {
>> +        .name           = TYPE_LOONGARCH_MACHINE,
>> +        .parent         = TYPE_MACHINE,
>> +        .instance_size  = sizeof(LoongArchMachineState),
>> +        .class_init     = loongarch_class_init,
>> +    }
>> +};
>> +
>> +DEFINE_TYPES(loongarch_machine_types)
>> diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
>> new file mode 100644
>> index 0000000000..1db3529cbc
>> --- /dev/null
>> +++ b/hw/loongarch/meson.build
>> @@ -0,0 +1,4 @@
>> +loongarch_ss = ss.source_set()
>> +loongarch_ss.add(when: 'CONFIG_LOONGSON3_LS7A', if_true: files('loongson3.c'))
>> +
>> +hw_arch += {'loongarch': loongarch_ss}
>> diff --git a/hw/meson.build b/hw/meson.build
>> index b3366c888e..95202649b7 100644
>> --- a/hw/meson.build
>> +++ b/hw/meson.build
>> @@ -49,6 +49,7 @@ subdir('avr')
>>  subdir('cris')
>>  subdir('hppa')
>>  subdir('i386')
>> +subdir('loongarch')
>>  subdir('m68k')
>>  subdir('microblaze')
>>  subdir('mips')
>> diff --git a/include/exec/poison.h b/include/exec/poison.h
>> index 7ad4ad18e8..590bc305c7 100644
>> --- a/include/exec/poison.h
>> +++ b/include/exec/poison.h
>> @@ -14,6 +14,7 @@
>>  #pragma GCC poison TARGET_CRIS
>>  #pragma GCC poison TARGET_HEXAGON
>>  #pragma GCC poison TARGET_HPPA
>> +#pragma GCC poison TARGET_LOONGARCH64
>>  #pragma GCC poison TARGET_M68K
>>  #pragma GCC poison TARGET_MICROBLAZE
>>  #pragma GCC poison TARGET_MIPS
>> @@ -73,6 +74,7 @@
>>  #pragma GCC poison CONFIG_HPPA_DIS
>>  #pragma GCC poison CONFIG_I386_DIS
>>  #pragma GCC poison CONFIG_HEXAGON_DIS
>> +#pragma GCC poison CONFIG_LOONGARCH_DIS
>>  #pragma GCC poison CONFIG_M68K_DIS
>>  #pragma GCC poison CONFIG_MICROBLAZE_DIS
>>  #pragma GCC poison CONFIG_MIPS_DIS
>> diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
>> new file mode 100644
>> index 0000000000..150403c93d
>> --- /dev/null
>> +++ b/include/hw/loongarch/loongarch.h
>> @@ -0,0 +1,48 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * Definitions for loongarch board emulation.
>> + *
>> + * Copyright (C) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef HW_LOONGARCH_H
>> +#define HW_LOONGARCH_H
>> +
>> +#include "target/loongarch/cpu.h"
>> +#include "qemu-common.h"
>> +#include "hw/boards.h"
>> +#include "qemu/queue.h"
>> +
>> +#define LOONGARCH_MAX_VCPUS     4
>> +#define PM_MMIO_ADDR            0x10080000UL
>> +#define PM_MMIO_SIZE            0x100
>> +#define PM_CNT_MODE             0x10
>> +#define FEATURE_REG             0x8
>> +#define IOCSRF_TEMP             0
>> +#define IOCSRF_NODECNT          1
>> +#define IOCSRF_MSI              2
>> +#define IOCSRF_EXTIOI           3
>> +#define IOCSRF_CSRIPI           4
>> +#define IOCSRF_FREQCSR          5
>> +#define IOCSRF_FREQSCALE        6
>> +#define IOCSRF_DVFSV1           7
>> +#define IOCSRF_GMOD             9
>> +#define IOCSRF_VM               11
>> +
>> +#define VENDOR_REG              0x10
>> +#define CPUNAME_REG             0x20
>> +
>> +typedef struct LoongArchMachineState {
>> +    /*< private >*/
>> +    MachineState parent_obj;
>> +
>> +    AddressSpace address_space_iocsr;
>> +    MemoryRegion system_iocsr;
>> +    MemoryRegion lowmem;
>> +    MemoryRegion highmem;
>> +} LoongArchMachineState;
>> +
>> +#define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("loongson3-ls7a")
>> +DECLARE_INSTANCE_CHECKER(LoongArchMachineState, LOONGARCH_MACHINE,
>> +                         TYPE_LOONGARCH_MACHINE)
>> +#endif
>> diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
>> index 70c579560a..3ac3634bbb 100644
>> --- a/include/sysemu/arch_init.h
>> +++ b/include/sysemu/arch_init.h
>> @@ -24,6 +24,7 @@ enum {
>>      QEMU_ARCH_RX = (1 << 20),
>>      QEMU_ARCH_AVR = (1 << 21),
>>      QEMU_ARCH_HEXAGON = (1 << 22),
>> +    QEMU_ARCH_LOONGARCH = (1 << 23),
>>  };
>>
>>  extern const uint32_t arch_type;
>> diff --git a/qapi/machine.json b/qapi/machine.json
>> index 067e3f5378..510ad6e566 100644
>> --- a/qapi/machine.json
>> +++ b/qapi/machine.json
>> @@ -30,7 +30,7 @@
>>  ##
>>  { 'enum' : 'SysEmuTarget',
>>    'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386',
>> -             'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
>> +             'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
>>               'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc',
>>               'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
>>               'sh4eb', 'sparc', 'sparc64', 'tricore',
>> diff --git a/target/Kconfig b/target/Kconfig
>> index ae7f24fc66..83da0bd293 100644
>> --- a/target/Kconfig
>> +++ b/target/Kconfig
>> @@ -4,6 +4,7 @@ source avr/Kconfig
>>  source cris/Kconfig
>>  source hppa/Kconfig
>>  source i386/Kconfig
>> +source loongarch/Kconfig
>>  source m68k/Kconfig
>>  source microblaze/Kconfig
>>  source mips/Kconfig
>> diff --git a/target/loongarch/Kconfig b/target/loongarch/Kconfig
>> new file mode 100644
>> index 0000000000..46b26b1a85
>> --- /dev/null
>> +++ b/target/loongarch/Kconfig
>> @@ -0,0 +1,2 @@
>> +config LOONGARCH64
>> +    bool
>> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
>> index 6d3839ea10..62c2a4d813 100644
>> --- a/target/loongarch/cpu.c
>> +++ b/target/loongarch/cpu.c
>> @@ -11,6 +11,7 @@
>>  #include "qemu/module.h"
>>  #include "sysemu/qtest.h"
>>  #include "exec/exec-all.h"
>> +#include "hw/qdev-properties.h"
>>  #include "qapi/qapi-commands-machine-target.h"
>>  #include "cpu.h"
>>  #include "internals.h"
>> @@ -521,6 +522,12 @@ static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
>>      return oc;
>>  }
>>
>> +static Property loongarch_cpu_properties[] = {
>> +    DEFINE_PROP_INT32("core-id", LoongArchCPU, core_id, -1),
>> +    DEFINE_PROP_UINT32("id", LoongArchCPU, id, UNASSIGNED_CPU_ID),
>> +    DEFINE_PROP_END_OF_LIST()
>> +};
>> +
>>  void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>>  {
>>      LoongArchCPU *cpu = LOONGARCH_CPU(cs);
>> @@ -603,6 +610,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
>>      device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
>>                                      &lacc->parent_realize);
>>      device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset);
>> +    device_class_set_props(dc, loongarch_cpu_properties);
>>
>>      cc->class_by_name = loongarch_cpu_class_by_name;
>>      cc->has_work = loongarch_cpu_has_work;
>> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
>> index 37cbe8924e..01bed0786c 100644
>> --- a/target/loongarch/cpu.h
>> +++ b/target/loongarch/cpu.h
>> @@ -16,6 +16,8 @@
>>
>>  #define TCG_GUEST_DEFAULT_MO (0)
>>
>> +#define UNASSIGNED_CPU_ID 0xFFFFFFFF
>> +
>>  #define FCSR0_M1    0x1f         /* FCSR1 mask, Enables */
>>  #define FCSR0_M2    0x1f1f0000   /* FCSR2 mask, Cause and Flags */
>>  #define FCSR0_M3    0x300        /* FCSR3 mask, Round Mode */
>> @@ -362,6 +364,8 @@ struct LoongArchCPU {
>>      CPUNegativeOffsetState neg;
>>      CPULoongArchState env;
>>      QEMUTimer timer; /* Internal timer */
>> +    uint32_t id;
>> +    int32_t core_id;
>>  };
>>
>>  #define TYPE_LOONGARCH_CPU "loongarch-cpu"
>> --
>> 2.27.0
>>
>>
> 
> 



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 05/27] target/loongarch: Add stabletimer support
  2021-12-06  4:38   ` chen huacai
@ 2021-12-07  7:04     ` maobibo
  0 siblings, 0 replies; 58+ messages in thread
From: maobibo @ 2021-12-07  7:04 UTC (permalink / raw)
  To: chen huacai, Xiaojuan Yang
  Cc: Peter Maydell, Thomas Huth, chenhuacai, Alex Bennée, i.qemu,
	mark.cave-ayland, Philippe Mathieu-Daudé,
	peterx, qemu-level, alistair.francis, Song Gao, Paolo Bonzini,
	Richard Henderson, Philippe Mathieu-Daudé,
	Laurent Vivier



On 12/06/2021 12:38 PM, chen huacai wrote:
> Hi, Xiaojuan,
> 
> Maybe it is better to use "constant timer" instead of "stable timer",
> which is more "native" in English.

Yeap, maybe we need more investigation. On arm platform its name is ArchTimer
rather than "constant timer" in x86. And we will investigate the timer name
across different architecture.

regards
bibo, mao

> 
> Huacai
> 
> On Sat, Dec 4, 2021 at 8:11 PM Xiaojuan Yang <yangxiaojuan@loongson.cn> wrote:
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>  target/loongarch/cpu.c         |  9 +++++
>>  target/loongarch/cpu.h         | 10 ++++++
>>  target/loongarch/meson.build   |  1 +
>>  target/loongarch/stabletimer.c | 63 ++++++++++++++++++++++++++++++++++
>>  4 files changed, 83 insertions(+)
>>  create mode 100644 target/loongarch/stabletimer.c
>>
>> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
>> index 343632c644..f34e9763af 100644
>> --- a/target/loongarch/cpu.c
>> +++ b/target/loongarch/cpu.c
>> @@ -234,12 +234,21 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
>>      LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
>>      Error *local_err = NULL;
>>
>> +#ifndef CONFIG_USER_ONLY
>> +    LoongArchCPU *cpu = LOONGARCH_CPU(dev);
>> +#endif
>> +
>>      cpu_exec_realizefn(cs, &local_err);
>>      if (local_err != NULL) {
>>          error_propagate(errp, local_err);
>>          return;
>>      }
>>
>> +#ifndef CONFIG_USER_ONLY
>> +    timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
>> +                  &loongarch_stable_timer_cb, cpu);
>> +#endif
>> +
>>      cpu_reset(cs);
>>      qemu_init_vcpu(cs);
>>
>> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
>> index a4acd3b285..aeb8a5d397 100644
>> --- a/target/loongarch/cpu.h
>> +++ b/target/loongarch/cpu.h
>> @@ -12,6 +12,7 @@
>>  #include "fpu/softfloat-types.h"
>>  #include "hw/registerfields.h"
>>  #include "cpu-csr.h"
>> +#include "qemu/timer.h"
>>
>>  #define TCG_GUEST_DEFAULT_MO (0)
>>
>> @@ -148,6 +149,9 @@ FIELD(CPUCFG20, L3IU_SIZE, 24, 7)
>>  extern const char * const regnames[];
>>  extern const char * const fregnames[];
>>
>> +#define N_IRQS      14
>> +#define IRQ_TIMER   11
>> +
>>  typedef struct CPULoongArchState CPULoongArchState;
>>  struct CPULoongArchState {
>>      uint64_t gpr[32];
>> @@ -242,6 +246,7 @@ struct LoongArchCPU {
>>
>>      CPUNegativeOffsetState neg;
>>      CPULoongArchState env;
>> +    QEMUTimer timer; /* Internal timer */
>>  };
>>
>>  #define TYPE_LOONGARCH_CPU "loongarch-cpu"
>> @@ -306,4 +311,9 @@ enum {
>>  #define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
>>  #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
>>
>> +void loongarch_stable_timer_cb(void *opaque);
>> +uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu);
>> +uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu);
>> +void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
>> +                                             uint64_t value);
>>  #endif /* LOONGARCH_CPU_H */
>> diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
>> index 103f36ee15..bda9f47ae4 100644
>> --- a/target/loongarch/meson.build
>> +++ b/target/loongarch/meson.build
>> @@ -17,6 +17,7 @@ loongarch_tcg_ss.add(zlib)
>>  loongarch_softmmu_ss = ss.source_set()
>>  loongarch_softmmu_ss.add(files(
>>    'machine.c',
>> +  'stabletimer.c',
>>  ))
>>
>>  loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
>> diff --git a/target/loongarch/stabletimer.c b/target/loongarch/stabletimer.c
>> new file mode 100644
>> index 0000000000..151f5073f5
>> --- /dev/null
>> +++ b/target/loongarch/stabletimer.c
>> @@ -0,0 +1,63 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * QEMU LoongArch timer support
>> + *
>> + * Copyright (c) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "hw/loongarch/loongarch.h"
>> +#include "qemu/timer.h"
>> +#include "cpu.h"
>> +
>> +#define TIMER_PERIOD                10 /* 10 ns period for 100 Mhz frequency */
>> +#define STABLETIMER_TICK_MASK       0xfffffffffffcUL
>> +#define STABLETIMER_ENABLE          0x1UL
>> +
>> +/* LoongArch timer */
>> +uint64_t cpu_loongarch_get_stable_counter(LoongArchCPU *cpu)
>> +{
>> +    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD;
>> +}
>> +
>> +uint64_t cpu_loongarch_get_stable_timer_ticks(LoongArchCPU *cpu)
>> +{
>> +    uint64_t now, expire;
>> +
>> +    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +    expire = timer_expire_time_ns(&cpu->timer);
>> +
>> +    return (expire - now) / TIMER_PERIOD;
>> +}
>> +
>> +void cpu_loongarch_store_stable_timer_config(LoongArchCPU *cpu,
>> +                                             uint64_t value)
>> +{
>> +    CPULoongArchState *env = &cpu->env;
>> +    uint64_t now, next;
>> +
>> +    env->CSR_TCFG = value;
>> +    if (value & STABLETIMER_ENABLE) {
>> +        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +        next = now + (value & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
>> +        timer_mod(&cpu->timer, next);
>> +    }
>> +}
>> +
>> +void loongarch_stable_timer_cb(void *opaque)
>> +{
>> +    LoongArchCPU *cpu  = opaque;
>> +    CPULoongArchState *env = &cpu->env;
>> +    uint64_t now, next;
>> +
>> +    if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) {
>> +        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +        next = now + (env->CSR_TCFG & STABLETIMER_TICK_MASK) * TIMER_PERIOD;
>> +        timer_mod(&cpu->timer, next);
>> +    } else {
>> +        env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
>> +    }
>> +
>> +    env->CSR_ESTAT |= 1 << IRQ_TIMER;
>> +    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
>> +}
>> --
>> 2.27.0
>>
>>
> 
> 



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 00/27] Add LoongArch softmmu support.
  2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
                   ` (26 preceding siblings ...)
  2021-12-04 12:07 ` [RFC PATCH v3 27/27] hw/loongarch: Add LoongArch acpi support Xiaojuan Yang
@ 2021-12-13  3:13 ` yangxiaojuan
  2021-12-13 22:43   ` Mark Cave-Ayland
  27 siblings, 1 reply; 58+ messages in thread
From: yangxiaojuan @ 2021-12-13  3:13 UTC (permalink / raw)
  To: qemu-level; +Cc: Mark Cave-Ayland, Richard Henderson

Ping!

Please help review the V3 patch, thank you!

On 12/04/2021 08:06 PM, Xiaojuan Yang wrote:
> This series patch add softmmu support for LoongArch.
> Base on the linux-user emulation support V13 patch.
>   * https://patchew.org/QEMU/1638610165-15036-1-git-send-email-gaosong@loongson.cn/
> The latest kernel:
>   * https://github.com/loongson/linux/tree/loongarch-next
> The manual:
>   * https://github.com/loongson/LoongArch-Documentation/releases/tag/2021.10.11
> 
> Changes for v3:
> 1.Target code mainly follow Richard's code review comments.
> 2.Put the csr and iocsr read/write instruction emulate into 2 different patch.
> 3.Simply the tlb emulation.
> 4.Delete some unused csr registers defintion.
> 5.Machine and board code mainly follow Mark's advice, discard the obsolete interface.
> 6.NUMA function is removed for it is not completed.
> 7.Adjust some format problem and the Naming problem 
> 
> Changes for v2:
> 1.Combine patch 2 and 3 into one.
> 2.Adjust the order of the patch.
> 3.Put all the binaries on the github.
> 4.Modify some emulate errors when use the kernel from the github.
> 5.Adjust some format problem and the Naming problem 
> 6.Others mainly follow Richard's code review comments.
> 
> Please help review!
> 
> Thanks
> 
> Xiaojuan Yang (27):
>   target/loongarch: Update README
>   target/loongarch: Add CSR registers definition
>   target/loongarch: Add basic vmstate description of CPU.
>   target/loongarch: Implement qmp_query_cpu_definitions()
>   target/loongarch: Add stabletimer support
>   target/loongarch: Add MMU support for LoongArch CPU.
>   target/loongarch: Add LoongArch CSR instruction
>   target/loongarch: Add LoongArch IOCSR instruction
>   target/loongarch: Add TLB instruction support
>   target/loongarch: Add other core instructions support
>   target/loongarch: Add LoongArch interrupt and exception handle
>   target/loongarch: Add timer related instructions support.
>   target/loongarch: Add gdb support.
>   hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson3
>     Platform
>   hw/loongarch: Add support loongson3-ls7a machine type.
>   hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC)
>   hw/loongarch: Add LoongArch ipi interrupt support(IPI)
>   hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
>   hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI)
>   hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
>   hw/loongarch: Add irq hierarchy for the system
>   hw/loongarch: Add some devices support for 3A5000.
>   hw/loongarch: Add LoongArch ls7a rtc device support
>   hw/loongarch: Add default bios startup support.
>   hw/loongarch: Add -kernel and -initrd options support
>   hw/loongarch: Add LoongArch smbios support
>   hw/loongarch: Add LoongArch acpi support
> 
>  .../devices/loongarch64-softmmu/default.mak   |   3 +
>  configs/targets/loongarch64-softmmu.mak       |   4 +
>  gdb-xml/loongarch-base64.xml                  |  43 +
>  gdb-xml/loongarch-fpu64.xml                   |  57 ++
>  hw/Kconfig                                    |   1 +
>  hw/acpi/Kconfig                               |   4 +
>  hw/acpi/ls7a.c                                | 349 ++++++++
>  hw/acpi/meson.build                           |   1 +
>  hw/intc/Kconfig                               |  15 +
>  hw/intc/loongarch_extioi.c                    | 499 +++++++++++
>  hw/intc/loongarch_ipi.c                       | 162 ++++
>  hw/intc/loongarch_pch_msi.c                   |  67 ++
>  hw/intc/loongarch_pch_pic.c                   | 357 ++++++++
>  hw/intc/meson.build                           |   4 +
>  hw/intc/trace-events                          |  21 +
>  hw/loongarch/Kconfig                          |  23 +
>  hw/loongarch/acpi-build.c                     | 637 ++++++++++++++
>  hw/loongarch/fw_cfg.c                         |  33 +
>  hw/loongarch/fw_cfg.h                         |  15 +
>  hw/loongarch/loongson3.c                      | 509 +++++++++++
>  hw/loongarch/meson.build                      |   6 +
>  hw/meson.build                                |   1 +
>  hw/pci-host/Kconfig                           |   4 +
>  hw/pci-host/ls7a.c                            | 214 +++++
>  hw/pci-host/meson.build                       |   1 +
>  hw/rtc/Kconfig                                |   3 +
>  hw/rtc/ls7a_rtc.c                             | 323 +++++++
>  hw/rtc/meson.build                            |   1 +
>  include/exec/poison.h                         |   2 +
>  include/hw/acpi/ls7a.h                        |  53 ++
>  include/hw/intc/loongarch_extioi.h            |  69 ++
>  include/hw/intc/loongarch_ipi.h               |  47 ++
>  include/hw/intc/loongarch_pch_msi.h           |  21 +
>  include/hw/intc/loongarch_pch_pic.h           |  61 ++
>  include/hw/loongarch/loongarch.h              |  68 ++
>  include/hw/pci-host/ls7a.h                    |  79 ++
>  include/sysemu/arch_init.h                    |   1 +
>  linux-user/loongarch64/cpu_loop.c             |   8 +-
>  qapi/machine-target.json                      |   6 +-
>  qapi/machine.json                             |   2 +-
>  softmmu/qdev-monitor.c                        |   3 +-
>  target/Kconfig                                |   1 +
>  target/loongarch/Kconfig                      |   2 +
>  target/loongarch/README                       |  20 +
>  target/loongarch/cpu-csr.h                    | 236 ++++++
>  target/loongarch/cpu-param.h                  |   2 +-
>  target/loongarch/cpu.c                        | 402 ++++++++-
>  target/loongarch/cpu.h                        | 216 ++++-
>  target/loongarch/csr_helper.c                 | 112 +++
>  target/loongarch/disas.c                      |  57 ++
>  target/loongarch/fpu_helper.c                 |   2 +-
>  target/loongarch/gdbstub.c                    |  97 +++
>  target/loongarch/helper.h                     |  26 +
>  target/loongarch/insn_trans/trans_core.c.inc  | 409 +++++++++
>  target/loongarch/insn_trans/trans_extra.c.inc |  36 +-
>  target/loongarch/insns.decode                 |  44 +
>  target/loongarch/internals.h                  |  29 +
>  target/loongarch/iocsr_helper.c               | 109 +++
>  target/loongarch/machine.c                    | 104 +++
>  target/loongarch/meson.build                  |  11 +
>  target/loongarch/op_helper.c                  |  56 ++
>  target/loongarch/stabletimer.c                |  63 ++
>  target/loongarch/tlb_helper.c                 | 789 ++++++++++++++++++
>  target/loongarch/translate.c                  |   9 +-
>  64 files changed, 6579 insertions(+), 30 deletions(-)
>  create mode 100644 configs/devices/loongarch64-softmmu/default.mak
>  create mode 100644 configs/targets/loongarch64-softmmu.mak
>  create mode 100644 gdb-xml/loongarch-base64.xml
>  create mode 100644 gdb-xml/loongarch-fpu64.xml
>  create mode 100644 hw/acpi/ls7a.c
>  create mode 100644 hw/intc/loongarch_extioi.c
>  create mode 100644 hw/intc/loongarch_ipi.c
>  create mode 100644 hw/intc/loongarch_pch_msi.c
>  create mode 100644 hw/intc/loongarch_pch_pic.c
>  create mode 100644 hw/loongarch/Kconfig
>  create mode 100644 hw/loongarch/acpi-build.c
>  create mode 100644 hw/loongarch/fw_cfg.c
>  create mode 100644 hw/loongarch/fw_cfg.h
>  create mode 100644 hw/loongarch/loongson3.c
>  create mode 100644 hw/loongarch/meson.build
>  create mode 100644 hw/pci-host/ls7a.c
>  create mode 100644 hw/rtc/ls7a_rtc.c
>  create mode 100644 include/hw/acpi/ls7a.h
>  create mode 100644 include/hw/intc/loongarch_extioi.h
>  create mode 100644 include/hw/intc/loongarch_ipi.h
>  create mode 100644 include/hw/intc/loongarch_pch_msi.h
>  create mode 100644 include/hw/intc/loongarch_pch_pic.h
>  create mode 100644 include/hw/loongarch/loongarch.h
>  create mode 100644 include/hw/pci-host/ls7a.h
>  create mode 100644 target/loongarch/Kconfig
>  create mode 100644 target/loongarch/cpu-csr.h
>  create mode 100644 target/loongarch/csr_helper.c
>  create mode 100644 target/loongarch/gdbstub.c
>  create mode 100644 target/loongarch/insn_trans/trans_core.c.inc
>  create mode 100644 target/loongarch/iocsr_helper.c
>  create mode 100644 target/loongarch/machine.c
>  create mode 100644 target/loongarch/stabletimer.c
>  create mode 100644 target/loongarch/tlb_helper.c
> 



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 00/27] Add LoongArch softmmu support.
  2021-12-13  3:13 ` [RFC PATCH v3 00/27] Add LoongArch softmmu support yangxiaojuan
@ 2021-12-13 22:43   ` Mark Cave-Ayland
  2021-12-14  1:08     ` yangxiaojuan
  0 siblings, 1 reply; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-13 22:43 UTC (permalink / raw)
  To: yangxiaojuan, qemu-level; +Cc: Richard Henderson

On 13/12/2021 03:13, yangxiaojuan wrote:

> Ping!
> 
> Please help review the V3 patch, thank you!

I've been fairly busy recently, but I will try and find some time to look at the v3 
sometime during the week.


ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 00/27] Add LoongArch softmmu support.
  2021-12-13 22:43   ` Mark Cave-Ayland
@ 2021-12-14  1:08     ` yangxiaojuan
  0 siblings, 0 replies; 58+ messages in thread
From: yangxiaojuan @ 2021-12-14  1:08 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-level; +Cc: Richard Henderson

thank you!

On 12/14/2021 06:43 AM, Mark Cave-Ayland wrote:
> On 13/12/2021 03:13, yangxiaojuan wrote:
> 
>> Ping!
>>
>> Please help review the V3 patch, thank you!
> 
> I've been fairly busy recently, but I will try and find some time to look at the v3 sometime during the week.
> 
> 
> ATB,
> 
> Mark.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 14/27] hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson3 Platform
  2021-12-04 12:07 ` [RFC PATCH v3 14/27] hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson3 Platform Xiaojuan Yang
@ 2021-12-17 23:39   ` Mark Cave-Ayland
  2021-12-20 11:42     ` yangxiaojuan
  0 siblings, 1 reply; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-17 23:39 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> This is a model of the PCIe Host Bridge found on a Loongson-5000
> processor. It includes a interrupt controller, some interface for
> pci and nonpci devices. Mainly emulate part of it that is not
> exactly the same as the host and only use part devices for
> tcg mode. It support for MSI and MSIX interrupt sources.
> 
> For more detailed info about ls7a1000 you can see the doc at
> https://github.com/loongson/LoongArch-Documentation/releases/latest/
> download/Loongson-7A1000-usermanual-2.00-EN.pdf
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/pci-host/Kconfig        |   4 +
>   hw/pci-host/ls7a.c         | 174 +++++++++++++++++++++++++++++++++++++
>   hw/pci-host/meson.build    |   1 +
>   include/hw/pci-host/ls7a.h |  51 +++++++++++
>   4 files changed, 230 insertions(+)
>   create mode 100644 hw/pci-host/ls7a.c
>   create mode 100644 include/hw/pci-host/ls7a.h
> 
> diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
> index 2b5f7d58cc..b02a9d1454 100644
> --- a/hw/pci-host/Kconfig
> +++ b/hw/pci-host/Kconfig
> @@ -77,3 +77,7 @@ config MV64361
>       bool
>       select PCI
>       select I8259
> +
> +config PCI_EXPRESS_7A
> +    bool
> +    select PCI_EXPRESS
> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
> new file mode 100644
> index 0000000000..a783fb2eda
> --- /dev/null
> +++ b/hw/pci-host/ls7a.c
> @@ -0,0 +1,174 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU Loongson 7A1000 North Bridge Emulation
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pcie_host.h"
> +#include "hw/qdev-properties.h"
> +#include "qapi/error.h"
> +#include "hw/irq.h"
> +#include "hw/pci/pci_bridge.h"
> +#include "hw/pci/pci_bus.h"
> +#include "sysemu/reset.h"
> +#include "hw/pci-host/ls7a.h"
> +#include "migration/vmstate.h"
> +
> +static const VMStateDescription vmstate_ls7a_pcie = {
> +    .name = "LS7A_PCIE",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(parent_obj, LS7APCIState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void pci_ls7a_config_write(void *opaque, hwaddr addr,
> +                                  uint64_t val, unsigned size)
> +{
> +    pci_data_write(opaque, addr, val, size);
> +}
> +
> +static uint64_t pci_ls7a_config_read(void *opaque,
> +                                     hwaddr addr, unsigned size)
> +{
> +    uint64_t val;
> +
> +    val = pci_data_read(opaque, addr, size);
> +
> +    return val;
> +}
> +
> +static const MemoryRegionOps pci_ls7a_config_ops = {
> +    .read = pci_ls7a_config_read,
> +    .write = pci_ls7a_config_write,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 4,
> +    },
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 4,
> +    },
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
> +{
> +    PCIHostState *pci = PCI_HOST_BRIDGE(dev);
> +    LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
> +    PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);

SysbusDevice *sbd = SYS_BUS_DEVICE(dev) will be needed for later use.

> +    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
> +                                     get_system_memory(), get_system_io(),
> +                                     PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);

A device shouldn't map itself into an address space: that is the job of the board. To 
achieve this LS7APCIEHost should have separate mmio and io memory regions defined and 
pci_register_root_bus() configured to use these i.e.

     pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
                                      &s->pci_mmio, &s->pci_io,
                                      PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);

> +    memory_region_init_io(&s->pci_conf, OBJECT(dev),
> +                          &pci_ls7a_config_ops, pci->bus,
> +                          "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
> +    memory_region_add_subregion(get_system_memory(), HT1LO_PCICFG_BASE,
> +                                &s->pci_conf);

Here add sysbus_init_mmio(sbd, &s->pci_conf) and remove memory_region_add_subregion().

> +    /* Add ls7a pci-io */
> +    memory_region_init_alias(&s->pci_io, OBJECT(dev), "ls7a-pci-io",
> +                             get_system_io(), 0, LS7A_PCI_IO_SIZE);
> +    memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE,
> +                                &s->pci_io);

Remove the alias onto the system io memory region and instead use 
sysbus_init_mmio(sbd, &s->pci_io).

You will also need to make the PCI mmio memory region availble to the board using 
sysbus_init_mmio(sbd, &s->pci_mmio).

> +    pcie_host_mmcfg_update(pex, true, LS_PCIECFG_BASE, LS_PCIECFG_SIZE);

It looks like the pcie_host_mmcfg_*() functions are hardcoded to map the device in 
system memory which is not recommended for new devices. The best example I can find 
is in hw/pci-host/xilinx-pcie.c whereby pcie_host_mmcfg_init() is used in 
xilinx_pcie_host_realize() to setup the MMCFG memory region and then 
sysbus_init_mmio(sbd, &pex->mmio) is used to make it available to the board.

Once all these sysbus memory regions have been defined they can be accessed in the 
board code using sysbus_mmio_get_region().

> +    qdev_realize(DEVICE(&s->pci_dev), BUS(pci->bus), &error_fatal);
> +}
> +
> +static void ls7a_pcie_realize(PCIDevice *d, Error **errp)
> +{
> +    /* pci status */
> +    d->config[0x6] = 0x01;
> +    /* base class code */
> +    d->config[0xb] = 0x06;
> +    /* header type */
> +    d->config[0xe] = 0x80;
> +    /* capabilities pointer */
> +    d->config[0x34] = 0x40;
> +    /* link status and control register 0 */
> +    d->config[0x44] = 0x20;
> +}

Should these definitely exist in realize() or should they belong in a reset() function?

> +static void ls7a_pcie_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
> +    dc->desc = "LS7A1000 PCIE Host bridge";
> +    dc->vmsd = &vmstate_ls7a_pcie;
> +    k->realize = ls7a_pcie_realize;
> +    k->vendor_id = 0x0014;
> +    k->device_id = 0x7a00;

Generally device and vendor ids are added as constants to include/hw/pci/pci_ids.h.

> +    k->revision = 0x0;
> +    k->class_id = PCI_CLASS_BRIDGE_HOST;
> +    /*
> +     * PCI-facing part of the host bridge, not usable without the
> +     * host-facing part, which can't be device_add'ed, yet.
> +     */
> +    dc->user_creatable = false;
> +}
> +
> +static const TypeInfo ls7a_pcie_device_info = {
> +    .name          = TYPE_LS7A_PCIE,

Why TYPE_LS7A_PCIE? The normal convention would be to call the type 
TYPE_LS7A_PCI_DEVICE to show that it is derived from a conventional PCI device.

> +    .parent        = TYPE_PCI_DEVICE,
> +    .instance_size = sizeof(LS7APCIState),
> +    .class_init    = ls7a_pcie_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        { },
> +    },
> +};
> +
> +static void ls7a_pciehost_initfn(Object *obj)
> +{
> +    LS7APCIEHost *s = LS7A_HOST_DEVICE(obj);
> +    LS7APCIState *ls7a_pci = &s->pci_dev;
> +
> +    object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
> +    qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
> +    qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
> +}
> +
> +static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
> +                                          PCIBus *rootbus)
> +{
> +    return "0000:00";
> +}
> +
> +static void ls7a_pciehost_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
> +
> +    hc->root_bus_path = ls7a_pciehost_root_bus_path;
> +    dc->realize = ls7a_pciehost_realize;
> +    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
> +    dc->fw_name = "pci";
> +    dc->user_creatable = false;
> +}
> +
> +static const TypeInfo ls7a_pciehost_info = {
> +    .name          = TYPE_LS7A_HOST_DEVICE,

TYPE_LS7A_PCIE_HOST_BRIDGE would be the normal convention.

> +    .parent        = TYPE_PCIE_HOST_BRIDGE,
> +    .instance_size = sizeof(LS7APCIEHost),
> +    .instance_init = ls7a_pciehost_initfn,
> +    .class_init    = ls7a_pciehost_class_init,
> +};
> +
> +static void ls7a_register_types(void)
> +{
> +    type_register_static(&ls7a_pciehost_info);
> +    type_register_static(&ls7a_pcie_device_info);
> +}
> +
> +type_init(ls7a_register_types)
> diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
> index 4c4f39c15c..c4955455fd 100644
> --- a/hw/pci-host/meson.build
> +++ b/hw/pci-host/meson.build
> @@ -11,6 +11,7 @@ pci_ss.add(when: 'CONFIG_PCI_SABRE', if_true: files('sabre.c'))
>   pci_ss.add(when: 'CONFIG_XEN_IGD_PASSTHROUGH', if_true: files('xen_igd_pt.c'))
>   pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c'))
>   pci_ss.add(when: 'CONFIG_SH_PCI', if_true: files('sh_pci.c'))
> +pci_ss.add(when: 'CONFIG_PCI_EXPRESS_7A', if_true: files('ls7a.c'))
>   
>   # PPC devices
>   pci_ss.add(when: 'CONFIG_RAVEN_PCI', if_true: files('raven.c'))
> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
> new file mode 100644
> index 0000000000..32d6f045dc
> --- /dev/null
> +++ b/include/hw/pci-host/ls7a.h
> @@ -0,0 +1,51 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU LoongArch CPU
> + *
> + * Copyright (c) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef HW_LS7A_H
> +#define HW_LS7A_H
> +
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pcie_host.h"
> +#include "hw/pci-host/pam.h"
> +#include "qemu/units.h"
> +#include "qemu/range.h"
> +#include "qom/object.h"
> +
> +#define HT1LO_PCICFG_BASE        0x1a000000
> +#define HT1LO_PCICFG_SIZE        0x02000000
> +
> +#define LS_PCIECFG_BASE          0x20000000
> +#define LS_PCIECFG_SIZE          0x08000000
> +
> +#define LS7A_PCI_IO_BASE         0x18000000UL
> +#define LS7A_PCI_IO_SIZE         0x00010000
> +
> +struct LS7APCIState {
> +    /*< private >*/
> +    PCIDevice parent_obj;
> +    /*< public >*/
> +};
> +
> +typedef struct LS7APCIState LS7APCIState;
> +typedef struct LS7APCIEHost {
> +    /*< private >*/
> +    PCIExpressHost parent_obj;
> +    /*< public >*/
> +
> +    LS7APCIState pci_dev;
> +
> +    MemoryRegion pci_conf;
> +    MemoryRegion pci_io;
> +} LS7APCIEHost;
> +
> +#define TYPE_LS7A_HOST_DEVICE "ls7a1000-pciehost"
> +OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIEHost, LS7A_HOST_DEVICE)
> +
> +#define TYPE_LS7A_PCIE "ls7a1000_pcie"
> +OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIState, LS7A_PCIE)
> +
> +#endif /* HW_LS7A_H */


ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 15/27] hw/loongarch: Add support loongson3-ls7a machine type.
  2021-12-04 12:07 ` [RFC PATCH v3 15/27] hw/loongarch: Add support loongson3-ls7a machine type Xiaojuan Yang
  2021-12-06  4:36   ` chen huacai
@ 2021-12-17 23:48   ` Mark Cave-Ayland
  1 sibling, 0 replies; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-17 23:48 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> Emulate a 3A5000 board use the new loongarch instruction.
> 3A5000 belongs to the Loongson3 series processors.
> The board consists of a 3A5000 cpu model and the 7A1000
> bridge. The host 3A5000 board is really complicated and
> contains many functions.Now for the tcg softmmu mode
> only part functions are emulated.
> 
> More detailed info you can see
> https://github.com/loongson/LoongArch-Documentation
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   .../devices/loongarch64-softmmu/default.mak   |   3 +
>   configs/targets/loongarch64-softmmu.mak       |   3 +
>   hw/Kconfig                                    |   1 +
>   hw/loongarch/Kconfig                          |   3 +
>   hw/loongarch/loongson3.c                      | 160 ++++++++++++++++++
>   hw/loongarch/meson.build                      |   4 +
>   hw/meson.build                                |   1 +
>   include/exec/poison.h                         |   2 +
>   include/hw/loongarch/loongarch.h              |  48 ++++++
>   include/sysemu/arch_init.h                    |   1 +
>   qapi/machine.json                             |   2 +-
>   target/Kconfig                                |   1 +
>   target/loongarch/Kconfig                      |   2 +
>   target/loongarch/cpu.c                        |   8 +
>   target/loongarch/cpu.h                        |   4 +
>   15 files changed, 242 insertions(+), 1 deletion(-)
>   create mode 100644 configs/devices/loongarch64-softmmu/default.mak
>   create mode 100644 hw/loongarch/Kconfig
>   create mode 100644 hw/loongarch/loongson3.c
>   create mode 100644 hw/loongarch/meson.build
>   create mode 100644 include/hw/loongarch/loongarch.h
>   create mode 100644 target/loongarch/Kconfig
> 
> diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak
> new file mode 100644
> index 0000000000..973ce4c30a
> --- /dev/null
> +++ b/configs/devices/loongarch64-softmmu/default.mak
> @@ -0,0 +1,3 @@
> +# Default configuration for loongarch64-softmmu
> +
> +CONFIG_LOONGSON3_LS7A=y
> diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak
> index f33fa1590b..7bc06c850c 100644
> --- a/configs/targets/loongarch64-softmmu.mak
> +++ b/configs/targets/loongarch64-softmmu.mak
> @@ -1 +1,4 @@
> +TARGET_ARCH=loongarch64
> +TARGET_BASE_ARCH=loongarch
> +TARGET_SUPPORTS_MTTCG=y
>   TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml
> diff --git a/hw/Kconfig b/hw/Kconfig
> index ad20cce0a9..f71b2155ed 100644
> --- a/hw/Kconfig
> +++ b/hw/Kconfig
> @@ -49,6 +49,7 @@ source avr/Kconfig
>   source cris/Kconfig
>   source hppa/Kconfig
>   source i386/Kconfig
> +source loongarch/Kconfig
>   source m68k/Kconfig
>   source microblaze/Kconfig
>   source mips/Kconfig
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> new file mode 100644
> index 0000000000..ae8498de6a
> --- /dev/null
> +++ b/hw/loongarch/Kconfig
> @@ -0,0 +1,3 @@
> +config LOONGSON3_LS7A
> +    bool
> +    select PCI_EXPRESS_7A
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> new file mode 100644
> index 0000000000..28b623e927
> --- /dev/null
> +++ b/hw/loongarch/loongson3.c
> @@ -0,0 +1,160 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU loongson 3a5000 develop board emulation
> + *
> + * Copyright (c) 2021 Loongson Technology Corporation Limited
> + */
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/units.h"
> +#include "qemu/datadir.h"
> +#include "qapi/error.h"
> +#include "hw/boards.h"
> +#include "sysemu/sysemu.h"
> +#include "sysemu/qtest.h"
> +#include "sysemu/runstate.h"
> +#include "sysemu/reset.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "hw/pci-host/ls7a.h"
> +
> +
> +static void loongarch_cpu_reset(void *opaque)
> +{
> +    LoongArchCPU *cpu = opaque;
> +
> +    cpu_reset(CPU(cpu));
> +}
> +
> +#define LOONGARCH_SIMPLE_MMIO_OPS(ADDR, NAME, SIZE) \
> +({\
> +     MemoryRegion *iomem = g_new(MemoryRegion, 1);\
> +     memory_region_init_io(iomem, NULL, &loongarch_qemu_ops,\
> +                           (void *)ADDR, NAME, SIZE);\
> +     memory_region_add_subregion(&lams->system_iocsr, ADDR, iomem);\
> +})

MemoryRegions should be allocated within a device rather than directly on the heap 
which allows the device to be set as its owner. It feels as if these MemoryRegions 
should be added to separate QEMU device within the system_iocsr memory space.

> +static void loongarch_qemu_write(void *opaque, hwaddr addr,
> +                                 uint64_t val, unsigned size)
> +{
> +}
> +
> +static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    uint64_t feature = 0UL;
> +    addr = ((hwaddr)(long)opaque) + addr;
> +
> +    switch (addr) {
> +    case FEATURE_REG:
> +        feature |= 1UL << IOCSRF_MSI | 1UL << IOCSRF_EXTIOI |
> +                   1UL << IOCSRF_CSRIPI;
> +        return feature ;
> +    case VENDOR_REG:
> +        return *(uint64_t *)"Loongson-3A5000";
> +    case CPUNAME_REG:
> +        return *(uint64_t *)"3A5000";
> +    }
> +    return 0;
> +}
> +
> +static const MemoryRegionOps loongarch_qemu_ops = {
> +    .read = loongarch_qemu_read,
> +    .write = loongarch_qemu_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 4,
> +        .max_access_size = 8,
> +    },
> +};
> +
> +static void loongson3_init(MachineState *machine)
> +{
> +    const char *cpu_model = machine->cpu_type;
> +    LoongArchCPU *cpu;
> +    ram_addr_t offset = 0;
> +    ram_addr_t ram_size = machine->ram_size;
> +    uint64_t highram_size = 0;
> +    MemoryRegion *address_space_mem = get_system_memory();
> +    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
> +    int i;
> +
> +    if (!cpu_model) {
> +        cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
> +    }
> +    if (!strstr(cpu_model, "Loongson-3A5000")) {
> +        error_report("LoongArch/TCG needs cpu type Loongson-3A5000");
> +        exit(1);
> +    }
> +
> +    memory_region_init_io(&lams->system_iocsr, NULL, NULL,
> +                          lams, "iocsr", UINT64_MAX);
> +    address_space_init(&lams->address_space_iocsr,
> +                       &lams->system_iocsr, "IOCSR");

address_space_init() needs to be in a realize() function instead of an init() 
function otherwise it causes problems with object lifecycles.

> +    /* Init CPUs */
> +    for (i = 0; i < machine->smp.cpus; i++) {
> +        Object *cpuobj = NULL;
> +        CPUState *cs;
> +
> +        cpuobj = object_new(machine->cpu_type);
> +
> +        cs = CPU(cpuobj);
> +        cs->cpu_index = i;

As per my previous comment: is the line above still needed?

> +        qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
> +        object_unref(cpuobj);

Can you use qdev_realize_and_unref() instead of handling this separately?

> +        cpu = LOONGARCH_CPU(cs);
> +        if (cpu == NULL) {
> +            fprintf(stderr, "Unable to find CPU definition\n");
> +            exit(1);
> +        }
> +        qemu_register_reset(loongarch_cpu_reset, cpu);
> +    }
> +
> +    memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
> +                             machine->ram, 0, 256 * MiB);
> +    memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
> +    offset += 256 * MiB;
> +
> +    highram_size = ram_size - 256 * MiB;
> +    memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
> +                             machine->ram, offset, highram_size);
> +    memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
> +    offset += highram_size;
> +
> +    LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
> +    LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
> +    LOONGARCH_SIMPLE_MMIO_OPS(CPUNAME_REG, "loongarch_cpuname", 0x8);
> +}
> +
> +static void loongarch_class_init(ObjectClass *oc, void *data)
> +{
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
> +    mc->desc = "Loongson-3A5000 LS7A1000 machine";
> +    mc->init = loongson3_init;
> +    mc->default_ram_size = 1 * GiB;
> +    mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
> +    mc->default_ram_id = "loongarch.ram";
> +    mc->max_cpus = LOONGARCH_MAX_VCPUS;
> +    mc->is_default = 1;
> +    mc->default_kernel_irqchip_split = false;
> +    mc->block_default_type = IF_VIRTIO;
> +    mc->default_boot_order = "c";
> +    mc->no_cdrom = 1;
> +}
> +
> +static const TypeInfo loongarch_machine_types[] = {
> +    {
> +        .name           = TYPE_LOONGARCH_MACHINE,
> +        .parent         = TYPE_MACHINE,
> +        .instance_size  = sizeof(LoongArchMachineState),
> +        .class_init     = loongarch_class_init,
> +    }
> +};
> +
> +DEFINE_TYPES(loongarch_machine_types)
> diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
> new file mode 100644
> index 0000000000..1db3529cbc
> --- /dev/null
> +++ b/hw/loongarch/meson.build
> @@ -0,0 +1,4 @@
> +loongarch_ss = ss.source_set()
> +loongarch_ss.add(when: 'CONFIG_LOONGSON3_LS7A', if_true: files('loongson3.c'))
> +
> +hw_arch += {'loongarch': loongarch_ss}
> diff --git a/hw/meson.build b/hw/meson.build
> index b3366c888e..95202649b7 100644
> --- a/hw/meson.build
> +++ b/hw/meson.build
> @@ -49,6 +49,7 @@ subdir('avr')
>   subdir('cris')
>   subdir('hppa')
>   subdir('i386')
> +subdir('loongarch')
>   subdir('m68k')
>   subdir('microblaze')
>   subdir('mips')
> diff --git a/include/exec/poison.h b/include/exec/poison.h
> index 7ad4ad18e8..590bc305c7 100644
> --- a/include/exec/poison.h
> +++ b/include/exec/poison.h
> @@ -14,6 +14,7 @@
>   #pragma GCC poison TARGET_CRIS
>   #pragma GCC poison TARGET_HEXAGON
>   #pragma GCC poison TARGET_HPPA
> +#pragma GCC poison TARGET_LOONGARCH64
>   #pragma GCC poison TARGET_M68K
>   #pragma GCC poison TARGET_MICROBLAZE
>   #pragma GCC poison TARGET_MIPS
> @@ -73,6 +74,7 @@
>   #pragma GCC poison CONFIG_HPPA_DIS
>   #pragma GCC poison CONFIG_I386_DIS
>   #pragma GCC poison CONFIG_HEXAGON_DIS
> +#pragma GCC poison CONFIG_LOONGARCH_DIS
>   #pragma GCC poison CONFIG_M68K_DIS
>   #pragma GCC poison CONFIG_MICROBLAZE_DIS
>   #pragma GCC poison CONFIG_MIPS_DIS
> diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
> new file mode 100644
> index 0000000000..150403c93d
> --- /dev/null
> +++ b/include/hw/loongarch/loongarch.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Definitions for loongarch board emulation.
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef HW_LOONGARCH_H
> +#define HW_LOONGARCH_H
> +
> +#include "target/loongarch/cpu.h"
> +#include "qemu-common.h"
> +#include "hw/boards.h"
> +#include "qemu/queue.h"
> +
> +#define LOONGARCH_MAX_VCPUS     4
> +#define PM_MMIO_ADDR            0x10080000UL
> +#define PM_MMIO_SIZE            0x100
> +#define PM_CNT_MODE             0x10
> +#define FEATURE_REG             0x8
> +#define IOCSRF_TEMP             0
> +#define IOCSRF_NODECNT          1
> +#define IOCSRF_MSI              2
> +#define IOCSRF_EXTIOI           3
> +#define IOCSRF_CSRIPI           4
> +#define IOCSRF_FREQCSR          5
> +#define IOCSRF_FREQSCALE        6
> +#define IOCSRF_DVFSV1           7
> +#define IOCSRF_GMOD             9
> +#define IOCSRF_VM               11
> +
> +#define VENDOR_REG              0x10
> +#define CPUNAME_REG             0x20
> +
> +typedef struct LoongArchMachineState {
> +    /*< private >*/
> +    MachineState parent_obj;
> +
> +    AddressSpace address_space_iocsr;
> +    MemoryRegion system_iocsr;
> +    MemoryRegion lowmem;
> +    MemoryRegion highmem;
> +} LoongArchMachineState;
> +
> +#define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("loongson3-ls7a")
> +DECLARE_INSTANCE_CHECKER(LoongArchMachineState, LOONGARCH_MACHINE,
> +                         TYPE_LOONGARCH_MACHINE)
> +#endif
> diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
> index 70c579560a..3ac3634bbb 100644
> --- a/include/sysemu/arch_init.h
> +++ b/include/sysemu/arch_init.h
> @@ -24,6 +24,7 @@ enum {
>       QEMU_ARCH_RX = (1 << 20),
>       QEMU_ARCH_AVR = (1 << 21),
>       QEMU_ARCH_HEXAGON = (1 << 22),
> +    QEMU_ARCH_LOONGARCH = (1 << 23),
>   };
>   
>   extern const uint32_t arch_type;
> diff --git a/qapi/machine.json b/qapi/machine.json
> index 067e3f5378..510ad6e566 100644
> --- a/qapi/machine.json
> +++ b/qapi/machine.json
> @@ -30,7 +30,7 @@
>   ##
>   { 'enum' : 'SysEmuTarget',
>     'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386',
> -             'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
> +             'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
>                'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc',
>                'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
>                'sh4eb', 'sparc', 'sparc64', 'tricore',
> diff --git a/target/Kconfig b/target/Kconfig
> index ae7f24fc66..83da0bd293 100644
> --- a/target/Kconfig
> +++ b/target/Kconfig
> @@ -4,6 +4,7 @@ source avr/Kconfig
>   source cris/Kconfig
>   source hppa/Kconfig
>   source i386/Kconfig
> +source loongarch/Kconfig
>   source m68k/Kconfig
>   source microblaze/Kconfig
>   source mips/Kconfig
> diff --git a/target/loongarch/Kconfig b/target/loongarch/Kconfig
> new file mode 100644
> index 0000000000..46b26b1a85
> --- /dev/null
> +++ b/target/loongarch/Kconfig
> @@ -0,0 +1,2 @@
> +config LOONGARCH64
> +    bool
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 6d3839ea10..62c2a4d813 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -11,6 +11,7 @@
>   #include "qemu/module.h"
>   #include "sysemu/qtest.h"
>   #include "exec/exec-all.h"
> +#include "hw/qdev-properties.h"
>   #include "qapi/qapi-commands-machine-target.h"
>   #include "cpu.h"
>   #include "internals.h"
> @@ -521,6 +522,12 @@ static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
>       return oc;
>   }
>   
> +static Property loongarch_cpu_properties[] = {
> +    DEFINE_PROP_INT32("core-id", LoongArchCPU, core_id, -1),
> +    DEFINE_PROP_UINT32("id", LoongArchCPU, id, UNASSIGNED_CPU_ID),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
>   void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>   {
>       LoongArchCPU *cpu = LOONGARCH_CPU(cs);
> @@ -603,6 +610,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
>       device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
>                                       &lacc->parent_realize);
>       device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset);
> +    device_class_set_props(dc, loongarch_cpu_properties);
>   
>       cc->class_by_name = loongarch_cpu_class_by_name;
>       cc->has_work = loongarch_cpu_has_work;
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 37cbe8924e..01bed0786c 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -16,6 +16,8 @@
>   
>   #define TCG_GUEST_DEFAULT_MO (0)
>   
> +#define UNASSIGNED_CPU_ID 0xFFFFFFFF
> +
>   #define FCSR0_M1    0x1f         /* FCSR1 mask, Enables */
>   #define FCSR0_M2    0x1f1f0000   /* FCSR2 mask, Cause and Flags */
>   #define FCSR0_M3    0x300        /* FCSR3 mask, Round Mode */
> @@ -362,6 +364,8 @@ struct LoongArchCPU {
>       CPUNegativeOffsetState neg;
>       CPULoongArchState env;
>       QEMUTimer timer; /* Internal timer */
> +    uint32_t id;
> +    int32_t core_id;
>   };
>   
>   #define TYPE_LOONGARCH_CPU "loongarch-cpu"

ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 16/27] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC)
  2021-12-04 12:07 ` [RFC PATCH v3 16/27] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC) Xiaojuan Yang
@ 2021-12-17 23:54   ` Mark Cave-Ayland
  2021-12-21  3:43     ` yangxiaojuan
  0 siblings, 1 reply; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-17 23:54 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, i.qemu, richard.henderson, laurent,
	peterx, f4bug, alistair.francis, maobibo, pbonzini, chenhuacai,
	alex.bennee, gaosong

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> Loongson-3A5000 support 14 interrupts from 64 - 77(Timer->75 IPI->76)
> Loongson-3A5000 and ls7a form a legacy model and extended model irq
> hierarchy.Tcg mode emulate a simplified extended model which
> has no Legacy I/O Interrupt Controller(LIOINTC) and LPC.
> e.g:
> 
>   |    +-----+    +---------+     +-------+             |
>   |    | IPI |--> | CPUINTC | <-- | Timer |             |
>   |    +-----+    +---------+     +-------+             |
>   |                    ^                                |
>   |                    |                                |
>   |               +---------+
>   |               | EIOINTC |
>   |               +---------+
>   |                ^       ^                            |
>   |                |       |                            |
>   |         +---------+ +---------+                     |
>   |         | PCH-PIC | | PCH-MSI |                     |
>   |         +---------+ +---------+                     |
>   |           ^     ^           ^                       |
>   |           |     |           |                       |
>   |   +---------+ +---------+ +---------+               |
>   |   | UARTs | | Devices | | Devices |                 |
>   |   +---------+ +---------+ +---------+               |
>   |        ^                                            |
> 
> The following series patch will realize the interrupt
> controller in this model.
> 
> More detailed info can be found at the kernel doc or manual
> 1.https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/
> linux-loongson.git/tree/Documentation/loongarch?h=loongarch-next
> 2.https://github.com/loongson/LoongArch-Documentation
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   target/loongarch/cpu.c | 28 ++++++++++++++++++++++++++++
>   1 file changed, 28 insertions(+)
> 
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 62c2a4d813..afa550c950 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -504,11 +504,39 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
>       lacc->parent_realize(dev, errp);
>   }
>   
> +#ifndef CONFIG_USER_ONLY
> +static void loongarch_cpu_set_irq(void *opaque, int irq, int level)
> +{
> +    LoongArchCPU *cpu = opaque;
> +    CPULoongArchState *env = &cpu->env;
> +    CPUState *cs = CPU(cpu);
> +
> +    if (irq < 0 || irq > N_IRQS) {
> +        return;
> +    }
> +
> +    if (level) {
> +        env->CSR_ESTAT |= 1 << irq;
> +    } else {
> +        env->CSR_ESTAT &= ~(1 << irq);
> +    }
> +
> +    if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
> +        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
> +    } else {
> +        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
> +    }
> +}
> +#endif
> +
>   static void loongarch_cpu_initfn(Object *obj)
>   {
>       LoongArchCPU *cpu = LOONGARCH_CPU(obj);
>   
>       cpu_set_cpustate_pointers(cpu);
> +#ifndef CONFIG_USER_ONLY
> +    qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
> +#endif
>   }
>   
>   static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)

Rather than use defines to split out user mode, I would suggest using a separate 
function in a similar way to sparc64_cpu_devinit() in hw/sparc64/sparc64.c to set up 
the parts of the CPU that are only required in system mode. This function can then be 
called as part of the board setup.


ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 17/27] hw/loongarch: Add LoongArch ipi interrupt support(IPI)
  2021-12-04 12:07 ` [RFC PATCH v3 17/27] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
@ 2021-12-18  0:09   ` Mark Cave-Ayland
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-18  0:09 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> This patch realize the IPI interrupt controller.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/intc/Kconfig                 |   3 +
>   hw/intc/loongarch_ipi.c         | 162 ++++++++++++++++++++++++++++++++
>   hw/intc/meson.build             |   1 +
>   hw/intc/trace-events            |   4 +
>   hw/loongarch/Kconfig            |   1 +
>   include/hw/intc/loongarch_ipi.h |  45 +++++++++
>   target/loongarch/cpu.h          |   1 +
>   7 files changed, 217 insertions(+)
>   create mode 100644 hw/intc/loongarch_ipi.c
>   create mode 100644 include/hw/intc/loongarch_ipi.h
> 
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index 78aed93c45..511dcac537 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -73,3 +73,6 @@ config GOLDFISH_PIC
>   
>   config M68K_IRQC
>       bool
> +
> +config LOONGARCH_IPI
> +    bool
> diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
> new file mode 100644
> index 0000000000..72e434c983
> --- /dev/null
> +++ b/hw/intc/loongarch_ipi.c
> @@ -0,0 +1,162 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch ipi interrupt support
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/sysbus.h"
> +#include "hw/intc/loongarch_ipi.h"
> +#include "hw/irq.h"
> +#include "qapi/error.h"
> +#include "qemu/log.h"
> +#include "exec/address-spaces.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
> +{
> +    ipi_core *s = opaque;
> +    uint64_t ret = 0;
> +
> +    addr &= 0xff;
> +    switch (addr) {
> +    case CORE_STATUS_OFF:
> +        ret = s->status;
> +        break;
> +    case CORE_EN_OFF:
> +        ret = s->en;
> +        break;
> +    case CORE_SET_OFF:
> +        ret = 0;
> +        break;
> +    case CORE_CLEAR_OFF:
> +        ret = 0;
> +        break;
> +    case CORE_BUF_20 ... CORE_BUF_38:
> +        if (size == 4) {
> +            ret = ldl_p((void *)s->buf + (addr - CORE_BUF_20));
> +        } else if (size == 8) {
> +            ret = ldq_p((void *)s->buf + (addr - CORE_BUF_20));
> +        }
> +        break;
> +    default:
> +        qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
> +        break;
> +    }
> +
> +    trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
> +    return ret;
> +}
> +
> +static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
> +                                 unsigned size)
> +{
> +    ipi_core *s = opaque;
> +
> +    addr &= 0xff;
> +    trace_loongarch_ipi_write(size, (uint64_t)addr, val);
> +    switch (addr) {
> +    case CORE_STATUS_OFF:
> +        qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
> +        break;
> +    case CORE_EN_OFF:
> +        s->en = val;
> +        break;
> +    case CORE_SET_OFF:
> +        s->status |= val;
> +        if (s->status != 0) {
> +            qemu_irq_raise(s->irq);
> +        }
> +        break;
> +    case CORE_CLEAR_OFF:
> +        s->status ^= val;
> +        if (s->status == 0) {
> +            qemu_irq_lower(s->irq);
> +        }
> +        break;
> +    case CORE_BUF_20 ... CORE_BUF_38:
> +        if (size == 4) {
> +            stl_p((void *)s->buf + (addr - CORE_BUF_20), val);
> +        } else if (size == 8) {
> +            stq_p((void *)s->buf + (addr - CORE_BUF_20), val);
> +        }
> +        break;
> +    default:
> +        qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps loongarch_ipi_ops = {
> +    .read = loongarch_ipi_readl,
> +    .write = loongarch_ipi_writel,
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 8,

This ensures that 8 byte accesses are always split into 2 x 4 byte accesses so I 
don't think the size == 8 parts are being used?

The use of ldl_p() and stl_p() doesn't seem right here: if you're setting 
.impl.min_access_size to 4 then that would suggest that buf in struct ipi_core should 
be an array of uint32_t instead of uint64_t, so then you can just use s->buf[offset] 
directly.

> +    .valid.min_access_size = 4,
> +    .valid.max_access_size = 8,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void loongarch_ipi_init(Object *obj)
> +{
> +    loongarch_ipi *s = LOONGARCH_IPI(obj);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> +    int cpu;
> +
> +    for (cpu = 0; cpu < MACHINE(qdev_get_machine())->smp.cpus; cpu++) {
> +        memory_region_init_io(&s->ipi_mmio[cpu], obj, &loongarch_ipi_ops,
> +                              &s->core[cpu], "loongarch_ipi", 0x100);
> +        sysbus_init_mmio(sbd, &s->ipi_mmio[cpu]);
> +        qdev_init_gpio_out(DEVICE(obj), &s->core[cpu].irq, 1);
> +   }
> +}
> +
> +static const VMStateDescription vmstate_ipi_core = {
> +    .name = "ipi-single",
> +    .version_id = 0,
> +    .minimum_version_id = 0,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(status, ipi_core),
> +        VMSTATE_UINT32(en, ipi_core),
> +        VMSTATE_UINT32(set, ipi_core),
> +        VMSTATE_UINT32(clear, ipi_core),
> +        VMSTATE_UINT64_ARRAY(buf, ipi_core, MAX_IPI_MBX_NUM),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static const VMStateDescription vmstate_loongarch_ipi = {
> +    .name = TYPE_LOONGARCH_IPI,
> +    .version_id = 0,
> +    .minimum_version_id = 0,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_STRUCT_ARRAY(core, loongarch_ipi, MAX_IPI_CORE_NUM, 0,
> +                             vmstate_ipi_core, ipi_core),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->vmsd = &vmstate_loongarch_ipi;
> +}
> +
> +static const TypeInfo loongarch_ipi_info = {
> +    .name          = TYPE_LOONGARCH_IPI,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(loongarch_ipi),
> +    .instance_init = loongarch_ipi_init,
> +    .class_init    = loongarch_ipi_class_init,
> +};
> +
> +static void loongarch_ipi_register_types(void)
> +{
> +    type_register_static(&loongarch_ipi_info);
> +}
> +
> +type_init(loongarch_ipi_register_types)
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index c89d2ca180..51f0c3988a 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -57,3 +57,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
>   		if_true: files('spapr_xive_kvm.c'))
>   specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
>   specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
> +specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 9aba7e3a7a..124608e51f 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -246,3 +246,7 @@ 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 0x%" 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"
> +
> +# loongarch_ipi.c
> +loongarch_ipi_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
> +loongarch_ipi_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index ae8498de6a..1591574397 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -1,3 +1,4 @@
>   config LOONGSON3_LS7A
>       bool
>       select PCI_EXPRESS_7A
> +    select LOONGARCH_IPI
> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
> new file mode 100644
> index 0000000000..d2397e53e7
> --- /dev/null
> +++ b/include/hw/intc/loongarch_ipi.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch ipi interrupt header files
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef HW_LOONGARCH_IPI_H
> +#define HW_LOONGARCH_IPI_H
> +
> +/* Mainy used by iocsr read and write */
> +#define SMP_IPI_MAILBOX      0x1000ULL
> +#define CORE_STATUS_OFF       0x0
> +#define CORE_EN_OFF           0x4
> +#define CORE_SET_OFF          0x8
> +#define CORE_CLEAR_OFF        0xc
> +#define CORE_BUF_20           0x20
> +#define CORE_BUF_28           0x28
> +#define CORE_BUF_30           0x30
> +#define CORE_BUF_38           0x38
> +
> +#define MAX_IPI_CORE_NUM      16
> +#define MAX_IPI_MBX_NUM       4
> +
> +#define TYPE_LOONGARCH_IPI "loongarch_ipi"
> +DECLARE_INSTANCE_CHECKER(struct loongarch_ipi, LOONGARCH_IPI,
> +                         TYPE_LOONGARCH_IPI)
> +
> +
> +typedef struct ipi_core {
> +    uint32_t status;
> +    uint32_t en;
> +    uint32_t set;
> +    uint32_t clear;
> +    uint64_t buf[MAX_IPI_MBX_NUM];
> +    qemu_irq irq;
> +} ipi_core;

Is ipi_core reused or can it be part of the loongarch_ipi struct?

> +typedef struct loongarch_ipi {
> +    SysBusDevice parent_obj;
> +    ipi_core core[MAX_IPI_CORE_NUM];
> +    MemoryRegion ipi_mmio[MAX_IPI_CORE_NUM];
> +} loongarch_ipi;

QOM types within QEMU are generally defined in camelcase rather than snake case i.e. 
LoongArchIPI rather than loongarch_ipi.

> +#endif
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 01bed0786c..b287d7fca8 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -153,6 +153,7 @@ extern const char * const fregnames[];
>   
>   #define N_IRQS      14
>   #define IRQ_TIMER   11
> +#define IRQ_IPI     12
>   
>   #define LOONGARCH_TLB_MAX      (2048 + 64) /* 2048 STLB + 64 MTLB */

ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 18/27] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
  2021-12-04 12:07 ` [RFC PATCH v3 18/27] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) Xiaojuan Yang
@ 2021-12-18  0:33   ` Mark Cave-Ayland
  2021-12-22  2:38     ` yangxiaojuan
  0 siblings, 1 reply; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-18  0:33 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> This patch realize the PCH-PIC interrupt controller.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/intc/Kconfig                     |   4 +
>   hw/intc/loongarch_pch_pic.c         | 357 ++++++++++++++++++++++++++++
>   hw/intc/meson.build                 |   1 +
>   hw/intc/trace-events                |   5 +
>   hw/loongarch/Kconfig                |   1 +
>   include/hw/intc/loongarch_pch_pic.h |  61 +++++
>   6 files changed, 429 insertions(+)
>   create mode 100644 hw/intc/loongarch_pch_pic.c
>   create mode 100644 include/hw/intc/loongarch_pch_pic.h
> 
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index 511dcac537..96da13ad1d 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -76,3 +76,7 @@ config M68K_IRQC
>   
>   config LOONGARCH_IPI
>       bool
> +
> +config LOONGARCH_PCH_PIC
> +    bool
> +    select UNIMP
> diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
> new file mode 100644
> index 0000000000..2ede29ceb0
> --- /dev/null
> +++ b/hw/intc/loongarch_pch_pic.c
> @@ -0,0 +1,357 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU Loongson 7A1000 I/O interrupt controller.
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/sysbus.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "hw/irq.h"
> +#include "hw/intc/loongarch_pch_pic.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +#define for_each_set_bit(bit, addr, size) \
> +         for ((bit) = find_first_bit((addr), (size));            \
> +              (bit) < (size);                                    \
> +              (bit) = find_next_bit((addr), (size), (bit) + 1))
> +
> +static void pch_pic_update_irq(loongarch_pch_pic *s, uint64_t mask, int level)
> +{
> +    int i;
> +    uint64_t val;
> +    val = mask & s->intirr & (~s->int_mask);
> +
> +    for_each_set_bit(i, &val, 64) {
> +        if (level == 1) {
> +            if ((s->intisr & (0x1ULL << i)) == 0) {
> +                s->intisr |= 1ULL << i;
> +                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 1);
> +            }
> +        } else if (level == 0) {
> +            if (s->intisr & (0x1ULL << i)) {
> +                s->intisr &= ~(0x1ULL << i);
> +                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 0);
> +            }
> +        }
> +    }
> +}

The normal pattern would be to use something like:

for (i = 0; i < 64; i++) {
     if (level) {
         s->intisr |= 1ULL << i;
     } else {
         s->intisr &= ~(0x1ULL << i);
     }

     qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], level);
}

Why is it necessary to check the previous value of (s->intisr & (0x1ULL << i)) here?

> +static void pch_pic_irq_handler(void *opaque, int irq, int level)
> +{
> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
> +
> +    assert(irq < PCH_PIC_IRQ_NUM);
> +    uint64_t mask = 1ULL << irq;
> +
> +    trace_pch_pic_irq_handler(s->intedge, irq, level);
> +
> +    if (s->intedge & mask) {
> +        /* Edge triggered */
> +        if (level) {
> +            if ((s->last_intirr & mask) == 0) {
> +                s->intirr |= mask;
> +            }
> +            s->last_intirr |= mask;
> +        } else {
> +            s->last_intirr &= ~mask;
> +        }
> +    } else {
> +        /* Level triggered */
> +        if (level) {
> +            s->intirr |= mask;
> +            s->last_intirr |= mask;
> +        } else {
> +            s->intirr &= ~mask;
> +            s->last_intirr &= ~mask;
> +        }
> +
> +    }
> +    pch_pic_update_irq(s, mask, level);
> +}
> +
> +static uint64_t loongarch_pch_pic_reg_read(void *opaque, hwaddr addr,
> +                                           unsigned size)
> +{
> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
> +    uint64_t val = 0;
> +    uint32_t offset = addr & 0xfff;
> +    int64_t offset_tmp;
> +
> +    if (size == 8) {
> +        switch (offset) {
> +        case PCH_PIC_INT_ID_OFFSET:
> +            val = (PCH_PIC_INT_ID_NUM << 32) | PCH_PIC_INT_ID_VAL;
> +            break;
> +        case PCH_PIC_INT_MASK_OFFSET:
> +            val =  s->int_mask;
> +            break;
> +        case PCH_PIC_INT_STATUS_OFFSET:
> +            val = s->intisr & (~s->int_mask);
> +            break;
> +        case PCH_PIC_INT_EDGE_OFFSET:
> +            val = s->intedge;
> +            break;
> +        case PCH_PIC_INT_POL_OFFSET:
> +            val = s->int_polarity;
> +            break;
> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
> +            val = s->htmsi_en;
> +            break;
> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
> +            break;
> +        default:
> +            break;
> +        }
> +    } else if (size == 4) {
> +        switch (offset) {
> +        case PCH_PIC_INT_ID_OFFSET:
> +            val = PCH_PIC_INT_ID_VAL;
> +            break;
> +        case PCH_PIC_INT_ID_OFFSET + 4:
> +            val = PCH_PIC_INT_ID_NUM;
> +            break;
> +        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
> +            val = ldl_p((void *)&s->int_mask +
> +                        (offset - PCH_PIC_INT_MASK_OFFSET));
> +            break;
> +        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
> +            val = ldl_p((void *)&s->intisr +
> +                        (offset - PCH_PIC_INT_STATUS_OFFSET)) & (~s->int_mask);
> +            break;
> +        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
> +            val = ldl_p((void *)&s->intedge +
> +                        (offset - PCH_PIC_INT_EDGE_OFFSET));
> +            break;
> +        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
> +            val = ldl_p((void *)&s->int_polarity +
> +                        (offset - PCH_PIC_INT_POL_OFFSET));
> +            break;
> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
> +            val = ldl_p((void *)&s->htmsi_en +
> +                        (offset - PCH_PIC_HTMSI_EN_OFFSET));
> +            break;
> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
> +            break;
> +        default:
> +            break;
> +        }
> +    } else if (size == 1) {
> +        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
> +            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
> +            if (offset_tmp >= 0 && offset_tmp < 64) {
> +                val = s->htmsi_vector[offset_tmp];
> +            }
> +        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
> +            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
> +            if (offset_tmp >= 0 && offset_tmp < 64) {
> +                val = s->route_entry[offset_tmp];
> +            }
> +        }
> +    }
> +
> +    trace_loongarch_pch_pic_read(size, (uint32_t)addr, val);
> +    return val;
> +}
> +
> +static void loongarch_pch_pic_reg_write(void *opaque, hwaddr addr,
> +                                        uint64_t data, unsigned size)
> +{
> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);

Perhaps use LoongArchPCHPIC for the camel case version?

> +    int32_t offset_tmp;
> +    uint32_t offset, old;
> +    offset = addr & 0xfff;
> +
> +    trace_loongarch_pch_pic_write(size, (uint32_t)addr, data);
> +
> +    if (size == 8) {
> +        switch (offset) {
> +        case PCH_PIC_INT_MASK_OFFSET:
> +            old = s->int_mask;
> +            s->int_mask = data;
> +            if (old & ~data) {
> +                pch_pic_update_irq(s, (old & ~data), 1);
> +            } else if (~old & data) {
> +                pch_pic_update_irq(s, (~old & data), 0);
> +            }
> +            break;
> +        case PCH_PIC_INT_STATUS_OFFSET:
> +            s->intisr = data;
> +            break;
> +        case PCH_PIC_INT_EDGE_OFFSET:
> +            s->intedge = data;
> +            break;
> +        case PCH_PIC_INT_CLEAR_OFFSET:
> +            s->intirr &= (~(data & s->intedge));
> +            pch_pic_update_irq(s, data, 0);
> +            s->intisr &= (~data);
> +            break;
> +        case PCH_PIC_INT_POL_OFFSET:
> +            s->int_polarity = data;
> +            break;
> +        case PCH_PIC_HTMSI_EN_OFFSET:
> +            s->htmsi_en = data;
> +            break;
> +        case PCH_PIC_AUTO_CTRL0_OFFSET:
> +        case PCH_PIC_AUTO_CTRL1_OFFSET:
> +            break;
> +        default:
> +            break;
> +        }
> +    } else if (size == 4) {
> +        switch (offset) {
> +        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
> +            offset -= PCH_PIC_INT_MASK_OFFSET;
> +            old = ldl_p((void *)&s->int_mask + offset);
> +            stl_p((void *)&s->int_mask + offset, data);
> +
> +            if (old & ~data) {
> +                pch_pic_update_irq(s, (old & ~data), 1);
> +            } else if (~old & data) {
> +                pch_pic_update_irq(s, (~old & data), 0);
> +            }
> +            break;
> +        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
> +            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_STATUS_OFFSET),
> +                  data);
> +            break;
> +        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
> +            stl_p((void *)&s->intedge + (offset - PCH_PIC_INT_EDGE_OFFSET),
> +                  data);
> +            break;
> +        case PCH_PIC_INT_CLEAR_OFFSET...PCH_PIC_INT_CLEAR_END:
> +            old = s->intirr & (~(data & s->intedge));
> +            stl_p((void *)&s->intirr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
> +                  old);
> +            pch_pic_update_irq(s, data, 0);
> +            old = s->intisr & (~data);
> +            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
> +                  old);
> +            break;
> +        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
> +            stl_p((void *)&s->int_polarity + (offset - PCH_PIC_INT_POL_OFFSET),
> +                  data);
> +            break;
> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
> +            stl_p((void *)&s->htmsi_en + (offset - PCH_PIC_HTMSI_EN_OFFSET),
> +                  data);
> +            break;
> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
> +            break;
> +        default:
> +            break;
> +        }
> +    } else if (size == 1) {
> +        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
> +            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
> +            if (offset_tmp >= 0 && offset_tmp < 64) {
> +                s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
> +            }
> +        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
> +            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
> +            if (offset_tmp >= 0 && offset_tmp < 64) {
> +                s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
> +            }
> +        }
> +    }
> +}
> +
> +static const MemoryRegionOps loongarch_pch_pic_ops = {
> +    .read = loongarch_pch_pic_reg_read,
> +    .write = loongarch_pch_pic_reg_write,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 8,
> +    },
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};

It feels like this should be split into 2 separate memory regions: as per before set 
.min_access_size = 4 for PCH_PIC_INT_MASK_OFFSET ... PCH_PIC_AUTO_CTRL1_END and use 
uint32_t for the underlying types in loongarch_pch_pic.

This leaves a separate memory region for accesses > PCH_PIC_HTMSI_VEC_OFFSET which 
can be set with .min_access_size = 1 which maps nicely to the underlying uint8_t 
types. Which means you should be able to access the arrays directly instead of having 
to use ldl_p() and stl_p().

> +static void loongarch_pch_pic_reset(DeviceState *d)
> +{
> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(d);
> +    int i;
> +
> +    s->int_mask = -1ULL;
> +    s->htmsi_en = 0x0;
> +    s->intedge  = 0x0;
> +    s->intclr   = 0x0;
> +    s->auto_crtl0 = 0x0;
> +    s->auto_crtl1 = 0x0;
> +    for (i = 0; i < 64; i++) {
> +        s->route_entry[i] = 0x1;
> +        s->htmsi_vector[i] = 0x0;
> +    }
> +    s->intirr = 0x0;
> +    s->intisr = 0x0;
> +    s->last_intirr = 0x0;
> +    s->int_polarity = 0x0;
> +}
> +
> +static void loongarch_pch_pic_init(Object *obj)
> +{
> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(obj);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> +    int i;
> +
> +    memory_region_init_io(&s->iomem, obj, &loongarch_pch_pic_ops,
> +                          s, TYPE_LOONGARCH_PCH_PIC, 0x1000);
> +    sysbus_init_mmio(sbd, &s->iomem);
> +
> +    for (i = 0; i < PCH_PIC_IRQ_NUM; i++) {
> +        sysbus_init_irq(sbd, &s->parent_irq[i]);
> +    }
> +    qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
> +}
> +
> +static const VMStateDescription vmstate_loongarch_pch_pic = {
> +    .name = TYPE_LOONGARCH_PCH_PIC,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT64(int_mask, loongarch_pch_pic),
> +        VMSTATE_UINT64(htmsi_en, loongarch_pch_pic),
> +        VMSTATE_UINT64(intedge, loongarch_pch_pic),
> +        VMSTATE_UINT64(intclr, loongarch_pch_pic),
> +        VMSTATE_UINT64(auto_crtl0, loongarch_pch_pic),
> +        VMSTATE_UINT64(auto_crtl1, loongarch_pch_pic),
> +        VMSTATE_UINT8_ARRAY(route_entry, loongarch_pch_pic, 64),
> +        VMSTATE_UINT8_ARRAY(htmsi_vector, loongarch_pch_pic, 64),
> +        VMSTATE_UINT64(last_intirr, loongarch_pch_pic),
> +        VMSTATE_UINT64(intirr, loongarch_pch_pic),
> +        VMSTATE_UINT64(intisr, loongarch_pch_pic),
> +        VMSTATE_UINT64(int_polarity, loongarch_pch_pic),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = loongarch_pch_pic_reset;
> +    dc->vmsd = &vmstate_loongarch_pch_pic;
> +}
> +
> +static const TypeInfo loongarch_pch_pic_info = {
> +    .name          = TYPE_LOONGARCH_PCH_PIC,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(loongarch_pch_pic),
> +    .instance_init = loongarch_pch_pic_init,
> +    .class_init    = loongarch_pch_pic_class_init,
> +};
> +
> +static void loongarch_pch_pic_register_types(void)
> +{
> +    type_register_static(&loongarch_pch_pic_info);
> +}
> +
> +type_init(loongarch_pch_pic_register_types)
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 51f0c3988a..33ba63266e 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -58,3 +58,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
>   specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
>   specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
>   specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
> +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 124608e51f..52fedf82be 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -250,3 +250,8 @@ sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
>   # loongarch_ipi.c
>   loongarch_ipi_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
>   loongarch_ipi_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
> +
> +# loongarch_pch_pic.c
> +pch_pic_irq_handler(uint32_t edge, int irq, int level) "edge 0x%02x irq %d level %d"
> +loongarch_pch_pic_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> +loongarch_pch_pic_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index 1591574397..c2b8046b94 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -2,3 +2,4 @@ config LOONGSON3_LS7A
>       bool
>       select PCI_EXPRESS_7A
>       select LOONGARCH_IPI
> +    select LOONGARCH_PCH_PIC
> diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
> new file mode 100644
> index 0000000000..bc04ed28ef
> --- /dev/null
> +++ b/include/hw/intc/loongarch_pch_pic.h
> @@ -0,0 +1,61 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch 7A1000 I/O interrupt controller definitions
> + *
> + * Copyright (c) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
> +DECLARE_INSTANCE_CHECKER(struct loongarch_pch_pic, LOONGARCH_PCH_PIC,
> +                         TYPE_LOONGARCH_PCH_PIC)
> +
> +#define PCH_PIC_IRQ_START               0
> +#define PCH_PIC_IRQ_END                 63
> +#define PCH_PIC_IRQ_NUM                 64
> +#define PCH_PIC_INT_ID_VAL              0x7000000UL
> +#define PCH_PIC_INT_ID_NUM              0x3f0001UL
> +
> +#define PCH_PIC_INT_ID_OFFSET           0x00
> +#define PCH_PIC_INT_ID_END              0x07
> +#define PCH_PIC_INT_MASK_OFFSET         0x20
> +#define PCH_PIC_INT_MASK_END            0x27
> +#define PCH_PIC_HTMSI_EN_OFFSET         0x40
> +#define PCH_PIC_HTMSI_EN_END            0x47
> +#define PCH_PIC_INT_EDGE_OFFSET         0x60
> +#define PCH_PIC_INT_EDGE_END            0x67
> +#define PCH_PIC_INT_CLEAR_OFFSET        0x80
> +#define PCH_PIC_INT_CLEAR_END           0x87
> +#define PCH_PIC_AUTO_CTRL0_OFFSET       0xc0
> +#define PCH_PIC_AUTO_CTRL0_END          0xc7
> +#define PCH_PIC_AUTO_CTRL1_OFFSET       0xe0
> +#define PCH_PIC_AUTO_CTRL1_END          0xe8
> +#define PCH_PIC_ROUTE_ENTRY_OFFSET      0x100
> +#define PCH_PIC_ROUTE_ENTRY_END         0x13f
> +#define PCH_PIC_HTMSI_VEC_OFFSET        0x200
> +#define PCH_PIC_HTMSI_VEC_END           0x23f
> +#define PCH_PIC_INT_STATUS_OFFSET       0x3a0
> +#define PCH_PIC_INT_STATUS_END          0x3a7
> +#define PCH_PIC_INT_POL_OFFSET          0x3e0
> +#define PCH_PIC_INT_POL_END             0x3e7
> +
> +typedef struct loongarch_pch_pic {
> +    SysBusDevice parent_obj;
> +    qemu_irq parent_irq[64];
> +    uint64_t int_mask; /*0x020 interrupt mask register*/
> +    uint64_t htmsi_en;/*0x040 1=msi*/
> +    uint64_t intedge; /*0x060 edge=1 level  =0*/
> +    uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
> +    uint64_t auto_crtl0; /*0x0c0*/
> +    uint64_t auto_crtl1; /*0x0e0*/
> +    uint8_t route_entry[64]; /*0x100 - 0x138*/
> +    uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
> +    uint64_t last_intirr;    /* edge detection */
> +    uint64_t intirr; /* 0x380 interrupt request register */
> +    uint64_t intisr; /* 0x3a0 interrupt service register */
> +    /*
> +     * 0x3e0 interrupt level polarity selection
> +     * register 0 for high level trigger
> +     */
> +    uint64_t int_polarity;
> +    MemoryRegion iomem;
> +} loongarch_pch_pic;


ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 19/27] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI)
  2021-12-04 12:07 ` [RFC PATCH v3 19/27] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) Xiaojuan Yang
@ 2021-12-18  0:36   ` Mark Cave-Ayland
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-18  0:36 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> This patch realize PCH-MSI interrupt controller.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/intc/Kconfig                     |  5 +++
>   hw/intc/loongarch_pch_msi.c         | 67 +++++++++++++++++++++++++++++
>   hw/intc/meson.build                 |  1 +
>   hw/intc/trace-events                |  3 ++
>   hw/loongarch/Kconfig                |  1 +
>   include/hw/intc/loongarch_pch_msi.h | 21 +++++++++
>   6 files changed, 98 insertions(+)
>   create mode 100644 hw/intc/loongarch_pch_msi.c
>   create mode 100644 include/hw/intc/loongarch_pch_msi.h
> 
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index 96da13ad1d..dc5f41f5f5 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -80,3 +80,8 @@ config LOONGARCH_IPI
>   config LOONGARCH_PCH_PIC
>       bool
>       select UNIMP
> +
> +config LOONGARCH_PCH_MSI
> +    select MSI_NONBROKEN
> +    bool
> +    select UNIMP
> diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c
> new file mode 100644
> index 0000000000..c7777f763b
> --- /dev/null
> +++ b/hw/intc/loongarch_pch_msi.c
> @@ -0,0 +1,67 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU Loongson 7A1000 msi interrupt controller.
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/sysbus.h"
> +#include "hw/irq.h"
> +#include "hw/intc/loongarch_pch_msi.h"
> +#include "hw/intc/loongarch_pch_pic.h"
> +#include "hw/pci/msi.h"
> +#include "hw/misc/unimp.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    return 0;
> +}
> +
> +static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
> +                                    uint64_t val, unsigned size)
> +{
> +    loongarch_pch_msi *s = LOONGARCH_PCH_MSI(opaque);
> +    int irq_num = val & 0xff;
> +
> +    trace_loongarch_msi_set_irq(irq_num);
> +    qemu_set_irq(s->pch_msi_irq[irq_num - PCH_PIC_IRQ_NUM], 1);
> +}
> +
> +static const MemoryRegionOps loongarch_pch_msi_ops = {
> +    .read  = loongarch_msi_mem_read,
> +    .write = loongarch_msi_mem_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void loongarch_pch_msi_init(Object *obj)
> +{
> +    loongarch_pch_msi *s = LOONGARCH_PCH_MSI(obj);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> +    int i;
> +
> +    memory_region_init_io(&s->msi_mmio, obj, &loongarch_pch_msi_ops,
> +                          s, TYPE_LOONGARCH_PCH_MSI, 0x8);
> +    sysbus_init_mmio(sbd, &s->msi_mmio);
> +    msi_nonbroken = true;
> +
> +    for (i = 0; i < PCH_MSI_IRQ_NUM; i++) {
> +        sysbus_init_irq(sbd, &s->pch_msi_irq[i]);
> +    }
> +}
> +
> +static const TypeInfo loongarch_pch_msi_info = {
> +    .name          = TYPE_LOONGARCH_PCH_MSI,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(loongarch_pch_msi),
> +    .instance_init = loongarch_pch_msi_init,
> +};
> +
> +static void loongarch_pch_msi_register_types(void)
> +{
> +    type_register_static(&loongarch_pch_msi_info);
> +}
> +
> +type_init(loongarch_pch_msi_register_types)
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 33ba63266e..acefe0c5aa 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -59,3 +59,4 @@ specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
>   specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
>   specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
>   specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
> +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 52fedf82be..20da343cfe 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -255,3 +255,6 @@ loongarch_ipi_write(unsigned size, uint32_t addr, unsigned long val) "size: %u a
>   pch_pic_irq_handler(uint32_t edge, int irq, int level) "edge 0x%02x irq %d level %d"
>   loongarch_pch_pic_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>   loongarch_pch_pic_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> +
> +# loongarch_pch_msi.c
> +loongarch_msi_set_irq(int irq_num) "set msi irq %d"
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index c2b8046b94..cd38d03a19 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -3,3 +3,4 @@ config LOONGSON3_LS7A
>       select PCI_EXPRESS_7A
>       select LOONGARCH_IPI
>       select LOONGARCH_PCH_PIC
> +    select LOONGARCH_PCH_MSI
> diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h
> new file mode 100644
> index 0000000000..35297d51d8
> --- /dev/null
> +++ b/include/hw/intc/loongarch_pch_msi.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch 7A1000 I/O interrupt controller definitions
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi"
> +DECLARE_INSTANCE_CHECKER(struct loongarch_pch_msi, LOONGARCH_PCH_MSI,
> +                         TYPE_LOONGARCH_PCH_MSI)
> +
> +/* Msi irq start start from 64 to 255 */
> +#define PCH_MSI_IRQ_START   64
> +#define PCH_MSI_IRQ_END     255
> +#define PCH_MSI_IRQ_NUM     192
> +
> +typedef struct loongarch_pch_msi {
> +    SysBusDevice parent_obj;
> +    qemu_irq pch_msi_irq[PCH_MSI_IRQ_NUM];
> +    MemoryRegion msi_mmio;
> +} loongarch_pch_msi;

LoongArchPCHMSI in camel-case?


ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 20/27] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
  2021-12-04 12:07 ` [RFC PATCH v3 20/27] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
@ 2021-12-18  0:50   ` Mark Cave-Ayland
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-18  0:50 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> This patch realize the EIOINTC interrupt controller.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/intc/Kconfig                    |   3 +
>   hw/intc/loongarch_extioi.c         | 499 +++++++++++++++++++++++++++++
>   hw/intc/meson.build                |   1 +
>   hw/intc/trace-events               |   9 +
>   hw/loongarch/Kconfig               |   1 +
>   include/hw/intc/loongarch_extioi.h |  69 ++++
>   6 files changed, 582 insertions(+)
>   create mode 100644 hw/intc/loongarch_extioi.c
>   create mode 100644 include/hw/intc/loongarch_extioi.h
> 
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index dc5f41f5f5..2868b25005 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -85,3 +85,6 @@ config LOONGARCH_PCH_MSI
>       select MSI_NONBROKEN
>       bool
>       select UNIMP
> +
> +config LOONGARCH_EXTIOI
> +    bool
> diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
> new file mode 100644
> index 0000000000..9838f05806
> --- /dev/null
> +++ b/hw/intc/loongarch_extioi.c
> @@ -0,0 +1,499 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Loongson 3A5000 ext interrupt controller emulation
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/module.h"
> +#include "qemu/log.h"
> +#include "hw/irq.h"
> +#include "hw/sysbus.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "hw/qdev-properties.h"
> +#include "exec/address-spaces.h"
> +#include "hw/intc/loongarch_extioi.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +static void extioi_update_irq(void *opaque, int irq_num, int level)
> +{
> +    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
> +    uint8_t  ipnum, cpu;
> +    unsigned long found1, found2;
> +
> +    ipnum = s->sw_ipmap[irq_num];
> +    cpu   = s->sw_coremap[irq_num];
> +    if (level == 1) {
> +        if (test_bit(irq_num, (void *)s->enable) == false) {
> +            return;
> +        }
> +        bitmap_set((void *)s->coreisr[cpu], irq_num, 1);
> +        found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
> +                               EXTIOI_IRQS, 0);
> +        bitmap_set((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
> +
> +        if (found1 >= EXTIOI_IRQS) {
> +            qemu_set_irq(s->parent_irq[cpu][ipnum], level);
> +        }
> +    } else {
> +        bitmap_clear((void *)s->coreisr[cpu], irq_num, 1);
> +        found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
> +                               EXTIOI_IRQS, 0);
> +        bitmap_clear((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
> +        found2 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
> +                               EXTIOI_IRQS, 0);
> +
> +        if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) {
> +            qemu_set_irq(s->parent_irq[cpu][ipnum], level);
> +        }
> +    }
> +}
> +
> +static void extioi_setirq(void *opaque, int irq, int level)
> +{
> +    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
> +    trace_extioi_setirq(irq, level);
> +    extioi_update_irq(s, irq, level);
> +}
> +
> +static uint32_t extioi_readb(void *opaque, hwaddr addr)
> +{
> +    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
> +    unsigned long offset, reg_count;
> +    uint8_t ret;
> +    int cpu;
> +
> +    offset = addr & 0xffff;
> +
> +    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
> +        ret = ldub_p((void *)s->enable + (offset - EXTIOI_ENABLE_START));
> +    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
> +        ret = ldub_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START));
> +    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
> +        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
> +        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
> +        ret = ldub_p((void *)s->coreisr[cpu] + reg_count);
> +    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
> +        ret = ldub_p((void *)&s->ipmap + (offset - EXTIOI_IPMAP_START));
> +    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
> +        ret = ldub_p((void *)s->coremap + (offset - EXTIOI_COREMAP_START));
> +    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
> +        ret = ldub_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START));
> +    }
> +
> +    trace_loongarch_extioi_readb((uint32_t)addr, ret);
> +    return ret;
> +}
> +
> +static uint32_t extioi_readw(void *opaque, hwaddr addr)
> +{
> +    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
> +    unsigned long offset, reg_count;
> +    uint32_t ret;
> +    int cpu;
> +
> +    offset = addr & 0xffff;
> +
> +    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
> +        ret = ldl_p((void *)s->enable + (offset - EXTIOI_ENABLE_START));
> +    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
> +        ret = ldl_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START));
> +    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
> +        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
> +        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
> +        ret = ldl_p((void *)s->coreisr[cpu] + reg_count);
> +    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
> +        ret = ldl_p((void *)&s->ipmap + (offset - EXTIOI_IPMAP_START));
> +    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
> +        ret = ldl_p((void *)s->coremap + (offset - EXTIOI_COREMAP_START));
> +    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
> +        ret = ldl_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START));
> +    }
> +
> +    trace_loongarch_extioi_readw((uint32_t)addr, ret);
> +    return ret;
> +}
> +
> +static uint64_t extioi_readl(void *opaque, hwaddr addr)
> +{
> +    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
> +    unsigned long offset, reg_count;
> +    uint64_t ret;
> +    int cpu;
> +
> +    offset = addr & 0xffff;
> +
> +    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
> +        ret = ldq_p((void *)s->enable + (offset - EXTIOI_ENABLE_START));
> +    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
> +        ret = ldq_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START));
> +    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
> +        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
> +        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
> +        ret = ldq_p((void *)s->coreisr[cpu] + reg_count);
> +    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
> +        ret = ldq_p((void *)&s->ipmap + (offset - EXTIOI_IPMAP_START));
> +    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
> +        ret = ldq_p((void *)s->coremap + (offset - EXTIOI_COREMAP_START));
> +    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
> +        ret = ldq_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START));
> +    }
> +
> +    trace_loongarch_extioi_readl((uint32_t)addr, ret);
> +    return ret;
> +}
> +
> +static void extioi_writeb(void *opaque, hwaddr addr, uint32_t val,
> +                          unsigned size)
> +{
> +    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
> +    unsigned long offset, reg_count;
> +    uint8_t old_data;
> +    int cpu, i, j, ipnum, level, irqnum, bits;
> +
> +    offset = addr & 0xffff;
> +    val = val & 0xffUL;
> +
> +    trace_loongarch_extioi_writeb(size, (uint32_t)addr, val);
> +    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
> +        reg_count = (offset - EXTIOI_ENABLE_START);
> +        old_data = ldub_p((void *)s->enable + reg_count);
> +        if (old_data != val) {
> +            stb_p((void *)s->enable + reg_count, val);
> +            old_data = old_data ^ val;
> +            bits = size * 8;
> +            while ((i = find_first_bit((void *)&old_data, bits)) != bits) {
> +                level = test_bit(i, (unsigned long *)&val);
> +                extioi_update_irq(s, i + reg_count * 8, level);
> +                clear_bit(i, (void *)&old_data);
> +            }
> +        }
> +    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
> +        stb_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START), val);
> +    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
> +        reg_count = (offset - EXTIOI_COREISR_START) & 0x1f;
> +        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
> +
> +        old_data = ldub_p((void *)s->coreisr[cpu] + reg_count);
> +        stb_p((void *)s->coreisr[cpu] + reg_count, (old_data & ~val));
> +
> +        if (old_data != (old_data & ~val)) {
> +            bits = size * 8;
> +
> +            while ((i = find_first_bit((void *)&val, bits)) != bits) {
> +                j = test_bit(i, (unsigned long *)&old_data);
> +                if (j) {
> +                    extioi_update_irq(s, i + reg_count * 8, 0);
> +                }
> +                clear_bit(i, (void *)&val);
> +            }
> +        }
> +    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
> +        /* Drop arch.core_ip_mask use s->ipmap */
> +        reg_count = (offset - EXTIOI_IPMAP_START);
> +        stb_p((void *)&s->ipmap + reg_count, val);
> +
> +        /* Routing in groups of 32 interrupt */
> +        while (val) {
> +            ipnum = find_first_bit((void *)&val, 4);
> +            for (i = 0; i < 32; i++) {
> +                irqnum = reg_count * 32 + i;
> +                if (ipnum != 4) {
> +                    s->sw_ipmap[irqnum] = ipnum;
> +                } else {
> +                    s->sw_ipmap[irqnum] = 0;
> +                }
> +            }
> +            val = val >> 8;
> +            reg_count += 1;
> +        }
> +    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
> +        reg_count = (offset - EXTIOI_COREMAP_START);
> +
> +        /* Only map the core */
> +        while (val) {
> +            stb_p((void *)s->coremap + reg_count, val);
> +            s->sw_coremap[reg_count] = val & 0xf;
> +            val = val >> 8;
> +        }
> +    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
> +        stb_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START), val);
> +    }
> +}
> +
> +static void extioi_writew(void *opaque, hwaddr addr, uint32_t val,
> +                          unsigned size)
> +{
> +    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
> +    int cpu, level, irqnum, ipnum;
> +    uint32_t offset, old_data, reg_count, i, j, bits;
> +
> +    offset = addr & 0xffff;
> +    trace_loongarch_extioi_writew(size, (uint32_t)addr, val);
> +
> +    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
> +        reg_count = (offset - EXTIOI_ENABLE_START);
> +        old_data = ldl_p((void *)s->enable + reg_count);
> +        if (old_data != val) {
> +            stl_p((void *)s->enable + reg_count, val);
> +            old_data = old_data ^ val;
> +
> +            bits = size * 8;
> +            while ((i = find_first_bit((void *)&old_data, bits)) != bits) {
> +                level = test_bit(i, (unsigned long *)&val);
> +                extioi_update_irq(s, i + reg_count * 8, level);
> +                clear_bit(i, (void *)&old_data);
> +            }
> +        }
> +    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
> +        stl_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START), val);
> +    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
> +        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
> +        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
> +
> +        /* Ext_core_ioisr */
> +        old_data = ldl_p((void *)s->coreisr[cpu] + reg_count);
> +        stl_p((void *)s->coreisr[cpu] + reg_count, (old_data & ~val));
> +
> +        if (old_data != (old_data & ~val)) {
> +            bits = size * 8;
> +            while ((i = find_first_bit((void *)&val, bits)) != bits) {
> +                j = test_bit(i, (unsigned long *)&old_data);
> +                if (j) {
> +                    extioi_update_irq(s, i + reg_count * 8, 0);
> +                }
> +                clear_bit(i, (void *)&val);
> +            }
> +        }
> +    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
> +        /* Drop arch.core_ip_mask use s->ipmap */
> +        reg_count = (offset - EXTIOI_IPMAP_START);
> +        stl_p((void *)&s->ipmap + reg_count, val);
> +
> +        /* Routing in groups of 32 interrupt */
> +        while (val) {
> +            ipnum = find_first_bit((void *)&val, 4);
> +            for (i = 0; i < 32; i++) {
> +                irqnum = reg_count * 32 + i;
> +                if (ipnum != 4) {
> +                    s->sw_ipmap[irqnum] = ipnum;
> +                } else {
> +                    s->sw_ipmap[irqnum] = 0;
> +                }
> +            }
> +            val = val >> 8;
> +            reg_count += 1;
> +        }
> +    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
> +        reg_count = (offset - EXTIOI_COREMAP_START);
> +        /* Only map the core */
> +        while (val) {
> +            stl_p((void *)s->coremap + reg_count, val);
> +            s->sw_coremap[reg_count] = val & 0xf;
> +            val = val >> 8;
> +        }
> +    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
> +        stl_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START), val);
> +    }
> +}
> +
> +static void extioi_writel(void *opaque, hwaddr addr, uint64_t val,
> +                          unsigned size)
> +{
> +    loongarch_extioi *s = LOONGARCH_EXTIOI(opaque);
> +    int cpu, level, i, j, bits, ipnum, irqnum;
> +    uint64_t offset, old_data, reg_count;
> +
> +    offset = addr & 0xffff;
> +    trace_loongarch_extioi_writel(size, (uint32_t)addr, val);
> +
> +    if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) {
> +        reg_count = (offset - EXTIOI_ENABLE_START);
> +        old_data = s->enable[reg_count];
> +        if (old_data != val) {
> +            s->enable[reg_count] = val;
> +            old_data = old_data ^ val;
> +
> +            bits = size * 8;
> +            while ((i = find_first_bit((void *)&old_data, bits)) != bits) {
> +                level = test_bit(i, (unsigned long *)&val);
> +                extioi_update_irq(s, i + reg_count * 8, level);
> +                clear_bit(i, (void *)&old_data);
> +            }
> +        }
> +    } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) {
> +        stq_p((void *)s->bounce + (offset - EXTIOI_BOUNCE_START), val);
> +    } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) {
> +        reg_count = ((offset - EXTIOI_COREISR_START) & 0x1f);
> +        cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
> +
> +        /* core_ext_ioisr */
> +        old_data = ldq_p((void *)s->coreisr[cpu] + reg_count);
> +        stq_p((void *)s->coreisr[cpu] + reg_count, (old_data & ~val));
> +
> +        if (old_data != (old_data & ~val)) {
> +            bits = size * 8;
> +            while ((i = find_first_bit((void *)&val, bits)) != bits) {
> +                j = test_bit(i, (unsigned long *)&old_data);
> +                if (j) {
> +                    extioi_update_irq(s, i + reg_count * 8, 0);
> +                }
> +                clear_bit(i, (void *)&val);
> +            }
> +        }
> +    } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) {
> +        /* Drop arch.core_ip_mask use s->ipmap */
> +        reg_count = (offset - EXTIOI_IPMAP_START);
> +        stq_p((void *)&s->ipmap + reg_count, val);
> +
> +        /* Routing in groups of 32 interrupt */
> +        while (val) {
> +            ipnum = find_first_bit((void *)&val, 4);
> +            for (i = 0; i < 32; i++) {
> +                irqnum = reg_count * 32 + i;
> +                if (ipnum != 4) {
> +                    s->sw_ipmap[irqnum] = ipnum;
> +                } else {
> +                    s->sw_ipmap[irqnum] = 0;
> +                }
> +            }
> +            val = val >> 8;
> +            reg_count += 1;
> +        }
> +    } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) {
> +        reg_count = (offset - EXTIOI_COREMAP_START);
> +        /* Only map the core */
> +        while (val) {
> +            stq_p((void *)s->coremap + reg_count, val);
> +            s->sw_coremap[reg_count] = val & 0xf;
> +            val = val >> 8;
> +        }
> +    } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) {
> +        stq_p((void *)s->nodetype + (offset - EXTIOI_NODETYPE_START), val);
> +    }
> +}
> +
> +static uint64_t extioi_readfn(void *opaque, hwaddr addr, unsigned size)
> +{
> +    switch (size) {
> +    case 1:
> +        return extioi_readb(opaque, addr);
> +    case 4:
> +        return extioi_readw(opaque, addr);
> +    case 8:
> +        return extioi_readl(opaque, addr);
> +    default:
> +        g_assert_not_reached();
> +    }
> +}
> +
> +static void extioi_writefn(void *opaque, hwaddr addr,
> +                           uint64_t value, unsigned size)
> +{
> +    switch (size) {
> +    case 1:
> +        extioi_writeb(opaque, addr, value, size);
> +        break;
> +    case 4:
> +        extioi_writew(opaque, addr, value, size);
> +        break;
> +    case 8:
> +        extioi_writel(opaque, addr, value, size);
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +}
> +
> +static const MemoryRegionOps extioi_ops = {
> +    .read = extioi_readfn,
> +    .write = extioi_writefn,
> +    .impl.min_access_size = 1,
> +    .impl.max_access_size = 8,
> +    .valid.min_access_size = 1,
> +    .valid.max_access_size = 8,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};

Are all of the extioi registers accessible with 1 byte accesses? It feels as if this 
should be split into separate memory regions.

> +static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
> +{
> +    LoongArchMachineState *lams = LOONGARCH_MACHINE(qdev_get_machine());
> +    MachineState *ms = MACHINE(lams);

Since lams isn't used could you not just use:

MachineState *ms = MACHINE(qdev_get_machine());

> +    loongarch_extioi *p = LOONGARCH_EXTIOI(dev);
> +    int i, cpu, pin;
> +
> +    qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS);
> +
> +    for (i = 0; i < EXTIOI_IRQS; i++) {
> +        sysbus_init_irq(SYS_BUS_DEVICE(dev), &p->irq[i]);
> +    }

Since qdev_init_gpio_in() doesn't depend upon a qdev property you can do this in an 
instance init function rather than realize.

> +    memory_region_init_io(&p->mmio, OBJECT(p), &extioi_ops, p,
> +                          TYPE_LOONGARCH_EXTIOI, 0x900);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &p->mmio);

Same here.

> +    for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
> +        for (pin = 0; pin < LS3A_INTC_IP; pin++) {
> +            qdev_init_gpio_out(dev, &p->parent_irq[cpu][pin], 1);
> +        }
> +    }
> +}
> +
> +static const VMStateDescription vmstate_ext_sw_ipisr = {
> +    .name = "ext_sw_ipisr",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_ARRAY(irq, ext_sw_ipisr, EXTIOI_IRQS_BITMAP_SIZE),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static const VMStateDescription vmstate_loongarch_extioi = {
> +    .name = TYPE_LOONGARCH_EXTIOI,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT64_ARRAY(enable, loongarch_extioi,
> +                             EXTIOI_IRQS_BITMAP_SIZE / 8),
> +        VMSTATE_UINT64_ARRAY(bounce, loongarch_extioi,
> +                             EXTIOI_IRQS_BITMAP_SIZE / 8),
> +        VMSTATE_UINT64_2DARRAY(coreisr, loongarch_extioi,
> +                               MAX_CORES, EXTIOI_IRQS_BITMAP_SIZE / 8),
> +        VMSTATE_UINT64(ipmap, loongarch_extioi),
> +        VMSTATE_UINT64_ARRAY(coremap, loongarch_extioi,
> +                             EXTIOI_IRQS_COREMAP_SIZE / 8),
> +        VMSTATE_UINT64_ARRAY(nodetype, loongarch_extioi,
> +                             EXTIOI_IRQS_NODETYPE_SIZE / 4),
> +        VMSTATE_UINT8_ARRAY(sw_ipmap, loongarch_extioi, EXTIOI_IRQS),
> +        VMSTATE_UINT8_ARRAY(sw_coremap, loongarch_extioi, EXTIOI_IRQS),
> +        VMSTATE_STRUCT_2DARRAY(sw_ipisr, loongarch_extioi, MAX_CORES,
> +                               LS3A_INTC_IP, 1, vmstate_ext_sw_ipisr,
> +                               ext_sw_ipisr),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->vmsd = &vmstate_loongarch_extioi;
> +    dc->realize = loongarch_extioi_realize;
> +}
> +
> +static const TypeInfo loongarch_extioi_info = {
> +    .name          = TYPE_LOONGARCH_EXTIOI,

TYPE_LOONGARCH_EXTIOI_SYS_BUS_DEVICE helps to show the inheritance from SYS_BUS_DEVICE.

> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(struct loongarch_extioi),
> +    .class_init    = loongarch_extioi_class_init,
> +};
> +
> +static void loongarch_extioi_register_types(void)
> +{
> +    type_register_static(&loongarch_extioi_info);
> +}
> +
> +type_init(loongarch_extioi_register_types)
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index acefe0c5aa..cee88a0d73 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -60,3 +60,4 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
>   specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
>   specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
>   specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
> +specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 20da343cfe..3f85126cf0 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -258,3 +258,12 @@ loongarch_pch_pic_write(unsigned size, uint32_t addr, unsigned long val) "size:
>   
>   # loongarch_pch_msi.c
>   loongarch_msi_set_irq(int irq_num) "set msi irq %d"
> +
> +# loongarch_extioi.c
> +extioi_setirq(int irq, int level) "set extirq irq %d level %d"
> +loongarch_extioi_readb(uint32_t addr, uint8_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIu8
> +loongarch_extioi_readw(uint32_t addr, uint32_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIx32
> +loongarch_extioi_readl(uint32_t addr, uint64_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIx64
> +loongarch_extioi_writeb(unsigned size, uint32_t addr, uint8_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIu8
> +loongarch_extioi_writew(unsigned size, uint32_t addr, uint32_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx32
> +loongarch_extioi_writel(unsigned size, uint32_t addr, uint64_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index cd38d03a19..468e3acc74 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -4,3 +4,4 @@ config LOONGSON3_LS7A
>       select LOONGARCH_IPI
>       select LOONGARCH_PCH_PIC
>       select LOONGARCH_PCH_MSI
> +    select LOONGARCH_EXTIOI
> diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
> new file mode 100644
> index 0000000000..4e6a20dced
> --- /dev/null
> +++ b/include/hw/intc/loongarch_extioi.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch 3A5000 ext interrupt controller definitions
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "hw/sysbus.h"
> +#include "hw/loongarch/loongarch.h"
> +
> +#ifndef LOONGARCH_EXTIOI_H
> +#define LOONGARCH_EXTIOI_H
> +
> +#define LS3A_INTC_IP               8
> +#define MAX_CORES                  LOONGARCH_MAX_VCPUS
> +#define EXTIOI_IRQS                (256)
> +#define EXTIOI_IRQS_BITMAP_SIZE    (256 / 8)
> +/* map to ipnum per 32 irqs */
> +#define EXTIOI_IRQS_IPMAP_SIZE     (256 / 32)
> +#define EXTIOI_IRQS_COREMAP_SIZE   256
> +#define EXTIOI_IRQS_NODETYPE_SIZE  16
> +
> +#define APIC_OFFSET                  0x400
> +#define APIC_BASE                    (0x1000ULL + APIC_OFFSET)
> +
> +#define EXTIOI_NODETYPE_START        (0x4a0 - APIC_OFFSET)
> +#define EXTIOI_NODETYPE_END          (0x4c0 - APIC_OFFSET)
> +#define EXTIOI_IPMAP_START           (0x4c0 - APIC_OFFSET)
> +#define EXTIOI_IPMAP_END             (0x4c8 - APIC_OFFSET)
> +#define EXTIOI_ENABLE_START          (0x600 - APIC_OFFSET)
> +#define EXTIOI_ENABLE_END            (0x620 - APIC_OFFSET)
> +#define EXTIOI_BOUNCE_START          (0x680 - APIC_OFFSET)
> +#define EXTIOI_BOUNCE_END            (0x6a0 - APIC_OFFSET)
> +#define EXTIOI_ISR_START             (0x700 - APIC_OFFSET)
> +#define EXTIOI_ISR_END               (0x720 - APIC_OFFSET)
> +#define EXTIOI_COREISR_START         (0x800 - APIC_OFFSET)
> +#define EXTIOI_COREISR_END           (0xB20 - APIC_OFFSET)
> +#define EXTIOI_COREMAP_START         (0xC00 - APIC_OFFSET)
> +#define EXTIOI_COREMAP_END           (0xD00 - APIC_OFFSET)
> +
> +#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi"
> +DECLARE_INSTANCE_CHECKER(struct loongarch_extioi, LOONGARCH_EXTIOI,
> +                         TYPE_LOONGARCH_EXTIOI)
> +
> +typedef struct ext_sw_ipisr {
> +    uint8_t irq[EXTIOI_IRQS_BITMAP_SIZE];
> +} ext_sw_ipisr;
> +
> +typedef struct loongarch_extioi {

LoongArchExtIOI?

> +    SysBusDevice parent_obj;
> +    /* hardware state */
> +    uint64_t enable[EXTIOI_IRQS_BITMAP_SIZE / 8];
> +    uint64_t bounce[EXTIOI_IRQS_BITMAP_SIZE / 8];
> +    uint64_t coreisr[MAX_CORES][EXTIOI_IRQS_BITMAP_SIZE / 8];
> +    uint64_t ipmap;
> +    uint64_t coremap[EXTIOI_IRQS_COREMAP_SIZE / 8];
> +    uint64_t nodetype[EXTIOI_IRQS_NODETYPE_SIZE / 4];
> +
> +    /*software state */
> +    uint8_t sw_ipmap[EXTIOI_IRQS];
> +    uint8_t sw_coremap[EXTIOI_IRQS];
> +    ext_sw_ipisr sw_ipisr[MAX_CORES][LS3A_INTC_IP];
> +
> +    qemu_irq parent_irq[MAX_CORES][LS3A_INTC_IP];
> +    qemu_irq irq[EXTIOI_IRQS];
> +    MemoryRegion mmio;
> +} loongarch_extioi;
> +
> +#endif /* LOONGARCH_EXTIOI_H */


ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 21/27] hw/loongarch: Add irq hierarchy for the system
  2021-12-04 12:07 ` [RFC PATCH v3 21/27] hw/loongarch: Add irq hierarchy for the system Xiaojuan Yang
@ 2021-12-18  9:45   ` Mark Cave-Ayland
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-18  9:45 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> This patch add the irq hierarchy for the virt board.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/loongarch/loongson3.c   | 84 ++++++++++++++++++++++++++++++++++++++
>   include/hw/pci-host/ls7a.h | 13 ++++++
>   2 files changed, 97 insertions(+)
> 
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> index 28b623e927..c42f830208 100644
> --- a/hw/loongarch/loongson3.c
> +++ b/hw/loongarch/loongson3.c
> @@ -15,6 +15,10 @@
>   #include "sysemu/runstate.h"
>   #include "sysemu/reset.h"
>   #include "hw/loongarch/loongarch.h"
> +#include "hw/intc/loongarch_ipi.h"
> +#include "hw/intc/loongarch_extioi.h"
> +#include "hw/intc/loongarch_pch_pic.h"
> +#include "hw/intc/loongarch_pch_msi.h"
>   #include "hw/pci-host/ls7a.h"
>   
>   
> @@ -70,6 +74,83 @@ static const MemoryRegionOps loongarch_qemu_ops = {
>       },
>   };
>   
> +static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
> +                                      hwaddr addr, MemoryRegion *iocsr)
> +{
> +    assert(n >= 0 && n < dev->num_mmio);
> +
> +    if (dev->mmio[n].addr == addr) {
> +        /* ??? region already mapped here. */
> +        return;
> +    }
> +    if (dev->mmio[n].addr != (hwaddr)-1) {
> +        /* Unregister previous mapping. */
> +        memory_region_del_subregion(iocsr, dev->mmio[n].memory);
> +    }
> +    dev->mmio[n].addr = addr;
> +    memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
> +}

Ah so this is a variant of QEMU's existing sysbus_mmio_map() but within the iocsr 
memory region instead? The sysbus API is designed to only map devices into the main 
memory address space.

> +static void loongson3_irq_init(MachineState *machine)
> +{
> +    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
> +    SysBusDevice *d;
> +    int cpu, pin, i;
> +    unsigned long ipi_addr;
> +
> +    ipi = qdev_new(TYPE_LOONGARCH_IPI);
> +    d = SYS_BUS_DEVICE(ipi);
> +    sysbus_realize_and_unref(d, &error_fatal);
> +    for (cpu = 0; cpu < machine->smp.cpus; cpu++) {
> +        cpudev = DEVICE(qemu_get_cpu(cpu));
> +        ipi_addr = SMP_IPI_MAILBOX + cpu * 0x100;
> +        sysbus_mmio_map_loongarch(d, cpu, ipi_addr, &lams->system_iocsr);

An alternative which doesn't need sysbus_mmio_map_loongarch() but can use memory 
regions exposed by a sysbus device:

     memory_region_add_subregion(&lams->system_iocsr, ipi_addr,
                                 sysbus_mmio_get_region(d, cpu));

> +        qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
> +    }
> +
> +    extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
> +    d = SYS_BUS_DEVICE(extioi);
> +    sysbus_realize_and_unref(d, &error_fatal);
> +    sysbus_mmio_map_loongarch(d, 0, APIC_BASE, &lams->system_iocsr);
> +
> +    for (i = 0; i < EXTIOI_IRQS; i++) {
> +        sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
> +    }
> +
> +    /*
> +     * connect ext irq to the cpu irq
> +     * cpu_pin[9:2] <= intc_pin[7:0]
> +     */
> +    for (cpu = 0; cpu < machine->smp.cpus; cpu++) {
> +        cpudev = DEVICE(qemu_get_cpu(cpu));
> +        for (pin = 0; pin < LS3A_INTC_IP; pin++) {
> +            qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
> +                                  qdev_get_gpio_in(cpudev, pin + 2));
> +        }
> +    }
> +
> +    pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
> +    d = SYS_BUS_DEVICE(pch_pic);
> +    sysbus_realize_and_unref(d, &error_fatal);
> +    sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
> +
> +    /* Connect 64 pch_pic irqs to extioi */
> +    for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
> +        sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
> +    }
> +
> +    pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
> +    d = SYS_BUS_DEVICE(pch_msi);
> +    sysbus_realize_and_unref(d, &error_fatal);
> +    sysbus_mmio_map(d, 0, LS7A_PCH_MSI_ADDR_LOW);
> +    for (i = 0; i < PCH_MSI_IRQ_NUM; i++) {
> +        /* Connect 192 pch_msi irqs to extioi */
> +        sysbus_connect_irq(d, i,
> +                           qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
> +    }
> +}
> +
>   static void loongson3_init(MachineState *machine)
>   {
>       const char *cpu_model = machine->cpu_type;
> @@ -126,6 +207,9 @@ static void loongson3_init(MachineState *machine)
>       memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>       offset += highram_size;
>   
> +    /* Initialize the IO interrupt subsystem */
> +    loongson3_irq_init(machine);
> +
>       LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>       LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>       LOONGARCH_SIMPLE_MMIO_OPS(CPUNAME_REG, "loongarch_cpuname", 0x8);
> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
> index 32d6f045dc..ac938d6d5f 100644
> --- a/include/hw/pci-host/ls7a.h
> +++ b/include/hw/pci-host/ls7a.h
> @@ -24,6 +24,19 @@
>   #define LS7A_PCI_IO_BASE         0x18000000UL
>   #define LS7A_PCI_IO_SIZE         0x00010000
>   
> +#define LS7A_PCH_REG_BASE       0x10000000UL
> +#define LS7A_IOAPIC_REG_BASE    (LS7A_PCH_REG_BASE)
> +#define LS7A_PCH_MSI_ADDR_LOW   0x2FF00000UL
> +
> +/*
> + * According to the kernel pch irq start from 64 offset
> + * 0 ~ 16 irqs used for non-pci device while 16 ~ 64 irqs
> + * used for pci device.
> + */
> +#define PCH_PIC_IRQ_OFFSET      64
> +#define LS7A_DEVICE_IRQS        16
> +#define LS7A_PCI_IRQS           48
> +
>   struct LS7APCIState {
>       /*< private >*/
>       PCIDevice parent_obj;

ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2021-12-04 12:07 ` [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000 Xiaojuan Yang
  2021-12-04 17:54   ` Philippe Mathieu-Daudé
@ 2021-12-18 10:02   ` Mark Cave-Ayland
  2021-12-22  8:26     ` yangxiaojuan
  1 sibling, 1 reply; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-18 10:02 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> 1.Add uart,virtio-net,vga and usb for 3A5000.
> 2.Add irq set and map for the pci host. Non pci device
> use irq 0-16, pci device use 16-64.
> 3.Add some unimplented device to emulate guest unused
> memory space.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/loongarch/Kconfig            |  8 +++++
>   hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>   hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>   include/hw/intc/loongarch_ipi.h |  2 ++
>   include/hw/pci-host/ls7a.h      |  4 +++
>   softmmu/qdev-monitor.c          |  3 +-
>   6 files changed, 117 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index 468e3acc74..9ea3b92708 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -1,5 +1,13 @@
>   config LOONGSON3_LS7A
>       bool
> +    imply VGA_PCI
> +    imply VIRTIO_VGA
> +    imply PARALLEL
> +    imply PCI_DEVICES
> +    select ISA_BUS
> +    select SERIAL
> +    select SERIAL_ISA
> +    select VIRTIO_PCI
>       select PCI_EXPRESS_7A
>       select LOONGARCH_IPI
>       select LOONGARCH_PCH_PIC
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> index c42f830208..e4a02e7c18 100644
> --- a/hw/loongarch/loongson3.c
> +++ b/hw/loongarch/loongson3.c
> @@ -10,8 +10,11 @@
>   #include "qemu/datadir.h"
>   #include "qapi/error.h"
>   #include "hw/boards.h"
> +#include "hw/char/serial.h"
>   #include "sysemu/sysemu.h"
>   #include "sysemu/qtest.h"
> +#include "hw/irq.h"
> +#include "net/net.h"
>   #include "sysemu/runstate.h"
>   #include "sysemu/reset.h"
>   #include "hw/loongarch/loongarch.h"
> @@ -20,6 +23,7 @@
>   #include "hw/intc/loongarch_pch_pic.h"
>   #include "hw/intc/loongarch_pch_msi.h"
>   #include "hw/pci-host/ls7a.h"
> +#include "hw/misc/unimp.h"
>   
>   
>   static void loongarch_cpu_reset(void *opaque)
> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>       memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>   }
>   
> -static void loongson3_irq_init(MachineState *machine)
> +static PCIBus *loongson3_irq_init(MachineState *machine)
>   {
>       LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>       SysBusDevice *d;
> +    PCIBus *pci_bus;
>       int cpu, pin, i;
>       unsigned long ipi_addr;
>   
> @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>       sysbus_realize_and_unref(d, &error_fatal);
>       sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>   
> +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
> +
>       /* Connect 64 pch_pic irqs to extioi */
>       for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>           sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>           sysbus_connect_irq(d, i,
>                              qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>       }
> +
> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
> +    d = SYS_BUS_DEVICE(pciehost);
> +    sysbus_realize_and_unref(d, &error_fatal);
> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
> +
> +    /* Connect 48 pci irq to pch_pic */
> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
> +        qdev_connect_gpio_out(pciehost, i,
> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
> +    }
> +
> +    return pci_bus;
> +}
> +
> +/* Network support */
> +static void network_init(PCIBus *pci_bus)
> +{
> +    int i;
> +
> +    for (i = 0; i < nb_nics; i++) {
> +        NICInfo *nd = &nd_table[i];
> +
> +        if (!nd->model) {
> +            nd->model = g_strdup("virtio");
> +        }
> +
> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
> +    }
>   }
>   
>   static void loongson3_init(MachineState *machine)
> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>       MemoryRegion *address_space_mem = get_system_memory();
>       LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>       int i;
> +    PCIBus *pci_bus = NULL;
>   
>       if (!cpu_model) {
>           cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>       memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>       offset += highram_size;
>   
> +    /*
> +     * There are some invalid guest memory access.
> +     * Create some unimplemented devices to emulate this.
> +     */
> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
> +
>       /* Initialize the IO interrupt subsystem */
> -    loongson3_irq_init(machine);
> +    pci_bus = loongson3_irq_init(machine);
> +
> +    /* Network card */
> +    network_init(pci_bus);
> +
> +    /* VGA setup. Don't bother loading the bios. */
> +    pci_vga_init(pci_bus);
> +
> +    pci_create_simple(pci_bus, -1, "pci-ohci");

By passing in -1 then you're allowing the PCI code to choose a suitable 
device/function which feels odd for an in-built device. Is this not fixed in real 
hardware?

Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines 
that don't have these devices in-built.

>       LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>       LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
> index a783fb2eda..06cd641573 100644
> --- a/hw/pci-host/ls7a.c
> +++ b/hw/pci-host/ls7a.c
> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>       }
>   };
>   
> +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
> +{
> +    PCIINTxRoute route;
> +
> +    route.irq = pin;
> +    route.mode = PCI_INTX_ENABLED;
> +    return route;
> +}
> +
> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
> +{
> +    PCIBus *bus;
> +    int offset, irq;
> +
> +    bus = pci_get_bus(d);
> +    if (bus->parent_dev) {
> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
> +        return irq;
> +    }

Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, 
for example pci_change_irq_level()?

> +    /* pci device start from irq 80 */
> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
> +
> +    return irq;
> +}
> +
> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
> +{
> +    LS7APCIEHost *pciehost = opaque;
> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
> +
> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
> +}
> +
>   static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>                                     uint64_t val, unsigned size)
>   {
> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>       LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>       PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>   
> -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
> +                                     pci_ls7a_map_irq, s,
>                                        get_system_memory(), get_system_io(),
>                                        PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>   
> +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
> +
>       memory_region_init_io(&s->pci_conf, OBJECT(dev),
>                             &pci_ls7a_config_ops, pci->bus,
>                             "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>       object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>       qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>       qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
> +
> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>   }
>   
>   static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
> index d2397e53e7..1113c3b1a8 100644
> --- a/include/hw/intc/loongarch_ipi.h
> +++ b/include/hw/intc/loongarch_ipi.h
> @@ -8,6 +8,8 @@
>   #ifndef HW_LOONGARCH_IPI_H
>   #define HW_LOONGARCH_IPI_H
>   
> +#include "hw/sysbus.h"
> +
>   /* Mainy used by iocsr read and write */
>   #define SMP_IPI_MAILBOX      0x1000ULL
>   #define CORE_STATUS_OFF       0x0
> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
> index ac938d6d5f..3b9ad1e175 100644
> --- a/include/hw/pci-host/ls7a.h
> +++ b/include/hw/pci-host/ls7a.h
> @@ -37,6 +37,9 @@
>   #define LS7A_DEVICE_IRQS        16
>   #define LS7A_PCI_IRQS           48
>   
> +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
> +#define LS7A_UART_BASE          0x1fe001e0
> +
>   struct LS7APCIState {
>       /*< private >*/
>       PCIDevice parent_obj;
> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>   
>       LS7APCIState pci_dev;
>   
> +    qemu_irq irqs[LS7A_PCI_IRQS];
>       MemoryRegion pci_conf;
>       MemoryRegion pci_io;
>   } LS7APCIEHost;
> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
> index 01f3834db5..49491d74a1 100644
> --- a/softmmu/qdev-monitor.c
> +++ b/softmmu/qdev-monitor.c
> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>                                 QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>                                 QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>                                 QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
> +                              QEMU_ARCH_LOONGARCH)

This part looks like it belongs to another patch?

>   #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>   #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)


ATB,

Mark.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 23/27] hw/loongarch: Add LoongArch ls7a rtc device support
  2021-12-04 12:07 ` [RFC PATCH v3 23/27] hw/loongarch: Add LoongArch ls7a rtc device support Xiaojuan Yang
@ 2021-12-18 10:10   ` Mark Cave-Ayland
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-18 10:10 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

On 04/12/2021 12:07, Xiaojuan Yang wrote:

> This patch add ls7a rtc device support.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/loongarch/Kconfig       |   1 +
>   hw/loongarch/loongson3.c   |   3 +
>   hw/rtc/Kconfig             |   3 +
>   hw/rtc/ls7a_rtc.c          | 323 +++++++++++++++++++++++++++++++++++++
>   hw/rtc/meson.build         |   1 +
>   include/hw/pci-host/ls7a.h |   4 +
>   6 files changed, 335 insertions(+)
>   create mode 100644 hw/rtc/ls7a_rtc.c
> 
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index 9ea3b92708..6d3506fee9 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -13,3 +13,4 @@ config LOONGSON3_LS7A
>       select LOONGARCH_PCH_PIC
>       select LOONGARCH_PCH_MSI
>       select LOONGARCH_EXTIOI
> +    select LS7A_RTC
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> index e4a02e7c18..f86f83c0b8 100644
> --- a/hw/loongarch/loongson3.c
> +++ b/hw/loongarch/loongson3.c
> @@ -144,6 +144,9 @@ static PCIBus *loongson3_irq_init(MachineState *machine)
>                      qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>                      115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>   
> +    sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE,
> +                         qdev_get_gpio_in(pch_pic, LS7A_RTC_IRQ - PCH_PIC_IRQ_OFFSET));
> +
>       /* Connect 64 pch_pic irqs to extioi */
>       for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>           sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
> diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
> index f06e133b8a..ba8f7bc202 100644
> --- a/hw/rtc/Kconfig
> +++ b/hw/rtc/Kconfig
> @@ -25,3 +25,6 @@ config SUN4V_RTC
>   
>   config GOLDFISH_RTC
>       bool
> +
> +config LS7A_RTC
> +    bool
> diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c
> new file mode 100644
> index 0000000000..b771db2e62
> --- /dev/null
> +++ b/hw/rtc/ls7a_rtc.c
> @@ -0,0 +1,323 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Loongarch LS7A Real Time Clock emulation
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "hw/sysbus.h"
> +#include "hw/irq.h"
> +#include "include/hw/register.h"
> +#include "qemu/timer.h"
> +#include "sysemu/sysemu.h"
> +#include "qemu/cutils.h"
> +#include "qemu/log.h"
> +#include "migration/vmstate.h"
> +#include "hw/misc/unimp.h"
> +
> +#define SYS_TOYTRIM        0x20
> +#define SYS_TOYWRITE0      0x24
> +#define SYS_TOYWRITE1      0x28
> +#define SYS_TOYREAD0       0x2C
> +#define SYS_TOYREAD1       0x30
> +#define SYS_TOYMATCH0      0x34
> +#define SYS_TOYMATCH1      0x38
> +#define SYS_TOYMATCH2      0x3C
> +#define SYS_RTCCTRL        0x40
> +#define SYS_RTCTRIM        0x60
> +#define SYS_RTCWRTIE0      0x64
> +#define SYS_RTCREAD0       0x68
> +#define SYS_RTCMATCH0      0x6C
> +#define SYS_RTCMATCH1      0x70
> +#define SYS_RTCMATCH2      0x74
> +
> +/*
> + * Shift bits and filed mask
> + */
> +#define TOY_MON_MASK   0x3f
> +#define TOY_DAY_MASK   0x1f
> +#define TOY_HOUR_MASK  0x1f
> +#define TOY_MIN_MASK   0x3f
> +#define TOY_SEC_MASK   0x3f
> +#define TOY_MSEC_MASK  0xf
> +
> +#define TOY_MON_SHIFT  26
> +#define TOY_DAY_SHIFT  21
> +#define TOY_HOUR_SHIFT 16
> +#define TOY_MIN_SHIFT  10
> +#define TOY_SEC_SHIFT  4
> +#define TOY_MSEC_SHIFT 0
> +
> +#define TOY_MATCH_YEAR_MASK  0x3f
> +#define TOY_MATCH_MON_MASK   0xf
> +#define TOY_MATCH_DAY_MASK   0x1f
> +#define TOY_MATCH_HOUR_MASK  0x1f
> +#define TOY_MATCH_MIN_MASK   0x3f
> +#define TOY_MATCH_SEC_MASK   0x3f
> +
> +#define TOY_MATCH_YEAR_SHIFT 26
> +#define TOY_MATCH_MON_SHIFT  22
> +#define TOY_MATCH_DAY_SHIFT  17
> +#define TOY_MATCH_HOUR_SHIFT 12
> +#define TOY_MATCH_MIN_SHIFT  6
> +#define TOY_MATCH_SEC_SHIFT  0
> +
> +#define TOY_ENABLE_BIT (1U << 11)
> +
> +#define TYPE_LS7A_RTC "ls7a_rtc"
> +OBJECT_DECLARE_SIMPLE_TYPE(LS7A_RTCState, LS7A_RTC)
> +
> +typedef struct LS7A_RTCState {
> +    SysBusDevice parent_obj;
> +
> +    MemoryRegion iomem;
> +    QEMUTimer *timer;
> +    /*
> +     * Needed to preserve the tick_count across migration, even if the
> +     * absolute value of the rtc_clock is different on the source and
> +     * destination.
> +     */
> +    int64_t offset;
> +    int64_t data;
> +    int64_t save_alarm_offset;
> +    int tidx;
> +    uint32_t toymatch[3];
> +    uint32_t toytrim;
> +    uint32_t cntrctl;
> +    uint32_t rtctrim;
> +    uint32_t rtccount;
> +    uint32_t rtcmatch[3];
> +    qemu_irq toy_irq;
> +} LS7A_RTCState;
> +
> +enum {
> +    TOYEN = 1UL << 11,
> +    RTCEN = 1UL << 13,
> +};
> +
> +static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    LS7A_RTCState *s = LS7A_RTC(opaque);
> +    struct tm tm;
> +    unsigned int val;
> +
> +    val = 0;
> +
> +    switch (addr) {
> +    case SYS_TOYREAD0:
> +        qemu_get_timedate(&tm, s->offset);
> +        val = (((tm.tm_mon + 1) & TOY_MON_MASK) << TOY_MON_SHIFT)
> +        | (((tm.tm_mday) & TOY_DAY_MASK) << TOY_DAY_SHIFT)
> +        | (((tm.tm_hour) & TOY_HOUR_MASK) << TOY_HOUR_SHIFT)
> +        | (((tm.tm_min) & TOY_MIN_MASK) << TOY_MIN_SHIFT)
> +        | (((tm.tm_sec) & TOY_SEC_MASK) << TOY_SEC_SHIFT) | 0x0;
> +        break;
> +    case SYS_TOYREAD1:
> +        qemu_get_timedate(&tm, s->offset);
> +        val = tm.tm_year;
> +        break;
> +    case SYS_TOYMATCH0:
> +        val = s->toymatch[0];
> +        break;
> +    case SYS_TOYMATCH1:
> +        val = s->toymatch[1];
> +        break;
> +    case SYS_TOYMATCH2:
> +        val = s->toymatch[2];
> +        break;
> +    case SYS_RTCCTRL:
> +        val = s->cntrctl;
> +        break;
> +    case SYS_RTCREAD0:
> +        val = s->rtccount;
> +        break;
> +    case SYS_RTCMATCH0:
> +        val = s->rtcmatch[0];
> +        break;
> +    case SYS_RTCMATCH1:
> +        val = s->rtcmatch[1];
> +        break;
> +    case SYS_RTCMATCH2:
> +        val = s->rtcmatch[2];
> +        break;
> +    default:
> +        val = 0;
> +        break;
> +    }
> +    return val;
> +}
> +
> +static void ls7a_rtc_write(void *opaque, hwaddr addr,
> +                           uint64_t val, unsigned size)
> +{
> +    LS7A_RTCState *s = LS7A_RTC(opaque);
> +    struct tm tm;
> +    int64_t alarm_offset, year_diff, expire_time;
> +
> +    switch (addr) {
> +    case SYS_TOYWRITE0:
> +        qemu_get_timedate(&tm, s->offset);
> +        tm.tm_sec = (val >> TOY_SEC_SHIFT) & TOY_SEC_MASK;
> +        tm.tm_min = (val >> TOY_MIN_SHIFT) & TOY_MIN_MASK;
> +        tm.tm_hour = (val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK;
> +        tm.tm_mday = ((val >> TOY_DAY_SHIFT) & TOY_DAY_MASK);
> +        tm.tm_mon = ((val >> TOY_MON_SHIFT) & TOY_MON_MASK) - 1;
> +        s->offset = qemu_timedate_diff(&tm);
> +        break;
> +    case SYS_TOYWRITE1:
> +        qemu_get_timedate(&tm, s->offset);
> +        tm.tm_year = val;
> +        s->offset = qemu_timedate_diff(&tm);
> +        break;
> +    case SYS_TOYMATCH0:
> +        s->toymatch[0] = val;
> +        qemu_get_timedate(&tm, s->offset);
> +        tm.tm_sec = (val >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK;
> +        tm.tm_min = (val >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK;
> +        tm.tm_hour = ((val >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK);
> +        tm.tm_mday = ((val >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK);
> +        tm.tm_mon = ((val >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1;
> +        year_diff = ((val >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK);
> +        year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK);
> +        tm.tm_year = tm.tm_year + year_diff;
> +        alarm_offset = qemu_timedate_diff(&tm) - s->offset;
> +        if ((alarm_offset < 0) && (alarm_offset > -5)) {
> +                alarm_offset = 0;
> +        }
> +        expire_time = qemu_clock_get_ms(rtc_clock);
> +        expire_time += ((alarm_offset * 1000) + 100);
> +        timer_mod(s->timer, expire_time);
> +        break;
> +    case SYS_TOYMATCH1:
> +        s->toymatch[1] = val;
> +        break;
> +    case SYS_TOYMATCH2:
> +        s->toymatch[2] = val;
> +        break;
> +    case SYS_RTCCTRL:
> +        s->cntrctl = val;
> +        break;
> +    case SYS_RTCWRTIE0:
> +        s->rtccount = val;
> +        break;
> +    case SYS_RTCMATCH0:
> +        s->rtcmatch[0] = val;
> +        break;
> +    case SYS_RTCMATCH1:
> +        val = s->rtcmatch[1];
> +        break;
> +    case SYS_RTCMATCH2:
> +        val = s->rtcmatch[2];
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps ls7a_rtc_ops = {
> +    .read = ls7a_rtc_read,
> +    .write = ls7a_rtc_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
> +
> +};
> +
> +static void toy_timer(void *opaque)
> +{
> +    LS7A_RTCState *s = LS7A_RTC(opaque);
> +
> +    if (s->cntrctl & TOY_ENABLE_BIT) {
> +            qemu_irq_pulse(s->toy_irq);

Spacing? Have you run the entire series through scripts/checkpatch.pl?

> +    }
> +}
> +
> +static void ls7a_rtc_realize(DeviceState *dev, Error **errp)
> +{
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    LS7A_RTCState *d = LS7A_RTC(sbd);
> +    memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops,
> +                    (void *)d, "ls7a_rtc", 0x100);

Spacing again.

> +
> +    sysbus_init_irq(sbd, &d->toy_irq);
> +
> +    sysbus_init_mmio(sbd, &d->iomem);
> +    d->timer = timer_new_ms(rtc_clock, toy_timer, d);
> +    timer_mod(d->timer, qemu_clock_get_ms(rtc_clock) + 100);
> +    d->offset = 0;
> +
> +    create_unimplemented_device("mmio fallback 1", 0x10013ffc, 0x4);
> +}
> +
> +static int ls7a_rtc_pre_save(void *opaque)
> +{
> +    LS7A_RTCState *s = LS7A_RTC(opaque);
> +    struct tm tm;
> +    int64_t year_diff, value;
> +
> +    value = s->toymatch[0];
> +    qemu_get_timedate(&tm, s->offset);
> +    tm.tm_sec = (value >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK;
> +    tm.tm_min = (value >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK;
> +    tm.tm_hour = ((value >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK);
> +    tm.tm_mday = ((value >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK);
> +    tm.tm_mon = ((value >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1;
> +    year_diff = ((value >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK);
> +    year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK);
> +    tm.tm_year = tm.tm_year + year_diff;
> +    s->save_alarm_offset = qemu_timedate_diff(&tm) - s->offset;
> +
> +    return 0;
> +}
> +
> +static int ls7a_rtc_post_load(void *opaque, int version_id)
> +{
> +    LS7A_RTCState *s = LS7A_RTC(opaque);
> +    int64_t expire_time;
> +
> +    expire_time = qemu_clock_get_ms(rtc_clock) + (s->save_alarm_offset * 1000);
> +    timer_mod(s->timer, expire_time);
> +
> +    return 0;
> +}

These pre_save and post_load functions seem a bit odd: it looks as if they are being 
used to calculate the next timer interval after restoring from a snapshot.

Can these not be handled automatically by QEMU with the appropriate macro in the 
VMStateDescription:

     VMSTATE_TIMER_PTR(timer, LS7A_RTCState)

Assuming this works then you should be able to remove the pre_save and post_load 
functions along with save_alarm_offset.

> +static const VMStateDescription vmstate_ls7a_rtc = {
> +    .name = "ls7a_rtc",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .pre_save = ls7a_rtc_pre_save,
> +    .post_load = ls7a_rtc_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_INT64(offset, LS7A_RTCState),
> +        VMSTATE_INT64(save_alarm_offset, LS7A_RTCState),
> +        VMSTATE_UINT32(toymatch[0], LS7A_RTCState),
> +        VMSTATE_UINT32(cntrctl, LS7A_RTCState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void ls7a_rtc_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->vmsd = &vmstate_ls7a_rtc;
> +    dc->realize = ls7a_rtc_realize;
> +    dc->desc = "ls7a rtc";
> +}
> +
> +static const TypeInfo ls7a_rtc_info = {
> +    .name          = TYPE_LS7A_RTC,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(LS7A_RTCState),
> +    .class_init    = ls7a_rtc_class_init,
> +};
> +
> +static void ls7a_rtc_register_types(void)
> +{
> +    type_register_static(&ls7a_rtc_info);
> +}
> +
> +type_init(ls7a_rtc_register_types)
> diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
> index 8fd8d8f9a7..1d4870d8c4 100644
> --- a/hw/rtc/meson.build
> +++ b/hw/rtc/meson.build
> @@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_rtc.c'))
>   softmmu_ss.add(when: 'CONFIG_SUN4V_RTC', if_true: files('sun4v-rtc.c'))
>   softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_rtc.c'))
>   softmmu_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
> +softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
>   softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
>   
>   specific_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
> index 3b9ad1e175..c724b93b6d 100644
> --- a/include/hw/pci-host/ls7a.h
> +++ b/include/hw/pci-host/ls7a.h
> @@ -39,6 +39,10 @@
>   
>   #define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>   #define LS7A_UART_BASE          0x1fe001e0
> +#define LS7A_RTC_IRQ            (PCH_PIC_IRQ_OFFSET + 3)
> +#define LS7A_MISC_REG_BASE      (LS7A_PCH_REG_BASE + 0x00080000)
> +#define LS7A_RTC_REG_BASE       (LS7A_MISC_REG_BASE + 0x00050100)
> +#define LS7A_RTC_LEN            0x100
>   
>   struct LS7APCIState {
>       /*< private >*/

ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 14/27] hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson3 Platform
  2021-12-17 23:39   ` Mark Cave-Ayland
@ 2021-12-20 11:42     ` yangxiaojuan
  0 siblings, 0 replies; 58+ messages in thread
From: yangxiaojuan @ 2021-12-20 11:42 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

Hi, Mark

On 12/18/2021 07:39 AM, Mark Cave-Ayland wrote:
> On 04/12/2021 12:07, Xiaojuan Yang wrote:
> 
>> This is a model of the PCIe Host Bridge found on a Loongson-5000
>> processor. It includes a interrupt controller, some interface for
>> pci and nonpci devices. Mainly emulate part of it that is not
>> exactly the same as the host and only use part devices for
>> tcg mode. It support for MSI and MSIX interrupt sources.
>>
>> For more detailed info about ls7a1000 you can see the doc at
>> https://github.com/loongson/LoongArch-Documentation/releases/latest/
>> download/Loongson-7A1000-usermanual-2.00-EN.pdf
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>   hw/pci-host/Kconfig        |   4 +
>>   hw/pci-host/ls7a.c         | 174 +++++++++++++++++++++++++++++++++++++
>>   hw/pci-host/meson.build    |   1 +
>>   include/hw/pci-host/ls7a.h |  51 +++++++++++
>>   4 files changed, 230 insertions(+)
>>   create mode 100644 hw/pci-host/ls7a.c
>>   create mode 100644 include/hw/pci-host/ls7a.h
>>
>> diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
>> index 2b5f7d58cc..b02a9d1454 100644
>> --- a/hw/pci-host/Kconfig
>> +++ b/hw/pci-host/Kconfig
>> @@ -77,3 +77,7 @@ config MV64361
>>       bool
>>       select PCI
>>       select I8259
>> +
>> +config PCI_EXPRESS_7A
>> +    bool
>> +    select PCI_EXPRESS
>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>> new file mode 100644
>> index 0000000000..a783fb2eda
>> --- /dev/null
>> +++ b/hw/pci-host/ls7a.c
>> @@ -0,0 +1,174 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * QEMU Loongson 7A1000 North Bridge Emulation
>> + *
>> + * Copyright (C) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +
>> +#include "hw/pci/pci.h"
>> +#include "hw/pci/pcie_host.h"
>> +#include "hw/qdev-properties.h"
>> +#include "qapi/error.h"
>> +#include "hw/irq.h"
>> +#include "hw/pci/pci_bridge.h"
>> +#include "hw/pci/pci_bus.h"
>> +#include "sysemu/reset.h"
>> +#include "hw/pci-host/ls7a.h"
>> +#include "migration/vmstate.h"
>> +
>> +static const VMStateDescription vmstate_ls7a_pcie = {
>> +    .name = "LS7A_PCIE",
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_PCI_DEVICE(parent_obj, LS7APCIState),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>> +static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>> +                                  uint64_t val, unsigned size)
>> +{
>> +    pci_data_write(opaque, addr, val, size);
>> +}
>> +
>> +static uint64_t pci_ls7a_config_read(void *opaque,
>> +                                     hwaddr addr, unsigned size)
>> +{
>> +    uint64_t val;
>> +
>> +    val = pci_data_read(opaque, addr, size);
>> +
>> +    return val;
>> +}
>> +
>> +static const MemoryRegionOps pci_ls7a_config_ops = {
>> +    .read = pci_ls7a_config_read,
>> +    .write = pci_ls7a_config_write,
>> +    .valid = {
>> +        .min_access_size = 1,
>> +        .max_access_size = 4,
>> +    },
>> +    .impl = {
>> +        .min_access_size = 1,
>> +        .max_access_size = 4,
>> +    },
>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>> +};
>> +
>> +static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>> +{
>> +    PCIHostState *pci = PCI_HOST_BRIDGE(dev);
>> +    LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>> +    PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
> 
> SysbusDevice *sbd = SYS_BUS_DEVICE(dev) will be needed for later use.
> 
>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>> +                                     get_system_memory(), get_system_io(),
>> +                                     PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
> 
> A device shouldn't map itself into an address space: that is the job of the board. To achieve this LS7APCIEHost should have separate mmio and io memory regions defined and pci_register_root_bus() configured to use these i.e.

OK, I get it and have modified all the region map. Thank you

> 
>     pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>                                      &s->pci_mmio, &s->pci_io,
>                                      PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
> 
>> +    memory_region_init_io(&s->pci_conf, OBJECT(dev),
>> +                          &pci_ls7a_config_ops, pci->bus,
>> +                          "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>> +    memory_region_add_subregion(get_system_memory(), HT1LO_PCICFG_BASE,
>> +                                &s->pci_conf);
> 
> Here add sysbus_init_mmio(sbd, &s->pci_conf) and remove memory_region_add_subregion().
> 
>> +    /* Add ls7a pci-io */
>> +    memory_region_init_alias(&s->pci_io, OBJECT(dev), "ls7a-pci-io",
>> +                             get_system_io(), 0, LS7A_PCI_IO_SIZE);
>> +    memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE,
>> +                                &s->pci_io);
> 
> Remove the alias onto the system io memory region and instead use sysbus_init_mmio(sbd, &s->pci_io).
> 
> You will also need to make the PCI mmio memory region availble to the board using sysbus_init_mmio(sbd, &s->pci_mmio).
> 
>> +    pcie_host_mmcfg_update(pex, true, LS_PCIECFG_BASE, LS_PCIECFG_SIZE);
> 
> It looks like the pcie_host_mmcfg_*() functions are hardcoded to map the device in system memory which is not recommended for new devices. The best example I can find is in hw/pci-host/xilinx-pcie.c whereby pcie_host_mmcfg_init() is used in xilinx_pcie_host_realize() to setup the MMCFG memory region and then sysbus_init_mmio(sbd, &pex->mmio) is used to make it available to the board.
> 
> Once all these sysbus memory regions have been defined they can be accessed in the board code using sysbus_mmio_get_region().
> 
>> +    qdev_realize(DEVICE(&s->pci_dev), BUS(pci->bus), &error_fatal);
>> +}
>> +
>> +static void ls7a_pcie_realize(PCIDevice *d, Error **errp)
>> +{
>> +    /* pci status */
>> +    d->config[0x6] = 0x01;
>> +    /* base class code */
>> +    d->config[0xb] = 0x06;
>> +    /* header type */
>> +    d->config[0xe] = 0x80;
>> +    /* capabilities pointer */
>> +    d->config[0x34] = 0x40;
>> +    /* link status and control register 0 */
>> +    d->config[0x44] = 0x20;
>> +}
> 
> Should these definitely exist in realize() or should they belong in a reset() function?

OK, I will put them into the reset function.

>  
>> +static void ls7a_pcie_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>> +
>> +    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
>> +    dc->desc = "LS7A1000 PCIE Host bridge";
>> +    dc->vmsd = &vmstate_ls7a_pcie;
>> +    k->realize = ls7a_pcie_realize;
>> +    k->vendor_id = 0x0014;
>> +    k->device_id = 0x7a00;
> 
> Generally device and vendor ids are added as constants to include/hw/pci/pci_ids.h.
> 
>> +    k->revision = 0x0;
>> +    k->class_id = PCI_CLASS_BRIDGE_HOST;
>> +    /*
>> +     * PCI-facing part of the host bridge, not usable without the
>> +     * host-facing part, which can't be device_add'ed, yet.
>> +     */
>> +    dc->user_creatable = false;
>> +}
>> +
>> +static const TypeInfo ls7a_pcie_device_info = {
>> +    .name          = TYPE_LS7A_PCIE,
> 
> Why TYPE_LS7A_PCIE? The normal convention would be to call the type TYPE_LS7A_PCI_DEVICE to show that it is derived from a conventional PCI device.

Here use TYPE_LS7A_PCIE means its connect to a pcie bridge, It seems TYPE_LS7A_PCI_DEVICE is more appropriate, for the bridge has show the pcie feature.
I will modify. Thank you for your advice.

> 
>> +    .parent        = TYPE_PCI_DEVICE,
>> +    .instance_size = sizeof(LS7APCIState),
>> +    .class_init    = ls7a_pcie_class_init,
>> +    .interfaces = (InterfaceInfo[]) {
>> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
>> +        { },
>> +    },
>> +};
>> +
>> +static void ls7a_pciehost_initfn(Object *obj)
>> +{
>> +    LS7APCIEHost *s = LS7A_HOST_DEVICE(obj);
>> +    LS7APCIState *ls7a_pci = &s->pci_dev;
>> +
>> +    object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>> +    qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>> +    qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>> +}
>> +
>> +static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>> +                                          PCIBus *rootbus)
>> +{
>> +    return "0000:00";
>> +}
>> +
>> +static void ls7a_pciehost_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
>> +
>> +    hc->root_bus_path = ls7a_pciehost_root_bus_path;
>> +    dc->realize = ls7a_pciehost_realize;
>> +    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
>> +    dc->fw_name = "pci";
>> +    dc->user_creatable = false;
>> +}
>> +
>> +static const TypeInfo ls7a_pciehost_info = {
>> +    .name          = TYPE_LS7A_HOST_DEVICE,
> 
> TYPE_LS7A_PCIE_HOST_BRIDGE would be the normal convention.
> 
>> +    .parent        = TYPE_PCIE_HOST_BRIDGE,
>> +    .instance_size = sizeof(LS7APCIEHost),
>> +    .instance_init = ls7a_pciehost_initfn,
>> +    .class_init    = ls7a_pciehost_class_init,
>> +};
>> +
>> +static void ls7a_register_types(void)
>> +{
>> +    type_register_static(&ls7a_pciehost_info);
>> +    type_register_static(&ls7a_pcie_device_info);
>> +}
>> +
>> +type_init(ls7a_register_types)
>> diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
>> index 4c4f39c15c..c4955455fd 100644
>> --- a/hw/pci-host/meson.build
>> +++ b/hw/pci-host/meson.build
>> @@ -11,6 +11,7 @@ pci_ss.add(when: 'CONFIG_PCI_SABRE', if_true: files('sabre.c'))
>>   pci_ss.add(when: 'CONFIG_XEN_IGD_PASSTHROUGH', if_true: files('xen_igd_pt.c'))
>>   pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c'))
>>   pci_ss.add(when: 'CONFIG_SH_PCI', if_true: files('sh_pci.c'))
>> +pci_ss.add(when: 'CONFIG_PCI_EXPRESS_7A', if_true: files('ls7a.c'))
>>     # PPC devices
>>   pci_ss.add(when: 'CONFIG_RAVEN_PCI', if_true: files('raven.c'))
>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>> new file mode 100644
>> index 0000000000..32d6f045dc
>> --- /dev/null
>> +++ b/include/hw/pci-host/ls7a.h
>> @@ -0,0 +1,51 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * QEMU LoongArch CPU
>> + *
>> + * Copyright (c) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef HW_LS7A_H
>> +#define HW_LS7A_H
>> +
>> +#include "hw/pci/pci.h"
>> +#include "hw/pci/pcie_host.h"
>> +#include "hw/pci-host/pam.h"
>> +#include "qemu/units.h"
>> +#include "qemu/range.h"
>> +#include "qom/object.h"
>> +
>> +#define HT1LO_PCICFG_BASE        0x1a000000
>> +#define HT1LO_PCICFG_SIZE        0x02000000
>> +
>> +#define LS_PCIECFG_BASE          0x20000000
>> +#define LS_PCIECFG_SIZE          0x08000000
>> +
>> +#define LS7A_PCI_IO_BASE         0x18000000UL
>> +#define LS7A_PCI_IO_SIZE         0x00010000
>> +
>> +struct LS7APCIState {
>> +    /*< private >*/
>> +    PCIDevice parent_obj;
>> +    /*< public >*/
>> +};
>> +
>> +typedef struct LS7APCIState LS7APCIState;
>> +typedef struct LS7APCIEHost {
>> +    /*< private >*/
>> +    PCIExpressHost parent_obj;
>> +    /*< public >*/
>> +
>> +    LS7APCIState pci_dev;
>> +
>> +    MemoryRegion pci_conf;
>> +    MemoryRegion pci_io;
>> +} LS7APCIEHost;
>> +
>> +#define TYPE_LS7A_HOST_DEVICE "ls7a1000-pciehost"
>> +OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIEHost, LS7A_HOST_DEVICE)
>> +
>> +#define TYPE_LS7A_PCIE "ls7a1000_pcie"
>> +OBJECT_DECLARE_SIMPLE_TYPE(LS7APCIState, LS7A_PCIE)
>> +
>> +#endif /* HW_LS7A_H */
> 
> 
> ATB,
> 
> Mark.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 16/27] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC)
  2021-12-17 23:54   ` Mark Cave-Ayland
@ 2021-12-21  3:43     ` yangxiaojuan
  0 siblings, 0 replies; 58+ messages in thread
From: yangxiaojuan @ 2021-12-21  3:43 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel
  Cc: peter.maydell, thuth, philmd, i.qemu, richard.henderson, laurent,
	peterx, f4bug, alistair.francis, maobibo, pbonzini, chenhuacai,
	alex.bennee, gaosong

Hi,Mark

On 12/18/2021 07:54 AM, Mark Cave-Ayland wrote:
> On 04/12/2021 12:07, Xiaojuan Yang wrote:
> 
>> Loongson-3A5000 support 14 interrupts from 64 - 77(Timer->75 IPI->76)
>> Loongson-3A5000 and ls7a form a legacy model and extended model irq
>> hierarchy.Tcg mode emulate a simplified extended model which
>> has no Legacy I/O Interrupt Controller(LIOINTC) and LPC.
>> e.g:
>>
>>   |    +-----+    +---------+     +-------+             |
>>   |    | IPI |--> | CPUINTC | <-- | Timer |             |
>>   |    +-----+    +---------+     +-------+             |
>>   |                    ^                                |
>>   |                    |                                |
>>   |               +---------+
>>   |               | EIOINTC |
>>   |               +---------+
>>   |                ^       ^                            |
>>   |                |       |                            |
>>   |         +---------+ +---------+                     |
>>   |         | PCH-PIC | | PCH-MSI |                     |
>>   |         +---------+ +---------+                     |
>>   |           ^     ^           ^                       |
>>   |           |     |           |                       |
>>   |   +---------+ +---------+ +---------+               |
>>   |   | UARTs | | Devices | | Devices |                 |
>>   |   +---------+ +---------+ +---------+               |
>>   |        ^                                            |
>>
>> The following series patch will realize the interrupt
>> controller in this model.
>>
>> More detailed info can be found at the kernel doc or manual
>> 1.https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/
>> linux-loongson.git/tree/Documentation/loongarch?h=loongarch-next
>> 2.https://github.com/loongson/LoongArch-Documentation
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>   target/loongarch/cpu.c | 28 ++++++++++++++++++++++++++++
>>   1 file changed, 28 insertions(+)
>>
>> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
>> index 62c2a4d813..afa550c950 100644
>> --- a/target/loongarch/cpu.c
>> +++ b/target/loongarch/cpu.c
>> @@ -504,11 +504,39 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
>>       lacc->parent_realize(dev, errp);
>>   }
>>   +#ifndef CONFIG_USER_ONLY
>> +static void loongarch_cpu_set_irq(void *opaque, int irq, int level)
>> +{
>> +    LoongArchCPU *cpu = opaque;
>> +    CPULoongArchState *env = &cpu->env;
>> +    CPUState *cs = CPU(cpu);
>> +
>> +    if (irq < 0 || irq > N_IRQS) {
>> +        return;
>> +    }
>> +
>> +    if (level) {
>> +        env->CSR_ESTAT |= 1 << irq;
>> +    } else {
>> +        env->CSR_ESTAT &= ~(1 << irq);
>> +    }
>> +
>> +    if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
>> +        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
>> +    } else {
>> +        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
>> +    }
>> +}
>> +#endif
>> +
>>   static void loongarch_cpu_initfn(Object *obj)
>>   {
>>       LoongArchCPU *cpu = LOONGARCH_CPU(obj);
>>         cpu_set_cpustate_pointers(cpu);
>> +#ifndef CONFIG_USER_ONLY
>> +    qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
>> +#endif
>>   }
>>     static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
> 
> Rather than use defines to split out user mode, I would suggest using a separate function in a similar way to sparc64_cpu_devinit() in hw/sparc64/sparc64.c to set up the parts of the CPU that are only required in system mode. This function can then be called as part of the board setup.
> 
yes, put the code to the board setup stage is more suitable, thank you!
> 
> ATB,
> 
> Mark.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 18/27] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
  2021-12-18  0:33   ` Mark Cave-Ayland
@ 2021-12-22  2:38     ` yangxiaojuan
  2021-12-23 10:21       ` Mark Cave-Ayland
  0 siblings, 1 reply; 58+ messages in thread
From: yangxiaojuan @ 2021-12-22  2:38 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

Hi, Mark

On 12/18/2021 08:33 AM, Mark Cave-Ayland wrote:
> On 04/12/2021 12:07, Xiaojuan Yang wrote:
> 
>> This patch realize the PCH-PIC interrupt controller.
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>   hw/intc/Kconfig                     |   4 +
>>   hw/intc/loongarch_pch_pic.c         | 357 ++++++++++++++++++++++++++++
>>   hw/intc/meson.build                 |   1 +
>>   hw/intc/trace-events                |   5 +
>>   hw/loongarch/Kconfig                |   1 +
>>   include/hw/intc/loongarch_pch_pic.h |  61 +++++
>>   6 files changed, 429 insertions(+)
>>   create mode 100644 hw/intc/loongarch_pch_pic.c
>>   create mode 100644 include/hw/intc/loongarch_pch_pic.h
>>
>> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
>> index 511dcac537..96da13ad1d 100644
>> --- a/hw/intc/Kconfig
>> +++ b/hw/intc/Kconfig
>> @@ -76,3 +76,7 @@ config M68K_IRQC
>>     config LOONGARCH_IPI
>>       bool
>> +
>> +config LOONGARCH_PCH_PIC
>> +    bool
>> +    select UNIMP
>> diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
>> new file mode 100644
>> index 0000000000..2ede29ceb0
>> --- /dev/null
>> +++ b/hw/intc/loongarch_pch_pic.c
>> @@ -0,0 +1,357 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * QEMU Loongson 7A1000 I/O interrupt controller.
>> + *
>> + * Copyright (C) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "hw/sysbus.h"
>> +#include "hw/loongarch/loongarch.h"
>> +#include "hw/irq.h"
>> +#include "hw/intc/loongarch_pch_pic.h"
>> +#include "migration/vmstate.h"
>> +#include "trace.h"
>> +
>> +#define for_each_set_bit(bit, addr, size) \
>> +         for ((bit) = find_first_bit((addr), (size));            \
>> +              (bit) < (size);                                    \
>> +              (bit) = find_next_bit((addr), (size), (bit) + 1))
>> +
>> +static void pch_pic_update_irq(loongarch_pch_pic *s, uint64_t mask, int level)
>> +{
>> +    int i;
>> +    uint64_t val;
>> +    val = mask & s->intirr & (~s->int_mask);
>> +
>> +    for_each_set_bit(i, &val, 64) {
>> +        if (level == 1) {
>> +            if ((s->intisr & (0x1ULL << i)) == 0) {
>> +                s->intisr |= 1ULL << i;
>> +                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 1);
>> +            }
>> +        } else if (level == 0) {
>> +            if (s->intisr & (0x1ULL << i)) {
>> +                s->intisr &= ~(0x1ULL << i);
>> +                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 0);
>> +            }
>> +        }
>> +    }
>> +}
> 
> The normal pattern would be to use something like:
> 
> for (i = 0; i < 64; i++) {
>     if (level) {
>         s->intisr |= 1ULL << i;
>     } else {
>         s->intisr &= ~(0x1ULL << i);
>     }
> 
>     qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], level);
> }
> 
> Why is it necessary to check the previous value of (s->intisr & (0x1ULL << i)) here?

Here check the previous value to avoid Unnecessary write. It seems make things more complicated. I will modify

> 
>> +static void pch_pic_irq_handler(void *opaque, int irq, int level)
>> +{
>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
>> +
>> +    assert(irq < PCH_PIC_IRQ_NUM);
>> +    uint64_t mask = 1ULL << irq;
>> +
>> +    trace_pch_pic_irq_handler(s->intedge, irq, level);
>> +
>> +    if (s->intedge & mask) {
>> +        /* Edge triggered */
>> +        if (level) {
>> +            if ((s->last_intirr & mask) == 0) {
>> +                s->intirr |= mask;
>> +            }
>> +            s->last_intirr |= mask;
>> +        } else {
>> +            s->last_intirr &= ~mask;
>> +        }
>> +    } else {
>> +        /* Level triggered */
>> +        if (level) {
>> +            s->intirr |= mask;
>> +            s->last_intirr |= mask;
>> +        } else {
>> +            s->intirr &= ~mask;
>> +            s->last_intirr &= ~mask;
>> +        }
>> +
>> +    }
>> +    pch_pic_update_irq(s, mask, level);
>> +}
>> +
>> +static uint64_t loongarch_pch_pic_reg_read(void *opaque, hwaddr addr,
>> +                                           unsigned size)
>> +{
>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
>> +    uint64_t val = 0;
>> +    uint32_t offset = addr & 0xfff;
>> +    int64_t offset_tmp;
>> +
>> +    if (size == 8) {
>> +        switch (offset) {
>> +        case PCH_PIC_INT_ID_OFFSET:
>> +            val = (PCH_PIC_INT_ID_NUM << 32) | PCH_PIC_INT_ID_VAL;
>> +            break;
>> +        case PCH_PIC_INT_MASK_OFFSET:
>> +            val =  s->int_mask;
>> +            break;
>> +        case PCH_PIC_INT_STATUS_OFFSET:
>> +            val = s->intisr & (~s->int_mask);
>> +            break;
>> +        case PCH_PIC_INT_EDGE_OFFSET:
>> +            val = s->intedge;
>> +            break;
>> +        case PCH_PIC_INT_POL_OFFSET:
>> +            val = s->int_polarity;
>> +            break;
>> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
>> +            val = s->htmsi_en;
>> +            break;
>> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
>> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
>> +            break;
>> +        default:
>> +            break;
>> +        }
>> +    } else if (size == 4) {
>> +        switch (offset) {
>> +        case PCH_PIC_INT_ID_OFFSET:
>> +            val = PCH_PIC_INT_ID_VAL;
>> +            break;
>> +        case PCH_PIC_INT_ID_OFFSET + 4:
>> +            val = PCH_PIC_INT_ID_NUM;
>> +            break;
>> +        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
>> +            val = ldl_p((void *)&s->int_mask +
>> +                        (offset - PCH_PIC_INT_MASK_OFFSET));
>> +            break;
>> +        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
>> +            val = ldl_p((void *)&s->intisr +
>> +                        (offset - PCH_PIC_INT_STATUS_OFFSET)) & (~s->int_mask);
>> +            break;
>> +        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
>> +            val = ldl_p((void *)&s->intedge +
>> +                        (offset - PCH_PIC_INT_EDGE_OFFSET));
>> +            break;
>> +        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
>> +            val = ldl_p((void *)&s->int_polarity +
>> +                        (offset - PCH_PIC_INT_POL_OFFSET));
>> +            break;
>> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
>> +            val = ldl_p((void *)&s->htmsi_en +
>> +                        (offset - PCH_PIC_HTMSI_EN_OFFSET));
>> +            break;
>> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
>> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
>> +            break;
>> +        default:
>> +            break;
>> +        }
>> +    } else if (size == 1) {
>> +        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
>> +            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>> +                val = s->htmsi_vector[offset_tmp];
>> +            }
>> +        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
>> +            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>> +                val = s->route_entry[offset_tmp];
>> +            }
>> +        }
>> +    }
>> +
>> +    trace_loongarch_pch_pic_read(size, (uint32_t)addr, val);
>> +    return val;
>> +}
>> +
>> +static void loongarch_pch_pic_reg_write(void *opaque, hwaddr addr,
>> +                                        uint64_t data, unsigned size)
>> +{
>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
> 
> Perhaps use LoongArchPCHPIC for the camel case version?

OK, all interrupt controller will use the camel case. 

> 
>> +    int32_t offset_tmp;
>> +    uint32_t offset, old;
>> +    offset = addr & 0xfff;
>> +
>> +    trace_loongarch_pch_pic_write(size, (uint32_t)addr, data);
>> +
>> +    if (size == 8) {
>> +        switch (offset) {
>> +        case PCH_PIC_INT_MASK_OFFSET:
>> +            old = s->int_mask;
>> +            s->int_mask = data;
>> +            if (old & ~data) {
>> +                pch_pic_update_irq(s, (old & ~data), 1);
>> +            } else if (~old & data) {
>> +                pch_pic_update_irq(s, (~old & data), 0);
>> +            }
>> +            break;
>> +        case PCH_PIC_INT_STATUS_OFFSET:
>> +            s->intisr = data;
>> +            break;
>> +        case PCH_PIC_INT_EDGE_OFFSET:
>> +            s->intedge = data;
>> +            break;
>> +        case PCH_PIC_INT_CLEAR_OFFSET:
>> +            s->intirr &= (~(data & s->intedge));
>> +            pch_pic_update_irq(s, data, 0);
>> +            s->intisr &= (~data);
>> +            break;
>> +        case PCH_PIC_INT_POL_OFFSET:
>> +            s->int_polarity = data;
>> +            break;
>> +        case PCH_PIC_HTMSI_EN_OFFSET:
>> +            s->htmsi_en = data;
>> +            break;
>> +        case PCH_PIC_AUTO_CTRL0_OFFSET:
>> +        case PCH_PIC_AUTO_CTRL1_OFFSET:
>> +            break;
>> +        default:
>> +            break;
>> +        }
>> +    } else if (size == 4) {
>> +        switch (offset) {
>> +        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
>> +            offset -= PCH_PIC_INT_MASK_OFFSET;
>> +            old = ldl_p((void *)&s->int_mask + offset);
>> +            stl_p((void *)&s->int_mask + offset, data);
>> +
>> +            if (old & ~data) {
>> +                pch_pic_update_irq(s, (old & ~data), 1);
>> +            } else if (~old & data) {
>> +                pch_pic_update_irq(s, (~old & data), 0);
>> +            }
>> +            break;
>> +        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
>> +            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_STATUS_OFFSET),
>> +                  data);
>> +            break;
>> +        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
>> +            stl_p((void *)&s->intedge + (offset - PCH_PIC_INT_EDGE_OFFSET),
>> +                  data);
>> +            break;
>> +        case PCH_PIC_INT_CLEAR_OFFSET...PCH_PIC_INT_CLEAR_END:
>> +            old = s->intirr & (~(data & s->intedge));
>> +            stl_p((void *)&s->intirr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
>> +                  old);
>> +            pch_pic_update_irq(s, data, 0);
>> +            old = s->intisr & (~data);
>> +            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
>> +                  old);
>> +            break;
>> +        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
>> +            stl_p((void *)&s->int_polarity + (offset - PCH_PIC_INT_POL_OFFSET),
>> +                  data);
>> +            break;
>> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
>> +            stl_p((void *)&s->htmsi_en + (offset - PCH_PIC_HTMSI_EN_OFFSET),
>> +                  data);
>> +            break;
>> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
>> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
>> +            break;
>> +        default:
>> +            break;
>> +        }
>> +    } else if (size == 1) {
>> +        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
>> +            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>> +                s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
>> +            }
>> +        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
>> +            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>> +                s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
>> +            }
>> +        }
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps loongarch_pch_pic_ops = {
>> +    .read = loongarch_pch_pic_reg_read,
>> +    .write = loongarch_pch_pic_reg_write,
>> +    .valid = {
>> +        .min_access_size = 1,
>> +        .max_access_size = 8,
>> +    },
>> +    .impl = {
>> +        .min_access_size = 1,
>> +        .max_access_size = 8,
>> +    },
>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>> +};
> 
> It feels like this should be split into 2 separate memory regions: as per before set .min_access_size = 4 for PCH_PIC_INT_MASK_OFFSET ... PCH_PIC_AUTO_CTRL1_END and use uint32_t for the underlying types in loongarch_pch_pic.
> 
> This leaves a separate memory region for accesses > PCH_PIC_HTMSI_VEC_OFFSET which can be set with .min_access_size = 1 which maps nicely to the underlying uint8_t types. Which means you should be able to access the arrays directly instead of having to use ldl_p() and stl_p().
> 

yeah, here the PCH_PIC_HTMSI_VEC_OFFSET region is right in the middle, I want to use a separate memory region to overlap the pch-pic region, is it ok to do like this? Thanks

> +static void loongarch_pch_pic_reset(DeviceState *d)
>> +{
>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(d);
>> +    int i;
>> +
>> +    s->int_mask = -1ULL;
>> +    s->htmsi_en = 0x0;
>> +    s->intedge  = 0x0;
>> +    s->intclr   = 0x0;
>> +    s->auto_crtl0 = 0x0;
>> +    s->auto_crtl1 = 0x0;
>> +    for (i = 0; i < 64; i++) {
>> +        s->route_entry[i] = 0x1;
>> +        s->htmsi_vector[i] = 0x0;
>> +    }
>> +    s->intirr = 0x0;
>> +    s->intisr = 0x0;
>> +    s->last_intirr = 0x0;
>> +    s->int_polarity = 0x0;
>> +}
>> +
>> +static void loongarch_pch_pic_init(Object *obj)
>> +{
>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(obj);
>> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
>> +    int i;
>> +
>> +    memory_region_init_io(&s->iomem, obj, &loongarch_pch_pic_ops,
>> +                          s, TYPE_LOONGARCH_PCH_PIC, 0x1000);
>> +    sysbus_init_mmio(sbd, &s->iomem);
>> +
>> +    for (i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>> +        sysbus_init_irq(sbd, &s->parent_irq[i]);
>> +    }
>> +    qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
>> +}
>> +
>> +static const VMStateDescription vmstate_loongarch_pch_pic = {
>> +    .name = TYPE_LOONGARCH_PCH_PIC,
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT64(int_mask, loongarch_pch_pic),
>> +        VMSTATE_UINT64(htmsi_en, loongarch_pch_pic),
>> +        VMSTATE_UINT64(intedge, loongarch_pch_pic),
>> +        VMSTATE_UINT64(intclr, loongarch_pch_pic),
>> +        VMSTATE_UINT64(auto_crtl0, loongarch_pch_pic),
>> +        VMSTATE_UINT64(auto_crtl1, loongarch_pch_pic),
>> +        VMSTATE_UINT8_ARRAY(route_entry, loongarch_pch_pic, 64),
>> +        VMSTATE_UINT8_ARRAY(htmsi_vector, loongarch_pch_pic, 64),
>> +        VMSTATE_UINT64(last_intirr, loongarch_pch_pic),
>> +        VMSTATE_UINT64(intirr, loongarch_pch_pic),
>> +        VMSTATE_UINT64(intisr, loongarch_pch_pic),
>> +        VMSTATE_UINT64(int_polarity, loongarch_pch_pic),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>> +static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->reset = loongarch_pch_pic_reset;
>> +    dc->vmsd = &vmstate_loongarch_pch_pic;
>> +}
>> +
>> +static const TypeInfo loongarch_pch_pic_info = {
>> +    .name          = TYPE_LOONGARCH_PCH_PIC,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(loongarch_pch_pic),
>> +    .instance_init = loongarch_pch_pic_init,
>> +    .class_init    = loongarch_pch_pic_class_init,
>> +};
>> +
>> +static void loongarch_pch_pic_register_types(void)
>> +{
>> +    type_register_static(&loongarch_pch_pic_info);
>> +}
>> +
>> +type_init(loongarch_pch_pic_register_types)
>> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
>> index 51f0c3988a..33ba63266e 100644
>> --- a/hw/intc/meson.build
>> +++ b/hw/intc/meson.build
>> @@ -58,3 +58,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
>>   specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
>>   specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
>>   specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
>> +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
>> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
>> index 124608e51f..52fedf82be 100644
>> --- a/hw/intc/trace-events
>> +++ b/hw/intc/trace-events
>> @@ -250,3 +250,8 @@ sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
>>   # loongarch_ipi.c
>>   loongarch_ipi_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
>>   loongarch_ipi_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
>> +
>> +# loongarch_pch_pic.c
>> +pch_pic_irq_handler(uint32_t edge, int irq, int level) "edge 0x%02x irq %d level %d"
>> +loongarch_pch_pic_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>> +loongarch_pch_pic_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>> index 1591574397..c2b8046b94 100644
>> --- a/hw/loongarch/Kconfig
>> +++ b/hw/loongarch/Kconfig
>> @@ -2,3 +2,4 @@ config LOONGSON3_LS7A
>>       bool
>>       select PCI_EXPRESS_7A
>>       select LOONGARCH_IPI
>> +    select LOONGARCH_PCH_PIC
>> diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
>> new file mode 100644
>> index 0000000000..bc04ed28ef
>> --- /dev/null
>> +++ b/include/hw/intc/loongarch_pch_pic.h
>> @@ -0,0 +1,61 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * LoongArch 7A1000 I/O interrupt controller definitions
>> + *
>> + * Copyright (c) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
>> +DECLARE_INSTANCE_CHECKER(struct loongarch_pch_pic, LOONGARCH_PCH_PIC,
>> +                         TYPE_LOONGARCH_PCH_PIC)
>> +
>> +#define PCH_PIC_IRQ_START               0
>> +#define PCH_PIC_IRQ_END                 63
>> +#define PCH_PIC_IRQ_NUM                 64
>> +#define PCH_PIC_INT_ID_VAL              0x7000000UL
>> +#define PCH_PIC_INT_ID_NUM              0x3f0001UL
>> +
>> +#define PCH_PIC_INT_ID_OFFSET           0x00
>> +#define PCH_PIC_INT_ID_END              0x07
>> +#define PCH_PIC_INT_MASK_OFFSET         0x20
>> +#define PCH_PIC_INT_MASK_END            0x27
>> +#define PCH_PIC_HTMSI_EN_OFFSET         0x40
>> +#define PCH_PIC_HTMSI_EN_END            0x47
>> +#define PCH_PIC_INT_EDGE_OFFSET         0x60
>> +#define PCH_PIC_INT_EDGE_END            0x67
>> +#define PCH_PIC_INT_CLEAR_OFFSET        0x80
>> +#define PCH_PIC_INT_CLEAR_END           0x87
>> +#define PCH_PIC_AUTO_CTRL0_OFFSET       0xc0
>> +#define PCH_PIC_AUTO_CTRL0_END          0xc7
>> +#define PCH_PIC_AUTO_CTRL1_OFFSET       0xe0
>> +#define PCH_PIC_AUTO_CTRL1_END          0xe8
>> +#define PCH_PIC_ROUTE_ENTRY_OFFSET      0x100
>> +#define PCH_PIC_ROUTE_ENTRY_END         0x13f
>> +#define PCH_PIC_HTMSI_VEC_OFFSET        0x200
>> +#define PCH_PIC_HTMSI_VEC_END           0x23f
>> +#define PCH_PIC_INT_STATUS_OFFSET       0x3a0
>> +#define PCH_PIC_INT_STATUS_END          0x3a7
>> +#define PCH_PIC_INT_POL_OFFSET          0x3e0
>> +#define PCH_PIC_INT_POL_END             0x3e7
>> +
>> +typedef struct loongarch_pch_pic {
>> +    SysBusDevice parent_obj;
>> +    qemu_irq parent_irq[64];
>> +    uint64_t int_mask; /*0x020 interrupt mask register*/
>> +    uint64_t htmsi_en;/*0x040 1=msi*/
>> +    uint64_t intedge; /*0x060 edge=1 level  =0*/
>> +    uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
>> +    uint64_t auto_crtl0; /*0x0c0*/
>> +    uint64_t auto_crtl1; /*0x0e0*/
>> +    uint8_t route_entry[64]; /*0x100 - 0x138*/
>> +    uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
>> +    uint64_t last_intirr;    /* edge detection */
>> +    uint64_t intirr; /* 0x380 interrupt request register */
>> +    uint64_t intisr; /* 0x3a0 interrupt service register */
>> +    /*
>> +     * 0x3e0 interrupt level polarity selection
>> +     * register 0 for high level trigger
>> +     */
>> +    uint64_t int_polarity;
>> +    MemoryRegion iomem;
>> +} loongarch_pch_pic;
> 
> 
> ATB,
> 
> Mark.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2021-12-18 10:02   ` Mark Cave-Ayland
@ 2021-12-22  8:26     ` yangxiaojuan
  2021-12-23 10:52       ` Mark Cave-Ayland
  0 siblings, 1 reply; 58+ messages in thread
From: yangxiaojuan @ 2021-12-22  8:26 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel
  Cc: peter.maydell, thuth, philmd, richard.henderson, laurent, peterx,
	f4bug, alex.bennee, alistair.francis, maobibo, gaosong, pbonzini,
	i.qemu, chenhuacai

Hi, Mark

On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
> On 04/12/2021 12:07, Xiaojuan Yang wrote:
> 
>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>> 2.Add irq set and map for the pci host. Non pci device
>> use irq 0-16, pci device use 16-64.
>> 3.Add some unimplented device to emulate guest unused
>> memory space.
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>   hw/loongarch/Kconfig            |  8 +++++
>>   hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>   hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>   include/hw/intc/loongarch_ipi.h |  2 ++
>>   include/hw/pci-host/ls7a.h      |  4 +++
>>   softmmu/qdev-monitor.c          |  3 +-
>>   6 files changed, 117 insertions(+), 5 deletions(-)
>>
>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>> index 468e3acc74..9ea3b92708 100644
>> --- a/hw/loongarch/Kconfig
>> +++ b/hw/loongarch/Kconfig
>> @@ -1,5 +1,13 @@
>>   config LOONGSON3_LS7A
>>       bool
>> +    imply VGA_PCI
>> +    imply VIRTIO_VGA
>> +    imply PARALLEL
>> +    imply PCI_DEVICES
>> +    select ISA_BUS
>> +    select SERIAL
>> +    select SERIAL_ISA
>> +    select VIRTIO_PCI
>>       select PCI_EXPRESS_7A
>>       select LOONGARCH_IPI
>>       select LOONGARCH_PCH_PIC
>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>> index c42f830208..e4a02e7c18 100644
>> --- a/hw/loongarch/loongson3.c
>> +++ b/hw/loongarch/loongson3.c
>> @@ -10,8 +10,11 @@
>>   #include "qemu/datadir.h"
>>   #include "qapi/error.h"
>>   #include "hw/boards.h"
>> +#include "hw/char/serial.h"
>>   #include "sysemu/sysemu.h"
>>   #include "sysemu/qtest.h"
>> +#include "hw/irq.h"
>> +#include "net/net.h"
>>   #include "sysemu/runstate.h"
>>   #include "sysemu/reset.h"
>>   #include "hw/loongarch/loongarch.h"
>> @@ -20,6 +23,7 @@
>>   #include "hw/intc/loongarch_pch_pic.h"
>>   #include "hw/intc/loongarch_pch_msi.h"
>>   #include "hw/pci-host/ls7a.h"
>> +#include "hw/misc/unimp.h"
>>       static void loongarch_cpu_reset(void *opaque)
>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>       memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>   }
>>   -static void loongson3_irq_init(MachineState *machine)
>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>   {
>>       LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>       SysBusDevice *d;
>> +    PCIBus *pci_bus;
>>       int cpu, pin, i;
>>       unsigned long ipi_addr;
>>   @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>       sysbus_realize_and_unref(d, &error_fatal);
>>       sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>   +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>> +
>>       /* Connect 64 pch_pic irqs to extioi */
>>       for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>           sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>           sysbus_connect_irq(d, i,
>>                              qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>       }
>> +
>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>> +    d = SYS_BUS_DEVICE(pciehost);
>> +    sysbus_realize_and_unref(d, &error_fatal);
>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>> +
>> +    /* Connect 48 pci irq to pch_pic */
>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>> +        qdev_connect_gpio_out(pciehost, i,
>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>> +    }
>> +
>> +    return pci_bus;
>> +}
>> +
>> +/* Network support */
>> +static void network_init(PCIBus *pci_bus)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < nb_nics; i++) {
>> +        NICInfo *nd = &nd_table[i];
>> +
>> +        if (!nd->model) {
>> +            nd->model = g_strdup("virtio");
>> +        }
>> +
>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>> +    }
>>   }
>>     static void loongson3_init(MachineState *machine)
>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>       MemoryRegion *address_space_mem = get_system_memory();
>>       LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>       int i;
>> +    PCIBus *pci_bus = NULL;
>>         if (!cpu_model) {
>>           cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>       memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>       offset += highram_size;
>>   +    /*
>> +     * There are some invalid guest memory access.
>> +     * Create some unimplemented devices to emulate this.
>> +     */
>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>> +
>>       /* Initialize the IO interrupt subsystem */
>> -    loongson3_irq_init(machine);
>> +    pci_bus = loongson3_irq_init(machine);
>> +
>> +    /* Network card */
>> +    network_init(pci_bus);
>> +
>> +    /* VGA setup. Don't bother loading the bios. */
>> +    pci_vga_init(pci_bus);
>> +
>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
> 
> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
> 
> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.

The machine has these devices but we don't want to emulate all the devices, only emulated part devices. 
I don't know if it is ok to do like this.

> 
>>       LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>       LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>> index a783fb2eda..06cd641573 100644
>> --- a/hw/pci-host/ls7a.c
>> +++ b/hw/pci-host/ls7a.c
>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>       }
>>   };
>>   +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>> +{
>> +    PCIINTxRoute route;
>> +
>> +    route.irq = pin;
>> +    route.mode = PCI_INTX_ENABLED;
>> +    return route;
>> +}
>> +
>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>> +{
>> +    PCIBus *bus;
>> +    int offset, irq;
>> +
>> +    bus = pci_get_bus(d);
>> +    if (bus->parent_dev) {
>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>> +        return irq;
>> +    }
> 
> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?

We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.

> 
>> +    /* pci device start from irq 80 */
>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>> +
>> +    return irq;
>> +}
>> +
>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>> +{
>> +    LS7APCIEHost *pciehost = opaque;
>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>> +
>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>> +}
>> +
>>   static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>                                     uint64_t val, unsigned size)
>>   {
>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>       LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>       PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>   -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>> +                                     pci_ls7a_map_irq, s,
>>                                        get_system_memory(), get_system_io(),
>>                                        PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>   +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>> +
>>       memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>                             &pci_ls7a_config_ops, pci->bus,
>>                             "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>       object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>       qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>       qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>> +
>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>   }
>>     static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>> index d2397e53e7..1113c3b1a8 100644
>> --- a/include/hw/intc/loongarch_ipi.h
>> +++ b/include/hw/intc/loongarch_ipi.h
>> @@ -8,6 +8,8 @@
>>   #ifndef HW_LOONGARCH_IPI_H
>>   #define HW_LOONGARCH_IPI_H
>>   +#include "hw/sysbus.h"
>> +
>>   /* Mainy used by iocsr read and write */
>>   #define SMP_IPI_MAILBOX      0x1000ULL
>>   #define CORE_STATUS_OFF       0x0
>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>> index ac938d6d5f..3b9ad1e175 100644
>> --- a/include/hw/pci-host/ls7a.h
>> +++ b/include/hw/pci-host/ls7a.h
>> @@ -37,6 +37,9 @@
>>   #define LS7A_DEVICE_IRQS        16
>>   #define LS7A_PCI_IRQS           48
>>   +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>> +#define LS7A_UART_BASE          0x1fe001e0
>> +
>>   struct LS7APCIState {
>>       /*< private >*/
>>       PCIDevice parent_obj;
>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>         LS7APCIState pci_dev;
>>   +    qemu_irq irqs[LS7A_PCI_IRQS];
>>       MemoryRegion pci_conf;
>>       MemoryRegion pci_io;
>>   } LS7APCIEHost;
>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>> index 01f3834db5..49491d74a1 100644
>> --- a/softmmu/qdev-monitor.c
>> +++ b/softmmu/qdev-monitor.c
>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>                                 QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>                                 QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>                                 QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>> +                              QEMU_ARCH_LOONGARCH)
> 
> This part looks like it belongs to another patch?

OK, I will put this part to a separate patch.

Thanks,
Xiaojuan

> 
>>   #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>   #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
> 
> 
> ATB,
> 
> Mark.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 18/27] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
  2021-12-22  2:38     ` yangxiaojuan
@ 2021-12-23 10:21       ` Mark Cave-Ayland
  2022-01-08  9:44         ` yangxiaojuan
  0 siblings, 1 reply; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-23 10:21 UTC (permalink / raw)
  To: yangxiaojuan, qemu-devel
  Cc: peter.maydell, thuth, alex.bennee, i.qemu, richard.henderson,
	laurent, peterx, f4bug, alistair.francis, maobibo, pbonzini,
	chenhuacai, philmd, gaosong

On 22/12/2021 02:38, yangxiaojuan wrote:

> Hi, Mark
> 
> On 12/18/2021 08:33 AM, Mark Cave-Ayland wrote:
>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>
>>> This patch realize the PCH-PIC interrupt controller.
>>>
>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>> ---
>>>    hw/intc/Kconfig                     |   4 +
>>>    hw/intc/loongarch_pch_pic.c         | 357 ++++++++++++++++++++++++++++
>>>    hw/intc/meson.build                 |   1 +
>>>    hw/intc/trace-events                |   5 +
>>>    hw/loongarch/Kconfig                |   1 +
>>>    include/hw/intc/loongarch_pch_pic.h |  61 +++++
>>>    6 files changed, 429 insertions(+)
>>>    create mode 100644 hw/intc/loongarch_pch_pic.c
>>>    create mode 100644 include/hw/intc/loongarch_pch_pic.h
>>>
>>> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
>>> index 511dcac537..96da13ad1d 100644
>>> --- a/hw/intc/Kconfig
>>> +++ b/hw/intc/Kconfig
>>> @@ -76,3 +76,7 @@ config M68K_IRQC
>>>      config LOONGARCH_IPI
>>>        bool
>>> +
>>> +config LOONGARCH_PCH_PIC
>>> +    bool
>>> +    select UNIMP
>>> diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
>>> new file mode 100644
>>> index 0000000000..2ede29ceb0
>>> --- /dev/null
>>> +++ b/hw/intc/loongarch_pch_pic.c
>>> @@ -0,0 +1,357 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>> +/*
>>> + * QEMU Loongson 7A1000 I/O interrupt controller.
>>> + *
>>> + * Copyright (C) 2021 Loongson Technology Corporation Limited
>>> + */
>>> +
>>> +#include "qemu/osdep.h"
>>> +#include "hw/sysbus.h"
>>> +#include "hw/loongarch/loongarch.h"
>>> +#include "hw/irq.h"
>>> +#include "hw/intc/loongarch_pch_pic.h"
>>> +#include "migration/vmstate.h"
>>> +#include "trace.h"
>>> +
>>> +#define for_each_set_bit(bit, addr, size) \
>>> +         for ((bit) = find_first_bit((addr), (size));            \
>>> +              (bit) < (size);                                    \
>>> +              (bit) = find_next_bit((addr), (size), (bit) + 1))
>>> +
>>> +static void pch_pic_update_irq(loongarch_pch_pic *s, uint64_t mask, int level)
>>> +{
>>> +    int i;
>>> +    uint64_t val;
>>> +    val = mask & s->intirr & (~s->int_mask);
>>> +
>>> +    for_each_set_bit(i, &val, 64) {
>>> +        if (level == 1) {
>>> +            if ((s->intisr & (0x1ULL << i)) == 0) {
>>> +                s->intisr |= 1ULL << i;
>>> +                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 1);
>>> +            }
>>> +        } else if (level == 0) {
>>> +            if (s->intisr & (0x1ULL << i)) {
>>> +                s->intisr &= ~(0x1ULL << i);
>>> +                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 0);
>>> +            }
>>> +        }
>>> +    }
>>> +}
>>
>> The normal pattern would be to use something like:
>>
>> for (i = 0; i < 64; i++) {
>>      if (level) {
>>          s->intisr |= 1ULL << i;
>>      } else {
>>          s->intisr &= ~(0x1ULL << i);
>>      }
>>
>>      qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], level);
>> }
>>
>> Why is it necessary to check the previous value of (s->intisr & (0x1ULL << i)) here?
> 
> Here check the previous value to avoid Unnecessary write. It seems make things more complicated. I will modify

In general a *_update_irq() function should be fine to propagate the IRQ up to the 
parent directly: I think this is fine in this case because you are directly 
manipulating the parent_irq elements rather than using e.g. a priority encoder within 
this device to raise an IRQ to the CPU. I'm presuming this final prioritisation and 
delivery is done elsewhere?

>>> +static void pch_pic_irq_handler(void *opaque, int irq, int level)
>>> +{
>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
>>> +
>>> +    assert(irq < PCH_PIC_IRQ_NUM);
>>> +    uint64_t mask = 1ULL << irq;
>>> +
>>> +    trace_pch_pic_irq_handler(s->intedge, irq, level);
>>> +
>>> +    if (s->intedge & mask) {
>>> +        /* Edge triggered */
>>> +        if (level) {
>>> +            if ((s->last_intirr & mask) == 0) {
>>> +                s->intirr |= mask;
>>> +            }
>>> +            s->last_intirr |= mask;
>>> +        } else {
>>> +            s->last_intirr &= ~mask;
>>> +        }
>>> +    } else {
>>> +        /* Level triggered */
>>> +        if (level) {
>>> +            s->intirr |= mask;
>>> +            s->last_intirr |= mask;
>>> +        } else {
>>> +            s->intirr &= ~mask;
>>> +            s->last_intirr &= ~mask;
>>> +        }
>>> +
>>> +    }
>>> +    pch_pic_update_irq(s, mask, level);
>>> +}
>>> +
>>> +static uint64_t loongarch_pch_pic_reg_read(void *opaque, hwaddr addr,
>>> +                                           unsigned size)
>>> +{
>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
>>> +    uint64_t val = 0;
>>> +    uint32_t offset = addr & 0xfff;
>>> +    int64_t offset_tmp;
>>> +
>>> +    if (size == 8) {
>>> +        switch (offset) {
>>> +        case PCH_PIC_INT_ID_OFFSET:
>>> +            val = (PCH_PIC_INT_ID_NUM << 32) | PCH_PIC_INT_ID_VAL;
>>> +            break;
>>> +        case PCH_PIC_INT_MASK_OFFSET:
>>> +            val =  s->int_mask;
>>> +            break;
>>> +        case PCH_PIC_INT_STATUS_OFFSET:
>>> +            val = s->intisr & (~s->int_mask);
>>> +            break;
>>> +        case PCH_PIC_INT_EDGE_OFFSET:
>>> +            val = s->intedge;
>>> +            break;
>>> +        case PCH_PIC_INT_POL_OFFSET:
>>> +            val = s->int_polarity;
>>> +            break;
>>> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
>>> +            val = s->htmsi_en;
>>> +            break;
>>> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
>>> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
>>> +            break;
>>> +        default:
>>> +            break;
>>> +        }
>>> +    } else if (size == 4) {
>>> +        switch (offset) {
>>> +        case PCH_PIC_INT_ID_OFFSET:
>>> +            val = PCH_PIC_INT_ID_VAL;
>>> +            break;
>>> +        case PCH_PIC_INT_ID_OFFSET + 4:
>>> +            val = PCH_PIC_INT_ID_NUM;
>>> +            break;
>>> +        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
>>> +            val = ldl_p((void *)&s->int_mask +
>>> +                        (offset - PCH_PIC_INT_MASK_OFFSET));
>>> +            break;
>>> +        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
>>> +            val = ldl_p((void *)&s->intisr +
>>> +                        (offset - PCH_PIC_INT_STATUS_OFFSET)) & (~s->int_mask);
>>> +            break;
>>> +        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
>>> +            val = ldl_p((void *)&s->intedge +
>>> +                        (offset - PCH_PIC_INT_EDGE_OFFSET));
>>> +            break;
>>> +        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
>>> +            val = ldl_p((void *)&s->int_polarity +
>>> +                        (offset - PCH_PIC_INT_POL_OFFSET));
>>> +            break;
>>> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
>>> +            val = ldl_p((void *)&s->htmsi_en +
>>> +                        (offset - PCH_PIC_HTMSI_EN_OFFSET));
>>> +            break;
>>> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
>>> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
>>> +            break;
>>> +        default:
>>> +            break;
>>> +        }
>>> +    } else if (size == 1) {
>>> +        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
>>> +            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
>>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>>> +                val = s->htmsi_vector[offset_tmp];
>>> +            }
>>> +        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
>>> +            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
>>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>>> +                val = s->route_entry[offset_tmp];
>>> +            }
>>> +        }
>>> +    }
>>> +
>>> +    trace_loongarch_pch_pic_read(size, (uint32_t)addr, val);
>>> +    return val;
>>> +}
>>> +
>>> +static void loongarch_pch_pic_reg_write(void *opaque, hwaddr addr,
>>> +                                        uint64_t data, unsigned size)
>>> +{
>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
>>
>> Perhaps use LoongArchPCHPIC for the camel case version?
> 
> OK, all interrupt controller will use the camel case.
> 
>>
>>> +    int32_t offset_tmp;
>>> +    uint32_t offset, old;
>>> +    offset = addr & 0xfff;
>>> +
>>> +    trace_loongarch_pch_pic_write(size, (uint32_t)addr, data);
>>> +
>>> +    if (size == 8) {
>>> +        switch (offset) {
>>> +        case PCH_PIC_INT_MASK_OFFSET:
>>> +            old = s->int_mask;
>>> +            s->int_mask = data;
>>> +            if (old & ~data) {
>>> +                pch_pic_update_irq(s, (old & ~data), 1);
>>> +            } else if (~old & data) {
>>> +                pch_pic_update_irq(s, (~old & data), 0);
>>> +            }
>>> +            break;
>>> +        case PCH_PIC_INT_STATUS_OFFSET:
>>> +            s->intisr = data;
>>> +            break;
>>> +        case PCH_PIC_INT_EDGE_OFFSET:
>>> +            s->intedge = data;
>>> +            break;
>>> +        case PCH_PIC_INT_CLEAR_OFFSET:
>>> +            s->intirr &= (~(data & s->intedge));
>>> +            pch_pic_update_irq(s, data, 0);
>>> +            s->intisr &= (~data);
>>> +            break;
>>> +        case PCH_PIC_INT_POL_OFFSET:
>>> +            s->int_polarity = data;
>>> +            break;
>>> +        case PCH_PIC_HTMSI_EN_OFFSET:
>>> +            s->htmsi_en = data;
>>> +            break;
>>> +        case PCH_PIC_AUTO_CTRL0_OFFSET:
>>> +        case PCH_PIC_AUTO_CTRL1_OFFSET:
>>> +            break;
>>> +        default:
>>> +            break;
>>> +        }
>>> +    } else if (size == 4) {
>>> +        switch (offset) {
>>> +        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
>>> +            offset -= PCH_PIC_INT_MASK_OFFSET;
>>> +            old = ldl_p((void *)&s->int_mask + offset);
>>> +            stl_p((void *)&s->int_mask + offset, data);
>>> +
>>> +            if (old & ~data) {
>>> +                pch_pic_update_irq(s, (old & ~data), 1);
>>> +            } else if (~old & data) {
>>> +                pch_pic_update_irq(s, (~old & data), 0);
>>> +            }
>>> +            break;
>>> +        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
>>> +            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_STATUS_OFFSET),
>>> +                  data);
>>> +            break;
>>> +        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
>>> +            stl_p((void *)&s->intedge + (offset - PCH_PIC_INT_EDGE_OFFSET),
>>> +                  data);
>>> +            break;
>>> +        case PCH_PIC_INT_CLEAR_OFFSET...PCH_PIC_INT_CLEAR_END:
>>> +            old = s->intirr & (~(data & s->intedge));
>>> +            stl_p((void *)&s->intirr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
>>> +                  old);
>>> +            pch_pic_update_irq(s, data, 0);
>>> +            old = s->intisr & (~data);
>>> +            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
>>> +                  old);
>>> +            break;
>>> +        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
>>> +            stl_p((void *)&s->int_polarity + (offset - PCH_PIC_INT_POL_OFFSET),
>>> +                  data);
>>> +            break;
>>> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
>>> +            stl_p((void *)&s->htmsi_en + (offset - PCH_PIC_HTMSI_EN_OFFSET),
>>> +                  data);
>>> +            break;
>>> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
>>> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
>>> +            break;
>>> +        default:
>>> +            break;
>>> +        }
>>> +    } else if (size == 1) {
>>> +        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
>>> +            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
>>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>>> +                s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
>>> +            }
>>> +        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
>>> +            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
>>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>>> +                s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
>>> +            }
>>> +        }
>>> +    }
>>> +}
>>> +
>>> +static const MemoryRegionOps loongarch_pch_pic_ops = {
>>> +    .read = loongarch_pch_pic_reg_read,
>>> +    .write = loongarch_pch_pic_reg_write,
>>> +    .valid = {
>>> +        .min_access_size = 1,
>>> +        .max_access_size = 8,
>>> +    },
>>> +    .impl = {
>>> +        .min_access_size = 1,
>>> +        .max_access_size = 8,
>>> +    },
>>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>>> +};
>>
>> It feels like this should be split into 2 separate memory regions: as per before set .min_access_size = 4 for PCH_PIC_INT_MASK_OFFSET ... PCH_PIC_AUTO_CTRL1_END and use uint32_t for the underlying types in loongarch_pch_pic.
>>
>> This leaves a separate memory region for accesses > PCH_PIC_HTMSI_VEC_OFFSET which can be set with .min_access_size = 1 which maps nicely to the underlying uint8_t types. Which means you should be able to access the arrays directly instead of having to use ldl_p() and stl_p().
>>
> 
> yeah, here the PCH_PIC_HTMSI_VEC_OFFSET region is right in the middle, I want to use a separate memory region to overlap the pch-pic region, is it ok to do like this? Thanks

That should be fine. I'd also use a single container memory region so that you only 
have to expose a single memory region with sysbus_init_mmio() as below:

>> +static void loongarch_pch_pic_reset(DeviceState *d)
>>> +{
>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(d);
>>> +    int i;
>>> +
>>> +    s->int_mask = -1ULL;
>>> +    s->htmsi_en = 0x0;
>>> +    s->intedge  = 0x0;
>>> +    s->intclr   = 0x0;
>>> +    s->auto_crtl0 = 0x0;
>>> +    s->auto_crtl1 = 0x0;
>>> +    for (i = 0; i < 64; i++) {
>>> +        s->route_entry[i] = 0x1;
>>> +        s->htmsi_vector[i] = 0x0;
>>> +    }
>>> +    s->intirr = 0x0;
>>> +    s->intisr = 0x0;
>>> +    s->last_intirr = 0x0;
>>> +    s->int_polarity = 0x0;
>>> +}
>>> +
>>> +static void loongarch_pch_pic_init(Object *obj)
>>> +{
>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(obj);
>>> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
>>> +    int i;
>>> +
>>> +    memory_region_init_io(&s->iomem, obj, &loongarch_pch_pic_ops,
>>> +                          s, TYPE_LOONGARCH_PCH_PIC, 0x1000);
>>> +    sysbus_init_mmio(sbd, &s->iomem);

Please adjust the example below for your particular case replacing the sizes as 
appropriate but I would expect it to look something like:

     memory_region_init(&s->picmem, obj, TYPE_LOONGARCH_PCH_PIC, 0x1000);

     memory_region_init_io(&s->picintmem, obj, &loongarch_pch_pic_int_ops,
                           s, "pic.int", 0xaaaa);
     memory_region_add_subregion(&s->picmem, INT_OFFSET, &s->picintmem);

     memory_region_init_io(&s->picintmem, obj, &loongarch_pch_pic_htmsi_ops,
                           s, "pic.htmsi", 0xbbbb);
     memory_region_add_subregion(&s->picmem, HTMSI_OFFSET, &s->picintmem);

     memory_region_init_io(&s->picroutemem, obj, &loongarch_pch_pic_route_ops,
                           s, "pic.route", 0xcccc);
     memory_region_add_subregion(&s->picmem, ROUTE_OFFSET, &s->picroutemem);

     sysbus_init_mmio(sbd, &s->picmem);

You can then configure each of the *_ops memory regions with the correct .min.access 
and .max.access sizes accordingly, and each region will show up separately in the 
output of "info mtree".

>>> +    for (i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>> +        sysbus_init_irq(sbd, &s->parent_irq[i]);
>>> +    }
>>> +    qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
>>> +}
>>> +
>>> +static const VMStateDescription vmstate_loongarch_pch_pic = {
>>> +    .name = TYPE_LOONGARCH_PCH_PIC,
>>> +    .version_id = 1,
>>> +    .minimum_version_id = 1,
>>> +    .fields = (VMStateField[]) {
>>> +        VMSTATE_UINT64(int_mask, loongarch_pch_pic),
>>> +        VMSTATE_UINT64(htmsi_en, loongarch_pch_pic),
>>> +        VMSTATE_UINT64(intedge, loongarch_pch_pic),
>>> +        VMSTATE_UINT64(intclr, loongarch_pch_pic),
>>> +        VMSTATE_UINT64(auto_crtl0, loongarch_pch_pic),
>>> +        VMSTATE_UINT64(auto_crtl1, loongarch_pch_pic),
>>> +        VMSTATE_UINT8_ARRAY(route_entry, loongarch_pch_pic, 64),
>>> +        VMSTATE_UINT8_ARRAY(htmsi_vector, loongarch_pch_pic, 64),
>>> +        VMSTATE_UINT64(last_intirr, loongarch_pch_pic),
>>> +        VMSTATE_UINT64(intirr, loongarch_pch_pic),
>>> +        VMSTATE_UINT64(intisr, loongarch_pch_pic),
>>> +        VMSTATE_UINT64(int_polarity, loongarch_pch_pic),
>>> +        VMSTATE_END_OF_LIST()
>>> +    }
>>> +};
>>> +
>>> +static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
>>> +{
>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>> +
>>> +    dc->reset = loongarch_pch_pic_reset;
>>> +    dc->vmsd = &vmstate_loongarch_pch_pic;
>>> +}
>>> +
>>> +static const TypeInfo loongarch_pch_pic_info = {
>>> +    .name          = TYPE_LOONGARCH_PCH_PIC,
>>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>>> +    .instance_size = sizeof(loongarch_pch_pic),
>>> +    .instance_init = loongarch_pch_pic_init,
>>> +    .class_init    = loongarch_pch_pic_class_init,
>>> +};
>>> +
>>> +static void loongarch_pch_pic_register_types(void)
>>> +{
>>> +    type_register_static(&loongarch_pch_pic_info);
>>> +}
>>> +
>>> +type_init(loongarch_pch_pic_register_types)
>>> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
>>> index 51f0c3988a..33ba63266e 100644
>>> --- a/hw/intc/meson.build
>>> +++ b/hw/intc/meson.build
>>> @@ -58,3 +58,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
>>>    specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
>>>    specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
>>>    specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
>>> +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
>>> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
>>> index 124608e51f..52fedf82be 100644
>>> --- a/hw/intc/trace-events
>>> +++ b/hw/intc/trace-events
>>> @@ -250,3 +250,8 @@ sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
>>>    # loongarch_ipi.c
>>>    loongarch_ipi_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
>>>    loongarch_ipi_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
>>> +
>>> +# loongarch_pch_pic.c
>>> +pch_pic_irq_handler(uint32_t edge, int irq, int level) "edge 0x%02x irq %d level %d"
>>> +loongarch_pch_pic_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>>> +loongarch_pch_pic_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>> index 1591574397..c2b8046b94 100644
>>> --- a/hw/loongarch/Kconfig
>>> +++ b/hw/loongarch/Kconfig
>>> @@ -2,3 +2,4 @@ config LOONGSON3_LS7A
>>>        bool
>>>        select PCI_EXPRESS_7A
>>>        select LOONGARCH_IPI
>>> +    select LOONGARCH_PCH_PIC
>>> diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
>>> new file mode 100644
>>> index 0000000000..bc04ed28ef
>>> --- /dev/null
>>> +++ b/include/hw/intc/loongarch_pch_pic.h
>>> @@ -0,0 +1,61 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>> +/*
>>> + * LoongArch 7A1000 I/O interrupt controller definitions
>>> + *
>>> + * Copyright (c) 2021 Loongson Technology Corporation Limited
>>> + */
>>> +
>>> +#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
>>> +DECLARE_INSTANCE_CHECKER(struct loongarch_pch_pic, LOONGARCH_PCH_PIC,
>>> +                         TYPE_LOONGARCH_PCH_PIC)
>>> +
>>> +#define PCH_PIC_IRQ_START               0
>>> +#define PCH_PIC_IRQ_END                 63
>>> +#define PCH_PIC_IRQ_NUM                 64
>>> +#define PCH_PIC_INT_ID_VAL              0x7000000UL
>>> +#define PCH_PIC_INT_ID_NUM              0x3f0001UL
>>> +
>>> +#define PCH_PIC_INT_ID_OFFSET           0x00
>>> +#define PCH_PIC_INT_ID_END              0x07
>>> +#define PCH_PIC_INT_MASK_OFFSET         0x20
>>> +#define PCH_PIC_INT_MASK_END            0x27
>>> +#define PCH_PIC_HTMSI_EN_OFFSET         0x40
>>> +#define PCH_PIC_HTMSI_EN_END            0x47
>>> +#define PCH_PIC_INT_EDGE_OFFSET         0x60
>>> +#define PCH_PIC_INT_EDGE_END            0x67
>>> +#define PCH_PIC_INT_CLEAR_OFFSET        0x80
>>> +#define PCH_PIC_INT_CLEAR_END           0x87
>>> +#define PCH_PIC_AUTO_CTRL0_OFFSET       0xc0
>>> +#define PCH_PIC_AUTO_CTRL0_END          0xc7
>>> +#define PCH_PIC_AUTO_CTRL1_OFFSET       0xe0
>>> +#define PCH_PIC_AUTO_CTRL1_END          0xe8
>>> +#define PCH_PIC_ROUTE_ENTRY_OFFSET      0x100
>>> +#define PCH_PIC_ROUTE_ENTRY_END         0x13f
>>> +#define PCH_PIC_HTMSI_VEC_OFFSET        0x200
>>> +#define PCH_PIC_HTMSI_VEC_END           0x23f
>>> +#define PCH_PIC_INT_STATUS_OFFSET       0x3a0
>>> +#define PCH_PIC_INT_STATUS_END          0x3a7
>>> +#define PCH_PIC_INT_POL_OFFSET          0x3e0
>>> +#define PCH_PIC_INT_POL_END             0x3e7
>>> +
>>> +typedef struct loongarch_pch_pic {
>>> +    SysBusDevice parent_obj;
>>> +    qemu_irq parent_irq[64];
>>> +    uint64_t int_mask; /*0x020 interrupt mask register*/
>>> +    uint64_t htmsi_en;/*0x040 1=msi*/
>>> +    uint64_t intedge; /*0x060 edge=1 level  =0*/
>>> +    uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
>>> +    uint64_t auto_crtl0; /*0x0c0*/
>>> +    uint64_t auto_crtl1; /*0x0e0*/
>>> +    uint8_t route_entry[64]; /*0x100 - 0x138*/
>>> +    uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
>>> +    uint64_t last_intirr;    /* edge detection */
>>> +    uint64_t intirr; /* 0x380 interrupt request register */
>>> +    uint64_t intisr; /* 0x3a0 interrupt service register */
>>> +    /*
>>> +     * 0x3e0 interrupt level polarity selection
>>> +     * register 0 for high level trigger
>>> +     */
>>> +    uint64_t int_polarity;
>>> +    MemoryRegion iomem;
>>> +} loongarch_pch_pic;

ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2021-12-22  8:26     ` yangxiaojuan
@ 2021-12-23 10:52       ` Mark Cave-Ayland
  2022-01-10  2:26         ` yangxiaojuan
  2022-01-12  9:37         ` maobibo
  0 siblings, 2 replies; 58+ messages in thread
From: Mark Cave-Ayland @ 2021-12-23 10:52 UTC (permalink / raw)
  To: yangxiaojuan, qemu-devel
  Cc: peter.maydell, thuth, alex.bennee, i.qemu, richard.henderson,
	laurent, peterx, f4bug, alistair.francis, maobibo, pbonzini,
	chenhuacai, philmd, gaosong

On 22/12/2021 08:26, yangxiaojuan wrote:

> Hi, Mark
> 
> On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>
>>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>>> 2.Add irq set and map for the pci host. Non pci device
>>> use irq 0-16, pci device use 16-64.
>>> 3.Add some unimplented device to emulate guest unused
>>> memory space.
>>>
>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>> ---
>>>    hw/loongarch/Kconfig            |  8 +++++
>>>    hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>>    hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>>    include/hw/intc/loongarch_ipi.h |  2 ++
>>>    include/hw/pci-host/ls7a.h      |  4 +++
>>>    softmmu/qdev-monitor.c          |  3 +-
>>>    6 files changed, 117 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>> index 468e3acc74..9ea3b92708 100644
>>> --- a/hw/loongarch/Kconfig
>>> +++ b/hw/loongarch/Kconfig
>>> @@ -1,5 +1,13 @@
>>>    config LOONGSON3_LS7A
>>>        bool
>>> +    imply VGA_PCI
>>> +    imply VIRTIO_VGA
>>> +    imply PARALLEL
>>> +    imply PCI_DEVICES
>>> +    select ISA_BUS
>>> +    select SERIAL
>>> +    select SERIAL_ISA
>>> +    select VIRTIO_PCI
>>>        select PCI_EXPRESS_7A
>>>        select LOONGARCH_IPI
>>>        select LOONGARCH_PCH_PIC
>>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>>> index c42f830208..e4a02e7c18 100644
>>> --- a/hw/loongarch/loongson3.c
>>> +++ b/hw/loongarch/loongson3.c
>>> @@ -10,8 +10,11 @@
>>>    #include "qemu/datadir.h"
>>>    #include "qapi/error.h"
>>>    #include "hw/boards.h"
>>> +#include "hw/char/serial.h"
>>>    #include "sysemu/sysemu.h"
>>>    #include "sysemu/qtest.h"
>>> +#include "hw/irq.h"
>>> +#include "net/net.h"
>>>    #include "sysemu/runstate.h"
>>>    #include "sysemu/reset.h"
>>>    #include "hw/loongarch/loongarch.h"
>>> @@ -20,6 +23,7 @@
>>>    #include "hw/intc/loongarch_pch_pic.h"
>>>    #include "hw/intc/loongarch_pch_msi.h"
>>>    #include "hw/pci-host/ls7a.h"
>>> +#include "hw/misc/unimp.h"
>>>        static void loongarch_cpu_reset(void *opaque)
>>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>>        memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>>    }
>>>    -static void loongson3_irq_init(MachineState *machine)
>>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>>    {
>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>>        SysBusDevice *d;
>>> +    PCIBus *pci_bus;
>>>        int cpu, pin, i;
>>>        unsigned long ipi_addr;
>>>    @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>>        sysbus_realize_and_unref(d, &error_fatal);
>>>        sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>>    +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>>> +
>>>        /* Connect 64 pch_pic irqs to extioi */
>>>        for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>>            sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>>            sysbus_connect_irq(d, i,
>>>                               qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>>        }
>>> +
>>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>>> +    d = SYS_BUS_DEVICE(pciehost);
>>> +    sysbus_realize_and_unref(d, &error_fatal);
>>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>>> +
>>> +    /* Connect 48 pci irq to pch_pic */
>>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>>> +        qdev_connect_gpio_out(pciehost, i,
>>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>>> +    }
>>> +
>>> +    return pci_bus;
>>> +}
>>> +
>>> +/* Network support */
>>> +static void network_init(PCIBus *pci_bus)
>>> +{
>>> +    int i;
>>> +
>>> +    for (i = 0; i < nb_nics; i++) {
>>> +        NICInfo *nd = &nd_table[i];
>>> +
>>> +        if (!nd->model) {
>>> +            nd->model = g_strdup("virtio");
>>> +        }
>>> +
>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>> +    }
>>>    }
>>>      static void loongson3_init(MachineState *machine)
>>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>>        MemoryRegion *address_space_mem = get_system_memory();
>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>        int i;
>>> +    PCIBus *pci_bus = NULL;
>>>          if (!cpu_model) {
>>>            cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>>        memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>>        offset += highram_size;
>>>    +    /*
>>> +     * There are some invalid guest memory access.
>>> +     * Create some unimplemented devices to emulate this.
>>> +     */
>>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>>> +
>>>        /* Initialize the IO interrupt subsystem */
>>> -    loongson3_irq_init(machine);
>>> +    pci_bus = loongson3_irq_init(machine);
>>> +
>>> +    /* Network card */
>>> +    network_init(pci_bus);
>>> +
>>> +    /* VGA setup. Don't bother loading the bios. */
>>> +    pci_vga_init(pci_bus);
>>> +
>>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
>>
>> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
>>
>> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.
> 
> The machine has these devices but we don't want to emulate all the devices, only emulated part devices.
> I don't know if it is ok to do like this.

I'm not sure I understand what you mean by part devices here - could you give an example?

>>>        LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>>        LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>>> index a783fb2eda..06cd641573 100644
>>> --- a/hw/pci-host/ls7a.c
>>> +++ b/hw/pci-host/ls7a.c
>>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>>        }
>>>    };
>>>    +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>>> +{
>>> +    PCIINTxRoute route;
>>> +
>>> +    route.irq = pin;
>>> +    route.mode = PCI_INTX_ENABLED;
>>> +    return route;
>>> +}
>>> +
>>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>>> +{
>>> +    PCIBus *bus;
>>> +    int offset, irq;
>>> +
>>> +    bus = pci_get_bus(d);
>>> +    if (bus->parent_dev) {
>>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>>> +        return irq;
>>> +    }
>>
>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
> 
> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.

I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected 
via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at 
pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to 
map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), 
which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?

>>> +    /* pci device start from irq 80 */
>>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>>> +
>>> +    return irq;
>>> +}
>>> +
>>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>>> +{
>>> +    LS7APCIEHost *pciehost = opaque;
>>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>> +
>>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>>> +}
>>> +
>>>    static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>>                                      uint64_t val, unsigned size)
>>>    {
>>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>>        LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>>        PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>>    -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>>> +                                     pci_ls7a_map_irq, s,
>>>                                         get_system_memory(), get_system_io(),
>>>                                         PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>>    +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>>> +
>>>        memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>>                              &pci_ls7a_config_ops, pci->bus,
>>>                              "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>>        object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>>        qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>>        qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>>> +
>>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>>    }
>>>      static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>>> index d2397e53e7..1113c3b1a8 100644
>>> --- a/include/hw/intc/loongarch_ipi.h
>>> +++ b/include/hw/intc/loongarch_ipi.h
>>> @@ -8,6 +8,8 @@
>>>    #ifndef HW_LOONGARCH_IPI_H
>>>    #define HW_LOONGARCH_IPI_H
>>>    +#include "hw/sysbus.h"
>>> +
>>>    /* Mainy used by iocsr read and write */
>>>    #define SMP_IPI_MAILBOX      0x1000ULL
>>>    #define CORE_STATUS_OFF       0x0
>>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>>> index ac938d6d5f..3b9ad1e175 100644
>>> --- a/include/hw/pci-host/ls7a.h
>>> +++ b/include/hw/pci-host/ls7a.h
>>> @@ -37,6 +37,9 @@
>>>    #define LS7A_DEVICE_IRQS        16
>>>    #define LS7A_PCI_IRQS           48
>>>    +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>>> +#define LS7A_UART_BASE          0x1fe001e0
>>> +
>>>    struct LS7APCIState {
>>>        /*< private >*/
>>>        PCIDevice parent_obj;
>>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>>          LS7APCIState pci_dev;
>>>    +    qemu_irq irqs[LS7A_PCI_IRQS];
>>>        MemoryRegion pci_conf;
>>>        MemoryRegion pci_io;
>>>    } LS7APCIEHost;
>>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>>> index 01f3834db5..49491d74a1 100644
>>> --- a/softmmu/qdev-monitor.c
>>> +++ b/softmmu/qdev-monitor.c
>>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>>                                  QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>>                                  QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>>                                  QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>>> +                              QEMU_ARCH_LOONGARCH)
>>
>> This part looks like it belongs to another patch?
> 
> OK, I will put this part to a separate patch.
> 
> Thanks,
> Xiaojuan
> 
>>
>>>    #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>>    #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)

ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 18/27] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
  2021-12-23 10:21       ` Mark Cave-Ayland
@ 2022-01-08  9:44         ` yangxiaojuan
  0 siblings, 0 replies; 58+ messages in thread
From: yangxiaojuan @ 2022-01-08  9:44 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-level

Hi,Mark:

  Sorry for the late reply. I just saw the mail after I send the v4 patch. I sorted the mail into different folders from
the qemu-devel, so I didn't see the mail in time. Sorry again.

Xiaojuan

On 12/23/2021 06:21 PM, Mark Cave-Ayland wrote:
> On 22/12/2021 02:38, yangxiaojuan wrote:
> 
>> Hi, Mark
>>
>> On 12/18/2021 08:33 AM, Mark Cave-Ayland wrote:
>>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>>
>>>> This patch realize the PCH-PIC interrupt controller.
>>>>
>>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>>> ---
>>>>    hw/intc/Kconfig                     |   4 +
>>>>    hw/intc/loongarch_pch_pic.c         | 357 ++++++++++++++++++++++++++++
>>>>    hw/intc/meson.build                 |   1 +
>>>>    hw/intc/trace-events                |   5 +
>>>>    hw/loongarch/Kconfig                |   1 +
>>>>    include/hw/intc/loongarch_pch_pic.h |  61 +++++
>>>>    6 files changed, 429 insertions(+)
>>>>    create mode 100644 hw/intc/loongarch_pch_pic.c
>>>>    create mode 100644 include/hw/intc/loongarch_pch_pic.h
>>>>
>>>> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
>>>> index 511dcac537..96da13ad1d 100644
>>>> --- a/hw/intc/Kconfig
>>>> +++ b/hw/intc/Kconfig
>>>> @@ -76,3 +76,7 @@ config M68K_IRQC
>>>>      config LOONGARCH_IPI
>>>>        bool
>>>> +
>>>> +config LOONGARCH_PCH_PIC
>>>> +    bool
>>>> +    select UNIMP
>>>> diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
>>>> new file mode 100644
>>>> index 0000000000..2ede29ceb0
>>>> --- /dev/null
>>>> +++ b/hw/intc/loongarch_pch_pic.c
>>>> @@ -0,0 +1,357 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>>> +/*
>>>> + * QEMU Loongson 7A1000 I/O interrupt controller.
>>>> + *
>>>> + * Copyright (C) 2021 Loongson Technology Corporation Limited
>>>> + */
>>>> +
>>>> +#include "qemu/osdep.h"
>>>> +#include "hw/sysbus.h"
>>>> +#include "hw/loongarch/loongarch.h"
>>>> +#include "hw/irq.h"
>>>> +#include "hw/intc/loongarch_pch_pic.h"
>>>> +#include "migration/vmstate.h"
>>>> +#include "trace.h"
>>>> +
>>>> +#define for_each_set_bit(bit, addr, size) \
>>>> +         for ((bit) = find_first_bit((addr), (size));            \
>>>> +              (bit) < (size);                                    \
>>>> +              (bit) = find_next_bit((addr), (size), (bit) + 1))
>>>> +
>>>> +static void pch_pic_update_irq(loongarch_pch_pic *s, uint64_t mask, int level)
>>>> +{
>>>> +    int i;
>>>> +    uint64_t val;
>>>> +    val = mask & s->intirr & (~s->int_mask);
>>>> +
>>>> +    for_each_set_bit(i, &val, 64) {
>>>> +        if (level == 1) {
>>>> +            if ((s->intisr & (0x1ULL << i)) == 0) {
>>>> +                s->intisr |= 1ULL << i;
>>>> +                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 1);
>>>> +            }
>>>> +        } else if (level == 0) {
>>>> +            if (s->intisr & (0x1ULL << i)) {
>>>> +                s->intisr &= ~(0x1ULL << i);
>>>> +                qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], 0);
>>>> +            }
>>>> +        }
>>>> +    }
>>>> +}
>>>
>>> The normal pattern would be to use something like:
>>>
>>> for (i = 0; i < 64; i++) {
>>>      if (level) {
>>>          s->intisr |= 1ULL << i;
>>>      } else {
>>>          s->intisr &= ~(0x1ULL << i);
>>>      }
>>>
>>>      qemu_set_irq(s->parent_irq[s->htmsi_vector[i]], level);
>>> }
>>>
>>> Why is it necessary to check the previous value of (s->intisr & (0x1ULL << i)) here?
>>
>> Here check the previous value to avoid Unnecessary write. It seems make things more complicated. I will modify
> 
> In general a *_update_irq() function should be fine to propagate the IRQ up to the parent directly: I think this is fine in this case because you are directly manipulating the parent_irq elements rather than using e.g. a priority encoder within this device to raise an IRQ to the CPU. I'm presuming this final prioritisation and delivery is done elsewhere?
> 
>>>> +static void pch_pic_irq_handler(void *opaque, int irq, int level)
>>>> +{
>>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
>>>> +
>>>> +    assert(irq < PCH_PIC_IRQ_NUM);
>>>> +    uint64_t mask = 1ULL << irq;
>>>> +
>>>> +    trace_pch_pic_irq_handler(s->intedge, irq, level);
>>>> +
>>>> +    if (s->intedge & mask) {
>>>> +        /* Edge triggered */
>>>> +        if (level) {
>>>> +            if ((s->last_intirr & mask) == 0) {
>>>> +                s->intirr |= mask;
>>>> +            }
>>>> +            s->last_intirr |= mask;
>>>> +        } else {
>>>> +            s->last_intirr &= ~mask;
>>>> +        }
>>>> +    } else {
>>>> +        /* Level triggered */
>>>> +        if (level) {
>>>> +            s->intirr |= mask;
>>>> +            s->last_intirr |= mask;
>>>> +        } else {
>>>> +            s->intirr &= ~mask;
>>>> +            s->last_intirr &= ~mask;
>>>> +        }
>>>> +
>>>> +    }
>>>> +    pch_pic_update_irq(s, mask, level);
>>>> +}
>>>> +
>>>> +static uint64_t loongarch_pch_pic_reg_read(void *opaque, hwaddr addr,
>>>> +                                           unsigned size)
>>>> +{
>>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
>>>> +    uint64_t val = 0;
>>>> +    uint32_t offset = addr & 0xfff;
>>>> +    int64_t offset_tmp;
>>>> +
>>>> +    if (size == 8) {
>>>> +        switch (offset) {
>>>> +        case PCH_PIC_INT_ID_OFFSET:
>>>> +            val = (PCH_PIC_INT_ID_NUM << 32) | PCH_PIC_INT_ID_VAL;
>>>> +            break;
>>>> +        case PCH_PIC_INT_MASK_OFFSET:
>>>> +            val =  s->int_mask;
>>>> +            break;
>>>> +        case PCH_PIC_INT_STATUS_OFFSET:
>>>> +            val = s->intisr & (~s->int_mask);
>>>> +            break;
>>>> +        case PCH_PIC_INT_EDGE_OFFSET:
>>>> +            val = s->intedge;
>>>> +            break;
>>>> +        case PCH_PIC_INT_POL_OFFSET:
>>>> +            val = s->int_polarity;
>>>> +            break;
>>>> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
>>>> +            val = s->htmsi_en;
>>>> +            break;
>>>> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
>>>> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
>>>> +            break;
>>>> +        default:
>>>> +            break;
>>>> +        }
>>>> +    } else if (size == 4) {
>>>> +        switch (offset) {
>>>> +        case PCH_PIC_INT_ID_OFFSET:
>>>> +            val = PCH_PIC_INT_ID_VAL;
>>>> +            break;
>>>> +        case PCH_PIC_INT_ID_OFFSET + 4:
>>>> +            val = PCH_PIC_INT_ID_NUM;
>>>> +            break;
>>>> +        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
>>>> +            val = ldl_p((void *)&s->int_mask +
>>>> +                        (offset - PCH_PIC_INT_MASK_OFFSET));
>>>> +            break;
>>>> +        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
>>>> +            val = ldl_p((void *)&s->intisr +
>>>> +                        (offset - PCH_PIC_INT_STATUS_OFFSET)) & (~s->int_mask);
>>>> +            break;
>>>> +        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
>>>> +            val = ldl_p((void *)&s->intedge +
>>>> +                        (offset - PCH_PIC_INT_EDGE_OFFSET));
>>>> +            break;
>>>> +        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
>>>> +            val = ldl_p((void *)&s->int_polarity +
>>>> +                        (offset - PCH_PIC_INT_POL_OFFSET));
>>>> +            break;
>>>> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
>>>> +            val = ldl_p((void *)&s->htmsi_en +
>>>> +                        (offset - PCH_PIC_HTMSI_EN_OFFSET));
>>>> +            break;
>>>> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
>>>> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
>>>> +            break;
>>>> +        default:
>>>> +            break;
>>>> +        }
>>>> +    } else if (size == 1) {
>>>> +        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
>>>> +            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
>>>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>>>> +                val = s->htmsi_vector[offset_tmp];
>>>> +            }
>>>> +        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
>>>> +            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
>>>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>>>> +                val = s->route_entry[offset_tmp];
>>>> +            }
>>>> +        }
>>>> +    }
>>>> +
>>>> +    trace_loongarch_pch_pic_read(size, (uint32_t)addr, val);
>>>> +    return val;
>>>> +}
>>>> +
>>>> +static void loongarch_pch_pic_reg_write(void *opaque, hwaddr addr,
>>>> +                                        uint64_t data, unsigned size)
>>>> +{
>>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(opaque);
>>>
>>> Perhaps use LoongArchPCHPIC for the camel case version?
>>
>> OK, all interrupt controller will use the camel case.
>>
>>>
>>>> +    int32_t offset_tmp;
>>>> +    uint32_t offset, old;
>>>> +    offset = addr & 0xfff;
>>>> +
>>>> +    trace_loongarch_pch_pic_write(size, (uint32_t)addr, data);
>>>> +
>>>> +    if (size == 8) {
>>>> +        switch (offset) {
>>>> +        case PCH_PIC_INT_MASK_OFFSET:
>>>> +            old = s->int_mask;
>>>> +            s->int_mask = data;
>>>> +            if (old & ~data) {
>>>> +                pch_pic_update_irq(s, (old & ~data), 1);
>>>> +            } else if (~old & data) {
>>>> +                pch_pic_update_irq(s, (~old & data), 0);
>>>> +            }
>>>> +            break;
>>>> +        case PCH_PIC_INT_STATUS_OFFSET:
>>>> +            s->intisr = data;
>>>> +            break;
>>>> +        case PCH_PIC_INT_EDGE_OFFSET:
>>>> +            s->intedge = data;
>>>> +            break;
>>>> +        case PCH_PIC_INT_CLEAR_OFFSET:
>>>> +            s->intirr &= (~(data & s->intedge));
>>>> +            pch_pic_update_irq(s, data, 0);
>>>> +            s->intisr &= (~data);
>>>> +            break;
>>>> +        case PCH_PIC_INT_POL_OFFSET:
>>>> +            s->int_polarity = data;
>>>> +            break;
>>>> +        case PCH_PIC_HTMSI_EN_OFFSET:
>>>> +            s->htmsi_en = data;
>>>> +            break;
>>>> +        case PCH_PIC_AUTO_CTRL0_OFFSET:
>>>> +        case PCH_PIC_AUTO_CTRL1_OFFSET:
>>>> +            break;
>>>> +        default:
>>>> +            break;
>>>> +        }
>>>> +    } else if (size == 4) {
>>>> +        switch (offset) {
>>>> +        case PCH_PIC_INT_MASK_OFFSET...PCH_PIC_INT_MASK_END:
>>>> +            offset -= PCH_PIC_INT_MASK_OFFSET;
>>>> +            old = ldl_p((void *)&s->int_mask + offset);
>>>> +            stl_p((void *)&s->int_mask + offset, data);
>>>> +
>>>> +            if (old & ~data) {
>>>> +                pch_pic_update_irq(s, (old & ~data), 1);
>>>> +            } else if (~old & data) {
>>>> +                pch_pic_update_irq(s, (~old & data), 0);
>>>> +            }
>>>> +            break;
>>>> +        case PCH_PIC_INT_STATUS_OFFSET...PCH_PIC_INT_STATUS_END:
>>>> +            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_STATUS_OFFSET),
>>>> +                  data);
>>>> +            break;
>>>> +        case PCH_PIC_INT_EDGE_OFFSET...PCH_PIC_INT_EDGE_END:
>>>> +            stl_p((void *)&s->intedge + (offset - PCH_PIC_INT_EDGE_OFFSET),
>>>> +                  data);
>>>> +            break;
>>>> +        case PCH_PIC_INT_CLEAR_OFFSET...PCH_PIC_INT_CLEAR_END:
>>>> +            old = s->intirr & (~(data & s->intedge));
>>>> +            stl_p((void *)&s->intirr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
>>>> +                  old);
>>>> +            pch_pic_update_irq(s, data, 0);
>>>> +            old = s->intisr & (~data);
>>>> +            stl_p((void *)&s->intisr + (offset - PCH_PIC_INT_CLEAR_OFFSET),
>>>> +                  old);
>>>> +            break;
>>>> +        case PCH_PIC_INT_POL_OFFSET...PCH_PIC_INT_POL_END:
>>>> +            stl_p((void *)&s->int_polarity + (offset - PCH_PIC_INT_POL_OFFSET),
>>>> +                  data);
>>>> +            break;
>>>> +        case PCH_PIC_HTMSI_EN_OFFSET...PCH_PIC_HTMSI_EN_END:
>>>> +            stl_p((void *)&s->htmsi_en + (offset - PCH_PIC_HTMSI_EN_OFFSET),
>>>> +                  data);
>>>> +            break;
>>>> +        case PCH_PIC_AUTO_CTRL0_OFFSET...PCH_PIC_AUTO_CTRL0_END:
>>>> +        case PCH_PIC_AUTO_CTRL1_OFFSET...PCH_PIC_AUTO_CTRL1_END:
>>>> +            break;
>>>> +        default:
>>>> +            break;
>>>> +        }
>>>> +    } else if (size == 1) {
>>>> +        if (offset >= PCH_PIC_HTMSI_VEC_OFFSET) {
>>>> +            offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
>>>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>>>> +                s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
>>>> +            }
>>>> +        } else if (offset >=  PCH_PIC_ROUTE_ENTRY_OFFSET) {
>>>> +            offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
>>>> +            if (offset_tmp >= 0 && offset_tmp < 64) {
>>>> +                s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
>>>> +            }
>>>> +        }
>>>> +    }
>>>> +}
>>>> +
>>>> +static const MemoryRegionOps loongarch_pch_pic_ops = {
>>>> +    .read = loongarch_pch_pic_reg_read,
>>>> +    .write = loongarch_pch_pic_reg_write,
>>>> +    .valid = {
>>>> +        .min_access_size = 1,
>>>> +        .max_access_size = 8,
>>>> +    },
>>>> +    .impl = {
>>>> +        .min_access_size = 1,
>>>> +        .max_access_size = 8,
>>>> +    },
>>>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>>>> +};
>>>
>>> It feels like this should be split into 2 separate memory regions: as per before set .min_access_size = 4 for PCH_PIC_INT_MASK_OFFSET ... PCH_PIC_AUTO_CTRL1_END and use uint32_t for the underlying types in loongarch_pch_pic.
>>>
>>> This leaves a separate memory region for accesses > PCH_PIC_HTMSI_VEC_OFFSET which can be set with .min_access_size = 1 which maps nicely to the underlying uint8_t types. Which means you should be able to access the arrays directly instead of having to use ldl_p() and stl_p().
>>>
>>
>> yeah, here the PCH_PIC_HTMSI_VEC_OFFSET region is right in the middle, I want to use a separate memory region to overlap the pch-pic region, is it ok to do like this? Thanks
> 
> That should be fine. I'd also use a single container memory region so that you only have to expose a single memory region with sysbus_init_mmio() as below:
> 
>>> +static void loongarch_pch_pic_reset(DeviceState *d)
>>>> +{
>>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(d);
>>>> +    int i;
>>>> +
>>>> +    s->int_mask = -1ULL;
>>>> +    s->htmsi_en = 0x0;
>>>> +    s->intedge  = 0x0;
>>>> +    s->intclr   = 0x0;
>>>> +    s->auto_crtl0 = 0x0;
>>>> +    s->auto_crtl1 = 0x0;
>>>> +    for (i = 0; i < 64; i++) {
>>>> +        s->route_entry[i] = 0x1;
>>>> +        s->htmsi_vector[i] = 0x0;
>>>> +    }
>>>> +    s->intirr = 0x0;
>>>> +    s->intisr = 0x0;
>>>> +    s->last_intirr = 0x0;
>>>> +    s->int_polarity = 0x0;
>>>> +}
>>>> +
>>>> +static void loongarch_pch_pic_init(Object *obj)
>>>> +{
>>>> +    loongarch_pch_pic *s = LOONGARCH_PCH_PIC(obj);
>>>> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
>>>> +    int i;
>>>> +
>>>> +    memory_region_init_io(&s->iomem, obj, &loongarch_pch_pic_ops,
>>>> +                          s, TYPE_LOONGARCH_PCH_PIC, 0x1000);
>>>> +    sysbus_init_mmio(sbd, &s->iomem);
> 
> Please adjust the example below for your particular case replacing the sizes as appropriate but I would expect it to look something like:
> 
>     memory_region_init(&s->picmem, obj, TYPE_LOONGARCH_PCH_PIC, 0x1000);
> 
>     memory_region_init_io(&s->picintmem, obj, &loongarch_pch_pic_int_ops,
>                           s, "pic.int", 0xaaaa);
>     memory_region_add_subregion(&s->picmem, INT_OFFSET, &s->picintmem);
> 
>     memory_region_init_io(&s->picintmem, obj, &loongarch_pch_pic_htmsi_ops,
>                           s, "pic.htmsi", 0xbbbb);
>     memory_region_add_subregion(&s->picmem, HTMSI_OFFSET, &s->picintmem);
> 
>     memory_region_init_io(&s->picroutemem, obj, &loongarch_pch_pic_route_ops,
>                           s, "pic.route", 0xcccc);
>     memory_region_add_subregion(&s->picmem, ROUTE_OFFSET, &s->picroutemem);
> 
>     sysbus_init_mmio(sbd, &s->picmem);
> 
> You can then configure each of the *_ops memory regions with the correct .min.access and .max.access sizes accordingly, and each region will show up separately in the output of "info mtree".
> 
>>>> +    for (i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>>> +        sysbus_init_irq(sbd, &s->parent_irq[i]);
>>>> +    }
>>>> +    qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
>>>> +}
>>>> +
>>>> +static const VMStateDescription vmstate_loongarch_pch_pic = {
>>>> +    .name = TYPE_LOONGARCH_PCH_PIC,
>>>> +    .version_id = 1,
>>>> +    .minimum_version_id = 1,
>>>> +    .fields = (VMStateField[]) {
>>>> +        VMSTATE_UINT64(int_mask, loongarch_pch_pic),
>>>> +        VMSTATE_UINT64(htmsi_en, loongarch_pch_pic),
>>>> +        VMSTATE_UINT64(intedge, loongarch_pch_pic),
>>>> +        VMSTATE_UINT64(intclr, loongarch_pch_pic),
>>>> +        VMSTATE_UINT64(auto_crtl0, loongarch_pch_pic),
>>>> +        VMSTATE_UINT64(auto_crtl1, loongarch_pch_pic),
>>>> +        VMSTATE_UINT8_ARRAY(route_entry, loongarch_pch_pic, 64),
>>>> +        VMSTATE_UINT8_ARRAY(htmsi_vector, loongarch_pch_pic, 64),
>>>> +        VMSTATE_UINT64(last_intirr, loongarch_pch_pic),
>>>> +        VMSTATE_UINT64(intirr, loongarch_pch_pic),
>>>> +        VMSTATE_UINT64(intisr, loongarch_pch_pic),
>>>> +        VMSTATE_UINT64(int_polarity, loongarch_pch_pic),
>>>> +        VMSTATE_END_OF_LIST()
>>>> +    }
>>>> +};
>>>> +
>>>> +static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
>>>> +{
>>>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>>>> +
>>>> +    dc->reset = loongarch_pch_pic_reset;
>>>> +    dc->vmsd = &vmstate_loongarch_pch_pic;
>>>> +}
>>>> +
>>>> +static const TypeInfo loongarch_pch_pic_info = {
>>>> +    .name          = TYPE_LOONGARCH_PCH_PIC,
>>>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>>>> +    .instance_size = sizeof(loongarch_pch_pic),
>>>> +    .instance_init = loongarch_pch_pic_init,
>>>> +    .class_init    = loongarch_pch_pic_class_init,
>>>> +};
>>>> +
>>>> +static void loongarch_pch_pic_register_types(void)
>>>> +{
>>>> +    type_register_static(&loongarch_pch_pic_info);
>>>> +}
>>>> +
>>>> +type_init(loongarch_pch_pic_register_types)
>>>> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
>>>> index 51f0c3988a..33ba63266e 100644
>>>> --- a/hw/intc/meson.build
>>>> +++ b/hw/intc/meson.build
>>>> @@ -58,3 +58,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
>>>>    specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
>>>>    specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
>>>>    specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
>>>> +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
>>>> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
>>>> index 124608e51f..52fedf82be 100644
>>>> --- a/hw/intc/trace-events
>>>> +++ b/hw/intc/trace-events
>>>> @@ -250,3 +250,8 @@ sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
>>>>    # loongarch_ipi.c
>>>>    loongarch_ipi_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
>>>>    loongarch_ipi_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%"PRIx64
>>>> +
>>>> +# loongarch_pch_pic.c
>>>> +pch_pic_irq_handler(uint32_t edge, int irq, int level) "edge 0x%02x irq %d level %d"
>>>> +loongarch_pch_pic_read(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>>>> +loongarch_pch_pic_write(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>>> index 1591574397..c2b8046b94 100644
>>>> --- a/hw/loongarch/Kconfig
>>>> +++ b/hw/loongarch/Kconfig
>>>> @@ -2,3 +2,4 @@ config LOONGSON3_LS7A
>>>>        bool
>>>>        select PCI_EXPRESS_7A
>>>>        select LOONGARCH_IPI
>>>> +    select LOONGARCH_PCH_PIC
>>>> diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
>>>> new file mode 100644
>>>> index 0000000000..bc04ed28ef
>>>> --- /dev/null
>>>> +++ b/include/hw/intc/loongarch_pch_pic.h
>>>> @@ -0,0 +1,61 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>>> +/*
>>>> + * LoongArch 7A1000 I/O interrupt controller definitions
>>>> + *
>>>> + * Copyright (c) 2021 Loongson Technology Corporation Limited
>>>> + */
>>>> +
>>>> +#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
>>>> +DECLARE_INSTANCE_CHECKER(struct loongarch_pch_pic, LOONGARCH_PCH_PIC,
>>>> +                         TYPE_LOONGARCH_PCH_PIC)
>>>> +
>>>> +#define PCH_PIC_IRQ_START               0
>>>> +#define PCH_PIC_IRQ_END                 63
>>>> +#define PCH_PIC_IRQ_NUM                 64
>>>> +#define PCH_PIC_INT_ID_VAL              0x7000000UL
>>>> +#define PCH_PIC_INT_ID_NUM              0x3f0001UL
>>>> +
>>>> +#define PCH_PIC_INT_ID_OFFSET           0x00
>>>> +#define PCH_PIC_INT_ID_END              0x07
>>>> +#define PCH_PIC_INT_MASK_OFFSET         0x20
>>>> +#define PCH_PIC_INT_MASK_END            0x27
>>>> +#define PCH_PIC_HTMSI_EN_OFFSET         0x40
>>>> +#define PCH_PIC_HTMSI_EN_END            0x47
>>>> +#define PCH_PIC_INT_EDGE_OFFSET         0x60
>>>> +#define PCH_PIC_INT_EDGE_END            0x67
>>>> +#define PCH_PIC_INT_CLEAR_OFFSET        0x80
>>>> +#define PCH_PIC_INT_CLEAR_END           0x87
>>>> +#define PCH_PIC_AUTO_CTRL0_OFFSET       0xc0
>>>> +#define PCH_PIC_AUTO_CTRL0_END          0xc7
>>>> +#define PCH_PIC_AUTO_CTRL1_OFFSET       0xe0
>>>> +#define PCH_PIC_AUTO_CTRL1_END          0xe8
>>>> +#define PCH_PIC_ROUTE_ENTRY_OFFSET      0x100
>>>> +#define PCH_PIC_ROUTE_ENTRY_END         0x13f
>>>> +#define PCH_PIC_HTMSI_VEC_OFFSET        0x200
>>>> +#define PCH_PIC_HTMSI_VEC_END           0x23f
>>>> +#define PCH_PIC_INT_STATUS_OFFSET       0x3a0
>>>> +#define PCH_PIC_INT_STATUS_END          0x3a7
>>>> +#define PCH_PIC_INT_POL_OFFSET          0x3e0
>>>> +#define PCH_PIC_INT_POL_END             0x3e7
>>>> +
>>>> +typedef struct loongarch_pch_pic {
>>>> +    SysBusDevice parent_obj;
>>>> +    qemu_irq parent_irq[64];
>>>> +    uint64_t int_mask; /*0x020 interrupt mask register*/
>>>> +    uint64_t htmsi_en;/*0x040 1=msi*/
>>>> +    uint64_t intedge; /*0x060 edge=1 level  =0*/
>>>> +    uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
>>>> +    uint64_t auto_crtl0; /*0x0c0*/
>>>> +    uint64_t auto_crtl1; /*0x0e0*/
>>>> +    uint8_t route_entry[64]; /*0x100 - 0x138*/
>>>> +    uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
>>>> +    uint64_t last_intirr;    /* edge detection */
>>>> +    uint64_t intirr; /* 0x380 interrupt request register */
>>>> +    uint64_t intisr; /* 0x3a0 interrupt service register */
>>>> +    /*
>>>> +     * 0x3e0 interrupt level polarity selection
>>>> +     * register 0 for high level trigger
>>>> +     */
>>>> +    uint64_t int_polarity;
>>>> +    MemoryRegion iomem;
>>>> +} loongarch_pch_pic;
> 
> ATB,
> 
> Mark.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2021-12-23 10:52       ` Mark Cave-Ayland
@ 2022-01-10  2:26         ` yangxiaojuan
  2022-01-15 14:03           ` Mark Cave-Ayland
  2022-01-12  9:37         ` maobibo
  1 sibling, 1 reply; 58+ messages in thread
From: yangxiaojuan @ 2022-01-10  2:26 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-level

Hi, Mark

On 12/23/2021 06:52 PM, Mark Cave-Ayland wrote:
> On 22/12/2021 08:26, yangxiaojuan wrote:
> 
>> Hi, Mark
>>
>> On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
>>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>>
>>>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>>>> 2.Add irq set and map for the pci host. Non pci device
>>>> use irq 0-16, pci device use 16-64.
>>>> 3.Add some unimplented device to emulate guest unused
>>>> memory space.
>>>>
>>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>>> ---
>>>>    hw/loongarch/Kconfig            |  8 +++++
>>>>    hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>>>    hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>>>    include/hw/intc/loongarch_ipi.h |  2 ++
>>>>    include/hw/pci-host/ls7a.h      |  4 +++
>>>>    softmmu/qdev-monitor.c          |  3 +-
>>>>    6 files changed, 117 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>>> index 468e3acc74..9ea3b92708 100644
>>>> --- a/hw/loongarch/Kconfig
>>>> +++ b/hw/loongarch/Kconfig
>>>> @@ -1,5 +1,13 @@
>>>>    config LOONGSON3_LS7A
>>>>        bool
>>>> +    imply VGA_PCI
>>>> +    imply VIRTIO_VGA
>>>> +    imply PARALLEL
>>>> +    imply PCI_DEVICES
>>>> +    select ISA_BUS
>>>> +    select SERIAL
>>>> +    select SERIAL_ISA
>>>> +    select VIRTIO_PCI
>>>>        select PCI_EXPRESS_7A
>>>>        select LOONGARCH_IPI
>>>>        select LOONGARCH_PCH_PIC
>>>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>>>> index c42f830208..e4a02e7c18 100644
>>>> --- a/hw/loongarch/loongson3.c
>>>> +++ b/hw/loongarch/loongson3.c
>>>> @@ -10,8 +10,11 @@
>>>>    #include "qemu/datadir.h"
>>>>    #include "qapi/error.h"
>>>>    #include "hw/boards.h"
>>>> +#include "hw/char/serial.h"
>>>>    #include "sysemu/sysemu.h"
>>>>    #include "sysemu/qtest.h"
>>>> +#include "hw/irq.h"
>>>> +#include "net/net.h"
>>>>    #include "sysemu/runstate.h"
>>>>    #include "sysemu/reset.h"
>>>>    #include "hw/loongarch/loongarch.h"
>>>> @@ -20,6 +23,7 @@
>>>>    #include "hw/intc/loongarch_pch_pic.h"
>>>>    #include "hw/intc/loongarch_pch_msi.h"
>>>>    #include "hw/pci-host/ls7a.h"
>>>> +#include "hw/misc/unimp.h"
>>>>        static void loongarch_cpu_reset(void *opaque)
>>>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>>>        memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>>>    }
>>>>    -static void loongson3_irq_init(MachineState *machine)
>>>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>>>    {
>>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>>>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>>>        SysBusDevice *d;
>>>> +    PCIBus *pci_bus;
>>>>        int cpu, pin, i;
>>>>        unsigned long ipi_addr;
>>>>    @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>>>        sysbus_realize_and_unref(d, &error_fatal);
>>>>        sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>>>    +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>>>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>>>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>>>> +
>>>>        /* Connect 64 pch_pic irqs to extioi */
>>>>        for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>>>            sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>>>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>>>            sysbus_connect_irq(d, i,
>>>>                               qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>>>        }
>>>> +
>>>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>>>> +    d = SYS_BUS_DEVICE(pciehost);
>>>> +    sysbus_realize_and_unref(d, &error_fatal);
>>>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>>>> +
>>>> +    /* Connect 48 pci irq to pch_pic */
>>>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>>>> +        qdev_connect_gpio_out(pciehost, i,
>>>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>>>> +    }
>>>> +
>>>> +    return pci_bus;
>>>> +}
>>>> +
>>>> +/* Network support */
>>>> +static void network_init(PCIBus *pci_bus)
>>>> +{
>>>> +    int i;
>>>> +
>>>> +    for (i = 0; i < nb_nics; i++) {
>>>> +        NICInfo *nd = &nd_table[i];
>>>> +
>>>> +        if (!nd->model) {
>>>> +            nd->model = g_strdup("virtio");
>>>> +        }
>>>> +
>>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>>> +    }
>>>>    }
>>>>      static void loongson3_init(MachineState *machine)
>>>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>>>        MemoryRegion *address_space_mem = get_system_memory();
>>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>>        int i;
>>>> +    PCIBus *pci_bus = NULL;
>>>>          if (!cpu_model) {
>>>>            cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>>>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>>>        memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>>>        offset += highram_size;
>>>>    +    /*
>>>> +     * There are some invalid guest memory access.
>>>> +     * Create some unimplemented devices to emulate this.
>>>> +     */
>>>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>>>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>>>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>>>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>>>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>>>> +
>>>>        /* Initialize the IO interrupt subsystem */
>>>> -    loongson3_irq_init(machine);
>>>> +    pci_bus = loongson3_irq_init(machine);
>>>> +
>>>> +    /* Network card */
>>>> +    network_init(pci_bus);
>>>> +
>>>> +    /* VGA setup. Don't bother loading the bios. */
>>>> +    pci_vga_init(pci_bus);
>>>> +
>>>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
>>>
>>> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
>>>
>>> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.
>>
>> The machine has these devices but we don't want to emulate all the devices, only emulated part devices.
>> I don't know if it is ok to do like this.
> 
> I'm not sure I understand what you mean by part devices here - could you give an example?


For example the ls7a1000 support multiple devices, such as sata, gmac, uart, rtc and so on. But we just realize the rtc.

> 
>>>>        LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>>>        LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>>>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>>>> index a783fb2eda..06cd641573 100644
>>>> --- a/hw/pci-host/ls7a.c
>>>> +++ b/hw/pci-host/ls7a.c
>>>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>>>        }
>>>>    };
>>>>    +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>>>> +{
>>>> +    PCIINTxRoute route;
>>>> +
>>>> +    route.irq = pin;
>>>> +    route.mode = PCI_INTX_ENABLED;
>>>> +    return route;
>>>> +}
>>>> +
>>>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>>>> +{
>>>> +    PCIBus *bus;
>>>> +    int offset, irq;
>>>> +
>>>> +    bus = pci_get_bus(d);
>>>> +    if (bus->parent_dev) {
>>>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>>>> +        return irq;
>>>> +    }
>>>
>>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
>>
>> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
>> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.
> 
> I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?
> 

For this part, I'm a bit confused. I think some pcie devices can directly connect to the host bridges while the pci devices will connected via a pcie-to-pci bridge. So the map irq is like this. 
I will learn more about PCIe to verify whether this idea is correct. Thank you!
 
>>>> +    /* pci device start from irq 80 */
>>>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>>>> +
>>>> +    return irq;
>>>> +}
>>>> +
>>>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>>>> +{
>>>> +    LS7APCIEHost *pciehost = opaque;
>>>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>> +
>>>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>>>> +}
>>>> +
>>>>    static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>>>                                      uint64_t val, unsigned size)
>>>>    {
>>>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>>>        LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>>>        PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>>>    -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>>>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>>>> +                                     pci_ls7a_map_irq, s,
>>>>                                         get_system_memory(), get_system_io(),
>>>>                                         PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>>>    +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>>>> +
>>>>        memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>>>                              &pci_ls7a_config_ops, pci->bus,
>>>>                              "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>>>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>>>        object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>>>        qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>>>        qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>>>> +
>>>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>>>    }
>>>>      static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>>>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>>>> index d2397e53e7..1113c3b1a8 100644
>>>> --- a/include/hw/intc/loongarch_ipi.h
>>>> +++ b/include/hw/intc/loongarch_ipi.h
>>>> @@ -8,6 +8,8 @@
>>>>    #ifndef HW_LOONGARCH_IPI_H
>>>>    #define HW_LOONGARCH_IPI_H
>>>>    +#include "hw/sysbus.h"
>>>> +
>>>>    /* Mainy used by iocsr read and write */
>>>>    #define SMP_IPI_MAILBOX      0x1000ULL
>>>>    #define CORE_STATUS_OFF       0x0
>>>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>>>> index ac938d6d5f..3b9ad1e175 100644
>>>> --- a/include/hw/pci-host/ls7a.h
>>>> +++ b/include/hw/pci-host/ls7a.h
>>>> @@ -37,6 +37,9 @@
>>>>    #define LS7A_DEVICE_IRQS        16
>>>>    #define LS7A_PCI_IRQS           48
>>>>    +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>>>> +#define LS7A_UART_BASE          0x1fe001e0
>>>> +
>>>>    struct LS7APCIState {
>>>>        /*< private >*/
>>>>        PCIDevice parent_obj;
>>>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>>>          LS7APCIState pci_dev;
>>>>    +    qemu_irq irqs[LS7A_PCI_IRQS];
>>>>        MemoryRegion pci_conf;
>>>>        MemoryRegion pci_io;
>>>>    } LS7APCIEHost;
>>>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>>>> index 01f3834db5..49491d74a1 100644
>>>> --- a/softmmu/qdev-monitor.c
>>>> +++ b/softmmu/qdev-monitor.c
>>>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>>>                                  QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>>>                                  QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>>>                                  QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>>>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>>>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>>>> +                              QEMU_ARCH_LOONGARCH)
>>>
>>> This part looks like it belongs to another patch?
>>
>> OK, I will put this part to a separate patch.
>>
>> Thanks,
>> Xiaojuan
>>
>>>
>>>>    #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>>>    #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
> 
> ATB,
> 
> Mark.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2021-12-23 10:52       ` Mark Cave-Ayland
  2022-01-10  2:26         ` yangxiaojuan
@ 2022-01-12  9:37         ` maobibo
  2022-01-15 14:05           ` Mark Cave-Ayland
  1 sibling, 1 reply; 58+ messages in thread
From: maobibo @ 2022-01-12  9:37 UTC (permalink / raw)
  To: Mark Cave-Ayland, yangxiaojuan, qemu-devel
  Cc: peter.maydell, thuth, alex.bennee, philmd, richard.henderson,
	laurent, peterx, f4bug, alistair.francis, gaosong, pbonzini,
	i.qemu, chenhuacai



On 12/23/2021 06:52 PM, Mark Cave-Ayland wrote:
> On 22/12/2021 08:26, yangxiaojuan wrote:
> 
>> Hi, Mark
>>
>> On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
>>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>>
>>>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>>>> 2.Add irq set and map for the pci host. Non pci device
>>>> use irq 0-16, pci device use 16-64.
>>>> 3.Add some unimplented device to emulate guest unused
>>>> memory space.
>>>>
>>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>>> ---
>>>>    hw/loongarch/Kconfig            |  8 +++++
>>>>    hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>>>    hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>>>    include/hw/intc/loongarch_ipi.h |  2 ++
>>>>    include/hw/pci-host/ls7a.h      |  4 +++
>>>>    softmmu/qdev-monitor.c          |  3 +-
>>>>    6 files changed, 117 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>>> index 468e3acc74..9ea3b92708 100644
>>>> --- a/hw/loongarch/Kconfig
>>>> +++ b/hw/loongarch/Kconfig
>>>> @@ -1,5 +1,13 @@
>>>>    config LOONGSON3_LS7A
>>>>        bool
>>>> +    imply VGA_PCI
>>>> +    imply VIRTIO_VGA
>>>> +    imply PARALLEL
>>>> +    imply PCI_DEVICES
>>>> +    select ISA_BUS
>>>> +    select SERIAL
>>>> +    select SERIAL_ISA
>>>> +    select VIRTIO_PCI
>>>>        select PCI_EXPRESS_7A
>>>>        select LOONGARCH_IPI
>>>>        select LOONGARCH_PCH_PIC
>>>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>>>> index c42f830208..e4a02e7c18 100644
>>>> --- a/hw/loongarch/loongson3.c
>>>> +++ b/hw/loongarch/loongson3.c
>>>> @@ -10,8 +10,11 @@
>>>>    #include "qemu/datadir.h"
>>>>    #include "qapi/error.h"
>>>>    #include "hw/boards.h"
>>>> +#include "hw/char/serial.h"
>>>>    #include "sysemu/sysemu.h"
>>>>    #include "sysemu/qtest.h"
>>>> +#include "hw/irq.h"
>>>> +#include "net/net.h"
>>>>    #include "sysemu/runstate.h"
>>>>    #include "sysemu/reset.h"
>>>>    #include "hw/loongarch/loongarch.h"
>>>> @@ -20,6 +23,7 @@
>>>>    #include "hw/intc/loongarch_pch_pic.h"
>>>>    #include "hw/intc/loongarch_pch_msi.h"
>>>>    #include "hw/pci-host/ls7a.h"
>>>> +#include "hw/misc/unimp.h"
>>>>        static void loongarch_cpu_reset(void *opaque)
>>>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>>>        memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>>>    }
>>>>    -static void loongson3_irq_init(MachineState *machine)
>>>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>>>    {
>>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>>>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>>>        SysBusDevice *d;
>>>> +    PCIBus *pci_bus;
>>>>        int cpu, pin, i;
>>>>        unsigned long ipi_addr;
>>>>    @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>>>        sysbus_realize_and_unref(d, &error_fatal);
>>>>        sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>>>    +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>>>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>>>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>>>> +
>>>>        /* Connect 64 pch_pic irqs to extioi */
>>>>        for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>>>            sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>>>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>>>            sysbus_connect_irq(d, i,
>>>>                               qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>>>        }
>>>> +
>>>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>>>> +    d = SYS_BUS_DEVICE(pciehost);
>>>> +    sysbus_realize_and_unref(d, &error_fatal);
>>>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>>>> +
>>>> +    /* Connect 48 pci irq to pch_pic */
>>>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>>>> +        qdev_connect_gpio_out(pciehost, i,
>>>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>>>> +    }
>>>> +
>>>> +    return pci_bus;
>>>> +}
>>>> +
>>>> +/* Network support */
>>>> +static void network_init(PCIBus *pci_bus)
>>>> +{
>>>> +    int i;
>>>> +
>>>> +    for (i = 0; i < nb_nics; i++) {
>>>> +        NICInfo *nd = &nd_table[i];
>>>> +
>>>> +        if (!nd->model) {
>>>> +            nd->model = g_strdup("virtio");
>>>> +        }
>>>> +
>>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>>> +    }
>>>>    }
>>>>      static void loongson3_init(MachineState *machine)
>>>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>>>        MemoryRegion *address_space_mem = get_system_memory();
>>>>        LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>>        int i;
>>>> +    PCIBus *pci_bus = NULL;
>>>>          if (!cpu_model) {
>>>>            cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>>>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>>>        memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>>>        offset += highram_size;
>>>>    +    /*
>>>> +     * There are some invalid guest memory access.
>>>> +     * Create some unimplemented devices to emulate this.
>>>> +     */
>>>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>>>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>>>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>>>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>>>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>>>> +
>>>>        /* Initialize the IO interrupt subsystem */
>>>> -    loongson3_irq_init(machine);
>>>> +    pci_bus = loongson3_irq_init(machine);
>>>> +
>>>> +    /* Network card */
>>>> +    network_init(pci_bus);
>>>> +
>>>> +    /* VGA setup. Don't bother loading the bios. */
>>>> +    pci_vga_init(pci_bus);
>>>> +
>>>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
>>>
>>> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
>>>
>>> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.
>>
>> The machine has these devices but we don't want to emulate all the devices, only emulated part devices.
>> I don't know if it is ok to do like this.
> 
> I'm not sure I understand what you mean by part devices here - could you give an example?
> 
>>>>        LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>>>        LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>>>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>>>> index a783fb2eda..06cd641573 100644
>>>> --- a/hw/pci-host/ls7a.c
>>>> +++ b/hw/pci-host/ls7a.c
>>>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>>>        }
>>>>    };
>>>>    +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>>>> +{
>>>> +    PCIINTxRoute route;
>>>> +
>>>> +    route.irq = pin;
>>>> +    route.mode = PCI_INTX_ENABLED;
>>>> +    return route;
>>>> +}
>>>> +
>>>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>>>> +{
>>>> +    PCIBus *bus;
>>>> +    int offset, irq;
>>>> +
>>>> +    bus = pci_get_bus(d);
>>>> +    if (bus->parent_dev) {
>>>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>>>> +        return irq;
>>>> +    }
>>>
>>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
>>
>> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
>> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.
> 
> I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?

Oh, we will remove these lines. Our original thoughts is that irq-lines of
root bridge is connected with irq controller, so root bridge can have more than
4 irq-lines, non root-bridge has 4 irq-lines at most.

From the code it is only treated as pcie root bridge, and its parent_dev is NULL
always. and we can simply add these sentences such as:
    /* pci device start from irq 80 */
    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;

    return irq;

regards
bibo, mao

> 
>>>> +    /* pci device start from irq 80 */
>>>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>>>> +
>>>> +    return irq;
>>>> +}
>>>> +
>>>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>>>> +{
>>>> +    LS7APCIEHost *pciehost = opaque;
>>>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>> +
>>>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>>>> +}
>>>> +
>>>>    static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>>>                                      uint64_t val, unsigned size)
>>>>    {
>>>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>>>        LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>>>        PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>>>    -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>>>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>>>> +                                     pci_ls7a_map_irq, s,
>>>>                                         get_system_memory(), get_system_io(),
>>>>                                         PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>>>    +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>>>> +
>>>>        memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>>>                              &pci_ls7a_config_ops, pci->bus,
>>>>                              "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>>>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>>>        object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>>>        qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>>>        qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>>>> +
>>>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>>>    }
>>>>      static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>>>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>>>> index d2397e53e7..1113c3b1a8 100644
>>>> --- a/include/hw/intc/loongarch_ipi.h
>>>> +++ b/include/hw/intc/loongarch_ipi.h
>>>> @@ -8,6 +8,8 @@
>>>>    #ifndef HW_LOONGARCH_IPI_H
>>>>    #define HW_LOONGARCH_IPI_H
>>>>    +#include "hw/sysbus.h"
>>>> +
>>>>    /* Mainy used by iocsr read and write */
>>>>    #define SMP_IPI_MAILBOX      0x1000ULL
>>>>    #define CORE_STATUS_OFF       0x0
>>>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>>>> index ac938d6d5f..3b9ad1e175 100644
>>>> --- a/include/hw/pci-host/ls7a.h
>>>> +++ b/include/hw/pci-host/ls7a.h
>>>> @@ -37,6 +37,9 @@
>>>>    #define LS7A_DEVICE_IRQS        16
>>>>    #define LS7A_PCI_IRQS           48
>>>>    +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>>>> +#define LS7A_UART_BASE          0x1fe001e0
>>>> +
>>>>    struct LS7APCIState {
>>>>        /*< private >*/
>>>>        PCIDevice parent_obj;
>>>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>>>          LS7APCIState pci_dev;
>>>>    +    qemu_irq irqs[LS7A_PCI_IRQS];
>>>>        MemoryRegion pci_conf;
>>>>        MemoryRegion pci_io;
>>>>    } LS7APCIEHost;
>>>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>>>> index 01f3834db5..49491d74a1 100644
>>>> --- a/softmmu/qdev-monitor.c
>>>> +++ b/softmmu/qdev-monitor.c
>>>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>>>                                  QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>>>                                  QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>>>                                  QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>>>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>>>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>>>> +                              QEMU_ARCH_LOONGARCH)
>>>
>>> This part looks like it belongs to another patch?
>>
>> OK, I will put this part to a separate patch.
>>
>> Thanks,
>> Xiaojuan
>>
>>>
>>>>    #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>>>    #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
> 
> ATB,
> 
> Mark.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2022-01-10  2:26         ` yangxiaojuan
@ 2022-01-15 14:03           ` Mark Cave-Ayland
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Cave-Ayland @ 2022-01-15 14:03 UTC (permalink / raw)
  To: yangxiaojuan, qemu-level

On 10/01/2022 02:26, yangxiaojuan wrote:

> Hi, Mark
> 
> On 12/23/2021 06:52 PM, Mark Cave-Ayland wrote:
>> On 22/12/2021 08:26, yangxiaojuan wrote:
>>
>>> Hi, Mark
>>>
>>> On 12/18/2021 06:02 PM, Mark Cave-Ayland wrote:
>>>> On 04/12/2021 12:07, Xiaojuan Yang wrote:
>>>>
>>>>> 1.Add uart,virtio-net,vga and usb for 3A5000.
>>>>> 2.Add irq set and map for the pci host. Non pci device
>>>>> use irq 0-16, pci device use 16-64.
>>>>> 3.Add some unimplented device to emulate guest unused
>>>>> memory space.
>>>>>
>>>>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>>>>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>>>>> ---
>>>>>     hw/loongarch/Kconfig            |  8 +++++
>>>>>     hw/loongarch/loongson3.c        | 63 +++++++++++++++++++++++++++++++--
>>>>>     hw/pci-host/ls7a.c              | 42 +++++++++++++++++++++-
>>>>>     include/hw/intc/loongarch_ipi.h |  2 ++
>>>>>     include/hw/pci-host/ls7a.h      |  4 +++
>>>>>     softmmu/qdev-monitor.c          |  3 +-
>>>>>     6 files changed, 117 insertions(+), 5 deletions(-)
>>>>>
>>>>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>>>>> index 468e3acc74..9ea3b92708 100644
>>>>> --- a/hw/loongarch/Kconfig
>>>>> +++ b/hw/loongarch/Kconfig
>>>>> @@ -1,5 +1,13 @@
>>>>>     config LOONGSON3_LS7A
>>>>>         bool
>>>>> +    imply VGA_PCI
>>>>> +    imply VIRTIO_VGA
>>>>> +    imply PARALLEL
>>>>> +    imply PCI_DEVICES
>>>>> +    select ISA_BUS
>>>>> +    select SERIAL
>>>>> +    select SERIAL_ISA
>>>>> +    select VIRTIO_PCI
>>>>>         select PCI_EXPRESS_7A
>>>>>         select LOONGARCH_IPI
>>>>>         select LOONGARCH_PCH_PIC
>>>>> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
>>>>> index c42f830208..e4a02e7c18 100644
>>>>> --- a/hw/loongarch/loongson3.c
>>>>> +++ b/hw/loongarch/loongson3.c
>>>>> @@ -10,8 +10,11 @@
>>>>>     #include "qemu/datadir.h"
>>>>>     #include "qapi/error.h"
>>>>>     #include "hw/boards.h"
>>>>> +#include "hw/char/serial.h"
>>>>>     #include "sysemu/sysemu.h"
>>>>>     #include "sysemu/qtest.h"
>>>>> +#include "hw/irq.h"
>>>>> +#include "net/net.h"
>>>>>     #include "sysemu/runstate.h"
>>>>>     #include "sysemu/reset.h"
>>>>>     #include "hw/loongarch/loongarch.h"
>>>>> @@ -20,6 +23,7 @@
>>>>>     #include "hw/intc/loongarch_pch_pic.h"
>>>>>     #include "hw/intc/loongarch_pch_msi.h"
>>>>>     #include "hw/pci-host/ls7a.h"
>>>>> +#include "hw/misc/unimp.h"
>>>>>         static void loongarch_cpu_reset(void *opaque)
>>>>> @@ -91,11 +95,12 @@ static void sysbus_mmio_map_loongarch(SysBusDevice *dev, int n,
>>>>>         memory_region_add_subregion(iocsr, addr, dev->mmio[n].memory);
>>>>>     }
>>>>>     -static void loongson3_irq_init(MachineState *machine)
>>>>> +static PCIBus *loongson3_irq_init(MachineState *machine)
>>>>>     {
>>>>>         LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>>> -    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev;
>>>>> +    DeviceState *ipi, *extioi, *pch_pic, *pch_msi, *cpudev, *pciehost;
>>>>>         SysBusDevice *d;
>>>>> +    PCIBus *pci_bus;
>>>>>         int cpu, pin, i;
>>>>>         unsigned long ipi_addr;
>>>>>     @@ -135,6 +140,10 @@ static void loongson3_irq_init(MachineState *machine)
>>>>>         sysbus_realize_and_unref(d, &error_fatal);
>>>>>         sysbus_mmio_map(d, 0, LS7A_IOAPIC_REG_BASE);
>>>>>     +    serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
>>>>> +                   qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
>>>>> +                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>>>>> +
>>>>>         /* Connect 64 pch_pic irqs to extioi */
>>>>>         for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>>>>>             sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
>>>>> @@ -149,6 +158,35 @@ static void loongson3_irq_init(MachineState *machine)
>>>>>             sysbus_connect_irq(d, i,
>>>>>                                qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
>>>>>         }
>>>>> +
>>>>> +    pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
>>>>> +    d = SYS_BUS_DEVICE(pciehost);
>>>>> +    sysbus_realize_and_unref(d, &error_fatal);
>>>>> +    pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
>>>>> +
>>>>> +    /* Connect 48 pci irq to pch_pic */
>>>>> +    for (i = 0; i < LS7A_PCI_IRQS; i++) {
>>>>> +        qdev_connect_gpio_out(pciehost, i,
>>>>> +                              qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
>>>>> +    }
>>>>> +
>>>>> +    return pci_bus;
>>>>> +}
>>>>> +
>>>>> +/* Network support */
>>>>> +static void network_init(PCIBus *pci_bus)
>>>>> +{
>>>>> +    int i;
>>>>> +
>>>>> +    for (i = 0; i < nb_nics; i++) {
>>>>> +        NICInfo *nd = &nd_table[i];
>>>>> +
>>>>> +        if (!nd->model) {
>>>>> +            nd->model = g_strdup("virtio");
>>>>> +        }
>>>>> +
>>>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>>>> +    }
>>>>>     }
>>>>>       static void loongson3_init(MachineState *machine)
>>>>> @@ -161,6 +199,7 @@ static void loongson3_init(MachineState *machine)
>>>>>         MemoryRegion *address_space_mem = get_system_memory();
>>>>>         LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>>>>>         int i;
>>>>> +    PCIBus *pci_bus = NULL;
>>>>>           if (!cpu_model) {
>>>>>             cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
>>>>> @@ -207,8 +246,26 @@ static void loongson3_init(MachineState *machine)
>>>>>         memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
>>>>>         offset += highram_size;
>>>>>     +    /*
>>>>> +     * There are some invalid guest memory access.
>>>>> +     * Create some unimplemented devices to emulate this.
>>>>> +     */
>>>>> +    create_unimplemented_device("ls7a-lpc", 0x10002000, 0x14);
>>>>> +    create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
>>>>> +    create_unimplemented_device("node-bridge", 0xEFDFB000274, 0x4);
>>>>> +    create_unimplemented_device("ls7a-lionlpc", 0x1fe01400, 0x38);
>>>>> +    create_unimplemented_device("ls7a-node0", 0x0EFDFB000274, 0x4);
>>>>> +
>>>>>         /* Initialize the IO interrupt subsystem */
>>>>> -    loongson3_irq_init(machine);
>>>>> +    pci_bus = loongson3_irq_init(machine);
>>>>> +
>>>>> +    /* Network card */
>>>>> +    network_init(pci_bus);
>>>>> +
>>>>> +    /* VGA setup. Don't bother loading the bios. */
>>>>> +    pci_vga_init(pci_bus);
>>>>> +
>>>>> +    pci_create_simple(pci_bus, -1, "pci-ohci");
>>>>
>>>> By passing in -1 then you're allowing the PCI code to choose a suitable device/function which feels odd for an in-built device. Is this not fixed in real hardware?
>>>>
>>>> Same with pci_nic_init_nofail() and pci_vga_init() which are intended for machines that don't have these devices in-built.
>>>
>>> The machine has these devices but we don't want to emulate all the devices, only emulated part devices.
>>> I don't know if it is ok to do like this.
>>
>> I'm not sure I understand what you mean by part devices here - could you give an example?
> 
> 
> For example the ls7a1000 support multiple devices, such as sata, gmac, uart, rtc and so on. But we just realize the rtc.

 From what I understand from the patchset you are creating a special "virt" board so 
of course it is up to you which devices you wish to support as long as they are 
documented somewhere.

>>
>>>>>         LOONGARCH_SIMPLE_MMIO_OPS(FEATURE_REG, "loongarch_feature", 0x8);
>>>>>         LOONGARCH_SIMPLE_MMIO_OPS(VENDOR_REG, "loongarch_vendor", 0x8);
>>>>> diff --git a/hw/pci-host/ls7a.c b/hw/pci-host/ls7a.c
>>>>> index a783fb2eda..06cd641573 100644
>>>>> --- a/hw/pci-host/ls7a.c
>>>>> +++ b/hw/pci-host/ls7a.c
>>>>> @@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
>>>>>         }
>>>>>     };
>>>>>     +static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
>>>>> +{
>>>>> +    PCIINTxRoute route;
>>>>> +
>>>>> +    route.irq = pin;
>>>>> +    route.mode = PCI_INTX_ENABLED;
>>>>> +    return route;
>>>>> +}
>>>>> +
>>>>> +static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
>>>>> +{
>>>>> +    PCIBus *bus;
>>>>> +    int offset, irq;
>>>>> +
>>>>> +    bus = pci_get_bus(d);
>>>>> +    if (bus->parent_dev) {
>>>>> +        irq = pci_swizzle_map_irq_fn(d, irq_num);
>>>>> +        return irq;
>>>>> +    }
>>>>
>>>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
>>>
>>> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
>>> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.
>>
>> I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?
>>
> 
> For this part, I'm a bit confused. I think some pcie devices can directly connect to the host bridges while the pci devices will connected via a pcie-to-pci bridge. So the map irq is like this.
> I will learn more about PCIe to verify whether this idea is correct. Thank you!
>   
>>>>> +    /* pci device start from irq 80 */
>>>>> +    offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>>> +    irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
>>>>> +
>>>>> +    return irq;
>>>>> +}
>>>>> +
>>>>> +static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
>>>>> +{
>>>>> +    LS7APCIEHost *pciehost = opaque;
>>>>> +    int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>>>>> +
>>>>> +    qemu_set_irq(pciehost->irqs[irq_num - offset], level);
>>>>> +}
>>>>> +
>>>>>     static void pci_ls7a_config_write(void *opaque, hwaddr addr,
>>>>>                                       uint64_t val, unsigned size)
>>>>>     {
>>>>> @@ -64,10 +99,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
>>>>>         LS7APCIEHost *s = LS7A_HOST_DEVICE(dev);
>>>>>         PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
>>>>>     -    pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
>>>>> +    pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
>>>>> +                                     pci_ls7a_map_irq, s,
>>>>>                                          get_system_memory(), get_system_io(),
>>>>>                                          PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
>>>>>     +    pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
>>>>> +
>>>>>         memory_region_init_io(&s->pci_conf, OBJECT(dev),
>>>>>                               &pci_ls7a_config_ops, pci->bus,
>>>>>                               "ls7a_pci_conf", HT1LO_PCICFG_SIZE);
>>>>> @@ -137,6 +175,8 @@ static void ls7a_pciehost_initfn(Object *obj)
>>>>>         object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCIE);
>>>>>         qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
>>>>>         qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
>>>>> +
>>>>> +    qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
>>>>>     }
>>>>>       static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
>>>>> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
>>>>> index d2397e53e7..1113c3b1a8 100644
>>>>> --- a/include/hw/intc/loongarch_ipi.h
>>>>> +++ b/include/hw/intc/loongarch_ipi.h
>>>>> @@ -8,6 +8,8 @@
>>>>>     #ifndef HW_LOONGARCH_IPI_H
>>>>>     #define HW_LOONGARCH_IPI_H
>>>>>     +#include "hw/sysbus.h"
>>>>> +
>>>>>     /* Mainy used by iocsr read and write */
>>>>>     #define SMP_IPI_MAILBOX      0x1000ULL
>>>>>     #define CORE_STATUS_OFF       0x0
>>>>> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
>>>>> index ac938d6d5f..3b9ad1e175 100644
>>>>> --- a/include/hw/pci-host/ls7a.h
>>>>> +++ b/include/hw/pci-host/ls7a.h
>>>>> @@ -37,6 +37,9 @@
>>>>>     #define LS7A_DEVICE_IRQS        16
>>>>>     #define LS7A_PCI_IRQS           48
>>>>>     +#define LS7A_UART_IRQ           (PCH_PIC_IRQ_OFFSET + 2)
>>>>> +#define LS7A_UART_BASE          0x1fe001e0
>>>>> +
>>>>>     struct LS7APCIState {
>>>>>         /*< private >*/
>>>>>         PCIDevice parent_obj;
>>>>> @@ -51,6 +54,7 @@ typedef struct LS7APCIEHost {
>>>>>           LS7APCIState pci_dev;
>>>>>     +    qemu_irq irqs[LS7A_PCI_IRQS];
>>>>>         MemoryRegion pci_conf;
>>>>>         MemoryRegion pci_io;
>>>>>     } LS7APCIEHost;
>>>>> diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
>>>>> index 01f3834db5..49491d74a1 100644
>>>>> --- a/softmmu/qdev-monitor.c
>>>>> +++ b/softmmu/qdev-monitor.c
>>>>> @@ -60,7 +60,8 @@ typedef struct QDevAlias
>>>>>                                   QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
>>>>>                                   QEMU_ARCH_MIPS | QEMU_ARCH_PPC |  \
>>>>>                                   QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
>>>>> -                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
>>>>> +                              QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
>>>>> +                              QEMU_ARCH_LOONGARCH)
>>>>
>>>> This part looks like it belongs to another patch?
>>>
>>> OK, I will put this part to a separate patch.
>>>
>>> Thanks,
>>> Xiaojuan
>>>
>>>>
>>>>>     #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
>>>>>     #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
>>
>> ATB,
>>
>> Mark.


ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000.
  2022-01-12  9:37         ` maobibo
@ 2022-01-15 14:05           ` Mark Cave-Ayland
  0 siblings, 0 replies; 58+ messages in thread
From: Mark Cave-Ayland @ 2022-01-15 14:05 UTC (permalink / raw)
  To: maobibo, yangxiaojuan, qemu-devel
  Cc: peter.maydell, thuth, philmd, i.qemu, richard.henderson, laurent,
	peterx, f4bug, alistair.francis, pbonzini, chenhuacai,
	alex.bennee, gaosong

On 12/01/2022 09:37, maobibo wrote:

>>>> Isn't this part already handled by the code in hw/pci/pci.c when the IRQ is asserted, for example pci_change_irq_level()?
>>>
>>> We design a different rule for the pcie devices connect to the root bridge, assign more irqs to these devices.
>>> For the pci device connect to a pcie-to-pci bridge use the common pci_swizzle_map_irq_fn to map irq.
>>
>> I'm less familiar with PCIe but shouldn't the interrupt mapping for devices connected via a pcie-to-pci bridge be handled by the bridge in this case? Have a look at pci_bridge_map_irq() to see how this is used. I'd expect the pcie-to-pci bridge to map the PCI irq to your host controller irq first before calling pci_ls7a_map_irq(), which I think then becomes just a simple call to pci_swizzle_map_irq_fn()?
> 
> Oh, we will remove these lines. Our original thoughts is that irq-lines of
> root bridge is connected with irq controller, so root bridge can have more than
> 4 irq-lines, non root-bridge has 4 irq-lines at most.
> 
>>From the code it is only treated as pcie root bridge, and its parent_dev is NULL
> always. and we can simply add these sentences such as:
>      /* pci device start from irq 80 */
>      offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
>      irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
> 
>      return irq;

Right, that makes more sense to me. Generally root bridges are different enough from 
downstream bridges to be modelled as a separate device (often with a slightly 
different product id), so if you can remove the parent_dev check and use the above 
that works for me.


ATB,

Mark.


^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2022-01-15 14:07 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-04 12:06 [RFC PATCH v3 00/27] Add LoongArch softmmu support Xiaojuan Yang
2021-12-04 12:06 ` [RFC PATCH v3 01/27] target/loongarch: Update README Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 02/27] target/loongarch: Add CSR registers definition Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 03/27] target/loongarch: Add basic vmstate description of CPU Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 04/27] target/loongarch: Implement qmp_query_cpu_definitions() Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 05/27] target/loongarch: Add stabletimer support Xiaojuan Yang
2021-12-06  4:38   ` chen huacai
2021-12-07  7:04     ` maobibo
2021-12-04 12:07 ` [RFC PATCH v3 06/27] target/loongarch: Add MMU support for LoongArch CPU Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 07/27] target/loongarch: Add LoongArch CSR instruction Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 08/27] target/loongarch: Add LoongArch IOCSR instruction Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 09/27] target/loongarch: Add TLB instruction support Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 10/27] target/loongarch: Add other core instructions support Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 11/27] target/loongarch: Add LoongArch interrupt and exception handle Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 12/27] target/loongarch: Add timer related instructions support Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 13/27] target/loongarch: Add gdb support Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 14/27] hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson3 Platform Xiaojuan Yang
2021-12-17 23:39   ` Mark Cave-Ayland
2021-12-20 11:42     ` yangxiaojuan
2021-12-04 12:07 ` [RFC PATCH v3 15/27] hw/loongarch: Add support loongson3-ls7a machine type Xiaojuan Yang
2021-12-06  4:36   ` chen huacai
2021-12-06  6:57     ` yangxiaojuan
2021-12-17 23:48   ` Mark Cave-Ayland
2021-12-04 12:07 ` [RFC PATCH v3 16/27] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC) Xiaojuan Yang
2021-12-17 23:54   ` Mark Cave-Ayland
2021-12-21  3:43     ` yangxiaojuan
2021-12-04 12:07 ` [RFC PATCH v3 17/27] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
2021-12-18  0:09   ` Mark Cave-Ayland
2021-12-04 12:07 ` [RFC PATCH v3 18/27] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) Xiaojuan Yang
2021-12-18  0:33   ` Mark Cave-Ayland
2021-12-22  2:38     ` yangxiaojuan
2021-12-23 10:21       ` Mark Cave-Ayland
2022-01-08  9:44         ` yangxiaojuan
2021-12-04 12:07 ` [RFC PATCH v3 19/27] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) Xiaojuan Yang
2021-12-18  0:36   ` Mark Cave-Ayland
2021-12-04 12:07 ` [RFC PATCH v3 20/27] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
2021-12-18  0:50   ` Mark Cave-Ayland
2021-12-04 12:07 ` [RFC PATCH v3 21/27] hw/loongarch: Add irq hierarchy for the system Xiaojuan Yang
2021-12-18  9:45   ` Mark Cave-Ayland
2021-12-04 12:07 ` [RFC PATCH v3 22/27] hw/loongarch: Add some devices support for 3A5000 Xiaojuan Yang
2021-12-04 17:54   ` Philippe Mathieu-Daudé
2021-12-06  6:55     ` yangxiaojuan
2021-12-18 10:02   ` Mark Cave-Ayland
2021-12-22  8:26     ` yangxiaojuan
2021-12-23 10:52       ` Mark Cave-Ayland
2022-01-10  2:26         ` yangxiaojuan
2022-01-15 14:03           ` Mark Cave-Ayland
2022-01-12  9:37         ` maobibo
2022-01-15 14:05           ` Mark Cave-Ayland
2021-12-04 12:07 ` [RFC PATCH v3 23/27] hw/loongarch: Add LoongArch ls7a rtc device support Xiaojuan Yang
2021-12-18 10:10   ` Mark Cave-Ayland
2021-12-04 12:07 ` [RFC PATCH v3 24/27] hw/loongarch: Add default bios startup support Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 25/27] hw/loongarch: Add -kernel and -initrd options support Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 26/27] hw/loongarch: Add LoongArch smbios support Xiaojuan Yang
2021-12-04 12:07 ` [RFC PATCH v3 27/27] hw/loongarch: Add LoongArch acpi support Xiaojuan Yang
2021-12-13  3:13 ` [RFC PATCH v3 00/27] Add LoongArch softmmu support yangxiaojuan
2021-12-13 22:43   ` Mark Cave-Ayland
2021-12-14  1:08     ` yangxiaojuan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.